diff --git a/.github/workflows/cs102.yml b/.github/workflows/cs102.yml index 4509ac4..2df86e7 100644 --- a/.github/workflows/cs102.yml +++ b/.github/workflows/cs102.yml @@ -7,10 +7,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Set up Python 3.8.6 + - name: Set up Python 3.9 uses: actions/setup-python@v2 with: - python-version: '3.8.6' + python-version: '3.9' - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/homework00/hello.py b/homework00/hello.py index efe8767..5802c29 100644 --- a/homework00/hello.py +++ b/homework00/hello.py @@ -1,5 +1,5 @@ def get_greeting(name: str) -> str: - pass + return f"Hello, {name}!" if __name__ == "__main__": diff --git a/homework01/caesar.py b/homework01/caesar.py index 09c3681..8e986dc 100644 --- a/homework01/caesar.py +++ b/homework01/caesar.py @@ -15,7 +15,16 @@ def encrypt_caesar(plaintext: str, shift: int = 3) -> str: '' """ ciphertext = "" - # PUT YOUR CODE HERE + for i in plaintext: + if i.isalpha(): + if i.isupper(): + code_i = ord(i) - ord("A") + ciphertext += chr((code_i + shift) % 26 + ord("A")) + else: + code_i = ord(i) - ord("a") + ciphertext += chr((code_i + shift) % 26 + ord("a")) + else: + ciphertext += i return ciphertext @@ -32,8 +41,19 @@ def decrypt_caesar(ciphertext: str, shift: int = 3) -> str: >>> decrypt_caesar("") '' """ + # abcdefghijklmnopqrstuvwxyz + # zyxwvutsrqponmlkjihgfedcba plaintext = "" - # PUT YOUR CODE HERE + for i in ciphertext: + if i.isalpha(): + if i.isupper(): + code_i = 25 - ord(i) + ord("A") + plaintext += chr(25 - (code_i + shift) % 26 + ord("A")) + else: + code_i = 25 - ord(i) + ord("a") + plaintext += chr(25 - (code_i + shift) % 26 + ord("a")) + else: + plaintext += i return plaintext diff --git a/homework01/rsa.py b/homework01/rsa.py index b777be5..6cac613 100644 --- a/homework01/rsa.py +++ b/homework01/rsa.py @@ -1,3 +1,4 @@ +import math import random import typing as tp @@ -13,8 +14,12 @@ def is_prime(n: int) -> bool: >>> is_prime(8) False """ - # PUT YOUR CODE HERE - pass + if n == 1: + return False + for i in range(2, int(math.sqrt(n)) + 1): + if n % i == 0: + return False + return True def gcd(a: int, b: int) -> int: @@ -26,8 +31,12 @@ def gcd(a: int, b: int) -> int: >>> gcd(3, 7) 1 """ - # PUT YOUR CODE HERE - pass + while a > 0 and b > 0: + if a > b: + a %= b + else: + b %= a + return a + b def multiplicative_inverse(e: int, phi: int) -> int: @@ -38,8 +47,19 @@ def multiplicative_inverse(e: int, phi: int) -> int: >>> multiplicative_inverse(7, 40) 23 """ - # PUT YOUR CODE HERE - pass + + def loc_0(e, phi): + if phi == 0: + return 1, 0 + (q, r) = (e // phi, e % phi) + print((q, r)) + (s, t) = loc_0(phi, r) + return t, s - (q * t) + + inverse = loc_0(e, phi)[0] + if inverse < 0: + inverse += phi + return inverse def generate_keypair(p: int, q: int) -> tp.Tuple[tp.Tuple[int, int], tp.Tuple[int, int]]: @@ -49,10 +69,10 @@ def generate_keypair(p: int, q: int) -> tp.Tuple[tp.Tuple[int, int], tp.Tuple[in raise ValueError("p and q cannot be equal") # n = pq - # PUT YOUR CODE HERE + n = p * q # phi = (p-1)(q-1) - # PUT YOUR CODE HERE + phi = (p - 1) * (q - 1) # Choose an integer e such that e and phi(n) are coprime e = random.randrange(1, phi) @@ -68,7 +88,7 @@ def generate_keypair(p: int, q: int) -> tp.Tuple[tp.Tuple[int, int], tp.Tuple[in # Return public and private keypair # Public key is (e, n) and private key is (d, n) - return ((e, n), (d, n)) + return (e, n), (d, n) def encrypt(pk: tp.Tuple[int, int], plaintext: str) -> tp.List[int]: @@ -85,7 +105,7 @@ def decrypt(pk: tp.Tuple[int, int], ciphertext: tp.List[int]) -> str: # Unpack the key into its components key, n = pk # Generate the plaintext based on the ciphertext and key using a^b mod m - plain = [chr((char ** key) % n) for char in ciphertext] + plain = [chr((char**key) % n) for char in ciphertext] # Return the array of bytes as a string return "".join(plain) diff --git a/homework01/vigenere.py b/homework01/vigenere.py index e51742e..a95631f 100644 --- a/homework01/vigenere.py +++ b/homework01/vigenere.py @@ -10,7 +10,19 @@ def encrypt_vigenere(plaintext: str, keyword: str) -> str: 'LXFOPVEFRNHR' """ ciphertext = "" - # PUT YOUR CODE HERE + for i in range(len(plaintext)): + symbol = plaintext[i] + if symbol.isalpha(): + if symbol.isupper(): + shift = ord(keyword[i % len(keyword)]) - ord("A") + code_of_symbol = ord(symbol) - ord("A") + ciphertext += chr((code_of_symbol + shift) % 26 + ord("A")) + else: + shift = ord(keyword[i % len(keyword)]) - ord("a") + code_of_symbol = ord(symbol) - ord("a") + ciphertext += chr((code_of_symbol + shift) % 26 + ord("a")) + else: + ciphertext += symbol return ciphertext @@ -26,5 +38,17 @@ def decrypt_vigenere(ciphertext: str, keyword: str) -> str: 'ATTACKATDAWN' """ plaintext = "" - # PUT YOUR CODE HERE + for i in range(len(ciphertext)): + symbol = ciphertext[i] + if symbol.isalpha(): + if symbol.isupper(): + shift = ord(keyword[i % len(keyword)]) - ord("A") + code_of_symbol = 25 - ord(symbol) + ord("A") + plaintext += chr(25 - (code_of_symbol + shift) % 26 + ord("A")) + else: + shift = ord(keyword[i % len(keyword)]) - ord("a") + code_of_symbol = 25 - ord(symbol) + ord("a") + plaintext += chr(25 - (code_of_symbol + shift) % 26 + ord("a")) + else: + plaintext += symbol return plaintext diff --git a/homework02/sudoku.py b/homework02/sudoku.py index df78ab1..2eafe39 100644 --- a/homework02/sudoku.py +++ b/homework02/sudoku.py @@ -1,11 +1,12 @@ import pathlib +import random import typing as tp T = tp.TypeVar("T") def read_sudoku(path: tp.Union[str, pathlib.Path]) -> tp.List[tp.List[str]]: - """ Прочитать Судоку из указанного файла """ + """Прочитать Судоку из указанного файла""" path = pathlib.Path(path) with path.open() as f: puzzle = f.read() @@ -19,7 +20,7 @@ def create_grid(puzzle: str) -> tp.List[tp.List[str]]: def display(grid: tp.List[tp.List[str]]) -> None: - """Вывод Судоку """ + """Вывод Судоку""" width = 2 line = "+".join(["-" * (width * 3)] * 3) for row in range(9): @@ -42,7 +43,12 @@ def group(values: tp.List[T], n: int) -> tp.List[tp.List[T]]: >>> group([1,2,3,4,5,6,7,8,9], 3) [[1, 2, 3], [4, 5, 6], [7, 8, 9]] """ - pass + matrix = [] + i = 0 + for j in range(n, len(values) + 1, n): + matrix.append(values[i:j]) + i = j + return matrix def get_row(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str]: @@ -55,7 +61,7 @@ def get_row(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str >>> get_row([['1', '2', '3'], ['4', '5', '6'], ['.', '8', '9']], (2, 0)) ['.', '8', '9'] """ - pass + return grid[pos[0]] def get_col(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str]: @@ -68,7 +74,10 @@ def get_col(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str >>> get_col([['1', '2', '3'], ['4', '5', '6'], ['.', '8', '9']], (0, 2)) ['3', '6', '9'] """ - pass + column = [] + for i in range(len(grid)): + column.append(grid[i][pos[1]]) + return column def get_block(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[str]: @@ -82,10 +91,16 @@ def get_block(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.List[s >>> get_block(grid, (8, 8)) ['2', '8', '.', '.', '.', '5', '.', '7', '9'] """ - pass + block = [] + number_of_string = pos[0] // 3 + number_of_column = pos[1] // 3 + for i in range(number_of_string * 3, number_of_string * 3 + 3): + for j in range(number_of_column * 3, number_of_column * 3 + 3): + block.append(grid[i][j]) + return block -def find_empty_positions(grid: tp.List[tp.List[str]]) -> tp.Optional[tp.Tuple[int, int]]: +def find_empty_positions(grid: tp.List[tp.List[str]]): """Найти первую свободную позицию в пазле >>> find_empty_positions([['1', '2', '.'], ['4', '5', '6'], ['7', '8', '9']]) @@ -95,7 +110,14 @@ def find_empty_positions(grid: tp.List[tp.List[str]]) -> tp.Optional[tp.Tuple[in >>> find_empty_positions([['1', '2', '3'], ['4', '5', '6'], ['.', '8', '9']]) (2, 0) """ - pass + x = -1 + for i in grid: + y = -1 + x += 1 + for j in i: + y += 1 + if j == ".": + return x, y def find_possible_values(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) -> tp.Set[str]: @@ -109,11 +131,18 @@ def find_possible_values(grid: tp.List[tp.List[str]], pos: tp.Tuple[int, int]) - >>> values == {'2', '5', '9'} True """ - pass - - -def solve(grid: tp.List[tp.List[str]]) -> tp.Optional[tp.List[tp.List[str]]]: - """ Решение пазла, заданного в grid """ + numbers = set("123456789") + string = set(get_row(grid, pos)) + column = set(get_col(grid, pos)) + block = set(get_block(grid, pos)) + numbers -= string + numbers -= column + numbers -= block + return numbers + + +def solve(grid: tp.List[tp.List[str]]): + """Решение пазла, заданного в grid""" """ Как решать Судоку? 1. Найти свободную позицию 2. Найти все возможные значения, которые могут находиться на этой позиции @@ -125,13 +154,33 @@ def solve(grid: tp.List[tp.List[str]]) -> tp.Optional[tp.List[tp.List[str]]]: >>> solve(grid) [['5', '3', '4', '6', '7', '8', '9', '1', '2'], ['6', '7', '2', '1', '9', '5', '3', '4', '8'], ['1', '9', '8', '3', '4', '2', '5', '6', '7'], ['8', '5', '9', '7', '6', '1', '4', '2', '3'], ['4', '2', '6', '8', '5', '3', '7', '9', '1'], ['7', '1', '3', '9', '2', '4', '8', '5', '6'], ['9', '6', '1', '5', '3', '7', '2', '8', '4'], ['2', '8', '7', '4', '1', '9', '6', '3', '5'], ['3', '4', '5', '2', '8', '6', '1', '7', '9']] """ - pass + pos = find_empty_positions(grid) + if pos is None: + return grid + else: + possible_values = find_possible_values(grid, pos) + for number in possible_values: + grid[pos[0]][pos[1]] = number + res = solve(grid) + if res: + return res + grid[pos[0]][pos[1]] = "." def check_solution(solution: tp.List[tp.List[str]]) -> bool: - """ Если решение solution верно, то вернуть True, в противном случае False """ + """Если решение solution верно, то вернуть True, в противном случае False""" # TODO: Add doctests with bad puzzles - pass + arr = ["1", "2", "3", "4", "5", "6", "7", "8", "9"] + for i in range(0, len(solution)): + for j in range(0, len(solution)): + pos = i, j + if not ( + arr == sorted(get_row(solution, pos)) + and arr == sorted(get_col(solution, pos)) + and arr == sorted(get_block(solution, pos)) + ): + return False + return True def generate_sudoku(N: int) -> tp.List[tp.List[str]]: @@ -156,7 +205,14 @@ def generate_sudoku(N: int) -> tp.List[tp.List[str]]: >>> check_solution(solution) True """ - pass + grid = [["." for _ in range(9)] for _ in range(9)] + if N > 81: + N = 81 + dots = random.sample([i for i in range(81)], 81 - N) + solve(grid) + for elem in dots: + grid[elem // 9][elem % 9] = "." + return grid if __name__ == "__main__": @@ -168,3 +224,8 @@ def generate_sudoku(N: int) -> tp.List[tp.List[str]]: print(f"Puzzle {fname} can't be solved") else: display(solution) + if check_solution(solution): + print("Solution is correct") + else: + print("Ooops") + display(generate_sudoku(1)) diff --git a/homework03/life.py b/homework03/life.py index 7aef0b6..8783f3a 100644 --- a/homework03/life.py +++ b/homework03/life.py @@ -2,9 +2,6 @@ import random import typing as tp -import pygame -from pygame.locals import * - Cell = tp.Tuple[int, int] Cells = tp.List[int] Grid = tp.List[Cells] @@ -29,46 +26,94 @@ def __init__( self.generations = 1 def create_grid(self, randomize: bool = False) -> Grid: - # Copy from previous assignment - pass + if randomize: + list_grid = [ + [random.choice([0, 1]) for _ in range(self.rows)] for _ in range(self.cols) + ] + else: + list_grid = [[0 for _ in range(self.rows)] for _ in range(self.cols)] + return list_grid def get_neighbours(self, cell: Cell) -> Cells: - # Copy from previous assignment - pass + row, col = cell + neighbours = [] + positions = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)] + + for i in positions: + row_pos, col_pos = row + i[0], col + i[1] + if row_pos < 0 or row_pos >= self.rows or col_pos < 0 or col_pos >= self.cols: + continue + else: + neighbours.append(self.curr_generation[row_pos][col_pos]) + return neighbours def get_next_generation(self) -> Grid: - # Copy from previous assignment - pass + new_grid = [] + for i in range(self.rows): + line = [] + for j in range(self.cols): + if self.curr_generation[i][j] == 0: + if sum(self.get_neighbours((i, j))) == 3: + line.append(1) + else: + line.append(0) + else: + if ( + sum(self.get_neighbours((i, j))) == 2 + or sum(self.get_neighbours((i, j))) == 3 + ): + line.append(1) + else: + line.append(0) + new_grid.append(line) + return new_grid def step(self) -> None: """ Выполнить один шаг игры. """ - pass + self.prev_generation = self.curr_generation + self.curr_generation = self.get_next_generation() + self.generations += 1 @property def is_max_generations_exceeded(self) -> bool: """ Не превысило ли текущее число поколений максимально допустимое. """ - pass + if self.generations == self.max_generations: + return True + else: + return False @property def is_changing(self) -> bool: """ Изменилось ли состояние клеток с предыдущего шага. """ - pass + if self.curr_generation != self.prev_generation: + return True + else: + return False @staticmethod def from_file(filename: pathlib.Path) -> "GameOfLife": """ Прочитать состояние клеток из указанного файла. """ - pass + file = open(filename).readlines() + grid_list = [] + for i in range(len(file)): + x = list(map(int, file[i].split())) + grid_list.append(x) + life = GameOfLife(size=(len(grid_list), len(grid_list[0])), randomize=False) + life.curr_generation = grid_list + return life def save(self, filename: pathlib.Path) -> None: """ Сохранить текущее состояние клеток в указанный файл. """ - pass + with open(filename, "w") as file: + for i in self.curr_generation: + file.write("".join([str(j) for j in i]) + "\n") diff --git a/homework03/life_console.py b/homework03/life_console.py index ddeb9ef..19c145f 100644 --- a/homework03/life_console.py +++ b/homework03/life_console.py @@ -9,14 +9,32 @@ def __init__(self, life: GameOfLife) -> None: super().__init__(life) def draw_borders(self, screen) -> None: - """ Отобразить рамку. """ - pass + """Отобразить рамку.""" + screen.border("|", "|", "-", "-", "+", "+", "+", "+") def draw_grid(self, screen) -> None: - """ Отобразить состояние клеток. """ - pass + """Отобразить состояние клеток.""" + for x in range(self.life.rows): + for y in range(self.life.cols): + if self.life.curr_generation[x][y] == 1: + screen.addch(x + 1, y + 1, "#") + else: + screen.addch(x + 1, y + 1, " ") def run(self) -> None: screen = curses.initscr() # PUT YOUR CODE HERE - curses.endwin() + while True: + self.draw_borders(screen) + self.draw_grid(screen) + screen.refresh() + self.life.step() + if screen.getch() == 32: # space + curses.endwin() + break + + +if __name__ == "__main__": + life = GameOfLife((24, 80), max_generations=50) + ui = Console(life) + ui.run() diff --git a/homework03/life_gui.py b/homework03/life_gui.py index 1126b29..95a39c5 100644 --- a/homework03/life_gui.py +++ b/homework03/life_gui.py @@ -1,21 +1,91 @@ import pygame from life import GameOfLife -from pygame.locals import * from ui import UI class GUI(UI): def __init__(self, life: GameOfLife, cell_size: int = 10, speed: int = 10) -> None: super().__init__(life) + self.cell_size = cell_size + self.speed = speed + self.width = life.rows * cell_size + self.height = life.cols * cell_size + self.screen_size = self.width, self.height + self.screen = pygame.display.set_mode(self.screen_size) def draw_lines(self) -> None: - # Copy from previous assignment - pass + for x in range(0, self.width, self.cell_size): + pygame.draw.line(self.screen, pygame.Color("black"), (x, 0), (x, self.height)) + for y in range(0, self.height, self.cell_size): + pygame.draw.line(self.screen, pygame.Color("black"), (0, y), (self.width, y)) def draw_grid(self) -> None: - # Copy from previous assignment - pass + for i in range(self.life.cols): + for j in range(self.life.rows): + if self.life.curr_generation[i][j] == 0: + pygame.draw.rect( + self.screen, + pygame.Color("white"), + ( + j * self.cell_size + 1, + i * self.cell_size + 1, + self.cell_size - 1, + self.cell_size - 1, + ), + ) + else: + pygame.draw.rect( + self.screen, + pygame.Color("green"), + ( + j * self.cell_size + 1, + i * self.cell_size + 1, + self.cell_size - 1, + self.cell_size - 1, + ), + ) + + def edit_cell(self, x, y) -> None: + row = y // self.cell_size + col = x // self.cell_size + if self.life.curr_generation[row][col] == 0: + self.life.curr_generation[row][col] = 1 + else: + self.life.curr_generation[row][col] = 0 def run(self) -> None: - # Copy from previous assignment - pass + pygame.init() + clock = pygame.time.Clock() + pygame.display.set_caption("Game of Life") + self.screen.fill(pygame.Color("white")) + + running = True + pause = False + while running: + for event in pygame.event.get(): + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_SPACE: + pause = not pause + elif event.type == pygame.MOUSEBUTTONDOWN: + x, y = event.pos + self.edit_cell(x, y) + self.draw_grid() + self.draw_lines() + pygame.display.flip() + if self.life.is_max_generations_exceeded: + running = False + elif not self.life.is_changing: + running = False + if not pause: + self.life.step() + self.draw_lines() + self.draw_grid() + pygame.display.flip() + clock.tick(self.speed) + pygame.quit() + + +if __name__ == "__main__": + game = GameOfLife(size=(50, 50), randomize=True) + gui = GUI(life=game, cell_size=20, speed=10) + gui.run() diff --git a/homework03/life_proto.py b/homework03/life_proto.py index c6d6010..dc94987 100644 --- a/homework03/life_proto.py +++ b/homework03/life_proto.py @@ -2,7 +2,6 @@ import typing as tp import pygame -from pygame.locals import * Cell = tp.Tuple[int, int] Cells = tp.List[int] @@ -30,33 +29,32 @@ def __init__( self.speed = speed def draw_lines(self) -> None: - """ Отрисовать сетку """ + """Отрисовать сетку""" for x in range(0, self.width, self.cell_size): pygame.draw.line(self.screen, pygame.Color("black"), (x, 0), (x, self.height)) for y in range(0, self.height, self.cell_size): pygame.draw.line(self.screen, pygame.Color("black"), (0, y), (self.width, y)) def run(self) -> None: - """ Запустить игру """ + """Запустить игру""" pygame.init() clock = pygame.time.Clock() pygame.display.set_caption("Game of Life") self.screen.fill(pygame.Color("white")) # Создание списка клеток - # PUT YOUR CODE HERE + self.grid = game.create_grid(randomize=True) + self.draw_grid(self.grid) running = True while running: - for event in pygame.event.get(): - if event.type == QUIT: - running = False self.draw_lines() # Отрисовка списка клеток # Выполнение одного шага игры (обновление состояния ячеек) - # PUT YOUR CODE HERE + self.grid = self.get_next_generation() + self.draw_grid(self.grid) pygame.display.flip() clock.tick(self.speed) pygame.quit() @@ -79,13 +77,43 @@ def create_grid(self, randomize: bool = False) -> Grid: out : Grid Матрица клеток размером `cell_height` х `cell_width`. """ - pass - - def draw_grid(self) -> None: + if randomize: + list_grid = [ + [random.choice([0, 1]) for _ in range(self.cell_width)] + for _ in range(self.cell_height) + ] + else: + list_grid = [[0 for _ in range(self.cell_width)] for _ in range(self.cell_height)] + return list_grid + + def draw_grid(self, ex_grid: list[list[int]]) -> None: """ Отрисовка списка клеток с закрашиванием их в соответствующе цвета. """ - pass + for i in range(self.cell_height): + for j in range(self.cell_width): + if ex_grid[i][j] == 0: + pygame.draw.rect( + self.screen, + pygame.Color("white"), + ( + j * self.cell_size + 1, + i * self.cell_size + 1, + self.cell_size - 1, + self.cell_size - 1, + ), + ) + else: + pygame.draw.rect( + self.screen, + pygame.Color("green"), + ( + j * self.cell_size + 1, + i * self.cell_size + 1, + self.cell_size - 1, + self.cell_size - 1, + ), + ) def get_neighbours(self, cell: Cell) -> Cells: """ @@ -105,7 +133,22 @@ def get_neighbours(self, cell: Cell) -> Cells: out : Cells Список соседних клеток. """ - pass + row, col = cell + neighbours = [] + positions = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)] + + for i in positions: + row_pos, col_pos = row + i[0], col + i[1] + if ( + row_pos < 0 + or row_pos >= self.cell_height + or col_pos < 0 + or col_pos >= self.cell_width + ): + continue + else: + neighbours.append(self.grid[row_pos][col_pos]) + return neighbours def get_next_generation(self) -> Grid: """ @@ -116,4 +159,27 @@ def get_next_generation(self) -> Grid: out : Grid Новое поколение клеток. """ - pass + new_grid = [] + for i in range(self.cell_height): + line = [] + for j in range(self.cell_width): + if self.grid[i][j] == 0: + if sum(self.get_neighbours((i, j))) == 3: + line.append(1) + else: + line.append(0) + else: + if ( + sum(self.get_neighbours((i, j))) == 2 + or sum(self.get_neighbours((i, j))) == 3 + ): + line.append(1) + else: + line.append(0) + new_grid.append(line) + return new_grid + + +if __name__ == "__main__": + game = GameOfLife(1920, 1080, 40, 10) + game.run() diff --git a/venv/Include/site/python3.9/pygame/_camera.h b/venv/Include/site/python3.9/pygame/_camera.h new file mode 100644 index 0000000..075ef6f --- /dev/null +++ b/venv/Include/site/python3.9/pygame/_camera.h @@ -0,0 +1,26 @@ +/* + pygame - Python Game Library + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef _CAMERA_H +#define _CAMERA_H + +#include "_pygame.h" +#include "camera.h" + +#endif diff --git a/venv/Include/site/python3.9/pygame/_pygame.h b/venv/Include/site/python3.9/pygame/_pygame.h new file mode 100644 index 0000000..23da37f --- /dev/null +++ b/venv/Include/site/python3.9/pygame/_pygame.h @@ -0,0 +1,326 @@ +/* + pygame - Python Game Library + Copyright (C) 2000-2001 Pete Shinners + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Pete Shinners + pete@shinners.org +*/ + +/* This will use PYGAMEAPI_EXTERN_SLOTS instead + * of PYGAMEAPI_DEFINE_SLOTS for base modules. + */ +#ifndef _PYGAME_INTERNAL_H +#define _PYGAME_INTERNAL_H + +#include "pgplatform.h" +/* + If PY_SSIZE_T_CLEAN is defined before including Python.h, length is a + Py_ssize_t rather than an int for all # variants of formats (s#, y#, etc.) +*/ +#define PY_SSIZE_T_CLEAN +#include + +/* Ensure PyPy-specific code is not in use when running on GraalPython (PR + * #2580) */ +#if defined(GRAALVM_PYTHON) && defined(PYPY_VERSION) +#undef PYPY_VERSION +#endif + +#include + +/* SDL 1.2 constants removed from SDL 2 */ +typedef enum { + SDL_HWSURFACE = 0, + SDL_RESIZABLE = SDL_WINDOW_RESIZABLE, + SDL_ASYNCBLIT = 0, + SDL_OPENGL = SDL_WINDOW_OPENGL, + SDL_OPENGLBLIT = 0, + SDL_ANYFORMAT = 0, + SDL_HWPALETTE = 0, + SDL_DOUBLEBUF = 0, + SDL_FULLSCREEN = SDL_WINDOW_FULLSCREEN, + SDL_HWACCEL = 0, + SDL_SRCCOLORKEY = 0, + SDL_RLEACCELOK = 0, + SDL_SRCALPHA = 0, + SDL_NOFRAME = SDL_WINDOW_BORDERLESS, + SDL_GL_SWAP_CONTROL = 0, + TIMER_RESOLUTION = 0 +} PygameVideoFlags; + +/* the wheel button constants were removed from SDL 2 */ +typedef enum { + PGM_BUTTON_LEFT = SDL_BUTTON_LEFT, + PGM_BUTTON_RIGHT = SDL_BUTTON_RIGHT, + PGM_BUTTON_MIDDLE = SDL_BUTTON_MIDDLE, + PGM_BUTTON_WHEELUP = 4, + PGM_BUTTON_WHEELDOWN = 5, + PGM_BUTTON_X1 = SDL_BUTTON_X1 + 2, + PGM_BUTTON_X2 = SDL_BUTTON_X2 + 2, + PGM_BUTTON_KEEP = 0x80 +} PygameMouseFlags; + +typedef enum { + /* Any SDL_* events here are for backward compatibility. */ + SDL_NOEVENT = 0, + + SDL_ACTIVEEVENT = SDL_USEREVENT, + SDL_VIDEORESIZE, + SDL_VIDEOEXPOSE, + + PGE_MIDIIN, + PGE_MIDIOUT, + PGE_KEYREPEAT, /* Special internal pygame event, for managing key-presses + */ + + /* DO NOT CHANGE THE ORDER OF EVENTS HERE */ + PGE_WINDOWSHOWN, + PGE_WINDOWHIDDEN, + PGE_WINDOWEXPOSED, + PGE_WINDOWMOVED, + PGE_WINDOWRESIZED, + PGE_WINDOWSIZECHANGED, + PGE_WINDOWMINIMIZED, + PGE_WINDOWMAXIMIZED, + PGE_WINDOWRESTORED, + PGE_WINDOWENTER, + PGE_WINDOWLEAVE, + PGE_WINDOWFOCUSGAINED, + PGE_WINDOWFOCUSLOST, + PGE_WINDOWCLOSE, + PGE_WINDOWTAKEFOCUS, + PGE_WINDOWHITTEST, + + /* Here we define PGPOST_* events, events that act as a one-to-one + * proxy for SDL events (and some extra events too!), the proxy is used + * internally when pygame users use event.post() + * + * At a first glance, these may look redundant, but they are really + * important, especially with event blocking. If proxy events are + * not there, blocked events dont make it to our event filter, and + * that can break a lot of stuff. + * + * IMPORTANT NOTE: Do not post events directly with these proxy types, + * use the appropriate functions from event.c, that handle these proxy + * events for you. + * Proxy events are for internal use only */ + PGPOST_EVENTBEGIN, /* mark start of proxy-events */ + PGPOST_ACTIVEEVENT = PGPOST_EVENTBEGIN, + PGPOST_AUDIODEVICEADDED, + PGPOST_AUDIODEVICEREMOVED, + PGPOST_CONTROLLERAXISMOTION, + PGPOST_CONTROLLERBUTTONDOWN, + PGPOST_CONTROLLERBUTTONUP, + PGPOST_CONTROLLERDEVICEADDED, + PGPOST_CONTROLLERDEVICEREMOVED, + PGPOST_CONTROLLERDEVICEREMAPPED, + PGPOST_CONTROLLERTOUCHPADDOWN, + PGPOST_CONTROLLERTOUCHPADMOTION, + PGPOST_CONTROLLERTOUCHPADUP, + PGPOST_DOLLARGESTURE, + PGPOST_DOLLARRECORD, + PGPOST_DROPFILE, + PGPOST_DROPTEXT, + PGPOST_DROPBEGIN, + PGPOST_DROPCOMPLETE, + PGPOST_FINGERMOTION, + PGPOST_FINGERDOWN, + PGPOST_FINGERUP, + PGPOST_KEYDOWN, + PGPOST_KEYUP, + PGPOST_JOYAXISMOTION, + PGPOST_JOYBALLMOTION, + PGPOST_JOYHATMOTION, + PGPOST_JOYBUTTONDOWN, + PGPOST_JOYBUTTONUP, + PGPOST_JOYDEVICEADDED, + PGPOST_JOYDEVICEREMOVED, + PGPOST_MIDIIN, + PGPOST_MIDIOUT, + PGPOST_MOUSEMOTION, + PGPOST_MOUSEBUTTONDOWN, + PGPOST_MOUSEBUTTONUP, + PGPOST_MOUSEWHEEL, + PGPOST_MULTIGESTURE, + PGPOST_NOEVENT, + PGPOST_QUIT, + PGPOST_SYSWMEVENT, + PGPOST_TEXTEDITING, + PGPOST_TEXTINPUT, + PGPOST_VIDEORESIZE, + PGPOST_VIDEOEXPOSE, + PGPOST_WINDOWSHOWN, + PGPOST_WINDOWHIDDEN, + PGPOST_WINDOWEXPOSED, + PGPOST_WINDOWMOVED, + PGPOST_WINDOWRESIZED, + PGPOST_WINDOWSIZECHANGED, + PGPOST_WINDOWMINIMIZED, + PGPOST_WINDOWMAXIMIZED, + PGPOST_WINDOWRESTORED, + PGPOST_WINDOWENTER, + PGPOST_WINDOWLEAVE, + PGPOST_WINDOWFOCUSGAINED, + PGPOST_WINDOWFOCUSLOST, + PGPOST_WINDOWCLOSE, + PGPOST_WINDOWTAKEFOCUS, + PGPOST_WINDOWHITTEST, + + PGE_USEREVENT, /* this event must stay in this position only */ + + PG_NUMEVENTS = + SDL_LASTEVENT /* Not an event. Indicates end of user events. */ +} PygameEventCode; + +typedef enum { + SDL_APPFOCUSMOUSE, + SDL_APPINPUTFOCUS, + SDL_APPACTIVE +} PygameAppCode; + +/* Surface flags: based on SDL 1.2 flags */ +typedef enum { + PGS_SWSURFACE = 0x00000000, + PGS_HWSURFACE = 0x00000001, + PGS_ASYNCBLIT = 0x00000004, + + PGS_ANYFORMAT = 0x10000000, + PGS_HWPALETTE = 0x20000000, + PGS_DOUBLEBUF = 0x40000000, + PGS_FULLSCREEN = 0x80000000, + PGS_SCALED = 0x00000200, + + PGS_OPENGL = 0x00000002, + PGS_OPENGLBLIT = 0x0000000A, + PGS_RESIZABLE = 0x00000010, + PGS_NOFRAME = 0x00000020, + PGS_SHOWN = 0x00000040, /* Added from SDL 2 */ + PGS_HIDDEN = 0x00000080, /* Added from SDL 2 */ + + PGS_HWACCEL = 0x00000100, + PGS_SRCCOLORKEY = 0x00001000, + PGS_RLEACCELOK = 0x00002000, + PGS_RLEACCEL = 0x00004000, + PGS_SRCALPHA = 0x00010000, + PGS_PREALLOC = 0x01000000 +} PygameSurfaceFlags; + +// TODO Implement check below in a way that does not break CI +/* New buffer protocol (PEP 3118) implemented on all supported Py versions. +#if !defined(Py_TPFLAGS_HAVE_NEWBUFFER) +#error No support for PEP 3118/Py_TPFLAGS_HAVE_NEWBUFFER. Please use a +supported Python version. #endif */ + +#define RAISE(x, y) (PyErr_SetString((x), (y)), (PyObject *)NULL) +#define DEL_ATTR_NOT_SUPPORTED_CHECK(name, value) \ + do { \ + if (!value) { \ + if (name) { \ + PyErr_Format(PyExc_AttributeError, \ + "Cannot delete attribute %s", name); \ + } \ + else { \ + PyErr_SetString(PyExc_AttributeError, \ + "Cannot delete attribute"); \ + } \ + return -1; \ + } \ + } while (0) + +/* + * Initialization checks + */ + +#define VIDEO_INIT_CHECK() \ + if (!SDL_WasInit(SDL_INIT_VIDEO)) \ + return RAISE(pgExc_SDLError, "video system not initialized") + +#define CDROM_INIT_CHECK() \ + if (!SDL_WasInit(SDL_INIT_CDROM)) \ + return RAISE(pgExc_SDLError, "cdrom system not initialized") + +#define JOYSTICK_INIT_CHECK() \ + if (!SDL_WasInit(SDL_INIT_JOYSTICK)) \ + return RAISE(pgExc_SDLError, "joystick system not initialized") + +/* thread check */ +#ifdef WITH_THREAD +#define PG_CHECK_THREADS() (1) +#else /* ~WITH_THREAD */ +#define PG_CHECK_THREADS() \ + (RAISE(PyExc_NotImplementedError, "Python built without thread support")) +#endif /* ~WITH_THREAD */ + +#define PyType_Init(x) (((x).ob_type) = &PyType_Type) + +/* + * event module internals + */ +struct pgEventObject { + PyObject_HEAD int type; + PyObject *dict; +}; + +/* + * surflock module internals + */ +typedef struct { + PyObject_HEAD PyObject *surface; + PyObject *lockobj; + PyObject *weakrefs; +} pgLifetimeLockObject; + +/* + * surface module internals + */ +struct pgSubSurface_Data { + PyObject *owner; + int pixeloffset; + int offsetx, offsety; +}; + +/* + * color module internals + */ +struct pgColorObject { + PyObject_HEAD Uint8 data[4]; + Uint8 len; +}; + +/* + * include public API + */ +#include "include/_pygame.h" + +/* Slot counts. + * Remember to keep these constants up to date. + */ + +#define PYGAMEAPI_RECT_NUMSLOTS 5 +#define PYGAMEAPI_JOYSTICK_NUMSLOTS 2 +#define PYGAMEAPI_DISPLAY_NUMSLOTS 2 +#define PYGAMEAPI_SURFACE_NUMSLOTS 4 +#define PYGAMEAPI_SURFLOCK_NUMSLOTS 8 +#define PYGAMEAPI_RWOBJECT_NUMSLOTS 7 +#define PYGAMEAPI_PIXELARRAY_NUMSLOTS 2 +#define PYGAMEAPI_COLOR_NUMSLOTS 5 +#define PYGAMEAPI_MATH_NUMSLOTS 2 +#define PYGAMEAPI_CDROM_NUMSLOTS 2 +#define PYGAMEAPI_BASE_NUMSLOTS 24 +#define PYGAMEAPI_EVENT_NUMSLOTS 6 + +#endif /* _PYGAME_INTERNAL_H */ diff --git a/venv/Include/site/python3.9/pygame/_surface.h b/venv/Include/site/python3.9/pygame/_surface.h new file mode 100644 index 0000000..b2b4644 --- /dev/null +++ b/venv/Include/site/python3.9/pygame/_surface.h @@ -0,0 +1,30 @@ +/* + pygame - Python Game Library + Copyright (C) 2000-2001 Pete Shinners + Copyright (C) 2007 Marcus von Appen + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Pete Shinners + pete@shinners.org +*/ + +#ifndef _SURFACE_H +#define _SURFACE_H + +#include "_pygame.h" +#include "surface.h" + +#endif diff --git a/venv/Include/site/python3.9/pygame/camera.h b/venv/Include/site/python3.9/pygame/camera.h new file mode 100644 index 0000000..6806dfe --- /dev/null +++ b/venv/Include/site/python3.9/pygame/camera.h @@ -0,0 +1,252 @@ +#ifndef CAMERA_H +#define CAMERA_H +/* + pygame - Python Game Library + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "pygame.h" +#include "pgcompat.h" +#include "doc/camera_doc.h" + +#if defined(__unix__) +#include +#include +#include +#include +#include + +#include /* low-level i/o */ +#include +#include +#include +#include +#include +#include +#include + +/* on freebsd there is no asm/types */ +#ifdef linux +#include /* for videodev2.h */ +#endif + +#include +#endif + +#if defined(__WIN32__) +#define PYGAME_WINDOWS_CAMERA 1 + +#include +#include +#include +#include +#include +#include +#endif + +/* some constants used which are not defined on non-v4l machines. */ +#ifndef V4L2_PIX_FMT_RGB24 +#define V4L2_PIX_FMT_RGB24 'RGB3' +#endif +#ifndef V4L2_PIX_FMT_RGB444 +#define V4L2_PIX_FMT_RGB444 'R444' +#endif +#ifndef V4L2_PIX_FMT_YUYV +#define V4L2_PIX_FMT_YUYV 'YUYV' +#endif +#ifndef V4L2_PIX_FMT_XBGR32 +#define V4L2_PIX_FMT_XBGR32 'XR24' +#endif + +#define CLEAR(x) memset(&(x), 0, sizeof(x)) +#define SAT(c) \ + if (c & (~255)) { \ + if (c < 0) \ + c = 0; \ + else \ + c = 255; \ + } +#define SAT2(c) ((c) & (~255) ? ((c) < 0 ? 0 : 255) : (c)) +#define DEFAULT_WIDTH 640 +#define DEFAULT_HEIGHT 480 +#define RGB_OUT 1 +#define YUV_OUT 2 +#define HSV_OUT 4 +#define CAM_V4L \ + 1 /* deprecated. the incomplete support in pygame was removed */ +#define CAM_V4L2 2 + +struct buffer { + void *start; + size_t length; +}; + +#if defined(__unix__) +typedef struct pgCameraObject { + PyObject_HEAD char *device_name; + int camera_type; + unsigned long pixelformat; + unsigned int color_out; + struct buffer *buffers; + unsigned int n_buffers; + int width; + int height; + int size; + int hflip; + int vflip; + int brightness; + int fd; +} pgCameraObject; +#elif defined(PYGAME_WINDOWS_CAMERA) +typedef struct pgCameraObject { + PyObject_HEAD WCHAR *device_name; + IMFSourceReader *reader; + IMFTransform *transform; + IMFVideoProcessorControl *control; + IMFMediaBuffer *buf; + IMFMediaBuffer *raw_buf; + int buffer_ready; + short open; /* used to signal the update_function to exit */ + HANDLE t_handle; + HRESULT t_error; + int t_error_line; + int width; + int height; + int hflip; + int vflip; + int last_vflip; + int color_out; + unsigned long pixelformat; +} pgCameraObject; + +#else +/* generic definition. + */ + +typedef struct pgCameraObject { + PyObject_HEAD char *device_name; + int camera_type; + unsigned long pixelformat; + unsigned int color_out; + struct buffer *buffers; + unsigned int n_buffers; + int width; + int height; + int size; + int hflip; + int vflip; + int brightness; + int fd; +} pgCameraObject; +#endif + +/* internal functions for colorspace conversion */ +void +colorspace(SDL_Surface *src, SDL_Surface *dst, int cspace); +void +rgb24_to_rgb(const void *src, void *dst, int length, SDL_PixelFormat *format); +void +bgr32_to_rgb(const void *src, void *dst, int length, SDL_PixelFormat *format); +void +rgb444_to_rgb(const void *src, void *dst, int length, SDL_PixelFormat *format); +void +rgb_to_yuv(const void *src, void *dst, int length, unsigned long source, + SDL_PixelFormat *format); +void +rgb_to_hsv(const void *src, void *dst, int length, unsigned long source, + SDL_PixelFormat *format); +void +yuyv_to_rgb(const void *src, void *dst, int length, SDL_PixelFormat *format); +void +yuyv_to_yuv(const void *src, void *dst, int length, SDL_PixelFormat *format); +void +uyvy_to_rgb(const void *src, void *dst, int length, SDL_PixelFormat *format); +void +uyvy_to_yuv(const void *src, void *dst, int length, SDL_PixelFormat *format); +void +sbggr8_to_rgb(const void *src, void *dst, int width, int height, + SDL_PixelFormat *format); +void +yuv420_to_rgb(const void *src, void *dst, int width, int height, + SDL_PixelFormat *format); +void +yuv420_to_yuv(const void *src, void *dst, int width, int height, + SDL_PixelFormat *format); + +#if defined(__unix__) +/* internal functions specific to v4l2 */ +char ** +v4l2_list_cameras(int *num_devices); +int +v4l2_get_control(int fd, int id, int *value); +int +v4l2_set_control(int fd, int id, int value); +PyObject * +v4l2_read_raw(pgCameraObject *self); +int +v4l2_xioctl(int fd, int request, void *arg); +int +v4l2_process_image(pgCameraObject *self, const void *image, + unsigned int buffer_size, SDL_Surface *surf); +int +v4l2_query_buffer(pgCameraObject *self); +int +v4l2_read_frame(pgCameraObject *self, SDL_Surface *surf); +int +v4l2_stop_capturing(pgCameraObject *self); +int +v4l2_start_capturing(pgCameraObject *self); +int +v4l2_uninit_device(pgCameraObject *self); +int +v4l2_init_mmap(pgCameraObject *self); +int +v4l2_init_device(pgCameraObject *self); +int +v4l2_close_device(pgCameraObject *self); +int +v4l2_open_device(pgCameraObject *self); + +#elif defined(PYGAME_WINDOWS_CAMERA) +/* internal functions specific to WINDOWS */ +WCHAR ** +windows_list_cameras(int *num_devices); +int +windows_init_device(pgCameraObject *self); +int +windows_open_device(pgCameraObject *self); +IMFActivate * +windows_device_from_name(WCHAR *device_name); +int +windows_close_device(pgCameraObject *self); +int +windows_read_frame(pgCameraObject *self, SDL_Surface *surf); +int +windows_frame_ready(pgCameraObject *self, int *result); +PyObject * +windows_read_raw(pgCameraObject *self); +int +windows_process_image(pgCameraObject *self, BYTE *data, DWORD buffer_size, + SDL_Surface *surf); +void +windows_dealloc_device(pgCameraObject *self); +int +windows_init_device(pgCameraObject *self); + +#endif + +#endif /* !CAMERA_H */ diff --git a/venv/Include/site/python3.9/pygame/font.h b/venv/Include/site/python3.9/pygame/font.h new file mode 100644 index 0000000..f5eedb2 --- /dev/null +++ b/venv/Include/site/python3.9/pygame/font.h @@ -0,0 +1,15 @@ +#ifndef PGFONT_INTERNAL_H +#define PGFONT_INTERNAL_H + +#include + +/* test font initialization */ +#define FONT_INIT_CHECK() \ + if (!(*(int *)PyFONT_C_API[2])) \ + return RAISE(pgExc_SDLError, "font system not initialized") + +#include "include/pygame_font.h" + +#define PYGAMEAPI_FONT_NUMSLOTS 3 + +#endif /* ~PGFONT_INTERNAL_H */ diff --git a/venv/Include/site/python3.9/pygame/freetype.h b/venv/Include/site/python3.9/pygame/freetype.h new file mode 100644 index 0000000..fd86bc2 --- /dev/null +++ b/venv/Include/site/python3.9/pygame/freetype.h @@ -0,0 +1,114 @@ +/* + pygame - Python Game Library + Copyright (C) 2009 Vicent Marti + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +#ifndef _PYGAME_FREETYPE_INTERNAL_H_ +#define _PYGAME_FREETYPE_INTERNAL_H_ + +#include "pgcompat.h" +#include "pgplatform.h" + +#include +#include FT_FREETYPE_H +#include FT_CACHE_H +#include FT_XFREE86_H +#include FT_TRIGONOMETRY_H + +/********************************************************** + * Global module constants + **********************************************************/ + +/* Render styles */ +#define FT_STYLE_NORMAL 0x00 +#define FT_STYLE_STRONG 0x01 +#define FT_STYLE_OBLIQUE 0x02 +#define FT_STYLE_UNDERLINE 0x04 +#define FT_STYLE_WIDE 0x08 +#define FT_STYLE_DEFAULT 0xFF + +/* Bounding box modes */ +#define FT_BBOX_EXACT FT_GLYPH_BBOX_SUBPIXELS +#define FT_BBOX_EXACT_GRIDFIT FT_GLYPH_BBOX_GRIDFIT +#define FT_BBOX_PIXEL FT_GLYPH_BBOX_TRUNCATE +#define FT_BBOX_PIXEL_GRIDFIT FT_GLYPH_BBOX_PIXELS + +/* Rendering flags */ +#define FT_RFLAG_NONE (0) +#define FT_RFLAG_ANTIALIAS (1 << 0) +#define FT_RFLAG_AUTOHINT (1 << 1) +#define FT_RFLAG_VERTICAL (1 << 2) +#define FT_RFLAG_HINTED (1 << 3) +#define FT_RFLAG_KERNING (1 << 4) +#define FT_RFLAG_TRANSFORM (1 << 5) +#define FT_RFLAG_PAD (1 << 6) +#define FT_RFLAG_ORIGIN (1 << 7) +#define FT_RFLAG_UCS4 (1 << 8) +#define FT_RFLAG_USE_BITMAP_STRIKES (1 << 9) +#define FT_RFLAG_DEFAULTS \ + (FT_RFLAG_HINTED | FT_RFLAG_USE_BITMAP_STRIKES | FT_RFLAG_ANTIALIAS) + +#define FT_RENDER_NEWBYTEARRAY 0x0 +#define FT_RENDER_NEWSURFACE 0x1 +#define FT_RENDER_EXISTINGSURFACE 0x2 + +/********************************************************** + * Global module types + **********************************************************/ + +typedef struct _scale_s { + FT_UInt x, y; +} Scale_t; +typedef FT_Angle Angle_t; + +struct fontinternals_; +struct freetypeinstance_; + +typedef struct { + FT_Long font_index; + FT_Open_Args open_args; +} pgFontId; + +typedef struct { + PyObject_HEAD pgFontId id; + PyObject *path; + int is_scalable; + int is_bg_col_set; + + Scale_t face_size; + FT_Int16 style; + FT_Int16 render_flags; + double strength; + double underline_adjustment; + FT_UInt resolution; + Angle_t rotation; + FT_Matrix transform; + FT_Byte fgcolor[4]; + FT_Byte bgcolor[4]; + + struct freetypeinstance_ *freetype; /* Personal reference */ + struct fontinternals_ *_internals; +} pgFontObject; + +#define pgFont_IS_ALIVE(o) (((pgFontObject *)(o))->_internals != 0) + +/* import public API */ +#include "include/pygame_freetype.h" + +#define PYGAMEAPI_FREETYPE_NUMSLOTS 2 + +#endif /* ~_PYGAME_FREETYPE_INTERNAL_H_ */ diff --git a/venv/Include/site/python3.9/pygame/include/_pygame.h b/venv/Include/site/python3.9/pygame/include/_pygame.h new file mode 100644 index 0000000..9817f96 --- /dev/null +++ b/venv/Include/site/python3.9/pygame/include/_pygame.h @@ -0,0 +1,497 @@ +/* + pygame - Python Game Library + Copyright (C) 2000-2001 Pete Shinners + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Pete Shinners + pete@shinners.org +*/ + +#ifndef _PYGAME_H +#define _PYGAME_H + +/** This header file includes all the definitions for the + ** base pygame extensions. This header only requires + ** Python includes (and SDL.h for functions that use SDL types). + ** The reason for functions prototyped with #define's is + ** to allow for maximum Python portability. It also uses + ** Python as the runtime linker, which allows for late binding. + '' For more information on this style of development, read + ** the Python docs on this subject. + ** http://www.python.org/doc/current/ext/using-cobjects.html + ** + ** If using this to build your own derived extensions, + ** you'll see that the functions available here are mainly + ** used to help convert between python objects and SDL objects. + ** Since this library doesn't add a lot of functionality to + ** the SDL library, it doesn't need to offer a lot either. + ** + ** When initializing your extension module, you must manually + ** import the modules you want to use. (this is the part about + ** using python as the runtime linker). Each module has its + ** own import_xxx() routine. You need to perform this import + ** after you have initialized your own module, and before + ** you call any routines from that module. Since every module + ** in pygame does this, there are plenty of examples. + ** + ** The base module does include some useful conversion routines + ** that you are free to use in your own extension. + **/ + +#include "pgplatform.h" +#include + +/* version macros (defined since version 1.9.5) */ +#define PG_MAJOR_VERSION 2 +#define PG_MINOR_VERSION 1 +#define PG_PATCH_VERSION 2 +#define PG_VERSIONNUM(MAJOR, MINOR, PATCH) \ + (1000 * (MAJOR) + 100 * (MINOR) + (PATCH)) +#define PG_VERSION_ATLEAST(MAJOR, MINOR, PATCH) \ + (PG_VERSIONNUM(PG_MAJOR_VERSION, PG_MINOR_VERSION, PG_PATCH_VERSION) >= \ + PG_VERSIONNUM(MAJOR, MINOR, PATCH)) + +#include "pgcompat.h" + +/* Flag indicating a pg_buffer; used for assertions within callbacks */ +#ifndef NDEBUG +#define PyBUF_PYGAME 0x4000 +#endif +#define PyBUF_HAS_FLAG(f, F) (((f) & (F)) == (F)) + +/* Array information exchange struct C type; inherits from Py_buffer + * + * Pygame uses its own Py_buffer derived C struct as an internal representation + * of an imported array buffer. The extended Py_buffer allows for a + * per-instance release callback, + */ +typedef void (*pybuffer_releaseproc)(Py_buffer *); + +typedef struct pg_bufferinfo_s { + Py_buffer view; + PyObject *consumer; /* Input: Borrowed reference */ + pybuffer_releaseproc release_buffer; +} pg_buffer; + +#include "pgimport.h" + +/* + * BASE module + */ +#ifndef PYGAMEAPI_BASE_INTERNAL +#define pgExc_SDLError ((PyObject *)PYGAMEAPI_GET_SLOT(base, 0)) + +#define pg_RegisterQuit \ + (*(void (*)(void (*)(void)))PYGAMEAPI_GET_SLOT(base, 1)) + +#define pg_IntFromObj \ + (*(int (*)(PyObject *, int *))PYGAMEAPI_GET_SLOT(base, 2)) + +#define pg_IntFromObjIndex \ + (*(int (*)(PyObject *, int, int *))PYGAMEAPI_GET_SLOT(base, 3)) + +#define pg_TwoIntsFromObj \ + (*(int (*)(PyObject *, int *, int *))PYGAMEAPI_GET_SLOT(base, 4)) + +#define pg_FloatFromObj \ + (*(int (*)(PyObject *, float *))PYGAMEAPI_GET_SLOT(base, 5)) + +#define pg_FloatFromObjIndex \ + (*(int (*)(PyObject *, int, float *))PYGAMEAPI_GET_SLOT(base, 6)) + +#define pg_TwoFloatsFromObj \ + (*(int (*)(PyObject *, float *, float *))PYGAMEAPI_GET_SLOT(base, 7)) + +#define pg_UintFromObj \ + (*(int (*)(PyObject *, Uint32 *))PYGAMEAPI_GET_SLOT(base, 8)) + +#define pg_UintFromObjIndex \ + (*(int (*)(PyObject *, int, Uint32 *))PYGAMEAPI_GET_SLOT(base, 9)) + +#define pg_mod_autoinit (*(int (*)(const char *))PYGAMEAPI_GET_SLOT(base, 10)) + +#define pg_mod_autoquit (*(void (*)(const char *))PYGAMEAPI_GET_SLOT(base, 11)) + +#define pg_RGBAFromObj \ + (*(int (*)(PyObject *, Uint8 *))PYGAMEAPI_GET_SLOT(base, 12)) + +#define pgBuffer_AsArrayInterface \ + (*(PyObject * (*)(Py_buffer *)) PYGAMEAPI_GET_SLOT(base, 13)) + +#define pgBuffer_AsArrayStruct \ + (*(PyObject * (*)(Py_buffer *)) PYGAMEAPI_GET_SLOT(base, 14)) + +#define pgObject_GetBuffer \ + (*(int (*)(PyObject *, pg_buffer *, int))PYGAMEAPI_GET_SLOT(base, 15)) + +#define pgBuffer_Release (*(void (*)(pg_buffer *))PYGAMEAPI_GET_SLOT(base, 16)) + +#define pgDict_AsBuffer \ + (*(int (*)(pg_buffer *, PyObject *, int))PYGAMEAPI_GET_SLOT(base, 17)) + +#define pgExc_BufferError ((PyObject *)PYGAMEAPI_GET_SLOT(base, 18)) + +#define pg_GetDefaultWindow \ + (*(SDL_Window * (*)(void)) PYGAMEAPI_GET_SLOT(base, 19)) + +#define pg_SetDefaultWindow \ + (*(void (*)(SDL_Window *))PYGAMEAPI_GET_SLOT(base, 20)) + +#define pg_GetDefaultWindowSurface \ + (*(pgSurfaceObject * (*)(void)) PYGAMEAPI_GET_SLOT(base, 21)) + +#define pg_SetDefaultWindowSurface \ + (*(void (*)(pgSurfaceObject *))PYGAMEAPI_GET_SLOT(base, 22)) + +#define pg_EnvShouldBlendAlphaSDL2 \ + (*(char *(*)(void))PYGAMEAPI_GET_SLOT(base, 23)) + +#define import_pygame_base() IMPORT_PYGAME_MODULE(base) +#endif /* ~PYGAMEAPI_BASE_INTERNAL */ + +typedef struct { + PyObject_HEAD SDL_Rect r; + PyObject *weakreflist; +} pgRectObject; + +#define pgRect_AsRect(x) (((pgRectObject *)x)->r) +#ifndef PYGAMEAPI_RECT_INTERNAL +#define pgRect_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(rect, 0)) + +#define pgRect_Check(x) ((x)->ob_type == &pgRect_Type) +#define pgRect_New (*(PyObject * (*)(SDL_Rect *)) PYGAMEAPI_GET_SLOT(rect, 1)) + +#define pgRect_New4 \ + (*(PyObject * (*)(int, int, int, int)) PYGAMEAPI_GET_SLOT(rect, 2)) + +#define pgRect_FromObject \ + (*(SDL_Rect * (*)(PyObject *, SDL_Rect *)) PYGAMEAPI_GET_SLOT(rect, 3)) + +#define pgRect_Normalize (*(void (*)(SDL_Rect *))PYGAMEAPI_GET_SLOT(rect, 4)) + +#define import_pygame_rect() IMPORT_PYGAME_MODULE(rect) +#endif /* ~PYGAMEAPI_RECT_INTERNAL */ + +/* + * CDROM module + */ + +typedef struct { + PyObject_HEAD int id; +} pgCDObject; + +#define pgCD_AsID(x) (((pgCDObject *)x)->id) +#ifndef PYGAMEAPI_CDROM_INTERNAL +#define pgCD_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(cdrom, 0)) + +#define pgCD_Check(x) ((x)->ob_type == &pgCD_Type) +#define pgCD_New (*(PyObject * (*)(int)) PYGAMEAPI_GET_SLOT(cdrom, 1)) + +#define import_pygame_cd() IMPORT_PYGAME_MODULE(cdrom) +#endif + +/* + * JOYSTICK module + */ +typedef struct pgJoystickObject { + PyObject_HEAD int id; + SDL_Joystick *joy; + + /* Joysticks form an intrusive linked list. + * + * Note that we don't maintain refcounts for these so they are weakrefs + * from the Python side. + */ + struct pgJoystickObject *next; + struct pgJoystickObject *prev; +} pgJoystickObject; + +#define pgJoystick_AsID(x) (((pgJoystickObject *)x)->id) +#define pgJoystick_AsSDL(x) (((pgJoystickObject *)x)->joy) + +#ifndef PYGAMEAPI_JOYSTICK_INTERNAL +#define pgJoystick_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(joystick, 0)) + +#define pgJoystick_Check(x) ((x)->ob_type == &pgJoystick_Type) +#define pgJoystick_New (*(PyObject * (*)(int)) PYGAMEAPI_GET_SLOT(joystick, 1)) + +#define import_pygame_joystick() IMPORT_PYGAME_MODULE(joystick) +#endif + +/* + * DISPLAY module + */ + +typedef struct { + Uint32 hw_available : 1; + Uint32 wm_available : 1; + Uint32 blit_hw : 1; + Uint32 blit_hw_CC : 1; + Uint32 blit_hw_A : 1; + Uint32 blit_sw : 1; + Uint32 blit_sw_CC : 1; + Uint32 blit_sw_A : 1; + Uint32 blit_fill : 1; + Uint32 video_mem; + SDL_PixelFormat *vfmt; + SDL_PixelFormat vfmt_data; + int current_w; + int current_h; +} pg_VideoInfo; + +typedef struct { + PyObject_HEAD pg_VideoInfo info; +} pgVidInfoObject; + +#define pgVidInfo_AsVidInfo(x) (((pgVidInfoObject *)x)->info) + +#ifndef PYGAMEAPI_DISPLAY_INTERNAL +#define pgVidInfo_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(display, 0)) + +#define pgVidInfo_Check(x) ((x)->ob_type == &pgVidInfo_Type) +#define pgVidInfo_New \ + (*(PyObject * (*)(pg_VideoInfo *)) PYGAMEAPI_GET_SLOT(display, 1)) + +#define import_pygame_display() IMPORT_PYGAME_MODULE(display) +#endif /* ~PYGAMEAPI_DISPLAY_INTERNAL */ + +/* + * SURFACE module + */ +struct pgSubSurface_Data; +struct SDL_Surface; + +typedef struct { + PyObject_HEAD struct SDL_Surface *surf; + int owner; + struct pgSubSurface_Data *subsurface; /* ptr to subsurface data (if a + * subsurface)*/ + PyObject *weakreflist; + PyObject *locklist; + PyObject *dependency; +} pgSurfaceObject; +#define pgSurface_AsSurface(x) (((pgSurfaceObject *)x)->surf) + +#ifndef PYGAMEAPI_SURFACE_INTERNAL +#define pgSurface_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(surface, 0)) + +#define pgSurface_Check(x) \ + (PyObject_IsInstance((x), (PyObject *)&pgSurface_Type)) +#define pgSurface_New2 \ + (*(pgSurfaceObject * (*)(SDL_Surface *, int)) \ + PYGAMEAPI_GET_SLOT(surface, 1)) + +#define pgSurface_SetSurface \ + (*(int (*)(pgSurfaceObject *, SDL_Surface *, int))PYGAMEAPI_GET_SLOT( \ + surface, 3)) + +#define pgSurface_Blit \ + (*(int (*)(pgSurfaceObject *, pgSurfaceObject *, SDL_Rect *, SDL_Rect *, \ + int))PYGAMEAPI_GET_SLOT(surface, 2)) + +#define import_pygame_surface() \ + do { \ + IMPORT_PYGAME_MODULE(surface); \ + if (PyErr_Occurred() != NULL) \ + break; \ + IMPORT_PYGAME_MODULE(surflock); \ + } while (0) + +#define pgSurface_New(surface) pgSurface_New2((surface), 1) +#define pgSurface_NewNoOwn(surface) pgSurface_New2((surface), 0) + +#endif /* ~PYGAMEAPI_SURFACE_INTERNAL */ + +/* + * SURFLOCK module + * auto imported/initialized by surface + */ +#ifndef PYGAMEAPI_SURFLOCK_INTERNAL +#define pgLifetimeLock_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(surflock, 0)) + +#define pgLifetimeLock_Check(x) ((x)->ob_type == &pgLifetimeLock_Type) + +#define pgSurface_Prep(x) \ + if ((x)->subsurface) \ + (*(*(void (*)(pgSurfaceObject *))PYGAMEAPI_GET_SLOT(surflock, 1)))(x) + +#define pgSurface_Unprep(x) \ + if ((x)->subsurface) \ + (*(*(void (*)(pgSurfaceObject *))PYGAMEAPI_GET_SLOT(surflock, 2)))(x) + +#define pgSurface_Lock \ + (*(int (*)(pgSurfaceObject *))PYGAMEAPI_GET_SLOT(surflock, 3)) + +#define pgSurface_Unlock \ + (*(int (*)(pgSurfaceObject *))PYGAMEAPI_GET_SLOT(surflock, 4)) + +#define pgSurface_LockBy \ + (*(int (*)(pgSurfaceObject *, PyObject *))PYGAMEAPI_GET_SLOT(surflock, 5)) + +#define pgSurface_UnlockBy \ + (*(int (*)(pgSurfaceObject *, PyObject *))PYGAMEAPI_GET_SLOT(surflock, 6)) + +#define pgSurface_LockLifetime \ + (*(PyObject * (*)(PyObject *, PyObject *)) PYGAMEAPI_GET_SLOT(surflock, 7)) +#endif + +/* + * EVENT module + */ +typedef struct pgEventObject pgEventObject; + +#ifndef PYGAMEAPI_EVENT_INTERNAL +#define pgEvent_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(event, 0)) + +#define pgEvent_Check(x) ((x)->ob_type == &pgEvent_Type) + +#define pgEvent_New \ + (*(PyObject * (*)(SDL_Event *)) PYGAMEAPI_GET_SLOT(event, 1)) + +#define pgEvent_New2 \ + (*(PyObject * (*)(int, PyObject *)) PYGAMEAPI_GET_SLOT(event, 2)) + +#define pgEvent_FillUserEvent \ + (*(int (*)(pgEventObject *, SDL_Event *))PYGAMEAPI_GET_SLOT(event, 3)) + +#define pg_EnableKeyRepeat (*(int (*)(int, int))PYGAMEAPI_GET_SLOT(event, 4)) + +#define pg_GetKeyRepeat (*(void (*)(int *, int *))PYGAMEAPI_GET_SLOT(event, 5)) + +#define import_pygame_event() IMPORT_PYGAME_MODULE(event) +#endif + +/* + * RWOBJECT module + * the rwobject are only needed for C side work, not accessable from python. + */ +#ifndef PYGAMEAPI_RWOBJECT_INTERNAL +#define pgRWops_FromObject \ + (*(SDL_RWops * (*)(PyObject *)) PYGAMEAPI_GET_SLOT(rwobject, 0)) + +#define pgRWops_IsFileObject \ + (*(int (*)(SDL_RWops *))PYGAMEAPI_GET_SLOT(rwobject, 1)) + +#define pg_EncodeFilePath \ + (*(PyObject * (*)(PyObject *, PyObject *)) PYGAMEAPI_GET_SLOT(rwobject, 2)) + +#define pg_EncodeString \ + (*(PyObject * (*)(PyObject *, const char *, const char *, PyObject *)) \ + PYGAMEAPI_GET_SLOT(rwobject, 3)) + +#define pgRWops_FromFileObject \ + (*(SDL_RWops * (*)(PyObject *)) PYGAMEAPI_GET_SLOT(rwobject, 4)) + +#define pgRWops_ReleaseObject \ + (*(int (*)(SDL_RWops *))PYGAMEAPI_GET_SLOT(rwobject, 5)) + +#define pgRWops_GetFileExtension \ + (*(char *(*)(SDL_RWops *))PYGAMEAPI_GET_SLOT(rwobject, 6)) + +#define import_pygame_rwobject() IMPORT_PYGAME_MODULE(rwobject) + +#endif + +/* + * PixelArray module + */ +#ifndef PYGAMEAPI_PIXELARRAY_INTERNAL +#define PyPixelArray_Type ((PyTypeObject *)PYGAMEAPI_GET_SLOT(pixelarray, 0)) + +#define PyPixelArray_Check(x) ((x)->ob_type == &PyPixelArray_Type) +#define PyPixelArray_New (*(PyObject * (*)) PYGAMEAPI_GET_SLOT(pixelarray, 1)) + +#define import_pygame_pixelarray() IMPORT_PYGAME_MODULE(pixelarray) +#endif /* PYGAMEAPI_PIXELARRAY_INTERNAL */ + +/* + * Color module + */ +typedef struct pgColorObject pgColorObject; + +#ifndef PYGAMEAPI_COLOR_INTERNAL +#define pgColor_Type (*(PyObject *)PYGAMEAPI_GET_SLOT(color, 0)) + +#define pgColor_Check(x) ((x)->ob_type == &pgColor_Type) +#define pgColor_New (*(PyObject * (*)(Uint8 *)) PYGAMEAPI_GET_SLOT(color, 1)) + +#define pgColor_NewLength \ + (*(PyObject * (*)(Uint8 *, Uint8)) PYGAMEAPI_GET_SLOT(color, 3)) + +#define pg_RGBAFromColorObj \ + (*(int (*)(PyObject *, Uint8 *))PYGAMEAPI_GET_SLOT(color, 2)) + +#define pg_RGBAFromFuzzyColorObj \ + (*(int (*)(PyObject *, Uint8 *))PYGAMEAPI_GET_SLOT(color, 4)) + +#define pgColor_AsArray(x) (((pgColorObject *)x)->data) +#define pgColor_NumComponents(x) (((pgColorObject *)x)->len) + +#define import_pygame_color() IMPORT_PYGAME_MODULE(color) +#endif /* PYGAMEAPI_COLOR_INTERNAL */ + +/* + * Math module + */ +#ifndef PYGAMEAPI_MATH_INTERNAL +#define pgVector2_Check(x) \ + ((x)->ob_type == (PyTypeObject *)PYGAMEAPI_GET_SLOT(math, 0)) + +#define pgVector3_Check(x) \ + ((x)->ob_type == (PyTypeObject *)PYGAMEAPI_GET_SLOT(math, 1)) +/* +#define pgVector2_New \ + (*(PyObject*(*)) \ + PYGAMEAPI_GET_SLOT(PyGAME_C_API, 1)) +*/ +#define import_pygame_math() IMPORT_PYGAME_MODULE(math) +#endif /* PYGAMEAPI_MATH_INTERNAL */ + +#define IMPORT_PYGAME_MODULE _IMPORT_PYGAME_MODULE + +/* + * base pygame API slots + * disable slots with NO_PYGAME_C_API + */ +#ifdef PYGAME_H +PYGAMEAPI_DEFINE_SLOTS(base); +PYGAMEAPI_DEFINE_SLOTS(rect); +PYGAMEAPI_DEFINE_SLOTS(cdrom); +PYGAMEAPI_DEFINE_SLOTS(joystick); +PYGAMEAPI_DEFINE_SLOTS(display); +PYGAMEAPI_DEFINE_SLOTS(surface); +PYGAMEAPI_DEFINE_SLOTS(surflock); +PYGAMEAPI_DEFINE_SLOTS(event); +PYGAMEAPI_DEFINE_SLOTS(rwobject); +PYGAMEAPI_DEFINE_SLOTS(pixelarray); +PYGAMEAPI_DEFINE_SLOTS(color); +PYGAMEAPI_DEFINE_SLOTS(math); +#else /* ~PYGAME_H */ +PYGAMEAPI_EXTERN_SLOTS(base); +PYGAMEAPI_EXTERN_SLOTS(rect); +PYGAMEAPI_EXTERN_SLOTS(cdrom); +PYGAMEAPI_EXTERN_SLOTS(joystick); +PYGAMEAPI_EXTERN_SLOTS(display); +PYGAMEAPI_EXTERN_SLOTS(surface); +PYGAMEAPI_EXTERN_SLOTS(surflock); +PYGAMEAPI_EXTERN_SLOTS(event); +PYGAMEAPI_EXTERN_SLOTS(rwobject); +PYGAMEAPI_EXTERN_SLOTS(pixelarray); +PYGAMEAPI_EXTERN_SLOTS(color); +PYGAMEAPI_EXTERN_SLOTS(math); +#endif /* ~PYGAME_H */ + +#endif /* PYGAME_H */ diff --git a/venv/Include/site/python3.9/pygame/include/bitmask.h b/venv/Include/site/python3.9/pygame/include/bitmask.h new file mode 100644 index 0000000..eee09b7 --- /dev/null +++ b/venv/Include/site/python3.9/pygame/include/bitmask.h @@ -0,0 +1,171 @@ +/* + Bitmask 1.7 - A pixel-perfect collision detection library. + + Copyright (C) 2002-2005 Ulf Ekstrom except for the bitcount + function which is copyright (C) Donald W. Gillies, 1992. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef BITMASK_H +#define BITMASK_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +/* Define INLINE for different compilers. If your compiler does not + support inlining then there might be a performance hit in + bitmask_overlap_area(). +*/ +#ifndef INLINE +#ifdef __GNUC__ +#define INLINE inline +#else +#ifdef _MSC_VER +#define INLINE __inline +#else +#define INLINE +#endif +#endif +#endif + +#define BITMASK_W unsigned long int +#define BITMASK_W_LEN (sizeof(BITMASK_W) * CHAR_BIT) +#define BITMASK_W_MASK (BITMASK_W_LEN - 1) +#define BITMASK_N(n) ((BITMASK_W)1 << (n)) + +typedef struct bitmask { + int w, h; + BITMASK_W bits[1]; +} bitmask_t; + +/* Creates a bitmask of width w and height h, where + w and h must both be greater than or equal to 0. + The mask is automatically cleared when created. + */ +bitmask_t * +bitmask_create(int w, int h); + +/* Frees all the memory allocated by bitmask_create for m. */ +void +bitmask_free(bitmask_t *m); + +/* Create a copy of the given bitmask. */ +bitmask_t * +bitmask_copy(bitmask_t *m); + +/* Clears all bits in the mask */ +void +bitmask_clear(bitmask_t *m); + +/* Sets all bits in the mask */ +void +bitmask_fill(bitmask_t *m); + +/* Flips all bits in the mask */ +void +bitmask_invert(bitmask_t *m); + +/* Counts the bits in the mask */ +unsigned int +bitmask_count(bitmask_t *m); + +/* Returns nonzero if the bit at (x,y) is set. Coordinates start at + (0,0) */ +static INLINE int +bitmask_getbit(const bitmask_t *m, int x, int y) +{ + return (m->bits[x / BITMASK_W_LEN * m->h + y] & + BITMASK_N(x & BITMASK_W_MASK)) != 0; +} + +/* Sets the bit at (x,y) */ +static INLINE void +bitmask_setbit(bitmask_t *m, int x, int y) +{ + m->bits[x / BITMASK_W_LEN * m->h + y] |= BITMASK_N(x & BITMASK_W_MASK); +} + +/* Clears the bit at (x,y) */ +static INLINE void +bitmask_clearbit(bitmask_t *m, int x, int y) +{ + m->bits[x / BITMASK_W_LEN * m->h + y] &= ~BITMASK_N(x & BITMASK_W_MASK); +} + +/* Returns nonzero if the masks overlap with the given offset. + The overlap tests uses the following offsets (which may be negative): + + +----+----------.. + |A | yoffset + | +-+----------.. + +--|B + |xoffset + | | + : : +*/ +int +bitmask_overlap(const bitmask_t *a, const bitmask_t *b, int xoffset, + int yoffset); + +/* Like bitmask_overlap(), but will also give a point of intersection. + x and y are given in the coordinates of mask a, and are untouched + if there is no overlap. */ +int +bitmask_overlap_pos(const bitmask_t *a, const bitmask_t *b, int xoffset, + int yoffset, int *x, int *y); + +/* Returns the number of overlapping 'pixels' */ +int +bitmask_overlap_area(const bitmask_t *a, const bitmask_t *b, int xoffset, + int yoffset); + +/* Fills a mask with the overlap of two other masks. A bitwise AND. */ +void +bitmask_overlap_mask(const bitmask_t *a, const bitmask_t *b, bitmask_t *c, + int xoffset, int yoffset); + +/* Draws mask b onto mask a (bitwise OR). Can be used to compose large + (game background?) mask from several submasks, which may speed up + the testing. */ + +void +bitmask_draw(bitmask_t *a, const bitmask_t *b, int xoffset, int yoffset); + +void +bitmask_erase(bitmask_t *a, const bitmask_t *b, int xoffset, int yoffset); + +/* Return a new scaled bitmask, with dimensions w*h. The quality of the + scaling may not be perfect for all circumstances, but it should + be reasonable. If either w or h is 0 a clear 1x1 mask is returned. */ +bitmask_t * +bitmask_scale(const bitmask_t *m, int w, int h); + +/* Convolve b into a, drawing the output into o, shifted by offset. If offset + * is 0, then the (x,y) bit will be set if and only if + * bitmask_overlap(a, b, x - b->w - 1, y - b->h - 1) returns true. + * + * Modifies bits o[xoffset ... xoffset + a->w + b->w - 1) + * [yoffset ... yoffset + a->h + b->h - 1). */ +void +bitmask_convolve(const bitmask_t *a, const bitmask_t *b, bitmask_t *o, + int xoffset, int yoffset); + +#ifdef __cplusplus +} /* End of extern "C" { */ +#endif + +#endif diff --git a/venv/Include/site/python3.9/pygame/include/pgcompat.h b/venv/Include/site/python3.9/pygame/include/pgcompat.h new file mode 100644 index 0000000..4a11ca0 --- /dev/null +++ b/venv/Include/site/python3.9/pygame/include/pgcompat.h @@ -0,0 +1,108 @@ +/* Python 2.x/3.x and SDL compatibility tools + */ + +#if !defined(PGCOMPAT_H) +#define PGCOMPAT_H + +#include + +/* define common types where SDL is not included */ +#ifndef SDL_VERSION_ATLEAST +#ifdef _MSC_VER +typedef unsigned __int8 uint8_t; +typedef unsigned __int32 uint32_t; +#else +#include +#endif +typedef uint32_t Uint32; +typedef uint8_t Uint8; +#endif /* no SDL */ + +#if defined(SDL_VERSION_ATLEAST) + +#ifndef SDL_WINDOW_VULKAN +#define SDL_WINDOW_VULKAN 0 +#endif + +#ifndef SDL_WINDOW_ALWAYS_ON_TOP +#define SDL_WINDOW_ALWAYS_ON_TOP 0 +#endif + +#ifndef SDL_WINDOW_SKIP_TASKBAR +#define SDL_WINDOW_SKIP_TASKBAR 0 +#endif + +#ifndef SDL_WINDOW_UTILITY +#define SDL_WINDOW_UTILITY 0 +#endif + +#ifndef SDL_WINDOW_TOOLTIP +#define SDL_WINDOW_TOOLTIP 0 +#endif + +#ifndef SDL_WINDOW_POPUP_MENU +#define SDL_WINDOW_POPUP_MENU 0 +#endif + +#ifndef SDL_WINDOW_INPUT_GRABBED +#define SDL_WINDOW_INPUT_GRABBED 0 +#endif + +#ifndef SDL_WINDOW_INPUT_FOCUS +#define SDL_WINDOW_INPUT_FOCUS 0 +#endif + +#ifndef SDL_WINDOW_MOUSE_FOCUS +#define SDL_WINDOW_MOUSE_FOCUS 0 +#endif + +#ifndef SDL_WINDOW_FOREIGN +#define SDL_WINDOW_FOREIGN 0 +#endif + +#ifndef SDL_WINDOW_ALLOW_HIGHDPI +#define SDL_WINDOW_ALLOW_HIGHDPI 0 +#endif + +#ifndef SDL_WINDOW_MOUSE_CAPTURE +#define SDL_WINDOW_MOUSE_CAPTURE 0 +#endif + +#ifndef SDL_WINDOW_ALWAYS_ON_TOP +#define SDL_WINDOW_ALWAYS_ON_TOP 0 +#endif + +#ifndef SDL_WINDOW_SKIP_TASKBAR +#define SDL_WINDOW_SKIP_TASKBAR 0 +#endif + +#ifndef SDL_WINDOW_UTILITY +#define SDL_WINDOW_UTILITY 0 +#endif + +#ifndef SDL_WINDOW_TOOLTIP +#define SDL_WINDOW_TOOLTIP 0 +#endif + +#ifndef SDL_WINDOW_POPUP_MENU +#define SDL_WINDOW_POPUP_MENU 0 +#endif + +#if SDL_VERSION_ATLEAST(2, 0, 4) +/* To control the use of: + * SDL_AUDIODEVICEADDED + * SDL_AUDIODEVICEREMOVED + * + * Ref: https://wiki.libsdl.org/SDL_EventType + * Ref: https://wiki.libsdl.org/SDL_AudioDeviceEvent + */ +#define SDL2_AUDIODEVICE_SUPPORTED +#endif + +#ifndef SDL_MOUSEWHEEL_FLIPPED +#define NO_SDL_MOUSEWHEEL_FLIPPED +#endif + +#endif /* defined(SDL_VERSION_ATLEAST) */ + +#endif /* ~defined(PGCOMPAT_H) */ diff --git a/venv/Include/site/python3.9/pygame/include/pgimport.h b/venv/Include/site/python3.9/pygame/include/pgimport.h new file mode 100644 index 0000000..16a36db --- /dev/null +++ b/venv/Include/site/python3.9/pygame/include/pgimport.h @@ -0,0 +1,80 @@ +#ifndef PGIMPORT_H +#define PGIMPORT_H + +/* Prefix when initializing module */ +#define MODPREFIX "" +/* Prefix when importing module */ +#define IMPPREFIX "pygame." + +#ifdef __SYMBIAN32__ + +/* On Symbian there is no pygame package. The extensions are built-in or in + * sys\bin. */ +#undef MODPREFIX +#undef IMPPREFIX +#define MODPREFIX "pygame_" +#define IMPPREFIX "pygame_" + +#endif /* __SYMBIAN32__ */ + +#include "pgcompat.h" + +#define PYGAMEAPI_LOCAL_ENTRY "_PYGAME_C_API" +#define PG_CAPSULE_NAME(m) (IMPPREFIX m "." PYGAMEAPI_LOCAL_ENTRY) + +/* + * fill API slots defined by PYGAMEAPI_DEFINE_SLOTS/PYGAMEAPI_EXTERN_SLOTS + */ +#define _IMPORT_PYGAME_MODULE(module) \ + { \ + PyObject *_mod_##module = PyImport_ImportModule(IMPPREFIX #module); \ + \ + if (_mod_##module != NULL) { \ + PyObject *_c_api = \ + PyObject_GetAttrString(_mod_##module, PYGAMEAPI_LOCAL_ENTRY); \ + \ + Py_DECREF(_mod_##module); \ + if (_c_api != NULL && PyCapsule_CheckExact(_c_api)) { \ + void **localptr = (void **)PyCapsule_GetPointer( \ + _c_api, PG_CAPSULE_NAME(#module)); \ + _PGSLOTS_##module = localptr; \ + } \ + Py_XDECREF(_c_api); \ + } \ + } + +#define PYGAMEAPI_IS_IMPORTED(module) (_PGSLOTS_##module != NULL) + +/* + * source file must include one of these in order to use _IMPORT_PYGAME_MODULE. + * this is set by import_pygame_*() functions. + * disable with NO_PYGAME_C_API + */ +#define PYGAMEAPI_DEFINE_SLOTS(module) void **_PGSLOTS_##module = NULL +#define PYGAMEAPI_EXTERN_SLOTS(module) extern void **_PGSLOTS_##module +#define PYGAMEAPI_GET_SLOT(module, index) _PGSLOTS_##module[(index)] + +/* + * disabled API with NO_PYGAME_C_API; do nothing instead + */ +#ifdef NO_PYGAME_C_API + +#undef PYGAMEAPI_DEFINE_SLOTS +#undef PYGAMEAPI_EXTERN_SLOTS + +#define PYGAMEAPI_DEFINE_SLOTS(module) +#define PYGAMEAPI_EXTERN_SLOTS(module) + +/* intentionally leave this defined to cause a compiler error * +#define PYGAMEAPI_GET_SLOT(api_root, index) +#undef PYGAMEAPI_GET_SLOT*/ + +#undef _IMPORT_PYGAME_MODULE +#define _IMPORT_PYGAME_MODULE(module) + +#endif /* NO_PYGAME_C_API */ + +#define encapsulate_api(ptr, module) \ + PyCapsule_New(ptr, PG_CAPSULE_NAME(module), NULL) + +#endif /* ~PGIMPORT_H */ diff --git a/venv/Include/site/python3.9/pygame/include/pgplatform.h b/venv/Include/site/python3.9/pygame/include/pgplatform.h new file mode 100644 index 0000000..c73cc24 --- /dev/null +++ b/venv/Include/site/python3.9/pygame/include/pgplatform.h @@ -0,0 +1,92 @@ +/* platform/compiler adjustments */ +#ifndef PG_PLATFORM_H +#define PG_PLATFORM_H + +#if defined(HAVE_SNPRINTF) /* defined in python.h (pyerrors.h) and SDL.h \ + (SDL_config.h) */ +#undef HAVE_SNPRINTF /* remove GCC redefine warning */ +#endif /* HAVE_SNPRINTF */ + +#ifndef PG_INLINE +#if defined(__clang__) +#define PG_INLINE __inline__ __attribute__((__unused__)) +#elif defined(__GNUC__) +#define PG_INLINE __inline__ +#elif defined(_MSC_VER) +#define PG_INLINE __inline +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define PG_INLINE inline +#else +#define PG_INLINE +#endif +#endif /* ~PG_INLINE */ + +// Worth trying this on MSVC/win32 builds to see if provides any speed up +#ifndef PG_FORCEINLINE +#if defined(__clang__) +#define PG_FORCEINLINE __inline__ __attribute__((__unused__)) +#elif defined(__GNUC__) +#define PG_FORCEINLINE __inline__ +#elif defined(_MSC_VER) +#define PG_FORCEINLINE __forceinline +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define PG_FORCEINLINE inline +#else +#define PG_FORCEINLINE +#endif +#endif /* ~PG_FORCEINLINE */ + +/* This is unconditionally defined in Python.h */ +#if defined(_POSIX_C_SOURCE) +#undef _POSIX_C_SOURCE +#endif + +/* No signal() */ +#if defined(__SYMBIAN32__) && defined(HAVE_SIGNAL_H) +#undef HAVE_SIGNAL_H +#endif + +#if defined(HAVE_SNPRINTF) +#undef HAVE_SNPRINTF +#endif + +/* SDL needs WIN32 */ +#if !defined(WIN32) && \ + (defined(MS_WIN32) || defined(_WIN32) || defined(__WIN32) || \ + defined(__WIN32__) || defined(_WINDOWS)) +#define WIN32 +#endif + +/* Commenting out SSE4_2 stuff because it does not do runtime detection. +#ifndef PG_TARGET_SSE4_2 +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ == 4 && +__GNUC_MINOR__ >= 9) || __GNUC__ >= 5 )) +//The old gcc 4.8 on centos used by manylinux1 does not seem to get sse4.2 +intrinsics #define PG_FUNCTION_TARGET_SSE4_2 __attribute__((target("sse4.2"))) +// No else; we define the fallback later +#endif +#endif +*/ +/* ~PG_TARGET_SSE4_2 */ + +/* +#ifdef PG_FUNCTION_TARGET_SSE4_2 +#if !defined(__SSE4_2__) && !defined(PG_COMPILE_SSE4_2) +#if defined(__x86_64__) || defined(__i386__) +#define PG_COMPILE_SSE4_2 1 +#endif +#endif +#endif +*/ +/* ~PG_TARGET_SSE4_2 */ + +/* Fallback definition of target attribute */ +#ifndef PG_FUNCTION_TARGET_SSE4_2 +#define PG_FUNCTION_TARGET_SSE4_2 +#endif + +#ifndef PG_COMPILE_SSE4_2 +#define PG_COMPILE_SSE4_2 0 +#endif + +#endif /* ~PG_PLATFORM_H */ diff --git a/venv/Include/site/python3.9/pygame/include/pygame.h b/venv/Include/site/python3.9/pygame/include/pygame.h new file mode 100644 index 0000000..3772ae6 --- /dev/null +++ b/venv/Include/site/python3.9/pygame/include/pygame.h @@ -0,0 +1,34 @@ +/* + pygame - Python Game Library + Copyright (C) 2000-2001 Pete Shinners + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Pete Shinners + pete@shinners.org +*/ + +/* To allow the Pygame C api to be globally shared by all code within an + * extension module built from multiple C files, only include the pygame.h + * header within the top level C file, the one which calls the + * 'import_pygame_*' macros. All other C source files of the module should + * include _pygame.h instead. + */ +#ifndef PYGAME_H +#define PYGAME_H + +#include "_pygame.h" + +#endif diff --git a/venv/Include/site/python3.9/pygame/include/pygame_bufferproxy.h b/venv/Include/site/python3.9/pygame/include/pygame_bufferproxy.h new file mode 100644 index 0000000..9284ff2 --- /dev/null +++ b/venv/Include/site/python3.9/pygame/include/pygame_bufferproxy.h @@ -0,0 +1,56 @@ +/* + pygame - Python Game Library + Copyright (C) 2000-2001 Pete Shinners + Copyright (C) 2007 Rene Dudfield, Richard Goedeken + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Pete Shinners + pete@shinners.org +*/ + +/* Bufferproxy module C api. */ +#if !defined(PG_BUFPROXY_HEADER) +#define PG_BUFPROXY_HEADER + +#include + +typedef PyObject *(*_pgbufproxy_new_t)(PyObject *, getbufferproc); +typedef PyObject *(*_pgbufproxy_get_obj_t)(PyObject *); +typedef int (*_pgbufproxy_trip_t)(PyObject *); + +#ifndef PYGAMEAPI_BUFPROXY_INTERNAL + +#include "pgimport.h" + +PYGAMEAPI_DEFINE_SLOTS(bufferproxy); + +#define pgBufproxy_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(bufferproxy, 0)) + +#define pgBufproxy_Check(x) ((x)->ob_type == &pgBufproxy_Type) + +#define pgBufproxy_New (*(_pgbufproxy_new_t)PYGAMEAPI_GET_SLOT(bufferproxy, 1)) + +#define pgBufproxy_GetParent \ + (*(_pgbufproxy_get_obj_t)PYGAMEAPI_GET_SLOT(bufferproxy, 2)) + +#define pgBufproxy_Trip \ + (*(_pgbufproxy_trip_t)PYGAMEAPI_GET_SLOT(bufferproxy, 3)) + +#define import_pygame_bufferproxy() _IMPORT_PYGAME_MODULE(bufferproxy) + +#endif /* ~PYGAMEAPI_BUFPROXY_INTERNAL */ + +#endif /* ~defined(PG_BUFPROXY_HEADER) */ diff --git a/venv/Include/site/python3.9/pygame/include/pygame_font.h b/venv/Include/site/python3.9/pygame/include/pygame_font.h new file mode 100644 index 0000000..aae41bf --- /dev/null +++ b/venv/Include/site/python3.9/pygame/include/pygame_font.h @@ -0,0 +1,50 @@ +/* + pygame - Python Game Library + Copyright (C) 2000-2001 Pete Shinners + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Pete Shinners + pete@shinners.org +*/ + +#include +#include "pgplatform.h" + +struct TTF_Font; + +typedef struct { + PyObject_HEAD TTF_Font *font; + PyObject *weakreflist; + unsigned int ttf_init_generation; +} PyFontObject; +#define PyFont_AsFont(x) (((PyFontObject *)x)->font) + +#ifndef PYGAMEAPI_FONT_INTERNAL + +#include "pgimport.h" + +PYGAMEAPI_DEFINE_SLOTS(font); + +#define PyFont_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(font, 0)) +#define PyFont_Check(x) ((x)->ob_type == &PyFont_Type) + +#define PyFont_New (*(PyObject * (*)(TTF_Font *)) PYGAMEAPI_GET_SLOT(font, 1)) + +/*slot 2 taken by FONT_INIT_CHECK*/ + +#define import_pygame_font() _IMPORT_PYGAME_MODULE(font) + +#endif diff --git a/venv/Include/site/python3.9/pygame/include/pygame_freetype.h b/venv/Include/site/python3.9/pygame/include/pygame_freetype.h new file mode 100644 index 0000000..90172cc --- /dev/null +++ b/venv/Include/site/python3.9/pygame/include/pygame_freetype.h @@ -0,0 +1,42 @@ +/* + pygame - Python Game Library + Copyright (C) 2009 Vicent Marti + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +#ifndef PYGAME_FREETYPE_H_ +#define PYGAME_FREETYPE_H_ + +#include "pgplatform.h" +#include "pgimport.h" +#include "pgcompat.h" + +#ifndef PYGAME_FREETYPE_INTERNAL + +PYGAMEAPI_DEFINE_SLOTS(_freetype); + +#define pgFont_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(_freetype, 0)) + +#define pgFont_Check(x) ((x)->ob_type == &pgFont_Type) + +#define pgFont_New \ + (*(PyObject * (*)(const char *, long)) PYGAMEAPI_GET_SLOT(_freetype, 1)) + +#define import_pygame_freetype() _IMPORT_PYGAME_MODULE(_freetype) + +#endif /* PYGAME_FREETYPE_INTERNAL */ + +#endif /* PYGAME_FREETYPE_H_ */ diff --git a/venv/Include/site/python3.9/pygame/include/pygame_mask.h b/venv/Include/site/python3.9/pygame/include/pygame_mask.h new file mode 100644 index 0000000..8dd8f17 --- /dev/null +++ b/venv/Include/site/python3.9/pygame/include/pygame_mask.h @@ -0,0 +1,45 @@ +/* + pygame - Python Game Library + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef PGMASK_H +#define PGMASK_H + +#include +#include "bitmask.h" + +typedef struct { + PyObject_HEAD bitmask_t *mask; + void *bufdata; +} pgMaskObject; + +#define pgMask_AsBitmap(x) (((pgMaskObject *)x)->mask) + +#ifndef PYGAMEAPI_MASK_INTERNAL + +#include "pgimport.h" + +PYGAMEAPI_DEFINE_SLOTS(mask); + +#define pgMask_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(mask, 0)) +#define pgMask_Check(x) ((x)->ob_type == &pgMask_Type) + +#define import_pygame_mask() _IMPORT_PYGAME_MODULE(mask) + +#endif /* ~PYGAMEAPI_MASK_INTERNAL */ + +#endif /* ~PGMASK_H */ diff --git a/venv/Include/site/python3.9/pygame/include/pygame_mixer.h b/venv/Include/site/python3.9/pygame/include/pygame_mixer.h new file mode 100644 index 0000000..e19d273 --- /dev/null +++ b/venv/Include/site/python3.9/pygame/include/pygame_mixer.h @@ -0,0 +1,71 @@ +/* + pygame - Python Game Library + Copyright (C) 2000-2001 Pete Shinners + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Pete Shinners + pete@shinners.org +*/ + +#ifndef PGMIXER_H +#define PGMIXER_H + +#include +#include + +#include "pgcompat.h" + +struct Mix_Chunk; + +typedef struct { + PyObject_HEAD Mix_Chunk *chunk; + Uint8 *mem; + PyObject *weakreflist; +} pgSoundObject; + +typedef struct { + PyObject_HEAD int chan; +} pgChannelObject; + +#define pgSound_AsChunk(x) (((pgSoundObject *)x)->chunk) +#define pgChannel_AsInt(x) (((pgChannelObject *)x)->chan) + +#include "pgimport.h" + +#ifndef PYGAMEAPI_MIXER_INTERNAL + +PYGAMEAPI_DEFINE_SLOTS(mixer); + +#define pgSound_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(mixer, 0)) + +#define pgSound_Check(x) ((x)->ob_type == &pgSound_Type) + +#define pgSound_New \ + (*(PyObject * (*)(Mix_Chunk *)) PYGAMEAPI_GET_SLOT(mixer, 1)) + +#define pgSound_Play \ + (*(PyObject * (*)(PyObject *, PyObject *)) PYGAMEAPI_GET_SLOT(mixer, 2)) + +#define pgChannel_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(mixer, 3)) +#define pgChannel_Check(x) ((x)->ob_type == &pgChannel_Type) + +#define pgChannel_New (*(PyObject * (*)(int)) PYGAMEAPI_GET_SLOT(mixer, 4)) + +#define import_pygame_mixer() _IMPORT_PYGAME_MODULE(mixer) + +#endif /* PYGAMEAPI_MIXER_INTERNAL */ + +#endif /* ~PGMIXER_H */ diff --git a/venv/Include/site/python3.9/pygame/include/sse2neon.h b/venv/Include/site/python3.9/pygame/include/sse2neon.h new file mode 100644 index 0000000..a3e3ac0 --- /dev/null +++ b/venv/Include/site/python3.9/pygame/include/sse2neon.h @@ -0,0 +1,6203 @@ +#ifndef SSE2NEON_H +#define SSE2NEON_H + +// This header file provides a simple API translation layer +// between SSE intrinsics to their corresponding Arm/Aarch64 NEON versions +// +// This header file does not yet translate all of the SSE intrinsics. +// +// Contributors to this work are: +// John W. Ratcliff +// Brandon Rowlett +// Ken Fast +// Eric van Beurden +// Alexander Potylitsin +// Hasindu Gamaarachchi +// Jim Huang +// Mark Cheng +// Malcolm James MacLeod +// Devin Hussey (easyaspi314) +// Sebastian Pop +// Developer Ecosystem Engineering +// Danila Kutenin +// François Turban (JishinMaster) +// Pei-Hsuan Hung +// Yang-Hao Yuan + +/* + * sse2neon is freely redistributable under the MIT License. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* Tunable configurations */ + +/* Enable precise implementation of _mm_min_ps and _mm_max_ps + * This would slow down the computation a bit, but gives consistent result with + * x86 SSE2. (e.g. would solve a hole or NaN pixel in the rendering result) + */ +#ifndef SSE2NEON_PRECISE_MINMAX +#define SSE2NEON_PRECISE_MINMAX (0) +#endif + +#if defined(__GNUC__) || defined(__clang__) +#pragma push_macro("FORCE_INLINE") +#pragma push_macro("ALIGN_STRUCT") +#define FORCE_INLINE static inline __attribute__((always_inline)) +#define ALIGN_STRUCT(x) __attribute__((aligned(x))) +#else +#error "Macro name collisions may happen with unsupported compiler." +#ifdef FORCE_INLINE +#undef FORCE_INLINE +#endif +#define FORCE_INLINE static inline +#ifndef ALIGN_STRUCT +#define ALIGN_STRUCT(x) __declspec(align(x)) +#endif +#endif + +#include +#include + +// These cause the build to fail on raspberry pi with 'unsupported target' +// and don't seem to do anything particularly useful +///* Architecture-specific build options */ +///* FIXME: #pragma GCC push_options is only available on GCC */ +//#if defined(__GNUC__) +//#if defined(__arm__) && __ARM_ARCH == 7 +///* According to ARM C Language Extensions Architecture specification, +// * __ARM_NEON is defined to a value indicating the Advanced SIMD (NEON) +// * architecture supported. +// */ +//#if !defined(__ARM_NEON) || !defined(__ARM_NEON__) +//#error "You must enable NEON instructions (e.g. -mfpu=neon) to use SSE2NEON." +//#endif +//#pragma GCC push_options +//#pragma GCC target("fpu=neon") +//#elif defined(__aarch64__) +//#pragma GCC push_options +//#pragma GCC target("+simd") +//#else +//#error "Unsupported target. Must be either ARMv7-A+NEON or ARMv8-A." +//#endif +//#endif + +#include + +/* Rounding functions require either Aarch64 instructions or libm failback */ +#if !defined(__aarch64__) +#include +#endif + +/* "__has_builtin" can be used to query support for built-in functions + * provided by gcc/clang and other compilers that support it. + */ +#ifndef __has_builtin /* GCC prior to 10 or non-clang compilers */ +/* Compatibility with gcc <= 9 */ +#if __GNUC__ <= 9 +#define __has_builtin(x) HAS##x +#define HAS__builtin_popcount 1 +#define HAS__builtin_popcountll 1 +#else +#define __has_builtin(x) 0 +#endif +#endif + +/** + * MACRO for shuffle parameter for _mm_shuffle_ps(). + * Argument fp3 is a digit[0123] that represents the fp from argument "b" + * of mm_shuffle_ps that will be placed in fp3 of result. fp2 is the same + * for fp2 in result. fp1 is a digit[0123] that represents the fp from + * argument "a" of mm_shuffle_ps that will be places in fp1 of result. + * fp0 is the same for fp0 of result. + */ +#define _MM_SHUFFLE(fp3, fp2, fp1, fp0) \ + (((fp3) << 6) | ((fp2) << 4) | ((fp1) << 2) | ((fp0))) + +/* Rounding mode macros. */ +#define _MM_FROUND_TO_NEAREST_INT 0x00 +#define _MM_FROUND_TO_NEG_INF 0x01 +#define _MM_FROUND_TO_POS_INF 0x02 +#define _MM_FROUND_TO_ZERO 0x03 +#define _MM_FROUND_CUR_DIRECTION 0x04 +#define _MM_FROUND_NO_EXC 0x08 + +/* indicate immediate constant argument in a given range */ +#define __constrange(a, b) const + +/* A few intrinsics accept traditional data types like ints or floats, but + * most operate on data types that are specific to SSE. + * If a vector type ends in d, it contains doubles, and if it does not have + * a suffix, it contains floats. An integer vector type can contain any type + * of integer, from chars to shorts to unsigned long longs. + */ +typedef int64x1_t __m64; +typedef float32x4_t __m128; /* 128-bit vector containing 4 floats */ +// On ARM 32-bit architecture, the float64x2_t is not supported. +// The data type __m128d should be represented in a different way for related +// intrinsic conversion. +#if defined(__aarch64__) +typedef float64x2_t __m128d; /* 128-bit vector containing 2 doubles */ +#else +typedef float32x4_t __m128d; +#endif +typedef int64x2_t __m128i; /* 128-bit vector containing integers */ + +/* type-safe casting between types */ + +#define vreinterpretq_m128_f16(x) vreinterpretq_f32_f16(x) +#define vreinterpretq_m128_f32(x) (x) +#define vreinterpretq_m128_f64(x) vreinterpretq_f32_f64(x) + +#define vreinterpretq_m128_u8(x) vreinterpretq_f32_u8(x) +#define vreinterpretq_m128_u16(x) vreinterpretq_f32_u16(x) +#define vreinterpretq_m128_u32(x) vreinterpretq_f32_u32(x) +#define vreinterpretq_m128_u64(x) vreinterpretq_f32_u64(x) + +#define vreinterpretq_m128_s8(x) vreinterpretq_f32_s8(x) +#define vreinterpretq_m128_s16(x) vreinterpretq_f32_s16(x) +#define vreinterpretq_m128_s32(x) vreinterpretq_f32_s32(x) +#define vreinterpretq_m128_s64(x) vreinterpretq_f32_s64(x) + +#define vreinterpretq_f16_m128(x) vreinterpretq_f16_f32(x) +#define vreinterpretq_f32_m128(x) (x) +#define vreinterpretq_f64_m128(x) vreinterpretq_f64_f32(x) + +#define vreinterpretq_u8_m128(x) vreinterpretq_u8_f32(x) +#define vreinterpretq_u16_m128(x) vreinterpretq_u16_f32(x) +#define vreinterpretq_u32_m128(x) vreinterpretq_u32_f32(x) +#define vreinterpretq_u64_m128(x) vreinterpretq_u64_f32(x) + +#define vreinterpretq_s8_m128(x) vreinterpretq_s8_f32(x) +#define vreinterpretq_s16_m128(x) vreinterpretq_s16_f32(x) +#define vreinterpretq_s32_m128(x) vreinterpretq_s32_f32(x) +#define vreinterpretq_s64_m128(x) vreinterpretq_s64_f32(x) + +#define vreinterpretq_m128i_s8(x) vreinterpretq_s64_s8(x) +#define vreinterpretq_m128i_s16(x) vreinterpretq_s64_s16(x) +#define vreinterpretq_m128i_s32(x) vreinterpretq_s64_s32(x) +#define vreinterpretq_m128i_s64(x) (x) + +#define vreinterpretq_m128i_u8(x) vreinterpretq_s64_u8(x) +#define vreinterpretq_m128i_u16(x) vreinterpretq_s64_u16(x) +#define vreinterpretq_m128i_u32(x) vreinterpretq_s64_u32(x) +#define vreinterpretq_m128i_u64(x) vreinterpretq_s64_u64(x) + +#define vreinterpretq_s8_m128i(x) vreinterpretq_s8_s64(x) +#define vreinterpretq_s16_m128i(x) vreinterpretq_s16_s64(x) +#define vreinterpretq_s32_m128i(x) vreinterpretq_s32_s64(x) +#define vreinterpretq_s64_m128i(x) (x) + +#define vreinterpretq_u8_m128i(x) vreinterpretq_u8_s64(x) +#define vreinterpretq_u16_m128i(x) vreinterpretq_u16_s64(x) +#define vreinterpretq_u32_m128i(x) vreinterpretq_u32_s64(x) +#define vreinterpretq_u64_m128i(x) vreinterpretq_u64_s64(x) + +#define vreinterpret_m64_s8(x) vreinterpret_s64_s8(x) +#define vreinterpret_m64_s16(x) vreinterpret_s64_s16(x) +#define vreinterpret_m64_s32(x) vreinterpret_s64_s32(x) +#define vreinterpret_m64_s64(x) (x) + +#define vreinterpret_m64_u8(x) vreinterpret_s64_u8(x) +#define vreinterpret_m64_u16(x) vreinterpret_s64_u16(x) +#define vreinterpret_m64_u32(x) vreinterpret_s64_u32(x) +#define vreinterpret_m64_u64(x) vreinterpret_s64_u64(x) + +#define vreinterpret_m64_f16(x) vreinterpret_s64_f16(x) +#define vreinterpret_m64_f32(x) vreinterpret_s64_f32(x) +#define vreinterpret_m64_f64(x) vreinterpret_s64_f64(x) + +#define vreinterpret_u8_m64(x) vreinterpret_u8_s64(x) +#define vreinterpret_u16_m64(x) vreinterpret_u16_s64(x) +#define vreinterpret_u32_m64(x) vreinterpret_u32_s64(x) +#define vreinterpret_u64_m64(x) vreinterpret_u64_s64(x) + +#define vreinterpret_s8_m64(x) vreinterpret_s8_s64(x) +#define vreinterpret_s16_m64(x) vreinterpret_s16_s64(x) +#define vreinterpret_s32_m64(x) vreinterpret_s32_s64(x) +#define vreinterpret_s64_m64(x) (x) + +#define vreinterpret_f32_m64(x) vreinterpret_f32_s64(x) + +#if defined(__aarch64__) +#define vreinterpretq_m128d_s32(x) vreinterpretq_f64_s32(x) +#define vreinterpretq_m128d_s64(x) vreinterpretq_f64_s64(x) + +#define vreinterpretq_m128d_f64(x) (x) + +#define vreinterpretq_s64_m128d(x) vreinterpretq_s64_f64(x) + +#define vreinterpretq_f64_m128d(x) (x) +#else +#define vreinterpretq_m128d_s32(x) vreinterpretq_f32_s32(x) +#define vreinterpretq_m128d_s64(x) vreinterpretq_f32_s64(x) + +#define vreinterpretq_m128d_f32(x) (x) + +#define vreinterpretq_s64_m128d(x) vreinterpretq_s64_f32(x) + +#define vreinterpretq_f32_m128d(x) (x) +#endif + +// A struct is defined in this header file called 'SIMDVec' which can be used +// by applications which attempt to access the contents of an _m128 struct +// directly. It is important to note that accessing the __m128 struct directly +// is bad coding practice by Microsoft: @see: +// https://msdn.microsoft.com/en-us/library/ayeb3ayc.aspx +// +// However, some legacy source code may try to access the contents of an __m128 +// struct directly so the developer can use the SIMDVec as an alias for it. Any +// casting must be done manually by the developer, as you cannot cast or +// otherwise alias the base NEON data type for intrinsic operations. +// +// union intended to allow direct access to an __m128 variable using the names +// that the MSVC compiler provides. This union should really only be used when +// trying to access the members of the vector as integer values. GCC/clang +// allow native access to the float members through a simple array access +// operator (in C since 4.6, in C++ since 4.8). +// +// Ideally direct accesses to SIMD vectors should not be used since it can cause +// a performance hit. If it really is needed however, the original __m128 +// variable can be aliased with a pointer to this union and used to access +// individual components. The use of this union should be hidden behind a macro +// that is used throughout the codebase to access the members instead of always +// declaring this type of variable. +typedef union ALIGN_STRUCT(16) SIMDVec { + float m128_f32[4]; // as floats - DON'T USE. Added for convenience. + int8_t m128_i8[16]; // as signed 8-bit integers. + int16_t m128_i16[8]; // as signed 16-bit integers. + int32_t m128_i32[4]; // as signed 32-bit integers. + int64_t m128_i64[2]; // as signed 64-bit integers. + uint8_t m128_u8[16]; // as unsigned 8-bit integers. + uint16_t m128_u16[8]; // as unsigned 16-bit integers. + uint32_t m128_u32[4]; // as unsigned 32-bit integers. + uint64_t m128_u64[2]; // as unsigned 64-bit integers. +} SIMDVec; + +// casting using SIMDVec +#define vreinterpretq_nth_u64_m128i(x, n) (((SIMDVec *) &x)->m128_u64[n]) +#define vreinterpretq_nth_u32_m128i(x, n) (((SIMDVec *) &x)->m128_u32[n]) +#define vreinterpretq_nth_u8_m128i(x, n) (((SIMDVec *) &x)->m128_u8[n]) + +/* Backwards compatibility for compilers with lack of specific type support */ + +// Older gcc does not define vld1q_u8_x4 type +#if defined(__GNUC__) && !defined(__clang__) +#if __GNUC__ <= 9 +FORCE_INLINE uint8x16x4_t vld1q_u8_x4(const uint8_t *p) +{ + uint8x16x4_t ret; + ret.val[0] = vld1q_u8(p + 0); + ret.val[1] = vld1q_u8(p + 16); + ret.val[2] = vld1q_u8(p + 32); + ret.val[3] = vld1q_u8(p + 48); + return ret; +} +#endif +#endif + +/* Function Naming Conventions + * The naming convention of SSE intrinsics is straightforward. A generic SSE + * intrinsic function is given as follows: + * _mm__ + * + * The parts of this format are given as follows: + * 1. describes the operation performed by the intrinsic + * 2. identifies the data type of the function's primary arguments + * + * This last part, , is a little complicated. It identifies the + * content of the input values, and can be set to any of the following values: + * + ps - vectors contain floats (ps stands for packed single-precision) + * + pd - vectors cantain doubles (pd stands for packed double-precision) + * + epi8/epi16/epi32/epi64 - vectors contain 8-bit/16-bit/32-bit/64-bit + * signed integers + * + epu8/epu16/epu32/epu64 - vectors contain 8-bit/16-bit/32-bit/64-bit + * unsigned integers + * + si128 - unspecified 128-bit vector or 256-bit vector + * + m128/m128i/m128d - identifies input vector types when they are different + * than the type of the returned vector + * + * For example, _mm_setzero_ps. The _mm implies that the function returns + * a 128-bit vector. The _ps at the end implies that the argument vectors + * contain floats. + * + * A complete example: Byte Shuffle - pshufb (_mm_shuffle_epi8) + * // Set packed 16-bit integers. 128 bits, 8 short, per 16 bits + * __m128i v_in = _mm_setr_epi16(1, 2, 3, 4, 5, 6, 7, 8); + * // Set packed 8-bit integers + * // 128 bits, 16 chars, per 8 bits + * __m128i v_perm = _mm_setr_epi8(1, 0, 2, 3, 8, 9, 10, 11, + * 4, 5, 12, 13, 6, 7, 14, 15); + * // Shuffle packed 8-bit integers + * __m128i v_out = _mm_shuffle_epi8(v_in, v_perm); // pshufb + * + * Data (Number, Binary, Byte Index): + +------+------+-------------+------+------+-------------+ + | 1 | 2 | 3 | 4 | Number + +------+------+------+------+------+------+------+------+ + | 0000 | 0001 | 0000 | 0010 | 0000 | 0011 | 0000 | 0100 | Binary + +------+------+------+------+------+------+------+------+ + | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | Index + +------+------+------+------+------+------+------+------+ + + +------+------+------+------+------+------+------+------+ + | 5 | 6 | 7 | 8 | Number + +------+------+------+------+------+------+------+------+ + | 0000 | 0101 | 0000 | 0110 | 0000 | 0111 | 0000 | 1000 | Binary + +------+------+------+------+------+------+------+------+ + | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Index + +------+------+------+------+------+------+------+------+ + * Index (Byte Index): + +------+------+------+------+------+------+------+------+ + | 1 | 0 | 2 | 3 | 8 | 9 | 10 | 11 | + +------+------+------+------+------+------+------+------+ + + +------+------+------+------+------+------+------+------+ + | 4 | 5 | 12 | 13 | 6 | 7 | 14 | 15 | + +------+------+------+------+------+------+------+------+ + * Result: + +------+------+------+------+------+------+------+------+ + | 1 | 0 | 2 | 3 | 8 | 9 | 10 | 11 | Index + +------+------+------+------+------+------+------+------+ + | 0001 | 0000 | 0000 | 0010 | 0000 | 0101 | 0000 | 0110 | Binary + +------+------+------+------+------+------+------+------+ + | 256 | 2 | 5 | 6 | Number + +------+------+------+------+------+------+------+------+ + + +------+------+------+------+------+------+------+------+ + | 4 | 5 | 12 | 13 | 6 | 7 | 14 | 15 | Index + +------+------+------+------+------+------+------+------+ + | 0000 | 0011 | 0000 | 0111 | 0000 | 0100 | 0000 | 1000 | Binary + +------+------+------+------+------+------+------+------+ + | 3 | 7 | 4 | 8 | Number + +------+------+------+------+------+------+-------------+ + */ + +/* Set/get methods */ + +/* Constants for use with _mm_prefetch. */ +enum _mm_hint { + _MM_HINT_NTA = 0, /* load data to L1 and L2 cache, mark it as NTA */ + _MM_HINT_T0 = 1, /* load data to L1 and L2 cache */ + _MM_HINT_T1 = 2, /* load data to L2 cache only */ + _MM_HINT_T2 = 3, /* load data to L2 cache only, mark it as NTA */ + _MM_HINT_ENTA = 4, /* exclusive version of _MM_HINT_NTA */ + _MM_HINT_ET0 = 5, /* exclusive version of _MM_HINT_T0 */ + _MM_HINT_ET1 = 6, /* exclusive version of _MM_HINT_T1 */ + _MM_HINT_ET2 = 7 /* exclusive version of _MM_HINT_T2 */ +}; + +// Loads one cache line of data from address p to a location closer to the +// processor. https://msdn.microsoft.com/en-us/library/84szxsww(v=vs.100).aspx +FORCE_INLINE void _mm_prefetch(const void *p, int i) +{ + (void) i; + __builtin_prefetch(p); +} + +// Copy the lower single-precision (32-bit) floating-point element of a to dst. +// +// dst[31:0] := a[31:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_f32 +FORCE_INLINE float _mm_cvtss_f32(__m128 a) +{ + return vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); +} + +// Convert the lower single-precision (32-bit) floating-point element in a to a +// 32-bit integer, and store the result in dst. +// +// dst[31:0] := Convert_FP32_To_Int32(a[31:0]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_si32 +#define _mm_cvtss_si32(a) _mm_cvt_ss2si(a) + +// Convert the lower single-precision (32-bit) floating-point element in a to a +// 64-bit integer, and store the result in dst. +// +// dst[63:0] := Convert_FP32_To_Int64(a[31:0]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_si64 +FORCE_INLINE int _mm_cvtss_si64(__m128 a) +{ +#if defined(__aarch64__) + return vgetq_lane_s64( + vreinterpretq_s64_s32(vcvtnq_s32_f32(vreinterpretq_f32_m128(a))), 0); +#else + float32_t data = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); + float32_t diff = data - floor(data); + if (diff > 0.5) + return (int64_t) ceil(data); + if (diff == 0.5) { + int64_t f = (int64_t) floor(data); + int64_t c = (int64_t) ceil(data); + return c & 1 ? f : c; + } + return (int64_t) floor(data); +#endif +} + +// Convert packed single-precision (32-bit) floating-point elements in a to +// packed 32-bit integers with truncation, and store the results in dst. +// +// FOR j := 0 to 1 +// i := 32*j +// dst[i+31:i] := Convert_FP32_To_Int32_Truncate(a[i+31:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_ps2pi +FORCE_INLINE __m64 _mm_cvtt_ps2pi(__m128 a) +{ + return vreinterpret_m64_s32( + vget_low_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a)))); +} + +// Convert the lower single-precision (32-bit) floating-point element in a to a +// 32-bit integer with truncation, and store the result in dst. +// +// dst[31:0] := Convert_FP32_To_Int32_Truncate(a[31:0]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_ss2si +FORCE_INLINE int _mm_cvtt_ss2si(__m128 a) +{ + return vgetq_lane_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a)), 0); +} + +// Convert packed single-precision (32-bit) floating-point elements in a to +// packed 32-bit integers with truncation, and store the results in dst. +// +// FOR j := 0 to 1 +// i := 32*j +// dst[i+31:i] := Convert_FP32_To_Int32_Truncate(a[i+31:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttps_pi32 +#define _mm_cvttps_pi32(a) _mm_cvtt_ps2pi(a) + +// Convert the lower single-precision (32-bit) floating-point element in a to a +// 32-bit integer with truncation, and store the result in dst. +// +// dst[31:0] := Convert_FP32_To_Int32_Truncate(a[31:0]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_si32 +#define _mm_cvttss_si32(a) _mm_cvtt_ss2si(a) + +// Convert the lower single-precision (32-bit) floating-point element in a to a +// 64-bit integer with truncation, and store the result in dst. +// +// dst[63:0] := Convert_FP32_To_Int64_Truncate(a[31:0]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_si64 +FORCE_INLINE int64_t _mm_cvttss_si64(__m128 a) +{ + return vgetq_lane_s64( + vmovl_s32(vget_low_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a)))), 0); +} + +// Sets the 128-bit value to zero +// https://msdn.microsoft.com/en-us/library/vstudio/ys7dw0kh(v=vs.100).aspx +FORCE_INLINE __m128i _mm_setzero_si128(void) +{ + return vreinterpretq_m128i_s32(vdupq_n_s32(0)); +} + +// Clears the four single-precision, floating-point values. +// https://msdn.microsoft.com/en-us/library/vstudio/tk1t2tbz(v=vs.100).aspx +FORCE_INLINE __m128 _mm_setzero_ps(void) +{ + return vreinterpretq_m128_f32(vdupq_n_f32(0)); +} + +// Return vector of type __m128d with all elements set to zero. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setzero_pd +FORCE_INLINE __m128d _mm_setzero_pd(void) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64(vdupq_n_f64(0)); +#else + return vreinterpretq_m128d_f32(vdupq_n_f32(0)); +#endif +} + +// Sets the four single-precision, floating-point values to w. +// +// r0 := r1 := r2 := r3 := w +// +// https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx +FORCE_INLINE __m128 _mm_set1_ps(float _w) +{ + return vreinterpretq_m128_f32(vdupq_n_f32(_w)); +} + +// Sets the four single-precision, floating-point values to w. +// https://msdn.microsoft.com/en-us/library/vstudio/2x1se8ha(v=vs.100).aspx +FORCE_INLINE __m128 _mm_set_ps1(float _w) +{ + return vreinterpretq_m128_f32(vdupq_n_f32(_w)); +} + +// Sets the four single-precision, floating-point values to the four inputs. +// https://msdn.microsoft.com/en-us/library/vstudio/afh0zf75(v=vs.100).aspx +FORCE_INLINE __m128 _mm_set_ps(float w, float z, float y, float x) +{ + float ALIGN_STRUCT(16) data[4] = {x, y, z, w}; + return vreinterpretq_m128_f32(vld1q_f32(data)); +} + +// Copy single-precision (32-bit) floating-point element a to the lower element +// of dst, and zero the upper 3 elements. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_ss +FORCE_INLINE __m128 _mm_set_ss(float a) +{ + float ALIGN_STRUCT(16) data[4] = {a, 0, 0, 0}; + return vreinterpretq_m128_f32(vld1q_f32(data)); +} + +// Sets the four single-precision, floating-point values to the four inputs in +// reverse order. +// https://msdn.microsoft.com/en-us/library/vstudio/d2172ct3(v=vs.100).aspx +FORCE_INLINE __m128 _mm_setr_ps(float w, float z, float y, float x) +{ + float ALIGN_STRUCT(16) data[4] = {w, z, y, x}; + return vreinterpretq_m128_f32(vld1q_f32(data)); +} + +// Sets the 8 signed 16-bit integer values in reverse order. +// +// Return Value +// r0 := w0 +// r1 := w1 +// ... +// r7 := w7 +FORCE_INLINE __m128i _mm_setr_epi16(short w0, + short w1, + short w2, + short w3, + short w4, + short w5, + short w6, + short w7) +{ + int16_t ALIGN_STRUCT(16) data[8] = {w0, w1, w2, w3, w4, w5, w6, w7}; + return vreinterpretq_m128i_s16(vld1q_s16((int16_t *) data)); +} + +// Sets the 4 signed 32-bit integer values in reverse order +// https://technet.microsoft.com/en-us/library/security/27yb3ee5(v=vs.90).aspx +FORCE_INLINE __m128i _mm_setr_epi32(int i3, int i2, int i1, int i0) +{ + int32_t ALIGN_STRUCT(16) data[4] = {i3, i2, i1, i0}; + return vreinterpretq_m128i_s32(vld1q_s32(data)); +} + +// Set packed 64-bit integers in dst with the supplied values in reverse order. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setr_epi64 +FORCE_INLINE __m128i _mm_setr_epi64(__m64 e1, __m64 e0) +{ + return vreinterpretq_m128i_s64(vcombine_s64(e1, e0)); +} + +// Sets the 16 signed 8-bit integer values to b. +// +// r0 := b +// r1 := b +// ... +// r15 := b +// +// https://msdn.microsoft.com/en-us/library/6e14xhyf(v=vs.100).aspx +FORCE_INLINE __m128i _mm_set1_epi8(signed char w) +{ + return vreinterpretq_m128i_s8(vdupq_n_s8(w)); +} + +// Sets the 8 signed 16-bit integer values to w. +// +// r0 := w +// r1 := w +// ... +// r7 := w +// +// https://msdn.microsoft.com/en-us/library/k0ya3x0e(v=vs.90).aspx +FORCE_INLINE __m128i _mm_set1_epi16(short w) +{ + return vreinterpretq_m128i_s16(vdupq_n_s16(w)); +} + +// Sets the 16 signed 8-bit integer values. +// https://msdn.microsoft.com/en-us/library/x0cx8zd3(v=vs.90).aspx +FORCE_INLINE __m128i _mm_set_epi8(signed char b15, + signed char b14, + signed char b13, + signed char b12, + signed char b11, + signed char b10, + signed char b9, + signed char b8, + signed char b7, + signed char b6, + signed char b5, + signed char b4, + signed char b3, + signed char b2, + signed char b1, + signed char b0) +{ + int8_t ALIGN_STRUCT(16) + data[16] = {(int8_t) b0, (int8_t) b1, (int8_t) b2, (int8_t) b3, + (int8_t) b4, (int8_t) b5, (int8_t) b6, (int8_t) b7, + (int8_t) b8, (int8_t) b9, (int8_t) b10, (int8_t) b11, + (int8_t) b12, (int8_t) b13, (int8_t) b14, (int8_t) b15}; + return (__m128i) vld1q_s8(data); +} + +// Sets the 8 signed 16-bit integer values. +// https://msdn.microsoft.com/en-au/library/3e0fek84(v=vs.90).aspx +FORCE_INLINE __m128i _mm_set_epi16(short i7, + short i6, + short i5, + short i4, + short i3, + short i2, + short i1, + short i0) +{ + int16_t ALIGN_STRUCT(16) data[8] = {i0, i1, i2, i3, i4, i5, i6, i7}; + return vreinterpretq_m128i_s16(vld1q_s16(data)); +} + +// Sets the 16 signed 8-bit integer values in reverse order. +// https://msdn.microsoft.com/en-us/library/2khb9c7k(v=vs.90).aspx +FORCE_INLINE __m128i _mm_setr_epi8(signed char b0, + signed char b1, + signed char b2, + signed char b3, + signed char b4, + signed char b5, + signed char b6, + signed char b7, + signed char b8, + signed char b9, + signed char b10, + signed char b11, + signed char b12, + signed char b13, + signed char b14, + signed char b15) +{ + int8_t ALIGN_STRUCT(16) + data[16] = {(int8_t) b0, (int8_t) b1, (int8_t) b2, (int8_t) b3, + (int8_t) b4, (int8_t) b5, (int8_t) b6, (int8_t) b7, + (int8_t) b8, (int8_t) b9, (int8_t) b10, (int8_t) b11, + (int8_t) b12, (int8_t) b13, (int8_t) b14, (int8_t) b15}; + return (__m128i) vld1q_s8(data); +} + +// Sets the 4 signed 32-bit integer values to i. +// +// r0 := i +// r1 := i +// r2 := i +// r3 := I +// +// https://msdn.microsoft.com/en-us/library/vstudio/h4xscxat(v=vs.100).aspx +FORCE_INLINE __m128i _mm_set1_epi32(int _i) +{ + return vreinterpretq_m128i_s32(vdupq_n_s32(_i)); +} + +// Sets the 2 signed 64-bit integer values to i. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/whtfzhzk(v=vs.100) +FORCE_INLINE __m128i _mm_set1_epi64(__m64 _i) +{ + return vreinterpretq_m128i_s64(vdupq_n_s64((int64_t) _i)); +} + +// Sets the 2 signed 64-bit integer values to i. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set1_epi64x +FORCE_INLINE __m128i _mm_set1_epi64x(int64_t _i) +{ + return vreinterpretq_m128i_s64(vdupq_n_s64(_i)); +} + +// Sets the 4 signed 32-bit integer values. +// https://msdn.microsoft.com/en-us/library/vstudio/019beekt(v=vs.100).aspx +FORCE_INLINE __m128i _mm_set_epi32(int i3, int i2, int i1, int i0) +{ + int32_t ALIGN_STRUCT(16) data[4] = {i0, i1, i2, i3}; + return vreinterpretq_m128i_s32(vld1q_s32(data)); +} + +// Returns the __m128i structure with its two 64-bit integer values +// initialized to the values of the two 64-bit integers passed in. +// https://msdn.microsoft.com/en-us/library/dk2sdw0h(v=vs.120).aspx +FORCE_INLINE __m128i _mm_set_epi64x(int64_t i1, int64_t i2) +{ + int64_t ALIGN_STRUCT(16) data[2] = {i2, i1}; + return vreinterpretq_m128i_s64(vld1q_s64(data)); +} + +// Returns the __m128i structure with its two 64-bit integer values +// initialized to the values of the two 64-bit integers passed in. +// https://msdn.microsoft.com/en-us/library/dk2sdw0h(v=vs.120).aspx +FORCE_INLINE __m128i _mm_set_epi64(__m64 i1, __m64 i2) +{ + return _mm_set_epi64x((int64_t) i1, (int64_t) i2); +} + +// Set packed double-precision (64-bit) floating-point elements in dst with the +// supplied values. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_pd +FORCE_INLINE __m128d _mm_set_pd(double e1, double e0) +{ + double ALIGN_STRUCT(16) data[2] = {e0, e1}; +#if defined(__aarch64__) + return vreinterpretq_m128d_f64(vld1q_f64((float64_t *) data)); +#else + return vreinterpretq_m128d_f32(vld1q_f32((float32_t *) data)); +#endif +} + +// Stores four single-precision, floating-point values. +// https://msdn.microsoft.com/en-us/library/vstudio/s3h4ay6y(v=vs.100).aspx +FORCE_INLINE void _mm_store_ps(float *p, __m128 a) +{ + vst1q_f32(p, vreinterpretq_f32_m128(a)); +} + +// Stores four single-precision, floating-point values. +// https://msdn.microsoft.com/en-us/library/44e30x22(v=vs.100).aspx +FORCE_INLINE void _mm_storeu_ps(float *p, __m128 a) +{ + vst1q_f32(p, vreinterpretq_f32_m128(a)); +} + +// Stores four 32-bit integer values as (as a __m128i value) at the address p. +// https://msdn.microsoft.com/en-us/library/vstudio/edk11s13(v=vs.100).aspx +FORCE_INLINE void _mm_store_si128(__m128i *p, __m128i a) +{ + vst1q_s32((int32_t *) p, vreinterpretq_s32_m128i(a)); +} + +// Stores four 32-bit integer values as (as a __m128i value) at the address p. +// https://msdn.microsoft.com/en-us/library/vstudio/edk11s13(v=vs.100).aspx +FORCE_INLINE void _mm_storeu_si128(__m128i *p, __m128i a) +{ + vst1q_s32((int32_t *) p, vreinterpretq_s32_m128i(a)); +} + +// Stores the lower single - precision, floating - point value. +// https://msdn.microsoft.com/en-us/library/tzz10fbx(v=vs.100).aspx +FORCE_INLINE void _mm_store_ss(float *p, __m128 a) +{ + vst1q_lane_f32(p, vreinterpretq_f32_m128(a), 0); +} + +// Store 128-bits (composed of 2 packed double-precision (64-bit) floating-point +// elements) from a into memory. mem_addr must be aligned on a 16-byte boundary +// or a general-protection exception may be generated. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store_pd +FORCE_INLINE void _mm_store_pd(double *mem_addr, __m128d a) +{ +#if defined(__aarch64__) + vst1q_f64((float64_t *) mem_addr, vreinterpretq_f64_m128d(a)); +#else + vst1q_f32((float32_t *) mem_addr, vreinterpretq_f32_m128d(a)); +#endif +} + +// Store 128-bits (composed of 2 packed double-precision (64-bit) floating-point +// elements) from a into memory. mem_addr does not need to be aligned on any +// particular boundary. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_pd +FORCE_INLINE void _mm_storeu_pd(double *mem_addr, __m128d a) +{ + _mm_store_pd(mem_addr, a); +} + +// Reads the lower 64 bits of b and stores them into the lower 64 bits of a. +// https://msdn.microsoft.com/en-us/library/hhwf428f%28v=vs.90%29.aspx +FORCE_INLINE void _mm_storel_epi64(__m128i *a, __m128i b) +{ + uint64x1_t hi = vget_high_u64(vreinterpretq_u64_m128i(*a)); + uint64x1_t lo = vget_low_u64(vreinterpretq_u64_m128i(b)); + *a = vreinterpretq_m128i_u64(vcombine_u64(lo, hi)); +} + +// Stores the lower two single-precision floating point values of a to the +// address p. +// +// *p0 := a0 +// *p1 := a1 +// +// https://msdn.microsoft.com/en-us/library/h54t98ks(v=vs.90).aspx +FORCE_INLINE void _mm_storel_pi(__m64 *p, __m128 a) +{ + *p = vreinterpret_m64_f32(vget_low_f32(a)); +} + +// Stores the upper two single-precision, floating-point values of a to the +// address p. +// +// *p0 := a2 +// *p1 := a3 +// +// https://msdn.microsoft.com/en-us/library/a7525fs8(v%3dvs.90).aspx +FORCE_INLINE void _mm_storeh_pi(__m64 *p, __m128 a) +{ + *p = vreinterpret_m64_f32(vget_high_f32(a)); +} + +// Loads a single single-precision, floating-point value, copying it into all +// four words +// https://msdn.microsoft.com/en-us/library/vstudio/5cdkf716(v=vs.100).aspx +FORCE_INLINE __m128 _mm_load1_ps(const float *p) +{ + return vreinterpretq_m128_f32(vld1q_dup_f32(p)); +} + +// Load a single-precision (32-bit) floating-point element from memory into all +// elements of dst. +// +// dst[31:0] := MEM[mem_addr+31:mem_addr] +// dst[63:32] := MEM[mem_addr+31:mem_addr] +// dst[95:64] := MEM[mem_addr+31:mem_addr] +// dst[127:96] := MEM[mem_addr+31:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_ps1 +#define _mm_load_ps1 _mm_load1_ps + +// Sets the lower two single-precision, floating-point values with 64 +// bits of data loaded from the address p; the upper two values are passed +// through from a. +// +// Return Value +// r0 := *p0 +// r1 := *p1 +// r2 := a2 +// r3 := a3 +// +// https://msdn.microsoft.com/en-us/library/s57cyak2(v=vs.100).aspx +FORCE_INLINE __m128 _mm_loadl_pi(__m128 a, __m64 const *p) +{ + return vreinterpretq_m128_f32( + vcombine_f32(vld1_f32((const float32_t *) p), vget_high_f32(a))); +} + +// Load 4 single-precision (32-bit) floating-point elements from memory into dst +// in reverse order. mem_addr must be aligned on a 16-byte boundary or a +// general-protection exception may be generated. +// +// dst[31:0] := MEM[mem_addr+127:mem_addr+96] +// dst[63:32] := MEM[mem_addr+95:mem_addr+64] +// dst[95:64] := MEM[mem_addr+63:mem_addr+32] +// dst[127:96] := MEM[mem_addr+31:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadr_ps +FORCE_INLINE __m128 _mm_loadr_ps(const float *p) +{ + float32x4_t v = vrev64q_f32(vld1q_f32(p)); + return vreinterpretq_m128_f32(vextq_f32(v, v, 2)); +} + +// Sets the upper two single-precision, floating-point values with 64 +// bits of data loaded from the address p; the lower two values are passed +// through from a. +// +// r0 := a0 +// r1 := a1 +// r2 := *p0 +// r3 := *p1 +// +// https://msdn.microsoft.com/en-us/library/w92wta0x(v%3dvs.100).aspx +FORCE_INLINE __m128 _mm_loadh_pi(__m128 a, __m64 const *p) +{ + return vreinterpretq_m128_f32( + vcombine_f32(vget_low_f32(a), vld1_f32((const float32_t *) p))); +} + +// Loads four single-precision, floating-point values. +// https://msdn.microsoft.com/en-us/library/vstudio/zzd50xxt(v=vs.100).aspx +FORCE_INLINE __m128 _mm_load_ps(const float *p) +{ + return vreinterpretq_m128_f32(vld1q_f32(p)); +} + +// Loads four single-precision, floating-point values. +// https://msdn.microsoft.com/en-us/library/x1b16s7z%28v=vs.90%29.aspx +FORCE_INLINE __m128 _mm_loadu_ps(const float *p) +{ + // for neon, alignment doesn't matter, so _mm_load_ps and _mm_loadu_ps are + // equivalent for neon + return vreinterpretq_m128_f32(vld1q_f32(p)); +} + +// Load unaligned 16-bit integer from memory into the first element of dst. +// +// dst[15:0] := MEM[mem_addr+15:mem_addr] +// dst[MAX:16] := 0 +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si16 +FORCE_INLINE __m128i _mm_loadu_si16(const void *p) +{ + return vreinterpretq_m128i_s16( + vsetq_lane_s16(*(const int16_t *) p, vdupq_n_s16(0), 0)); +} + +// Load unaligned 64-bit integer from memory into the first element of dst. +// +// dst[63:0] := MEM[mem_addr+63:mem_addr] +// dst[MAX:64] := 0 +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si64 +FORCE_INLINE __m128i _mm_loadu_si64(const void *p) +{ + return vreinterpretq_m128i_s64( + vcombine_s64(vld1_s64((const int64_t *) p), vdup_n_s64(0))); +} + +// Load a double-precision (64-bit) floating-point element from memory into the +// lower of dst, and zero the upper element. mem_addr does not need to be +// aligned on any particular boundary. +// +// dst[63:0] := MEM[mem_addr+63:mem_addr] +// dst[127:64] := 0 +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_sd +FORCE_INLINE __m128d _mm_load_sd(const double *p) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64(vsetq_lane_f64(*p, vdupq_n_f64(0), 0)); +#else + const float *fp = (const float *) p; + float ALIGN_STRUCT(16) data[4] = {fp[0], fp[1], 0, 0}; + return vreinterpretq_m128d_f32(vld1q_f32(data)); +#endif +} + +// Loads two double-precision from 16-byte aligned memory, floating-point +// values. +// +// dst[127:0] := MEM[mem_addr+127:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_pd +FORCE_INLINE __m128d _mm_load_pd(const double *p) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64(vld1q_f64(p)); +#else + const float *fp = (const float *) p; + float ALIGN_STRUCT(16) data[4] = {fp[0], fp[1], fp[2], fp[3]}; + return vreinterpretq_m128d_f32(vld1q_f32(data)); +#endif +} + +// Loads two double-precision from unaligned memory, floating-point values. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_pd +FORCE_INLINE __m128d _mm_loadu_pd(const double *p) +{ + return _mm_load_pd(p); +} + +// Loads an single - precision, floating - point value into the low word and +// clears the upper three words. +// https://msdn.microsoft.com/en-us/library/548bb9h4%28v=vs.90%29.aspx +FORCE_INLINE __m128 _mm_load_ss(const float *p) +{ + return vreinterpretq_m128_f32(vsetq_lane_f32(*p, vdupq_n_f32(0), 0)); +} + +FORCE_INLINE __m128i _mm_loadl_epi64(__m128i const *p) +{ + /* Load the lower 64 bits of the value pointed to by p into the + * lower 64 bits of the result, zeroing the upper 64 bits of the result. + */ + return vreinterpretq_m128i_s32( + vcombine_s32(vld1_s32((int32_t const *) p), vcreate_s32(0))); +} + +// Load a double-precision (64-bit) floating-point element from memory into the +// lower element of dst, and copy the upper element from a to dst. mem_addr does +// not need to be aligned on any particular boundary. +// +// dst[63:0] := MEM[mem_addr+63:mem_addr] +// dst[127:64] := a[127:64] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadl_pd +FORCE_INLINE __m128d _mm_loadl_pd(__m128d a, const double *p) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64( + vcombine_f64(vld1_f64(p), vget_high_f64(vreinterpretq_f64_m128d(a)))); +#else + return vreinterpretq_m128d_f32( + vcombine_f32(vld1_f32((const float *) p), + vget_high_f32(vreinterpretq_f32_m128d(a)))); +#endif +} + +// Load 2 double-precision (64-bit) floating-point elements from memory into dst +// in reverse order. mem_addr must be aligned on a 16-byte boundary or a +// general-protection exception may be generated. +// +// dst[63:0] := MEM[mem_addr+127:mem_addr+64] +// dst[127:64] := MEM[mem_addr+63:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadr_pd +FORCE_INLINE __m128d _mm_loadr_pd(const double *p) +{ +#if defined(__aarch64__) + float64x2_t v = vld1q_f64(p); + return vreinterpretq_m128d_f64(vextq_f64(v, v, 1)); +#else + int64x2_t v = vld1q_s64((const int64_t *) p); + return vreinterpretq_m128d_s64(vextq_s64(v, v, 1)); +#endif +} + +// Sets the low word to the single-precision, floating-point value of b +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/35hdzazd(v=vs.100) +FORCE_INLINE __m128 _mm_move_ss(__m128 a, __m128 b) +{ + return vreinterpretq_m128_f32( + vsetq_lane_f32(vgetq_lane_f32(vreinterpretq_f32_m128(b), 0), + vreinterpretq_f32_m128(a), 0)); +} + +// Copy the lower 64-bit integer in a to the lower element of dst, and zero the +// upper element. +// +// dst[63:0] := a[63:0] +// dst[127:64] := 0 +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_move_epi64 +FORCE_INLINE __m128i _mm_move_epi64(__m128i a) +{ + return vreinterpretq_m128i_s64( + vsetq_lane_s64(0, vreinterpretq_s64_m128i(a), 1)); +} + +// Return vector of type __m128 with undefined elements. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_undefined_ps +FORCE_INLINE __m128 _mm_undefined_ps(void) +{ + __m128 a; + return a; +} + +/* Logic/Binary operations */ + +// Computes the bitwise AND-NOT of the four single-precision, floating-point +// values of a and b. +// +// r0 := ~a0 & b0 +// r1 := ~a1 & b1 +// r2 := ~a2 & b2 +// r3 := ~a3 & b3 +// +// https://msdn.microsoft.com/en-us/library/vstudio/68h7wd02(v=vs.100).aspx +FORCE_INLINE __m128 _mm_andnot_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_s32( + vbicq_s32(vreinterpretq_s32_m128(b), + vreinterpretq_s32_m128(a))); // *NOTE* argument swap +} + +// Compute the bitwise NOT of packed double-precision (64-bit) floating-point +// elements in a and then AND with b, and store the results in dst. +// +// FOR j := 0 to 1 +// i := j*64 +// dst[i+63:i] := ((NOT a[i+63:i]) AND b[i+63:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_andnot_pd +FORCE_INLINE __m128d _mm_andnot_pd(__m128d a, __m128d b) +{ + // *NOTE* argument swap + return vreinterpretq_m128d_s64( + vbicq_s64(vreinterpretq_s64_m128d(b), vreinterpretq_s64_m128d(a))); +} + +// Computes the bitwise AND of the 128-bit value in b and the bitwise NOT of the +// 128-bit value in a. +// +// r := (~a) & b +// +// https://msdn.microsoft.com/en-us/library/vstudio/1beaceh8(v=vs.100).aspx +FORCE_INLINE __m128i _mm_andnot_si128(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s32( + vbicq_s32(vreinterpretq_s32_m128i(b), + vreinterpretq_s32_m128i(a))); // *NOTE* argument swap +} + +// Computes the bitwise AND of the 128-bit value in a and the 128-bit value in +// b. +// +// r := a & b +// +// https://msdn.microsoft.com/en-us/library/vstudio/6d1txsa8(v=vs.100).aspx +FORCE_INLINE __m128i _mm_and_si128(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s32( + vandq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +} + +// Computes the bitwise AND of the four single-precision, floating-point values +// of a and b. +// +// r0 := a0 & b0 +// r1 := a1 & b1 +// r2 := a2 & b2 +// r3 := a3 & b3 +// +// https://msdn.microsoft.com/en-us/library/vstudio/73ck1xc5(v=vs.100).aspx +FORCE_INLINE __m128 _mm_and_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_s32( + vandq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b))); +} + +// Compute the bitwise AND of packed double-precision (64-bit) floating-point +// elements in a and b, and store the results in dst. +// +// FOR j := 0 to 1 +// i := j*64 +// dst[i+63:i] := a[i+63:i] AND b[i+63:i] +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_and_pd +FORCE_INLINE __m128d _mm_and_pd(__m128d a, __m128d b) +{ + return vreinterpretq_m128d_s64( + vandq_s64(vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b))); +} + +// Computes the bitwise OR of the four single-precision, floating-point values +// of a and b. +// https://msdn.microsoft.com/en-us/library/vstudio/7ctdsyy0(v=vs.100).aspx +FORCE_INLINE __m128 _mm_or_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_s32( + vorrq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b))); +} + +// Computes bitwise EXOR (exclusive-or) of the four single-precision, +// floating-point values of a and b. +// https://msdn.microsoft.com/en-us/library/ss6k3wk8(v=vs.100).aspx +FORCE_INLINE __m128 _mm_xor_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_s32( + veorq_s32(vreinterpretq_s32_m128(a), vreinterpretq_s32_m128(b))); +} + +// Compute the bitwise XOR of packed double-precision (64-bit) floating-point +// elements in a and b, and store the results in dst. +// +// FOR j := 0 to 1 +// i := j*64 +// dst[i+63:i] := a[i+63:i] XOR b[i+63:i] +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_xor_pd +FORCE_INLINE __m128d _mm_xor_pd(__m128d a, __m128d b) +{ + return vreinterpretq_m128d_s64( + veorq_s64(vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b))); +} + +// Computes the bitwise OR of the 128-bit value in a and the 128-bit value in b. +// +// r := a | b +// +// https://msdn.microsoft.com/en-us/library/vstudio/ew8ty0db(v=vs.100).aspx +FORCE_INLINE __m128i _mm_or_si128(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s32( + vorrq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +} + +// Computes the bitwise XOR of the 128-bit value in a and the 128-bit value in +// b. https://msdn.microsoft.com/en-us/library/fzt08www(v=vs.100).aspx +FORCE_INLINE __m128i _mm_xor_si128(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s32( + veorq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +} + +// Duplicate odd-indexed single-precision (32-bit) floating-point elements +// from a, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movehdup_ps +FORCE_INLINE __m128 _mm_movehdup_ps(__m128 a) +{ +#if __has_builtin(__builtin_shufflevector) + return vreinterpretq_m128_f32(__builtin_shufflevector( + vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 1, 1, 3, 3)); +#else + float32_t a1 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 1); + float32_t a3 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 3); + float ALIGN_STRUCT(16) data[4] = {a1, a1, a3, a3}; + return vreinterpretq_m128_f32(vld1q_f32(data)); +#endif +} + +// Duplicate even-indexed single-precision (32-bit) floating-point elements +// from a, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_moveldup_ps +FORCE_INLINE __m128 _mm_moveldup_ps(__m128 a) +{ +#if __has_builtin(__builtin_shufflevector) + return vreinterpretq_m128_f32(__builtin_shufflevector( + vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 0, 0, 2, 2)); +#else + float32_t a0 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); + float32_t a2 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 2); + float ALIGN_STRUCT(16) data[4] = {a0, a0, a2, a2}; + return vreinterpretq_m128_f32(vld1q_f32(data)); +#endif +} + +// Moves the upper two values of B into the lower two values of A. +// +// r3 := a3 +// r2 := a2 +// r1 := b3 +// r0 := b2 +FORCE_INLINE __m128 _mm_movehl_ps(__m128 __A, __m128 __B) +{ + float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(__A)); + float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(__B)); + return vreinterpretq_m128_f32(vcombine_f32(b32, a32)); +} + +// Moves the lower two values of B into the upper two values of A. +// +// r3 := b1 +// r2 := b0 +// r1 := a1 +// r0 := a0 +FORCE_INLINE __m128 _mm_movelh_ps(__m128 __A, __m128 __B) +{ + float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(__A)); + float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(__B)); + return vreinterpretq_m128_f32(vcombine_f32(a10, b10)); +} + +// Compute the absolute value of packed signed 32-bit integers in a, and store +// the unsigned results in dst. +// +// FOR j := 0 to 3 +// i := j*32 +// dst[i+31:i] := ABS(a[i+31:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi32 +FORCE_INLINE __m128i _mm_abs_epi32(__m128i a) +{ + return vreinterpretq_m128i_s32(vabsq_s32(vreinterpretq_s32_m128i(a))); +} + +// Compute the absolute value of packed signed 16-bit integers in a, and store +// the unsigned results in dst. +// +// FOR j := 0 to 7 +// i := j*16 +// dst[i+15:i] := ABS(a[i+15:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi16 +FORCE_INLINE __m128i _mm_abs_epi16(__m128i a) +{ + return vreinterpretq_m128i_s16(vabsq_s16(vreinterpretq_s16_m128i(a))); +} + +// Compute the absolute value of packed signed 8-bit integers in a, and store +// the unsigned results in dst. +// +// FOR j := 0 to 15 +// i := j*8 +// dst[i+7:i] := ABS(a[i+7:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi8 +FORCE_INLINE __m128i _mm_abs_epi8(__m128i a) +{ + return vreinterpretq_m128i_s8(vabsq_s8(vreinterpretq_s8_m128i(a))); +} + +// Compute the absolute value of packed signed 32-bit integers in a, and store +// the unsigned results in dst. +// +// FOR j := 0 to 1 +// i := j*32 +// dst[i+31:i] := ABS(a[i+31:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi32 +FORCE_INLINE __m64 _mm_abs_pi32(__m64 a) +{ + return vreinterpret_m64_s32(vabs_s32(vreinterpret_s32_m64(a))); +} + +// Compute the absolute value of packed signed 16-bit integers in a, and store +// the unsigned results in dst. +// +// FOR j := 0 to 3 +// i := j*16 +// dst[i+15:i] := ABS(a[i+15:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi16 +FORCE_INLINE __m64 _mm_abs_pi16(__m64 a) +{ + return vreinterpret_m64_s16(vabs_s16(vreinterpret_s16_m64(a))); +} + +// Compute the absolute value of packed signed 8-bit integers in a, and store +// the unsigned results in dst. +// +// FOR j := 0 to 7 +// i := j*8 +// dst[i+7:i] := ABS(a[i+7:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi8 +FORCE_INLINE __m64 _mm_abs_pi8(__m64 a) +{ + return vreinterpret_m64_s8(vabs_s8(vreinterpret_s8_m64(a))); +} + +// Takes the upper 64 bits of a and places it in the low end of the result +// Takes the lower 64 bits of b and places it into the high end of the result. +FORCE_INLINE __m128 _mm_shuffle_ps_1032(__m128 a, __m128 b) +{ + float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a)); + float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b)); + return vreinterpretq_m128_f32(vcombine_f32(a32, b10)); +} + +// takes the lower two 32-bit values from a and swaps them and places in high +// end of result takes the higher two 32 bit values from b and swaps them and +// places in low end of result. +FORCE_INLINE __m128 _mm_shuffle_ps_2301(__m128 a, __m128 b) +{ + float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a))); + float32x2_t b23 = vrev64_f32(vget_high_f32(vreinterpretq_f32_m128(b))); + return vreinterpretq_m128_f32(vcombine_f32(a01, b23)); +} + +FORCE_INLINE __m128 _mm_shuffle_ps_0321(__m128 a, __m128 b) +{ + float32x2_t a21 = vget_high_f32( + vextq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 3)); + float32x2_t b03 = vget_low_f32( + vextq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b), 3)); + return vreinterpretq_m128_f32(vcombine_f32(a21, b03)); +} + +FORCE_INLINE __m128 _mm_shuffle_ps_2103(__m128 a, __m128 b) +{ + float32x2_t a03 = vget_low_f32( + vextq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 3)); + float32x2_t b21 = vget_high_f32( + vextq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b), 3)); + return vreinterpretq_m128_f32(vcombine_f32(a03, b21)); +} + +FORCE_INLINE __m128 _mm_shuffle_ps_1010(__m128 a, __m128 b) +{ + float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a)); + float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b)); + return vreinterpretq_m128_f32(vcombine_f32(a10, b10)); +} + +FORCE_INLINE __m128 _mm_shuffle_ps_1001(__m128 a, __m128 b) +{ + float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a))); + float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b)); + return vreinterpretq_m128_f32(vcombine_f32(a01, b10)); +} + +FORCE_INLINE __m128 _mm_shuffle_ps_0101(__m128 a, __m128 b) +{ + float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a))); + float32x2_t b01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(b))); + return vreinterpretq_m128_f32(vcombine_f32(a01, b01)); +} + +// keeps the low 64 bits of b in the low and puts the high 64 bits of a in the +// high +FORCE_INLINE __m128 _mm_shuffle_ps_3210(__m128 a, __m128 b) +{ + float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a)); + float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b)); + return vreinterpretq_m128_f32(vcombine_f32(a10, b32)); +} + +FORCE_INLINE __m128 _mm_shuffle_ps_0011(__m128 a, __m128 b) +{ + float32x2_t a11 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(a)), 1); + float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0); + return vreinterpretq_m128_f32(vcombine_f32(a11, b00)); +} + +FORCE_INLINE __m128 _mm_shuffle_ps_0022(__m128 a, __m128 b) +{ + float32x2_t a22 = + vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(a)), 0); + float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0); + return vreinterpretq_m128_f32(vcombine_f32(a22, b00)); +} + +FORCE_INLINE __m128 _mm_shuffle_ps_2200(__m128 a, __m128 b) +{ + float32x2_t a00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(a)), 0); + float32x2_t b22 = + vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(b)), 0); + return vreinterpretq_m128_f32(vcombine_f32(a00, b22)); +} + +FORCE_INLINE __m128 _mm_shuffle_ps_3202(__m128 a, __m128 b) +{ + float32_t a0 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); + float32x2_t a22 = + vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(a)), 0); + float32x2_t a02 = vset_lane_f32(a0, a22, 1); /* TODO: use vzip ?*/ + float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b)); + return vreinterpretq_m128_f32(vcombine_f32(a02, b32)); +} + +FORCE_INLINE __m128 _mm_shuffle_ps_1133(__m128 a, __m128 b) +{ + float32x2_t a33 = + vdup_lane_f32(vget_high_f32(vreinterpretq_f32_m128(a)), 1); + float32x2_t b11 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 1); + return vreinterpretq_m128_f32(vcombine_f32(a33, b11)); +} + +FORCE_INLINE __m128 _mm_shuffle_ps_2010(__m128 a, __m128 b) +{ + float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a)); + float32_t b2 = vgetq_lane_f32(vreinterpretq_f32_m128(b), 2); + float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0); + float32x2_t b20 = vset_lane_f32(b2, b00, 1); + return vreinterpretq_m128_f32(vcombine_f32(a10, b20)); +} + +FORCE_INLINE __m128 _mm_shuffle_ps_2001(__m128 a, __m128 b) +{ + float32x2_t a01 = vrev64_f32(vget_low_f32(vreinterpretq_f32_m128(a))); + float32_t b2 = vgetq_lane_f32(b, 2); + float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0); + float32x2_t b20 = vset_lane_f32(b2, b00, 1); + return vreinterpretq_m128_f32(vcombine_f32(a01, b20)); +} + +FORCE_INLINE __m128 _mm_shuffle_ps_2032(__m128 a, __m128 b) +{ + float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a)); + float32_t b2 = vgetq_lane_f32(b, 2); + float32x2_t b00 = vdup_lane_f32(vget_low_f32(vreinterpretq_f32_m128(b)), 0); + float32x2_t b20 = vset_lane_f32(b2, b00, 1); + return vreinterpretq_m128_f32(vcombine_f32(a32, b20)); +} + +// NEON does not support a general purpose permute intrinsic +// Selects four specific single-precision, floating-point values from a and b, +// based on the mask i. +// +// C equivalent: +// __m128 _mm_shuffle_ps_default(__m128 a, __m128 b, +// __constrange(0, 255) int imm) { +// __m128 ret; +// ret[0] = a[imm & 0x3]; ret[1] = a[(imm >> 2) & 0x3]; +// ret[2] = b[(imm >> 4) & 0x03]; ret[3] = b[(imm >> 6) & 0x03]; +// return ret; +// } +// +// https://msdn.microsoft.com/en-us/library/vstudio/5f0858x0(v=vs.100).aspx +#define _mm_shuffle_ps_default(a, b, imm) \ + __extension__({ \ + float32x4_t ret; \ + ret = vmovq_n_f32( \ + vgetq_lane_f32(vreinterpretq_f32_m128(a), (imm) & (0x3))); \ + ret = vsetq_lane_f32( \ + vgetq_lane_f32(vreinterpretq_f32_m128(a), ((imm) >> 2) & 0x3), \ + ret, 1); \ + ret = vsetq_lane_f32( \ + vgetq_lane_f32(vreinterpretq_f32_m128(b), ((imm) >> 4) & 0x3), \ + ret, 2); \ + ret = vsetq_lane_f32( \ + vgetq_lane_f32(vreinterpretq_f32_m128(b), ((imm) >> 6) & 0x3), \ + ret, 3); \ + vreinterpretq_m128_f32(ret); \ + }) + +// FORCE_INLINE __m128 _mm_shuffle_ps(__m128 a, __m128 b, __constrange(0,255) +// int imm) +#if __has_builtin(__builtin_shufflevector) +#define _mm_shuffle_ps(a, b, imm) \ + __extension__({ \ + float32x4_t _input1 = vreinterpretq_f32_m128(a); \ + float32x4_t _input2 = vreinterpretq_f32_m128(b); \ + float32x4_t _shuf = __builtin_shufflevector( \ + _input1, _input2, (imm) & (0x3), ((imm) >> 2) & 0x3, \ + (((imm) >> 4) & 0x3) + 4, (((imm) >> 6) & 0x3) + 4); \ + vreinterpretq_m128_f32(_shuf); \ + }) +#else // generic +#define _mm_shuffle_ps(a, b, imm) \ + __extension__({ \ + __m128 ret; \ + switch (imm) { \ + case _MM_SHUFFLE(1, 0, 3, 2): \ + ret = _mm_shuffle_ps_1032((a), (b)); \ + break; \ + case _MM_SHUFFLE(2, 3, 0, 1): \ + ret = _mm_shuffle_ps_2301((a), (b)); \ + break; \ + case _MM_SHUFFLE(0, 3, 2, 1): \ + ret = _mm_shuffle_ps_0321((a), (b)); \ + break; \ + case _MM_SHUFFLE(2, 1, 0, 3): \ + ret = _mm_shuffle_ps_2103((a), (b)); \ + break; \ + case _MM_SHUFFLE(1, 0, 1, 0): \ + ret = _mm_movelh_ps((a), (b)); \ + break; \ + case _MM_SHUFFLE(1, 0, 0, 1): \ + ret = _mm_shuffle_ps_1001((a), (b)); \ + break; \ + case _MM_SHUFFLE(0, 1, 0, 1): \ + ret = _mm_shuffle_ps_0101((a), (b)); \ + break; \ + case _MM_SHUFFLE(3, 2, 1, 0): \ + ret = _mm_shuffle_ps_3210((a), (b)); \ + break; \ + case _MM_SHUFFLE(0, 0, 1, 1): \ + ret = _mm_shuffle_ps_0011((a), (b)); \ + break; \ + case _MM_SHUFFLE(0, 0, 2, 2): \ + ret = _mm_shuffle_ps_0022((a), (b)); \ + break; \ + case _MM_SHUFFLE(2, 2, 0, 0): \ + ret = _mm_shuffle_ps_2200((a), (b)); \ + break; \ + case _MM_SHUFFLE(3, 2, 0, 2): \ + ret = _mm_shuffle_ps_3202((a), (b)); \ + break; \ + case _MM_SHUFFLE(3, 2, 3, 2): \ + ret = _mm_movehl_ps((b), (a)); \ + break; \ + case _MM_SHUFFLE(1, 1, 3, 3): \ + ret = _mm_shuffle_ps_1133((a), (b)); \ + break; \ + case _MM_SHUFFLE(2, 0, 1, 0): \ + ret = _mm_shuffle_ps_2010((a), (b)); \ + break; \ + case _MM_SHUFFLE(2, 0, 0, 1): \ + ret = _mm_shuffle_ps_2001((a), (b)); \ + break; \ + case _MM_SHUFFLE(2, 0, 3, 2): \ + ret = _mm_shuffle_ps_2032((a), (b)); \ + break; \ + default: \ + ret = _mm_shuffle_ps_default((a), (b), (imm)); \ + break; \ + } \ + ret; \ + }) +#endif + +// Takes the upper 64 bits of a and places it in the low end of the result +// Takes the lower 64 bits of a and places it into the high end of the result. +FORCE_INLINE __m128i _mm_shuffle_epi_1032(__m128i a) +{ + int32x2_t a32 = vget_high_s32(vreinterpretq_s32_m128i(a)); + int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a)); + return vreinterpretq_m128i_s32(vcombine_s32(a32, a10)); +} + +// takes the lower two 32-bit values from a and swaps them and places in low end +// of result takes the higher two 32 bit values from a and swaps them and places +// in high end of result. +FORCE_INLINE __m128i _mm_shuffle_epi_2301(__m128i a) +{ + int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a))); + int32x2_t a23 = vrev64_s32(vget_high_s32(vreinterpretq_s32_m128i(a))); + return vreinterpretq_m128i_s32(vcombine_s32(a01, a23)); +} + +// rotates the least significant 32 bits into the most signficant 32 bits, and +// shifts the rest down +FORCE_INLINE __m128i _mm_shuffle_epi_0321(__m128i a) +{ + return vreinterpretq_m128i_s32( + vextq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(a), 1)); +} + +// rotates the most significant 32 bits into the least signficant 32 bits, and +// shifts the rest up +FORCE_INLINE __m128i _mm_shuffle_epi_2103(__m128i a) +{ + return vreinterpretq_m128i_s32( + vextq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(a), 3)); +} + +// gets the lower 64 bits of a, and places it in the upper 64 bits +// gets the lower 64 bits of a and places it in the lower 64 bits +FORCE_INLINE __m128i _mm_shuffle_epi_1010(__m128i a) +{ + int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a)); + return vreinterpretq_m128i_s32(vcombine_s32(a10, a10)); +} + +// gets the lower 64 bits of a, swaps the 0 and 1 elements, and places it in the +// lower 64 bits gets the lower 64 bits of a, and places it in the upper 64 bits +FORCE_INLINE __m128i _mm_shuffle_epi_1001(__m128i a) +{ + int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a))); + int32x2_t a10 = vget_low_s32(vreinterpretq_s32_m128i(a)); + return vreinterpretq_m128i_s32(vcombine_s32(a01, a10)); +} + +// gets the lower 64 bits of a, swaps the 0 and 1 elements and places it in the +// upper 64 bits gets the lower 64 bits of a, swaps the 0 and 1 elements, and +// places it in the lower 64 bits +FORCE_INLINE __m128i _mm_shuffle_epi_0101(__m128i a) +{ + int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a))); + return vreinterpretq_m128i_s32(vcombine_s32(a01, a01)); +} + +FORCE_INLINE __m128i _mm_shuffle_epi_2211(__m128i a) +{ + int32x2_t a11 = vdup_lane_s32(vget_low_s32(vreinterpretq_s32_m128i(a)), 1); + int32x2_t a22 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 0); + return vreinterpretq_m128i_s32(vcombine_s32(a11, a22)); +} + +FORCE_INLINE __m128i _mm_shuffle_epi_0122(__m128i a) +{ + int32x2_t a22 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 0); + int32x2_t a01 = vrev64_s32(vget_low_s32(vreinterpretq_s32_m128i(a))); + return vreinterpretq_m128i_s32(vcombine_s32(a22, a01)); +} + +FORCE_INLINE __m128i _mm_shuffle_epi_3332(__m128i a) +{ + int32x2_t a32 = vget_high_s32(vreinterpretq_s32_m128i(a)); + int32x2_t a33 = vdup_lane_s32(vget_high_s32(vreinterpretq_s32_m128i(a)), 1); + return vreinterpretq_m128i_s32(vcombine_s32(a32, a33)); +} + +// Shuffle packed 8-bit integers in a according to shuffle control mask in the +// corresponding 8-bit element of b, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_epi8 +FORCE_INLINE __m128i _mm_shuffle_epi8(__m128i a, __m128i b) +{ + int8x16_t tbl = vreinterpretq_s8_m128i(a); // input a + uint8x16_t idx = vreinterpretq_u8_m128i(b); // input b + uint8x16_t idx_masked = + vandq_u8(idx, vdupq_n_u8(0x8F)); // avoid using meaningless bits +#if defined(__aarch64__) + return vreinterpretq_m128i_s8(vqtbl1q_s8(tbl, idx_masked)); +#elif defined(__GNUC__) + int8x16_t ret; + // %e and %f represent the even and odd D registers + // respectively. + __asm__ __volatile__( + "vtbl.8 %e[ret], {%e[tbl], %f[tbl]}, %e[idx]\n" + "vtbl.8 %f[ret], {%e[tbl], %f[tbl]}, %f[idx]\n" + : [ret] "=&w"(ret) + : [tbl] "w"(tbl), [idx] "w"(idx_masked)); + return vreinterpretq_m128i_s8(ret); +#else + // use this line if testing on aarch64 + int8x8x2_t a_split = {vget_low_s8(tbl), vget_high_s8(tbl)}; + return vreinterpretq_m128i_s8( + vcombine_s8(vtbl2_s8(a_split, vget_low_u8(idx_masked)), + vtbl2_s8(a_split, vget_high_u8(idx_masked)))); +#endif +} + +// C equivalent: +// __m128i _mm_shuffle_epi32_default(__m128i a, +// __constrange(0, 255) int imm) { +// __m128i ret; +// ret[0] = a[imm & 0x3]; ret[1] = a[(imm >> 2) & 0x3]; +// ret[2] = a[(imm >> 4) & 0x03]; ret[3] = a[(imm >> 6) & 0x03]; +// return ret; +// } +#define _mm_shuffle_epi32_default(a, imm) \ + __extension__({ \ + int32x4_t ret; \ + ret = vmovq_n_s32( \ + vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm) & (0x3))); \ + ret = vsetq_lane_s32( \ + vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 2) & 0x3), \ + ret, 1); \ + ret = vsetq_lane_s32( \ + vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 4) & 0x3), \ + ret, 2); \ + ret = vsetq_lane_s32( \ + vgetq_lane_s32(vreinterpretq_s32_m128i(a), ((imm) >> 6) & 0x3), \ + ret, 3); \ + vreinterpretq_m128i_s32(ret); \ + }) + +// FORCE_INLINE __m128i _mm_shuffle_epi32_splat(__m128i a, __constrange(0,255) +// int imm) +#if defined(__aarch64__) +#define _mm_shuffle_epi32_splat(a, imm) \ + __extension__({ \ + vreinterpretq_m128i_s32( \ + vdupq_laneq_s32(vreinterpretq_s32_m128i(a), (imm))); \ + }) +#else +#define _mm_shuffle_epi32_splat(a, imm) \ + __extension__({ \ + vreinterpretq_m128i_s32( \ + vdupq_n_s32(vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm)))); \ + }) +#endif + +// Shuffles the 4 signed or unsigned 32-bit integers in a as specified by imm. +// https://msdn.microsoft.com/en-us/library/56f67xbk%28v=vs.90%29.aspx +// FORCE_INLINE __m128i _mm_shuffle_epi32(__m128i a, +// __constrange(0,255) int imm) +#if __has_builtin(__builtin_shufflevector) +#define _mm_shuffle_epi32(a, imm) \ + __extension__({ \ + int32x4_t _input = vreinterpretq_s32_m128i(a); \ + int32x4_t _shuf = __builtin_shufflevector( \ + _input, _input, (imm) & (0x3), ((imm) >> 2) & 0x3, \ + ((imm) >> 4) & 0x3, ((imm) >> 6) & 0x3); \ + vreinterpretq_m128i_s32(_shuf); \ + }) +#else // generic +#define _mm_shuffle_epi32(a, imm) \ + __extension__({ \ + __m128i ret; \ + switch (imm) { \ + case _MM_SHUFFLE(1, 0, 3, 2): \ + ret = _mm_shuffle_epi_1032((a)); \ + break; \ + case _MM_SHUFFLE(2, 3, 0, 1): \ + ret = _mm_shuffle_epi_2301((a)); \ + break; \ + case _MM_SHUFFLE(0, 3, 2, 1): \ + ret = _mm_shuffle_epi_0321((a)); \ + break; \ + case _MM_SHUFFLE(2, 1, 0, 3): \ + ret = _mm_shuffle_epi_2103((a)); \ + break; \ + case _MM_SHUFFLE(1, 0, 1, 0): \ + ret = _mm_shuffle_epi_1010((a)); \ + break; \ + case _MM_SHUFFLE(1, 0, 0, 1): \ + ret = _mm_shuffle_epi_1001((a)); \ + break; \ + case _MM_SHUFFLE(0, 1, 0, 1): \ + ret = _mm_shuffle_epi_0101((a)); \ + break; \ + case _MM_SHUFFLE(2, 2, 1, 1): \ + ret = _mm_shuffle_epi_2211((a)); \ + break; \ + case _MM_SHUFFLE(0, 1, 2, 2): \ + ret = _mm_shuffle_epi_0122((a)); \ + break; \ + case _MM_SHUFFLE(3, 3, 3, 2): \ + ret = _mm_shuffle_epi_3332((a)); \ + break; \ + case _MM_SHUFFLE(0, 0, 0, 0): \ + ret = _mm_shuffle_epi32_splat((a), 0); \ + break; \ + case _MM_SHUFFLE(1, 1, 1, 1): \ + ret = _mm_shuffle_epi32_splat((a), 1); \ + break; \ + case _MM_SHUFFLE(2, 2, 2, 2): \ + ret = _mm_shuffle_epi32_splat((a), 2); \ + break; \ + case _MM_SHUFFLE(3, 3, 3, 3): \ + ret = _mm_shuffle_epi32_splat((a), 3); \ + break; \ + default: \ + ret = _mm_shuffle_epi32_default((a), (imm)); \ + break; \ + } \ + ret; \ + }) +#endif + +// Shuffles the lower 4 signed or unsigned 16-bit integers in a as specified +// by imm. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/y41dkk37(v=vs.100) +// FORCE_INLINE __m128i _mm_shufflelo_epi16_function(__m128i a, +// __constrange(0,255) int +// imm) +#define _mm_shufflelo_epi16_function(a, imm) \ + __extension__({ \ + int16x8_t ret = vreinterpretq_s16_m128i(a); \ + int16x4_t lowBits = vget_low_s16(ret); \ + ret = vsetq_lane_s16(vget_lane_s16(lowBits, (imm) & (0x3)), ret, 0); \ + ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 2) & 0x3), ret, \ + 1); \ + ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 4) & 0x3), ret, \ + 2); \ + ret = vsetq_lane_s16(vget_lane_s16(lowBits, ((imm) >> 6) & 0x3), ret, \ + 3); \ + vreinterpretq_m128i_s16(ret); \ + }) + +// FORCE_INLINE __m128i _mm_shufflelo_epi16(__m128i a, +// __constrange(0,255) int imm) +#if __has_builtin(__builtin_shufflevector) +#define _mm_shufflelo_epi16(a, imm) \ + __extension__({ \ + int16x8_t _input = vreinterpretq_s16_m128i(a); \ + int16x8_t _shuf = __builtin_shufflevector( \ + _input, _input, ((imm) & (0x3)), (((imm) >> 2) & 0x3), \ + (((imm) >> 4) & 0x3), (((imm) >> 6) & 0x3), 4, 5, 6, 7); \ + vreinterpretq_m128i_s16(_shuf); \ + }) +#else // generic +#define _mm_shufflelo_epi16(a, imm) _mm_shufflelo_epi16_function((a), (imm)) +#endif + +// Shuffles the upper 4 signed or unsigned 16-bit integers in a as specified +// by imm. +// https://msdn.microsoft.com/en-us/library/13ywktbs(v=vs.100).aspx +// FORCE_INLINE __m128i _mm_shufflehi_epi16_function(__m128i a, +// __constrange(0,255) int +// imm) +#define _mm_shufflehi_epi16_function(a, imm) \ + __extension__({ \ + int16x8_t ret = vreinterpretq_s16_m128i(a); \ + int16x4_t highBits = vget_high_s16(ret); \ + ret = vsetq_lane_s16(vget_lane_s16(highBits, (imm) & (0x3)), ret, 4); \ + ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 2) & 0x3), ret, \ + 5); \ + ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 4) & 0x3), ret, \ + 6); \ + ret = vsetq_lane_s16(vget_lane_s16(highBits, ((imm) >> 6) & 0x3), ret, \ + 7); \ + vreinterpretq_m128i_s16(ret); \ + }) + +// FORCE_INLINE __m128i _mm_shufflehi_epi16(__m128i a, +// __constrange(0,255) int imm) +#if __has_builtin(__builtin_shufflevector) +#define _mm_shufflehi_epi16(a, imm) \ + __extension__({ \ + int16x8_t _input = vreinterpretq_s16_m128i(a); \ + int16x8_t _shuf = __builtin_shufflevector( \ + _input, _input, 0, 1, 2, 3, ((imm) & (0x3)) + 4, \ + (((imm) >> 2) & 0x3) + 4, (((imm) >> 4) & 0x3) + 4, \ + (((imm) >> 6) & 0x3) + 4); \ + vreinterpretq_m128i_s16(_shuf); \ + }) +#else // generic +#define _mm_shufflehi_epi16(a, imm) _mm_shufflehi_epi16_function((a), (imm)) +#endif + +// Blend packed 16-bit integers from a and b using control mask imm8, and store +// the results in dst. +// +// FOR j := 0 to 7 +// i := j*16 +// IF imm8[j] +// dst[i+15:i] := b[i+15:i] +// ELSE +// dst[i+15:i] := a[i+15:i] +// FI +// ENDFOR +// FORCE_INLINE __m128i _mm_blend_epi16(__m128i a, __m128i b, +// __constrange(0,255) int imm) +#define _mm_blend_epi16(a, b, imm) \ + __extension__({ \ + const uint16_t _mask[8] = {((imm) & (1 << 0)) ? 0xFFFF : 0x0000, \ + ((imm) & (1 << 1)) ? 0xFFFF : 0x0000, \ + ((imm) & (1 << 2)) ? 0xFFFF : 0x0000, \ + ((imm) & (1 << 3)) ? 0xFFFF : 0x0000, \ + ((imm) & (1 << 4)) ? 0xFFFF : 0x0000, \ + ((imm) & (1 << 5)) ? 0xFFFF : 0x0000, \ + ((imm) & (1 << 6)) ? 0xFFFF : 0x0000, \ + ((imm) & (1 << 7)) ? 0xFFFF : 0x0000}; \ + uint16x8_t _mask_vec = vld1q_u16(_mask); \ + uint16x8_t _a = vreinterpretq_u16_m128i(a); \ + uint16x8_t _b = vreinterpretq_u16_m128i(b); \ + vreinterpretq_m128i_u16(vbslq_u16(_mask_vec, _b, _a)); \ + }) + +// Blend packed 8-bit integers from a and b using mask, and store the results in +// dst. +// +// FOR j := 0 to 15 +// i := j*8 +// IF mask[i+7] +// dst[i+7:i] := b[i+7:i] +// ELSE +// dst[i+7:i] := a[i+7:i] +// FI +// ENDFOR +FORCE_INLINE __m128i _mm_blendv_epi8(__m128i _a, __m128i _b, __m128i _mask) +{ + // Use a signed shift right to create a mask with the sign bit + uint8x16_t mask = + vreinterpretq_u8_s8(vshrq_n_s8(vreinterpretq_s8_m128i(_mask), 7)); + uint8x16_t a = vreinterpretq_u8_m128i(_a); + uint8x16_t b = vreinterpretq_u8_m128i(_b); + return vreinterpretq_m128i_u8(vbslq_u8(mask, b, a)); +} + +/* Shifts */ + + +// Shift packed 16-bit integers in a right by imm while shifting in sign +// bits, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srai_epi16 +FORCE_INLINE __m128i _mm_srai_epi16(__m128i a, int imm) +{ + const int count = (imm & ~15) ? 15 : imm; + return (__m128i) vshlq_s16((int16x8_t) a, vdupq_n_s16(-count)); +} + +// Shifts the 8 signed or unsigned 16-bit integers in a left by count bits while +// shifting in zeros. +// +// r0 := a0 << count +// r1 := a1 << count +// ... +// r7 := a7 << count +// +// https://msdn.microsoft.com/en-us/library/es73bcsy(v=vs.90).aspx +#define _mm_slli_epi16(a, imm) \ + __extension__({ \ + __m128i ret; \ + if ((imm) <= 0) { \ + ret = a; \ + } else if ((imm) > 15) { \ + ret = _mm_setzero_si128(); \ + } else { \ + ret = vreinterpretq_m128i_s16( \ + vshlq_n_s16(vreinterpretq_s16_m128i(a), (imm))); \ + } \ + ret; \ + }) + +// Shifts the 4 signed or unsigned 32-bit integers in a left by count bits while +// shifting in zeros. : +// https://msdn.microsoft.com/en-us/library/z2k3bbtb%28v=vs.90%29.aspx +// FORCE_INLINE __m128i _mm_slli_epi32(__m128i a, __constrange(0,255) int imm) +FORCE_INLINE __m128i _mm_slli_epi32(__m128i a, int imm) +{ + if (imm <= 0) /* TODO: add constant range macro: [0, 255] */ + return a; + if (imm > 31) /* TODO: add unlikely macro */ + return _mm_setzero_si128(); + return vreinterpretq_m128i_s32( + vshlq_s32(vreinterpretq_s32_m128i(a), vdupq_n_s32(imm))); +} + +// Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and +// store the results in dst. +FORCE_INLINE __m128i _mm_slli_epi64(__m128i a, int imm) +{ + if (imm <= 0) /* TODO: add constant range macro: [0, 255] */ + return a; + if (imm > 63) /* TODO: add unlikely macro */ + return _mm_setzero_si128(); + return vreinterpretq_m128i_s64( + vshlq_s64(vreinterpretq_s64_m128i(a), vdupq_n_s64(imm))); +} + +// Shift packed 16-bit integers in a right by imm8 while shifting in zeros, and +// store the results in dst. +// +// FOR j := 0 to 7 +// i := j*16 +// IF imm8[7:0] > 15 +// dst[i+15:i] := 0 +// ELSE +// dst[i+15:i] := ZeroExtend16(a[i+15:i] >> imm8[7:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi16 +#define _mm_srli_epi16(a, imm) \ + __extension__({ \ + __m128i ret; \ + if ((imm) == 0) { \ + ret = a; \ + } else if (0 < (imm) && (imm) < 16) { \ + ret = vreinterpretq_m128i_u16( \ + vshlq_u16(vreinterpretq_u16_m128i(a), vdupq_n_s16(-imm))); \ + } else { \ + ret = _mm_setzero_si128(); \ + } \ + ret; \ + }) + +// Shift packed 32-bit integers in a right by imm8 while shifting in zeros, and +// store the results in dst. +// +// FOR j := 0 to 3 +// i := j*32 +// IF imm8[7:0] > 31 +// dst[i+31:i] := 0 +// ELSE +// dst[i+31:i] := ZeroExtend32(a[i+31:i] >> imm8[7:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi32 +// FORCE_INLINE __m128i _mm_srli_epi32(__m128i a, __constrange(0,255) int imm) +#define _mm_srli_epi32(a, imm) \ + __extension__({ \ + __m128i ret; \ + if ((imm) == 0) { \ + ret = a; \ + } else if (0 < (imm) && (imm) < 32) { \ + ret = vreinterpretq_m128i_u32( \ + vshlq_u32(vreinterpretq_u32_m128i(a), vdupq_n_s32(-imm))); \ + } else { \ + ret = _mm_setzero_si128(); \ + } \ + ret; \ + }) + +// Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and +// store the results in dst. +// +// FOR j := 0 to 1 +// i := j*64 +// IF imm8[7:0] > 63 +// dst[i+63:i] := 0 +// ELSE +// dst[i+63:i] := ZeroExtend64(a[i+63:i] >> imm8[7:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi64 +#define _mm_srli_epi64(a, imm) \ + __extension__({ \ + __m128i ret; \ + if ((imm) == 0) { \ + ret = a; \ + } else if (0 < (imm) && (imm) < 64) { \ + ret = vreinterpretq_m128i_u64( \ + vshlq_u64(vreinterpretq_u64_m128i(a), vdupq_n_s64(-imm))); \ + } else { \ + ret = _mm_setzero_si128(); \ + } \ + ret; \ + }) + +// Shift packed 32-bit integers in a right by imm8 while shifting in sign bits, +// and store the results in dst. +// +// FOR j := 0 to 3 +// i := j*32 +// IF imm8[7:0] > 31 +// dst[i+31:i] := (a[i+31] ? 0xFFFFFFFF : 0x0) +// ELSE +// dst[i+31:i] := SignExtend32(a[i+31:i] >> imm8[7:0]) +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srai_epi32 +// FORCE_INLINE __m128i _mm_srai_epi32(__m128i a, __constrange(0,255) int imm) +#define _mm_srai_epi32(a, imm) \ + __extension__({ \ + __m128i ret; \ + if ((imm) == 0) { \ + ret = a; \ + } else if (0 < (imm) && (imm) < 32) { \ + ret = vreinterpretq_m128i_s32( \ + vshlq_s32(vreinterpretq_s32_m128i(a), vdupq_n_s32(-imm))); \ + } else { \ + ret = vreinterpretq_m128i_s32( \ + vshrq_n_s32(vreinterpretq_s32_m128i(a), 31)); \ + } \ + ret; \ + }) + +// Shifts the 128 - bit value in a right by imm bytes while shifting in +// zeros.imm must be an immediate. +// +// r := srl(a, imm*8) +// +// https://msdn.microsoft.com/en-us/library/305w28yz(v=vs.100).aspx +// FORCE_INLINE _mm_srli_si128(__m128i a, __constrange(0,255) int imm) +#define _mm_srli_si128(a, imm) \ + __extension__({ \ + __m128i ret; \ + if ((imm) <= 0) { \ + ret = a; \ + } else if ((imm) > 15) { \ + ret = _mm_setzero_si128(); \ + } else { \ + ret = vreinterpretq_m128i_s8( \ + vextq_s8(vreinterpretq_s8_m128i(a), vdupq_n_s8(0), (imm))); \ + } \ + ret; \ + }) + +// Shifts the 128-bit value in a left by imm bytes while shifting in zeros. imm +// must be an immediate. +// +// r := a << (imm * 8) +// +// https://msdn.microsoft.com/en-us/library/34d3k2kt(v=vs.100).aspx +// FORCE_INLINE __m128i _mm_slli_si128(__m128i a, __constrange(0,255) int imm) +#define _mm_slli_si128(a, imm) \ + __extension__({ \ + __m128i ret; \ + if ((imm) <= 0) { \ + ret = a; \ + } else if ((imm) > 15) { \ + ret = _mm_setzero_si128(); \ + } else { \ + ret = vreinterpretq_m128i_s8(vextq_s8( \ + vdupq_n_s8(0), vreinterpretq_s8_m128i(a), 16 - (imm))); \ + } \ + ret; \ + }) + +// Shifts the 8 signed or unsigned 16-bit integers in a left by count bits while +// shifting in zeros. +// +// r0 := a0 << count +// r1 := a1 << count +// ... +// r7 := a7 << count +// +// https://msdn.microsoft.com/en-us/library/c79w388h(v%3dvs.90).aspx +FORCE_INLINE __m128i _mm_sll_epi16(__m128i a, __m128i count) +{ + uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); + if (c > 15) + return _mm_setzero_si128(); + + int16x8_t vc = vdupq_n_s16((int16_t) c); + return vreinterpretq_m128i_s16(vshlq_s16(vreinterpretq_s16_m128i(a), vc)); +} + +// Shifts the 4 signed or unsigned 32-bit integers in a left by count bits while +// shifting in zeros. +// +// r0 := a0 << count +// r1 := a1 << count +// r2 := a2 << count +// r3 := a3 << count +// +// https://msdn.microsoft.com/en-us/library/6fe5a6s9(v%3dvs.90).aspx +FORCE_INLINE __m128i _mm_sll_epi32(__m128i a, __m128i count) +{ + uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); + if (c > 31) + return _mm_setzero_si128(); + + int32x4_t vc = vdupq_n_s32((int32_t) c); + return vreinterpretq_m128i_s32(vshlq_s32(vreinterpretq_s32_m128i(a), vc)); +} + +// Shifts the 2 signed or unsigned 64-bit integers in a left by count bits while +// shifting in zeros. +// +// r0 := a0 << count +// r1 := a1 << count +// +// https://msdn.microsoft.com/en-us/library/6ta9dffd(v%3dvs.90).aspx +FORCE_INLINE __m128i _mm_sll_epi64(__m128i a, __m128i count) +{ + uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); + if (c > 63) + return _mm_setzero_si128(); + + int64x2_t vc = vdupq_n_s64((int64_t) c); + return vreinterpretq_m128i_s64(vshlq_s64(vreinterpretq_s64_m128i(a), vc)); +} + +// Shifts the 8 signed or unsigned 16-bit integers in a right by count bits +// while shifting in zeros. +// +// r0 := srl(a0, count) +// r1 := srl(a1, count) +// ... +// r7 := srl(a7, count) +// +// https://msdn.microsoft.com/en-us/library/wd5ax830(v%3dvs.90).aspx +FORCE_INLINE __m128i _mm_srl_epi16(__m128i a, __m128i count) +{ + uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); + if (c > 15) + return _mm_setzero_si128(); + + int16x8_t vc = vdupq_n_s16(-(int16_t) c); + return vreinterpretq_m128i_u16(vshlq_u16(vreinterpretq_u16_m128i(a), vc)); +} + +// Shifts the 4 signed or unsigned 32-bit integers in a right by count bits +// while shifting in zeros. +// +// r0 := srl(a0, count) +// r1 := srl(a1, count) +// r2 := srl(a2, count) +// r3 := srl(a3, count) +// +// https://msdn.microsoft.com/en-us/library/a9cbttf4(v%3dvs.90).aspx +FORCE_INLINE __m128i _mm_srl_epi32(__m128i a, __m128i count) +{ + uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); + if (c > 31) + return _mm_setzero_si128(); + + int32x4_t vc = vdupq_n_s32(-(int32_t) c); + return vreinterpretq_m128i_u32(vshlq_u32(vreinterpretq_u32_m128i(a), vc)); +} + +// Shifts the 2 signed or unsigned 64-bit integers in a right by count bits +// while shifting in zeros. +// +// r0 := srl(a0, count) +// r1 := srl(a1, count) +// +// https://msdn.microsoft.com/en-us/library/yf6cf9k8(v%3dvs.90).aspx +FORCE_INLINE __m128i _mm_srl_epi64(__m128i a, __m128i count) +{ + uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); + if (c > 63) + return _mm_setzero_si128(); + + int64x2_t vc = vdupq_n_s64(-(int64_t) c); + return vreinterpretq_m128i_u64(vshlq_u64(vreinterpretq_u64_m128i(a), vc)); +} + +// NEON does not provide a version of this function. +// Creates a 16-bit mask from the most significant bits of the 16 signed or +// unsigned 8-bit integers in a and zero extends the upper bits. +// https://msdn.microsoft.com/en-us/library/vstudio/s090c8fk(v=vs.100).aspx +FORCE_INLINE int _mm_movemask_epi8(__m128i a) +{ +#if defined(__aarch64__) + uint8x16_t input = vreinterpretq_u8_m128i(a); + const int8_t ALIGN_STRUCT(16) + xr[16] = {-7, -6, -5, -4, -3, -2, -1, 0, -7, -6, -5, -4, -3, -2, -1, 0}; + const uint8x16_t mask_and = vdupq_n_u8(0x80); + const int8x16_t mask_shift = vld1q_s8(xr); + const uint8x16_t mask_result = + vshlq_u8(vandq_u8(input, mask_and), mask_shift); + uint8x8_t lo = vget_low_u8(mask_result); + uint8x8_t hi = vget_high_u8(mask_result); + + return vaddv_u8(lo) + (vaddv_u8(hi) << 8); +#else + // Use increasingly wide shifts+adds to collect the sign bits + // together. + // Since the widening shifts would be rather confusing to follow in little + // endian, everything will be illustrated in big endian order instead. This + // has a different result - the bits would actually be reversed on a big + // endian machine. + + // Starting input (only half the elements are shown): + // 89 ff 1d c0 00 10 99 33 + uint8x16_t input = vreinterpretq_u8_m128i(a); + + // Shift out everything but the sign bits with an unsigned shift right. + // + // Bytes of the vector:: + // 89 ff 1d c0 00 10 99 33 + // \ \ \ \ \ \ \ \ high_bits = (uint16x4_t)(input >> 7) + // | | | | | | | | + // 01 01 00 01 00 00 01 00 + // + // Bits of first important lane(s): + // 10001001 (89) + // \______ + // | + // 00000001 (01) + uint16x8_t high_bits = vreinterpretq_u16_u8(vshrq_n_u8(input, 7)); + + // Merge the even lanes together with a 16-bit unsigned shift right + add. + // 'xx' represents garbage data which will be ignored in the final result. + // In the important bytes, the add functions like a binary OR. + // + // 01 01 00 01 00 00 01 00 + // \_ | \_ | \_ | \_ | paired16 = (uint32x4_t)(input + (input >> 7)) + // \| \| \| \| + // xx 03 xx 01 xx 00 xx 02 + // + // 00000001 00000001 (01 01) + // \_______ | + // \| + // xxxxxxxx xxxxxx11 (xx 03) + uint32x4_t paired16 = + vreinterpretq_u32_u16(vsraq_n_u16(high_bits, high_bits, 7)); + + // Repeat with a wider 32-bit shift + add. + // xx 03 xx 01 xx 00 xx 02 + // \____ | \____ | paired32 = (uint64x1_t)(paired16 + (paired16 >> + // 14)) + // \| \| + // xx xx xx 0d xx xx xx 02 + // + // 00000011 00000001 (03 01) + // \\_____ || + // '----.\|| + // xxxxxxxx xxxx1101 (xx 0d) + uint64x2_t paired32 = + vreinterpretq_u64_u32(vsraq_n_u32(paired16, paired16, 14)); + + // Last, an even wider 64-bit shift + add to get our result in the low 8 bit + // lanes. xx xx xx 0d xx xx xx 02 + // \_________ | paired64 = (uint8x8_t)(paired32 + (paired32 >> + // 28)) + // \| + // xx xx xx xx xx xx xx d2 + // + // 00001101 00000010 (0d 02) + // \ \___ | | + // '---. \| | + // xxxxxxxx 11010010 (xx d2) + uint8x16_t paired64 = + vreinterpretq_u8_u64(vsraq_n_u64(paired32, paired32, 28)); + + // Extract the low 8 bits from each 64-bit lane with 2 8-bit extracts. + // xx xx xx xx xx xx xx d2 + // || return paired64[0] + // d2 + // Note: Little endian would return the correct value 4b (01001011) instead. + return vgetq_lane_u8(paired64, 0) | ((int) vgetq_lane_u8(paired64, 8) << 8); +#endif +} + +// Copy the lower 64-bit integer in a to dst. +// +// dst[63:0] := a[63:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movepi64_pi64 +FORCE_INLINE __m64 _mm_movepi64_pi64(__m128i a) +{ + return vreinterpret_m64_s64(vget_low_s64(vreinterpretq_s64_m128i(a))); +} + +// Copy the 64-bit integer a to the lower element of dst, and zero the upper +// element. +// +// dst[63:0] := a[63:0] +// dst[127:64] := 0 +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movpi64_epi64 +FORCE_INLINE __m128i _mm_movpi64_epi64(__m64 a) +{ + return vreinterpretq_m128i_s64( + vcombine_s64(vreinterpret_s64_m64(a), vdup_n_s64(0))); +} + +// NEON does not provide this method +// Creates a 4-bit mask from the most significant bits of the four +// single-precision, floating-point values. +// https://msdn.microsoft.com/en-us/library/vstudio/4490ys29(v=vs.100).aspx +FORCE_INLINE int _mm_movemask_ps(__m128 a) +{ + uint32x4_t input = vreinterpretq_u32_m128(a); +#if defined(__aarch64__) + static const int32x4_t shift = {0, 1, 2, 3}; + uint32x4_t tmp = vshrq_n_u32(input, 31); + return vaddvq_u32(vshlq_u32(tmp, shift)); +#else + // Uses the exact same method as _mm_movemask_epi8, see that for details. + // Shift out everything but the sign bits with a 32-bit unsigned shift + // right. + uint64x2_t high_bits = vreinterpretq_u64_u32(vshrq_n_u32(input, 31)); + // Merge the two pairs together with a 64-bit unsigned shift right + add. + uint8x16_t paired = + vreinterpretq_u8_u64(vsraq_n_u64(high_bits, high_bits, 31)); + // Extract the result. + return vgetq_lane_u8(paired, 0) | (vgetq_lane_u8(paired, 8) << 2); +#endif +} + +// Compute the bitwise NOT of a and then AND with a 128-bit vector containing +// all 1's, and return 1 if the result is zero, otherwise return 0. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_test_all_ones +FORCE_INLINE int _mm_test_all_ones(__m128i a) +{ + return (uint64_t)(vgetq_lane_s64(a, 0) & vgetq_lane_s64(a, 1)) == + ~(uint64_t) 0; +} + +// Compute the bitwise AND of 128 bits (representing integer data) in a and +// mask, and return 1 if the result is zero, otherwise return 0. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_test_all_zeros +FORCE_INLINE int _mm_test_all_zeros(__m128i a, __m128i mask) +{ + int64x2_t a_and_mask = + vandq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(mask)); + return (vgetq_lane_s64(a_and_mask, 0) | vgetq_lane_s64(a_and_mask, 1)) ? 0 + : 1; +} + +/* Math operations */ + +// Subtracts the four single-precision, floating-point values of a and b. +// +// r0 := a0 - b0 +// r1 := a1 - b1 +// r2 := a2 - b2 +// r3 := a3 - b3 +// +// https://msdn.microsoft.com/en-us/library/vstudio/1zad2k61(v=vs.100).aspx +FORCE_INLINE __m128 _mm_sub_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_f32( + vsubq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +} + +// Subtract the lower single-precision (32-bit) floating-point element in b from +// the lower single-precision (32-bit) floating-point element in a, store the +// result in the lower element of dst, and copy the upper 3 packed elements from +// a to the upper elements of dst. +// +// dst[31:0] := a[31:0] - b[31:0] +// dst[127:32] := a[127:32] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_ss +FORCE_INLINE __m128 _mm_sub_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_sub_ps(a, b)); +} + +// Subtract 2 packed 64-bit integers in b from 2 packed 64-bit integers in a, +// and store the results in dst. +// r0 := a0 - b0 +// r1 := a1 - b1 +FORCE_INLINE __m128i _mm_sub_epi64(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s64( + vsubq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b))); +} + +// Subtracts the 4 signed or unsigned 32-bit integers of b from the 4 signed or +// unsigned 32-bit integers of a. +// +// r0 := a0 - b0 +// r1 := a1 - b1 +// r2 := a2 - b2 +// r3 := a3 - b3 +// +// https://msdn.microsoft.com/en-us/library/vstudio/fhh866h0(v=vs.100).aspx +FORCE_INLINE __m128i _mm_sub_epi32(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s32( + vsubq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +} + +FORCE_INLINE __m128i _mm_sub_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s16( + vsubq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +} + +FORCE_INLINE __m128i _mm_sub_epi8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s8( + vsubq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); +} + +// Subtract 64-bit integer b from 64-bit integer a, and store the result in dst. +// +// dst[63:0] := a[63:0] - b[63:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_si64 +FORCE_INLINE __m64 _mm_sub_si64(__m64 a, __m64 b) +{ + return vreinterpret_m64_s64( + vsub_s64(vreinterpret_s64_m64(a), vreinterpret_s64_m64(b))); +} + +// Subtracts the 8 unsigned 16-bit integers of bfrom the 8 unsigned 16-bit +// integers of a and saturates.. +// https://technet.microsoft.com/en-us/subscriptions/index/f44y0s19(v=vs.90).aspx +FORCE_INLINE __m128i _mm_subs_epu16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u16( + vqsubq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b))); +} + +// Subtracts the 16 unsigned 8-bit integers of b from the 16 unsigned 8-bit +// integers of a and saturates. +// +// r0 := UnsignedSaturate(a0 - b0) +// r1 := UnsignedSaturate(a1 - b1) +// ... +// r15 := UnsignedSaturate(a15 - b15) +// +// https://technet.microsoft.com/en-us/subscriptions/yadkxc18(v=vs.90) +FORCE_INLINE __m128i _mm_subs_epu8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u8( + vqsubq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); +} + +// Subtracts the 16 signed 8-bit integers of b from the 16 signed 8-bit integers +// of a and saturates. +// +// r0 := SignedSaturate(a0 - b0) +// r1 := SignedSaturate(a1 - b1) +// ... +// r15 := SignedSaturate(a15 - b15) +// +// https://technet.microsoft.com/en-us/subscriptions/by7kzks1(v=vs.90) +FORCE_INLINE __m128i _mm_subs_epi8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s8( + vqsubq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); +} + +// Subtracts the 8 signed 16-bit integers of b from the 8 signed 16-bit integers +// of a and saturates. +// +// r0 := SignedSaturate(a0 - b0) +// r1 := SignedSaturate(a1 - b1) +// ... +// r7 := SignedSaturate(a7 - b7) +// +// https://technet.microsoft.com/en-us/subscriptions/3247z5b8(v=vs.90) +FORCE_INLINE __m128i _mm_subs_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s16( + vqsubq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +} + +FORCE_INLINE __m128i _mm_adds_epu16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u16( + vqaddq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b))); +} + +// Negate packed 8-bit integers in a when the corresponding signed +// 8-bit integer in b is negative, and store the results in dst. +// Element in dst are zeroed out when the corresponding element +// in b is zero. +// +// for i in 0..15 +// if b[i] < 0 +// r[i] := -a[i] +// else if b[i] == 0 +// r[i] := 0 +// else +// r[i] := a[i] +// fi +// done +FORCE_INLINE __m128i _mm_sign_epi8(__m128i _a, __m128i _b) +{ + int8x16_t a = vreinterpretq_s8_m128i(_a); + int8x16_t b = vreinterpretq_s8_m128i(_b); + + // signed shift right: faster than vclt + // (b < 0) ? 0xFF : 0 + uint8x16_t ltMask = vreinterpretq_u8_s8(vshrq_n_s8(b, 7)); + + // (b == 0) ? 0xFF : 0 +#if defined(__aarch64__) + int8x16_t zeroMask = vreinterpretq_s8_u8(vceqzq_s8(b)); +#else + int8x16_t zeroMask = vreinterpretq_s8_u8(vceqq_s8(b, vdupq_n_s8(0))); +#endif + + // bitwise select either a or nagative 'a' (vnegq_s8(a) return nagative 'a') + // based on ltMask + int8x16_t masked = vbslq_s8(ltMask, vnegq_s8(a), a); + // res = masked & (~zeroMask) + int8x16_t res = vbicq_s8(masked, zeroMask); + + return vreinterpretq_m128i_s8(res); +} + +// Negate packed 16-bit integers in a when the corresponding signed +// 16-bit integer in b is negative, and store the results in dst. +// Element in dst are zeroed out when the corresponding element +// in b is zero. +// +// for i in 0..7 +// if b[i] < 0 +// r[i] := -a[i] +// else if b[i] == 0 +// r[i] := 0 +// else +// r[i] := a[i] +// fi +// done +FORCE_INLINE __m128i _mm_sign_epi16(__m128i _a, __m128i _b) +{ + int16x8_t a = vreinterpretq_s16_m128i(_a); + int16x8_t b = vreinterpretq_s16_m128i(_b); + + // signed shift right: faster than vclt + // (b < 0) ? 0xFFFF : 0 + uint16x8_t ltMask = vreinterpretq_u16_s16(vshrq_n_s16(b, 15)); + // (b == 0) ? 0xFFFF : 0 +#if defined(__aarch64__) + int16x8_t zeroMask = vreinterpretq_s16_u16(vceqzq_s16(b)); +#else + int16x8_t zeroMask = vreinterpretq_s16_u16(vceqq_s16(b, vdupq_n_s16(0))); +#endif + + // bitwise select either a or negative 'a' (vnegq_s16(a) equals to negative + // 'a') based on ltMask + int16x8_t masked = vbslq_s16(ltMask, vnegq_s16(a), a); + // res = masked & (~zeroMask) + int16x8_t res = vbicq_s16(masked, zeroMask); + return vreinterpretq_m128i_s16(res); +} + +// Negate packed 32-bit integers in a when the corresponding signed +// 32-bit integer in b is negative, and store the results in dst. +// Element in dst are zeroed out when the corresponding element +// in b is zero. +// +// for i in 0..3 +// if b[i] < 0 +// r[i] := -a[i] +// else if b[i] == 0 +// r[i] := 0 +// else +// r[i] := a[i] +// fi +// done +FORCE_INLINE __m128i _mm_sign_epi32(__m128i _a, __m128i _b) +{ + int32x4_t a = vreinterpretq_s32_m128i(_a); + int32x4_t b = vreinterpretq_s32_m128i(_b); + + // signed shift right: faster than vclt + // (b < 0) ? 0xFFFFFFFF : 0 + uint32x4_t ltMask = vreinterpretq_u32_s32(vshrq_n_s32(b, 31)); + + // (b == 0) ? 0xFFFFFFFF : 0 +#if defined(__aarch64__) + int32x4_t zeroMask = vreinterpretq_s32_u32(vceqzq_s32(b)); +#else + int32x4_t zeroMask = vreinterpretq_s32_u32(vceqq_s32(b, vdupq_n_s32(0))); +#endif + + // bitwise select either a or negative 'a' (vnegq_s32(a) equals to negative + // 'a') based on ltMask + int32x4_t masked = vbslq_s32(ltMask, vnegq_s32(a), a); + // res = masked & (~zeroMask) + int32x4_t res = vbicq_s32(masked, zeroMask); + return vreinterpretq_m128i_s32(res); +} + +// Negate packed 16-bit integers in a when the corresponding signed 16-bit +// integer in b is negative, and store the results in dst. Element in dst are +// zeroed out when the corresponding element in b is zero. +// +// FOR j := 0 to 3 +// i := j*16 +// IF b[i+15:i] < 0 +// dst[i+15:i] := -(a[i+15:i]) +// ELSE IF b[i+15:i] == 0 +// dst[i+15:i] := 0 +// ELSE +// dst[i+15:i] := a[i+15:i] +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sign_pi16 +FORCE_INLINE __m64 _mm_sign_pi16(__m64 _a, __m64 _b) +{ + int16x4_t a = vreinterpret_s16_m64(_a); + int16x4_t b = vreinterpret_s16_m64(_b); + + // signed shift right: faster than vclt + // (b < 0) ? 0xFFFF : 0 + uint16x4_t ltMask = vreinterpret_u16_s16(vshr_n_s16(b, 15)); + + // (b == 0) ? 0xFFFF : 0 +#if defined(__aarch64__) + int16x4_t zeroMask = vreinterpret_s16_u16(vceqz_s16(b)); +#else + int16x4_t zeroMask = vreinterpret_s16_u16(vceq_s16(b, vdup_n_s16(0))); +#endif + + // bitwise select either a or nagative 'a' (vneg_s16(a) return nagative 'a') + // based on ltMask + int16x4_t masked = vbsl_s16(ltMask, vneg_s16(a), a); + // res = masked & (~zeroMask) + int16x4_t res = vbic_s16(masked, zeroMask); + + return vreinterpret_m64_s16(res); +} + +// Negate packed 32-bit integers in a when the corresponding signed 32-bit +// integer in b is negative, and store the results in dst. Element in dst are +// zeroed out when the corresponding element in b is zero. +// +// FOR j := 0 to 1 +// i := j*32 +// IF b[i+31:i] < 0 +// dst[i+31:i] := -(a[i+31:i]) +// ELSE IF b[i+31:i] == 0 +// dst[i+31:i] := 0 +// ELSE +// dst[i+31:i] := a[i+31:i] +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sign_pi32 +FORCE_INLINE __m64 _mm_sign_pi32(__m64 _a, __m64 _b) +{ + int32x2_t a = vreinterpret_s32_m64(_a); + int32x2_t b = vreinterpret_s32_m64(_b); + + // signed shift right: faster than vclt + // (b < 0) ? 0xFFFFFFFF : 0 + uint32x2_t ltMask = vreinterpret_u32_s32(vshr_n_s32(b, 31)); + + // (b == 0) ? 0xFFFFFFFF : 0 +#if defined(__aarch64__) + int32x2_t zeroMask = vreinterpret_s32_u32(vceqz_s32(b)); +#else + int32x2_t zeroMask = vreinterpret_s32_u32(vceq_s32(b, vdup_n_s32(0))); +#endif + + // bitwise select either a or nagative 'a' (vneg_s32(a) return nagative 'a') + // based on ltMask + int32x2_t masked = vbsl_s32(ltMask, vneg_s32(a), a); + // res = masked & (~zeroMask) + int32x2_t res = vbic_s32(masked, zeroMask); + + return vreinterpret_m64_s32(res); +} + +// Negate packed 8-bit integers in a when the corresponding signed 8-bit integer +// in b is negative, and store the results in dst. Element in dst are zeroed out +// when the corresponding element in b is zero. +// +// FOR j := 0 to 7 +// i := j*8 +// IF b[i+7:i] < 0 +// dst[i+7:i] := -(a[i+7:i]) +// ELSE IF b[i+7:i] == 0 +// dst[i+7:i] := 0 +// ELSE +// dst[i+7:i] := a[i+7:i] +// FI +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sign_pi8 +FORCE_INLINE __m64 _mm_sign_pi8(__m64 _a, __m64 _b) +{ + int8x8_t a = vreinterpret_s8_m64(_a); + int8x8_t b = vreinterpret_s8_m64(_b); + + // signed shift right: faster than vclt + // (b < 0) ? 0xFF : 0 + uint8x8_t ltMask = vreinterpret_u8_s8(vshr_n_s8(b, 7)); + + // (b == 0) ? 0xFF : 0 +#if defined(__aarch64__) + int8x8_t zeroMask = vreinterpret_s8_u8(vceqz_s8(b)); +#else + int8x8_t zeroMask = vreinterpret_s8_u8(vceq_s8(b, vdup_n_s8(0))); +#endif + + // bitwise select either a or nagative 'a' (vneg_s8(a) return nagative 'a') + // based on ltMask + int8x8_t masked = vbsl_s8(ltMask, vneg_s8(a), a); + // res = masked & (~zeroMask) + int8x8_t res = vbic_s8(masked, zeroMask); + + return vreinterpret_m64_s8(res); +} + +// Average packed unsigned 16-bit integers in a and b, and store the results in +// dst. +// +// FOR j := 0 to 3 +// i := j*16 +// dst[i+15:i] := (a[i+15:i] + b[i+15:i] + 1) >> 1 +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_avg_pu16 +FORCE_INLINE __m64 _mm_avg_pu16(__m64 a, __m64 b) +{ + return vreinterpret_m64_u16( + vrhadd_u16(vreinterpret_u16_m64(a), vreinterpret_u16_m64(b))); +} + +// Average packed unsigned 8-bit integers in a and b, and store the results in +// dst. +// +// FOR j := 0 to 7 +// i := j*8 +// dst[i+7:i] := (a[i+7:i] + b[i+7:i] + 1) >> 1 +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_avg_pu8 +FORCE_INLINE __m64 _mm_avg_pu8(__m64 a, __m64 b) +{ + return vreinterpret_m64_u8( + vrhadd_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b))); +} + +// Average packed unsigned 8-bit integers in a and b, and store the results in +// dst. +// +// FOR j := 0 to 7 +// i := j*8 +// dst[i+7:i] := (a[i+7:i] + b[i+7:i] + 1) >> 1 +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pavgb +#define _m_pavgb(a, b) _mm_avg_pu8(a, b) + +// Average packed unsigned 16-bit integers in a and b, and store the results in +// dst. +// +// FOR j := 0 to 3 +// i := j*16 +// dst[i+15:i] := (a[i+15:i] + b[i+15:i] + 1) >> 1 +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pavgw +#define _m_pavgw(a, b) _mm_avg_pu16(a, b) + +// Computes the average of the 16 unsigned 8-bit integers in a and the 16 +// unsigned 8-bit integers in b and rounds. +// +// r0 := (a0 + b0) / 2 +// r1 := (a1 + b1) / 2 +// ... +// r15 := (a15 + b15) / 2 +// +// https://msdn.microsoft.com/en-us/library/vstudio/8zwh554a(v%3dvs.90).aspx +FORCE_INLINE __m128i _mm_avg_epu8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u8( + vrhaddq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); +} + +// Computes the average of the 8 unsigned 16-bit integers in a and the 8 +// unsigned 16-bit integers in b and rounds. +// +// r0 := (a0 + b0) / 2 +// r1 := (a1 + b1) / 2 +// ... +// r7 := (a7 + b7) / 2 +// +// https://msdn.microsoft.com/en-us/library/vstudio/y13ca3c8(v=vs.90).aspx +FORCE_INLINE __m128i _mm_avg_epu16(__m128i a, __m128i b) +{ + return (__m128i) vrhaddq_u16(vreinterpretq_u16_m128i(a), + vreinterpretq_u16_m128i(b)); +} + +// Adds the four single-precision, floating-point values of a and b. +// +// r0 := a0 + b0 +// r1 := a1 + b1 +// r2 := a2 + b2 +// r3 := a3 + b3 +// +// https://msdn.microsoft.com/en-us/library/vstudio/c9848chc(v=vs.100).aspx +FORCE_INLINE __m128 _mm_add_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_f32( + vaddq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +} + +// Add packed double-precision (64-bit) floating-point elements in a and b, and +// store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_pd +FORCE_INLINE __m128d _mm_add_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64( + vaddq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); +#else + double *da = (double *) &a; + double *db = (double *) &b; + double c[2]; + c[0] = da[0] + db[0]; + c[1] = da[1] + db[1]; + return vld1q_f32((float32_t *) c); +#endif +} + +// Add 64-bit integers a and b, and store the result in dst. +// +// dst[63:0] := a[63:0] + b[63:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_si64 +FORCE_INLINE __m64 _mm_add_si64(__m64 a, __m64 b) +{ + return vreinterpret_m64_s64( + vadd_s64(vreinterpret_s64_m64(a), vreinterpret_s64_m64(b))); +} + +// adds the scalar single-precision floating point values of a and b. +// https://msdn.microsoft.com/en-us/library/be94x2y6(v=vs.100).aspx +FORCE_INLINE __m128 _mm_add_ss(__m128 a, __m128 b) +{ + float32_t b0 = vgetq_lane_f32(vreinterpretq_f32_m128(b), 0); + float32x4_t value = vsetq_lane_f32(b0, vdupq_n_f32(0), 0); + // the upper values in the result must be the remnants of . + return vreinterpretq_m128_f32(vaddq_f32(a, value)); +} + +// Adds the 4 signed or unsigned 64-bit integers in a to the 4 signed or +// unsigned 32-bit integers in b. +// https://msdn.microsoft.com/en-us/library/vstudio/09xs4fkk(v=vs.100).aspx +FORCE_INLINE __m128i _mm_add_epi64(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s64( + vaddq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b))); +} + +// Adds the 4 signed or unsigned 32-bit integers in a to the 4 signed or +// unsigned 32-bit integers in b. +// +// r0 := a0 + b0 +// r1 := a1 + b1 +// r2 := a2 + b2 +// r3 := a3 + b3 +// +// https://msdn.microsoft.com/en-us/library/vstudio/09xs4fkk(v=vs.100).aspx +FORCE_INLINE __m128i _mm_add_epi32(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s32( + vaddq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +} + +// Adds the 8 signed or unsigned 16-bit integers in a to the 8 signed or +// unsigned 16-bit integers in b. +// https://msdn.microsoft.com/en-us/library/fceha5k4(v=vs.100).aspx +FORCE_INLINE __m128i _mm_add_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s16( + vaddq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +} + +// Adds the 16 signed or unsigned 8-bit integers in a to the 16 signed or +// unsigned 8-bit integers in b. +// https://technet.microsoft.com/en-us/subscriptions/yc7tcyzs(v=vs.90) +FORCE_INLINE __m128i _mm_add_epi8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s8( + vaddq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); +} + +// Adds the 8 signed 16-bit integers in a to the 8 signed 16-bit integers in b +// and saturates. +// +// r0 := SignedSaturate(a0 + b0) +// r1 := SignedSaturate(a1 + b1) +// ... +// r7 := SignedSaturate(a7 + b7) +// +// https://msdn.microsoft.com/en-us/library/1a306ef8(v=vs.100).aspx +FORCE_INLINE __m128i _mm_adds_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s16( + vqaddq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +} + +// Add packed signed 8-bit integers in a and b using saturation, and store the +// results in dst. +// +// FOR j := 0 to 15 +// i := j*8 +// dst[i+7:i] := Saturate8( a[i+7:i] + b[i+7:i] ) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_adds_epi8 +FORCE_INLINE __m128i _mm_adds_epi8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s8( + vqaddq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); +} + +// Adds the 16 unsigned 8-bit integers in a to the 16 unsigned 8-bit integers in +// b and saturates.. +// https://msdn.microsoft.com/en-us/library/9hahyddy(v=vs.100).aspx +FORCE_INLINE __m128i _mm_adds_epu8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u8( + vqaddq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); +} + +// Multiplies the 8 signed or unsigned 16-bit integers from a by the 8 signed or +// unsigned 16-bit integers from b. +// +// r0 := (a0 * b0)[15:0] +// r1 := (a1 * b1)[15:0] +// ... +// r7 := (a7 * b7)[15:0] +// +// https://msdn.microsoft.com/en-us/library/vstudio/9ks1472s(v=vs.100).aspx +FORCE_INLINE __m128i _mm_mullo_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s16( + vmulq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +} + +// Multiplies the 4 signed or unsigned 32-bit integers from a by the 4 signed or +// unsigned 32-bit integers from b. +// https://msdn.microsoft.com/en-us/library/vstudio/bb531409(v=vs.100).aspx +FORCE_INLINE __m128i _mm_mullo_epi32(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s32( + vmulq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +} + +// Multiply the packed unsigned 16-bit integers in a and b, producing +// intermediate 32-bit integers, and store the high 16 bits of the intermediate +// integers in dst. +// +// FOR j := 0 to 3 +// i := j*16 +// tmp[31:0] := a[i+15:i] * b[i+15:i] +// dst[i+15:i] := tmp[31:16] +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmulhuw +#define _m_pmulhuw(a, b) _mm_mulhi_pu16(a, b) + +// Multiplies the four single-precision, floating-point values of a and b. +// +// r0 := a0 * b0 +// r1 := a1 * b1 +// r2 := a2 * b2 +// r3 := a3 * b3 +// +// https://msdn.microsoft.com/en-us/library/vstudio/22kbk6t9(v=vs.100).aspx +FORCE_INLINE __m128 _mm_mul_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_f32( + vmulq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +} + +// Multiply packed double-precision (64-bit) floating-point elements in a and b, +// and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_pd +FORCE_INLINE __m128d _mm_mul_pd(__m128d a, __m128d b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64( + vmulq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); +#else + double *da = (double *) &a; + double *db = (double *) &b; + double c[2]; + c[0] = da[0] * db[0]; + c[1] = da[1] * db[1]; + return vld1q_f32((float32_t *) c); +#endif +} + +// Multiply the lower single-precision (32-bit) floating-point element in a and +// b, store the result in the lower element of dst, and copy the upper 3 packed +// elements from a to the upper elements of dst. +// +// dst[31:0] := a[31:0] * b[31:0] +// dst[127:32] := a[127:32] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_ss +FORCE_INLINE __m128 _mm_mul_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_mul_ps(a, b)); +} + +// Multiply the low unsigned 32-bit integers from each packed 64-bit element in +// a and b, and store the unsigned 64-bit results in dst. +// +// r0 := (a0 & 0xFFFFFFFF) * (b0 & 0xFFFFFFFF) +// r1 := (a2 & 0xFFFFFFFF) * (b2 & 0xFFFFFFFF) +FORCE_INLINE __m128i _mm_mul_epu32(__m128i a, __m128i b) +{ + // vmull_u32 upcasts instead of masking, so we downcast. + uint32x2_t a_lo = vmovn_u64(vreinterpretq_u64_m128i(a)); + uint32x2_t b_lo = vmovn_u64(vreinterpretq_u64_m128i(b)); + return vreinterpretq_m128i_u64(vmull_u32(a_lo, b_lo)); +} + +// Multiply the low unsigned 32-bit integers from a and b, and store the +// unsigned 64-bit result in dst. +// +// dst[63:0] := a[31:0] * b[31:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_su32 +FORCE_INLINE __m64 _mm_mul_su32(__m64 a, __m64 b) +{ + return vreinterpret_m64_u64(vget_low_u64( + vmull_u32(vreinterpret_u32_m64(a), vreinterpret_u32_m64(b)))); +} + +// Multiply the low signed 32-bit integers from each packed 64-bit element in +// a and b, and store the signed 64-bit results in dst. +// +// r0 := (int64_t)(int32_t)a0 * (int64_t)(int32_t)b0 +// r1 := (int64_t)(int32_t)a2 * (int64_t)(int32_t)b2 +FORCE_INLINE __m128i _mm_mul_epi32(__m128i a, __m128i b) +{ + // vmull_s32 upcasts instead of masking, so we downcast. + int32x2_t a_lo = vmovn_s64(vreinterpretq_s64_m128i(a)); + int32x2_t b_lo = vmovn_s64(vreinterpretq_s64_m128i(b)); + return vreinterpretq_m128i_s64(vmull_s32(a_lo, b_lo)); +} + +// Multiplies the 8 signed 16-bit integers from a by the 8 signed 16-bit +// integers from b. +// +// r0 := (a0 * b0) + (a1 * b1) +// r1 := (a2 * b2) + (a3 * b3) +// r2 := (a4 * b4) + (a5 * b5) +// r3 := (a6 * b6) + (a7 * b7) +// https://msdn.microsoft.com/en-us/library/yht36sa6(v=vs.90).aspx +FORCE_INLINE __m128i _mm_madd_epi16(__m128i a, __m128i b) +{ + int32x4_t low = vmull_s16(vget_low_s16(vreinterpretq_s16_m128i(a)), + vget_low_s16(vreinterpretq_s16_m128i(b))); + int32x4_t high = vmull_s16(vget_high_s16(vreinterpretq_s16_m128i(a)), + vget_high_s16(vreinterpretq_s16_m128i(b))); + + int32x2_t low_sum = vpadd_s32(vget_low_s32(low), vget_high_s32(low)); + int32x2_t high_sum = vpadd_s32(vget_low_s32(high), vget_high_s32(high)); + + return vreinterpretq_m128i_s32(vcombine_s32(low_sum, high_sum)); +} + +// Multiply packed signed 16-bit integers in a and b, producing intermediate +// signed 32-bit integers. Shift right by 15 bits while rounding up, and store +// the packed 16-bit integers in dst. +// +// r0 := Round(((int32_t)a0 * (int32_t)b0) >> 15) +// r1 := Round(((int32_t)a1 * (int32_t)b1) >> 15) +// r2 := Round(((int32_t)a2 * (int32_t)b2) >> 15) +// ... +// r7 := Round(((int32_t)a7 * (int32_t)b7) >> 15) +FORCE_INLINE __m128i _mm_mulhrs_epi16(__m128i a, __m128i b) +{ + // Has issues due to saturation + // return vreinterpretq_m128i_s16(vqrdmulhq_s16(a, b)); + + // Multiply + int32x4_t mul_lo = vmull_s16(vget_low_s16(vreinterpretq_s16_m128i(a)), + vget_low_s16(vreinterpretq_s16_m128i(b))); + int32x4_t mul_hi = vmull_s16(vget_high_s16(vreinterpretq_s16_m128i(a)), + vget_high_s16(vreinterpretq_s16_m128i(b))); + + // Rounding narrowing shift right + // narrow = (int16_t)((mul + 16384) >> 15); + int16x4_t narrow_lo = vrshrn_n_s32(mul_lo, 15); + int16x4_t narrow_hi = vrshrn_n_s32(mul_hi, 15); + + // Join together + return vreinterpretq_m128i_s16(vcombine_s16(narrow_lo, narrow_hi)); +} + +// Vertically multiply each unsigned 8-bit integer from a with the corresponding +// signed 8-bit integer from b, producing intermediate signed 16-bit integers. +// Horizontally add adjacent pairs of intermediate signed 16-bit integers, +// and pack the saturated results in dst. +// +// FOR j := 0 to 7 +// i := j*16 +// dst[i+15:i] := Saturate_To_Int16( a[i+15:i+8]*b[i+15:i+8] + +// a[i+7:i]*b[i+7:i] ) +// ENDFOR +FORCE_INLINE __m128i _mm_maddubs_epi16(__m128i _a, __m128i _b) +{ +#if defined(__aarch64__) + uint8x16_t a = vreinterpretq_u8_m128i(_a); + int8x16_t b = vreinterpretq_s8_m128i(_b); + int16x8_t tl = vmulq_s16(vreinterpretq_s16_u16(vmovl_u8(vget_low_u8(a))), + vmovl_s8(vget_low_s8(b))); + int16x8_t th = vmulq_s16(vreinterpretq_s16_u16(vmovl_u8(vget_high_u8(a))), + vmovl_s8(vget_high_s8(b))); + return vreinterpretq_m128i_s16( + vqaddq_s16(vuzp1q_s16(tl, th), vuzp2q_s16(tl, th))); +#else + // This would be much simpler if x86 would choose to zero extend OR sign + // extend, not both. This could probably be optimized better. + uint16x8_t a = vreinterpretq_u16_m128i(_a); + int16x8_t b = vreinterpretq_s16_m128i(_b); + + // Zero extend a + int16x8_t a_odd = vreinterpretq_s16_u16(vshrq_n_u16(a, 8)); + int16x8_t a_even = vreinterpretq_s16_u16(vbicq_u16(a, vdupq_n_u16(0xff00))); + + // Sign extend by shifting left then shifting right. + int16x8_t b_even = vshrq_n_s16(vshlq_n_s16(b, 8), 8); + int16x8_t b_odd = vshrq_n_s16(b, 8); + + // multiply + int16x8_t prod1 = vmulq_s16(a_even, b_even); + int16x8_t prod2 = vmulq_s16(a_odd, b_odd); + + // saturated add + return vreinterpretq_m128i_s16(vqaddq_s16(prod1, prod2)); +#endif +} + +// Computes the fused multiple add product of 32-bit floating point numbers. +// +// Return Value +// Multiplies A and B, and adds C to the temporary result before returning it. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmadd +FORCE_INLINE __m128 _mm_fmadd_ps(__m128 a, __m128 b, __m128 c) +{ +#if defined(__aarch64__) + return vreinterpretq_m128_f32(vfmaq_f32(vreinterpretq_f32_m128(c), + vreinterpretq_f32_m128(b), + vreinterpretq_f32_m128(a))); +#else + return _mm_add_ps(_mm_mul_ps(a, b), c); +#endif +} + +// Alternatively add and subtract packed single-precision (32-bit) +// floating-point elements in a to/from packed elements in b, and store the +// results in dst. +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=addsub_ps +FORCE_INLINE __m128 _mm_addsub_ps(__m128 a, __m128 b) +{ + __m128 mask = {-1.0f, 1.0f, -1.0f, 1.0f}; + return _mm_fmadd_ps(b, mask, a); +} + +// Compute the absolute differences of packed unsigned 8-bit integers in a and +// b, then horizontally sum each consecutive 8 differences to produce two +// unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low +// 16 bits of 64-bit elements in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sad_epu8 +FORCE_INLINE __m128i _mm_sad_epu8(__m128i a, __m128i b) +{ + uint16x8_t t = vpaddlq_u8(vabdq_u8((uint8x16_t) a, (uint8x16_t) b)); + uint16_t r0 = t[0] + t[1] + t[2] + t[3]; + uint16_t r4 = t[4] + t[5] + t[6] + t[7]; + uint16x8_t r = vsetq_lane_u16(r0, vdupq_n_u16(0), 0); + return (__m128i) vsetq_lane_u16(r4, r, 4); +} + +// Compute the absolute differences of packed unsigned 8-bit integers in a and +// b, then horizontally sum each consecutive 8 differences to produce four +// unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low +// 16 bits of dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sad_pu8 +FORCE_INLINE __m64 _mm_sad_pu8(__m64 a, __m64 b) +{ + uint16x4_t t = + vpaddl_u8(vabd_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b))); + uint16_t r0 = t[0] + t[1] + t[2] + t[3]; + return vreinterpret_m64_u16(vset_lane_u16(r0, vdup_n_u16(0), 0)); +} + +// Compute the absolute differences of packed unsigned 8-bit integers in a and +// b, then horizontally sum each consecutive 8 differences to produce four +// unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low +// 16 bits of dst. +// +// FOR j := 0 to 7 +// i := j*8 +// tmp[i+7:i] := ABS(a[i+7:i] - b[i+7:i]) +// ENDFOR +// dst[15:0] := tmp[7:0] + tmp[15:8] + tmp[23:16] + tmp[31:24] + tmp[39:32] + +// tmp[47:40] + tmp[55:48] + tmp[63:56] dst[63:16] := 0 +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_psadbw +#define _m_psadbw(a, b) _mm_sad_pu8(a, b) + +// Divides the four single-precision, floating-point values of a and b. +// +// r0 := a0 / b0 +// r1 := a1 / b1 +// r2 := a2 / b2 +// r3 := a3 / b3 +// +// https://msdn.microsoft.com/en-us/library/edaw8147(v=vs.100).aspx +FORCE_INLINE __m128 _mm_div_ps(__m128 a, __m128 b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128_f32( + vdivq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +#else + float32x4_t recip0 = vrecpeq_f32(vreinterpretq_f32_m128(b)); + float32x4_t recip1 = + vmulq_f32(recip0, vrecpsq_f32(recip0, vreinterpretq_f32_m128(b))); + return vreinterpretq_m128_f32(vmulq_f32(vreinterpretq_f32_m128(a), recip1)); +#endif +} + +// Divides the scalar single-precision floating point value of a by b. +// https://msdn.microsoft.com/en-us/library/4y73xa49(v=vs.100).aspx +FORCE_INLINE __m128 _mm_div_ss(__m128 a, __m128 b) +{ + float32_t value = + vgetq_lane_f32(vreinterpretq_f32_m128(_mm_div_ps(a, b)), 0); + return vreinterpretq_m128_f32( + vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0)); +} + +// Compute the approximate reciprocal of packed single-precision (32-bit) +// floating-point elements in a, and store the results in dst. The maximum +// relative error for this approximation is less than 1.5*2^-12. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp_ps +FORCE_INLINE __m128 _mm_rcp_ps(__m128 in) +{ +#if defined(__aarch64__) + return vreinterpretq_m128_f32( + vdivq_f32(vdupq_n_f32(1.0f), vreinterpretq_f32_m128(in))); +#else + float32x4_t recip = vrecpeq_f32(vreinterpretq_f32_m128(in)); + recip = vmulq_f32(recip, vrecpsq_f32(recip, vreinterpretq_f32_m128(in))); + return vreinterpretq_m128_f32(recip); +#endif +} + +// Compute the approximate reciprocal of the lower single-precision (32-bit) +// floating-point element in a, store the result in the lower element of dst, +// and copy the upper 3 packed elements from a to the upper elements of dst. The +// maximum relative error for this approximation is less than 1.5*2^-12. +// +// dst[31:0] := (1.0 / a[31:0]) +// dst[127:32] := a[127:32] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp_ss +FORCE_INLINE __m128 _mm_rcp_ss(__m128 a) +{ + return _mm_move_ss(a, _mm_rcp_ps(a)); +} + +// Computes the approximations of square roots of the four single-precision, +// floating-point values of a. First computes reciprocal square roots and then +// reciprocals of the four values. +// +// r0 := sqrt(a0) +// r1 := sqrt(a1) +// r2 := sqrt(a2) +// r3 := sqrt(a3) +// +// https://msdn.microsoft.com/en-us/library/vstudio/8z67bwwk(v=vs.100).aspx +FORCE_INLINE __m128 _mm_sqrt_ps(__m128 in) +{ +#if defined(__aarch64__) + return vreinterpretq_m128_f32(vsqrtq_f32(vreinterpretq_f32_m128(in))); +#else + float32x4_t recipsq = vrsqrteq_f32(vreinterpretq_f32_m128(in)); + float32x4_t sq = vrecpeq_f32(recipsq); + // ??? use step versions of both sqrt and recip for better accuracy? + return vreinterpretq_m128_f32(sq); +#endif +} + +// Computes the approximation of the square root of the scalar single-precision +// floating point value of in. +// https://msdn.microsoft.com/en-us/library/ahfsc22d(v=vs.100).aspx +FORCE_INLINE __m128 _mm_sqrt_ss(__m128 in) +{ + float32_t value = + vgetq_lane_f32(vreinterpretq_f32_m128(_mm_sqrt_ps(in)), 0); + return vreinterpretq_m128_f32( + vsetq_lane_f32(value, vreinterpretq_f32_m128(in), 0)); +} + +// Computes the approximations of the reciprocal square roots of the four +// single-precision floating point values of in. +// https://msdn.microsoft.com/en-us/library/22hfsh53(v=vs.100).aspx +FORCE_INLINE __m128 _mm_rsqrt_ps(__m128 in) +{ + return vreinterpretq_m128_f32(vrsqrteq_f32(vreinterpretq_f32_m128(in))); +} + +// Compute the approximate reciprocal square root of the lower single-precision +// (32-bit) floating-point element in a, store the result in the lower element +// of dst, and copy the upper 3 packed elements from a to the upper elements of +// dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rsqrt_ss +FORCE_INLINE __m128 _mm_rsqrt_ss(__m128 in) +{ + return vsetq_lane_f32(vgetq_lane_f32(_mm_rsqrt_ps(in), 0), in, 0); +} + +// Compare packed signed 16-bit integers in a and b, and store packed maximum +// values in dst. +// +// FOR j := 0 to 3 +// i := j*16 +// dst[i+15:i] := MAX(a[i+15:i], b[i+15:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pi16 +FORCE_INLINE __m64 _mm_max_pi16(__m64 a, __m64 b) +{ + return vreinterpret_m64_s16( + vmax_s16(vreinterpret_s16_m64(a), vreinterpret_s16_m64(b))); +} + +// Compare packed signed 16-bit integers in a and b, and store packed maximum +// values in dst. +// +// FOR j := 0 to 3 +// i := j*16 +// dst[i+15:i] := MAX(a[i+15:i], b[i+15:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pi16 +#define _m_pmaxsw(a, b) _mm_max_pi16(a, b) + +// Computes the maximums of the four single-precision, floating-point values of +// a and b. +// https://msdn.microsoft.com/en-us/library/vstudio/ff5d607a(v=vs.100).aspx +FORCE_INLINE __m128 _mm_max_ps(__m128 a, __m128 b) +{ +#if SSE2NEON_PRECISE_MINMAX + float32x4_t _a = vreinterpretq_f32_m128(a); + float32x4_t _b = vreinterpretq_f32_m128(b); + return vbslq_f32(vcltq_f32(_b, _a), _a, _b); +#else + return vreinterpretq_m128_f32( + vmaxq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +#endif +} + +// Compare packed unsigned 8-bit integers in a and b, and store packed maximum +// values in dst. +// +// FOR j := 0 to 7 +// i := j*8 +// dst[i+7:i] := MAX(a[i+7:i], b[i+7:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pu8 +FORCE_INLINE __m64 _mm_max_pu8(__m64 a, __m64 b) +{ + return vreinterpret_m64_u8( + vmax_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b))); +} + +// Compare packed unsigned 8-bit integers in a and b, and store packed maximum +// values in dst. +// +// FOR j := 0 to 7 +// i := j*8 +// dst[i+7:i] := MAX(a[i+7:i], b[i+7:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pu8 +#define _m_pmaxub(a, b) _mm_max_pu8(a, b) + +// Compare packed signed 16-bit integers in a and b, and store packed minimum +// values in dst. +// +// FOR j := 0 to 3 +// i := j*16 +// dst[i+15:i] := MIN(a[i+15:i], b[i+15:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pi16 +FORCE_INLINE __m64 _mm_min_pi16(__m64 a, __m64 b) +{ + return vreinterpret_m64_s16( + vmin_s16(vreinterpret_s16_m64(a), vreinterpret_s16_m64(b))); +} + +// Compare packed signed 16-bit integers in a and b, and store packed minimum +// values in dst. +// +// FOR j := 0 to 3 +// i := j*16 +// dst[i+15:i] := MIN(a[i+15:i], b[i+15:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pi16 +#define _m_pminsw(a, b) _mm_min_pi16(a, b) + +// Computes the minima of the four single-precision, floating-point values of a +// and b. +// https://msdn.microsoft.com/en-us/library/vstudio/wh13kadz(v=vs.100).aspx +FORCE_INLINE __m128 _mm_min_ps(__m128 a, __m128 b) +{ +#if SSE2NEON_PRECISE_MINMAX + float32x4_t _a = vreinterpretq_f32_m128(a); + float32x4_t _b = vreinterpretq_f32_m128(b); + return vbslq_f32(vcltq_f32(_a, _b), _a, _b); +#else + return vreinterpretq_m128_f32( + vminq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +#endif +} + +// Compare packed unsigned 8-bit integers in a and b, and store packed minimum +// values in dst. +// +// FOR j := 0 to 7 +// i := j*8 +// dst[i+7:i] := MIN(a[i+7:i], b[i+7:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pu8 +FORCE_INLINE __m64 _mm_min_pu8(__m64 a, __m64 b) +{ + return vreinterpret_m64_u8( + vmin_u8(vreinterpret_u8_m64(a), vreinterpret_u8_m64(b))); +} + +// Compare packed unsigned 8-bit integers in a and b, and store packed minimum +// values in dst. +// +// FOR j := 0 to 7 +// i := j*8 +// dst[i+7:i] := MIN(a[i+7:i], b[i+7:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pu8 +#define _m_pminub(a, b) _mm_min_pu8(a, b) + +// Computes the maximum of the two lower scalar single-precision floating point +// values of a and b. +// https://msdn.microsoft.com/en-us/library/s6db5esz(v=vs.100).aspx +FORCE_INLINE __m128 _mm_max_ss(__m128 a, __m128 b) +{ + float32_t value = vgetq_lane_f32(_mm_max_ps(a, b), 0); + return vreinterpretq_m128_f32( + vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0)); +} + +// Computes the minimum of the two lower scalar single-precision floating point +// values of a and b. +// https://msdn.microsoft.com/en-us/library/0a9y7xaa(v=vs.100).aspx +FORCE_INLINE __m128 _mm_min_ss(__m128 a, __m128 b) +{ + float32_t value = vgetq_lane_f32(_mm_min_ps(a, b), 0); + return vreinterpretq_m128_f32( + vsetq_lane_f32(value, vreinterpretq_f32_m128(a), 0)); +} + +// Computes the pairwise maxima of the 16 unsigned 8-bit integers from a and the +// 16 unsigned 8-bit integers from b. +// https://msdn.microsoft.com/en-us/library/st6634za(v=vs.100).aspx +FORCE_INLINE __m128i _mm_max_epu8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u8( + vmaxq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); +} + +// Computes the pairwise minima of the 16 unsigned 8-bit integers from a and the +// 16 unsigned 8-bit integers from b. +// https://msdn.microsoft.com/ko-kr/library/17k8cf58(v=vs.100).aspxx +FORCE_INLINE __m128i _mm_min_epu8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u8( + vminq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b))); +} + +// Computes the pairwise minima of the 8 signed 16-bit integers from a and the 8 +// signed 16-bit integers from b. +// https://msdn.microsoft.com/en-us/library/vstudio/6te997ew(v=vs.100).aspx +FORCE_INLINE __m128i _mm_min_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s16( + vminq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +} + +// Compare packed signed 8-bit integers in a and b, and store packed maximum +// values in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epi8 +FORCE_INLINE __m128i _mm_max_epi8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s8( + vmaxq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); +} + +// Compare packed unsigned 16-bit integers in a and b, and store packed maximum +// values in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu16 +FORCE_INLINE __m128i _mm_max_epu16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u16( + vmaxq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b))); +} + +// Compare packed signed 8-bit integers in a and b, and store packed minimum +// values in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_epi8 +FORCE_INLINE __m128i _mm_min_epi8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s8( + vminq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); +} + +// Compare packed unsigned 16-bit integers in a and b, and store packed minimum +// values in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_epu16 +FORCE_INLINE __m128i _mm_min_epu16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u16( + vminq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b))); +} + +// Computes the pairwise maxima of the 8 signed 16-bit integers from a and the 8 +// signed 16-bit integers from b. +// https://msdn.microsoft.com/en-us/LIBRary/3x060h7c(v=vs.100).aspx +FORCE_INLINE __m128i _mm_max_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s16( + vmaxq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +} + +// epi versions of min/max +// Computes the pariwise maximums of the four signed 32-bit integer values of a +// and b. +// +// A 128-bit parameter that can be defined with the following equations: +// r0 := (a0 > b0) ? a0 : b0 +// r1 := (a1 > b1) ? a1 : b1 +// r2 := (a2 > b2) ? a2 : b2 +// r3 := (a3 > b3) ? a3 : b3 +// +// https://msdn.microsoft.com/en-us/library/vstudio/bb514055(v=vs.100).aspx +FORCE_INLINE __m128i _mm_max_epi32(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s32( + vmaxq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +} + +// Computes the pariwise minima of the four signed 32-bit integer values of a +// and b. +// +// A 128-bit parameter that can be defined with the following equations: +// r0 := (a0 < b0) ? a0 : b0 +// r1 := (a1 < b1) ? a1 : b1 +// r2 := (a2 < b2) ? a2 : b2 +// r3 := (a3 < b3) ? a3 : b3 +// +// https://msdn.microsoft.com/en-us/library/vstudio/bb531476(v=vs.100).aspx +FORCE_INLINE __m128i _mm_min_epi32(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s32( + vminq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +} + +// Compare packed unsigned 32-bit integers in a and b, and store packed maximum +// values in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu32 +FORCE_INLINE __m128i _mm_max_epu32(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u32( + vmaxq_u32(vreinterpretq_u32_m128i(a), vreinterpretq_u32_m128i(b))); +} + +// Compare packed unsigned 32-bit integers in a and b, and store packed minimum +// values in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu32 +FORCE_INLINE __m128i _mm_min_epu32(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u32( + vminq_u32(vreinterpretq_u32_m128i(a), vreinterpretq_u32_m128i(b))); +} + +// Multiply the packed unsigned 16-bit integers in a and b, producing +// intermediate 32-bit integers, and store the high 16 bits of the intermediate +// integers in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mulhi_pu16 +FORCE_INLINE __m64 _mm_mulhi_pu16(__m64 a, __m64 b) +{ + return vreinterpret_m64_u16(vshrn_n_u32( + vmull_u16(vreinterpret_u16_m64(a), vreinterpret_u16_m64(b)), 16)); +} + +// Multiplies the 8 signed 16-bit integers from a by the 8 signed 16-bit +// integers from b. +// +// r0 := (a0 * b0)[31:16] +// r1 := (a1 * b1)[31:16] +// ... +// r7 := (a7 * b7)[31:16] +// +// https://msdn.microsoft.com/en-us/library/vstudio/59hddw1d(v=vs.100).aspx +FORCE_INLINE __m128i _mm_mulhi_epi16(__m128i a, __m128i b) +{ + /* FIXME: issue with large values because of result saturation */ + // int16x8_t ret = vqdmulhq_s16(vreinterpretq_s16_m128i(a), + // vreinterpretq_s16_m128i(b)); /* =2*a*b */ return + // vreinterpretq_m128i_s16(vshrq_n_s16(ret, 1)); + int16x4_t a3210 = vget_low_s16(vreinterpretq_s16_m128i(a)); + int16x4_t b3210 = vget_low_s16(vreinterpretq_s16_m128i(b)); + int32x4_t ab3210 = vmull_s16(a3210, b3210); /* 3333222211110000 */ + int16x4_t a7654 = vget_high_s16(vreinterpretq_s16_m128i(a)); + int16x4_t b7654 = vget_high_s16(vreinterpretq_s16_m128i(b)); + int32x4_t ab7654 = vmull_s16(a7654, b7654); /* 7777666655554444 */ + uint16x8x2_t r = + vuzpq_u16(vreinterpretq_u16_s32(ab3210), vreinterpretq_u16_s32(ab7654)); + return vreinterpretq_m128i_u16(r.val[1]); +} + +// Multiply the packed unsigned 16-bit integers in a and b, producing +// intermediate 32-bit integers, and store the high 16 bits of the intermediate +// integers in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mulhi_epu16 +FORCE_INLINE __m128i _mm_mulhi_epu16(__m128i a, __m128i b) +{ + uint16x4_t a3210 = vget_low_u16(vreinterpretq_u16_m128i(a)); + uint16x4_t b3210 = vget_low_u16(vreinterpretq_u16_m128i(b)); + uint32x4_t ab3210 = vmull_u16(a3210, b3210); +#if defined(__aarch64__) + uint32x4_t ab7654 = + vmull_high_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b)); + uint16x8_t r = vuzp2q_u16(vreinterpretq_u16_u32(ab3210), + vreinterpretq_u16_u32(ab7654)); + return vreinterpretq_m128i_u16(r); +#else + uint16x4_t a7654 = vget_high_u16(vreinterpretq_u16_m128i(a)); + uint16x4_t b7654 = vget_high_u16(vreinterpretq_u16_m128i(b)); + uint32x4_t ab7654 = vmull_u16(a7654, b7654); + uint16x8x2_t r = + vuzpq_u16(vreinterpretq_u16_u32(ab3210), vreinterpretq_u16_u32(ab7654)); + return vreinterpretq_m128i_u16(r.val[1]); +#endif +} + +// Computes pairwise add of each argument as single-precision, floating-point +// values a and b. +// https://msdn.microsoft.com/en-us/library/yd9wecaa.aspx +FORCE_INLINE __m128 _mm_hadd_ps(__m128 a, __m128 b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128_f32( + vpaddq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +#else + float32x2_t a10 = vget_low_f32(vreinterpretq_f32_m128(a)); + float32x2_t a32 = vget_high_f32(vreinterpretq_f32_m128(a)); + float32x2_t b10 = vget_low_f32(vreinterpretq_f32_m128(b)); + float32x2_t b32 = vget_high_f32(vreinterpretq_f32_m128(b)); + return vreinterpretq_m128_f32( + vcombine_f32(vpadd_f32(a10, a32), vpadd_f32(b10, b32))); +#endif +} + +// Computes pairwise add of each argument as a 16-bit signed or unsigned integer +// values a and b. +FORCE_INLINE __m128i _mm_hadd_epi16(__m128i _a, __m128i _b) +{ + int16x8_t a = vreinterpretq_s16_m128i(_a); + int16x8_t b = vreinterpretq_s16_m128i(_b); +#if defined(__aarch64__) + return vreinterpretq_m128i_s16(vpaddq_s16(a, b)); +#else + return vreinterpretq_m128i_s16( + vcombine_s16(vpadd_s16(vget_low_s16(a), vget_high_s16(a)), + vpadd_s16(vget_low_s16(b), vget_high_s16(b)))); +#endif +} + +// Horizontally substract adjacent pairs of single-precision (32-bit) +// floating-point elements in a and b, and pack the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsub_ps +FORCE_INLINE __m128 _mm_hsub_ps(__m128 _a, __m128 _b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128_f32(vsubq_f32( + vuzp1q_f32(vreinterpretq_f32_m128(_a), vreinterpretq_f32_m128(_b)), + vuzp2q_f32(vreinterpretq_f32_m128(_a), vreinterpretq_f32_m128(_b)))); +#else + float32x4x2_t c = + vuzpq_f32(vreinterpretq_f32_m128(_a), vreinterpretq_f32_m128(_b)); + return vreinterpretq_m128_f32(vsubq_f32(c.val[0], c.val[1])); +#endif +} + +// Horizontally add adjacent pairs of 16-bit integers in a and b, and pack the +// signed 16-bit results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pi16 +FORCE_INLINE __m64 _mm_hadd_pi16(__m64 a, __m64 b) +{ + return vreinterpret_m64_s16( + vpadd_s16(vreinterpret_s16_m64(a), vreinterpret_s16_m64(b))); +} + +// Horizontally add adjacent pairs of 32-bit integers in a and b, and pack the +// signed 32-bit results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pi32 +FORCE_INLINE __m64 _mm_hadd_pi32(__m64 a, __m64 b) +{ + return vreinterpret_m64_s32( + vpadd_s32(vreinterpret_s32_m64(a), vreinterpret_s32_m64(b))); +} + +// Computes pairwise difference of each argument as a 16-bit signed or unsigned +// integer values a and b. +FORCE_INLINE __m128i _mm_hsub_epi16(__m128i _a, __m128i _b) +{ + int32x4_t a = vreinterpretq_s32_m128i(_a); + int32x4_t b = vreinterpretq_s32_m128i(_b); + // Interleave using vshrn/vmovn + // [a0|a2|a4|a6|b0|b2|b4|b6] + // [a1|a3|a5|a7|b1|b3|b5|b7] + int16x8_t ab0246 = vcombine_s16(vmovn_s32(a), vmovn_s32(b)); + int16x8_t ab1357 = vcombine_s16(vshrn_n_s32(a, 16), vshrn_n_s32(b, 16)); + // Subtract + return vreinterpretq_m128i_s16(vsubq_s16(ab0246, ab1357)); +} + +// Computes saturated pairwise sub of each argument as a 16-bit signed +// integer values a and b. +FORCE_INLINE __m128i _mm_hadds_epi16(__m128i _a, __m128i _b) +{ +#if defined(__aarch64__) + int16x8_t a = vreinterpretq_s16_m128i(_a); + int16x8_t b = vreinterpretq_s16_m128i(_b); + return vreinterpretq_s64_s16( + vqaddq_s16(vuzp1q_s16(a, b), vuzp2q_s16(a, b))); +#else + int32x4_t a = vreinterpretq_s32_m128i(_a); + int32x4_t b = vreinterpretq_s32_m128i(_b); + // Interleave using vshrn/vmovn + // [a0|a2|a4|a6|b0|b2|b4|b6] + // [a1|a3|a5|a7|b1|b3|b5|b7] + int16x8_t ab0246 = vcombine_s16(vmovn_s32(a), vmovn_s32(b)); + int16x8_t ab1357 = vcombine_s16(vshrn_n_s32(a, 16), vshrn_n_s32(b, 16)); + // Saturated add + return vreinterpretq_m128i_s16(vqaddq_s16(ab0246, ab1357)); +#endif +} + +// Computes saturated pairwise difference of each argument as a 16-bit signed +// integer values a and b. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsubs_epi16 +FORCE_INLINE __m128i _mm_hsubs_epi16(__m128i _a, __m128i _b) +{ +#if defined(__aarch64__) + int16x8_t a = vreinterpretq_s16_m128i(_a); + int16x8_t b = vreinterpretq_s16_m128i(_b); + return vreinterpretq_s64_s16( + vqsubq_s16(vuzp1q_s16(a, b), vuzp2q_s16(a, b))); +#else + int32x4_t a = vreinterpretq_s32_m128i(_a); + int32x4_t b = vreinterpretq_s32_m128i(_b); + // Interleave using vshrn/vmovn + // [a0|a2|a4|a6|b0|b2|b4|b6] + // [a1|a3|a5|a7|b1|b3|b5|b7] + int16x8_t ab0246 = vcombine_s16(vmovn_s32(a), vmovn_s32(b)); + int16x8_t ab1357 = vcombine_s16(vshrn_n_s32(a, 16), vshrn_n_s32(b, 16)); + // Saturated subtract + return vreinterpretq_m128i_s16(vqsubq_s16(ab0246, ab1357)); +#endif +} + +// Computes pairwise add of each argument as a 32-bit signed or unsigned integer +// values a and b. +FORCE_INLINE __m128i _mm_hadd_epi32(__m128i _a, __m128i _b) +{ + int32x4_t a = vreinterpretq_s32_m128i(_a); + int32x4_t b = vreinterpretq_s32_m128i(_b); + return vreinterpretq_m128i_s32( + vcombine_s32(vpadd_s32(vget_low_s32(a), vget_high_s32(a)), + vpadd_s32(vget_low_s32(b), vget_high_s32(b)))); +} + +// Computes pairwise difference of each argument as a 32-bit signed or unsigned +// integer values a and b. +FORCE_INLINE __m128i _mm_hsub_epi32(__m128i _a, __m128i _b) +{ + int64x2_t a = vreinterpretq_s64_m128i(_a); + int64x2_t b = vreinterpretq_s64_m128i(_b); + // Interleave using vshrn/vmovn + // [a0|a2|b0|b2] + // [a1|a2|b1|b3] + int32x4_t ab02 = vcombine_s32(vmovn_s64(a), vmovn_s64(b)); + int32x4_t ab13 = vcombine_s32(vshrn_n_s64(a, 32), vshrn_n_s64(b, 32)); + // Subtract + return vreinterpretq_m128i_s32(vsubq_s32(ab02, ab13)); +} + +// Kahan summation for accurate summation of floating-point numbers. +// http://blog.zachbjornson.com/2019/08/11/fast-float-summation.html +FORCE_INLINE void sse2neon_kadd_f32(float *sum, float *c, float y) +{ + y -= *c; + float t = *sum + y; + *c = (t - *sum) - y; + *sum = t; +} + +// Conditionally multiply the packed single-precision (32-bit) floating-point +// elements in a and b using the high 4 bits in imm8, sum the four products, +// and conditionally store the sum in dst using the low 4 bits of imm. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_dp_ps +FORCE_INLINE __m128 _mm_dp_ps(__m128 a, __m128 b, const int imm) +{ +#if defined(__aarch64__) + /* shortcuts */ + if (imm == 0xFF) { + return _mm_set1_ps(vaddvq_f32(_mm_mul_ps(a, b))); + } + if (imm == 0x7F) { + float32x4_t m = _mm_mul_ps(a, b); + m[3] = 0; + return _mm_set1_ps(vaddvq_f32(m)); + } +#endif + + float s = 0, c = 0; + float32x4_t f32a = vreinterpretq_f32_m128(a); + float32x4_t f32b = vreinterpretq_f32_m128(b); + + /* To improve the accuracy of floating-point summation, Kahan algorithm + * is used for each operation. + */ + if (imm & (1 << 4)) + sse2neon_kadd_f32(&s, &c, f32a[0] * f32b[0]); + if (imm & (1 << 5)) + sse2neon_kadd_f32(&s, &c, f32a[1] * f32b[1]); + if (imm & (1 << 6)) + sse2neon_kadd_f32(&s, &c, f32a[2] * f32b[2]); + if (imm & (1 << 7)) + sse2neon_kadd_f32(&s, &c, f32a[3] * f32b[3]); + s += c; + + float32x4_t res = { + (imm & 0x1) ? s : 0, + (imm & 0x2) ? s : 0, + (imm & 0x4) ? s : 0, + (imm & 0x8) ? s : 0, + }; + return vreinterpretq_m128_f32(res); +} + +/* Compare operations */ + +// Compares for less than +// https://msdn.microsoft.com/en-us/library/vstudio/f330yhc8(v=vs.100).aspx +FORCE_INLINE __m128 _mm_cmplt_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_u32( + vcltq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +} + +// Compares for less than +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/fy94wye7(v=vs.100) +FORCE_INLINE __m128 _mm_cmplt_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmplt_ps(a, b)); +} + +// Compares for greater than. +// +// r0 := (a0 > b0) ? 0xffffffff : 0x0 +// r1 := (a1 > b1) ? 0xffffffff : 0x0 +// r2 := (a2 > b2) ? 0xffffffff : 0x0 +// r3 := (a3 > b3) ? 0xffffffff : 0x0 +// +// https://msdn.microsoft.com/en-us/library/vstudio/11dy102s(v=vs.100).aspx +FORCE_INLINE __m128 _mm_cmpgt_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_u32( + vcgtq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +} + +// Compares for greater than. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/1xyyyy9e(v=vs.100) +FORCE_INLINE __m128 _mm_cmpgt_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmpgt_ps(a, b)); +} + +// Compares for greater than or equal. +// https://msdn.microsoft.com/en-us/library/vstudio/fs813y2t(v=vs.100).aspx +FORCE_INLINE __m128 _mm_cmpge_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_u32( + vcgeq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +} + +// Compares for greater than or equal. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/kesh3ddc(v=vs.100) +FORCE_INLINE __m128 _mm_cmpge_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmpge_ps(a, b)); +} + +// Compares for less than or equal. +// +// r0 := (a0 <= b0) ? 0xffffffff : 0x0 +// r1 := (a1 <= b1) ? 0xffffffff : 0x0 +// r2 := (a2 <= b2) ? 0xffffffff : 0x0 +// r3 := (a3 <= b3) ? 0xffffffff : 0x0 +// +// https://msdn.microsoft.com/en-us/library/vstudio/1s75w83z(v=vs.100).aspx +FORCE_INLINE __m128 _mm_cmple_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_u32( + vcleq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +} + +// Compares for less than or equal. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/a7x0hbhw(v=vs.100) +FORCE_INLINE __m128 _mm_cmple_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmple_ps(a, b)); +} + +// Compares for equality. +// https://msdn.microsoft.com/en-us/library/vstudio/36aectz5(v=vs.100).aspx +FORCE_INLINE __m128 _mm_cmpeq_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_u32( + vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +} + +// Compares for equality. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/k423z28e(v=vs.100) +FORCE_INLINE __m128 _mm_cmpeq_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmpeq_ps(a, b)); +} + +// Compares for inequality. +// https://msdn.microsoft.com/en-us/library/sf44thbx(v=vs.100).aspx +FORCE_INLINE __m128 _mm_cmpneq_ps(__m128 a, __m128 b) +{ + return vreinterpretq_m128_u32(vmvnq_u32( + vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)))); +} + +// Compares for inequality. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/ekya8fh4(v=vs.100) +FORCE_INLINE __m128 _mm_cmpneq_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmpneq_ps(a, b)); +} + +// Compares for not greater than or equal. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/wsexys62(v=vs.100) +FORCE_INLINE __m128 _mm_cmpnge_ps(__m128 a, __m128 b) +{ + return _mm_cmplt_ps(a, b); +} + +// Compares for not greater than or equal. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/fk2y80s8(v=vs.100) +FORCE_INLINE __m128 _mm_cmpnge_ss(__m128 a, __m128 b) +{ + return _mm_cmplt_ss(a, b); +} + +// Compares for not greater than. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/d0xh7w0s(v=vs.100) +FORCE_INLINE __m128 _mm_cmpngt_ps(__m128 a, __m128 b) +{ + return _mm_cmple_ps(a, b); +} + +// Compares for not greater than. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/z7x9ydwh(v=vs.100) +FORCE_INLINE __m128 _mm_cmpngt_ss(__m128 a, __m128 b) +{ + return _mm_cmple_ss(a, b); +} + +// Compares for not less than or equal. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/6a330kxw(v=vs.100) +FORCE_INLINE __m128 _mm_cmpnle_ps(__m128 a, __m128 b) +{ + return _mm_cmpgt_ps(a, b); +} + +// Compares for not less than or equal. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/z7x9ydwh(v=vs.100) +FORCE_INLINE __m128 _mm_cmpnle_ss(__m128 a, __m128 b) +{ + return _mm_cmpgt_ss(a, b); +} + +// Compares for not less than. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/4686bbdw(v=vs.100) +FORCE_INLINE __m128 _mm_cmpnlt_ps(__m128 a, __m128 b) +{ + return _mm_cmpge_ps(a, b); +} + +// Compares for not less than. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/56b9z2wf(v=vs.100) +FORCE_INLINE __m128 _mm_cmpnlt_ss(__m128 a, __m128 b) +{ + return _mm_cmpge_ss(a, b); +} + +// Compares the 16 signed or unsigned 8-bit integers in a and the 16 signed or +// unsigned 8-bit integers in b for equality. +// https://msdn.microsoft.com/en-us/library/windows/desktop/bz5xk21a(v=vs.90).aspx +FORCE_INLINE __m128i _mm_cmpeq_epi8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u8( + vceqq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); +} + +// Compares the 8 signed or unsigned 16-bit integers in a and the 8 signed or +// unsigned 16-bit integers in b for equality. +// https://msdn.microsoft.com/en-us/library/2ay060te(v=vs.100).aspx +FORCE_INLINE __m128i _mm_cmpeq_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u16( + vceqq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +} + +// Compare packed 32-bit integers in a and b for equality, and store the results +// in dst +FORCE_INLINE __m128i _mm_cmpeq_epi32(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u32( + vceqq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +} + +// Compare packed 64-bit integers in a and b for equality, and store the results +// in dst +FORCE_INLINE __m128i _mm_cmpeq_epi64(__m128i a, __m128i b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128i_u64( + vceqq_u64(vreinterpretq_u64_m128i(a), vreinterpretq_u64_m128i(b))); +#else + // ARMv7 lacks vceqq_u64 + // (a == b) -> (a_lo == b_lo) && (a_hi == b_hi) + uint32x4_t cmp = + vceqq_u32(vreinterpretq_u32_m128i(a), vreinterpretq_u32_m128i(b)); + uint32x4_t swapped = vrev64q_u32(cmp); + return vreinterpretq_m128i_u32(vandq_u32(cmp, swapped)); +#endif +} + +// Compares the 16 signed 8-bit integers in a and the 16 signed 8-bit integers +// in b for lesser than. +// https://msdn.microsoft.com/en-us/library/windows/desktop/9s46csht(v=vs.90).aspx +FORCE_INLINE __m128i _mm_cmplt_epi8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u8( + vcltq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); +} + +// Compares the 16 signed 8-bit integers in a and the 16 signed 8-bit integers +// in b for greater than. +// +// r0 := (a0 > b0) ? 0xff : 0x0 +// r1 := (a1 > b1) ? 0xff : 0x0 +// ... +// r15 := (a15 > b15) ? 0xff : 0x0 +// +// https://msdn.microsoft.com/zh-tw/library/wf45zt2b(v=vs.100).aspx +FORCE_INLINE __m128i _mm_cmpgt_epi8(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u8( + vcgtq_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); +} + +// Compares the 8 signed 16-bit integers in a and the 8 signed 16-bit integers +// in b for less than. +// +// r0 := (a0 < b0) ? 0xffff : 0x0 +// r1 := (a1 < b1) ? 0xffff : 0x0 +// ... +// r7 := (a7 < b7) ? 0xffff : 0x0 +// +// https://technet.microsoft.com/en-us/library/t863edb2(v=vs.100).aspx +FORCE_INLINE __m128i _mm_cmplt_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u16( + vcltq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +} + +// Compares the 8 signed 16-bit integers in a and the 8 signed 16-bit integers +// in b for greater than. +// +// r0 := (a0 > b0) ? 0xffff : 0x0 +// r1 := (a1 > b1) ? 0xffff : 0x0 +// ... +// r7 := (a7 > b7) ? 0xffff : 0x0 +// +// https://technet.microsoft.com/en-us/library/xd43yfsa(v=vs.100).aspx +FORCE_INLINE __m128i _mm_cmpgt_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u16( + vcgtq_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +} + + +// Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers +// in b for less than. +// https://msdn.microsoft.com/en-us/library/vstudio/4ak0bf5d(v=vs.100).aspx +FORCE_INLINE __m128i _mm_cmplt_epi32(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u32( + vcltq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +} + +// Compares the 4 signed 32-bit integers in a and the 4 signed 32-bit integers +// in b for greater than. +// https://msdn.microsoft.com/en-us/library/vstudio/1s9f2z0y(v=vs.100).aspx +FORCE_INLINE __m128i _mm_cmpgt_epi32(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u32( + vcgtq_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +} + +// Compares the 2 signed 64-bit integers in a and the 2 signed 64-bit integers +// in b for greater than. +FORCE_INLINE __m128i _mm_cmpgt_epi64(__m128i a, __m128i b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128i_u64( + vcgtq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b))); +#else + // ARMv7 lacks vcgtq_s64. + // This is based off of Clang's SSE2 polyfill: + // (a > b) -> ((a_hi > b_hi) || (a_lo > b_lo && a_hi == b_hi)) + + // Mask the sign bit out since we need a signed AND an unsigned comparison + // and it is ugly to try and split them. + int32x4_t mask = vreinterpretq_s32_s64(vdupq_n_s64(0x80000000ull)); + int32x4_t a_mask = veorq_s32(vreinterpretq_s32_m128i(a), mask); + int32x4_t b_mask = veorq_s32(vreinterpretq_s32_m128i(b), mask); + // Check if a > b + int64x2_t greater = vreinterpretq_s64_u32(vcgtq_s32(a_mask, b_mask)); + // Copy upper mask to lower mask + // a_hi > b_hi + int64x2_t gt_hi = vshrq_n_s64(greater, 63); + // Copy lower mask to upper mask + // a_lo > b_lo + int64x2_t gt_lo = vsliq_n_s64(greater, greater, 32); + // Compare for equality + int64x2_t equal = vreinterpretq_s64_u32(vceqq_s32(a_mask, b_mask)); + // Copy upper mask to lower mask + // a_hi == b_hi + int64x2_t eq_hi = vshrq_n_s64(equal, 63); + // a_hi > b_hi || (a_lo > b_lo && a_hi == b_hi) + int64x2_t ret = vorrq_s64(gt_hi, vandq_s64(gt_lo, eq_hi)); + return vreinterpretq_m128i_s64(ret); +#endif +} + +// Compares the four 32-bit floats in a and b to check if any values are NaN. +// Ordered compare between each value returns true for "orderable" and false for +// "not orderable" (NaN). +// https://msdn.microsoft.com/en-us/library/vstudio/0h9w00fx(v=vs.100).aspx see +// also: +// http://stackoverflow.com/questions/8627331/what-does-ordered-unordered-comparison-mean +// http://stackoverflow.com/questions/29349621/neon-isnanval-intrinsics +FORCE_INLINE __m128 _mm_cmpord_ps(__m128 a, __m128 b) +{ + // Note: NEON does not have ordered compare builtin + // Need to compare a eq a and b eq b to check for NaN + // Do AND of results to get final + uint32x4_t ceqaa = + vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); + uint32x4_t ceqbb = + vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); + return vreinterpretq_m128_u32(vandq_u32(ceqaa, ceqbb)); +} + +// Compares for ordered. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/343t62da(v=vs.100) +FORCE_INLINE __m128 _mm_cmpord_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmpord_ps(a, b)); +} + +// Compares for unordered. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/khy6fk1t(v=vs.100) +FORCE_INLINE __m128 _mm_cmpunord_ps(__m128 a, __m128 b) +{ + uint32x4_t f32a = + vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); + uint32x4_t f32b = + vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); + return vreinterpretq_m128_u32(vmvnq_u32(vandq_u32(f32a, f32b))); +} + +// Compares for unordered. +// https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/2as2387b(v=vs.100) +FORCE_INLINE __m128 _mm_cmpunord_ss(__m128 a, __m128 b) +{ + return _mm_move_ss(a, _mm_cmpunord_ps(a, b)); +} + +// Compares the lower single-precision floating point scalar values of a and b +// using a less than operation. : +// https://msdn.microsoft.com/en-us/library/2kwe606b(v=vs.90).aspx Important +// note!! The documentation on MSDN is incorrect! If either of the values is a +// NAN the docs say you will get a one, but in fact, it will return a zero!! +FORCE_INLINE int _mm_comilt_ss(__m128 a, __m128 b) +{ + uint32x4_t a_not_nan = + vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); + uint32x4_t b_not_nan = + vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); + uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan); + uint32x4_t a_lt_b = + vcltq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); + return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_lt_b), 0) != 0) ? 1 : 0; +} + +// Compares the lower single-precision floating point scalar values of a and b +// using a greater than operation. : +// https://msdn.microsoft.com/en-us/library/b0738e0t(v=vs.100).aspx +FORCE_INLINE int _mm_comigt_ss(__m128 a, __m128 b) +{ + // return vgetq_lane_u32(vcgtq_f32(vreinterpretq_f32_m128(a), + // vreinterpretq_f32_m128(b)), 0); + uint32x4_t a_not_nan = + vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); + uint32x4_t b_not_nan = + vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); + uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan); + uint32x4_t a_gt_b = + vcgtq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); + return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_gt_b), 0) != 0) ? 1 : 0; +} + +// Compares the lower single-precision floating point scalar values of a and b +// using a less than or equal operation. : +// https://msdn.microsoft.com/en-us/library/1w4t7c57(v=vs.90).aspx +FORCE_INLINE int _mm_comile_ss(__m128 a, __m128 b) +{ + // return vgetq_lane_u32(vcleq_f32(vreinterpretq_f32_m128(a), + // vreinterpretq_f32_m128(b)), 0); + uint32x4_t a_not_nan = + vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); + uint32x4_t b_not_nan = + vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); + uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan); + uint32x4_t a_le_b = + vcleq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); + return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_le_b), 0) != 0) ? 1 : 0; +} + +// Compares the lower single-precision floating point scalar values of a and b +// using a greater than or equal operation. : +// https://msdn.microsoft.com/en-us/library/8t80des6(v=vs.100).aspx +FORCE_INLINE int _mm_comige_ss(__m128 a, __m128 b) +{ + // return vgetq_lane_u32(vcgeq_f32(vreinterpretq_f32_m128(a), + // vreinterpretq_f32_m128(b)), 0); + uint32x4_t a_not_nan = + vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); + uint32x4_t b_not_nan = + vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); + uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan); + uint32x4_t a_ge_b = + vcgeq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); + return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_ge_b), 0) != 0) ? 1 : 0; +} + +// Compares the lower single-precision floating point scalar values of a and b +// using an equality operation. : +// https://msdn.microsoft.com/en-us/library/93yx2h2b(v=vs.100).aspx +FORCE_INLINE int _mm_comieq_ss(__m128 a, __m128 b) +{ + // return vgetq_lane_u32(vceqq_f32(vreinterpretq_f32_m128(a), + // vreinterpretq_f32_m128(b)), 0); + uint32x4_t a_not_nan = + vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); + uint32x4_t b_not_nan = + vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); + uint32x4_t a_and_b_not_nan = vandq_u32(a_not_nan, b_not_nan); + uint32x4_t a_eq_b = + vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b)); + return (vgetq_lane_u32(vandq_u32(a_and_b_not_nan, a_eq_b), 0) != 0) ? 1 : 0; +} + +// Compares the lower single-precision floating point scalar values of a and b +// using an inequality operation. : +// https://msdn.microsoft.com/en-us/library/bafh5e0a(v=vs.90).aspx +FORCE_INLINE int _mm_comineq_ss(__m128 a, __m128 b) +{ + // return !vgetq_lane_u32(vceqq_f32(vreinterpretq_f32_m128(a), + // vreinterpretq_f32_m128(b)), 0); + uint32x4_t a_not_nan = + vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a)); + uint32x4_t b_not_nan = + vceqq_f32(vreinterpretq_f32_m128(b), vreinterpretq_f32_m128(b)); + uint32x4_t a_or_b_nan = vmvnq_u32(vandq_u32(a_not_nan, b_not_nan)); + uint32x4_t a_neq_b = vmvnq_u32( + vceqq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); + return (vgetq_lane_u32(vorrq_u32(a_or_b_nan, a_neq_b), 0) != 0) ? 1 : 0; +} + +// according to the documentation, these intrinsics behave the same as the +// non-'u' versions. We'll just alias them here. +#define _mm_ucomilt_ss _mm_comilt_ss +#define _mm_ucomile_ss _mm_comile_ss +#define _mm_ucomigt_ss _mm_comigt_ss +#define _mm_ucomige_ss _mm_comige_ss +#define _mm_ucomieq_ss _mm_comieq_ss +#define _mm_ucomineq_ss _mm_comineq_ss + +/* Conversions */ + +// Convert packed signed 32-bit integers in b to packed single-precision +// (32-bit) floating-point elements, store the results in the lower 2 elements +// of dst, and copy the upper 2 packed elements from a to the upper elements of +// dst. +// +// dst[31:0] := Convert_Int32_To_FP32(b[31:0]) +// dst[63:32] := Convert_Int32_To_FP32(b[63:32]) +// dst[95:64] := a[95:64] +// dst[127:96] := a[127:96] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_pi2ps +FORCE_INLINE __m128 _mm_cvt_pi2ps(__m128 a, __m64 b) +{ + return vreinterpretq_m128_f32( + vcombine_f32(vcvt_f32_s32(vreinterpret_s32_m64(b)), + vget_high_f32(vreinterpretq_f32_m128(a)))); +} + +// Convert the signed 32-bit integer b to a single-precision (32-bit) +// floating-point element, store the result in the lower element of dst, and +// copy the upper 3 packed elements from a to the upper elements of dst. +// +// dst[31:0] := Convert_Int32_To_FP32(b[31:0]) +// dst[127:32] := a[127:32] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_si2ss +FORCE_INLINE __m128 _mm_cvt_si2ss(__m128 a, int b) +{ + return vreinterpretq_m128_f32( + vsetq_lane_f32((float) b, vreinterpretq_f32_m128(a), 0)); +} + +// Convert the signed 32-bit integer b to a single-precision (32-bit) +// floating-point element, store the result in the lower element of dst, and +// copy the upper 3 packed elements from a to the upper elements of dst. +// +// dst[31:0] := Convert_Int32_To_FP32(b[31:0]) +// dst[127:32] := a[127:32] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi32_ss +#define _mm_cvtsi32_ss(a, b) _mm_cvt_si2ss(a, b) + +// Convert the signed 64-bit integer b to a single-precision (32-bit) +// floating-point element, store the result in the lower element of dst, and +// copy the upper 3 packed elements from a to the upper elements of dst. +// +// dst[31:0] := Convert_Int64_To_FP32(b[63:0]) +// dst[127:32] := a[127:32] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi64_ss +FORCE_INLINE __m128 _mm_cvtsi64_ss(__m128 a, int64_t b) +{ + return vreinterpretq_m128_f32( + vsetq_lane_f32((float) b, vreinterpretq_f32_m128(a), 0)); +} + +// Convert the lower single-precision (32-bit) floating-point element in a to a +// 32-bit integer, and store the result in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_ss2si +FORCE_INLINE int _mm_cvt_ss2si(__m128 a) +{ +#if defined(__aarch64__) + return vgetq_lane_s32(vcvtnq_s32_f32(vreinterpretq_f32_m128(a)), 0); +#else + float32_t data = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); + float32_t diff = data - floor(data); + if (diff > 0.5) + return (int32_t) ceil(data); + if (diff == 0.5) { + int32_t f = (int32_t) floor(data); + int32_t c = (int32_t) ceil(data); + return c & 1 ? f : c; + } + return (int32_t) floor(data); +#endif +} + +// Convert packed 16-bit integers in a to packed single-precision (32-bit) +// floating-point elements, and store the results in dst. +// +// FOR j := 0 to 3 +// i := j*16 +// m := j*32 +// dst[m+31:m] := Convert_Int16_To_FP32(a[i+15:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi16_ps +FORCE_INLINE __m128 _mm_cvtpi16_ps(__m64 a) +{ + return vreinterpretq_m128_f32( + vcvtq_f32_s32(vmovl_s16(vreinterpret_s16_m64(a)))); +} + +// Convert packed 32-bit integers in b to packed single-precision (32-bit) +// floating-point elements, store the results in the lower 2 elements of dst, +// and copy the upper 2 packed elements from a to the upper elements of dst. +// +// dst[31:0] := Convert_Int32_To_FP32(b[31:0]) +// dst[63:32] := Convert_Int32_To_FP32(b[63:32]) +// dst[95:64] := a[95:64] +// dst[127:96] := a[127:96] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi32_ps +FORCE_INLINE __m128 _mm_cvtpi32_ps(__m128 a, __m64 b) +{ + return vreinterpretq_m128_f32( + vcombine_f32(vcvt_f32_s32(vreinterpret_s32_m64(b)), + vget_high_f32(vreinterpretq_f32_m128(a)))); +} + +// Convert packed signed 32-bit integers in a to packed single-precision +// (32-bit) floating-point elements, store the results in the lower 2 elements +// of dst, then covert the packed signed 32-bit integers in b to +// single-precision (32-bit) floating-point element, and store the results in +// the upper 2 elements of dst. +// +// dst[31:0] := Convert_Int32_To_FP32(a[31:0]) +// dst[63:32] := Convert_Int32_To_FP32(a[63:32]) +// dst[95:64] := Convert_Int32_To_FP32(b[31:0]) +// dst[127:96] := Convert_Int32_To_FP32(b[63:32]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi32x2_ps +FORCE_INLINE __m128 _mm_cvtpi32x2_ps(__m64 a, __m64 b) +{ + return vreinterpretq_m128_f32(vcvtq_f32_s32( + vcombine_s32(vreinterpret_s32_m64(a), vreinterpret_s32_m64(b)))); +} + +// Convert the lower packed 8-bit integers in a to packed single-precision +// (32-bit) floating-point elements, and store the results in dst. +// +// FOR j := 0 to 3 +// i := j*8 +// m := j*32 +// dst[m+31:m] := Convert_Int8_To_FP32(a[i+7:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi8_ps +FORCE_INLINE __m128 _mm_cvtpi8_ps(__m64 a) +{ + return vreinterpretq_m128_f32(vcvtq_f32_s32( + vmovl_s16(vget_low_s16(vmovl_s8(vreinterpret_s8_m64(a)))))); +} + +// Convert packed unsigned 16-bit integers in a to packed single-precision +// (32-bit) floating-point elements, and store the results in dst. +// +// FOR j := 0 to 3 +// i := j*16 +// m := j*32 +// dst[m+31:m] := Convert_UInt16_To_FP32(a[i+15:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpu16_ps +FORCE_INLINE __m128 _mm_cvtpu16_ps(__m64 a) +{ + return vreinterpretq_m128_f32( + vcvtq_f32_u32(vmovl_u16(vreinterpret_u16_m64(a)))); +} + +// Convert the lower packed unsigned 8-bit integers in a to packed +// single-precision (32-bit) floating-point elements, and store the results in +// dst. +// +// FOR j := 0 to 3 +// i := j*8 +// m := j*32 +// dst[m+31:m] := Convert_UInt8_To_FP32(a[i+7:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpu8_ps +FORCE_INLINE __m128 _mm_cvtpu8_ps(__m64 a) +{ + return vreinterpretq_m128_f32(vcvtq_f32_u32( + vmovl_u16(vget_low_u16(vmovl_u8(vreinterpret_u8_m64(a)))))); +} + +// Converts the four single-precision, floating-point values of a to signed +// 32-bit integer values using truncate. +// https://msdn.microsoft.com/en-us/library/vstudio/1h005y6x(v=vs.100).aspx +FORCE_INLINE __m128i _mm_cvttps_epi32(__m128 a) +{ + return vreinterpretq_m128i_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a))); +} + +// Convert the lower double-precision (64-bit) floating-point element in a to a +// 64-bit integer with truncation, and store the result in dst. +// +// dst[63:0] := Convert_FP64_To_Int64_Truncate(a[63:0]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_si64 +FORCE_INLINE int64_t _mm_cvttsd_si64(__m128d a) +{ +#if defined(__aarch64__) + return vgetq_lane_s64(vcvtq_s64_f64(vreinterpretq_f64_m128d(a)), 0); +#else + double ret = *((double *) &a); + return (int64_t) ret; +#endif +} + +// Convert the lower double-precision (64-bit) floating-point element in a to a +// 64-bit integer with truncation, and store the result in dst. +// +// dst[63:0] := Convert_FP64_To_Int64_Truncate(a[63:0]) +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_si64x +#define _mm_cvttsd_si64x(a) _mm_cvttsd_si64(a) + +// Converts the four signed 32-bit integer values of a to single-precision, +// floating-point values +// https://msdn.microsoft.com/en-us/library/vstudio/36bwxcx5(v=vs.100).aspx +FORCE_INLINE __m128 _mm_cvtepi32_ps(__m128i a) +{ + return vreinterpretq_m128_f32(vcvtq_f32_s32(vreinterpretq_s32_m128i(a))); +} + +// Converts the four unsigned 8-bit integers in the lower 16 bits to four +// unsigned 32-bit integers. +FORCE_INLINE __m128i _mm_cvtepu8_epi16(__m128i a) +{ + uint8x16_t u8x16 = vreinterpretq_u8_m128i(a); /* xxxx xxxx xxxx DCBA */ + uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16)); /* 0x0x 0x0x 0D0C 0B0A */ + return vreinterpretq_m128i_u16(u16x8); +} + +// Converts the four unsigned 8-bit integers in the lower 32 bits to four +// unsigned 32-bit integers. +// https://msdn.microsoft.com/en-us/library/bb531467%28v=vs.100%29.aspx +FORCE_INLINE __m128i _mm_cvtepu8_epi32(__m128i a) +{ + uint8x16_t u8x16 = vreinterpretq_u8_m128i(a); /* xxxx xxxx xxxx DCBA */ + uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16)); /* 0x0x 0x0x 0D0C 0B0A */ + uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000D 000C 000B 000A */ + return vreinterpretq_m128i_u32(u32x4); +} + +// Converts the two unsigned 8-bit integers in the lower 16 bits to two +// unsigned 64-bit integers. +FORCE_INLINE __m128i _mm_cvtepu8_epi64(__m128i a) +{ + uint8x16_t u8x16 = vreinterpretq_u8_m128i(a); /* xxxx xxxx xxxx xxBA */ + uint16x8_t u16x8 = vmovl_u8(vget_low_u8(u8x16)); /* 0x0x 0x0x 0x0x 0B0A */ + uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000x 000x 000B 000A */ + uint64x2_t u64x2 = vmovl_u32(vget_low_u32(u32x4)); /* 0000 000B 0000 000A */ + return vreinterpretq_m128i_u64(u64x2); +} + +// Converts the four unsigned 8-bit integers in the lower 16 bits to four +// unsigned 32-bit integers. +FORCE_INLINE __m128i _mm_cvtepi8_epi16(__m128i a) +{ + int8x16_t s8x16 = vreinterpretq_s8_m128i(a); /* xxxx xxxx xxxx DCBA */ + int16x8_t s16x8 = vmovl_s8(vget_low_s8(s8x16)); /* 0x0x 0x0x 0D0C 0B0A */ + return vreinterpretq_m128i_s16(s16x8); +} + +// Converts the four unsigned 8-bit integers in the lower 32 bits to four +// unsigned 32-bit integers. +FORCE_INLINE __m128i _mm_cvtepi8_epi32(__m128i a) +{ + int8x16_t s8x16 = vreinterpretq_s8_m128i(a); /* xxxx xxxx xxxx DCBA */ + int16x8_t s16x8 = vmovl_s8(vget_low_s8(s8x16)); /* 0x0x 0x0x 0D0C 0B0A */ + int32x4_t s32x4 = vmovl_s16(vget_low_s16(s16x8)); /* 000D 000C 000B 000A */ + return vreinterpretq_m128i_s32(s32x4); +} + +// Converts the two signed 8-bit integers in the lower 32 bits to four +// signed 64-bit integers. +FORCE_INLINE __m128i _mm_cvtepi8_epi64(__m128i a) +{ + int8x16_t s8x16 = vreinterpretq_s8_m128i(a); /* xxxx xxxx xxxx xxBA */ + int16x8_t s16x8 = vmovl_s8(vget_low_s8(s8x16)); /* 0x0x 0x0x 0x0x 0B0A */ + int32x4_t s32x4 = vmovl_s16(vget_low_s16(s16x8)); /* 000x 000x 000B 000A */ + int64x2_t s64x2 = vmovl_s32(vget_low_s32(s32x4)); /* 0000 000B 0000 000A */ + return vreinterpretq_m128i_s64(s64x2); +} + +// Converts the four signed 16-bit integers in the lower 64 bits to four signed +// 32-bit integers. +FORCE_INLINE __m128i _mm_cvtepi16_epi32(__m128i a) +{ + return vreinterpretq_m128i_s32( + vmovl_s16(vget_low_s16(vreinterpretq_s16_m128i(a)))); +} + +// Converts the two signed 16-bit integers in the lower 32 bits two signed +// 32-bit integers. +FORCE_INLINE __m128i _mm_cvtepi16_epi64(__m128i a) +{ + int16x8_t s16x8 = vreinterpretq_s16_m128i(a); /* xxxx xxxx xxxx 0B0A */ + int32x4_t s32x4 = vmovl_s16(vget_low_s16(s16x8)); /* 000x 000x 000B 000A */ + int64x2_t s64x2 = vmovl_s32(vget_low_s32(s32x4)); /* 0000 000B 0000 000A */ + return vreinterpretq_m128i_s64(s64x2); +} + +// Converts the four unsigned 16-bit integers in the lower 64 bits to four +// unsigned 32-bit integers. +FORCE_INLINE __m128i _mm_cvtepu16_epi32(__m128i a) +{ + return vreinterpretq_m128i_u32( + vmovl_u16(vget_low_u16(vreinterpretq_u16_m128i(a)))); +} + +// Converts the two unsigned 16-bit integers in the lower 32 bits to two +// unsigned 64-bit integers. +FORCE_INLINE __m128i _mm_cvtepu16_epi64(__m128i a) +{ + uint16x8_t u16x8 = vreinterpretq_u16_m128i(a); /* xxxx xxxx xxxx 0B0A */ + uint32x4_t u32x4 = vmovl_u16(vget_low_u16(u16x8)); /* 000x 000x 000B 000A */ + uint64x2_t u64x2 = vmovl_u32(vget_low_u32(u32x4)); /* 0000 000B 0000 000A */ + return vreinterpretq_m128i_u64(u64x2); +} + +// Converts the two unsigned 32-bit integers in the lower 64 bits to two +// unsigned 64-bit integers. +FORCE_INLINE __m128i _mm_cvtepu32_epi64(__m128i a) +{ + return vreinterpretq_m128i_u64( + vmovl_u32(vget_low_u32(vreinterpretq_u32_m128i(a)))); +} + +// Converts the two signed 32-bit integers in the lower 64 bits to two signed +// 64-bit integers. +FORCE_INLINE __m128i _mm_cvtepi32_epi64(__m128i a) +{ + return vreinterpretq_m128i_s64( + vmovl_s32(vget_low_s32(vreinterpretq_s32_m128i(a)))); +} + +// Converts the four single-precision, floating-point values of a to signed +// 32-bit integer values. +// +// r0 := (int) a0 +// r1 := (int) a1 +// r2 := (int) a2 +// r3 := (int) a3 +// +// https://msdn.microsoft.com/en-us/library/vstudio/xdc42k5e(v=vs.100).aspx +// *NOTE*. The default rounding mode on SSE is 'round to even', which ARMv7-A +// does not support! It is supported on ARMv8-A however. +FORCE_INLINE __m128i _mm_cvtps_epi32(__m128 a) +{ +#if defined(__aarch64__) + return vreinterpretq_m128i_s32(vcvtnq_s32_f32(a)); +#else + uint32x4_t signmask = vdupq_n_u32(0x80000000); + float32x4_t half = vbslq_f32(signmask, vreinterpretq_f32_m128(a), + vdupq_n_f32(0.5f)); /* +/- 0.5 */ + int32x4_t r_normal = vcvtq_s32_f32(vaddq_f32( + vreinterpretq_f32_m128(a), half)); /* round to integer: [a + 0.5]*/ + int32x4_t r_trunc = + vcvtq_s32_f32(vreinterpretq_f32_m128(a)); /* truncate to integer: [a] */ + int32x4_t plusone = vreinterpretq_s32_u32(vshrq_n_u32( + vreinterpretq_u32_s32(vnegq_s32(r_trunc)), 31)); /* 1 or 0 */ + int32x4_t r_even = vbicq_s32(vaddq_s32(r_trunc, plusone), + vdupq_n_s32(1)); /* ([a] + {0,1}) & ~1 */ + float32x4_t delta = vsubq_f32( + vreinterpretq_f32_m128(a), + vcvtq_f32_s32(r_trunc)); /* compute delta: delta = (a - [a]) */ + uint32x4_t is_delta_half = vceqq_f32(delta, half); /* delta == +/- 0.5 */ + return vreinterpretq_m128i_s32(vbslq_s32(is_delta_half, r_even, r_normal)); +#endif +} + +// Copy the lower 32-bit integer in a to dst. +// +// dst[31:0] := a[31:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si32 +FORCE_INLINE int _mm_cvtsi128_si32(__m128i a) +{ + return vgetq_lane_s32(vreinterpretq_s32_m128i(a), 0); +} + +// Copy the lower 64-bit integer in a to dst. +// +// dst[63:0] := a[63:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si64 +FORCE_INLINE int64_t _mm_cvtsi128_si64(__m128i a) +{ + return vgetq_lane_s64(vreinterpretq_s64_m128i(a), 0); +} + +// Copy the lower 64-bit integer in a to dst. +// +// dst[63:0] := a[63:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si64x +#define _mm_cvtsi128_si64x(a) _mm_cvtsi128_si64(a) + +// Moves 32-bit integer a to the least significant 32 bits of an __m128 object, +// zero extending the upper bits. +// +// r0 := a +// r1 := 0x0 +// r2 := 0x0 +// r3 := 0x0 +// +// https://msdn.microsoft.com/en-us/library/ct3539ha%28v=vs.90%29.aspx +FORCE_INLINE __m128i _mm_cvtsi32_si128(int a) +{ + return vreinterpretq_m128i_s32(vsetq_lane_s32(a, vdupq_n_s32(0), 0)); +} + +// Moves 64-bit integer a to the least significant 64 bits of an __m128 object, +// zero extending the upper bits. +// +// r0 := a +// r1 := 0x0 +FORCE_INLINE __m128i _mm_cvtsi64_si128(int64_t a) +{ + return vreinterpretq_m128i_s64(vsetq_lane_s64(a, vdupq_n_s64(0), 0)); +} + +// Cast vector of type __m128 to type __m128d. This intrinsic is only used for +// compilation and does not generate any instructions, thus it has zero latency. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castps_pd +FORCE_INLINE __m128d _mm_castps_pd(__m128 a) +{ + return vreinterpretq_m128d_s32(vreinterpretq_s32_m128(a)); +} + +// Applies a type cast to reinterpret four 32-bit floating point values passed +// in as a 128-bit parameter as packed 32-bit integers. +// https://msdn.microsoft.com/en-us/library/bb514099.aspx +FORCE_INLINE __m128i _mm_castps_si128(__m128 a) +{ + return vreinterpretq_m128i_s32(vreinterpretq_s32_m128(a)); +} + +// Applies a type cast to reinterpret four 32-bit integers passed in as a +// 128-bit parameter as packed 32-bit floating point values. +// https://msdn.microsoft.com/en-us/library/bb514029.aspx +FORCE_INLINE __m128 _mm_castsi128_ps(__m128i a) +{ + return vreinterpretq_m128_s32(vreinterpretq_s32_m128i(a)); +} + +// Loads 128-bit value. : +// https://msdn.microsoft.com/en-us/library/atzzad1h(v=vs.80).aspx +FORCE_INLINE __m128i _mm_load_si128(const __m128i *p) +{ + return vreinterpretq_m128i_s32(vld1q_s32((const int32_t *) p)); +} + +// Load a double-precision (64-bit) floating-point element from memory into both +// elements of dst. +// +// dst[63:0] := MEM[mem_addr+63:mem_addr] +// dst[127:64] := MEM[mem_addr+63:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load1_pd +FORCE_INLINE __m128d _mm_load1_pd(const double *p) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64(vld1q_dup_f64(p)); +#else + return vreinterpretq_m128d_s64(vdupq_n_s64(*(const int64_t *) p)); +#endif +} + +// Load a double-precision (64-bit) floating-point element from memory into the +// upper element of dst, and copy the lower element from a to dst. mem_addr does +// not need to be aligned on any particular boundary. +// +// dst[63:0] := a[63:0] +// dst[127:64] := MEM[mem_addr+63:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadh_pd +FORCE_INLINE __m128d _mm_loadh_pd(__m128d a, const double *p) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64( + vcombine_f64(vget_low_f64(vreinterpretq_f64_m128d(a)), vld1_f64(p))); +#else + return vreinterpretq_m128d_f32(vcombine_f32( + vget_low_f32(vreinterpretq_f32_m128d(a)), vld1_f32((const float *) p))); +#endif +} + +// Load a double-precision (64-bit) floating-point element from memory into both +// elements of dst. +// +// dst[63:0] := MEM[mem_addr+63:mem_addr] +// dst[127:64] := MEM[mem_addr+63:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_pd1 +#define _mm_load_pd1 _mm_load1_pd + +// Load a double-precision (64-bit) floating-point element from memory into both +// elements of dst. +// +// dst[63:0] := MEM[mem_addr+63:mem_addr] +// dst[127:64] := MEM[mem_addr+63:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loaddup_pd +#define _mm_loaddup_pd _mm_load1_pd + +// Loads 128-bit value. : +// https://msdn.microsoft.com/zh-cn/library/f4k12ae8(v=vs.90).aspx +FORCE_INLINE __m128i _mm_loadu_si128(const __m128i *p) +{ + return vreinterpretq_m128i_s32(vld1q_s32((const int32_t *) p)); +} + +// Load unaligned 32-bit integer from memory into the first element of dst. +// +// dst[31:0] := MEM[mem_addr+31:mem_addr] +// dst[MAX:32] := 0 +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si32 +FORCE_INLINE __m128i _mm_loadu_si32(const void *p) +{ + return vreinterpretq_m128i_s32( + vsetq_lane_s32(*(const int32_t *) p, vdupq_n_s32(0), 0)); +} + +// Convert packed double-precision (64-bit) floating-point elements in a to +// packed single-precision (32-bit) floating-point elements, and store the +// results in dst. +// +// FOR j := 0 to 1 +// i := 32*j +// k := 64*j +// dst[i+31:i] := Convert_FP64_To_FP32(a[k+64:k]) +// ENDFOR +// dst[127:64] := 0 +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpd_ps +FORCE_INLINE __m128 _mm_cvtpd_ps(__m128d a) +{ +#if defined(__aarch64__) + float32x2_t tmp = vcvt_f32_f64(vreinterpretq_f64_m128d(a)); + return vreinterpretq_m128_f32(vcombine_f32(tmp, vdup_n_f32(0))); +#else + float a0 = (float) ((double *) &a)[0]; + float a1 = (float) ((double *) &a)[1]; + return _mm_set_ps(0, 0, a1, a0); +#endif +} + +// Copy the lower double-precision (64-bit) floating-point element of a to dst. +// +// dst[63:0] := a[63:0] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_f64 +FORCE_INLINE double _mm_cvtsd_f64(__m128d a) +{ +#if defined(__aarch64__) + return (double) vgetq_lane_f64(vreinterpretq_f64_m128d(a), 0); +#else + return ((double *) &a)[0]; +#endif +} + +// Convert packed single-precision (32-bit) floating-point elements in a to +// packed double-precision (64-bit) floating-point elements, and store the +// results in dst. +// +// FOR j := 0 to 1 +// i := 64*j +// k := 32*j +// dst[i+63:i] := Convert_FP32_To_FP64(a[k+31:k]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pd +FORCE_INLINE __m128d _mm_cvtps_pd(__m128 a) +{ +#if defined(__aarch64__) + return vreinterpretq_m128d_f64( + vcvt_f64_f32(vget_low_f32(vreinterpretq_f32_m128(a)))); +#else + double a0 = (double) vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); + double a1 = (double) vgetq_lane_f32(vreinterpretq_f32_m128(a), 1); + return _mm_set_pd(a1, a0); +#endif +} + +// Cast vector of type __m128d to type __m128i. This intrinsic is only used for +// compilation and does not generate any instructions, thus it has zero latency. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castpd_si128 +FORCE_INLINE __m128i _mm_castpd_si128(__m128d a) +{ + return vreinterpretq_m128i_s64(vreinterpretq_s64_m128d(a)); +} + +// Blend packed single-precision (32-bit) floating-point elements from a and b +// using mask, and store the results in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blendv_ps +FORCE_INLINE __m128 _mm_blendv_ps(__m128 a, __m128 b, __m128 mask) +{ + return vreinterpretq_m128_f32(vbslq_f32(vreinterpretq_u32_m128(mask), + vreinterpretq_f32_m128(b), + vreinterpretq_f32_m128(a))); +} + +// Round the packed single-precision (32-bit) floating-point elements in a using +// the rounding parameter, and store the results as packed single-precision +// floating-point elements in dst. +// software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_round_ps +FORCE_INLINE __m128 _mm_round_ps(__m128 a, int rounding) +{ +#if defined(__aarch64__) + switch (rounding) { + case (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC): + return vreinterpretq_m128_f32(vrndnq_f32(vreinterpretq_f32_m128(a))); + case (_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC): + return vreinterpretq_m128_f32(vrndmq_f32(vreinterpretq_f32_m128(a))); + case (_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC): + return vreinterpretq_m128_f32(vrndpq_f32(vreinterpretq_f32_m128(a))); + case (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC): + return vreinterpretq_m128_f32(vrndq_f32(vreinterpretq_f32_m128(a))); + default: //_MM_FROUND_CUR_DIRECTION + return vreinterpretq_m128_f32(vrndiq_f32(vreinterpretq_f32_m128(a))); + } +#else + float *v_float = (float *) &a; + __m128 zero, neg_inf, pos_inf; + + switch (rounding) { + case (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC): + return _mm_cvtepi32_ps(_mm_cvtps_epi32(a)); + case (_MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC): + return (__m128){floorf(v_float[0]), floorf(v_float[1]), + floorf(v_float[2]), floorf(v_float[3])}; + case (_MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC): + return (__m128){ceilf(v_float[0]), ceilf(v_float[1]), ceilf(v_float[2]), + ceilf(v_float[3])}; + case (_MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC): + zero = _mm_set_ps(0.0f, 0.0f, 0.0f, 0.0f); + neg_inf = _mm_set_ps(floorf(v_float[0]), floorf(v_float[1]), + floorf(v_float[2]), floorf(v_float[3])); + pos_inf = _mm_set_ps(ceilf(v_float[0]), ceilf(v_float[1]), + ceilf(v_float[2]), ceilf(v_float[3])); + return _mm_blendv_ps(pos_inf, neg_inf, _mm_cmple_ps(a, zero)); + default: //_MM_FROUND_CUR_DIRECTION + return (__m128){roundf(v_float[0]), roundf(v_float[1]), + roundf(v_float[2]), roundf(v_float[3])}; + } +#endif +} + +// Convert packed single-precision (32-bit) floating-point elements in a to +// packed 32-bit integers, and store the results in dst. +// +// FOR j := 0 to 1 +// i := 32*j +// dst[i+31:i] := Convert_FP32_To_Int32(a[i+31:i]) +// ENDFOR +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_ps2pi +FORCE_INLINE __m64 _mm_cvt_ps2pi(__m128 a) +{ +#if defined(__aarch64__) + return vreinterpret_m64_s32( + vget_low_s32(vcvtnq_s32_f32(vreinterpretq_f32_m128(a)))); +#else + return vreinterpret_m64_s32( + vcvt_s32_f32(vget_low_f32(vreinterpretq_f32_m128( + _mm_round_ps(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC))))); +#endif +} + +// Round the packed single-precision (32-bit) floating-point elements in a up to +// an integer value, and store the results as packed single-precision +// floating-point elements in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_ceil_ps +FORCE_INLINE __m128 _mm_ceil_ps(__m128 a) +{ + return _mm_round_ps(a, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); +} + +// Round the packed single-precision (32-bit) floating-point elements in a down +// to an integer value, and store the results as packed single-precision +// floating-point elements in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_floor_ps +FORCE_INLINE __m128 _mm_floor_ps(__m128 a) +{ + return _mm_round_ps(a, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); +} + + +// Load 128-bits of integer data from unaligned memory into dst. This intrinsic +// may perform better than _mm_loadu_si128 when the data crosses a cache line +// boundary. +// +// dst[127:0] := MEM[mem_addr+127:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_lddqu_si128 +#define _mm_lddqu_si128 _mm_loadu_si128 + +/* Miscellaneous Operations */ + +// Shifts the 8 signed 16-bit integers in a right by count bits while shifting +// in the sign bit. +// +// r0 := a0 >> count +// r1 := a1 >> count +// ... +// r7 := a7 >> count +// +// https://msdn.microsoft.com/en-us/library/3c9997dk(v%3dvs.90).aspx +FORCE_INLINE __m128i _mm_sra_epi16(__m128i a, __m128i count) +{ + int64_t c = (int64_t) vget_low_s64((int64x2_t) count); + if (c > 15) + return _mm_cmplt_epi16(a, _mm_setzero_si128()); + return vreinterpretq_m128i_s16(vshlq_s16((int16x8_t) a, vdupq_n_s16(-c))); +} + +// Shifts the 4 signed 32-bit integers in a right by count bits while shifting +// in the sign bit. +// +// r0 := a0 >> count +// r1 := a1 >> count +// r2 := a2 >> count +// r3 := a3 >> count +// +// https://msdn.microsoft.com/en-us/library/ce40009e(v%3dvs.100).aspx +FORCE_INLINE __m128i _mm_sra_epi32(__m128i a, __m128i count) +{ + int64_t c = (int64_t) vget_low_s64((int64x2_t) count); + if (c > 31) + return _mm_cmplt_epi32(a, _mm_setzero_si128()); + return vreinterpretq_m128i_s32(vshlq_s32((int32x4_t) a, vdupq_n_s32(-c))); +} + +// Packs the 16 signed 16-bit integers from a and b into 8-bit integers and +// saturates. +// https://msdn.microsoft.com/en-us/library/k4y4f7w5%28v=vs.90%29.aspx +FORCE_INLINE __m128i _mm_packs_epi16(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s8( + vcombine_s8(vqmovn_s16(vreinterpretq_s16_m128i(a)), + vqmovn_s16(vreinterpretq_s16_m128i(b)))); +} + +// Packs the 16 signed 16 - bit integers from a and b into 8 - bit unsigned +// integers and saturates. +// +// r0 := UnsignedSaturate(a0) +// r1 := UnsignedSaturate(a1) +// ... +// r7 := UnsignedSaturate(a7) +// r8 := UnsignedSaturate(b0) +// r9 := UnsignedSaturate(b1) +// ... +// r15 := UnsignedSaturate(b7) +// +// https://msdn.microsoft.com/en-us/library/07ad1wx4(v=vs.100).aspx +FORCE_INLINE __m128i _mm_packus_epi16(const __m128i a, const __m128i b) +{ + return vreinterpretq_m128i_u8( + vcombine_u8(vqmovun_s16(vreinterpretq_s16_m128i(a)), + vqmovun_s16(vreinterpretq_s16_m128i(b)))); +} + +// Packs the 8 signed 32-bit integers from a and b into signed 16-bit integers +// and saturates. +// +// r0 := SignedSaturate(a0) +// r1 := SignedSaturate(a1) +// r2 := SignedSaturate(a2) +// r3 := SignedSaturate(a3) +// r4 := SignedSaturate(b0) +// r5 := SignedSaturate(b1) +// r6 := SignedSaturate(b2) +// r7 := SignedSaturate(b3) +// +// https://msdn.microsoft.com/en-us/library/393t56f9%28v=vs.90%29.aspx +FORCE_INLINE __m128i _mm_packs_epi32(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_s16( + vcombine_s16(vqmovn_s32(vreinterpretq_s32_m128i(a)), + vqmovn_s32(vreinterpretq_s32_m128i(b)))); +} + +// Packs the 8 unsigned 32-bit integers from a and b into unsigned 16-bit +// integers and saturates. +// +// r0 := UnsignedSaturate(a0) +// r1 := UnsignedSaturate(a1) +// r2 := UnsignedSaturate(a2) +// r3 := UnsignedSaturate(a3) +// r4 := UnsignedSaturate(b0) +// r5 := UnsignedSaturate(b1) +// r6 := UnsignedSaturate(b2) +// r7 := UnsignedSaturate(b3) +FORCE_INLINE __m128i _mm_packus_epi32(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u16( + vcombine_u16(vqmovun_s32(vreinterpretq_s32_m128i(a)), + vqmovun_s32(vreinterpretq_s32_m128i(b)))); +} + +// Interleaves the lower 8 signed or unsigned 8-bit integers in a with the lower +// 8 signed or unsigned 8-bit integers in b. +// +// r0 := a0 +// r1 := b0 +// r2 := a1 +// r3 := b1 +// ... +// r14 := a7 +// r15 := b7 +// +// https://msdn.microsoft.com/en-us/library/xf7k860c%28v=vs.90%29.aspx +FORCE_INLINE __m128i _mm_unpacklo_epi8(__m128i a, __m128i b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128i_s8( + vzip1q_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); +#else + int8x8_t a1 = vreinterpret_s8_s16(vget_low_s16(vreinterpretq_s16_m128i(a))); + int8x8_t b1 = vreinterpret_s8_s16(vget_low_s16(vreinterpretq_s16_m128i(b))); + int8x8x2_t result = vzip_s8(a1, b1); + return vreinterpretq_m128i_s8(vcombine_s8(result.val[0], result.val[1])); +#endif +} + +// Interleaves the lower 4 signed or unsigned 16-bit integers in a with the +// lower 4 signed or unsigned 16-bit integers in b. +// +// r0 := a0 +// r1 := b0 +// r2 := a1 +// r3 := b1 +// r4 := a2 +// r5 := b2 +// r6 := a3 +// r7 := b3 +// +// https://msdn.microsoft.com/en-us/library/btxb17bw%28v=vs.90%29.aspx +FORCE_INLINE __m128i _mm_unpacklo_epi16(__m128i a, __m128i b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128i_s16( + vzip1q_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +#else + int16x4_t a1 = vget_low_s16(vreinterpretq_s16_m128i(a)); + int16x4_t b1 = vget_low_s16(vreinterpretq_s16_m128i(b)); + int16x4x2_t result = vzip_s16(a1, b1); + return vreinterpretq_m128i_s16(vcombine_s16(result.val[0], result.val[1])); +#endif +} + +// Interleaves the lower 2 signed or unsigned 32 - bit integers in a with the +// lower 2 signed or unsigned 32 - bit integers in b. +// +// r0 := a0 +// r1 := b0 +// r2 := a1 +// r3 := b1 +// +// https://msdn.microsoft.com/en-us/library/x8atst9d(v=vs.100).aspx +FORCE_INLINE __m128i _mm_unpacklo_epi32(__m128i a, __m128i b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128i_s32( + vzip1q_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +#else + int32x2_t a1 = vget_low_s32(vreinterpretq_s32_m128i(a)); + int32x2_t b1 = vget_low_s32(vreinterpretq_s32_m128i(b)); + int32x2x2_t result = vzip_s32(a1, b1); + return vreinterpretq_m128i_s32(vcombine_s32(result.val[0], result.val[1])); +#endif +} + +FORCE_INLINE __m128i _mm_unpacklo_epi64(__m128i a, __m128i b) +{ + int64x1_t a_l = vget_low_s64(vreinterpretq_s64_m128i(a)); + int64x1_t b_l = vget_low_s64(vreinterpretq_s64_m128i(b)); + return vreinterpretq_m128i_s64(vcombine_s64(a_l, b_l)); +} + +// Selects and interleaves the lower two single-precision, floating-point values +// from a and b. +// +// r0 := a0 +// r1 := b0 +// r2 := a1 +// r3 := b1 +// +// https://msdn.microsoft.com/en-us/library/25st103b%28v=vs.90%29.aspx +FORCE_INLINE __m128 _mm_unpacklo_ps(__m128 a, __m128 b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128_f32( + vzip1q_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +#else + float32x2_t a1 = vget_low_f32(vreinterpretq_f32_m128(a)); + float32x2_t b1 = vget_low_f32(vreinterpretq_f32_m128(b)); + float32x2x2_t result = vzip_f32(a1, b1); + return vreinterpretq_m128_f32(vcombine_f32(result.val[0], result.val[1])); +#endif +} + +// Selects and interleaves the upper two single-precision, floating-point values +// from a and b. +// +// r0 := a2 +// r1 := b2 +// r2 := a3 +// r3 := b3 +// +// https://msdn.microsoft.com/en-us/library/skccxx7d%28v=vs.90%29.aspx +FORCE_INLINE __m128 _mm_unpackhi_ps(__m128 a, __m128 b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128_f32( + vzip2q_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); +#else + float32x2_t a1 = vget_high_f32(vreinterpretq_f32_m128(a)); + float32x2_t b1 = vget_high_f32(vreinterpretq_f32_m128(b)); + float32x2x2_t result = vzip_f32(a1, b1); + return vreinterpretq_m128_f32(vcombine_f32(result.val[0], result.val[1])); +#endif +} + +// Interleaves the upper 8 signed or unsigned 8-bit integers in a with the upper +// 8 signed or unsigned 8-bit integers in b. +// +// r0 := a8 +// r1 := b8 +// r2 := a9 +// r3 := b9 +// ... +// r14 := a15 +// r15 := b15 +// +// https://msdn.microsoft.com/en-us/library/t5h7783k(v=vs.100).aspx +FORCE_INLINE __m128i _mm_unpackhi_epi8(__m128i a, __m128i b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128i_s8( + vzip2q_s8(vreinterpretq_s8_m128i(a), vreinterpretq_s8_m128i(b))); +#else + int8x8_t a1 = + vreinterpret_s8_s16(vget_high_s16(vreinterpretq_s16_m128i(a))); + int8x8_t b1 = + vreinterpret_s8_s16(vget_high_s16(vreinterpretq_s16_m128i(b))); + int8x8x2_t result = vzip_s8(a1, b1); + return vreinterpretq_m128i_s8(vcombine_s8(result.val[0], result.val[1])); +#endif +} + +// Interleaves the upper 4 signed or unsigned 16-bit integers in a with the +// upper 4 signed or unsigned 16-bit integers in b. +// +// r0 := a4 +// r1 := b4 +// r2 := a5 +// r3 := b5 +// r4 := a6 +// r5 := b6 +// r6 := a7 +// r7 := b7 +// +// https://msdn.microsoft.com/en-us/library/03196cz7(v=vs.100).aspx +FORCE_INLINE __m128i _mm_unpackhi_epi16(__m128i a, __m128i b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128i_s16( + vzip2q_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b))); +#else + int16x4_t a1 = vget_high_s16(vreinterpretq_s16_m128i(a)); + int16x4_t b1 = vget_high_s16(vreinterpretq_s16_m128i(b)); + int16x4x2_t result = vzip_s16(a1, b1); + return vreinterpretq_m128i_s16(vcombine_s16(result.val[0], result.val[1])); +#endif +} + +// Interleaves the upper 2 signed or unsigned 32-bit integers in a with the +// upper 2 signed or unsigned 32-bit integers in b. +// https://msdn.microsoft.com/en-us/library/65sa7cbs(v=vs.100).aspx +FORCE_INLINE __m128i _mm_unpackhi_epi32(__m128i a, __m128i b) +{ +#if defined(__aarch64__) + return vreinterpretq_m128i_s32( + vzip2q_s32(vreinterpretq_s32_m128i(a), vreinterpretq_s32_m128i(b))); +#else + int32x2_t a1 = vget_high_s32(vreinterpretq_s32_m128i(a)); + int32x2_t b1 = vget_high_s32(vreinterpretq_s32_m128i(b)); + int32x2x2_t result = vzip_s32(a1, b1); + return vreinterpretq_m128i_s32(vcombine_s32(result.val[0], result.val[1])); +#endif +} + +// Interleaves the upper signed or unsigned 64-bit integer in a with the +// upper signed or unsigned 64-bit integer in b. +// +// r0 := a1 +// r1 := b1 +FORCE_INLINE __m128i _mm_unpackhi_epi64(__m128i a, __m128i b) +{ + int64x1_t a_h = vget_high_s64(vreinterpretq_s64_m128i(a)); + int64x1_t b_h = vget_high_s64(vreinterpretq_s64_m128i(b)); + return vreinterpretq_m128i_s64(vcombine_s64(a_h, b_h)); +} + +// Horizontally compute the minimum amongst the packed unsigned 16-bit integers +// in a, store the minimum and index in dst, and zero the remaining bits in dst. +// +// index[2:0] := 0 +// min[15:0] := a[15:0] +// FOR j := 0 to 7 +// i := j*16 +// IF a[i+15:i] < min[15:0] +// index[2:0] := j +// min[15:0] := a[i+15:i] +// FI +// ENDFOR +// dst[15:0] := min[15:0] +// dst[18:16] := index[2:0] +// dst[127:19] := 0 +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_minpos_epu16 +FORCE_INLINE __m128i _mm_minpos_epu16(__m128i a) +{ + __m128i dst; + uint16_t min, idx = 0; + // Find the minimum value +#if defined(__aarch64__) + min = vminvq_u16(vreinterpretq_u16_m128i(a)); +#else + __m64 tmp; + tmp = vreinterpret_m64_u16( + vmin_u16(vget_low_u16(vreinterpretq_u16_m128i(a)), + vget_high_u16(vreinterpretq_u16_m128i(a)))); + tmp = vreinterpret_m64_u16( + vpmin_u16(vreinterpret_u16_m64(tmp), vreinterpret_u16_m64(tmp))); + tmp = vreinterpret_m64_u16( + vpmin_u16(vreinterpret_u16_m64(tmp), vreinterpret_u16_m64(tmp))); + min = vget_lane_u16(vreinterpret_u16_m64(tmp), 0); +#endif + // Get the index of the minimum value + int i; + for (i = 0; i < 8; i++) { + if (min == vgetq_lane_u16(vreinterpretq_u16_m128i(a), 0)) { + idx = (uint16_t) i; + break; + } + a = _mm_srli_si128(a, 2); + } + // Generate result + dst = _mm_setzero_si128(); + dst = vreinterpretq_m128i_u16( + vsetq_lane_u16(min, vreinterpretq_u16_m128i(dst), 0)); + dst = vreinterpretq_m128i_u16( + vsetq_lane_u16(idx, vreinterpretq_u16_m128i(dst), 1)); + return dst; +} + +// shift to right +// https://msdn.microsoft.com/en-us/library/bb514041(v=vs.120).aspx +// http://blog.csdn.net/hemmingway/article/details/44828303 +// Clang requires a macro here, as it is extremely picky about c being a +// literal. +#define _mm_alignr_epi8(a, b, c) \ + ((__m128i) vextq_s8((int8x16_t)(b), (int8x16_t)(a), (c))) + +// Compute the bitwise AND of 128 bits (representing integer data) in a and b, +// and set ZF to 1 if the result is zero, otherwise set ZF to 0. Compute the +// bitwise NOT of a and then AND with b, and set CF to 1 if the result is zero, +// otherwise set CF to 0. Return the CF value. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_testc_si128 +FORCE_INLINE int _mm_testc_si128(__m128i a, __m128i b) +{ + int64x2_t s64 = + vandq_s64(vreinterpretq_s64_s32(vmvnq_s32(vreinterpretq_s32_m128i(a))), + vreinterpretq_s64_m128i(b)); + return !(vgetq_lane_s64(s64, 0) | vgetq_lane_s64(s64, 1)); +} + +// Compute the bitwise AND of 128 bits (representing integer data) in a and b, +// and set ZF to 1 if the result is zero, otherwise set ZF to 0. Compute the +// bitwise NOT of a and then AND with b, and set CF to 1 if the result is zero, +// otherwise set CF to 0. Return the ZF value. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_testz_si128 +FORCE_INLINE int _mm_testz_si128(__m128i a, __m128i b) +{ + int64x2_t s64 = + vandq_s64(vreinterpretq_s64_m128i(a), vreinterpretq_s64_m128i(b)); + return !(vgetq_lane_s64(s64, 0) | vgetq_lane_s64(s64, 1)); +} + +// Extracts the selected signed or unsigned 8-bit integer from a and zero +// extends. +// FORCE_INLINE int _mm_extract_epi8(__m128i a, __constrange(0,16) int imm) +#define _mm_extract_epi8(a, imm) vgetq_lane_u8(vreinterpretq_u8_m128i(a), (imm)) + +// Inserts the least significant 8 bits of b into the selected 8-bit integer +// of a. +// FORCE_INLINE __m128i _mm_insert_epi8(__m128i a, int b, +// __constrange(0,16) int imm) +#define _mm_insert_epi8(a, b, imm) \ + __extension__({ \ + vreinterpretq_m128i_s8( \ + vsetq_lane_s8((b), vreinterpretq_s8_m128i(a), (imm))); \ + }) + +// Extracts the selected signed or unsigned 16-bit integer from a and zero +// extends. +// https://msdn.microsoft.com/en-us/library/6dceta0c(v=vs.100).aspx +// FORCE_INLINE int _mm_extract_epi16(__m128i a, __constrange(0,8) int imm) +#define _mm_extract_epi16(a, imm) \ + vgetq_lane_u16(vreinterpretq_u16_m128i(a), (imm)) + +// Inserts the least significant 16 bits of b into the selected 16-bit integer +// of a. +// https://msdn.microsoft.com/en-us/library/kaze8hz1%28v=vs.100%29.aspx +// FORCE_INLINE __m128i _mm_insert_epi16(__m128i a, int b, +// __constrange(0,8) int imm) +#define _mm_insert_epi16(a, b, imm) \ + __extension__({ \ + vreinterpretq_m128i_s16( \ + vsetq_lane_s16((b), vreinterpretq_s16_m128i(a), (imm))); \ + }) + +// Extracts the selected signed or unsigned 32-bit integer from a and zero +// extends. +// FORCE_INLINE int _mm_extract_epi32(__m128i a, __constrange(0,4) int imm) +#define _mm_extract_epi32(a, imm) \ + vgetq_lane_s32(vreinterpretq_s32_m128i(a), (imm)) + +// Extracts the selected single-precision (32-bit) floating-point from a. +// FORCE_INLINE int _mm_extract_ps(__m128 a, __constrange(0,4) int imm) +#define _mm_extract_ps(a, imm) vgetq_lane_s32(vreinterpretq_s32_m128(a), (imm)) + +// Inserts the least significant 32 bits of b into the selected 32-bit integer +// of a. +// FORCE_INLINE __m128i _mm_insert_epi32(__m128i a, int b, +// __constrange(0,4) int imm) +#define _mm_insert_epi32(a, b, imm) \ + __extension__({ \ + vreinterpretq_m128i_s32( \ + vsetq_lane_s32((b), vreinterpretq_s32_m128i(a), (imm))); \ + }) + +// Extracts the selected signed or unsigned 64-bit integer from a and zero +// extends. +// FORCE_INLINE __int64 _mm_extract_epi64(__m128i a, __constrange(0,2) int imm) +#define _mm_extract_epi64(a, imm) \ + vgetq_lane_s64(vreinterpretq_s64_m128i(a), (imm)) + +// Inserts the least significant 64 bits of b into the selected 64-bit integer +// of a. +// FORCE_INLINE __m128i _mm_insert_epi64(__m128i a, __int64 b, +// __constrange(0,2) int imm) +#define _mm_insert_epi64(a, b, imm) \ + __extension__({ \ + vreinterpretq_m128i_s64( \ + vsetq_lane_s64((b), vreinterpretq_s64_m128i(a), (imm))); \ + }) + +// Count the number of bits set to 1 in unsigned 32-bit integer a, and +// return that count in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_u32 +FORCE_INLINE int _mm_popcnt_u32(unsigned int a) +{ +#if defined(__aarch64__) +#if __has_builtin(__builtin_popcount) + return __builtin_popcount(a); +#else + return (int) vaddlv_u8(vcnt_u8(vcreate_u8((uint64_t) a))); +#endif +#else + uint32_t count = 0; + uint8x8_t input_val, count8x8_val; + uint16x4_t count16x4_val; + uint32x2_t count32x2_val; + + input_val = vld1_u8((uint8_t *) &a); + count8x8_val = vcnt_u8(input_val); + count16x4_val = vpaddl_u8(count8x8_val); + count32x2_val = vpaddl_u16(count16x4_val); + + vst1_u32(&count, count32x2_val); + return count; +#endif +} + +// Count the number of bits set to 1 in unsigned 64-bit integer a, and +// return that count in dst. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_u64 +FORCE_INLINE int64_t _mm_popcnt_u64(uint64_t a) +{ +#if defined(__aarch64__) +#if __has_builtin(__builtin_popcountll) + return __builtin_popcountll(a); +#else + return (int64_t) vaddlv_u8(vcnt_u8(vcreate_u8(a))); +#endif +#else + uint64_t count = 0; + uint8x8_t input_val, count8x8_val; + uint16x4_t count16x4_val; + uint32x2_t count32x2_val; + uint64x1_t count64x1_val; + + input_val = vld1_u8((uint8_t *) &a); + count8x8_val = vcnt_u8(input_val); + count16x4_val = vpaddl_u8(count8x8_val); + count32x2_val = vpaddl_u16(count16x4_val); + count64x1_val = vpaddl_u32(count32x2_val); + vst1_u64(&count, count64x1_val); + return count; +#endif +} + +// Macro: Transpose the 4x4 matrix formed by the 4 rows of single-precision +// (32-bit) floating-point elements in row0, row1, row2, and row3, and store the +// transposed matrix in these vectors (row0 now contains column 0, etc.). +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=MM_TRANSPOSE4_PS +#define _MM_TRANSPOSE4_PS(row0, row1, row2, row3) \ + do { \ + float32x4x2_t ROW01 = vtrnq_f32(row0, row1); \ + float32x4x2_t ROW23 = vtrnq_f32(row2, row3); \ + row0 = vcombine_f32(vget_low_f32(ROW01.val[0]), \ + vget_low_f32(ROW23.val[0])); \ + row1 = vcombine_f32(vget_low_f32(ROW01.val[1]), \ + vget_low_f32(ROW23.val[1])); \ + row2 = vcombine_f32(vget_high_f32(ROW01.val[0]), \ + vget_high_f32(ROW23.val[0])); \ + row3 = vcombine_f32(vget_high_f32(ROW01.val[1]), \ + vget_high_f32(ROW23.val[1])); \ + } while (0) + +/* Crypto Extensions */ + +#if defined(__ARM_FEATURE_CRYPTO) +// Wraps vmull_p64 +FORCE_INLINE uint64x2_t _sse2neon_vmull_p64(uint64x1_t _a, uint64x1_t _b) +{ + poly64_t a = vget_lane_p64(vreinterpret_p64_u64(_a), 0); + poly64_t b = vget_lane_p64(vreinterpret_p64_u64(_b), 0); + return vreinterpretq_u64_p128(vmull_p64(a, b)); +} +#else // ARMv7 polyfill +// ARMv7/some A64 lacks vmull_p64, but it has vmull_p8. +// +// vmull_p8 calculates 8 8-bit->16-bit polynomial multiplies, but we need a +// 64-bit->128-bit polynomial multiply. +// +// It needs some work and is somewhat slow, but it is still faster than all +// known scalar methods. +// +// Algorithm adapted to C from +// https://www.workofard.com/2017/07/ghash-for-low-end-cores/, which is adapted +// from "Fast Software Polynomial Multiplication on ARM Processors Using the +// NEON Engine" by Danilo Camara, Conrado Gouvea, Julio Lopez and Ricardo Dahab +// (https://hal.inria.fr/hal-01506572) +static uint64x2_t _sse2neon_vmull_p64(uint64x1_t _a, uint64x1_t _b) +{ + poly8x8_t a = vreinterpret_p8_u64(_a); + poly8x8_t b = vreinterpret_p8_u64(_b); + + // Masks + uint8x16_t k48_32 = vcombine_u8(vcreate_u8(0x0000ffffffffffff), + vcreate_u8(0x00000000ffffffff)); + uint8x16_t k16_00 = vcombine_u8(vcreate_u8(0x000000000000ffff), + vcreate_u8(0x0000000000000000)); + + // Do the multiplies, rotating with vext to get all combinations + uint8x16_t d = vreinterpretq_u8_p16(vmull_p8(a, b)); // D = A0 * B0 + uint8x16_t e = + vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 1))); // E = A0 * B1 + uint8x16_t f = + vreinterpretq_u8_p16(vmull_p8(vext_p8(a, a, 1), b)); // F = A1 * B0 + uint8x16_t g = + vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 2))); // G = A0 * B2 + uint8x16_t h = + vreinterpretq_u8_p16(vmull_p8(vext_p8(a, a, 2), b)); // H = A2 * B0 + uint8x16_t i = + vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 3))); // I = A0 * B3 + uint8x16_t j = + vreinterpretq_u8_p16(vmull_p8(vext_p8(a, a, 3), b)); // J = A3 * B0 + uint8x16_t k = + vreinterpretq_u8_p16(vmull_p8(a, vext_p8(b, b, 4))); // L = A0 * B4 + + // Add cross products + uint8x16_t l = veorq_u8(e, f); // L = E + F + uint8x16_t m = veorq_u8(g, h); // M = G + H + uint8x16_t n = veorq_u8(i, j); // N = I + J + + // Interleave. Using vzip1 and vzip2 prevents Clang from emitting TBL + // instructions. +#if defined(__aarch64__) + uint8x16_t lm_p0 = vreinterpretq_u8_u64( + vzip1q_u64(vreinterpretq_u64_u8(l), vreinterpretq_u64_u8(m))); + uint8x16_t lm_p1 = vreinterpretq_u8_u64( + vzip2q_u64(vreinterpretq_u64_u8(l), vreinterpretq_u64_u8(m))); + uint8x16_t nk_p0 = vreinterpretq_u8_u64( + vzip1q_u64(vreinterpretq_u64_u8(n), vreinterpretq_u64_u8(k))); + uint8x16_t nk_p1 = vreinterpretq_u8_u64( + vzip2q_u64(vreinterpretq_u64_u8(n), vreinterpretq_u64_u8(k))); +#else + uint8x16_t lm_p0 = vcombine_u8(vget_low_u8(l), vget_low_u8(m)); + uint8x16_t lm_p1 = vcombine_u8(vget_high_u8(l), vget_high_u8(m)); + uint8x16_t nk_p0 = vcombine_u8(vget_low_u8(n), vget_low_u8(k)); + uint8x16_t nk_p1 = vcombine_u8(vget_high_u8(n), vget_high_u8(k)); +#endif + // t0 = (L) (P0 + P1) << 8 + // t1 = (M) (P2 + P3) << 16 + uint8x16_t t0t1_tmp = veorq_u8(lm_p0, lm_p1); + uint8x16_t t0t1_h = vandq_u8(lm_p1, k48_32); + uint8x16_t t0t1_l = veorq_u8(t0t1_tmp, t0t1_h); + + // t2 = (N) (P4 + P5) << 24 + // t3 = (K) (P6 + P7) << 32 + uint8x16_t t2t3_tmp = veorq_u8(nk_p0, nk_p1); + uint8x16_t t2t3_h = vandq_u8(nk_p1, k16_00); + uint8x16_t t2t3_l = veorq_u8(t2t3_tmp, t2t3_h); + + // De-interleave +#if defined(__aarch64__) + uint8x16_t t0 = vreinterpretq_u8_u64( + vuzp1q_u64(vreinterpretq_u64_u8(t0t1_l), vreinterpretq_u64_u8(t0t1_h))); + uint8x16_t t1 = vreinterpretq_u8_u64( + vuzp2q_u64(vreinterpretq_u64_u8(t0t1_l), vreinterpretq_u64_u8(t0t1_h))); + uint8x16_t t2 = vreinterpretq_u8_u64( + vuzp1q_u64(vreinterpretq_u64_u8(t2t3_l), vreinterpretq_u64_u8(t2t3_h))); + uint8x16_t t3 = vreinterpretq_u8_u64( + vuzp2q_u64(vreinterpretq_u64_u8(t2t3_l), vreinterpretq_u64_u8(t2t3_h))); +#else + uint8x16_t t1 = vcombine_u8(vget_high_u8(t0t1_l), vget_high_u8(t0t1_h)); + uint8x16_t t0 = vcombine_u8(vget_low_u8(t0t1_l), vget_low_u8(t0t1_h)); + uint8x16_t t3 = vcombine_u8(vget_high_u8(t2t3_l), vget_high_u8(t2t3_h)); + uint8x16_t t2 = vcombine_u8(vget_low_u8(t2t3_l), vget_low_u8(t2t3_h)); +#endif + // Shift the cross products + uint8x16_t t0_shift = vextq_u8(t0, t0, 15); // t0 << 8 + uint8x16_t t1_shift = vextq_u8(t1, t1, 14); // t1 << 16 + uint8x16_t t2_shift = vextq_u8(t2, t2, 13); // t2 << 24 + uint8x16_t t3_shift = vextq_u8(t3, t3, 12); // t3 << 32 + + // Accumulate the products + uint8x16_t cross1 = veorq_u8(t0_shift, t1_shift); + uint8x16_t cross2 = veorq_u8(t2_shift, t3_shift); + uint8x16_t mix = veorq_u8(d, cross1); + uint8x16_t r = veorq_u8(mix, cross2); + return vreinterpretq_u64_u8(r); +} +#endif // ARMv7 polyfill + +FORCE_INLINE __m128i _mm_clmulepi64_si128(__m128i _a, __m128i _b, const int imm) +{ + uint64x2_t a = vreinterpretq_u64_m128i(_a); + uint64x2_t b = vreinterpretq_u64_m128i(_b); + switch (imm & 0x11) { + case 0x00: + return vreinterpretq_m128i_u64( + _sse2neon_vmull_p64(vget_low_u64(a), vget_low_u64(b))); + case 0x01: + return vreinterpretq_m128i_u64( + _sse2neon_vmull_p64(vget_high_u64(a), vget_low_u64(b))); + case 0x10: + return vreinterpretq_m128i_u64( + _sse2neon_vmull_p64(vget_low_u64(a), vget_high_u64(b))); + case 0x11: + return vreinterpretq_m128i_u64( + _sse2neon_vmull_p64(vget_high_u64(a), vget_high_u64(b))); + default: + abort(); + } +} + +#if !defined(__ARM_FEATURE_CRYPTO) +/* clang-format off */ +#define SSE2NEON_AES_DATA(w) \ + { \ + w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), \ + w(0xc5), w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), \ + w(0xab), w(0x76), w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), \ + w(0x59), w(0x47), w(0xf0), w(0xad), w(0xd4), w(0xa2), w(0xaf), \ + w(0x9c), w(0xa4), w(0x72), w(0xc0), w(0xb7), w(0xfd), w(0x93), \ + w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc), w(0x34), w(0xa5), \ + w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15), w(0x04), \ + w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a), \ + w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), \ + w(0x75), w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), \ + w(0x5a), w(0xa0), w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), \ + w(0xe3), w(0x2f), w(0x84), w(0x53), w(0xd1), w(0x00), w(0xed), \ + w(0x20), w(0xfc), w(0xb1), w(0x5b), w(0x6a), w(0xcb), w(0xbe), \ + w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf), w(0xd0), w(0xef), \ + w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85), w(0x45), \ + w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8), \ + w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), \ + w(0xf5), w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), \ + w(0xf3), w(0xd2), w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), \ + w(0x97), w(0x44), w(0x17), w(0xc4), w(0xa7), w(0x7e), w(0x3d), \ + w(0x64), w(0x5d), w(0x19), w(0x73), w(0x60), w(0x81), w(0x4f), \ + w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88), w(0x46), w(0xee), \ + w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb), w(0xe0), \ + w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c), \ + w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), \ + w(0x79), w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), \ + w(0x4e), w(0xa9), w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), \ + w(0x7a), w(0xae), w(0x08), w(0xba), w(0x78), w(0x25), w(0x2e), \ + w(0x1c), w(0xa6), w(0xb4), w(0xc6), w(0xe8), w(0xdd), w(0x74), \ + w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a), w(0x70), w(0x3e), \ + w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e), w(0x61), \ + w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e), \ + w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), \ + w(0x94), w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), \ + w(0x28), w(0xdf), w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), \ + w(0xe6), w(0x42), w(0x68), w(0x41), w(0x99), w(0x2d), w(0x0f), \ + w(0xb0), w(0x54), w(0xbb), w(0x16) \ + } +/* clang-format on */ + +/* X Macro trick. See https://en.wikipedia.org/wiki/X_Macro */ +#define SSE2NEON_AES_H0(x) (x) +static const uint8_t SSE2NEON_sbox[256] = SSE2NEON_AES_DATA(SSE2NEON_AES_H0); +#undef SSE2NEON_AES_H0 + +// In the absence of crypto extensions, implement aesenc using regular neon +// intrinsics instead. See: +// https://www.workofard.com/2017/01/accelerated-aes-for-the-arm64-linux-kernel/ +// https://www.workofard.com/2017/07/ghash-for-low-end-cores/ and +// https://github.com/ColinIanKing/linux-next-mirror/blob/b5f466091e130caaf0735976648f72bd5e09aa84/crypto/aegis128-neon-inner.c#L52 +// for more information Reproduced with permission of the author. +FORCE_INLINE __m128i _mm_aesenc_si128(__m128i EncBlock, __m128i RoundKey) +{ +#if defined(__aarch64__) + static const uint8_t shift_rows[] = {0x0, 0x5, 0xa, 0xf, 0x4, 0x9, + 0xe, 0x3, 0x8, 0xd, 0x2, 0x7, + 0xc, 0x1, 0x6, 0xb}; + static const uint8_t ror32by8[] = {0x1, 0x2, 0x3, 0x0, 0x5, 0x6, 0x7, 0x4, + 0x9, 0xa, 0xb, 0x8, 0xd, 0xe, 0xf, 0xc}; + + uint8x16_t v; + uint8x16_t w = vreinterpretq_u8_m128i(EncBlock); + + // shift rows + w = vqtbl1q_u8(w, vld1q_u8(shift_rows)); + + // sub bytes + v = vqtbl4q_u8(vld1q_u8_x4(SSE2NEON_sbox), w); + v = vqtbx4q_u8(v, vld1q_u8_x4(SSE2NEON_sbox + 0x40), w - 0x40); + v = vqtbx4q_u8(v, vld1q_u8_x4(SSE2NEON_sbox + 0x80), w - 0x80); + v = vqtbx4q_u8(v, vld1q_u8_x4(SSE2NEON_sbox + 0xc0), w - 0xc0); + + // mix columns + w = (v << 1) ^ (uint8x16_t)(((int8x16_t) v >> 7) & 0x1b); + w ^= (uint8x16_t) vrev32q_u16((uint16x8_t) v); + w ^= vqtbl1q_u8(v ^ w, vld1q_u8(ror32by8)); + + // add round key + return vreinterpretq_m128i_u8(w) ^ RoundKey; + +#else /* ARMv7-A NEON implementation */ +#define SSE2NEON_AES_B2W(b0, b1, b2, b3) \ + (((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | \ + (b0)) +#define SSE2NEON_AES_F2(x) ((x << 1) ^ (((x >> 7) & 1) * 0x011b /* WPOLY */)) +#define SSE2NEON_AES_F3(x) (SSE2NEON_AES_F2(x) ^ x) +#define SSE2NEON_AES_U0(p) \ + SSE2NEON_AES_B2W(SSE2NEON_AES_F2(p), p, p, SSE2NEON_AES_F3(p)) +#define SSE2NEON_AES_U1(p) \ + SSE2NEON_AES_B2W(SSE2NEON_AES_F3(p), SSE2NEON_AES_F2(p), p, p) +#define SSE2NEON_AES_U2(p) \ + SSE2NEON_AES_B2W(p, SSE2NEON_AES_F3(p), SSE2NEON_AES_F2(p), p) +#define SSE2NEON_AES_U3(p) \ + SSE2NEON_AES_B2W(p, p, SSE2NEON_AES_F3(p), SSE2NEON_AES_F2(p)) + static const uint32_t ALIGN_STRUCT(16) aes_table[4][256] = { + SSE2NEON_AES_DATA(SSE2NEON_AES_U0), + SSE2NEON_AES_DATA(SSE2NEON_AES_U1), + SSE2NEON_AES_DATA(SSE2NEON_AES_U2), + SSE2NEON_AES_DATA(SSE2NEON_AES_U3), + }; +#undef SSE2NEON_AES_B2W +#undef SSE2NEON_AES_F2 +#undef SSE2NEON_AES_F3 +#undef SSE2NEON_AES_U0 +#undef SSE2NEON_AES_U1 +#undef SSE2NEON_AES_U2 +#undef SSE2NEON_AES_U3 + + uint32_t x0 = _mm_cvtsi128_si32(EncBlock); + uint32_t x1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(EncBlock, 0x55)); + uint32_t x2 = _mm_cvtsi128_si32(_mm_shuffle_epi32(EncBlock, 0xAA)); + uint32_t x3 = _mm_cvtsi128_si32(_mm_shuffle_epi32(EncBlock, 0xFF)); + + __m128i out = _mm_set_epi32( + (aes_table[0][x3 & 0xff] ^ aes_table[1][(x0 >> 8) & 0xff] ^ + aes_table[2][(x1 >> 16) & 0xff] ^ aes_table[3][x2 >> 24]), + (aes_table[0][x2 & 0xff] ^ aes_table[1][(x3 >> 8) & 0xff] ^ + aes_table[2][(x0 >> 16) & 0xff] ^ aes_table[3][x1 >> 24]), + (aes_table[0][x1 & 0xff] ^ aes_table[1][(x2 >> 8) & 0xff] ^ + aes_table[2][(x3 >> 16) & 0xff] ^ aes_table[3][x0 >> 24]), + (aes_table[0][x0 & 0xff] ^ aes_table[1][(x1 >> 8) & 0xff] ^ + aes_table[2][(x2 >> 16) & 0xff] ^ aes_table[3][x3 >> 24])); + + return _mm_xor_si128(out, RoundKey); +#endif +} + +FORCE_INLINE __m128i _mm_aesenclast_si128(__m128i a, __m128i RoundKey) +{ + /* FIXME: optimized for NEON */ + uint8_t v[4][4] = { + [0] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 0)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 5)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 10)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 15)]}, + [1] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 4)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 9)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 14)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 3)]}, + [2] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 8)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 13)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 2)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 7)]}, + [3] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 12)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 1)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 6)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 11)]}, + }; + for (int i = 0; i < 16; i++) + vreinterpretq_nth_u8_m128i(a, i) = + v[i / 4][i % 4] ^ vreinterpretq_nth_u8_m128i(RoundKey, i); + return a; +} + +// Emits the Advanced Encryption Standard (AES) instruction aeskeygenassist. +// This instruction generates a round key for AES encryption. See +// https://kazakov.life/2017/11/01/cryptocurrency-mining-on-ios-devices/ +// for details. +// +// https://msdn.microsoft.com/en-us/library/cc714138(v=vs.120).aspx +FORCE_INLINE __m128i _mm_aeskeygenassist_si128(__m128i key, const int rcon) +{ + uint32_t X1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(key, 0x55)); + uint32_t X3 = _mm_cvtsi128_si32(_mm_shuffle_epi32(key, 0xFF)); + for (int i = 0; i < 4; ++i) { + ((uint8_t *) &X1)[i] = SSE2NEON_sbox[((uint8_t *) &X1)[i]]; + ((uint8_t *) &X3)[i] = SSE2NEON_sbox[((uint8_t *) &X3)[i]]; + } + return _mm_set_epi32(((X3 >> 8) | (X3 << 24)) ^ rcon, X3, + ((X1 >> 8) | (X1 << 24)) ^ rcon, X1); +} +#undef SSE2NEON_AES_DATA + +#else /* __ARM_FEATURE_CRYPTO */ +// Implements equivalent of 'aesenc' by combining AESE (with an empty key) and +// AESMC and then manually applying the real key as an xor operation. This +// unfortunately means an additional xor op; the compiler should be able to +// optimize this away for repeated calls however. See +// https://blog.michaelbrase.com/2018/05/08/emulating-x86-aes-intrinsics-on-armv8-a +// for more details. +FORCE_INLINE __m128i _mm_aesenc_si128(__m128i a, __m128i b) +{ + return vreinterpretq_m128i_u8( + vaesmcq_u8(vaeseq_u8(vreinterpretq_u8_m128i(a), vdupq_n_u8(0))) ^ + vreinterpretq_u8_m128i(b)); +} + +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_aesenclast_si128 +FORCE_INLINE __m128i _mm_aesenclast_si128(__m128i a, __m128i RoundKey) +{ + return _mm_xor_si128(vreinterpretq_m128i_u8(vaeseq_u8( + vreinterpretq_u8_m128i(a), vdupq_n_u8(0))), + RoundKey); +} + +FORCE_INLINE __m128i _mm_aeskeygenassist_si128(__m128i a, const int rcon) +{ + // AESE does ShiftRows and SubBytes on A + uint8x16_t u8 = vaeseq_u8(vreinterpretq_u8_m128i(a), vdupq_n_u8(0)); + + uint8x16_t dest = { + // Undo ShiftRows step from AESE and extract X1 and X3 + u8[0x4], u8[0x1], u8[0xE], u8[0xB], // SubBytes(X1) + u8[0x1], u8[0xE], u8[0xB], u8[0x4], // ROT(SubBytes(X1)) + u8[0xC], u8[0x9], u8[0x6], u8[0x3], // SubBytes(X3) + u8[0x9], u8[0x6], u8[0x3], u8[0xC], // ROT(SubBytes(X3)) + }; + uint32x4_t r = {0, (unsigned) rcon, 0, (unsigned) rcon}; + return vreinterpretq_m128i_u8(dest) ^ vreinterpretq_m128i_u32(r); +} +#endif + +/* Streaming Extensions */ + +// Guarantees that every preceding store is globally visible before any +// subsequent store. +// https://msdn.microsoft.com/en-us/library/5h2w73d1%28v=vs.90%29.aspx +FORCE_INLINE void _mm_sfence(void) +{ + __sync_synchronize(); +} + +// Store 128-bits (composed of 4 packed single-precision (32-bit) floating- +// point elements) from a into memory using a non-temporal memory hint. +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_ps +FORCE_INLINE void _mm_stream_ps(float *p, __m128 a) +{ +#if __has_builtin(__builtin_nontemporal_store) + __builtin_nontemporal_store(a, (float32x4_t *) p); +#else + vst1q_f32(p, vreinterpretq_f32_m128(a)); +#endif +} + +// Stores the data in a to the address p without polluting the caches. If the +// cache line containing address p is already in the cache, the cache will be +// updated. +// https://msdn.microsoft.com/en-us/library/ba08y07y%28v=vs.90%29.aspx +FORCE_INLINE void _mm_stream_si128(__m128i *p, __m128i a) +{ +#if __has_builtin(__builtin_nontemporal_store) + __builtin_nontemporal_store(a, p); +#else + vst1q_s64((int64_t *) p, vreinterpretq_s64_m128i(a)); +#endif +} + +// Load 128-bits of integer data from memory into dst using a non-temporal +// memory hint. mem_addr must be aligned on a 16-byte boundary or a +// general-protection exception may be generated. +// +// dst[127:0] := MEM[mem_addr+127:mem_addr] +// +// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_load_si128 +FORCE_INLINE __m128i _mm_stream_load_si128(__m128i *p) +{ +#if __has_builtin(__builtin_nontemporal_store) + return __builtin_nontemporal_load(p); +#else + return vreinterpretq_m128i_s64(vld1q_s64((int64_t *) p)); +#endif +} + +// Cache line containing p is flushed and invalidated from all caches in the +// coherency domain. : +// https://msdn.microsoft.com/en-us/library/ba08y07y(v=vs.100).aspx +FORCE_INLINE void _mm_clflush(void const *p) +{ + (void) p; + // no corollary for Neon? +} + +// Allocate aligned blocks of memory. +// https://software.intel.com/en-us/ +// cpp-compiler-developer-guide-and-reference-allocating-and-freeing-aligned-memory-blocks +FORCE_INLINE void *_mm_malloc(size_t size, size_t align) +{ + void *ptr; + if (align == 1) + return malloc(size); + if (align == 2 || (sizeof(void *) == 8 && align == 4)) + align = sizeof(void *); + if (!posix_memalign(&ptr, align, size)) + return ptr; + return NULL; +} + +FORCE_INLINE void _mm_free(void *addr) +{ + free(addr); +} + +// Starting with the initial value in crc, accumulates a CRC32 value for +// unsigned 8-bit integer v. +// https://msdn.microsoft.com/en-us/library/bb514036(v=vs.100) +FORCE_INLINE uint32_t _mm_crc32_u8(uint32_t crc, uint8_t v) +{ +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) + __asm__ __volatile__("crc32cb %w[c], %w[c], %w[v]\n\t" + : [c] "+r"(crc) + : [v] "r"(v)); +#else + crc ^= v; + for (int bit = 0; bit < 8; bit++) { + if (crc & 1) + crc = (crc >> 1) ^ UINT32_C(0x82f63b78); + else + crc = (crc >> 1); + } +#endif + return crc; +} + +// Starting with the initial value in crc, accumulates a CRC32 value for +// unsigned 16-bit integer v. +// https://msdn.microsoft.com/en-us/library/bb531411(v=vs.100) +FORCE_INLINE uint32_t _mm_crc32_u16(uint32_t crc, uint16_t v) +{ +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) + __asm__ __volatile__("crc32ch %w[c], %w[c], %w[v]\n\t" + : [c] "+r"(crc) + : [v] "r"(v)); +#else + crc = _mm_crc32_u8(crc, v & 0xff); + crc = _mm_crc32_u8(crc, (v >> 8) & 0xff); +#endif + return crc; +} + +// Starting with the initial value in crc, accumulates a CRC32 value for +// unsigned 32-bit integer v. +// https://msdn.microsoft.com/en-us/library/bb531394(v=vs.100) +FORCE_INLINE uint32_t _mm_crc32_u32(uint32_t crc, uint32_t v) +{ +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) + __asm__ __volatile__("crc32cw %w[c], %w[c], %w[v]\n\t" + : [c] "+r"(crc) + : [v] "r"(v)); +#else + crc = _mm_crc32_u16(crc, v & 0xffff); + crc = _mm_crc32_u16(crc, (v >> 16) & 0xffff); +#endif + return crc; +} + +// Starting with the initial value in crc, accumulates a CRC32 value for +// unsigned 64-bit integer v. +// https://msdn.microsoft.com/en-us/library/bb514033(v=vs.100) +FORCE_INLINE uint64_t _mm_crc32_u64(uint64_t crc, uint64_t v) +{ +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) + __asm__ __volatile__("crc32cx %w[c], %w[c], %x[v]\n\t" + : [c] "+r"(crc) + : [v] "r"(v)); +#else + crc = _mm_crc32_u32((uint32_t)(crc), v & 0xffffffff); + crc = _mm_crc32_u32((uint32_t)(crc), (v >> 32) & 0xffffffff); +#endif + return crc; +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma pop_macro("ALIGN_STRUCT") +#pragma pop_macro("FORCE_INLINE") +#endif + +#if defined(__GNUC__) +#pragma GCC pop_options +#endif + +#endif diff --git a/venv/Include/site/python3.9/pygame/mask.h b/venv/Include/site/python3.9/pygame/mask.h new file mode 100644 index 0000000..45ad8c5 --- /dev/null +++ b/venv/Include/site/python3.9/pygame/mask.h @@ -0,0 +1,7 @@ +#ifndef PGMASK_INTERNAL_H +#define PGMASK_INTERNAL_H + +#include "include/pygame_mask.h" +#define PYGAMEAPI_MASK_NUMSLOTS 1 + +#endif /* ~PGMASK_INTERNAL_H */ diff --git a/venv/Include/site/python3.9/pygame/mixer.h b/venv/Include/site/python3.9/pygame/mixer.h new file mode 100644 index 0000000..97f5a0f --- /dev/null +++ b/venv/Include/site/python3.9/pygame/mixer.h @@ -0,0 +1,14 @@ +#ifndef MIXER_INTERNAL_H +#define MIXER_INTERNAL_H + +#include + +/* test mixer initializations */ +#define MIXER_INIT_CHECK() \ + if (!SDL_WasInit(SDL_INIT_AUDIO)) \ + return RAISE(pgExc_SDLError, "mixer not initialized") + +#define PYGAMEAPI_MIXER_NUMSLOTS 5 +#include "include/pygame_mixer.h" + +#endif /* ~MIXER_INTERNAL_H */ diff --git a/venv/Include/site/python3.9/pygame/palette.h b/venv/Include/site/python3.9/pygame/palette.h new file mode 100644 index 0000000..1ae4cf6 --- /dev/null +++ b/venv/Include/site/python3.9/pygame/palette.h @@ -0,0 +1,123 @@ +/* + pygame - Python Game Library + Copyright (C) 2000-2001 Pete Shinners + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Pete Shinners + pete@shinners.org +*/ + +#ifndef PALETTE_H +#define PALETTE_H + +#include + +/* SDL 2 does not assign a default palette color scheme to a new 8 bit + * surface. Instead, the palette is set all white. This defines the SDL 1.2 + * default palette. + */ +static const SDL_Color default_palette_colors[] = { + {0, 0, 0, 255}, {0, 0, 85, 255}, {0, 0, 170, 255}, + {0, 0, 255, 255}, {0, 36, 0, 255}, {0, 36, 85, 255}, + {0, 36, 170, 255}, {0, 36, 255, 255}, {0, 73, 0, 255}, + {0, 73, 85, 255}, {0, 73, 170, 255}, {0, 73, 255, 255}, + {0, 109, 0, 255}, {0, 109, 85, 255}, {0, 109, 170, 255}, + {0, 109, 255, 255}, {0, 146, 0, 255}, {0, 146, 85, 255}, + {0, 146, 170, 255}, {0, 146, 255, 255}, {0, 182, 0, 255}, + {0, 182, 85, 255}, {0, 182, 170, 255}, {0, 182, 255, 255}, + {0, 219, 0, 255}, {0, 219, 85, 255}, {0, 219, 170, 255}, + {0, 219, 255, 255}, {0, 255, 0, 255}, {0, 255, 85, 255}, + {0, 255, 170, 255}, {0, 255, 255, 255}, {85, 0, 0, 255}, + {85, 0, 85, 255}, {85, 0, 170, 255}, {85, 0, 255, 255}, + {85, 36, 0, 255}, {85, 36, 85, 255}, {85, 36, 170, 255}, + {85, 36, 255, 255}, {85, 73, 0, 255}, {85, 73, 85, 255}, + {85, 73, 170, 255}, {85, 73, 255, 255}, {85, 109, 0, 255}, + {85, 109, 85, 255}, {85, 109, 170, 255}, {85, 109, 255, 255}, + {85, 146, 0, 255}, {85, 146, 85, 255}, {85, 146, 170, 255}, + {85, 146, 255, 255}, {85, 182, 0, 255}, {85, 182, 85, 255}, + {85, 182, 170, 255}, {85, 182, 255, 255}, {85, 219, 0, 255}, + {85, 219, 85, 255}, {85, 219, 170, 255}, {85, 219, 255, 255}, + {85, 255, 0, 255}, {85, 255, 85, 255}, {85, 255, 170, 255}, + {85, 255, 255, 255}, {170, 0, 0, 255}, {170, 0, 85, 255}, + {170, 0, 170, 255}, {170, 0, 255, 255}, {170, 36, 0, 255}, + {170, 36, 85, 255}, {170, 36, 170, 255}, {170, 36, 255, 255}, + {170, 73, 0, 255}, {170, 73, 85, 255}, {170, 73, 170, 255}, + {170, 73, 255, 255}, {170, 109, 0, 255}, {170, 109, 85, 255}, + {170, 109, 170, 255}, {170, 109, 255, 255}, {170, 146, 0, 255}, + {170, 146, 85, 255}, {170, 146, 170, 255}, {170, 146, 255, 255}, + {170, 182, 0, 255}, {170, 182, 85, 255}, {170, 182, 170, 255}, + {170, 182, 255, 255}, {170, 219, 0, 255}, {170, 219, 85, 255}, + {170, 219, 170, 255}, {170, 219, 255, 255}, {170, 255, 0, 255}, + {170, 255, 85, 255}, {170, 255, 170, 255}, {170, 255, 255, 255}, + {255, 0, 0, 255}, {255, 0, 85, 255}, {255, 0, 170, 255}, + {255, 0, 255, 255}, {255, 36, 0, 255}, {255, 36, 85, 255}, + {255, 36, 170, 255}, {255, 36, 255, 255}, {255, 73, 0, 255}, + {255, 73, 85, 255}, {255, 73, 170, 255}, {255, 73, 255, 255}, + {255, 109, 0, 255}, {255, 109, 85, 255}, {255, 109, 170, 255}, + {255, 109, 255, 255}, {255, 146, 0, 255}, {255, 146, 85, 255}, + {255, 146, 170, 255}, {255, 146, 255, 255}, {255, 182, 0, 255}, + {255, 182, 85, 255}, {255, 182, 170, 255}, {255, 182, 255, 255}, + {255, 219, 0, 255}, {255, 219, 85, 255}, {255, 219, 170, 255}, + {255, 219, 255, 255}, {255, 255, 0, 255}, {255, 255, 85, 255}, + {255, 255, 170, 255}, {255, 255, 255, 255}, {0, 0, 0, 255}, + {0, 0, 85, 255}, {0, 0, 170, 255}, {0, 0, 255, 255}, + {0, 36, 0, 255}, {0, 36, 85, 255}, {0, 36, 170, 255}, + {0, 36, 255, 255}, {0, 73, 0, 255}, {0, 73, 85, 255}, + {0, 73, 170, 255}, {0, 73, 255, 255}, {0, 109, 0, 255}, + {0, 109, 85, 255}, {0, 109, 170, 255}, {0, 109, 255, 255}, + {0, 146, 0, 255}, {0, 146, 85, 255}, {0, 146, 170, 255}, + {0, 146, 255, 255}, {0, 182, 0, 255}, {0, 182, 85, 255}, + {0, 182, 170, 255}, {0, 182, 255, 255}, {0, 219, 0, 255}, + {0, 219, 85, 255}, {0, 219, 170, 255}, {0, 219, 255, 255}, + {0, 255, 0, 255}, {0, 255, 85, 255}, {0, 255, 170, 255}, + {0, 255, 255, 255}, {85, 0, 0, 255}, {85, 0, 85, 255}, + {85, 0, 170, 255}, {85, 0, 255, 255}, {85, 36, 0, 255}, + {85, 36, 85, 255}, {85, 36, 170, 255}, {85, 36, 255, 255}, + {85, 73, 0, 255}, {85, 73, 85, 255}, {85, 73, 170, 255}, + {85, 73, 255, 255}, {85, 109, 0, 255}, {85, 109, 85, 255}, + {85, 109, 170, 255}, {85, 109, 255, 255}, {85, 146, 0, 255}, + {85, 146, 85, 255}, {85, 146, 170, 255}, {85, 146, 255, 255}, + {85, 182, 0, 255}, {85, 182, 85, 255}, {85, 182, 170, 255}, + {85, 182, 255, 255}, {85, 219, 0, 255}, {85, 219, 85, 255}, + {85, 219, 170, 255}, {85, 219, 255, 255}, {85, 255, 0, 255}, + {85, 255, 85, 255}, {85, 255, 170, 255}, {85, 255, 255, 255}, + {170, 0, 0, 255}, {170, 0, 85, 255}, {170, 0, 170, 255}, + {170, 0, 255, 255}, {170, 36, 0, 255}, {170, 36, 85, 255}, + {170, 36, 170, 255}, {170, 36, 255, 255}, {170, 73, 0, 255}, + {170, 73, 85, 255}, {170, 73, 170, 255}, {170, 73, 255, 255}, + {170, 109, 0, 255}, {170, 109, 85, 255}, {170, 109, 170, 255}, + {170, 109, 255, 255}, {170, 146, 0, 255}, {170, 146, 85, 255}, + {170, 146, 170, 255}, {170, 146, 255, 255}, {170, 182, 0, 255}, + {170, 182, 85, 255}, {170, 182, 170, 255}, {170, 182, 255, 255}, + {170, 219, 0, 255}, {170, 219, 85, 255}, {170, 219, 170, 255}, + {170, 219, 255, 255}, {170, 255, 0, 255}, {170, 255, 85, 255}, + {170, 255, 170, 255}, {170, 255, 255, 255}, {255, 0, 0, 255}, + {255, 0, 85, 255}, {255, 0, 170, 255}, {255, 0, 255, 255}, + {255, 36, 0, 255}, {255, 36, 85, 255}, {255, 36, 170, 255}, + {255, 36, 255, 255}, {255, 73, 0, 255}, {255, 73, 85, 255}, + {255, 73, 170, 255}, {255, 73, 255, 255}, {255, 109, 0, 255}, + {255, 109, 85, 255}, {255, 109, 170, 255}, {255, 109, 255, 255}, + {255, 146, 0, 255}, {255, 146, 85, 255}, {255, 146, 170, 255}, + {255, 146, 255, 255}, {255, 182, 0, 255}, {255, 182, 85, 255}, + {255, 182, 170, 255}, {255, 182, 255, 255}, {255, 219, 0, 255}, + {255, 219, 85, 255}, {255, 219, 170, 255}, {255, 219, 255, 255}, + {255, 255, 0, 255}, {255, 255, 85, 255}, {255, 255, 170, 255}, + {255, 255, 255, 255}}; + +static const int default_palette_size = + (int)(sizeof(default_palette_colors) / sizeof(SDL_Color)); + +#endif diff --git a/venv/Include/site/python3.9/pygame/pgarrinter.h b/venv/Include/site/python3.9/pygame/pgarrinter.h new file mode 100644 index 0000000..5ba096b --- /dev/null +++ b/venv/Include/site/python3.9/pygame/pgarrinter.h @@ -0,0 +1,26 @@ +/* array structure interface version 3 declarations */ + +#if !defined(PG_ARRAYINTER_HEADER) +#define PG_ARRAYINTER_HEADER + +static const int PAI_CONTIGUOUS = 0x01; +static const int PAI_FORTRAN = 0x02; +static const int PAI_ALIGNED = 0x100; +static const int PAI_NOTSWAPPED = 0x200; +static const int PAI_WRITEABLE = 0x400; +static const int PAI_ARR_HAS_DESCR = 0x800; + +typedef struct { + int two; /* contains the integer 2 -- simple sanity check */ + int nd; /* number of dimensions */ + char typekind; /* kind in array -- character code of typestr */ + int itemsize; /* size of each element */ + int flags; /* flags indicating how the data should be */ + /* interpreted */ + Py_intptr_t *shape; /* A length-nd array of shape information */ + Py_intptr_t *strides; /* A length-nd array of stride information */ + void *data; /* A pointer to the first element of the array */ + PyObject *descr; /* NULL or a data-description */ +} PyArrayInterface; + +#endif diff --git a/venv/Include/site/python3.9/pygame/pgbufferproxy.h b/venv/Include/site/python3.9/pygame/pgbufferproxy.h new file mode 100644 index 0000000..1507608 --- /dev/null +++ b/venv/Include/site/python3.9/pygame/pgbufferproxy.h @@ -0,0 +1,7 @@ +#ifndef PG_BUFPROXY_INTERNAL_H +#define PG_BUFPROXY_INTERNAL_H + +#include "include/pygame_bufferproxy.h" +#define PYGAMEAPI_BUFPROXY_NUMSLOTS 4 + +#endif /* ~PG_BUFPROXY_INTERNAL_H */ diff --git a/venv/Include/site/python3.9/pygame/pgcompat.h b/venv/Include/site/python3.9/pygame/pgcompat.h new file mode 100644 index 0000000..602043d --- /dev/null +++ b/venv/Include/site/python3.9/pygame/pgcompat.h @@ -0,0 +1,57 @@ +/* Python 2.x/3.x compatibility tools (internal) + */ +#ifndef PGCOMPAT_INTERNAL_H +#define PGCOMPAT_INTERNAL_H + +#include "include/pgcompat.h" + +/* Module init function returns new module instance. */ +#define MODINIT_DEFINE(mod_name) PyMODINIT_FUNC PyInit_##mod_name(void) + +/* Defaults for unicode file path encoding */ +#if defined(MS_WIN32) +#define UNICODE_DEF_FS_ERROR "replace" +#else +#define UNICODE_DEF_FS_ERROR "surrogateescape" +#endif + +#define RELATIVE_MODULE(m) ("." m) + +#ifndef Py_TPFLAGS_HAVE_NEWBUFFER +#define Py_TPFLAGS_HAVE_NEWBUFFER 0 +#endif + +#ifndef Py_TPFLAGS_HAVE_CLASS +#define Py_TPFLAGS_HAVE_CLASS 0 +#endif + +#ifndef Py_TPFLAGS_CHECKTYPES +#define Py_TPFLAGS_CHECKTYPES 0 +#endif + +#define Slice_GET_INDICES_EX(slice, length, start, stop, step, slicelength) \ + PySlice_GetIndicesEx(slice, length, start, stop, step, slicelength) + +#if defined(SDL_VERSION_ATLEAST) +#if !(SDL_VERSION_ATLEAST(2, 0, 5)) +/* These functions require SDL 2.0.5 or greater. + + https://wiki.libsdl.org/SDL_SetWindowResizable +*/ +void +SDL_SetWindowResizable(SDL_Window *window, SDL_bool resizable); +int +SDL_GetWindowOpacity(SDL_Window *window, float *opacity); +int +SDL_SetWindowOpacity(SDL_Window *window, float opacity); +int +SDL_SetWindowModalFor(SDL_Window *modal_window, SDL_Window *parent_window); +int +SDL_SetWindowInputFocus(SDL_Window *window); +SDL_Surface * +SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth, + Uint32 format); +#endif /* !(SDL_VERSION_ATLEAST(2, 0, 5)) */ +#endif /* defined(SDL_VERSION_ATLEAST) */ + +#endif /* ~PGCOMPAT_INTERNAL_H */ diff --git a/venv/Include/site/python3.9/pygame/pgopengl.h b/venv/Include/site/python3.9/pygame/pgopengl.h new file mode 100644 index 0000000..a845cbf --- /dev/null +++ b/venv/Include/site/python3.9/pygame/pgopengl.h @@ -0,0 +1,20 @@ +#if !defined(PGOPENGL_H) +#define PGOPENGL_H + +/** This header includes definitions of Opengl functions as pointer types for + ** use with the SDL function SDL_GL_GetProcAddress. + **/ + +#if defined(_WIN32) +#define GL_APIENTRY __stdcall +#else +#define GL_APIENTRY +#endif + +typedef void(GL_APIENTRY *GL_glReadPixels_Func)(int, int, int, int, + unsigned int, unsigned int, + void *); + +typedef void(GL_APIENTRY *GL_glViewport_Func)(int, int, unsigned int, + unsigned int); +#endif diff --git a/venv/Include/site/python3.9/pygame/pgplatform.h b/venv/Include/site/python3.9/pygame/pgplatform.h new file mode 100644 index 0000000..1c6c285 --- /dev/null +++ b/venv/Include/site/python3.9/pygame/pgplatform.h @@ -0,0 +1,39 @@ +/* platform/compiler adjustments (internal) */ +#ifndef PG_PLATFORM_INTERNAL_H +#define PG_PLATFORM_INTERNAL_H + +/* This must be before all else */ +#if defined(__SYMBIAN32__) && defined(OPENC) +#include +#if defined(__WINS__) +void * +_alloca(size_t size); +#define alloca _alloca +#endif /* __WINS__ */ +#endif /* defined(__SYMBIAN32__) && defined(OPENC) */ + +#include "include/pgplatform.h" + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif +#ifndef ABS +#define ABS(a) (((a) < 0) ? -(a) : (a)) +#endif + +#if defined(macintosh) && defined(__MWERKS__) || defined(__SYMBIAN32__) +#define PYGAME_EXPORT __declspec(export) +#else +#define PYGAME_EXPORT +#endif + +/* warnings */ +#define PG_STRINGIZE_HELPER(x) #x +#define PG_STRINGIZE(x) PG_STRINGIZE_HELPER(x) +#define PG_WARN(desc) \ + message(__FILE__ "(" PG_STRINGIZE(__LINE__) "): WARNING: " #desc) + +#endif /* ~PG_PLATFORM_INTERNAL_H */ diff --git a/venv/Include/site/python3.9/pygame/pygame.h b/venv/Include/site/python3.9/pygame/pygame.h new file mode 100644 index 0000000..d7eaf73 --- /dev/null +++ b/venv/Include/site/python3.9/pygame/pygame.h @@ -0,0 +1,32 @@ +/* + pygame - Python Game Library + Copyright (C) 2000-2001 Pete Shinners + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Pete Shinners + pete@shinners.org +*/ + +/* This will use PYGAMEAPI_DEFINE_SLOTS instead + * of PYGAMEAPI_EXTERN_SLOTS for base modules. + */ +#ifndef PYGAME_INTERNAL_H +#define PYGAME_INTERNAL_H + +#define PYGAME_H +#include "_pygame.h" + +#endif /* ~PYGAME_INTERNAL_H */ diff --git a/venv/Include/site/python3.9/pygame/scrap.h b/venv/Include/site/python3.9/pygame/scrap.h new file mode 100644 index 0000000..b3265a3 --- /dev/null +++ b/venv/Include/site/python3.9/pygame/scrap.h @@ -0,0 +1,147 @@ +/* + pygame - Python Game Library + Copyright (C) 2006, 2007 Rene Dudfield, Marcus von Appen + + Originally put in the public domain by Sam Lantinga. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef SCRAP_H +#define SCRAP_H + +/* This is unconditionally defined in Python.h */ +#if defined(_POSIX_C_SOURCE) +#undef _POSIX_C_SOURCE +#endif + +#include + +/* Handle clipboard text and data in arbitrary formats */ + +/** + * Predefined supported pygame scrap types. + */ +#define PYGAME_SCRAP_TEXT "text/plain" +#define PYGAME_SCRAP_BMP "image/bmp" +#define PYGAME_SCRAP_PPM "image/ppm" +#define PYGAME_SCRAP_PBM "image/pbm" + +/** + * The supported scrap clipboard types. + * + * This is only relevant in a X11 environment, which supports mouse + * selections as well. For Win32 and MacOS environments the default + * clipboard is used, no matter what value is passed. + */ +typedef enum { + SCRAP_CLIPBOARD, + SCRAP_SELECTION /* only supported in X11 environments. */ +} ScrapClipType; + +/** + * Macro for initialization checks. + */ +#define PYGAME_SCRAP_INIT_CHECK() \ + if (!pygame_scrap_initialized()) \ + return (PyErr_SetString(pgExc_SDLError, "scrap system not initialized."), \ + NULL) + +/** + * \brief Checks, whether the pygame scrap module was initialized. + * + * \return 1 if the modules was initialized, 0 otherwise. + */ +extern int +pygame_scrap_initialized(void); + +/** + * \brief Initializes the pygame scrap module internals. Call this before any + * other method. + * + * \return 1 on successful initialization, 0 otherwise. + */ +extern int +pygame_scrap_init(void); + +/** + * \brief Checks, whether the pygame window lost the clipboard focus or not. + * + * \return 1 if the window lost the focus, 0 otherwise. + */ +extern int +pygame_scrap_lost(void); + +/** + * \brief Places content of a specific type into the clipboard. + * + * \note For X11 the following notes are important: The following types + * are reserved for internal usage and thus will throw an error on + * setting them: "TIMESTAMP", "TARGETS", "SDL_SELECTION". + * Setting PYGAME_SCRAP_TEXT ("text/plain") will also automatically + * set the X11 types "STRING" (XA_STRING), "TEXT" and "UTF8_STRING". + * + * For Win32 the following notes are important: Setting + * PYGAME_SCRAP_TEXT ("text/plain") will also automatically set + * the Win32 type "TEXT" (CF_TEXT). + * + * For QNX the following notes are important: Setting + * PYGAME_SCRAP_TEXT ("text/plain") will also automatically set + * the QNX type "TEXT" (Ph_CL_TEXT). + * + * \param type The type of the content. + * \param srclen The length of the content. + * \param src The NULL terminated content. + * \return 1, if the content could be successfully pasted into the clipboard, + * 0 otherwise. + */ +extern int +pygame_scrap_put(char *type, int srclen, char *src); + +/** + * \brief Gets the current content from the clipboard. + * + * \note The received content does not need to be the content previously + * placed in the clipboard using pygame_put_scrap(). See the + * pygame_put_scrap() notes for more details. + * + * \param type The type of the content to receive. + * \param count The size of the returned content. + * \return The content or NULL in case of an error or if no content of the + * specified type was available. + */ +extern char * +pygame_scrap_get(char *type, unsigned long *count); + +/** + * \brief Gets the currently available content types from the clipboard. + * + * \return The different available content types or NULL in case of an + * error or if no content type is available. + */ +extern char ** +pygame_scrap_get_types(void); + +/** + * \brief Checks whether content for the specified scrap type is currently + * available in the clipboard. + * + * \param type The type to check for. + * \return 1, if there is content and 0 otherwise. + */ +extern int +pygame_scrap_contains(char *type); + +#endif /* SCRAP_H */ diff --git a/venv/Include/site/python3.9/pygame/surface.h b/venv/Include/site/python3.9/pygame/surface.h new file mode 100644 index 0000000..eb9bbed --- /dev/null +++ b/venv/Include/site/python3.9/pygame/surface.h @@ -0,0 +1,355 @@ +/* + pygame - Python Game Library + Copyright (C) 2000-2001 Pete Shinners + Copyright (C) 2007 Marcus von Appen + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Pete Shinners + pete@shinners.org +*/ + +#ifndef SURFACE_H +#define SURFACE_H + +/* This is defined in SDL.h */ +#if defined(_POSIX_C_SOURCE) +#undef _POSIX_C_SOURCE +#endif + +#include +#include "pygame.h" + +/* Blend modes */ +#define PYGAME_BLEND_ADD 0x1 +#define PYGAME_BLEND_SUB 0x2 +#define PYGAME_BLEND_MULT 0x3 +#define PYGAME_BLEND_MIN 0x4 +#define PYGAME_BLEND_MAX 0x5 + +#define PYGAME_BLEND_RGB_ADD 0x1 +#define PYGAME_BLEND_RGB_SUB 0x2 +#define PYGAME_BLEND_RGB_MULT 0x3 +#define PYGAME_BLEND_RGB_MIN 0x4 +#define PYGAME_BLEND_RGB_MAX 0x5 + +#define PYGAME_BLEND_RGBA_ADD 0x6 +#define PYGAME_BLEND_RGBA_SUB 0x7 +#define PYGAME_BLEND_RGBA_MULT 0x8 +#define PYGAME_BLEND_RGBA_MIN 0x9 +#define PYGAME_BLEND_RGBA_MAX 0x10 +#define PYGAME_BLEND_PREMULTIPLIED 0x11 +#define PYGAME_BLEND_ALPHA_SDL2 0x12 + +#if SDL_BYTEORDER == SDL_LIL_ENDIAN +#define GET_PIXEL_24(b) (b[0] + (b[1] << 8) + (b[2] << 16)) +#else +#define GET_PIXEL_24(b) (b[2] + (b[1] << 8) + (b[0] << 16)) +#endif + +#define GET_PIXEL(pxl, bpp, source) \ + switch (bpp) { \ + case 2: \ + pxl = *((Uint16 *)(source)); \ + break; \ + case 4: \ + pxl = *((Uint32 *)(source)); \ + break; \ + default: { \ + Uint8 *b = (Uint8 *)source; \ + pxl = GET_PIXEL_24(b); \ + } break; \ + } + +#define GET_PIXELVALS(_sR, _sG, _sB, _sA, px, fmt, ppa) \ + SDL_GetRGBA(px, fmt, &(_sR), &(_sG), &(_sB), &(_sA)); \ + if (!ppa) { \ + _sA = 255; \ + } + +#define GET_PIXELVALS_1(sr, sg, sb, sa, _src, _fmt) \ + sr = _fmt->palette->colors[*((Uint8 *)(_src))].r; \ + sg = _fmt->palette->colors[*((Uint8 *)(_src))].g; \ + sb = _fmt->palette->colors[*((Uint8 *)(_src))].b; \ + sa = 255; + +/* For 1 byte palette pixels */ +#define SET_PIXELVAL(px, fmt, _dR, _dG, _dB, _dA) \ + *(px) = (Uint8)SDL_MapRGBA(fmt, _dR, _dG, _dB, _dA) + +#if SDL_BYTEORDER == SDL_LIL_ENDIAN +#define SET_OFFSETS_24(or, og, ob, fmt) \ + { \ + or = (fmt->Rshift == 0 ? 0 : fmt->Rshift == 8 ? 1 : 2); \ + og = (fmt->Gshift == 0 ? 0 : fmt->Gshift == 8 ? 1 : 2); \ + ob = (fmt->Bshift == 0 ? 0 : fmt->Bshift == 8 ? 1 : 2); \ + } + +#define SET_OFFSETS_32(or, og, ob, fmt) \ + { \ + or = (fmt->Rshift == 0 ? 0 \ + : fmt->Rshift == 8 ? 1 \ + : fmt->Rshift == 16 ? 2 \ + : 3); \ + og = (fmt->Gshift == 0 ? 0 \ + : fmt->Gshift == 8 ? 1 \ + : fmt->Gshift == 16 ? 2 \ + : 3); \ + ob = (fmt->Bshift == 0 ? 0 \ + : fmt->Bshift == 8 ? 1 \ + : fmt->Bshift == 16 ? 2 \ + : 3); \ + } +#else +#define SET_OFFSETS_24(or, og, ob, fmt) \ + { \ + or = (fmt->Rshift == 0 ? 2 : fmt->Rshift == 8 ? 1 : 0); \ + og = (fmt->Gshift == 0 ? 2 : fmt->Gshift == 8 ? 1 : 0); \ + ob = (fmt->Bshift == 0 ? 2 : fmt->Bshift == 8 ? 1 : 0); \ + } + +#define SET_OFFSETS_32(or, og, ob, fmt) \ + { \ + or = (fmt->Rshift == 0 ? 3 \ + : fmt->Rshift == 8 ? 2 \ + : fmt->Rshift == 16 ? 1 \ + : 0); \ + og = (fmt->Gshift == 0 ? 3 \ + : fmt->Gshift == 8 ? 2 \ + : fmt->Gshift == 16 ? 1 \ + : 0); \ + ob = (fmt->Bshift == 0 ? 3 \ + : fmt->Bshift == 8 ? 2 \ + : fmt->Bshift == 16 ? 1 \ + : 0); \ + } +#endif + +#define CREATE_PIXEL(buf, r, g, b, a, bp, ft) \ + switch (bp) { \ + case 2: \ + *((Uint16 *)(buf)) = ((r >> ft->Rloss) << ft->Rshift) | \ + ((g >> ft->Gloss) << ft->Gshift) | \ + ((b >> ft->Bloss) << ft->Bshift) | \ + ((a >> ft->Aloss) << ft->Ashift); \ + break; \ + case 4: \ + *((Uint32 *)(buf)) = ((r >> ft->Rloss) << ft->Rshift) | \ + ((g >> ft->Gloss) << ft->Gshift) | \ + ((b >> ft->Bloss) << ft->Bshift) | \ + ((a >> ft->Aloss) << ft->Ashift); \ + break; \ + } + +/* Pretty good idea from Tom Duff :-). */ +#define LOOP_UNROLLED4(code, n, width) \ + n = (width + 3) / 4; \ + switch (width & 3) { \ + case 0: \ + do { \ + code; \ + case 3: \ + code; \ + case 2: \ + code; \ + case 1: \ + code; \ + } while (--n > 0); \ + } + +/* Used in the srcbpp == dstbpp == 1 blend functions */ +#define REPEAT_3(code) \ + code; \ + code; \ + code; + +#define REPEAT_4(code) \ + code; \ + code; \ + code; \ + code; + +#define BLEND_ADD(tmp, sR, sG, sB, sA, dR, dG, dB, dA) \ + tmp = dR + sR; \ + dR = (tmp <= 255 ? tmp : 255); \ + tmp = dG + sG; \ + dG = (tmp <= 255 ? tmp : 255); \ + tmp = dB + sB; \ + dB = (tmp <= 255 ? tmp : 255); + +#define BLEND_SUB(tmp, sR, sG, sB, sA, dR, dG, dB, dA) \ + tmp = dR - sR; \ + dR = (tmp >= 0 ? tmp : 0); \ + tmp = dG - sG; \ + dG = (tmp >= 0 ? tmp : 0); \ + tmp = dB - sB; \ + dB = (tmp >= 0 ? tmp : 0); + +#define BLEND_MULT(sR, sG, sB, sA, dR, dG, dB, dA) \ + dR = (dR && sR) ? (dR * sR) >> 8 : 0; \ + dG = (dG && sG) ? (dG * sG) >> 8 : 0; \ + dB = (dB && sB) ? (dB * sB) >> 8 : 0; + +#define BLEND_MIN(sR, sG, sB, sA, dR, dG, dB, dA) \ + if (sR < dR) { \ + dR = sR; \ + } \ + if (sG < dG) { \ + dG = sG; \ + } \ + if (sB < dB) { \ + dB = sB; \ + } + +#define BLEND_MAX(sR, sG, sB, sA, dR, dG, dB, dA) \ + if (sR > dR) { \ + dR = sR; \ + } \ + if (sG > dG) { \ + dG = sG; \ + } \ + if (sB > dB) { \ + dB = sB; \ + } + +#define BLEND_RGBA_ADD(tmp, sR, sG, sB, sA, dR, dG, dB, dA) \ + tmp = dR + sR; \ + dR = (tmp <= 255 ? tmp : 255); \ + tmp = dG + sG; \ + dG = (tmp <= 255 ? tmp : 255); \ + tmp = dB + sB; \ + dB = (tmp <= 255 ? tmp : 255); \ + tmp = dA + sA; \ + dA = (tmp <= 255 ? tmp : 255); + +#define BLEND_RGBA_SUB(tmp, sR, sG, sB, sA, dR, dG, dB, dA) \ + tmp = dR - sR; \ + dR = (tmp >= 0 ? tmp : 0); \ + tmp = dG - sG; \ + dG = (tmp >= 0 ? tmp : 0); \ + tmp = dB - sB; \ + dB = (tmp >= 0 ? tmp : 0); \ + tmp = dA - sA; \ + dA = (tmp >= 0 ? tmp : 0); + +#define BLEND_RGBA_MULT(sR, sG, sB, sA, dR, dG, dB, dA) \ + dR = (dR && sR) ? (dR * sR) >> 8 : 0; \ + dG = (dG && sG) ? (dG * sG) >> 8 : 0; \ + dB = (dB && sB) ? (dB * sB) >> 8 : 0; \ + dA = (dA && sA) ? (dA * sA) >> 8 : 0; + +#define BLEND_RGBA_MIN(sR, sG, sB, sA, dR, dG, dB, dA) \ + if (sR < dR) { \ + dR = sR; \ + } \ + if (sG < dG) { \ + dG = sG; \ + } \ + if (sB < dB) { \ + dB = sB; \ + } \ + if (sA < dA) { \ + dA = sA; \ + } + +#define BLEND_RGBA_MAX(sR, sG, sB, sA, dR, dG, dB, dA) \ + if (sR > dR) { \ + dR = sR; \ + } \ + if (sG > dG) { \ + dG = sG; \ + } \ + if (sB > dB) { \ + dB = sB; \ + } \ + if (sA > dA) { \ + dA = sA; \ + } + +#if 1 +/* Choose an alpha blend equation. If the sign is preserved on a right shift + * then use a specialized, faster, equation. Otherwise a more general form, + * where all additions are done before the shift, is needed. + */ +#if (-1 >> 1) < 0 +#define ALPHA_BLEND_COMP(sC, dC, sA) ((((sC - dC) * sA + sC) >> 8) + dC) +#else +#define ALPHA_BLEND_COMP(sC, dC, sA) (((dC << 8) + (sC - dC) * sA + sC) >> 8) +#endif + +#define ALPHA_BLEND(sR, sG, sB, sA, dR, dG, dB, dA) \ + do { \ + if (dA) { \ + dR = ALPHA_BLEND_COMP(sR, dR, sA); \ + dG = ALPHA_BLEND_COMP(sG, dG, sA); \ + dB = ALPHA_BLEND_COMP(sB, dB, sA); \ + dA = sA + dA - ((sA * dA) / 255); \ + } \ + else { \ + dR = sR; \ + dG = sG; \ + dB = sB; \ + dA = sA; \ + } \ + } while (0) + +#define ALPHA_BLEND_PREMULTIPLIED_COMP(sC, dC, sA) \ + (sC + dC - ((dC + 1) * sA >> 8)) + +#define ALPHA_BLEND_PREMULTIPLIED(tmp, sR, sG, sB, sA, dR, dG, dB, dA) \ + do { \ + dR = ALPHA_BLEND_PREMULTIPLIED_COMP(sR, dR, sA); \ + dG = ALPHA_BLEND_PREMULTIPLIED_COMP(sG, dG, sA); \ + dB = ALPHA_BLEND_PREMULTIPLIED_COMP(sB, dB, sA); \ + dA = ALPHA_BLEND_PREMULTIPLIED_COMP(sA, dA, sA); \ + } while (0) +#elif 0 + +#define ALPHA_BLEND(sR, sG, sB, sA, dR, dG, dB, dA) \ + do { \ + if (sA) { \ + if (dA && sA < 255) { \ + int dContrib = dA * (255 - sA) / 255; \ + dA = sA + dA - ((sA * dA) / 255); \ + dR = (dR * dContrib + sR * sA) / dA; \ + dG = (dG * dContrib + sG * sA) / dA; \ + dB = (dB * dContrib + sB * sA) / dA; \ + } \ + else { \ + dR = sR; \ + dG = sG; \ + dB = sB; \ + dA = sA; \ + } \ + } \ + } while (0) +#endif + +int +surface_fill_blend(SDL_Surface *surface, SDL_Rect *rect, Uint32 color, + int blendargs); + +void +surface_respect_clip_rect(SDL_Surface *surface, SDL_Rect *rect); + +int +pygame_AlphaBlit(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, + SDL_Rect *dstrect, int the_args); + +int +pygame_Blit(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, + SDL_Rect *dstrect, int the_args); + +#endif /* SURFACE_H */ diff --git a/venv/Lib/site-packages/_black_version.py b/venv/Lib/site-packages/_black_version.py new file mode 100644 index 0000000..8ac5331 --- /dev/null +++ b/venv/Lib/site-packages/_black_version.py @@ -0,0 +1 @@ +version = "20.8b1" diff --git a/venv/Lib/site-packages/appdirs-1.4.4.dist-info/INSTALLER b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/appdirs-1.4.4.dist-info/LICENSE.txt b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/LICENSE.txt new file mode 100644 index 0000000..107c614 --- /dev/null +++ b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/LICENSE.txt @@ -0,0 +1,23 @@ +# This is the MIT license + +Copyright (c) 2010 ActiveState Software Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/venv/Lib/site-packages/appdirs-1.4.4.dist-info/METADATA b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/METADATA new file mode 100644 index 0000000..f950731 --- /dev/null +++ b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/METADATA @@ -0,0 +1,264 @@ +Metadata-Version: 2.1 +Name: appdirs +Version: 1.4.4 +Summary: A small Python module for determining appropriate platform-specific dirs, e.g. a "user data dir". +Home-page: http://github.com/ActiveState/appdirs +Author: Trent Mick +Author-email: trentm@gmail.com +Maintainer: Jeff Rouse +Maintainer-email: jr@its.to +License: MIT +Keywords: application directory log cache user +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Topic :: Software Development :: Libraries :: Python Modules + + +.. image:: https://secure.travis-ci.org/ActiveState/appdirs.png + :target: http://travis-ci.org/ActiveState/appdirs + +the problem +=========== + +What directory should your app use for storing user data? If running on Mac OS X, you +should use:: + + ~/Library/Application Support/ + +If on Windows (at least English Win XP) that should be:: + + C:\Documents and Settings\\Application Data\Local Settings\\ + +or possibly:: + + C:\Documents and Settings\\Application Data\\ + +for `roaming profiles `_ but that is another story. + +On Linux (and other Unices) the dir, according to the `XDG +spec `_, is:: + + ~/.local/share/ + + +``appdirs`` to the rescue +========================= + +This kind of thing is what the ``appdirs`` module is for. ``appdirs`` will +help you choose an appropriate: + +- user data dir (``user_data_dir``) +- user config dir (``user_config_dir``) +- user cache dir (``user_cache_dir``) +- site data dir (``site_data_dir``) +- site config dir (``site_config_dir``) +- user log dir (``user_log_dir``) + +and also: + +- is a single module so other Python packages can include their own private copy +- is slightly opinionated on the directory names used. Look for "OPINION" in + documentation and code for when an opinion is being applied. + + +some example output +=================== + +On Mac OS X:: + + >>> from appdirs import * + >>> appname = "SuperApp" + >>> appauthor = "Acme" + >>> user_data_dir(appname, appauthor) + '/Users/trentm/Library/Application Support/SuperApp' + >>> site_data_dir(appname, appauthor) + '/Library/Application Support/SuperApp' + >>> user_cache_dir(appname, appauthor) + '/Users/trentm/Library/Caches/SuperApp' + >>> user_log_dir(appname, appauthor) + '/Users/trentm/Library/Logs/SuperApp' + +On Windows 7:: + + >>> from appdirs import * + >>> appname = "SuperApp" + >>> appauthor = "Acme" + >>> user_data_dir(appname, appauthor) + 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp' + >>> user_data_dir(appname, appauthor, roaming=True) + 'C:\\Users\\trentm\\AppData\\Roaming\\Acme\\SuperApp' + >>> user_cache_dir(appname, appauthor) + 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Cache' + >>> user_log_dir(appname, appauthor) + 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Logs' + +On Linux:: + + >>> from appdirs import * + >>> appname = "SuperApp" + >>> appauthor = "Acme" + >>> user_data_dir(appname, appauthor) + '/home/trentm/.local/share/SuperApp + >>> site_data_dir(appname, appauthor) + '/usr/local/share/SuperApp' + >>> site_data_dir(appname, appauthor, multipath=True) + '/usr/local/share/SuperApp:/usr/share/SuperApp' + >>> user_cache_dir(appname, appauthor) + '/home/trentm/.cache/SuperApp' + >>> user_log_dir(appname, appauthor) + '/home/trentm/.cache/SuperApp/log' + >>> user_config_dir(appname) + '/home/trentm/.config/SuperApp' + >>> site_config_dir(appname) + '/etc/xdg/SuperApp' + >>> os.environ['XDG_CONFIG_DIRS'] = '/etc:/usr/local/etc' + >>> site_config_dir(appname, multipath=True) + '/etc/SuperApp:/usr/local/etc/SuperApp' + + +``AppDirs`` for convenience +=========================== + +:: + + >>> from appdirs import AppDirs + >>> dirs = AppDirs("SuperApp", "Acme") + >>> dirs.user_data_dir + '/Users/trentm/Library/Application Support/SuperApp' + >>> dirs.site_data_dir + '/Library/Application Support/SuperApp' + >>> dirs.user_cache_dir + '/Users/trentm/Library/Caches/SuperApp' + >>> dirs.user_log_dir + '/Users/trentm/Library/Logs/SuperApp' + + + +Per-version isolation +===================== + +If you have multiple versions of your app in use that you want to be +able to run side-by-side, then you may want version-isolation for these +dirs:: + + >>> from appdirs import AppDirs + >>> dirs = AppDirs("SuperApp", "Acme", version="1.0") + >>> dirs.user_data_dir + '/Users/trentm/Library/Application Support/SuperApp/1.0' + >>> dirs.site_data_dir + '/Library/Application Support/SuperApp/1.0' + >>> dirs.user_cache_dir + '/Users/trentm/Library/Caches/SuperApp/1.0' + >>> dirs.user_log_dir + '/Users/trentm/Library/Logs/SuperApp/1.0' + + + +appdirs Changelog +================= + +appdirs 1.4.4 +------------- +- [PR #92] Don't import appdirs from setup.py + +Project officially classified as Stable which is important +for inclusion in other distros such as ActivePython. + +First of several incremental releases to catch up on maintenance. + +appdirs 1.4.3 +------------- +- [PR #76] Python 3.6 invalid escape sequence deprecation fixes +- Fix for Python 3.6 support + +appdirs 1.4.2 +------------- +- [PR #84] Allow installing without setuptools +- [PR #86] Fix string delimiters in setup.py description +- Add Python 3.6 support + +appdirs 1.4.1 +------------- +- [issue #38] Fix _winreg import on Windows Py3 +- [issue #55] Make appname optional + +appdirs 1.4.0 +------------- +- [PR #42] AppAuthor is now optional on Windows +- [issue 41] Support Jython on Windows, Mac, and Unix-like platforms. Windows + support requires `JNA `_. +- [PR #44] Fix incorrect behaviour of the site_config_dir method + +appdirs 1.3.0 +------------- +- [Unix, issue 16] Conform to XDG standard, instead of breaking it for + everybody +- [Unix] Removes gratuitous case mangling of the case, since \*nix-es are + usually case sensitive, so mangling is not wise +- [Unix] Fixes the utterly wrong behaviour in ``site_data_dir``, return result + based on XDG_DATA_DIRS and make room for respecting the standard which + specifies XDG_DATA_DIRS is a multiple-value variable +- [Issue 6] Add ``*_config_dir`` which are distinct on nix-es, according to + XDG specs; on Windows and Mac return the corresponding ``*_data_dir`` + +appdirs 1.2.0 +------------- + +- [Unix] Put ``user_log_dir`` under the *cache* dir on Unix. Seems to be more + typical. +- [issue 9] Make ``unicode`` work on py3k. + +appdirs 1.1.0 +------------- + +- [issue 4] Add ``AppDirs.user_log_dir``. +- [Unix, issue 2, issue 7] appdirs now conforms to `XDG base directory spec + `_. +- [Mac, issue 5] Fix ``site_data_dir()`` on Mac. +- [Mac] Drop use of 'Carbon' module in favour of hardcoded paths; supports + Python3 now. +- [Windows] Append "Cache" to ``user_cache_dir`` on Windows by default. Use + ``opinion=False`` option to disable this. +- Add ``appdirs.AppDirs`` convenience class. Usage: + + >>> dirs = AppDirs("SuperApp", "Acme", version="1.0") + >>> dirs.user_data_dir + '/Users/trentm/Library/Application Support/SuperApp/1.0' + +- [Windows] Cherry-pick Komodo's change to downgrade paths to the Windows short + paths if there are high bit chars. +- [Linux] Change default ``user_cache_dir()`` on Linux to be singular, e.g. + "~/.superapp/cache". +- [Windows] Add ``roaming`` option to ``user_data_dir()`` (for use on Windows only) + and change the default ``user_data_dir`` behaviour to use a *non*-roaming + profile dir (``CSIDL_LOCAL_APPDATA`` instead of ``CSIDL_APPDATA``). Why? Because + a large roaming profile can cause login speed issues. The "only syncs on + logout" behaviour can cause surprises in appdata info. + + +appdirs 1.0.1 (never released) +------------------------------ + +Started this changelog 27 July 2010. Before that this module originated in the +`Komodo `_ product as ``applib.py`` and then +as `applib/location.py +`_ (used by +`PyPM `_ in `ActivePython +`_). This is basically a fork of +applib.py 1.0.1 and applib/location.py 1.0.1. + + + diff --git a/venv/Lib/site-packages/appdirs-1.4.4.dist-info/RECORD b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/RECORD new file mode 100644 index 0000000..5adf271 --- /dev/null +++ b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/RECORD @@ -0,0 +1,8 @@ +__pycache__/appdirs.cpython-39.pyc,, +appdirs-1.4.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +appdirs-1.4.4.dist-info/LICENSE.txt,sha256=Nt200KdFqTqyAyA9cZCBSxuJcn0lTK_0jHp6-71HAAs,1097 +appdirs-1.4.4.dist-info/METADATA,sha256=k5TVfXMNKGHTfp2wm6EJKTuGwGNuoQR5TqQgH8iwG8M,8981 +appdirs-1.4.4.dist-info/RECORD,, +appdirs-1.4.4.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110 +appdirs-1.4.4.dist-info/top_level.txt,sha256=nKncE8CUqZERJ6VuQWL4_bkunSPDNfn7KZqb4Tr5YEM,8 +appdirs.py,sha256=g99s2sXhnvTEm79oj4bWI0Toapc-_SmKKNXvOXHkVic,24720 diff --git a/venv/Lib/site-packages/appdirs-1.4.4.dist-info/WHEEL b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/WHEEL new file mode 100644 index 0000000..ef99c6c --- /dev/null +++ b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/appdirs-1.4.4.dist-info/top_level.txt b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/top_level.txt new file mode 100644 index 0000000..d64bc32 --- /dev/null +++ b/venv/Lib/site-packages/appdirs-1.4.4.dist-info/top_level.txt @@ -0,0 +1 @@ +appdirs diff --git a/venv/Lib/site-packages/appdirs.py b/venv/Lib/site-packages/appdirs.py new file mode 100644 index 0000000..2acd1de --- /dev/null +++ b/venv/Lib/site-packages/appdirs.py @@ -0,0 +1,608 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (c) 2005-2010 ActiveState Software Inc. +# Copyright (c) 2013 Eddy Petrișor + +"""Utilities for determining application-specific dirs. + +See for details and usage. +""" +# Dev Notes: +# - MSDN on where to store app data files: +# http://support.microsoft.com/default.aspx?scid=kb;en-us;310294#XSLTH3194121123120121120120 +# - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html +# - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html + +__version__ = "1.4.4" +__version_info__ = tuple(int(segment) for segment in __version__.split(".")) + + +import sys +import os + +PY3 = sys.version_info[0] == 3 + +if PY3: + unicode = str + +if sys.platform.startswith('java'): + import platform + os_name = platform.java_ver()[3][0] + if os_name.startswith('Windows'): # "Windows XP", "Windows 7", etc. + system = 'win32' + elif os_name.startswith('Mac'): # "Mac OS X", etc. + system = 'darwin' + else: # "Linux", "SunOS", "FreeBSD", etc. + # Setting this to "linux2" is not ideal, but only Windows or Mac + # are actually checked for and the rest of the module expects + # *sys.platform* style strings. + system = 'linux2' +else: + system = sys.platform + + + +def user_data_dir(appname=None, appauthor=None, version=None, roaming=False): + r"""Return full path to the user-specific data dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "roaming" (boolean, default False) can be set True to use the Windows + roaming appdata directory. That means that for users on a Windows + network setup for roaming profiles, this user data will be + sync'd on login. See + + for a discussion of issues. + + Typical user data directories are: + Mac OS X: ~/Library/Application Support/ + Unix: ~/.local/share/ # or in $XDG_DATA_HOME, if defined + Win XP (not roaming): C:\Documents and Settings\\Application Data\\ + Win XP (roaming): C:\Documents and Settings\\Local Settings\Application Data\\ + Win 7 (not roaming): C:\Users\\AppData\Local\\ + Win 7 (roaming): C:\Users\\AppData\Roaming\\ + + For Unix, we follow the XDG spec and support $XDG_DATA_HOME. + That means, by default "~/.local/share/". + """ + if system == "win32": + if appauthor is None: + appauthor = appname + const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA" + path = os.path.normpath(_get_win_folder(const)) + if appname: + if appauthor is not False: + path = os.path.join(path, appauthor, appname) + else: + path = os.path.join(path, appname) + elif system == 'darwin': + path = os.path.expanduser('~/Library/Application Support/') + if appname: + path = os.path.join(path, appname) + else: + path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share")) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def site_data_dir(appname=None, appauthor=None, version=None, multipath=False): + r"""Return full path to the user-shared data dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "multipath" is an optional parameter only applicable to *nix + which indicates that the entire list of data dirs should be + returned. By default, the first item from XDG_DATA_DIRS is + returned, or '/usr/local/share/', + if XDG_DATA_DIRS is not set + + Typical site data directories are: + Mac OS X: /Library/Application Support/ + Unix: /usr/local/share/ or /usr/share/ + Win XP: C:\Documents and Settings\All Users\Application Data\\ + Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.) + Win 7: C:\ProgramData\\ # Hidden, but writeable on Win 7. + + For Unix, this is using the $XDG_DATA_DIRS[0] default. + + WARNING: Do not use this on Windows. See the Vista-Fail note above for why. + """ + if system == "win32": + if appauthor is None: + appauthor = appname + path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA")) + if appname: + if appauthor is not False: + path = os.path.join(path, appauthor, appname) + else: + path = os.path.join(path, appname) + elif system == 'darwin': + path = os.path.expanduser('/Library/Application Support') + if appname: + path = os.path.join(path, appname) + else: + # XDG default for $XDG_DATA_DIRS + # only first, if multipath is False + path = os.getenv('XDG_DATA_DIRS', + os.pathsep.join(['/usr/local/share', '/usr/share'])) + pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)] + if appname: + if version: + appname = os.path.join(appname, version) + pathlist = [os.sep.join([x, appname]) for x in pathlist] + + if multipath: + path = os.pathsep.join(pathlist) + else: + path = pathlist[0] + return path + + if appname and version: + path = os.path.join(path, version) + return path + + +def user_config_dir(appname=None, appauthor=None, version=None, roaming=False): + r"""Return full path to the user-specific config dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "roaming" (boolean, default False) can be set True to use the Windows + roaming appdata directory. That means that for users on a Windows + network setup for roaming profiles, this user data will be + sync'd on login. See + + for a discussion of issues. + + Typical user config directories are: + Mac OS X: same as user_data_dir + Unix: ~/.config/ # or in $XDG_CONFIG_HOME, if defined + Win *: same as user_data_dir + + For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME. + That means, by default "~/.config/". + """ + if system in ["win32", "darwin"]: + path = user_data_dir(appname, appauthor, None, roaming) + else: + path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.config")) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def site_config_dir(appname=None, appauthor=None, version=None, multipath=False): + r"""Return full path to the user-shared data dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "multipath" is an optional parameter only applicable to *nix + which indicates that the entire list of config dirs should be + returned. By default, the first item from XDG_CONFIG_DIRS is + returned, or '/etc/xdg/', if XDG_CONFIG_DIRS is not set + + Typical site config directories are: + Mac OS X: same as site_data_dir + Unix: /etc/xdg/ or $XDG_CONFIG_DIRS[i]/ for each value in + $XDG_CONFIG_DIRS + Win *: same as site_data_dir + Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.) + + For Unix, this is using the $XDG_CONFIG_DIRS[0] default, if multipath=False + + WARNING: Do not use this on Windows. See the Vista-Fail note above for why. + """ + if system in ["win32", "darwin"]: + path = site_data_dir(appname, appauthor) + if appname and version: + path = os.path.join(path, version) + else: + # XDG default for $XDG_CONFIG_DIRS + # only first, if multipath is False + path = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg') + pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)] + if appname: + if version: + appname = os.path.join(appname, version) + pathlist = [os.sep.join([x, appname]) for x in pathlist] + + if multipath: + path = os.pathsep.join(pathlist) + else: + path = pathlist[0] + return path + + +def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True): + r"""Return full path to the user-specific cache dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "opinion" (boolean) can be False to disable the appending of + "Cache" to the base app data dir for Windows. See + discussion below. + + Typical user cache directories are: + Mac OS X: ~/Library/Caches/ + Unix: ~/.cache/ (XDG default) + Win XP: C:\Documents and Settings\\Local Settings\Application Data\\\Cache + Vista: C:\Users\\AppData\Local\\\Cache + + On Windows the only suggestion in the MSDN docs is that local settings go in + the `CSIDL_LOCAL_APPDATA` directory. This is identical to the non-roaming + app data dir (the default returned by `user_data_dir` above). Apps typically + put cache data somewhere *under* the given dir here. Some examples: + ...\Mozilla\Firefox\Profiles\\Cache + ...\Acme\SuperApp\Cache\1.0 + OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value. + This can be disabled with the `opinion=False` option. + """ + if system == "win32": + if appauthor is None: + appauthor = appname + path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA")) + if appname: + if appauthor is not False: + path = os.path.join(path, appauthor, appname) + else: + path = os.path.join(path, appname) + if opinion: + path = os.path.join(path, "Cache") + elif system == 'darwin': + path = os.path.expanduser('~/Library/Caches') + if appname: + path = os.path.join(path, appname) + else: + path = os.getenv('XDG_CACHE_HOME', os.path.expanduser('~/.cache')) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def user_state_dir(appname=None, appauthor=None, version=None, roaming=False): + r"""Return full path to the user-specific state dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "roaming" (boolean, default False) can be set True to use the Windows + roaming appdata directory. That means that for users on a Windows + network setup for roaming profiles, this user data will be + sync'd on login. See + + for a discussion of issues. + + Typical user state directories are: + Mac OS X: same as user_data_dir + Unix: ~/.local/state/ # or in $XDG_STATE_HOME, if defined + Win *: same as user_data_dir + + For Unix, we follow this Debian proposal + to extend the XDG spec and support $XDG_STATE_HOME. + + That means, by default "~/.local/state/". + """ + if system in ["win32", "darwin"]: + path = user_data_dir(appname, appauthor, None, roaming) + else: + path = os.getenv('XDG_STATE_HOME', os.path.expanduser("~/.local/state")) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def user_log_dir(appname=None, appauthor=None, version=None, opinion=True): + r"""Return full path to the user-specific log dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "opinion" (boolean) can be False to disable the appending of + "Logs" to the base app data dir for Windows, and "log" to the + base cache dir for Unix. See discussion below. + + Typical user log directories are: + Mac OS X: ~/Library/Logs/ + Unix: ~/.cache//log # or under $XDG_CACHE_HOME if defined + Win XP: C:\Documents and Settings\\Local Settings\Application Data\\\Logs + Vista: C:\Users\\AppData\Local\\\Logs + + On Windows the only suggestion in the MSDN docs is that local settings + go in the `CSIDL_LOCAL_APPDATA` directory. (Note: I'm interested in + examples of what some windows apps use for a logs dir.) + + OPINION: This function appends "Logs" to the `CSIDL_LOCAL_APPDATA` + value for Windows and appends "log" to the user cache dir for Unix. + This can be disabled with the `opinion=False` option. + """ + if system == "darwin": + path = os.path.join( + os.path.expanduser('~/Library/Logs'), + appname) + elif system == "win32": + path = user_data_dir(appname, appauthor, version) + version = False + if opinion: + path = os.path.join(path, "Logs") + else: + path = user_cache_dir(appname, appauthor, version) + version = False + if opinion: + path = os.path.join(path, "log") + if appname and version: + path = os.path.join(path, version) + return path + + +class AppDirs(object): + """Convenience wrapper for getting application dirs.""" + def __init__(self, appname=None, appauthor=None, version=None, + roaming=False, multipath=False): + self.appname = appname + self.appauthor = appauthor + self.version = version + self.roaming = roaming + self.multipath = multipath + + @property + def user_data_dir(self): + return user_data_dir(self.appname, self.appauthor, + version=self.version, roaming=self.roaming) + + @property + def site_data_dir(self): + return site_data_dir(self.appname, self.appauthor, + version=self.version, multipath=self.multipath) + + @property + def user_config_dir(self): + return user_config_dir(self.appname, self.appauthor, + version=self.version, roaming=self.roaming) + + @property + def site_config_dir(self): + return site_config_dir(self.appname, self.appauthor, + version=self.version, multipath=self.multipath) + + @property + def user_cache_dir(self): + return user_cache_dir(self.appname, self.appauthor, + version=self.version) + + @property + def user_state_dir(self): + return user_state_dir(self.appname, self.appauthor, + version=self.version) + + @property + def user_log_dir(self): + return user_log_dir(self.appname, self.appauthor, + version=self.version) + + +#---- internal support stuff + +def _get_win_folder_from_registry(csidl_name): + """This is a fallback technique at best. I'm not sure if using the + registry for this guarantees us the correct answer for all CSIDL_* + names. + """ + if PY3: + import winreg as _winreg + else: + import _winreg + + shell_folder_name = { + "CSIDL_APPDATA": "AppData", + "CSIDL_COMMON_APPDATA": "Common AppData", + "CSIDL_LOCAL_APPDATA": "Local AppData", + }[csidl_name] + + key = _winreg.OpenKey( + _winreg.HKEY_CURRENT_USER, + r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" + ) + dir, type = _winreg.QueryValueEx(key, shell_folder_name) + return dir + + +def _get_win_folder_with_pywin32(csidl_name): + from win32com.shell import shellcon, shell + dir = shell.SHGetFolderPath(0, getattr(shellcon, csidl_name), 0, 0) + # Try to make this a unicode path because SHGetFolderPath does + # not return unicode strings when there is unicode data in the + # path. + try: + dir = unicode(dir) + + # Downgrade to short path name if have highbit chars. See + # . + has_high_char = False + for c in dir: + if ord(c) > 255: + has_high_char = True + break + if has_high_char: + try: + import win32api + dir = win32api.GetShortPathName(dir) + except ImportError: + pass + except UnicodeError: + pass + return dir + + +def _get_win_folder_with_ctypes(csidl_name): + import ctypes + + csidl_const = { + "CSIDL_APPDATA": 26, + "CSIDL_COMMON_APPDATA": 35, + "CSIDL_LOCAL_APPDATA": 28, + }[csidl_name] + + buf = ctypes.create_unicode_buffer(1024) + ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf) + + # Downgrade to short path name if have highbit chars. See + # . + has_high_char = False + for c in buf: + if ord(c) > 255: + has_high_char = True + break + if has_high_char: + buf2 = ctypes.create_unicode_buffer(1024) + if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024): + buf = buf2 + + return buf.value + +def _get_win_folder_with_jna(csidl_name): + import array + from com.sun import jna + from com.sun.jna.platform import win32 + + buf_size = win32.WinDef.MAX_PATH * 2 + buf = array.zeros('c', buf_size) + shell = win32.Shell32.INSTANCE + shell.SHGetFolderPath(None, getattr(win32.ShlObj, csidl_name), None, win32.ShlObj.SHGFP_TYPE_CURRENT, buf) + dir = jna.Native.toString(buf.tostring()).rstrip("\0") + + # Downgrade to short path name if have highbit chars. See + # . + has_high_char = False + for c in dir: + if ord(c) > 255: + has_high_char = True + break + if has_high_char: + buf = array.zeros('c', buf_size) + kernel = win32.Kernel32.INSTANCE + if kernel.GetShortPathName(dir, buf, buf_size): + dir = jna.Native.toString(buf.tostring()).rstrip("\0") + + return dir + +if system == "win32": + try: + import win32com.shell + _get_win_folder = _get_win_folder_with_pywin32 + except ImportError: + try: + from ctypes import windll + _get_win_folder = _get_win_folder_with_ctypes + except ImportError: + try: + import com.sun.jna + _get_win_folder = _get_win_folder_with_jna + except ImportError: + _get_win_folder = _get_win_folder_from_registry + + +#---- self test code + +if __name__ == "__main__": + appname = "MyApp" + appauthor = "MyCompany" + + props = ("user_data_dir", + "user_config_dir", + "user_cache_dir", + "user_state_dir", + "user_log_dir", + "site_data_dir", + "site_config_dir") + + print("-- app dirs %s --" % __version__) + + print("-- app dirs (with optional 'version')") + dirs = AppDirs(appname, appauthor, version="1.0") + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) + + print("\n-- app dirs (without optional 'version')") + dirs = AppDirs(appname, appauthor) + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) + + print("\n-- app dirs (without optional 'appauthor')") + dirs = AppDirs(appname) + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) + + print("\n-- app dirs (with disabled 'appauthor')") + dirs = AppDirs(appname, appauthor=False) + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) diff --git a/venv/Lib/site-packages/astroid-2.5.dist-info/COPYING b/venv/Lib/site-packages/astroid-2.5.dist-info/COPYING new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/venv/Lib/site-packages/astroid-2.5.dist-info/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/venv/Lib/site-packages/astroid-2.5.dist-info/COPYING.LESSER b/venv/Lib/site-packages/astroid-2.5.dist-info/COPYING.LESSER new file mode 100644 index 0000000..2d2d780 --- /dev/null +++ b/venv/Lib/site-packages/astroid-2.5.dist-info/COPYING.LESSER @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/venv/Lib/site-packages/astroid-2.5.dist-info/INSTALLER b/venv/Lib/site-packages/astroid-2.5.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/astroid-2.5.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/astroid-2.5.dist-info/METADATA b/venv/Lib/site-packages/astroid-2.5.dist-info/METADATA new file mode 100644 index 0000000..cd81d8d --- /dev/null +++ b/venv/Lib/site-packages/astroid-2.5.dist-info/METADATA @@ -0,0 +1,118 @@ +Metadata-Version: 2.1 +Name: astroid +Version: 2.5 +Summary: An abstract syntax tree for Python with inference support. +Home-page: https://github.com/PyCQA/astroid +Author: Python Code Quality Authority +Author-email: code-quality@python.org +License: LGPL +Platform: UNKNOWN +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Software Development :: Quality Assurance +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Requires-Python: >=3.6 +Requires-Dist: lazy-object-proxy (>=1.4.0) +Requires-Dist: wrapt (<1.13,>=1.11) +Requires-Dist: typed-ast (<1.5,>=1.4.0) ; implementation_name == "cpython" and python_version < "3.8" + +Astroid +======= + +.. image:: https://travis-ci.org/PyCQA/astroid.svg?branch=master + :target: https://travis-ci.org/PyCQA/astroid + +.. image:: https://ci.appveyor.com/api/projects/status/co3u42kunguhbh6l/branch/master?svg=true + :alt: AppVeyor Build Status + :target: https://ci.appveyor.com/project/PCManticore/astroid + +.. image:: https://coveralls.io/repos/github/PyCQA/astroid/badge.svg?branch=master + :target: https://coveralls.io/github/PyCQA/astroid?branch=master + +.. image:: https://readthedocs.org/projects/astroid/badge/?version=latest + :target: http://astroid.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status + +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/ambv/black + +.. |tideliftlogo| image:: doc/media/Tidelift_Logos_RGB_Tidelift_Shorthand_On-White_small.png + :width: 75 + :height: 60 + :alt: Tidelift + +.. list-table:: + :widths: 10 100 + + * - |tideliftlogo| + - Professional support for astroid is available as part of the `Tidelift + Subscription`_. Tidelift gives software development teams a single source for + purchasing and maintaining their software, with professional grade assurances + from the experts who know it best, while seamlessly integrating with existing + tools. + +.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-astroid?utm_source=pypi-astroid&utm_medium=referral&utm_campaign=readme + + + +What's this? +------------ + +The aim of this module is to provide a common base representation of +python source code. It is currently the library powering pylint's capabilities. + +It provides a compatible representation which comes from the `_ast` +module. It rebuilds the tree generated by the builtin _ast module by +recursively walking down the AST and building an extended ast. The new +node classes have additional methods and attributes for different +usages. They include some support for static inference and local name +scopes. Furthermore, astroid can also build partial trees by inspecting living +objects. + + +Installation +------------ + +Extract the tarball, jump into the created directory and run:: + + pip install . + + +If you want to do an editable installation, you can run:: + + pip install -e . + + +If you have any questions, please mail the code-quality@python.org +mailing list for support. See +http://mail.python.org/mailman/listinfo/code-quality for subscription +information and archives. + +Documentation +------------- +http://astroid.readthedocs.io/en/latest/ + + +Python Versions +--------------- + +astroid 2.0 is currently available for Python 3 only. If you want Python 2 +support, use an older version of astroid (though note that these versions +are no longer supported). + +Test +---- + +Tests are in the 'test' subdirectory. To launch the whole tests suite, you can use +either `tox` or `pytest`:: + + tox + pytest astroid + + diff --git a/venv/Lib/site-packages/astroid-2.5.dist-info/RECORD b/venv/Lib/site-packages/astroid-2.5.dist-info/RECORD new file mode 100644 index 0000000..8be30ad --- /dev/null +++ b/venv/Lib/site-packages/astroid-2.5.dist-info/RECORD @@ -0,0 +1,157 @@ +astroid-2.5.dist-info/COPYING,sha256=qxX9UmvY3Rip5368E5ZWv00z6X_HI4zRG_YOK5uGZsY,17987 +astroid-2.5.dist-info/COPYING.LESSER,sha256=qb3eVhbs3R6YC0TzYGAO6Hg7H5m4zIOivrFjoKOQ6GE,26527 +astroid-2.5.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +astroid-2.5.dist-info/METADATA,sha256=GW3UL-XpUgfhKPM6Y8JM4kyCiatY2fXHy-8_QmIbhrg,3923 +astroid-2.5.dist-info/RECORD,, +astroid-2.5.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92 +astroid-2.5.dist-info/top_level.txt,sha256=HsdW4O2x7ZXRj6k-agi3RaQybGLobI3VSE-jt4vQUXM,8 +astroid/__init__.py,sha256=9te_uMnyht3uK05VIPFt6NmWrtA_uV96uLF2pDA03kw,5720 +astroid/__pkginfo__.py,sha256=I-omqBsGWLDJDfOQbwaNBOvEhK5DweSGyBp04kGgNTY,2557 +astroid/__pycache__/__init__.cpython-39.pyc,, +astroid/__pycache__/__pkginfo__.cpython-39.pyc,, +astroid/__pycache__/_ast.cpython-39.pyc,, +astroid/__pycache__/arguments.cpython-39.pyc,, +astroid/__pycache__/as_string.cpython-39.pyc,, +astroid/__pycache__/bases.cpython-39.pyc,, +astroid/__pycache__/builder.cpython-39.pyc,, +astroid/__pycache__/context.cpython-39.pyc,, +astroid/__pycache__/decorators.cpython-39.pyc,, +astroid/__pycache__/exceptions.cpython-39.pyc,, +astroid/__pycache__/helpers.cpython-39.pyc,, +astroid/__pycache__/inference.cpython-39.pyc,, +astroid/__pycache__/manager.cpython-39.pyc,, +astroid/__pycache__/mixins.cpython-39.pyc,, +astroid/__pycache__/modutils.cpython-39.pyc,, +astroid/__pycache__/node_classes.cpython-39.pyc,, +astroid/__pycache__/nodes.cpython-39.pyc,, +astroid/__pycache__/objects.cpython-39.pyc,, +astroid/__pycache__/protocols.cpython-39.pyc,, +astroid/__pycache__/raw_building.cpython-39.pyc,, +astroid/__pycache__/rebuilder.cpython-39.pyc,, +astroid/__pycache__/scoped_nodes.cpython-39.pyc,, +astroid/__pycache__/test_utils.cpython-39.pyc,, +astroid/__pycache__/transforms.cpython-39.pyc,, +astroid/__pycache__/util.cpython-39.pyc,, +astroid/_ast.py,sha256=n1U2HblBNrMhsmrjF84HUfIgEZ3PyHyiJJOrOkgiUFk,3385 +astroid/arguments.py,sha256=pD-SweKT4voiJUSnOJz2BG1PEpyzWhhWgZvsXTxxLx4,12647 +astroid/as_string.py,sha256=8bOZWsGG79TLmlzRzPtmHdanIAqQUFTKiYH873iMhOw,22821 +astroid/bases.py,sha256=wL9C23mHFaj7vhMqM83DdsU6kfP488aEjoFWaO8p6Cg,19175 +astroid/brain/__pycache__/brain_argparse.cpython-39.pyc,, +astroid/brain/__pycache__/brain_attrs.cpython-39.pyc,, +astroid/brain/__pycache__/brain_boto3.cpython-39.pyc,, +astroid/brain/__pycache__/brain_builtin_inference.cpython-39.pyc,, +astroid/brain/__pycache__/brain_collections.cpython-39.pyc,, +astroid/brain/__pycache__/brain_crypt.cpython-39.pyc,, +astroid/brain/__pycache__/brain_curses.cpython-39.pyc,, +astroid/brain/__pycache__/brain_dataclasses.cpython-39.pyc,, +astroid/brain/__pycache__/brain_dateutil.cpython-39.pyc,, +astroid/brain/__pycache__/brain_fstrings.cpython-39.pyc,, +astroid/brain/__pycache__/brain_functools.cpython-39.pyc,, +astroid/brain/__pycache__/brain_gi.cpython-39.pyc,, +astroid/brain/__pycache__/brain_hashlib.cpython-39.pyc,, +astroid/brain/__pycache__/brain_http.cpython-39.pyc,, +astroid/brain/__pycache__/brain_hypothesis.cpython-39.pyc,, +astroid/brain/__pycache__/brain_io.cpython-39.pyc,, +astroid/brain/__pycache__/brain_mechanize.cpython-39.pyc,, +astroid/brain/__pycache__/brain_multiprocessing.cpython-39.pyc,, +astroid/brain/__pycache__/brain_namedtuple_enum.cpython-39.pyc,, +astroid/brain/__pycache__/brain_nose.cpython-39.pyc,, +astroid/brain/__pycache__/brain_numpy_core_fromnumeric.cpython-39.pyc,, +astroid/brain/__pycache__/brain_numpy_core_function_base.cpython-39.pyc,, +astroid/brain/__pycache__/brain_numpy_core_multiarray.cpython-39.pyc,, +astroid/brain/__pycache__/brain_numpy_core_numeric.cpython-39.pyc,, +astroid/brain/__pycache__/brain_numpy_core_numerictypes.cpython-39.pyc,, +astroid/brain/__pycache__/brain_numpy_core_umath.cpython-39.pyc,, +astroid/brain/__pycache__/brain_numpy_ndarray.cpython-39.pyc,, +astroid/brain/__pycache__/brain_numpy_random_mtrand.cpython-39.pyc,, +astroid/brain/__pycache__/brain_numpy_utils.cpython-39.pyc,, +astroid/brain/__pycache__/brain_pkg_resources.cpython-39.pyc,, +astroid/brain/__pycache__/brain_pytest.cpython-39.pyc,, +astroid/brain/__pycache__/brain_qt.cpython-39.pyc,, +astroid/brain/__pycache__/brain_random.cpython-39.pyc,, +astroid/brain/__pycache__/brain_re.cpython-39.pyc,, +astroid/brain/__pycache__/brain_responses.cpython-39.pyc,, +astroid/brain/__pycache__/brain_scipy_signal.cpython-39.pyc,, +astroid/brain/__pycache__/brain_six.cpython-39.pyc,, +astroid/brain/__pycache__/brain_sqlalchemy.cpython-39.pyc,, +astroid/brain/__pycache__/brain_ssl.cpython-39.pyc,, +astroid/brain/__pycache__/brain_subprocess.cpython-39.pyc,, +astroid/brain/__pycache__/brain_threading.cpython-39.pyc,, +astroid/brain/__pycache__/brain_type.cpython-39.pyc,, +astroid/brain/__pycache__/brain_typing.cpython-39.pyc,, +astroid/brain/__pycache__/brain_uuid.cpython-39.pyc,, +astroid/brain/brain_argparse.py,sha256=5XqcThekktCIWRlWAMs-R47wkbsOUSnQlsEbLEnRpsY,1041 +astroid/brain/brain_attrs.py,sha256=k8zJqIXsIbQrncthrzyB5NtdPTktgVi9wG7nyl8xMzs,2208 +astroid/brain/brain_boto3.py,sha256=nE8Cw_S_Gp___IszRDRkhEGS6WGrKcF_gTOs3GVxH9k,862 +astroid/brain/brain_builtin_inference.py,sha256=E4Fc8Z7b2Q0-SO1lcTzT-KNwb_sL_OyLHz1jGkaaDaw,30014 +astroid/brain/brain_collections.py,sha256=4F0XwtQsSAJTOfBUc6MDhcVA_I5kPgx8b56PGoYo6Wg,2947 +astroid/brain/brain_crypt.py,sha256=gA7Q4GVuAM4viuTGWM6SNTPQXv5Gr_mFapyKMTRcsJ0,875 +astroid/brain/brain_curses.py,sha256=tDnlCP1bEvleqCMz856yua9mM5um1p_JendFhT4rBFk,3303 +astroid/brain/brain_dataclasses.py,sha256=5WndOYSY0oi2v-Od6KdPte-FKt00LoNRH2riSB4S1os,1647 +astroid/brain/brain_dateutil.py,sha256=HlqfFY6a2Lb-bATMBRkmE-22Yolw2XOFQ1o3R2vnCI0,866 +astroid/brain/brain_fstrings.py,sha256=7lsCbeAU0X5ygEIoA5gBlMQXli7bNX5Uj5ktu0Ar3ME,2268 +astroid/brain/brain_functools.py,sha256=fMr0TgjC4Er_6bckRGI3racueIUO9v0eqYuWK88RBbA,5587 +astroid/brain/brain_gi.py,sha256=pubq_OzIyv7WknT_nllxD-1tJ0l7gIm--ywHjKeLL3U,7619 +astroid/brain/brain_hashlib.py,sha256=H_4audmA4XUdORbJtqnHcfWaqrj6EhHYzW6V8Sd8V5U,2328 +astroid/brain/brain_http.py,sha256=AtkQlpS-Bkc2ZnpCKK0Wn1a8UIz4IRitTYhE2PS-gfg,10583 +astroid/brain/brain_hypothesis.py,sha256=QMm6vuRlND5VIDVDOYm3ihLe_p-r7sXLiYMO1d2mOPA,1586 +astroid/brain/brain_io.py,sha256=49BpoqShTZ7HItrm0S5uHXJS_Ub5-OIHkPggDtIz5nc,1541 +astroid/brain/brain_mechanize.py,sha256=XDadcIFAEHyn3WtJ60k0PmpyVSJsIYNOes-zycCJFcE,2753 +astroid/brain/brain_multiprocessing.py,sha256=WpOLPq78BL95dfr16Dg5oLdX_HogmgY7bjEzcWJpxrM,3211 +astroid/brain/brain_namedtuple_enum.py,sha256=2i755pfXXXXuHcrUar8j4xty-6peFUOSjfoMIie10gk,16811 +astroid/brain/brain_nose.py,sha256=x3H9APRnK31dYGuKepApw6lr96Ud4PqC_E7q9RB9uCc,2282 +astroid/brain/brain_numpy_core_fromnumeric.py,sha256=Fu69SbUg_kgRgHkYP-FACOiYdtTZXOSG9qXuCbYijdc,684 +astroid/brain/brain_numpy_core_function_base.py,sha256=9wPN1ZLc7u6fb1dhsEe_m_p2nKxLtjvuGzvbnE2xMic,1231 +astroid/brain/brain_numpy_core_multiarray.py,sha256=AnOwZO63voE6ocNTKqvJQjzB_7i1VZ9zbCqfc4fgOiY,4073 +astroid/brain/brain_numpy_core_numeric.py,sha256=qbOZkvJovzrNQj39pAw4IGrC2zPtaa3WXhEbbpXuSjQ,1447 +astroid/brain/brain_numpy_core_numerictypes.py,sha256=98Vn-XRG7yQD4cB576yE1SDUC-uasn-tJHRcHEbga1c,8261 +astroid/brain/brain_numpy_core_umath.py,sha256=2TncpzZpdLqUSf52nr0iftt41_0eM0Yng2F0e1BHlsA,4845 +astroid/brain/brain_numpy_ndarray.py,sha256=T3ryDRCdQOkRyeR14ndX0nyBdIUmSyONcGCKQCIbZcc,8663 +astroid/brain/brain_numpy_random_mtrand.py,sha256=OxiHH53jt1iWHcDwTNh9FIY45mZcwvHZtx7EHVZO34w,3387 +astroid/brain/brain_numpy_utils.py,sha256=jRsY0zM79hkgHUTF_YNai7cjA9-L61p9UHuGdk83Dwo,1880 +astroid/brain/brain_pkg_resources.py,sha256=S_5UED1Zg8ObEJumRdpYGnjxZzemh_G_NFj3p5NGPfc,2262 +astroid/brain/brain_pytest.py,sha256=Eqyvo3nVaH1Y9ex5AxYuGTGgcJmDP-QyC4bQB7wFQJM,2455 +astroid/brain/brain_qt.py,sha256=aezJA3x-tlMZQtYY6NTXteFRrVvj1-So_kyW_6y1i8A,2601 +astroid/brain/brain_random.py,sha256=BCkFRJiQ7XzKCKf1Y18jyiDs1By3Vv2iTsQ0Bv0ZPFQ,2448 +astroid/brain/brain_re.py,sha256=le7VJHUAf80HyE_aQCh7_8FyDVK6JwNWA--c9RaMVQ8,1128 +astroid/brain/brain_responses.py,sha256=GIAGkwMEGEZ9bJHI9uBGs_UmUy3DRBtjI_j_8dLBVsc,1534 +astroid/brain/brain_scipy_signal.py,sha256=9dBElFU0jZoxGAWH2mmLMECYh3cQ9IGh6iyWbs5FZR0,2372 +astroid/brain/brain_six.py,sha256=64kQm4CPlTXZR5P0rZiu5QRW8BlWxVQKRNiDkVjI7jc,7711 +astroid/brain/brain_sqlalchemy.py,sha256=HUZukREsO7rShdkPHEc7VHzMaeU6sGsdT8Mv2SC29Ig,680 +astroid/brain/brain_ssl.py,sha256=hA2ROZD0kRoVRz0DT92PeMYrpsiuJpD1ttNPXh7u2S0,3787 +astroid/brain/brain_subprocess.py,sha256=DfsCzHrgDeMhOty_crDc40v8VT5JRlU_ADNWBmrf_8s,5286 +astroid/brain/brain_threading.py,sha256=topLWdF3MHxqfUN9M8YBkMw0m-Sqe6zWxj5j5n9jiNk,896 +astroid/brain/brain_type.py,sha256=0VcOfVnPJZO3DtnQbqciebkIM4V1_UE9qYjazxiRCUE,1966 +astroid/brain/brain_typing.py,sha256=iFw33beNCitCJjJNvccIY6SsFJcdKVDdl-56DxDioh0,2780 +astroid/brain/brain_uuid.py,sha256=4tmJ7CWciQsbzUgvVDyKfBhVJfrCppzr0DmqWUco8RI,634 +astroid/builder.py,sha256=7xAEVBfM5zwn4Dl4m_OKbQLipmuksqY-Dnxt5cR2_LI,16950 +astroid/context.py,sha256=kUp9xS79VtCf9mrsqLl4MPvSY9wmLmJrnpWMB1iYTa4,5095 +astroid/decorators.py,sha256=pt1fXaFiINfw7AgiuwqDJ-BobnekP77sHJdHS95mNys,4419 +astroid/exceptions.py,sha256=Bc0ji7NYg_jR4J_jAcsEKJxtDO1YrofxCoaeRp_U3dE,6956 +astroid/helpers.py,sha256=uU3DSRjyyavoa5q0QZwSv0dgiraiU-N_pOYb_uIMZLQ,10418 +astroid/inference.py,sha256=UiKKPRYqb5JINQIw1lSdBniHhXjCohCGAqycp2GkVI4,34686 +astroid/interpreter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +astroid/interpreter/__pycache__/__init__.cpython-39.pyc,, +astroid/interpreter/__pycache__/dunder_lookup.cpython-39.pyc,, +astroid/interpreter/__pycache__/objectmodel.cpython-39.pyc,, +astroid/interpreter/_import/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +astroid/interpreter/_import/__pycache__/__init__.cpython-39.pyc,, +astroid/interpreter/_import/__pycache__/spec.cpython-39.pyc,, +astroid/interpreter/_import/__pycache__/util.cpython-39.pyc,, +astroid/interpreter/_import/spec.py,sha256=oexwj1UFUevwvp5GzaA8mcWMqguQHqXD1da3WuWIsxY,13253 +astroid/interpreter/_import/util.py,sha256=inubUz6F3_kaMFaeleKUW6E6wCMIPrhU882zvwEZ02I,255 +astroid/interpreter/dunder_lookup.py,sha256=dP-AZU_aGPNt03b1ttrMglxzeU3NtgnG0MfpSLPH6sg,2155 +astroid/interpreter/objectmodel.py,sha256=ioD4qW3JPG92IaUjv9ifxXa3x87GnvK7vY28QA372NU,27545 +astroid/manager.py,sha256=4TnkTWfWXW1EneOQ6YXK0bycwlFcEOSKAgnVNgNDs6U,14075 +astroid/mixins.py,sha256=F2rv2Ow7AU3YT_2jitVJik95ZWRVK6hpf8BrkkspzUY,5571 +astroid/modutils.py,sha256=0jntr_4xcKNsZKh3MDef9Ilu5-6QkiUFFEkKTKtWBP4,22435 +astroid/node_classes.py,sha256=Ua3a9eEEd5yDmdjo0fPYsWIcV1tUSMibbZt3dtASL-0,143883 +astroid/nodes.py,sha256=WoyRe22GNVRc2TRHWOUlqdxCdOVD8GKOq9v1LpPhkr8,2978 +astroid/objects.py,sha256=caKeQPBtrrfqa1q844vkehXwpdMzvph5YJdJJdbD_m8,11035 +astroid/protocols.py,sha256=Q_1K8YpxWeFCK58gpRAy8d2afswWIdD9W_im9RArnDw,27558 +astroid/raw_building.py,sha256=nWI31iO3ib7Pva76NphYd62Q6tfsVDqefwJWSeWETSs,17598 +astroid/rebuilder.py,sha256=SEjmTugtAevr60JcLybaMyly6Fi_G5lugdF_PFiB_qI,39432 +astroid/scoped_nodes.py,sha256=mA2iTDZlkgBS7L-6Wu9fLs1rmIe68fvVg0ncUTd0LH8,98492 +astroid/test_utils.py,sha256=U6TK1dIiyVHUe5IxYbgo8mr8pGeJ9tofXR6HURl1EAY,2378 +astroid/transforms.py,sha256=1npwJWcQUSIjcpcWd1pc-dJhtHOyiboQHsETAIQd5co,3377 +astroid/util.py,sha256=uZ10BJuMM7J5bBdDUf02o1iAErYxSAkHXEB92eo5vpo,4260 diff --git a/venv/Lib/site-packages/astroid-2.5.dist-info/WHEEL b/venv/Lib/site-packages/astroid-2.5.dist-info/WHEEL new file mode 100644 index 0000000..385faab --- /dev/null +++ b/venv/Lib/site-packages/astroid-2.5.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.2) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/astroid-2.5.dist-info/top_level.txt b/venv/Lib/site-packages/astroid-2.5.dist-info/top_level.txt new file mode 100644 index 0000000..450d4fe --- /dev/null +++ b/venv/Lib/site-packages/astroid-2.5.dist-info/top_level.txt @@ -0,0 +1 @@ +astroid diff --git a/venv/Lib/site-packages/atomicwrites-1.4.1-py3.9.egg-info/PKG-INFO b/venv/Lib/site-packages/atomicwrites-1.4.1-py3.9.egg-info/PKG-INFO new file mode 100644 index 0000000..63f78b6 --- /dev/null +++ b/venv/Lib/site-packages/atomicwrites-1.4.1-py3.9.egg-info/PKG-INFO @@ -0,0 +1,147 @@ +Metadata-Version: 2.1 +Name: atomicwrites +Version: 1.4.1 +Summary: Atomic file writes. +Home-page: https://github.com/untitaker/python-atomicwrites +Author: Markus Unterwaditzer +Author-email: markus@unterwaditzer.net +License: MIT +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: Implementation :: CPython +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* +License-File: LICENSE + +=================== +python-atomicwrites +=================== + +.. image:: https://travis-ci.com/untitaker/python-atomicwrites.svg?branch=master + :target: https://travis-ci.com/untitaker/python-atomicwrites +.. image:: https://ci.appveyor.com/api/projects/status/vadc4le3c27to59x/branch/master?svg=true + :target: https://ci.appveyor.com/project/untitaker/python-atomicwrites/branch/master +.. image:: https://readthedocs.org/projects/python-atomicwrites/badge/?version=latest + :target: https://python-atomicwrites.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status + +**Atomic file writes.** + +.. code-block:: python + + from atomicwrites import atomic_write + + with atomic_write('foo.txt', overwrite=True) as f: + f.write('Hello world.') + # "foo.txt" doesn't exist yet. + + # Now it does. + +See `API documentation `_ for more +low-level interfaces. + +Features that distinguish it from other similar libraries (see `Alternatives and Credit`_): + +- Race-free assertion that the target file doesn't yet exist. This can be + controlled with the ``overwrite`` parameter. + +- Windows support, although not well-tested. The MSDN resources are not very + explicit about which operations are atomic. I'm basing my assumptions off `a + comment + `_ + by `Doug Cook + `_, who appears + to be a Microsoft employee: + + Question: Is MoveFileEx atomic if the existing and new + files are both on the same drive? + + The simple answer is "usually, but in some cases it will silently fall-back + to a non-atomic method, so don't count on it". + + The implementation of MoveFileEx looks something like this: [...] + + The problem is if the rename fails, you might end up with a CopyFile, which + is definitely not atomic. + + If you really need atomic-or-nothing, you can try calling + NtSetInformationFile, which is unsupported but is much more likely to be + atomic. + +- Simple high-level API that wraps a very flexible class-based API. + +- Consistent error handling across platforms. + + +How it works +============ + +It uses a temporary file in the same directory as the given path. This ensures +that the temporary file resides on the same filesystem. + +The temporary file will then be atomically moved to the target location: On +POSIX, it will use ``rename`` if files should be overwritten, otherwise a +combination of ``link`` and ``unlink``. On Windows, it uses MoveFileEx_ through +stdlib's ``ctypes`` with the appropriate flags. + +Note that with ``link`` and ``unlink``, there's a timewindow where the file +might be available under two entries in the filesystem: The name of the +temporary file, and the name of the target file. + +Also note that the permissions of the target file may change this way. In some +situations a ``chmod`` can be issued without any concurrency problems, but +since that is not always the case, this library doesn't do it by itself. + +.. _MoveFileEx: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365240%28v=vs.85%29.aspx + +fsync +----- + +On POSIX, ``fsync`` is invoked on the temporary file after it is written (to +flush file content and metadata), and on the parent directory after the file is +moved (to flush filename). + +``fsync`` does not take care of disks' internal buffers, but there don't seem +to be any standard POSIX APIs for that. On OS X, ``fcntl`` is used with +``F_FULLFSYNC`` instead of ``fsync`` for that reason. + +On Windows, `_commit `_ +is used, but there are no guarantees about disk internal buffers. + +Alternatives and Credit +======================= + +Atomicwrites is directly inspired by the following libraries (and shares a +minimal amount of code): + +- The Trac project's `utility functions + `_, + also used in `Werkzeug `_ and + `mitsuhiko/python-atomicfile + `_. The idea to use + ``ctypes`` instead of ``PyWin32`` originated there. + +- `abarnert/fatomic `_. Windows support + (based on ``PyWin32``) was originally taken from there. + +Other alternatives to atomicwrites include: + +- `sashka/atomicfile `_. Originally I + considered using that, but at the time it was lacking a lot of features I + needed (Windows support, overwrite-parameter, overriding behavior through + subclassing). + +- The `Boltons library collection `_ + features a class for atomic file writes, which seems to have a very similar + ``overwrite`` parameter. It is lacking Windows support though. + +License +======= + +Licensed under the MIT, see ``LICENSE``. diff --git a/venv/Lib/site-packages/atomicwrites-1.4.1-py3.9.egg-info/SOURCES.txt b/venv/Lib/site-packages/atomicwrites-1.4.1-py3.9.egg-info/SOURCES.txt new file mode 100644 index 0000000..bf97334 --- /dev/null +++ b/venv/Lib/site-packages/atomicwrites-1.4.1-py3.9.egg-info/SOURCES.txt @@ -0,0 +1,15 @@ +LICENSE +MANIFEST.in +README.rst +setup.cfg +setup.py +atomicwrites/__init__.py +atomicwrites.egg-info/PKG-INFO +atomicwrites.egg-info/SOURCES.txt +atomicwrites.egg-info/dependency_links.txt +atomicwrites.egg-info/top_level.txt +docs/Makefile +docs/conf.py +docs/index.rst +docs/make.bat +tests/test_atomicwrites.py \ No newline at end of file diff --git a/venv/Lib/site-packages/atomicwrites-1.4.1-py3.9.egg-info/dependency_links.txt b/venv/Lib/site-packages/atomicwrites-1.4.1-py3.9.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/venv/Lib/site-packages/atomicwrites-1.4.1-py3.9.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/venv/Lib/site-packages/atomicwrites-1.4.1-py3.9.egg-info/installed-files.txt b/venv/Lib/site-packages/atomicwrites-1.4.1-py3.9.egg-info/installed-files.txt new file mode 100644 index 0000000..7129f9d --- /dev/null +++ b/venv/Lib/site-packages/atomicwrites-1.4.1-py3.9.egg-info/installed-files.txt @@ -0,0 +1,6 @@ +..\atomicwrites\__init__.py +..\atomicwrites\__pycache__\__init__.cpython-39.pyc +PKG-INFO +SOURCES.txt +dependency_links.txt +top_level.txt diff --git a/venv/Lib/site-packages/atomicwrites-1.4.1-py3.9.egg-info/top_level.txt b/venv/Lib/site-packages/atomicwrites-1.4.1-py3.9.egg-info/top_level.txt new file mode 100644 index 0000000..5fa5a87 --- /dev/null +++ b/venv/Lib/site-packages/atomicwrites-1.4.1-py3.9.egg-info/top_level.txt @@ -0,0 +1 @@ +atomicwrites diff --git a/venv/Lib/site-packages/atomicwrites/__init__.py b/venv/Lib/site-packages/atomicwrites/__init__.py new file mode 100644 index 0000000..669191b --- /dev/null +++ b/venv/Lib/site-packages/atomicwrites/__init__.py @@ -0,0 +1,229 @@ +import contextlib +import io +import os +import sys +import tempfile + +try: + import fcntl +except ImportError: + fcntl = None + +# `fspath` was added in Python 3.6 +try: + from os import fspath +except ImportError: + fspath = None + +__version__ = '1.4.1' + + +PY2 = sys.version_info[0] == 2 + +text_type = unicode if PY2 else str # noqa + + +def _path_to_unicode(x): + if not isinstance(x, text_type): + return x.decode(sys.getfilesystemencoding()) + return x + + +DEFAULT_MODE = "wb" if PY2 else "w" + + +_proper_fsync = os.fsync + + +if sys.platform != 'win32': + if hasattr(fcntl, 'F_FULLFSYNC'): + def _proper_fsync(fd): + # https://lists.apple.com/archives/darwin-dev/2005/Feb/msg00072.html + # https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/fsync.2.html + # https://github.com/untitaker/python-atomicwrites/issues/6 + fcntl.fcntl(fd, fcntl.F_FULLFSYNC) + + def _sync_directory(directory): + # Ensure that filenames are written to disk + fd = os.open(directory, 0) + try: + _proper_fsync(fd) + finally: + os.close(fd) + + def _replace_atomic(src, dst): + os.rename(src, dst) + _sync_directory(os.path.normpath(os.path.dirname(dst))) + + def _move_atomic(src, dst): + os.link(src, dst) + os.unlink(src) + + src_dir = os.path.normpath(os.path.dirname(src)) + dst_dir = os.path.normpath(os.path.dirname(dst)) + _sync_directory(dst_dir) + if src_dir != dst_dir: + _sync_directory(src_dir) +else: + from ctypes import windll, WinError + + _MOVEFILE_REPLACE_EXISTING = 0x1 + _MOVEFILE_WRITE_THROUGH = 0x8 + _windows_default_flags = _MOVEFILE_WRITE_THROUGH + + def _handle_errors(rv): + if not rv: + raise WinError() + + def _replace_atomic(src, dst): + _handle_errors(windll.kernel32.MoveFileExW( + _path_to_unicode(src), _path_to_unicode(dst), + _windows_default_flags | _MOVEFILE_REPLACE_EXISTING + )) + + def _move_atomic(src, dst): + _handle_errors(windll.kernel32.MoveFileExW( + _path_to_unicode(src), _path_to_unicode(dst), + _windows_default_flags + )) + + +def replace_atomic(src, dst): + ''' + Move ``src`` to ``dst``. If ``dst`` exists, it will be silently + overwritten. + + Both paths must reside on the same filesystem for the operation to be + atomic. + ''' + return _replace_atomic(src, dst) + + +def move_atomic(src, dst): + ''' + Move ``src`` to ``dst``. There might a timewindow where both filesystem + entries exist. If ``dst`` already exists, :py:exc:`FileExistsError` will be + raised. + + Both paths must reside on the same filesystem for the operation to be + atomic. + ''' + return _move_atomic(src, dst) + + +class AtomicWriter(object): + ''' + A helper class for performing atomic writes. Usage:: + + with AtomicWriter(path).open() as f: + f.write(...) + + :param path: The destination filepath. May or may not exist. + :param mode: The filemode for the temporary file. This defaults to `wb` in + Python 2 and `w` in Python 3. + :param overwrite: If set to false, an error is raised if ``path`` exists. + Errors are only raised after the file has been written to. Either way, + the operation is atomic. + :param open_kwargs: Keyword-arguments to pass to the underlying + :py:func:`open` call. This can be used to set the encoding when opening + files in text-mode. + + If you need further control over the exact behavior, you are encouraged to + subclass. + ''' + + def __init__(self, path, mode=DEFAULT_MODE, overwrite=False, + **open_kwargs): + if 'a' in mode: + raise ValueError( + 'Appending to an existing file is not supported, because that ' + 'would involve an expensive `copy`-operation to a temporary ' + 'file. Open the file in normal `w`-mode and copy explicitly ' + 'if that\'s what you\'re after.' + ) + if 'x' in mode: + raise ValueError('Use the `overwrite`-parameter instead.') + if 'w' not in mode: + raise ValueError('AtomicWriters can only be written to.') + + # Attempt to convert `path` to `str` or `bytes` + if fspath is not None: + path = fspath(path) + + self._path = path + self._mode = mode + self._overwrite = overwrite + self._open_kwargs = open_kwargs + + def open(self): + ''' + Open the temporary file. + ''' + return self._open(self.get_fileobject) + + @contextlib.contextmanager + def _open(self, get_fileobject): + f = None # make sure f exists even if get_fileobject() fails + try: + success = False + with get_fileobject(**self._open_kwargs) as f: + yield f + self.sync(f) + self.commit(f) + success = True + finally: + if not success: + try: + self.rollback(f) + except Exception: + pass + + def get_fileobject(self, suffix="", prefix=tempfile.gettempprefix(), + dir=None, **kwargs): + '''Return the temporary file to use.''' + if dir is None: + dir = os.path.normpath(os.path.dirname(self._path)) + descriptor, name = tempfile.mkstemp(suffix=suffix, prefix=prefix, + dir=dir) + # io.open() will take either the descriptor or the name, but we need + # the name later for commit()/replace_atomic() and couldn't find a way + # to get the filename from the descriptor. + os.close(descriptor) + kwargs['mode'] = self._mode + kwargs['file'] = name + return io.open(**kwargs) + + def sync(self, f): + '''responsible for clearing as many file caches as possible before + commit''' + f.flush() + _proper_fsync(f.fileno()) + + def commit(self, f): + '''Move the temporary file to the target location.''' + if self._overwrite: + replace_atomic(f.name, self._path) + else: + move_atomic(f.name, self._path) + + def rollback(self, f): + '''Clean up all temporary resources.''' + os.unlink(f.name) + + +def atomic_write(path, writer_cls=AtomicWriter, **cls_kwargs): + ''' + Simple atomic writes. This wraps :py:class:`AtomicWriter`:: + + with atomic_write(path) as f: + f.write(...) + + :param path: The target path to write to. + :param writer_cls: The writer class to use. This parameter is useful if you + subclassed :py:class:`AtomicWriter` to change some behavior and want to + use that new subclass. + + Additional keyword arguments are passed to the writer class. See + :py:class:`AtomicWriter`. + ''' + return writer_cls(path, **cls_kwargs).open() diff --git a/venv/Lib/site-packages/attrs-22.2.0.dist-info/INSTALLER b/venv/Lib/site-packages/attrs-22.2.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/attrs-22.2.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/attrs-22.2.0.dist-info/LICENSE b/venv/Lib/site-packages/attrs-22.2.0.dist-info/LICENSE new file mode 100644 index 0000000..2bd6453 --- /dev/null +++ b/venv/Lib/site-packages/attrs-22.2.0.dist-info/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Hynek Schlawack and the attrs contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/venv/Lib/site-packages/attrs-22.2.0.dist-info/METADATA b/venv/Lib/site-packages/attrs-22.2.0.dist-info/METADATA new file mode 100644 index 0000000..0f71b57 --- /dev/null +++ b/venv/Lib/site-packages/attrs-22.2.0.dist-info/METADATA @@ -0,0 +1,278 @@ +Metadata-Version: 2.1 +Name: attrs +Version: 22.2.0 +Summary: Classes Without Boilerplate +Home-page: https://www.attrs.org/ +Author: Hynek Schlawack +Author-email: hs@ox.cx +Maintainer: Hynek Schlawack +Maintainer-email: hs@ox.cx +License: MIT +Project-URL: Documentation, https://www.attrs.org/ +Project-URL: Changelog, https://www.attrs.org/en/stable/changelog.html +Project-URL: Bug Tracker, https://github.com/python-attrs/attrs/issues +Project-URL: Source Code, https://github.com/python-attrs/attrs +Project-URL: Funding, https://github.com/sponsors/hynek +Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=pypi +Project-URL: Ko-fi, https://ko-fi.com/the_hynek +Keywords: class,attribute,boilerplate,dataclass +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Natural Language :: English +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >=3.6 +Description-Content-Type: text/markdown +License-File: LICENSE +Provides-Extra: cov +Requires-Dist: attrs[tests] ; extra == 'cov' +Requires-Dist: coverage-enable-subprocess ; extra == 'cov' +Requires-Dist: coverage[toml] (>=5.3) ; extra == 'cov' +Provides-Extra: dev +Requires-Dist: attrs[docs,tests] ; extra == 'dev' +Provides-Extra: docs +Requires-Dist: furo ; extra == 'docs' +Requires-Dist: sphinx ; extra == 'docs' +Requires-Dist: myst-parser ; extra == 'docs' +Requires-Dist: zope.interface ; extra == 'docs' +Requires-Dist: sphinx-notfound-page ; extra == 'docs' +Requires-Dist: sphinxcontrib-towncrier ; extra == 'docs' +Requires-Dist: towncrier ; extra == 'docs' +Provides-Extra: tests +Requires-Dist: attrs[tests-no-zope] ; extra == 'tests' +Requires-Dist: zope.interface ; extra == 'tests' +Provides-Extra: tests-no-zope +Requires-Dist: hypothesis ; extra == 'tests-no-zope' +Requires-Dist: pympler ; extra == 'tests-no-zope' +Requires-Dist: pytest (>=4.3.0) ; extra == 'tests-no-zope' +Requires-Dist: pytest-xdist[psutil] ; extra == 'tests-no-zope' +Requires-Dist: cloudpickle ; (platform_python_implementation == "CPython") and extra == 'tests-no-zope' +Requires-Dist: mypy (<0.990,>=0.971) ; (platform_python_implementation == "CPython") and extra == 'tests-no-zope' +Requires-Dist: pytest-mypy-plugins ; (platform_python_implementation == "CPython" and python_version < "3.11") and extra == 'tests-no-zope' +Provides-Extra: tests_no_zope +Requires-Dist: hypothesis ; extra == 'tests_no_zope' +Requires-Dist: pympler ; extra == 'tests_no_zope' +Requires-Dist: pytest (>=4.3.0) ; extra == 'tests_no_zope' +Requires-Dist: pytest-xdist[psutil] ; extra == 'tests_no_zope' +Requires-Dist: cloudpickle ; (platform_python_implementation == "CPython") and extra == 'tests_no_zope' +Requires-Dist: mypy (<0.990,>=0.971) ; (platform_python_implementation == "CPython") and extra == 'tests_no_zope' +Requires-Dist: pytest-mypy-plugins ; (platform_python_implementation == "CPython" and python_version < "3.11") and extra == 'tests_no_zope' + +

+ + attrs + +

+ + +

+ + Documentation + + + License: MIT + + + + + + + Downloads per month + + DOI +

+ + + +*attrs* is the Python package that will bring back the **joy** of **writing classes** by relieving you from the drudgery of implementing object protocols (aka [dunder methods](https://www.attrs.org/en/latest/glossary.html#term-dunder-methods)). +[Trusted by NASA](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-profile/customizing-your-profile/personalizing-your-profile#list-of-qualifying-repositories-for-mars-2020-helicopter-contributor-achievement) for Mars missions since 2020! + +Its main goal is to help you to write **concise** and **correct** software without slowing down your code. + + +## Sponsors + +*attrs* would not be possible without our [amazing sponsors](https://github.com/sponsors/hynek). +Especially those generously supporting us at the *The Organization* tier and higher: + +

+ + + + + + + + + + + + + + + +

+ +

+ Please consider joining them to help make attrs’s maintenance more sustainable! +

+ + + +## Example + +*attrs* gives you a class decorator and a way to declaratively define the attributes on that class: + + + +```pycon +>>> from attrs import asdict, define, make_class, Factory + +>>> @define +... class SomeClass: +... a_number: int = 42 +... list_of_numbers: list[int] = Factory(list) +... +... def hard_math(self, another_number): +... return self.a_number + sum(self.list_of_numbers) * another_number + + +>>> sc = SomeClass(1, [1, 2, 3]) +>>> sc +SomeClass(a_number=1, list_of_numbers=[1, 2, 3]) + +>>> sc.hard_math(3) +19 +>>> sc == SomeClass(1, [1, 2, 3]) +True +>>> sc != SomeClass(2, [3, 2, 1]) +True + +>>> asdict(sc) +{'a_number': 1, 'list_of_numbers': [1, 2, 3]} + +>>> SomeClass() +SomeClass(a_number=42, list_of_numbers=[]) + +>>> C = make_class("C", ["a", "b"]) +>>> C("foo", "bar") +C(a='foo', b='bar') +``` + +After *declaring* your attributes, *attrs* gives you: + +- a concise and explicit overview of the class's attributes, +- a nice human-readable `__repr__`, +- equality-checking methods, +- an initializer, +- and much more, + +*without* writing dull boilerplate code again and again and *without* runtime performance penalties. + +**Hate type annotations**!? +No problem! +Types are entirely **optional** with *attrs*. +Simply assign `attrs.field()` to the attributes instead of annotating them with types. + +--- + +This example uses *attrs*'s modern APIs that have been introduced in version 20.1.0, and the *attrs* package import name that has been added in version 21.3.0. +The classic APIs (`@attr.s`, `attr.ib`, plus their serious-business aliases) and the `attr` package import name will remain **indefinitely**. + +Please check out [*On The Core API Names*](https://www.attrs.org/en/latest/names.html) for a more in-depth explanation. + + +## Data Classes + +On the tin, *attrs* might remind you of `dataclasses` (and indeed, `dataclasses` [are a descendant](https://hynek.me/articles/import-attrs/) of *attrs*). +In practice it does a lot more and is more flexible. +For instance it allows you to define [special handling of NumPy arrays for equality checks](https://www.attrs.org/en/stable/comparison.html#customization), or allows more ways to [plug into the initialization process](https://www.attrs.org/en/stable/init.html#hooking-yourself-into-initialization). + +For more details, please refer to our [comparison page](https://www.attrs.org/en/stable/why.html#data-classes). + + +## Project Information + +- [**Changelog**](https://www.attrs.org/en/stable/changelog.html) +- [**Documentation**](https://www.attrs.org/) +- [**PyPI**](https://pypi.org/project/attrs/) +- [**Source Code**](https://github.com/python-attrs/attrs) +- [**Contributing**](https://github.com/python-attrs/attrs/blob/main/.github/CONTRIBUTING.md) +- [**Third-party Extensions**](https://github.com/python-attrs/attrs/wiki/Extensions-to-attrs) +- **License**: [MIT](https://www.attrs.org/en/latest/license.html) +- **Get Help**: please use the `python-attrs` tag on [StackOverflow](https://stackoverflow.com/questions/tagged/python-attrs) +- **Supported Python Versions**: 3.6 and later + + +### *attrs* for Enterprise + +Available as part of the Tidelift Subscription. + +The maintainers of *attrs* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. +Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. +[Learn more.](https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) + + +## Changes in This Release + +### Backwards-incompatible Changes + +- Python 3.5 is not supported anymore. + [#988](https://github.com/python-attrs/attrs/issues/988) + + +### Deprecations + +- Python 3.6 is now deprecated and support will be removed in the next release. + [#1017](https://github.com/python-attrs/attrs/issues/1017) + + +### Changes + +- `attrs.field()` now supports an *alias* option for explicit `__init__` argument names. + + Get `__init__` signatures matching any taste, peculiar or plain! + The [PEP 681 compatible](https://peps.python.org/pep-0681/#field-specifier-parameters) *alias* option can be use to override private attribute name mangling, or add other arbitrary field argument name overrides. + [#950](https://github.com/python-attrs/attrs/issues/950) +- `attrs.NOTHING` is now an enum value, making it possible to use with e.g. [`typing.Literal`](https://docs.python.org/3/library/typing.html#typing.Literal). + [#983](https://github.com/python-attrs/attrs/issues/983) +- Added missing re-import of `attr.AttrsInstance` to the `attrs` namespace. + [#987](https://github.com/python-attrs/attrs/issues/987) +- Fix slight performance regression in classes with custom `__setattr__` and speedup even more. + [#991](https://github.com/python-attrs/attrs/issues/991) +- Class-creation performance improvements by switching performance-sensitive templating operations to f-strings. + + You can expect an improvement of about 5% -- even for very simple classes. + [#995](https://github.com/python-attrs/attrs/issues/995) +- `attrs.has()` is now a [`TypeGuard`](https://docs.python.org/3/library/typing.html#typing.TypeGuard) for `AttrsInstance`. + That means that type checkers know a class is an instance of an `attrs` class if you check it using `attrs.has()` (or `attr.has()`) first. + [#997](https://github.com/python-attrs/attrs/issues/997) +- Made `attrs.AttrsInstance` stub available at runtime and fixed type errors related to the usage of `attrs.AttrsInstance` in *Pyright*. + [#999](https://github.com/python-attrs/attrs/issues/999) +- On Python 3.10 and later, call [`abc.update_abstractmethods()`](https://docs.python.org/3/library/abc.html#abc.update_abstractmethods) on dict classes after creation. + This improves the detection of abstractness. + [#1001](https://github.com/python-attrs/attrs/issues/1001) +- *attrs*'s pickling methods now use dicts instead of tuples. + That is safer and more robust across different versions of a class. + [#1009](https://github.com/python-attrs/attrs/issues/1009) +- Added `attrs.validators.not_(wrapped_validator)` to logically invert *wrapped_validator* by accepting only values where *wrapped_validator* rejects the value with a `ValueError` or `TypeError` (by default, exception types configurable). + [#1010](https://github.com/python-attrs/attrs/issues/1010) +- The type stubs for `attrs.cmp_using()` now have default values. + [#1027](https://github.com/python-attrs/attrs/issues/1027) +- To conform with [PEP 681](https://peps.python.org/pep-0681/), `attr.s()` and `attrs.define()` now accept *unsafe_hash* in addition to *hash*. + [#1065](https://github.com/python-attrs/attrs/issues/1065) + +--- + +[Full changelog](https://www.attrs.org/en/stable/changelog.html) diff --git a/venv/Lib/site-packages/attrs-22.2.0.dist-info/RECORD b/venv/Lib/site-packages/attrs-22.2.0.dist-info/RECORD new file mode 100644 index 0000000..0527666 --- /dev/null +++ b/venv/Lib/site-packages/attrs-22.2.0.dist-info/RECORD @@ -0,0 +1,56 @@ +attr/__init__.py,sha256=-lJ5CXKE5yKk97Z2HSMRJFiGz1TdXLU9q4Ysb2Id4IQ,1947 +attr/__init__.pyi,sha256=qOjUNync7Lq8NLk30l_DRTh1h62mMl1e4VnqBgY2x24,15831 +attr/__pycache__/__init__.cpython-39.pyc,, +attr/__pycache__/_cmp.cpython-39.pyc,, +attr/__pycache__/_compat.cpython-39.pyc,, +attr/__pycache__/_config.cpython-39.pyc,, +attr/__pycache__/_funcs.cpython-39.pyc,, +attr/__pycache__/_make.cpython-39.pyc,, +attr/__pycache__/_next_gen.cpython-39.pyc,, +attr/__pycache__/_version_info.cpython-39.pyc,, +attr/__pycache__/converters.cpython-39.pyc,, +attr/__pycache__/exceptions.cpython-39.pyc,, +attr/__pycache__/filters.cpython-39.pyc,, +attr/__pycache__/setters.cpython-39.pyc,, +attr/__pycache__/validators.cpython-39.pyc,, +attr/_cmp.py,sha256=mwr1ImJlkFL9Zi0E55-90IfchMKr94ko6e-p4y__M_4,4094 +attr/_cmp.pyi,sha256=sGQmOM0w3_K4-X8cTXR7g0Hqr290E8PTObA9JQxWQqc,399 +attr/_compat.py,sha256=Da-SeMicy7SkTKCCwKtfX41sUMf0o54tK96zsu1qE60,5435 +attr/_config.py,sha256=5W8lgRePuIOWu1ZuqF1899e2CmXGc95-ipwTpF1cEU4,826 +attr/_funcs.py,sha256=0EqqZgKNZBk4PXQvCF_fuWWAz14mSdZpk4UBZpX_fDQ,14545 +attr/_make.py,sha256=MdYHoWXJ2WlQNZPMTX4gkBO06QgPyb3qwSWSxaJ6QVg,96087 +attr/_next_gen.py,sha256=95DRKAfIuHbcwO9W_yWtRsHt3IbfxbAgpyB6agxbghw,6059 +attr/_typing_compat.pyi,sha256=XDP54TUn-ZKhD62TOQebmzrwFyomhUCoGRpclb6alRA,469 +attr/_version_info.py,sha256=exSqb3b5E-fMSsgZAlEw9XcLpEgobPORCZpcaEglAM4,2121 +attr/_version_info.pyi,sha256=x_M3L3WuB7r_ULXAWjx959udKQ4HLB8l-hsc1FDGNvk,209 +attr/converters.py,sha256=xfGVSPRgWGcym6N5FZM9fyfvCQePqFyApWeC5BXKvoM,3602 +attr/converters.pyi,sha256=jKlpHBEt6HVKJvgrMFJRrHq8p61GXg4-Nd5RZWKJX7M,406 +attr/exceptions.py,sha256=ZGEMLv0CDY1TOtj49OF84myejOn-LCCXAKGIKalKkVU,1915 +attr/exceptions.pyi,sha256=zZq8bCUnKAy9mDtBEw42ZhPhAUIHoTKedDQInJD883M,539 +attr/filters.py,sha256=aZep54h8-4ZYV5lmZ3Dx2mqeQH4cMx6tuCmCylLNbEU,1038 +attr/filters.pyi,sha256=_Sm80jGySETX_Clzdkon5NHVjQWRl3Y3liQKZX1czXc,215 +attr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +attr/setters.py,sha256=pbCZQ-pE6ZxjDqZfWWUhUFefXtpekIU4qS_YDMLPQ50,1400 +attr/setters.pyi,sha256=pyY8TVNBu8TWhOldv_RxHzmGvdgFQH981db70r0fn5I,567 +attr/validators.py,sha256=gBJAzoo1UNDRTG9-kE0LUoUTgDr2slJymPxb6-UPt7c,20501 +attr/validators.pyi,sha256=ZbJDuF6Kom-L6ym9Cc6eT370S_a7z8YhWmP7z35ayXc,2538 +attrs-22.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +attrs-22.2.0.dist-info/LICENSE,sha256=iCEVyV38KvHutnFPjsbVy8q_Znyv-HKfQkINpj9xTp8,1109 +attrs-22.2.0.dist-info/METADATA,sha256=jgQypZGK_yplaxCh1S1gnQ_NZYKk-EwtfWygdZ_NgIc,13531 +attrs-22.2.0.dist-info/RECORD,, +attrs-22.2.0.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92 +attrs-22.2.0.dist-info/top_level.txt,sha256=AGbmKnOtYpdkLRsDRQVSBIwfL32pAQ6BSo1mt-BxI7M,11 +attrs/__init__.py,sha256=90bKLoqyIHpMjnzJuXSar1dH5anUQXHqT7-yI1Qzg00,1149 +attrs/__init__.pyi,sha256=KMHncABV_sq4pubLAli-iOQjc9EM3g9y2r6M9V71_vY,2148 +attrs/__pycache__/__init__.cpython-39.pyc,, +attrs/__pycache__/converters.cpython-39.pyc,, +attrs/__pycache__/exceptions.cpython-39.pyc,, +attrs/__pycache__/filters.cpython-39.pyc,, +attrs/__pycache__/setters.cpython-39.pyc,, +attrs/__pycache__/validators.cpython-39.pyc,, +attrs/converters.py,sha256=fCBEdlYWcmI3sCnpUk2pz22GYtXzqTkp6NeOpdI64PY,70 +attrs/exceptions.py,sha256=SlDli6AY77f6ny-H7oy98OkQjsrw-D_supEuErIVYkE,70 +attrs/filters.py,sha256=dc_dNey29kH6KLU1mT2Dakq7tZ3kBfzEGwzOmDzw1F8,67 +attrs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +attrs/setters.py,sha256=oKw51C72Hh45wTwYvDHJP9kbicxiMhMR4Y5GvdpKdHQ,67 +attrs/validators.py,sha256=4ag1SyVD2Hm3PYKiNG_NOtR_e7f81Hr6GiNl4YvXo4Q,70 diff --git a/venv/Lib/site-packages/attrs-22.2.0.dist-info/WHEEL b/venv/Lib/site-packages/attrs-22.2.0.dist-info/WHEEL new file mode 100644 index 0000000..57e3d84 --- /dev/null +++ b/venv/Lib/site-packages/attrs-22.2.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.38.4) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/attrs-22.2.0.dist-info/top_level.txt b/venv/Lib/site-packages/attrs-22.2.0.dist-info/top_level.txt new file mode 100644 index 0000000..eca8ba9 --- /dev/null +++ b/venv/Lib/site-packages/attrs-22.2.0.dist-info/top_level.txt @@ -0,0 +1,2 @@ +attr +attrs diff --git a/venv/Lib/site-packages/black-20.8b1.dist-info/INSTALLER b/venv/Lib/site-packages/black-20.8b1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/black-20.8b1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/black-20.8b1.dist-info/LICENSE b/venv/Lib/site-packages/black-20.8b1.dist-info/LICENSE new file mode 100644 index 0000000..7a9b891 --- /dev/null +++ b/venv/Lib/site-packages/black-20.8b1.dist-info/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018 Łukasz Langa + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/venv/Lib/site-packages/black-20.8b1.dist-info/METADATA b/venv/Lib/site-packages/black-20.8b1.dist-info/METADATA new file mode 100644 index 0000000..c80abcf --- /dev/null +++ b/venv/Lib/site-packages/black-20.8b1.dist-info/METADATA @@ -0,0 +1,1230 @@ +Metadata-Version: 2.1 +Name: black +Version: 20.8b1 +Summary: The uncompromising code formatter. +Home-page: https://github.com/psf/black +Author: Łukasz Langa +Author-email: lukasz@langa.pl +License: MIT +Project-URL: Changelog, https://github.com/psf/black/blob/master/CHANGES.md +Keywords: automation formatter yapf autopep8 pyfmt gofmt rustfmt +Classifier: Development Status :: 4 - Beta +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Software Development :: Quality Assurance +Requires-Python: >=3.6 +Description-Content-Type: text/markdown +License-File: LICENSE +Requires-Dist: click (>=7.1.2) +Requires-Dist: appdirs +Requires-Dist: toml (>=0.10.1) +Requires-Dist: typed-ast (>=1.4.0) +Requires-Dist: regex (>=2020.1.8) +Requires-Dist: pathspec (<1,>=0.6) +Requires-Dist: typing-extensions (>=3.7.4) +Requires-Dist: mypy-extensions (>=0.4.3) +Requires-Dist: dataclasses (>=0.6) ; python_version < "3.7" +Provides-Extra: colorama +Requires-Dist: colorama (>=0.4.3) ; extra == 'colorama' +Provides-Extra: d +Requires-Dist: aiohttp (>=3.3.2) ; extra == 'd' +Requires-Dist: aiohttp-cors ; extra == 'd' + +![Black Logo](https://raw.githubusercontent.com/psf/black/master/docs/_static/logo2-readme.png) + +

The Uncompromising Code Formatter

+ +

+Build Status +Actions Status +Actions Status +Documentation Status +Coverage Status +License: MIT +PyPI +Downloads +Code style: black +

+ +> “Any color you like.” + +_Black_ is the uncompromising Python code formatter. By using it, you agree to cede +control over minutiae of hand-formatting. In return, _Black_ gives you speed, +determinism, and freedom from `pycodestyle` nagging about formatting. You will save time +and mental energy for more important matters. + +Blackened code looks the same regardless of the project you're reading. Formatting +becomes transparent after a while and you can focus on the content instead. + +_Black_ makes code review faster by producing the smallest diffs possible. + +Try it out now using the [Black Playground](https://black.now.sh). Watch the +[PyCon 2019 talk](https://youtu.be/esZLCuWs_2Y) to learn more. + +--- + +_Contents:_ **[Installation and usage](#installation-and-usage)** | +**[Code style](#the-black-code-style)** | **[Pragmatism](#pragmatism)** | +**[pyproject.toml](#pyprojecttoml)** | **[Editor integration](#editor-integration)** | +**[blackd](#blackd)** | **[black-primer](#black-primer)** | +**[Version control integration](#version-control-integration)** | +**[GitHub Actions](#github-actions)** | +**[Ignoring unmodified files](#ignoring-unmodified-files)** | **[Used by](#used-by)** | +**[Testimonials](#testimonials)** | **[Show your style](#show-your-style)** | +**[Contributing](#contributing-to-black)** | **[Change log](#change-log)** | +**[Authors](#authors)** + +--- + +## Installation and usage + +### Installation + +_Black_ can be installed by running `pip install black`. It requires Python 3.6.0+ to +run but you can reformat Python 2 code with it, too. + +#### Install from GitHub + +If you can't wait for the latest _hotness_ and want to install from GitHub, use: + +`pip install git+git://github.com/psf/black` + +### Usage + +To get started right away with sensible defaults: + +```sh +black {source_file_or_directory} +``` + +You can run _Black_ as a package if running it as a script doesn't work: + +```sh +python -m black {source_file_or_directory} +``` + +### Command line options + +_Black_ doesn't provide many options. You can list them by running `black --help`: + +```text +Usage: black [OPTIONS] [SRC]... + + The uncompromising code formatter. + +Options: + -c, --code TEXT Format the code passed in as a string. + -l, --line-length INTEGER How many characters per line to allow. + [default: 88] + + -t, --target-version [py27|py33|py34|py35|py36|py37|py38] + Python versions that should be supported by + Black's output. [default: per-file auto- + detection] + + --pyi Format all input files like typing stubs + regardless of file extension (useful when + piping source on standard input). + + -S, --skip-string-normalization + Don't normalize string quotes or prefixes. + --check Don't write the files back, just return the + status. Return code 0 means nothing would + change. Return code 1 means some files + would be reformatted. Return code 123 means + there was an internal error. + + --diff Don't write the files back, just output a + diff for each file on stdout. + + --color / --no-color Show colored diff. Only applies when + `--diff` is given. + + --fast / --safe If --fast given, skip temporary sanity + checks. [default: --safe] + + --include TEXT A regular expression that matches files and + directories that should be included on + recursive searches. An empty value means + all files are included regardless of the + name. Use forward slashes for directories + on all platforms (Windows, too). Exclusions + are calculated first, inclusions later. + [default: \.pyi?$] + + --exclude TEXT A regular expression that matches files and + directories that should be excluded on + recursive searches. An empty value means no + paths are excluded. Use forward slashes for + directories on all platforms (Windows, too). + Exclusions are calculated first, inclusions + later. [default: /(\.eggs|\.git|\.hg|\.mypy + _cache|\.nox|\.tox|\.venv|\.svn|_build|buck- + out|build|dist)/] + + --force-exclude TEXT Like --exclude, but files and directories + matching this regex will be excluded even + when they are passed explicitly as arguments + + -q, --quiet Don't emit non-error messages to stderr. + Errors are still emitted; silence those with + 2>/dev/null. + + -v, --verbose Also emit messages to stderr about files + that were not changed or were ignored due to + --exclude=. + + --version Show the version and exit. + --config FILE Read configuration from FILE path. + -h, --help Show this message and exit. +``` + +_Black_ is a well-behaved Unix-style command-line tool: + +- it does nothing if no sources are passed to it; +- it will read from standard input and write to standard output if `-` is used as the + filename; +- it only outputs messages to users on standard error; +- exits with code 0 unless an internal error occurred (or `--check` was used). + +### Using _Black_ with other tools + +While _Black_ enforces formatting that conforms to PEP 8, other tools may raise warnings +about _Black_'s changes or will overwrite _Black_'s changes. A good example of this is +[isort](https://pypi.org/p/isort). Since _Black_ is barely configurable, these tools +should be configured to neither warn about nor overwrite _Black_'s changes. + +Actual details on _Black_ compatible configurations for various tools can be found in +[compatible_configs](https://github.com/psf/black/blob/master/docs/compatible_configs.md). + +### Migrating your code style without ruining git blame + +A long-standing argument against moving to automated code formatters like _Black_ is +that the migration will clutter up the output of `git blame`. This was a valid argument, +but since Git version 2.23, Git natively supports +[ignoring revisions in blame](https://git-scm.com/docs/git-blame#Documentation/git-blame.txt---ignore-revltrevgt) +with the `--ignore-rev` option. You can also pass a file listing the revisions to ignore +using the `--ignore-revs-file` option. The changes made by the revision will be ignored +when assigning blame. Lines modified by an ignored revision will be blamed on the +previous revision that modified those lines. + +So when migrating your project's code style to _Black_, reformat everything and commit +the changes (preferably in one massive commit). Then put the full 40 characters commit +identifier(s) into a file. + +``` +# Migrate code style to Black +5b4ab991dede475d393e9d69ec388fd6bd949699 +``` + +Afterwards, you can pass that file to `git blame` and see clean and meaningful blame +information. + +```console +$ git blame important.py --ignore-revs-file .git-blame-ignore-revs +7a1ae265 (John Smith 2019-04-15 15:55:13 -0400 1) def very_important_function(text, file): +abdfd8b0 (Alice Doe 2019-09-23 11:39:32 -0400 2) text = text.lstrip() +7a1ae265 (John Smith 2019-04-15 15:55:13 -0400 3) with open(file, "r+") as f: +7a1ae265 (John Smith 2019-04-15 15:55:13 -0400 4) f.write(formatted) +``` + +You can even configure `git` to automatically ignore revisions listed in a file on every +call to `git blame`. + +```console +$ git config blame.ignoreRevsFile .git-blame-ignore-revs +``` + +**The one caveat is that GitHub and GitLab do not yet support ignoring revisions using +their native UI of blame.** So blame information will be cluttered with a reformatting +commit on those platforms. (If you'd like this feature, there's an open issue for +[GitLab](https://gitlab.com/gitlab-org/gitlab/-/issues/31423) and please let GitHub +know!) + +### NOTE: This is a beta product + +_Black_ is already [successfully used](#used-by) by many projects, small and big. It +also sports a decent test suite. However, it is still very new. Things will probably be +wonky for a while. This is made explicit by the "Beta" trove classifier, as well as by +the "b" in the version number. What this means for you is that **until the formatter +becomes stable, you should expect some formatting to change in the future**. That being +said, no drastic stylistic changes are planned, mostly responses to bug reports. + +Also, as a temporary safety measure, _Black_ will check that the reformatted code still +produces a valid AST that is equivalent to the original. This slows it down. If you're +feeling confident, use `--fast`. + +## The _Black_ code style + +_Black_ is a PEP 8 compliant opinionated formatter. _Black_ reformats entire files in +place. It is not configurable. It doesn't take previous formatting into account. Your +main option of configuring _Black_ is that it doesn't reformat blocks that start with +`# fmt: off` and end with `# fmt: on`. `# fmt: on/off` have to be on the same level of +indentation. To learn more about _Black_'s opinions, to go +[the_black_code_style](https://github.com/psf/black/blob/master/docs/the_black_code_style.md). + +Please refer to this document before submitting an issue. What seems like a bug might be +intended behaviour. + +## Pragmatism + +Early versions of _Black_ used to be absolutist in some respects. They took after its +initial author. This was fine at the time as it made the implementation simpler and +there were not many users anyway. Not many edge cases were reported. As a mature tool, +_Black_ does make some exceptions to rules it otherwise holds. This +[section](https://github.com/psf/black/blob/master/docs/the_black_code_style.md#pragmatism) +of `the_black_code_style` describes what those exceptions are and why this is the case. + +Please refer to this document before submitting an issue just like with the document +above. What seems like a bug might be intended behaviour. + +## pyproject.toml + +_Black_ is able to read project-specific default values for its command line options +from a `pyproject.toml` file. This is especially useful for specifying custom +`--include` and `--exclude` patterns for your project. + +**Pro-tip**: If you're asking yourself "Do I need to configure anything?" the answer is +"No". _Black_ is all about sensible defaults. + +### What on Earth is a `pyproject.toml` file? + +[PEP 518](https://www.python.org/dev/peps/pep-0518/) defines `pyproject.toml` as a +configuration file to store build system requirements for Python projects. With the help +of tools like [Poetry](https://python-poetry.org/) or +[Flit](https://flit.readthedocs.io/en/latest/) it can fully replace the need for +`setup.py` and `setup.cfg` files. + +### Where _Black_ looks for the file + +By default _Black_ looks for `pyproject.toml` starting from the common base directory of +all files and directories passed on the command line. If it's not there, it looks in +parent directories. It stops looking when it finds the file, or a `.git` directory, or a +`.hg` directory, or the root of the file system, whichever comes first. + +If you're formatting standard input, _Black_ will look for configuration starting from +the current working directory. + +You can also explicitly specify the path to a particular file that you want with +`--config`. In this situation _Black_ will not look for any other file. + +If you're running with `--verbose`, you will see a blue message if a file was found and +used. + +Please note `blackd` will not use `pyproject.toml` configuration. + +### Configuration format + +As the file extension suggests, `pyproject.toml` is a +[TOML](https://github.com/toml-lang/toml) file. It contains separate sections for +different tools. _Black_ is using the `[tool.black]` section. The option keys are the +same as long names of options on the command line. + +Note that you have to use single-quoted strings in TOML for regular expressions. It's +the equivalent of r-strings in Python. Multiline strings are treated as verbose regular +expressions by Black. Use `[ ]` to denote a significant space character. + +
+Example pyproject.toml + +```toml +[tool.black] +line-length = 88 +target-version = ['py37'] +include = '\.pyi?$' +exclude = ''' + +( + /( + \.eggs # exclude a few common directories in the + | \.git # root of the project + | \.hg + | \.mypy_cache + | \.tox + | \.venv + | _build + | buck-out + | build + | dist + )/ + | foo.py # also separately exclude a file named foo.py in + # the root of the project +) +''' +``` + +
+ +### Lookup hierarchy + +Command-line options have defaults that you can see in `--help`. A `pyproject.toml` can +override those defaults. Finally, options provided by the user on the command line +override both. + +_Black_ will only ever use one `pyproject.toml` file during an entire run. It doesn't +look for multiple files, and doesn't compose configuration from different levels of the +file hierarchy. + +## Editor integration + +_Black_ can be integrated into many editors with plugins. They let you run _Black_ on +your code with the ease of doing it in your editor. To get started using _Black_ in your +editor of choice, please see +[editor_integration](https://github.com/psf/black/blob/master/docs/editor_integration.md). + +Patches are welcome for editors without an editor integration or plugin! More +information can be found in +[editor_integration](https://github.com/psf/black/blob/master/docs/editor_integration.md#other-editors). + +## blackd + +`blackd` is a small HTTP server that exposes Black's functionality over a simple +protocol. The main benefit of using it is to avoid paying the cost of starting up a new +Black process every time you want to blacken a file. Please refer to +[blackd](https://github.com/psf/black/blob/master/docs/blackd.md) to get the ball +rolling. + +## black-primer + +`black-primer` is a tool built for CI (and humans) to have _Black_ `--check` a number of +(configured in `primer.json`) Git accessible projects in parallel. +[black_primer](https://github.com/psf/black/blob/master/docs/black_primer.md) has more +information regarding its usage and configuration. + +(A PR adding Mercurial support will be accepted.) + +## Version control integration + +Use [pre-commit](https://pre-commit.com/). Once you +[have it installed](https://pre-commit.com/#install), add this to the +`.pre-commit-config.yaml` in your repository: + +```yaml +repos: + - repo: https://github.com/psf/black + rev: 19.10b0 # Replace by any tag/version: https://github.com/psf/black/tags + hooks: + - id: black + language_version: python3 # Should be a command that runs python3.6+ +``` + +Then run `pre-commit install` and you're ready to go. + +Avoid using `args` in the hook. Instead, store necessary configuration in +`pyproject.toml` so that editors and command-line usage of Black all behave consistently +for your project. See _Black_'s own +[pyproject.toml](https://github.com/psf/black/blob/master/pyproject.toml) for an +example. + +If you're already using Python 3.7, switch the `language_version` accordingly. Finally, +`stable` is a branch that tracks the latest release on PyPI. If you'd rather run on +master, this is also an option. + +## GitHub Actions + +Create a file named `.github/workflows/black.yml` inside your repository with: + +```yaml +name: Lint + +on: [push, pull_request] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + - uses: psf/black@stable +``` + +## Ignoring unmodified files + +_Black_ remembers files it has already formatted, unless the `--diff` flag is used or +code is passed via standard input. This information is stored per-user. The exact +location of the file depends on the _Black_ version and the system on which _Black_ is +run. The file is non-portable. The standard location on common operating systems is: + +- Windows: + `C:\\Users\\AppData\Local\black\black\Cache\\cache...pickle` +- macOS: + `/Users//Library/Caches/black//cache...pickle` +- Linux: + `/home//.cache/black//cache...pickle` + +`file-mode` is an int flag that determines whether the file was formatted as 3.6+ only, +as .pyi, and whether string normalization was omitted. + +To override the location of these files on macOS or Linux, set the environment variable +`XDG_CACHE_HOME` to your preferred location. For example, if you want to put the cache +in the directory you're running _Black_ from, set `XDG_CACHE_HOME=.cache`. _Black_ will +then write the above files to `.cache/black//`. + +## Used by + +The following notable open-source projects trust _Black_ with enforcing a consistent +code style: pytest, tox, Pyramid, Django Channels, Hypothesis, attrs, SQLAlchemy, +Poetry, PyPA applications (Warehouse, Bandersnatch, Pipenv, virtualenv), pandas, Pillow, +every Datadog Agent Integration, Home Assistant. + +The following organizations use _Black_: Facebook, Dropbox, Mozilla, Quora. + +Are we missing anyone? Let us know. + +## Testimonials + +**Dusty Phillips**, +[writer](https://smile.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Daps&field-keywords=dusty+phillips): + +> _Black_ is opinionated so you don't have to be. + +**Hynek Schlawack**, [creator of `attrs`](https://www.attrs.org/), core developer of +Twisted and CPython: + +> An auto-formatter that doesn't suck is all I want for Xmas! + +**Carl Meyer**, [Django](https://www.djangoproject.com/) core developer: + +> At least the name is good. + +**Kenneth Reitz**, creator of [`requests`](http://python-requests.org/) and +[`pipenv`](https://readthedocs.org/projects/pipenv/): + +> This vastly improves the formatting of our code. Thanks a ton! + +## Show your style + +Use the badge in your project's README.md: + +```md +[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) +``` + +Using the badge in README.rst: + +``` +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/psf/black +``` + +Looks like this: +[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) + +## License + +MIT + +## Contributing to _Black_ + +In terms of inspiration, _Black_ is about as configurable as _gofmt_. This is +deliberate. + +Bug reports and fixes are always welcome! However, before you suggest a new feature or +configuration knob, ask yourself why you want it. If it enables better integration with +some workflow, fixes an inconsistency, speeds things up, and so on - go for it! On the +other hand, if your answer is "because I don't like a particular formatting" then you're +not ready to embrace _Black_ yet. Such changes are unlikely to get accepted. You can +still try but prepare to be disappointed. + +More details can be found in +[CONTRIBUTING](https://github.com/psf/black/blob/master/CONTRIBUTING.md). + +## Change log + +The log's become rather long. It moved to its own file. + +See [CHANGES](https://github.com/psf/black/blob/master/CHANGES.md). + +## Authors + +Glued together by [Łukasz Langa](mailto:lukasz@langa.pl). + +Maintained with [Carol Willing](mailto:carolcode@willingconsulting.com), +[Carl Meyer](mailto:carl@oddbird.net), +[Jelle Zijlstra](mailto:jelle.zijlstra@gmail.com), +[Mika Naylor](mailto:mail@autophagy.io), +[Zsolt Dollenstein](mailto:zsol.zsol@gmail.com), and +[Cooper Lees](mailto:me@cooperlees.com). + +Multiple contributions by: + +- [Abdur-Rahmaan Janhangeer](mailto:arj.python@gmail.com) +- [Adam Johnson](mailto:me@adamj.eu) +- [Adam Williamson](mailto:adamw@happyassassin.net) +- [Alexander Huynh](mailto:github@grande.coffee) +- [Alex Vandiver](mailto:github@chmrr.net) +- [Allan Simon](mailto:allan.simon@supinfo.com) +- Anders-Petter Ljungquist +- [Andrew Thorp](mailto:andrew.thorp.dev@gmail.com) +- [Andrew Zhou](mailto:andrewfzhou@gmail.com) +- [Andrey](mailto:dyuuus@yandex.ru) +- [Andy Freeland](mailto:andy@andyfreeland.net) +- [Anthony Sottile](mailto:asottile@umich.edu) +- [Arjaan Buijk](mailto:arjaan.buijk@gmail.com) +- [Arnav Borbornah](mailto:arnavborborah11@gmail.com) +- [Artem Malyshev](mailto:proofit404@gmail.com) +- [Asger Hautop Drewsen](mailto:asgerdrewsen@gmail.com) +- [Augie Fackler](mailto:raf@durin42.com) +- [Aviskar KC](mailto:aviskarkc10@gmail.com) +- Batuhan Taşkaya +- [Benjamin Wohlwend](mailto:bw@piquadrat.ch) +- [Benjamin Woodruff](mailto:github@benjam.info) +- [Bharat Raghunathan](mailto:bharatraghunthan9767@gmail.com) +- [Brandt Bucher](mailto:brandtbucher@gmail.com) +- [Brett Cannon](mailto:brett@python.org) +- [Bryan Bugyi](mailto:bryan.bugyi@rutgers.edu) +- [Bryan Forbes](mailto:bryan@reigndropsfall.net) +- [Calum Lind](mailto:calumlind@gmail.com) +- [Charles](mailto:peacech@gmail.com) +- Charles Reid +- [Christian Clauss](mailto:cclauss@bluewin.ch) +- [Christian Heimes](mailto:christian@python.org) +- [Chuck Wooters](mailto:chuck.wooters@microsoft.com) +- [Chris Rose](mailto:offline@offby1.net) +- Codey Oxley +- [Cong](mailto:congusbongus@gmail.com) +- [Cooper Ry Lees](mailto:me@cooperlees.com) +- [Dan Davison](mailto:dandavison7@gmail.com) +- [Daniel Hahler](mailto:github@thequod.de) +- [Daniel M. Capella](mailto:polycitizen@gmail.com) +- Daniele Esposti +- [David Hotham](mailto:david.hotham@metaswitch.com) +- [David Lukes](mailto:dafydd.lukes@gmail.com) +- [David Szotten](mailto:davidszotten@gmail.com) +- [Denis Laxalde](mailto:denis@laxalde.org) +- [Douglas Thor](mailto:dthor@transphormusa.com) +- dylanjblack +- [Eli Treuherz](mailto:eli@treuherz.com) +- [Emil Hessman](mailto:emil@hessman.se) +- [Felix Kohlgrüber](mailto:felix.kohlgrueber@gmail.com) +- [Florent Thiery](mailto:fthiery@gmail.com) +- Francisco +- [Giacomo Tagliabue](mailto:giacomo.tag@gmail.com) +- [Greg Gandenberger](mailto:ggandenberger@shoprunner.com) +- [Gregory P. Smith](mailto:greg@krypto.org) +- Gustavo Camargo +- hauntsaninja +- [Heaford](mailto:dan@heaford.com) +- [Hugo Barrera](mailto::hugo@barrera.io) +- Hugo van Kemenade +- [Hynek Schlawack](mailto:hs@ox.cx) +- [Ivan Katanić](mailto:ivan.katanic@gmail.com) +- [Jakub Kadlubiec](mailto:jakub.kadlubiec@skyscanner.net) +- [Jakub Warczarek](mailto:jakub.warczarek@gmail.com) +- [Jan Hnátek](mailto:jan.hnatek@gmail.com) +- [Jason Fried](mailto:me@jasonfried.info) +- [Jason Friedland](mailto:jason@friedland.id.au) +- [jgirardet](mailto:ijkl@netc.fr) +- Jim Brännlund +- [Jimmy Jia](mailto:tesrin@gmail.com) +- [Joe Antonakakis](mailto:jma353@cornell.edu) +- [Jon Dufresne](mailto:jon.dufresne@gmail.com) +- [Jonas Obrist](mailto:ojiidotch@gmail.com) +- [Jonty Wareing](mailto:jonty@jonty.co.uk) +- [Jose Nazario](mailto:jose.monkey.org@gmail.com) +- [Joseph Larson](mailto:larson.joseph@gmail.com) +- [Josh Bode](mailto:joshbode@fastmail.com) +- [Josh Holland](mailto:anowlcalledjosh@gmail.com) +- [José Padilla](mailto:jpadilla@webapplicate.com) +- [Juan Luis Cano Rodríguez](mailto:hello@juanlu.space) +- [kaiix](mailto:kvn.hou@gmail.com) +- [Katie McLaughlin](mailto:katie@glasnt.com) +- Katrin Leinweber +- [Keith Smiley](mailto:keithbsmiley@gmail.com) +- [Kenyon Ralph](mailto:kenyon@kenyonralph.com) +- [Kevin Kirsche](mailto:Kev.Kirsche+GitHub@gmail.com) +- [Kyle Hausmann](mailto:kyle.hausmann@gmail.com) +- [Kyle Sunden](mailto:sunden@wisc.edu) +- Lawrence Chan +- [Linus Groh](mailto:mail@linusgroh.de) +- [Loren Carvalho](mailto:comradeloren@gmail.com) +- [Luka Sterbic](mailto:luka.sterbic@gmail.com) +- [LukasDrude](mailto:mail@lukas-drude.de) +- Mahmoud Hossam +- Mariatta +- [Matt VanEseltine](mailto:vaneseltine@gmail.com) +- [Matthew Clapp](mailto:itsayellow+dev@gmail.com) +- [Matthew Walster](mailto:matthew@walster.org) +- Max Smolens +- [Michael Aquilina](mailto:michaelaquilina@gmail.com) +- [Michael Flaxman](mailto:michael.flaxman@gmail.com) +- [Michael J. Sullivan](mailto:sully@msully.net) +- [Michael McClimon](mailto:michael@mcclimon.org) +- [Miguel Gaiowski](mailto:miggaiowski@gmail.com) +- [Mike](mailto:roshi@fedoraproject.org) +- [mikehoyio](mailto:mikehoy@gmail.com) +- [Min ho Kim](mailto:minho42@gmail.com) +- [Miroslav Shubernetskiy](mailto:miroslav@miki725.com) +- MomIsBestFriend +- [Nathan Goldbaum](mailto:ngoldbau@illinois.edu) +- [Nathan Hunt](mailto:neighthan.hunt@gmail.com) +- [Neraste](mailto:neraste.herr10@gmail.com) +- [Nikolaus Waxweiler](mailto:madigens@gmail.com) +- [Ofek Lev](mailto:ofekmeister@gmail.com) +- [Osaetin Daniel](mailto:osaetindaniel@gmail.com) +- [otstrel](mailto:otstrel@gmail.com) +- [Pablo Galindo](mailto:Pablogsal@gmail.com) +- [Paul Ganssle](mailto:p.ganssle@gmail.com) +- [Paul Meinhardt](mailto:mnhrdt@gmail.com) +- [Peter Bengtsson](mailto:mail@peterbe.com) +- [Peter Stensmyr](mailto:peter.stensmyr@gmail.com) +- pmacosta +- [Quentin Pradet](mailto:quentin@pradet.me) +- [Ralf Schmitt](mailto:ralf@systemexit.de) +- [Ramón Valles](mailto:mroutis@protonmail.com) +- [Richard Fearn](mailto:richardfearn@gmail.com) +- Richard Si +- [Rishikesh Jha](mailto:rishijha424@gmail.com) +- [Rupert Bedford](mailto:rupert@rupertb.com) +- Russell Davis +- [Rémi Verschelde](mailto:rverschelde@gmail.com) +- [Sami Salonen](mailto:sakki@iki.fi) +- [Samuel Cormier-Iijima](mailto:samuel@cormier-iijima.com) +- [Sanket Dasgupta](mailto:sanketdasgupta@gmail.com) +- Sergi +- [Scott Stevenson](mailto:scott@stevenson.io) +- Shantanu +- [shaoran](mailto:shaoran@sakuranohana.org) +- [Shinya Fujino](mailto:shf0811@gmail.com) +- springstan +- [Stavros Korokithakis](mailto:hi@stavros.io) +- [Stephen Rosen](mailto:sirosen@globus.org) +- [Steven M. Vascellaro](mailto:S.Vascellaro@gmail.com) +- [Sunil Kapil](mailto:snlkapil@gmail.com) +- [Sébastien Eustace](mailto:sebastien.eustace@gmail.com) +- [Tal Amuyal](mailto:TalAmuyal@gmail.com) +- [Terrance](mailto:git@terrance.allofti.me) +- [Thom Lu](mailto:thomas.c.lu@gmail.com) +- [Thomas Grainger](mailto:tagrain@gmail.com) +- [Tim Gates](mailto:tim.gates@iress.com) +- [Tim Swast](mailto:swast@google.com) +- [Timo](mailto:timo_tk@hotmail.com) +- Toby Fleming +- [Tom Christie](mailto:tom@tomchristie.com) +- [Tony Narlock](mailto:tony@git-pull.com) +- [Tsuyoshi Hombashi](mailto:tsuyoshi.hombashi@gmail.com) +- [Tushar Chandra](mailto:tusharchandra2018@u.northwestern.edu) +- [Tzu-ping Chung](mailto:uranusjr@gmail.com) +- [Utsav Shah](mailto:ukshah2@illinois.edu) +- utsav-dbx +- vezeli +- [Ville Skyttä](mailto:ville.skytta@iki.fi) +- [Vishwas B Sharma](mailto:sharma.vishwas88@gmail.com) +- [Vlad Emelianov](mailto:volshebnyi@gmail.com) +- [williamfzc](mailto:178894043@qq.com) +- [wouter bolsterlee](mailto:wouter@bolsterl.ee) +- Yazdan +- [Yngve Høiseth](mailto:yngve@hoiseth.net) +- [Yurii Karabas](mailto:1998uriyyo@gmail.com) +- [Zac Hatfield-Dodds](mailto:zac@zhd.dev) + + +## Change Log + +### 20.8b1 + +#### _Packaging_ + +- explicitly depend on Click 7.1.2 or newer as `Black` no longer works with versions + older than 7.0 + +### 20.8b0 + +#### _Black_ + +- re-implemented support for explicit trailing commas: now it works consistently within + any bracket pair, including nested structures (#1288 and duplicates) + +- `Black` now reindents docstrings when reindenting code around it (#1053) + +- `Black` now shows colored diffs (#1266) + +- `Black` is now packaged using 'py3' tagged wheels (#1388) + +- `Black` now supports Python 3.8 code, e.g. star expressions in return statements + (#1121) + +- `Black` no longer normalizes capital R-string prefixes as those have a + community-accepted meaning (#1244) + +- `Black` now uses exit code 2 when specified configuration file doesn't exit (#1361) + +- `Black` now works on AWS Lambda (#1141) + +- added `--force-exclude` argument (#1032) + +- removed deprecated `--py36` option (#1236) + +- fixed `--diff` output when EOF is encountered (#526) + +- fixed `# fmt: off` handling around decorators (#560) + +- fixed unstable formatting with some `# type: ignore` comments (#1113) + +- fixed invalid removal on organizing brackets followed by indexing (#1575) + +- introduced `black-primer`, a CI tool that allows us to run regression tests against + existing open source users of Black (#1402) + +- introduced property-based fuzzing to our test suite based on Hypothesis and + Hypothersmith (#1566) + +- implemented experimental and disabled by default long string rewrapping (#1132), + hidden under a `--experimental-string-processing` flag while it's being worked on; + this is an undocumented and unsupported feature, you lose Internet points for + depending on it (#1609) + +#### Vim plugin + +- prefer virtualenv packages over global packages (#1383) + +### 19.10b0 + +- added support for PEP 572 assignment expressions (#711) + +- added support for PEP 570 positional-only arguments (#943) + +- added support for async generators (#593) + +- added support for pre-splitting collections by putting an explicit trailing comma + inside (#826) + +- added `black -c` as a way to format code passed from the command line (#761) + +- --safe now works with Python 2 code (#840) + +- fixed grammar selection for Python 2-specific code (#765) + +- fixed feature detection for trailing commas in function definitions and call sites + (#763) + +- `# fmt: off`/`# fmt: on` comment pairs placed multiple times within the same block of + code now behave correctly (#1005) + +- _Black_ no longer crashes on Windows machines with more than 61 cores (#838) + +- _Black_ no longer crashes on standalone comments prepended with a backslash (#767) + +- _Black_ no longer crashes on `from` ... `import` blocks with comments (#829) + +- _Black_ no longer crashes on Python 3.7 on some platform configurations (#494) + +- _Black_ no longer fails on comments in from-imports (#671) + +- _Black_ no longer fails when the file starts with a backslash (#922) + +- _Black_ no longer merges regular comments with type comments (#1027) + +- _Black_ no longer splits long lines that contain type comments (#997) + +- removed unnecessary parentheses around `yield` expressions (#834) + +- added parentheses around long tuples in unpacking assignments (#832) + +- added parentheses around complex powers when they are prefixed by a unary operator + (#646) + +- fixed bug that led _Black_ format some code with a line length target of 1 (#762) + +- _Black_ no longer introduces quotes in f-string subexpressions on string boundaries + (#863) + +- if _Black_ puts parenthesis around a single expression, it moves comments to the + wrapped expression instead of after the brackets (#872) + +- `blackd` now returns the version of _Black_ in the response headers (#1013) + +- `blackd` can now output the diff of formats on source code when the `X-Diff` header is + provided (#969) + +### 19.3b0 + +- new option `--target-version` to control which Python versions _Black_-formatted code + should target (#618) + +- deprecated `--py36` (use `--target-version=py36` instead) (#724) + +- _Black_ no longer normalizes numeric literals to include `_` separators (#696) + +- long `del` statements are now split into multiple lines (#698) + +- type comments are no longer mangled in function signatures + +- improved performance of formatting deeply nested data structures (#509) + +- _Black_ now properly formats multiple files in parallel on Windows (#632) + +- _Black_ now creates cache files atomically which allows it to be used in parallel + pipelines (like `xargs -P8`) (#673) + +- _Black_ now correctly indents comments in files that were previously formatted with + tabs (#262) + +- `blackd` now supports CORS (#622) + +### 18.9b0 + +- numeric literals are now formatted by _Black_ (#452, #461, #464, #469): + + - numeric literals are normalized to include `_` separators on Python 3.6+ code + + - added `--skip-numeric-underscore-normalization` to disable the above behavior and + leave numeric underscores as they were in the input + + - code with `_` in numeric literals is recognized as Python 3.6+ + + - most letters in numeric literals are lowercased (e.g., in `1e10`, `0x01`) + + - hexadecimal digits are always uppercased (e.g. `0xBADC0DE`) + +- added `blackd`, see [its documentation](#blackd) for more info (#349) + +- adjacent string literals are now correctly split into multiple lines (#463) + +- trailing comma is now added to single imports that don't fit on a line (#250) + +- cache is now populated when `--check` is successful for a file which speeds up + consecutive checks of properly formatted unmodified files (#448) + +- whitespace at the beginning of the file is now removed (#399) + +- fixed mangling [pweave](http://mpastell.com/pweave/) and + [Spyder IDE](https://www.spyder-ide.org/) special comments (#532) + +- fixed unstable formatting when unpacking big tuples (#267) + +- fixed parsing of `__future__` imports with renames (#389) + +- fixed scope of `# fmt: off` when directly preceding `yield` and other nodes (#385) + +- fixed formatting of lambda expressions with default arguments (#468) + +- fixed `async for` statements: _Black_ no longer breaks them into separate lines (#372) + +- note: the Vim plugin stopped registering `,=` as a default chord as it turned out to + be a bad idea (#415) + +### 18.6b4 + +- hotfix: don't freeze when multiple comments directly precede `# fmt: off` (#371) + +### 18.6b3 + +- typing stub files (`.pyi`) now have blank lines added after constants (#340) + +- `# fmt: off` and `# fmt: on` are now much more dependable: + + - they now work also within bracket pairs (#329) + + - they now correctly work across function/class boundaries (#335) + + - they now work when an indentation block starts with empty lines or misaligned + comments (#334) + +- made Click not fail on invalid environments; note that Click is right but the + likelihood we'll need to access non-ASCII file paths when dealing with Python source + code is low (#277) + +- fixed improper formatting of f-strings with quotes inside interpolated expressions + (#322) + +- fixed unnecessary slowdown when long list literals where found in a file + +- fixed unnecessary slowdown on AST nodes with very many siblings + +- fixed cannibalizing backslashes during string normalization + +- fixed a crash due to symbolic links pointing outside of the project directory (#338) + +### 18.6b2 + +- added `--config` (#65) + +- added `-h` equivalent to `--help` (#316) + +- fixed improper unmodified file caching when `-S` was used + +- fixed extra space in string unpacking (#305) + +- fixed formatting of empty triple quoted strings (#313) + +- fixed unnecessary slowdown in comment placement calculation on lines without comments + +### 18.6b1 + +- hotfix: don't output human-facing information on stdout (#299) + +- hotfix: don't output cake emoji on non-zero return code (#300) + +### 18.6b0 + +- added `--include` and `--exclude` (#270) + +- added `--skip-string-normalization` (#118) + +- added `--verbose` (#283) + +- the header output in `--diff` now actually conforms to the unified diff spec + +- fixed long trivial assignments being wrapped in unnecessary parentheses (#273) + +- fixed unnecessary parentheses when a line contained multiline strings (#232) + +- fixed stdin handling not working correctly if an old version of Click was used (#276) + +- _Black_ now preserves line endings when formatting a file in place (#258) + +### 18.5b1 + +- added `--pyi` (#249) + +- added `--py36` (#249) + +- Python grammar pickle caches are stored with the formatting caches, making _Black_ + work in environments where site-packages is not user-writable (#192) + +- _Black_ now enforces a PEP 257 empty line after a class-level docstring (and/or + fields) and the first method + +- fixed invalid code produced when standalone comments were present in a trailer that + was omitted from line splitting on a large expression (#237) + +- fixed optional parentheses being removed within `# fmt: off` sections (#224) + +- fixed invalid code produced when stars in very long imports were incorrectly wrapped + in optional parentheses (#234) + +- fixed unstable formatting when inline comments were moved around in a trailer that was + omitted from line splitting on a large expression (#238) + +- fixed extra empty line between a class declaration and the first method if no class + docstring or fields are present (#219) + +- fixed extra empty line between a function signature and an inner function or inner + class (#196) + +### 18.5b0 + +- call chains are now formatted according to the + [fluent interfaces](https://en.wikipedia.org/wiki/Fluent_interface) style (#67) + +- data structure literals (tuples, lists, dictionaries, and sets) are now also always + exploded like imports when they don't fit in a single line (#152) + +- slices are now formatted according to PEP 8 (#178) + +- parentheses are now also managed automatically on the right-hand side of assignments + and return statements (#140) + +- math operators now use their respective priorities for delimiting multiline + expressions (#148) + +- optional parentheses are now omitted on expressions that start or end with a bracket + and only contain a single operator (#177) + +- empty parentheses in a class definition are now removed (#145, #180) + +- string prefixes are now standardized to lowercase and `u` is removed on Python 3.6+ + only code and Python 2.7+ code with the `unicode_literals` future import (#188, #198, + #199) + +- typing stub files (`.pyi`) are now formatted in a style that is consistent with PEP + 484 (#207, #210) + +- progress when reformatting many files is now reported incrementally + +- fixed trailers (content with brackets) being unnecessarily exploded into their own + lines after a dedented closing bracket (#119) + +- fixed an invalid trailing comma sometimes left in imports (#185) + +- fixed non-deterministic formatting when multiple pairs of removable parentheses were + used (#183) + +- fixed multiline strings being unnecessarily wrapped in optional parentheses in long + assignments (#215) + +- fixed not splitting long from-imports with only a single name + +- fixed Python 3.6+ file discovery by also looking at function calls with unpacking. + This fixed non-deterministic formatting if trailing commas where used both in function + signatures with stars and function calls with stars but the former would be + reformatted to a single line. + +- fixed crash on dealing with optional parentheses (#193) + +- fixed "is", "is not", "in", and "not in" not considered operators for splitting + purposes + +- fixed crash when dead symlinks where encountered + +### 18.4a4 + +- don't populate the cache on `--check` (#175) + +### 18.4a3 + +- added a "cache"; files already reformatted that haven't changed on disk won't be + reformatted again (#109) + +- `--check` and `--diff` are no longer mutually exclusive (#149) + +- generalized star expression handling, including double stars; this fixes + multiplication making expressions "unsafe" for trailing commas (#132) + +- _Black_ no longer enforces putting empty lines behind control flow statements (#90) + +- _Black_ now splits imports like "Mode 3 + trailing comma" of isort (#127) + +- fixed comment indentation when a standalone comment closes a block (#16, #32) + +- fixed standalone comments receiving extra empty lines if immediately preceding a + class, def, or decorator (#56, #154) + +- fixed `--diff` not showing entire path (#130) + +- fixed parsing of complex expressions after star and double stars in function calls + (#2) + +- fixed invalid splitting on comma in lambda arguments (#133) + +- fixed missing splits of ternary expressions (#141) + +### 18.4a2 + +- fixed parsing of unaligned standalone comments (#99, #112) + +- fixed placement of dictionary unpacking inside dictionary literals (#111) + +- Vim plugin now works on Windows, too + +- fixed unstable formatting when encountering unnecessarily escaped quotes in a string + (#120) + +### 18.4a1 + +- added `--quiet` (#78) + +- added automatic parentheses management (#4) + +- added [pre-commit](https://pre-commit.com) integration (#103, #104) + +- fixed reporting on `--check` with multiple files (#101, #102) + +- fixed removing backslash escapes from raw strings (#100, #105) + +### 18.4a0 + +- added `--diff` (#87) + +- add line breaks before all delimiters, except in cases like commas, to better comply + with PEP 8 (#73) + +- standardize string literals to use double quotes (almost) everywhere (#75) + +- fixed handling of standalone comments within nested bracketed expressions; _Black_ + will no longer produce super long lines or put all standalone comments at the end of + the expression (#22) + +- fixed 18.3a4 regression: don't crash and burn on empty lines with trailing whitespace + (#80) + +- fixed 18.3a4 regression: `# yapf: disable` usage as trailing comment would cause + _Black_ to not emit the rest of the file (#95) + +- when CTRL+C is pressed while formatting many files, _Black_ no longer freaks out with + a flurry of asyncio-related exceptions + +- only allow up to two empty lines on module level and only single empty lines within + functions (#74) + +### 18.3a4 + +- `# fmt: off` and `# fmt: on` are implemented (#5) + +- automatic detection of deprecated Python 2 forms of print statements and exec + statements in the formatted file (#49) + +- use proper spaces for complex expressions in default values of typed function + arguments (#60) + +- only return exit code 1 when --check is used (#50) + +- don't remove single trailing commas from square bracket indexing (#59) + +- don't omit whitespace if the previous factor leaf wasn't a math operator (#55) + +- omit extra space in kwarg unpacking if it's the first argument (#46) + +- omit extra space in + [Sphinx auto-attribute comments](http://www.sphinx-doc.org/en/stable/ext/autodoc.html#directive-autoattribute) + (#68) + +### 18.3a3 + +- don't remove single empty lines outside of bracketed expressions (#19) + +- added ability to pipe formatting from stdin to stdin (#25) + +- restored ability to format code with legacy usage of `async` as a name (#20, #42) + +- even better handling of numpy-style array indexing (#33, again) + +### 18.3a2 + +- changed positioning of binary operators to occur at beginning of lines instead of at + the end, following + [a recent change to PEP 8](https://github.com/python/peps/commit/c59c4376ad233a62ca4b3a6060c81368bd21e85b) + (#21) + +- ignore empty bracket pairs while splitting. This avoids very weirdly looking + formattings (#34, #35) + +- remove a trailing comma if there is a single argument to a call + +- if top level functions were separated by a comment, don't put four empty lines after + the upper function + +- fixed unstable formatting of newlines with imports + +- fixed unintentional folding of post scriptum standalone comments into last statement + if it was a simple statement (#18, #28) + +- fixed missing space in numpy-style array indexing (#33) + +- fixed spurious space after star-based unary expressions (#31) + +### 18.3a1 + +- added `--check` + +- only put trailing commas in function signatures and calls if it's safe to do so. If + the file is Python 3.6+ it's always safe, otherwise only safe if there are no `*args` + or `**kwargs` used in the signature or call. (#8) + +- fixed invalid spacing of dots in relative imports (#6, #13) + +- fixed invalid splitting after comma on unpacked variables in for-loops (#23) + +- fixed spurious space in parenthesized set expressions (#7) + +- fixed spurious space after opening parentheses and in default arguments (#14, #17) + +- fixed spurious space after unary operators when the operand was a complex expression + (#15) + +### 18.3a0 + +- first published version, Happy 🍰 Day 2018! + +- alpha quality + +- date-versioned (see: https://calver.org/) diff --git a/venv/Lib/site-packages/black-20.8b1.dist-info/RECORD b/venv/Lib/site-packages/black-20.8b1.dist-info/RECORD new file mode 100644 index 0000000..cdf6faa --- /dev/null +++ b/venv/Lib/site-packages/black-20.8b1.dist-info/RECORD @@ -0,0 +1,50 @@ +../../Scripts/black-primer.exe,sha256=Wxc5y8Ae7wh2mhvXy1cHwxfSSlIDO-D4lIBhZZVErD0,108419 +../../Scripts/black.exe,sha256=U3b-GsC512sTB3238AxVUceu5D_PedZ7VzWoO13wkpg,108424 +../../Scripts/blackd.exe,sha256=nu9VVWvFMzKiIP8bKLKLSTstNfTZ0rpsFacWz7Eid3I,108425 +__pycache__/_black_version.cpython-39.pyc,, +_black_version.py,sha256=Vu_KwaySdLsgmQvdLhJq0EnCq411D-0N_SK8Grt3U38,20 +black-20.8b1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +black-20.8b1.dist-info/LICENSE,sha256=nAQo8MO0d5hQz1vZbhGqqK_HLUqG1KNiI9erouWNbgA,1080 +black-20.8b1.dist-info/METADATA,sha256=Byh5pw0cwoszEg45nLOky-yMc9OxMTy0rbMIzpAs3Sc,48192 +black-20.8b1.dist-info/RECORD,, +black-20.8b1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +black-20.8b1.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92 +black-20.8b1.dist-info/entry_points.txt,sha256=-F12nJfxVtaq2X5PXAmGLfBYU_B3OXrv5GX2kxzwCJY,115 +black-20.8b1.dist-info/top_level.txt,sha256=jGkYA_03ZBzJOsfB7YnyswRCARxXZRcCbzc3pugKwew,50 +black/__init__.py,sha256=jV4lN68cGFoApK06Lmv-oHoCesvbL6EQ4TCxpmsJPOg,230988 +black/__main__.py,sha256=mogeA4o9zt4w-ufKvaQjSEhtSgQkcMVLK9ChvdB5wH8,47 +black/__pycache__/__init__.cpython-39.pyc,, +black/__pycache__/__main__.cpython-39.pyc,, +black/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 +black_primer/__pycache__/cli.cpython-39.pyc,, +black_primer/__pycache__/lib.cpython-39.pyc,, +black_primer/cli.py,sha256=qMSRkjX3wTK_5Kr3TfSELK0AzfHIQkpbnQdHGg4ahe8,3220 +black_primer/lib.py,sha256=KM9pB3KDSZyv3rvlEcPBN-U-biPBisELyijpM6_a1Jk,11098 +blackd/__init__.py,sha256=JCxaK4hLkMRwVfZMj8FRpRRYC0172-juKqbN22bISLE,6672 +blackd/__pycache__/__init__.cpython-39.pyc,, +blib2to3/Grammar.txt,sha256=2CsB0CgiKAMdyUxlvQlLlAD0J6Hy3Kha-wIy8rfqqWw,9648 +blib2to3/PatternGrammar.txt,sha256=7lul2ztnIqDi--JWDrwciD5yMo75w7TaHHxdHMZJvOM,793 +blib2to3/__init__.py,sha256=9_8wL9Scv8_Cs8HJyJHGvx1vwXErsuvlsAqNZLcJQR0,8 +blib2to3/__pycache__/__init__.cpython-39.pyc,, +blib2to3/__pycache__/pygram.cpython-39.pyc,, +blib2to3/__pycache__/pytree.cpython-39.pyc,, +blib2to3/pgen2/__init__.py,sha256=hY6w9QUzvTvRb-MoFfd_q_7ZLt6IUHC2yxWCfsZupQA,143 +blib2to3/pgen2/__pycache__/__init__.cpython-39.pyc,, +blib2to3/pgen2/__pycache__/conv.cpython-39.pyc,, +blib2to3/pgen2/__pycache__/driver.cpython-39.pyc,, +blib2to3/pgen2/__pycache__/grammar.cpython-39.pyc,, +blib2to3/pgen2/__pycache__/literals.cpython-39.pyc,, +blib2to3/pgen2/__pycache__/parse.cpython-39.pyc,, +blib2to3/pgen2/__pycache__/pgen.cpython-39.pyc,, +blib2to3/pgen2/__pycache__/token.cpython-39.pyc,, +blib2to3/pgen2/__pycache__/tokenize.cpython-39.pyc,, +blib2to3/pgen2/conv.py,sha256=CyP0XsoRNvg-aPBYeq3MZKDeifwU-pn_8lmsZYh4Vgc,9616 +blib2to3/pgen2/driver.py,sha256=T5EVi9UifsQnlo6kMW6uXbLP5q8-z0WDZsCtxM5Tw3g,8559 +blib2to3/pgen2/grammar.py,sha256=Uo2Vq4fmyz_ASSrLZsMDYcCw_6AjrwcGlebdbzbvw60,6714 +blib2to3/pgen2/literals.py,sha256=vbzw1RX0NvATBR971WwRNtp68fsXky4-pV4cBZ02_9E,1628 +blib2to3/pgen2/parse.py,sha256=sYaafJxjPI1QtmzQ8ma5E-aUcKau62xKNRH2lxjXFgI,9061 +blib2to3/pgen2/pgen.py,sha256=arjJwrKNu0h72X_kM_wK0js7LtBYEoXcNLTrFnmS80w,15387 +blib2to3/pgen2/token.py,sha256=_1qwiLFzfVmn39HNpmKzGLILQbBm_Van_zFSwuVH70s,1838 +blib2to3/pgen2/tokenize.py,sha256=I5TQdFF9azv46dEWS3Djgbjfc2FXiUSXatRP6Snih-s,22689 +blib2to3/pygram.py,sha256=TdtI_UR8v4_6fSrBZkfxWpTV-NHm9p3Amk_jE5jsdEk,4984 +blib2to3/pytree.py,sha256=FIP19CLLQ4xN8n0r0AzgqwOoHsHQphJhkaBm3gWaWdY,31743 diff --git a/venv/Lib/site-packages/black-20.8b1.dist-info/REQUESTED b/venv/Lib/site-packages/black-20.8b1.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/black-20.8b1.dist-info/WHEEL b/venv/Lib/site-packages/black-20.8b1.dist-info/WHEEL new file mode 100644 index 0000000..57e3d84 --- /dev/null +++ b/venv/Lib/site-packages/black-20.8b1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.38.4) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/black-20.8b1.dist-info/entry_points.txt b/venv/Lib/site-packages/black-20.8b1.dist-info/entry_points.txt new file mode 100644 index 0000000..96efbd9 --- /dev/null +++ b/venv/Lib/site-packages/black-20.8b1.dist-info/entry_points.txt @@ -0,0 +1,4 @@ +[console_scripts] +black = black:patched_main +black-primer = black_primer.cli:main +blackd = blackd:patched_main [d] diff --git a/venv/Lib/site-packages/black-20.8b1.dist-info/top_level.txt b/venv/Lib/site-packages/black-20.8b1.dist-info/top_level.txt new file mode 100644 index 0000000..edff6bd --- /dev/null +++ b/venv/Lib/site-packages/black-20.8b1.dist-info/top_level.txt @@ -0,0 +1,5 @@ +_black_version +black +black_primer +blackd +blib2to3 diff --git a/venv/Lib/site-packages/click-8.1.3.dist-info/INSTALLER b/venv/Lib/site-packages/click-8.1.3.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/click-8.1.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/click-8.1.3.dist-info/LICENSE.rst b/venv/Lib/site-packages/click-8.1.3.dist-info/LICENSE.rst new file mode 100644 index 0000000..d12a849 --- /dev/null +++ b/venv/Lib/site-packages/click-8.1.3.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2014 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/Lib/site-packages/click-8.1.3.dist-info/METADATA b/venv/Lib/site-packages/click-8.1.3.dist-info/METADATA new file mode 100644 index 0000000..8e5dc1e --- /dev/null +++ b/venv/Lib/site-packages/click-8.1.3.dist-info/METADATA @@ -0,0 +1,111 @@ +Metadata-Version: 2.1 +Name: click +Version: 8.1.3 +Summary: Composable command line interface toolkit +Home-page: https://palletsprojects.com/p/click/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://click.palletsprojects.com/ +Project-URL: Changes, https://click.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/click/ +Project-URL: Issue Tracker, https://github.com/pallets/click/issues/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +Project-URL: Chat, https://discord.gg/pallets +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst +Requires-Dist: colorama ; platform_system == "Windows" +Requires-Dist: importlib-metadata ; python_version < "3.8" + +\$ click\_ +========== + +Click is a Python package for creating beautiful command line interfaces +in a composable way with as little code as necessary. It's the "Command +Line Interface Creation Kit". It's highly configurable but comes with +sensible defaults out of the box. + +It aims to make the process of writing command line tools quick and fun +while also preventing any frustration caused by the inability to +implement an intended CLI API. + +Click in three points: + +- Arbitrary nesting of commands +- Automatic help page generation +- Supports lazy loading of subcommands at runtime + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + $ pip install -U click + +.. _pip: https://pip.pypa.io/en/stable/getting-started/ + + +A Simple Example +---------------- + +.. code-block:: python + + import click + + @click.command() + @click.option("--count", default=1, help="Number of greetings.") + @click.option("--name", prompt="Your name", help="The person to greet.") + def hello(count, name): + """Simple program that greets NAME for a total of COUNT times.""" + for _ in range(count): + click.echo(f"Hello, {name}!") + + if __name__ == '__main__': + hello() + +.. code-block:: text + + $ python hello.py --count=3 + Your name: Click + Hello, Click! + Hello, Click! + Hello, Click! + + +Donate +------ + +The Pallets organization develops and supports Click and other popular +packages. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, `please +donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://click.palletsprojects.com/ +- Changes: https://click.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/click/ +- Source Code: https://github.com/pallets/click +- Issue Tracker: https://github.com/pallets/click/issues +- Website: https://palletsprojects.com/p/click +- Twitter: https://twitter.com/PalletsTeam +- Chat: https://discord.gg/pallets + + diff --git a/venv/Lib/site-packages/click-8.1.3.dist-info/RECORD b/venv/Lib/site-packages/click-8.1.3.dist-info/RECORD new file mode 100644 index 0000000..3ca86f8 --- /dev/null +++ b/venv/Lib/site-packages/click-8.1.3.dist-info/RECORD @@ -0,0 +1,39 @@ +click-8.1.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +click-8.1.3.dist-info/LICENSE.rst,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475 +click-8.1.3.dist-info/METADATA,sha256=tFJIX5lOjx7c5LjZbdTPFVDJSgyv9F74XY0XCPp_gnc,3247 +click-8.1.3.dist-info/RECORD,, +click-8.1.3.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +click-8.1.3.dist-info/top_level.txt,sha256=J1ZQogalYS4pphY_lPECoNMfw0HzTSrZglC4Yfwo4xA,6 +click/__init__.py,sha256=rQBLutqg-z6m8nOzivIfigDn_emijB_dKv9BZ2FNi5s,3138 +click/__pycache__/__init__.cpython-39.pyc,, +click/__pycache__/_compat.cpython-39.pyc,, +click/__pycache__/_termui_impl.cpython-39.pyc,, +click/__pycache__/_textwrap.cpython-39.pyc,, +click/__pycache__/_winconsole.cpython-39.pyc,, +click/__pycache__/core.cpython-39.pyc,, +click/__pycache__/decorators.cpython-39.pyc,, +click/__pycache__/exceptions.cpython-39.pyc,, +click/__pycache__/formatting.cpython-39.pyc,, +click/__pycache__/globals.cpython-39.pyc,, +click/__pycache__/parser.cpython-39.pyc,, +click/__pycache__/shell_completion.cpython-39.pyc,, +click/__pycache__/termui.cpython-39.pyc,, +click/__pycache__/testing.cpython-39.pyc,, +click/__pycache__/types.cpython-39.pyc,, +click/__pycache__/utils.cpython-39.pyc,, +click/_compat.py,sha256=JIHLYs7Jzz4KT9t-ds4o4jBzLjnwCiJQKqur-5iwCKI,18810 +click/_termui_impl.py,sha256=qK6Cfy4mRFxvxE8dya8RBhLpSC8HjF-lvBc6aNrPdwg,23451 +click/_textwrap.py,sha256=10fQ64OcBUMuK7mFvh8363_uoOxPlRItZBmKzRJDgoY,1353 +click/_winconsole.py,sha256=5ju3jQkcZD0W27WEMGqmEP4y_crUVzPCqsX_FYb7BO0,7860 +click/core.py,sha256=mz87bYEKzIoNYEa56BFAiOJnvt1Y0L-i7wD4_ZecieE,112782 +click/decorators.py,sha256=yo3zvzgUm5q7h5CXjyV6q3h_PJAiUaem178zXwdWUFI,16350 +click/exceptions.py,sha256=7gDaLGuFZBeCNwY9ERMsF2-Z3R9Fvq09Zc6IZSKjseo,9167 +click/formatting.py,sha256=Frf0-5W33-loyY_i9qrwXR8-STnW3m5gvyxLVUdyxyk,9706 +click/globals.py,sha256=TP-qM88STzc7f127h35TD_v920FgfOD2EwzqA0oE8XU,1961 +click/parser.py,sha256=cAEt1uQR8gq3-S9ysqbVU-fdAZNvilxw4ReJ_T1OQMk,19044 +click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +click/shell_completion.py,sha256=qOp_BeC9esEOSZKyu5G7RIxEUaLsXUX-mTb7hB1r4QY,18018 +click/termui.py,sha256=ACBQVOvFCTSqtD5VREeCAdRtlHd-Imla-Lte4wSfMjA,28355 +click/testing.py,sha256=ptpMYgRY7dVfE3UDgkgwayu9ePw98sQI3D7zZXiCpj4,16063 +click/types.py,sha256=rEb1aZSQKq3ciCMmjpG2Uva9vk498XRL7ThrcK2GRss,35805 +click/utils.py,sha256=33D6E7poH_nrKB-xr-UyDEXnxOcCiQqxuRLtrqeVv6o,18682 diff --git a/venv/Lib/site-packages/click-8.1.3.dist-info/WHEEL b/venv/Lib/site-packages/click-8.1.3.dist-info/WHEEL new file mode 100644 index 0000000..becc9a6 --- /dev/null +++ b/venv/Lib/site-packages/click-8.1.3.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/click-8.1.3.dist-info/top_level.txt b/venv/Lib/site-packages/click-8.1.3.dist-info/top_level.txt new file mode 100644 index 0000000..dca9a90 --- /dev/null +++ b/venv/Lib/site-packages/click-8.1.3.dist-info/top_level.txt @@ -0,0 +1 @@ +click diff --git a/venv/Lib/site-packages/colorama-0.4.6.dist-info/INSTALLER b/venv/Lib/site-packages/colorama-0.4.6.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/colorama-0.4.6.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/colorama-0.4.6.dist-info/METADATA b/venv/Lib/site-packages/colorama-0.4.6.dist-info/METADATA new file mode 100644 index 0000000..a1b5c57 --- /dev/null +++ b/venv/Lib/site-packages/colorama-0.4.6.dist-info/METADATA @@ -0,0 +1,441 @@ +Metadata-Version: 2.1 +Name: colorama +Version: 0.4.6 +Summary: Cross-platform colored terminal text. +Project-URL: Homepage, https://github.com/tartley/colorama +Author-email: Jonathan Hartley +License-File: LICENSE.txt +Keywords: ansi,color,colour,crossplatform,terminal,text,windows,xplatform +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Terminals +Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7 +Description-Content-Type: text/x-rst + +.. image:: https://img.shields.io/pypi/v/colorama.svg + :target: https://pypi.org/project/colorama/ + :alt: Latest Version + +.. image:: https://img.shields.io/pypi/pyversions/colorama.svg + :target: https://pypi.org/project/colorama/ + :alt: Supported Python versions + +.. image:: https://github.com/tartley/colorama/actions/workflows/test.yml/badge.svg + :target: https://github.com/tartley/colorama/actions/workflows/test.yml + :alt: Build Status + +Colorama +======== + +Makes ANSI escape character sequences (for producing colored terminal text and +cursor positioning) work under MS Windows. + +.. |donate| image:: https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif + :target: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=2MZ9D2GMLYCUJ&item_name=Colorama¤cy_code=USD + :alt: Donate with Paypal + +`PyPI for releases `_ | +`Github for source `_ | +`Colorama for enterprise on Tidelift `_ + +If you find Colorama useful, please |donate| to the authors. Thank you! + +Installation +------------ + +Tested on CPython 2.7, 3.7, 3.8, 3.9 and 3.10 and Pypy 2.7 and 3.8. + +No requirements other than the standard library. + +.. code-block:: bash + + pip install colorama + # or + conda install -c anaconda colorama + +Description +----------- + +ANSI escape character sequences have long been used to produce colored terminal +text and cursor positioning on Unix and Macs. Colorama makes this work on +Windows, too, by wrapping ``stdout``, stripping ANSI sequences it finds (which +would appear as gobbledygook in the output), and converting them into the +appropriate win32 calls to modify the state of the terminal. On other platforms, +Colorama does nothing. + +This has the upshot of providing a simple cross-platform API for printing +colored terminal text from Python, and has the happy side-effect that existing +applications or libraries which use ANSI sequences to produce colored output on +Linux or Macs can now also work on Windows, simply by calling +``colorama.just_fix_windows_console()`` (since v0.4.6) or ``colorama.init()`` +(all versions, but may have other side-effects – see below). + +An alternative approach is to install ``ansi.sys`` on Windows machines, which +provides the same behaviour for all applications running in terminals. Colorama +is intended for situations where that isn't easy (e.g., maybe your app doesn't +have an installer.) + +Demo scripts in the source code repository print some colored text using +ANSI sequences. Compare their output under Gnome-terminal's built in ANSI +handling, versus on Windows Command-Prompt using Colorama: + +.. image:: https://github.com/tartley/colorama/raw/master/screenshots/ubuntu-demo.png + :width: 661 + :height: 357 + :alt: ANSI sequences on Ubuntu under gnome-terminal. + +.. image:: https://github.com/tartley/colorama/raw/master/screenshots/windows-demo.png + :width: 668 + :height: 325 + :alt: Same ANSI sequences on Windows, using Colorama. + +These screenshots show that, on Windows, Colorama does not support ANSI 'dim +text'; it looks the same as 'normal text'. + +Usage +----- + +Initialisation +.............. + +If the only thing you want from Colorama is to get ANSI escapes to work on +Windows, then run: + +.. code-block:: python + + from colorama import just_fix_windows_console + just_fix_windows_console() + +If you're on a recent version of Windows 10 or better, and your stdout/stderr +are pointing to a Windows console, then this will flip the magic configuration +switch to enable Windows' built-in ANSI support. + +If you're on an older version of Windows, and your stdout/stderr are pointing to +a Windows console, then this will wrap ``sys.stdout`` and/or ``sys.stderr`` in a +magic file object that intercepts ANSI escape sequences and issues the +appropriate Win32 calls to emulate them. + +In all other circumstances, it does nothing whatsoever. Basically the idea is +that this makes Windows act like Unix with respect to ANSI escape handling. + +It's safe to call this function multiple times. It's safe to call this function +on non-Windows platforms, but it won't do anything. It's safe to call this +function when one or both of your stdout/stderr are redirected to a file – it +won't do anything to those streams. + +Alternatively, you can use the older interface with more features (but also more +potential footguns): + +.. code-block:: python + + from colorama import init + init() + +This does the same thing as ``just_fix_windows_console``, except for the +following differences: + +- It's not safe to call ``init`` multiple times; you can end up with multiple + layers of wrapping and broken ANSI support. + +- Colorama will apply a heuristic to guess whether stdout/stderr support ANSI, + and if it thinks they don't, then it will wrap ``sys.stdout`` and + ``sys.stderr`` in a magic file object that strips out ANSI escape sequences + before printing them. This happens on all platforms, and can be convenient if + you want to write your code to emit ANSI escape sequences unconditionally, and + let Colorama decide whether they should actually be output. But note that + Colorama's heuristic is not particularly clever. + +- ``init`` also accepts explicit keyword args to enable/disable various + functionality – see below. + +To stop using Colorama before your program exits, simply call ``deinit()``. +This will restore ``stdout`` and ``stderr`` to their original values, so that +Colorama is disabled. To resume using Colorama again, call ``reinit()``; it is +cheaper than calling ``init()`` again (but does the same thing). + +Most users should depend on ``colorama >= 0.4.6``, and use +``just_fix_windows_console``. The old ``init`` interface will be supported +indefinitely for backwards compatibility, but we don't plan to fix any issues +with it, also for backwards compatibility. + +Colored Output +.............. + +Cross-platform printing of colored text can then be done using Colorama's +constant shorthand for ANSI escape sequences. These are deliberately +rudimentary, see below. + +.. code-block:: python + + from colorama import Fore, Back, Style + print(Fore.RED + 'some red text') + print(Back.GREEN + 'and with a green background') + print(Style.DIM + 'and in dim text') + print(Style.RESET_ALL) + print('back to normal now') + +...or simply by manually printing ANSI sequences from your own code: + +.. code-block:: python + + print('\033[31m' + 'some red text') + print('\033[39m') # and reset to default color + +...or, Colorama can be used in conjunction with existing ANSI libraries +such as the venerable `Termcolor `_ +the fabulous `Blessings `_, +or the incredible `_Rich `_. + +If you wish Colorama's Fore, Back and Style constants were more capable, +then consider using one of the above highly capable libraries to generate +colors, etc, and use Colorama just for its primary purpose: to convert +those ANSI sequences to also work on Windows: + +SIMILARLY, do not send PRs adding the generation of new ANSI types to Colorama. +We are only interested in converting ANSI codes to win32 API calls, not +shortcuts like the above to generate ANSI characters. + +.. code-block:: python + + from colorama import just_fix_windows_console + from termcolor import colored + + # use Colorama to make Termcolor work on Windows too + just_fix_windows_console() + + # then use Termcolor for all colored text output + print(colored('Hello, World!', 'green', 'on_red')) + +Available formatting constants are:: + + Fore: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET. + Back: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET. + Style: DIM, NORMAL, BRIGHT, RESET_ALL + +``Style.RESET_ALL`` resets foreground, background, and brightness. Colorama will +perform this reset automatically on program exit. + +These are fairly well supported, but not part of the standard:: + + Fore: LIGHTBLACK_EX, LIGHTRED_EX, LIGHTGREEN_EX, LIGHTYELLOW_EX, LIGHTBLUE_EX, LIGHTMAGENTA_EX, LIGHTCYAN_EX, LIGHTWHITE_EX + Back: LIGHTBLACK_EX, LIGHTRED_EX, LIGHTGREEN_EX, LIGHTYELLOW_EX, LIGHTBLUE_EX, LIGHTMAGENTA_EX, LIGHTCYAN_EX, LIGHTWHITE_EX + +Cursor Positioning +.................. + +ANSI codes to reposition the cursor are supported. See ``demos/demo06.py`` for +an example of how to generate them. + +Init Keyword Args +................. + +``init()`` accepts some ``**kwargs`` to override default behaviour. + +init(autoreset=False): + If you find yourself repeatedly sending reset sequences to turn off color + changes at the end of every print, then ``init(autoreset=True)`` will + automate that: + + .. code-block:: python + + from colorama import init + init(autoreset=True) + print(Fore.RED + 'some red text') + print('automatically back to default color again') + +init(strip=None): + Pass ``True`` or ``False`` to override whether ANSI codes should be + stripped from the output. The default behaviour is to strip if on Windows + or if output is redirected (not a tty). + +init(convert=None): + Pass ``True`` or ``False`` to override whether to convert ANSI codes in the + output into win32 calls. The default behaviour is to convert if on Windows + and output is to a tty (terminal). + +init(wrap=True): + On Windows, Colorama works by replacing ``sys.stdout`` and ``sys.stderr`` + with proxy objects, which override the ``.write()`` method to do their work. + If this wrapping causes you problems, then this can be disabled by passing + ``init(wrap=False)``. The default behaviour is to wrap if ``autoreset`` or + ``strip`` or ``convert`` are True. + + When wrapping is disabled, colored printing on non-Windows platforms will + continue to work as normal. To do cross-platform colored output, you can + use Colorama's ``AnsiToWin32`` proxy directly: + + .. code-block:: python + + import sys + from colorama import init, AnsiToWin32 + init(wrap=False) + stream = AnsiToWin32(sys.stderr).stream + + # Python 2 + print >>stream, Fore.BLUE + 'blue text on stderr' + + # Python 3 + print(Fore.BLUE + 'blue text on stderr', file=stream) + +Recognised ANSI Sequences +......................... + +ANSI sequences generally take the form:: + + ESC [ ; ... + +Where ```` is an integer, and ```` is a single letter. Zero or +more params are passed to a ````. If no params are passed, it is +generally synonymous with passing a single zero. No spaces exist in the +sequence; they have been inserted here simply to read more easily. + +The only ANSI sequences that Colorama converts into win32 calls are:: + + ESC [ 0 m # reset all (colors and brightness) + ESC [ 1 m # bright + ESC [ 2 m # dim (looks same as normal brightness) + ESC [ 22 m # normal brightness + + # FOREGROUND: + ESC [ 30 m # black + ESC [ 31 m # red + ESC [ 32 m # green + ESC [ 33 m # yellow + ESC [ 34 m # blue + ESC [ 35 m # magenta + ESC [ 36 m # cyan + ESC [ 37 m # white + ESC [ 39 m # reset + + # BACKGROUND + ESC [ 40 m # black + ESC [ 41 m # red + ESC [ 42 m # green + ESC [ 43 m # yellow + ESC [ 44 m # blue + ESC [ 45 m # magenta + ESC [ 46 m # cyan + ESC [ 47 m # white + ESC [ 49 m # reset + + # cursor positioning + ESC [ y;x H # position cursor at x across, y down + ESC [ y;x f # position cursor at x across, y down + ESC [ n A # move cursor n lines up + ESC [ n B # move cursor n lines down + ESC [ n C # move cursor n characters forward + ESC [ n D # move cursor n characters backward + + # clear the screen + ESC [ mode J # clear the screen + + # clear the line + ESC [ mode K # clear the line + +Multiple numeric params to the ``'m'`` command can be combined into a single +sequence:: + + ESC [ 36 ; 45 ; 1 m # bright cyan text on magenta background + +All other ANSI sequences of the form ``ESC [ ; ... `` +are silently stripped from the output on Windows. + +Any other form of ANSI sequence, such as single-character codes or alternative +initial characters, are not recognised or stripped. It would be cool to add +them though. Let me know if it would be useful for you, via the Issues on +GitHub. + +Status & Known Problems +----------------------- + +I've personally only tested it on Windows XP (CMD, Console2), Ubuntu +(gnome-terminal, xterm), and OS X. + +Some valid ANSI sequences aren't recognised. + +If you're hacking on the code, see `README-hacking.md`_. ESPECIALLY, see the +explanation there of why we do not want PRs that allow Colorama to generate new +types of ANSI codes. + +See outstanding issues and wish-list: +https://github.com/tartley/colorama/issues + +If anything doesn't work for you, or doesn't do what you expected or hoped for, +I'd love to hear about it on that issues list, would be delighted by patches, +and would be happy to grant commit access to anyone who submits a working patch +or two. + +.. _README-hacking.md: README-hacking.md + +License +------- + +Copyright Jonathan Hartley & Arnon Yaari, 2013-2020. BSD 3-Clause license; see +LICENSE file. + +Professional support +-------------------- + +.. |tideliftlogo| image:: https://cdn2.hubspot.net/hubfs/4008838/website/logos/logos_for_download/Tidelift_primary-shorthand-logo.png + :alt: Tidelift + :target: https://tidelift.com/subscription/pkg/pypi-colorama?utm_source=pypi-colorama&utm_medium=referral&utm_campaign=readme + +.. list-table:: + :widths: 10 100 + + * - |tideliftlogo| + - Professional support for colorama is available as part of the + `Tidelift Subscription`_. + Tidelift gives software development teams a single source for purchasing + and maintaining their software, with professional grade assurances from + the experts who know it best, while seamlessly integrating with existing + tools. + +.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-colorama?utm_source=pypi-colorama&utm_medium=referral&utm_campaign=readme + +Thanks +------ + +See the CHANGELOG for more thanks! + +* Marc Schlaich (schlamar) for a ``setup.py`` fix for Python2.5. +* Marc Abramowitz, reported & fixed a crash on exit with closed ``stdout``, + providing a solution to issue #7's setuptools/distutils debate, + and other fixes. +* User 'eryksun', for guidance on correctly instantiating ``ctypes.windll``. +* Matthew McCormick for politely pointing out a longstanding crash on non-Win. +* Ben Hoyt, for a magnificent fix under 64-bit Windows. +* Jesse at Empty Square for submitting a fix for examples in the README. +* User 'jamessp', an observant documentation fix for cursor positioning. +* User 'vaal1239', Dave Mckee & Lackner Kristof for a tiny but much-needed Win7 + fix. +* Julien Stuyck, for wisely suggesting Python3 compatible updates to README. +* Daniel Griffith for multiple fabulous patches. +* Oscar Lesta for a valuable fix to stop ANSI chars being sent to non-tty + output. +* Roger Binns, for many suggestions, valuable feedback, & bug reports. +* Tim Golden for thought and much appreciated feedback on the initial idea. +* User 'Zearin' for updates to the README file. +* John Szakmeister for adding support for light colors +* Charles Merriam for adding documentation to demos +* Jurko for a fix on 64-bit Windows CPython2.5 w/o ctypes +* Florian Bruhin for a fix when stdout or stderr are None +* Thomas Weininger for fixing ValueError on Windows +* Remi Rampin for better Github integration and fixes to the README file +* Simeon Visser for closing a file handle using 'with' and updating classifiers + to include Python 3.3 and 3.4 +* Andy Neff for fixing RESET of LIGHT_EX colors. +* Jonathan Hartley for the initial idea and implementation. diff --git a/venv/Lib/site-packages/colorama-0.4.6.dist-info/RECORD b/venv/Lib/site-packages/colorama-0.4.6.dist-info/RECORD new file mode 100644 index 0000000..1e4031e --- /dev/null +++ b/venv/Lib/site-packages/colorama-0.4.6.dist-info/RECORD @@ -0,0 +1,31 @@ +colorama-0.4.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +colorama-0.4.6.dist-info/METADATA,sha256=e67SnrUMOym9sz_4TjF3vxvAV4T3aF7NyqRHHH3YEMw,17158 +colorama-0.4.6.dist-info/RECORD,, +colorama-0.4.6.dist-info/WHEEL,sha256=cdcF4Fbd0FPtw2EMIOwH-3rSOTUdTCeOSXRMD1iLUb8,105 +colorama-0.4.6.dist-info/licenses/LICENSE.txt,sha256=ysNcAmhuXQSlpxQL-zs25zrtSWZW6JEQLkKIhteTAxg,1491 +colorama/__init__.py,sha256=wePQA4U20tKgYARySLEC047ucNX-g8pRLpYBuiHlLb8,266 +colorama/__pycache__/__init__.cpython-39.pyc,, +colorama/__pycache__/ansi.cpython-39.pyc,, +colorama/__pycache__/ansitowin32.cpython-39.pyc,, +colorama/__pycache__/initialise.cpython-39.pyc,, +colorama/__pycache__/win32.cpython-39.pyc,, +colorama/__pycache__/winterm.cpython-39.pyc,, +colorama/ansi.py,sha256=Top4EeEuaQdBWdteKMEcGOTeKeF19Q-Wo_6_Cj5kOzQ,2522 +colorama/ansitowin32.py,sha256=vPNYa3OZbxjbuFyaVo0Tmhmy1FZ1lKMWCnT7odXpItk,11128 +colorama/initialise.py,sha256=-hIny86ClXo39ixh5iSCfUIa2f_h_bgKRDW7gqs-KLU,3325 +colorama/tests/__init__.py,sha256=MkgPAEzGQd-Rq0w0PZXSX2LadRWhUECcisJY8lSrm4Q,75 +colorama/tests/__pycache__/__init__.cpython-39.pyc,, +colorama/tests/__pycache__/ansi_test.cpython-39.pyc,, +colorama/tests/__pycache__/ansitowin32_test.cpython-39.pyc,, +colorama/tests/__pycache__/initialise_test.cpython-39.pyc,, +colorama/tests/__pycache__/isatty_test.cpython-39.pyc,, +colorama/tests/__pycache__/utils.cpython-39.pyc,, +colorama/tests/__pycache__/winterm_test.cpython-39.pyc,, +colorama/tests/ansi_test.py,sha256=FeViDrUINIZcr505PAxvU4AjXz1asEiALs9GXMhwRaE,2839 +colorama/tests/ansitowin32_test.py,sha256=RN7AIhMJ5EqDsYaCjVo-o4u8JzDD4ukJbmevWKS70rY,10678 +colorama/tests/initialise_test.py,sha256=BbPy-XfyHwJ6zKozuQOvNvQZzsx9vdb_0bYXn7hsBTc,6741 +colorama/tests/isatty_test.py,sha256=Pg26LRpv0yQDB5Ac-sxgVXG7hsA1NYvapFgApZfYzZg,1866 +colorama/tests/utils.py,sha256=1IIRylG39z5-dzq09R_ngufxyPZxgldNbrxKxUGwGKE,1079 +colorama/tests/winterm_test.py,sha256=qoWFPEjym5gm2RuMwpf3pOis3a5r_PJZFCzK254JL8A,3709 +colorama/win32.py,sha256=YQOKwMTwtGBbsY4dL5HYTvwTeP9wIQra5MvPNddpxZs,6181 +colorama/winterm.py,sha256=XCQFDHjPi6AHYNdZwy0tA02H-Jh48Jp-HvCjeLeLp3U,7134 diff --git a/venv/Lib/site-packages/colorama-0.4.6.dist-info/WHEEL b/venv/Lib/site-packages/colorama-0.4.6.dist-info/WHEEL new file mode 100644 index 0000000..d79189f --- /dev/null +++ b/venv/Lib/site-packages/colorama-0.4.6.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.11.1 +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any diff --git a/venv/Lib/site-packages/colorama-0.4.6.dist-info/licenses/LICENSE.txt b/venv/Lib/site-packages/colorama-0.4.6.dist-info/licenses/LICENSE.txt new file mode 100644 index 0000000..3105888 --- /dev/null +++ b/venv/Lib/site-packages/colorama-0.4.6.dist-info/licenses/LICENSE.txt @@ -0,0 +1,27 @@ +Copyright (c) 2010 Jonathan Hartley +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holders, nor those of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/Lib/site-packages/distutils-precedence.pth b/venv/Lib/site-packages/distutils-precedence.pth new file mode 100644 index 0000000..7f009fe --- /dev/null +++ b/venv/Lib/site-packages/distutils-precedence.pth @@ -0,0 +1 @@ +import os; var = 'SETUPTOOLS_USE_DISTUTILS'; enabled = os.environ.get(var, 'local') == 'local'; enabled and __import__('_distutils_hack').add_shim(); diff --git a/venv/Lib/site-packages/iniconfig-2.0.0.dist-info/INSTALLER b/venv/Lib/site-packages/iniconfig-2.0.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/iniconfig-2.0.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/iniconfig-2.0.0.dist-info/METADATA b/venv/Lib/site-packages/iniconfig-2.0.0.dist-info/METADATA new file mode 100644 index 0000000..3ea1e01 --- /dev/null +++ b/venv/Lib/site-packages/iniconfig-2.0.0.dist-info/METADATA @@ -0,0 +1,80 @@ +Metadata-Version: 2.1 +Name: iniconfig +Version: 2.0.0 +Summary: brain-dead simple config-ini parsing +Project-URL: Homepage, https://github.com/pytest-dev/iniconfig +Author-email: Ronny Pfannschmidt , Holger Krekel +License-Expression: MIT +License-File: LICENSE +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: POSIX +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Utilities +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst + +iniconfig: brain-dead simple parsing of ini files +======================================================= + +iniconfig is a small and simple INI-file parser module +having a unique set of features: + +* maintains order of sections and entries +* supports multi-line values with or without line-continuations +* supports "#" comments everywhere +* raises errors with proper line-numbers +* no bells and whistles like automatic substitutions +* iniconfig raises an Error if two sections have the same name. + +If you encounter issues or have feature wishes please report them to: + + https://github.com/RonnyPfannschmidt/iniconfig/issues + +Basic Example +=================================== + +If you have an ini file like this: + +.. code-block:: ini + + # content of example.ini + [section1] # comment + name1=value1 # comment + name1b=value1,value2 # comment + + [section2] + name2= + line1 + line2 + +then you can do: + +.. code-block:: pycon + + >>> import iniconfig + >>> ini = iniconfig.IniConfig("example.ini") + >>> ini['section1']['name1'] # raises KeyError if not exists + 'value1' + >>> ini.get('section1', 'name1b', [], lambda x: x.split(",")) + ['value1', 'value2'] + >>> ini.get('section1', 'notexist', [], lambda x: x.split(",")) + [] + >>> [x.name for x in list(ini)] + ['section1', 'section2'] + >>> list(list(ini)[0].items()) + [('name1', 'value1'), ('name1b', 'value1,value2')] + >>> 'section1' in ini + True + >>> 'inexistendsection' in ini + False diff --git a/venv/Lib/site-packages/iniconfig-2.0.0.dist-info/RECORD b/venv/Lib/site-packages/iniconfig-2.0.0.dist-info/RECORD new file mode 100644 index 0000000..822c1a4 --- /dev/null +++ b/venv/Lib/site-packages/iniconfig-2.0.0.dist-info/RECORD @@ -0,0 +1,14 @@ +iniconfig-2.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +iniconfig-2.0.0.dist-info/METADATA,sha256=2KcBd5DEFiZclO-ruP_qzN71qcTL0hNsCw5MCDIPN6I,2599 +iniconfig-2.0.0.dist-info/RECORD,, +iniconfig-2.0.0.dist-info/WHEEL,sha256=hKi7AIIx6qfnsRbr087vpeJnrVUuDokDHZacPPMW7-Y,87 +iniconfig-2.0.0.dist-info/licenses/LICENSE,sha256=KvaAw570k_uCgwNW0dPfGstaBgM8ui3sehniHKp3qGY,1061 +iniconfig/__init__.py,sha256=ALJSNenAgTD7RNj820NggEQuyaZp2QseTCThGJPavk0,5473 +iniconfig/__pycache__/__init__.cpython-39.pyc,, +iniconfig/__pycache__/_parse.cpython-39.pyc,, +iniconfig/__pycache__/_version.cpython-39.pyc,, +iniconfig/__pycache__/exceptions.cpython-39.pyc,, +iniconfig/_parse.py,sha256=OWGLbmE8GjxcoMWTvnGbck1RoNsTm5bt5ficIRZqWJ8,2436 +iniconfig/_version.py,sha256=WM8rOXoL5t25aMQJp4qbU2XP09nrDtmDnrAGhHSk0Wk,160 +iniconfig/exceptions.py,sha256=3V2JS5rndwiYUh84PNYS_1zd8H8IB-Rar81ARAA7E9s,501 +iniconfig/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/venv/Lib/site-packages/iniconfig-2.0.0.dist-info/WHEEL b/venv/Lib/site-packages/iniconfig-2.0.0.dist-info/WHEEL new file mode 100644 index 0000000..8d5c0ce --- /dev/null +++ b/venv/Lib/site-packages/iniconfig-2.0.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.12.2 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/venv/Lib/site-packages/iniconfig-2.0.0.dist-info/licenses/LICENSE b/venv/Lib/site-packages/iniconfig-2.0.0.dist-info/licenses/LICENSE new file mode 100644 index 0000000..31ecdfb --- /dev/null +++ b/venv/Lib/site-packages/iniconfig-2.0.0.dist-info/licenses/LICENSE @@ -0,0 +1,19 @@ + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + diff --git a/venv/Lib/site-packages/isort-5.4.2.dist-info/INSTALLER b/venv/Lib/site-packages/isort-5.4.2.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/isort-5.4.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/isort-5.4.2.dist-info/LICENSE b/venv/Lib/site-packages/isort-5.4.2.dist-info/LICENSE new file mode 100644 index 0000000..b5083a5 --- /dev/null +++ b/venv/Lib/site-packages/isort-5.4.2.dist-info/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013 Timothy Edmund Crosley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/venv/Lib/site-packages/isort-5.4.2.dist-info/METADATA b/venv/Lib/site-packages/isort-5.4.2.dist-info/METADATA new file mode 100644 index 0000000..4301784 --- /dev/null +++ b/venv/Lib/site-packages/isort-5.4.2.dist-info/METADATA @@ -0,0 +1,694 @@ +Metadata-Version: 2.1 +Name: isort +Version: 5.4.2 +Summary: A Python utility / library to sort Python imports. +Home-page: https://timothycrosley.github.io/isort/ +License: MIT +Keywords: Refactor,Lint,Imports,Sort,Clean +Author: Timothy Crosley +Author-email: timothy.crosley@gmail.com +Requires-Python: >=3.6,<4.0 +Classifier: Development Status :: 6 - Mature +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Natural Language :: English +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Utilities +Provides-Extra: colors +Provides-Extra: pipfile_deprecated_finder +Provides-Extra: requirements_deprecated_finder +Requires-Dist: colorama (>=0.4.3,<0.5.0); extra == "colors" +Requires-Dist: pip-api; extra == "requirements_deprecated_finder" +Requires-Dist: pipreqs; extra == "pipfile_deprecated_finder" or extra == "requirements_deprecated_finder" +Requires-Dist: requirementslib; extra == "pipfile_deprecated_finder" +Requires-Dist: tomlkit (>=0.5.3); extra == "pipfile_deprecated_finder" +Project-URL: Changelog, https://github.com/timothycrosley/isort/blob/master/CHANGELOG.md +Project-URL: Documentation, https://timothycrosley.github.io/isort/ +Project-URL: Repository, https://github.com/timothycrosley/isort +Description-Content-Type: text/markdown + +[![isort - isort your imports, so you don't have to.](https://raw.githubusercontent.com/timothycrosley/isort/develop/art/logo_large.png)](https://timothycrosley.github.io/isort/) + +------------------------------------------------------------------------ + +[![PyPI version](https://badge.fury.io/py/isort.svg)](https://badge.fury.io/py/isort) +[![Test Status](https://github.com/timothycrosley/isort/workflows/Test/badge.svg?branch=develop)](https://github.com/timothycrosley/isort/actions?query=workflow%3ATest) +[![Lint Status](https://github.com/timothycrosley/isort/workflows/Lint/badge.svg?branch=develop)](https://github.com/timothycrosley/isort/actions?query=workflow%3ALint) +[![Code coverage Status](https://codecov.io/gh/timothycrosley/isort/branch/develop/graph/badge.svg)](https://codecov.io/gh/timothycrosley/isort) +[![Maintainability](https://api.codeclimate.com/v1/badges/060372d3e77573072609/maintainability)](https://codeclimate.com/github/timothycrosley/isort/maintainability) +[![License](https://img.shields.io/github/license/mashape/apistatus.svg)](https://pypi.org/project/isort/) +[![Join the chat at https://gitter.im/timothycrosley/isort](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/timothycrosley/isort?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Downloads](https://pepy.tech/badge/isort)](https://pepy.tech/project/isort) +[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) +[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://timothycrosley.github.io/isort/) +[![DeepSource](https://static.deepsource.io/deepsource-badge-light-mini.svg)](https://deepsource.io/gh/timothycrosley/isort/?ref=repository-badge) +_________________ + +[Read Latest Documentation](https://timothycrosley.github.io/isort/) - [Browse GitHub Code Repository](https://github.com/timothycrosley/isort/) +_________________ + +isort your imports, so you don't have to. + +isort is a Python utility / library to sort imports alphabetically, and +automatically separated into sections and by type. It provides a command line +utility, Python library and [plugins for various +editors](https://github.com/timothycrosley/isort/wiki/isort-Plugins) to +quickly sort all your imports. It requires Python 3.6+ to run but +supports formatting Python 2 code too. + +[Try isort now from your browser!](https://timothycrosley.github.io/isort/docs/quick_start/0.-try/) + +![Example Usage](https://raw.github.com/timothycrosley/isort/develop/example.gif) + +Before isort: + +```python +from my_lib import Object + +import os + +from my_lib import Object3 + +from my_lib import Object2 + +import sys + +from third_party import lib15, lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8, lib9, lib10, lib11, lib12, lib13, lib14 + +import sys + +from __future__ import absolute_import + +from third_party import lib3 + +print("Hey") +print("yo") +``` + +After isort: + +```python +from __future__ import absolute_import + +import os +import sys + +from third_party import (lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8, + lib9, lib10, lib11, lib12, lib13, lib14, lib15) + +from my_lib import Object, Object2, Object3 + +print("Hey") +print("yo") +``` + +## Installing isort + +Installing isort is as simple as: + +```bash +pip install isort +``` + +Install isort with requirements.txt support: + +```bash +pip install isort[requirements_deprecated_finder] +``` + +Install isort with Pipfile support: + +```bash +pip install isort[pipfile_deprecated_finder] +``` + +Install isort with both formats support: + +```bash +pip install isort[requirements_deprecated_finder,pipfile_deprecated_finder] +``` + +## Using isort + +**From the command line**: + +```bash +isort mypythonfile.py mypythonfile2.py +``` + +or recursively: + +```bash +isort . +``` + +*which is equivalent to:* + +```bash +isort **/*.py +``` + +or to see the proposed changes without applying them: + +```bash +isort mypythonfile.py --diff +``` + +Finally, to atomically run isort against a project, only applying +changes if they don't introduce syntax errors do: + +```bash +isort --atomic . +``` + +(Note: this is disabled by default as it keeps isort from being able to +run against code written using a different version of Python) + +**From within Python**: + +```bash +import isort + +isort.file("pythonfile.py") +``` + +or: + +```bash +import isort + +sorted_code = isort.code("import b\nimport a\n") +``` + +## Installing isort's for your preferred text editor + +Several plugins have been written that enable to use isort from within a +variety of text-editors. You can find a full list of them [on the isort +wiki](https://github.com/timothycrosley/isort/wiki/isort-Plugins). +Additionally, I will enthusiastically accept pull requests that include +plugins for other text editors and add documentation for them as I am +notified. + +## Multi line output modes + +You will notice above the \"multi\_line\_output\" setting. This setting +defines how from imports wrap when they extend past the line\_length +limit and has 6 possible settings: + +**0 - Grid** + +```python +from third_party import (lib1, lib2, lib3, + lib4, lib5, ...) +``` + +**1 - Vertical** + +```python +from third_party import (lib1, + lib2, + lib3 + lib4, + lib5, + ...) +``` + +**2 - Hanging Indent** + +```python +from third_party import \ + lib1, lib2, lib3, \ + lib4, lib5, lib6 +``` + +**3 - Vertical Hanging Indent** + +```python +from third_party import ( + lib1, + lib2, + lib3, + lib4, +) +``` + +**4 - Hanging Grid** + +```python +from third_party import ( + lib1, lib2, lib3, lib4, + lib5, ...) +``` + +**5 - Hanging Grid Grouped** + +```python +from third_party import ( + lib1, lib2, lib3, lib4, + lib5, ... +) +``` + +**6 - Hanging Grid Grouped, No Trailing Comma** + +In Mode 5 isort leaves a single extra space to maintain consistency of +output when a comma is added at the end. Mode 6 is the same - except +that no extra space is maintained leading to the possibility of lines +one character longer. You can enforce a trailing comma by using this in +conjunction with `-tc` or `include_trailing_comma: True`. + +```python +from third_party import ( + lib1, lib2, lib3, lib4, + lib5 +) +``` + +**7 - NOQA** + +```python +from third_party import lib1, lib2, lib3, ... # NOQA +``` + +Alternatively, you can set `force_single_line` to `True` (`-sl` on the +command line) and every import will appear on its own line: + +```python +from third_party import lib1 +from third_party import lib2 +from third_party import lib3 +... +``` + +**8 - Vertical Hanging Indent Bracket** + +Same as Mode 3 - _Vertical Hanging Indent_ but the closing parentheses +on the last line is indented. + +```python +from third_party import ( + lib1, + lib2, + lib3, + lib4, + ) +``` + +**9 - Vertical Prefix From Module Import** + +Starts a new line with the same `from MODULE import ` prefix when lines are longer than the line length limit. + +```python +from third_party import lib1, lib2, lib3 +from third_party import lib4, lib5, lib6 +``` + +**10 - Hanging Indent With Parentheses** + +Same as Mode 2 - _Hanging Indent_ but uses parentheses instead of backslash +for wrapping long lines. + +```python +from third_party import ( + lib1, lib2, lib3, + lib4, lib5, lib6) +``` + +Note: to change the how constant indents appear - simply change the +indent property with the following accepted formats: + +- Number of spaces you would like. For example: 4 would cause standard + 4 space indentation. +- Tab +- A verbatim string with quotes around it. + +For example: + +```python +" " +``` + +is equivalent to 4. + +For the import styles that use parentheses, you can control whether or +not to include a trailing comma after the last import with the +`include_trailing_comma` option (defaults to `False`). + +## Intelligently Balanced Multi-line Imports + +As of isort 3.1.0 support for balanced multi-line imports has been +added. With this enabled isort will dynamically change the import length +to the one that produces the most balanced grid, while staying below the +maximum import length defined. + +Example: + +```python +from __future__ import (absolute_import, division, + print_function, unicode_literals) +``` + +Will be produced instead of: + +```python +from __future__ import (absolute_import, division, print_function, + unicode_literals) +``` + +To enable this set `balanced_wrapping` to `True` in your config or pass +the `-e` option into the command line utility. + +## Custom Sections and Ordering + +You can change the section order with `sections` option from the default +of: + +```ini +FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER +``` + +to your preference: + +```ini +sections=FUTURE,STDLIB,FIRSTPARTY,THIRDPARTY,LOCALFOLDER +``` + +You also can define your own sections and their order. + +Example: + +```ini +known_django=django +known_pandas=pandas,numpy +sections=FUTURE,STDLIB,DJANGO,THIRDPARTY,PANDAS,FIRSTPARTY,LOCALFOLDER +``` + +would create two new sections with the specified known modules. + +The `no_lines_before` option will prevent the listed sections from being +split from the previous section by an empty line. + +Example: + +```ini +sections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER +no_lines_before=LOCALFOLDER +``` + +would produce a section with both FIRSTPARTY and LOCALFOLDER modules +combined. + +**IMPORTANT NOTE**: It is very important to know when setting `known` sections that the naming +does not directly map for historical reasons. For custom settings, the only difference is +capitalization (`known_custom=custom` VS `sections=CUSTOM,...`) for all others reference the +following mapping: + + - `known_standard_library` : `STANDARD_LIBRARY` + - `extra_standard_library` : `STANDARD_LIBRARY` # Like known standard library but appends instead of replacing + - `known_future_library` : `FUTURE` + - `known_first_party`: `FIRSTPARTY` + - `known_third_party`: `THIRDPARTY` + - `known_local_folder`: `LOCALFOLDER` + +This will likely be changed in isort 6.0.0+ in a backwards compatible way. + +## Auto-comment import sections + +Some projects prefer to have import sections uniquely titled to aid in +identifying the sections quickly when visually scanning. isort can +automate this as well. To do this simply set the +`import_heading_{section_name}` setting for each section you wish to +have auto commented - to the desired comment. + +For Example: + +```ini +import_heading_stdlib=Standard Library +import_heading_firstparty=My Stuff +``` + +Would lead to output looking like the following: + +```python +# Standard Library +import os +import sys + +import django.settings + +# My Stuff +import myproject.test +``` + +## Ordering by import length + +isort also makes it easy to sort your imports by length, simply by +setting the `length_sort` option to `True`. This will result in the +following output style: + +```python +from evn.util import ( + Pool, + Dict, + Options, + Constant, + DecayDict, + UnexpectedCodePath, +) +``` + +It is also possible to opt-in to sorting imports by length for only +specific sections by using `length_sort_` followed by the section name +as a configuration item, e.g.: + + length_sort_stdlib=1 + +## Controlling how isort sections `from` imports + +By default isort places straight (`import y`) imports above from imports (`from x import y`): + +```python +import b +from a import a # This will always appear below because it is a from import. +``` + +However, if you prefer to keep strict alphabetical sorting you can set [force sort within sections](https://timothycrosley.github.io/isort/docs/configuration/options/#force-sort-within-sections) to true. Resulting in: + + +```python +from a import a # This will now appear at top because a appears in the alphabet before b +import b +``` + +You can even tell isort to always place from imports on top, instead of the default of placing them on bottom, using [from first](https://timothycrosley.github.io/isort/docs/configuration/options/#from-first). + +```python +from b import b # If from first is set to True, all from imports will be placed before non-from imports. +import a +``` + +## Skip processing of imports (outside of configuration) + +To make isort ignore a single import simply add a comment at the end of +the import line containing the text `isort:skip`: + +```python +import module # isort:skip +``` + +or: + +```python +from xyz import (abc, # isort:skip + yo, + hey) +``` + +To make isort skip an entire file simply add `isort:skip_file` to the +module's doc string: + +```python +""" my_module.py + Best module ever + + isort:skip_file +""" + +import b +import a +``` + +## Adding an import to multiple files + +isort makes it easy to add an import statement across multiple files, +while being assured it's correctly placed. + +To add an import to all files: + +```bash +isort -a "from __future__ import print_function" *.py +``` + +To add an import only to files that already have imports: + +```bash +isort -a "from __future__ import print_function" --append-only *.py +``` + + +## Removing an import from multiple files + +isort also makes it easy to remove an import from multiple files, +without having to be concerned with how it was originally formatted. + +From the command line: + +```bash +isort --rm "os.system" *.py +``` + +## Using isort to verify code + +The `--check-only` option +------------------------- + +isort can also be used to used to verify that code is correctly +formatted by running it with `-c`. Any files that contain incorrectly +sorted and/or formatted imports will be outputted to `stderr`. + +```bash +isort **/*.py -c -v + +SUCCESS: /home/timothy/Projects/Open_Source/isort/isort_kate_plugin.py Everything Looks Good! +ERROR: /home/timothy/Projects/Open_Source/isort/isort/isort.py Imports are incorrectly sorted. +``` + +One great place this can be used is with a pre-commit git hook, such as +this one by \@acdha: + + + +This can help to ensure a certain level of code quality throughout a +project. + +Git hook +-------- + +isort provides a hook function that can be integrated into your Git +pre-commit script to check Python code before committing. + +To cause the commit to fail if there are isort errors (strict mode), +include the following in `.git/hooks/pre-commit`: + +```python +#!/usr/bin/env python +import sys +from isort.hooks import git_hook + +sys.exit(git_hook(strict=True, modify=True, lazy=True)) +``` + +If you just want to display warnings, but allow the commit to happen +anyway, call `git_hook` without the strict parameter. If you want to +display warnings, but not also fix the code, call `git_hook` without the +modify parameter. +The `lazy` argument is to support users who are "lazy" to add files +individually to the index and tend to use `git commit -a` instead. +Set it to `True` to ensure all tracked files are properly isorted, +leave it out or set it to `False` to check only files added to your +index. + +## Setuptools integration + +Upon installation, isort enables a `setuptools` command that checks +Python files declared by your project. + +Running `python setup.py isort` on the command line will check the files +listed in your `py_modules` and `packages`. If any warning is found, the +command will exit with an error code: + +```bash +$ python setup.py isort +``` + +Also, to allow users to be able to use the command without having to +install isort themselves, add isort to the setup\_requires of your +`setup()` like so: + +```python +setup( + name="project", + packages=["project"], + + setup_requires=[ + "isort" + ] +) +``` + +## Spread the word + +[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://timothycrosley.github.io/isort/) + +Place this badge at the top of your repository to let others know your project uses isort. + +For README.md: + +```markdown +[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://timothycrosley.github.io/isort/) +``` + +Or README.rst: + +```rst +.. image:: https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336 + :target: https://timothycrosley.github.io/isort/ +``` + +## Security contact information + +To report a security vulnerability, please use the [Tidelift security +contact](https://tidelift.com/security). Tidelift will coordinate the +fix and disclosure. + +## Why isort? + +isort simply stands for import sort. It was originally called +"sortImports" however I got tired of typing the extra characters and +came to the realization camelCase is not pythonic. + +I wrote isort because in an organization I used to work in the manager +came in one day and decided all code must have alphabetically sorted +imports. The code base was huge - and he meant for us to do it by hand. +However, being a programmer - I\'m too lazy to spend 8 hours mindlessly +performing a function, but not too lazy to spend 16 hours automating it. +I was given permission to open source sortImports and here we are :) + +------------------------------------------------------------------------ + +[Get professionally supported isort with the Tidelift +Subscription](https://tidelift.com/subscription/pkg/pypi-isort?utm_source=pypi-isort&utm_medium=referral&utm_campaign=readme) + +Professional support for isort is available as part of the [Tidelift +Subscription](https://tidelift.com/subscription/pkg/pypi-isort?utm_source=pypi-isort&utm_medium=referral&utm_campaign=readme). +Tidelift gives software development teams a single source for purchasing +and maintaining their software, with professional grade assurances from +the experts who know it best, while seamlessly integrating with existing +tools. + +------------------------------------------------------------------------ + +Thanks and I hope you find isort useful! + +~Timothy Crosley + diff --git a/venv/Lib/site-packages/isort-5.4.2.dist-info/RECORD b/venv/Lib/site-packages/isort-5.4.2.dist-info/RECORD new file mode 100644 index 0000000..2219197 --- /dev/null +++ b/venv/Lib/site-packages/isort-5.4.2.dist-info/RECORD @@ -0,0 +1,97 @@ +../../Scripts/isort.exe,sha256=pxNnDpAV0902iJHn_PbrX_gjILj507qRJk3QtJppjRw,108413 +isort-5.4.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +isort-5.4.2.dist-info/LICENSE,sha256=BjKUABw9Uj26y6ud1UrCKZgnVsyvWSylMkCysM3YIGU,1089 +isort-5.4.2.dist-info/METADATA,sha256=DeBAWU6fk135MZXZzo4U9F8Wh3fQZjFm4X6abQDsDxI,19579 +isort-5.4.2.dist-info/RECORD,, +isort-5.4.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +isort-5.4.2.dist-info/WHEEL,sha256=xSvaL1DM8LOHfdyo0cCcwjZu1tC6CnCsRGWUgazvlbM,83 +isort-5.4.2.dist-info/entry_points.txt,sha256=_Iy7m5GNm89oXcjsXzVEFav4wXWsTqKXiZUARWjFI7M,148 +isort/__init__.py,sha256=u8zdFTPFro_l9J7JzdeNSlu6CU6BboY3fRTuloxbl7c,374 +isort/__main__.py,sha256=iK0trzN9CCXpQX-XPZDZ9JVkm2Lc0q0oiAgsa6FkJb4,36 +isort/__pycache__/__init__.cpython-39.pyc,, +isort/__pycache__/__main__.cpython-39.pyc,, +isort/__pycache__/_version.cpython-39.pyc,, +isort/__pycache__/api.cpython-39.pyc,, +isort/__pycache__/comments.cpython-39.pyc,, +isort/__pycache__/core.cpython-39.pyc,, +isort/__pycache__/exceptions.cpython-39.pyc,, +isort/__pycache__/format.cpython-39.pyc,, +isort/__pycache__/hooks.cpython-39.pyc,, +isort/__pycache__/io.cpython-39.pyc,, +isort/__pycache__/literal.cpython-39.pyc,, +isort/__pycache__/logo.cpython-39.pyc,, +isort/__pycache__/main.cpython-39.pyc,, +isort/__pycache__/output.cpython-39.pyc,, +isort/__pycache__/parse.cpython-39.pyc,, +isort/__pycache__/place.cpython-39.pyc,, +isort/__pycache__/profiles.cpython-39.pyc,, +isort/__pycache__/pylama_isort.cpython-39.pyc,, +isort/__pycache__/sections.cpython-39.pyc,, +isort/__pycache__/settings.cpython-39.pyc,, +isort/__pycache__/setuptools_commands.cpython-39.pyc,, +isort/__pycache__/sorting.cpython-39.pyc,, +isort/__pycache__/utils.cpython-39.pyc,, +isort/__pycache__/wrap.cpython-39.pyc,, +isort/__pycache__/wrap_modes.cpython-39.pyc,, +isort/_future/__init__.py,sha256=wn-Aa4CVe0zZfA_YBTkJqb6LA9HR9NgpAp0uatzNRNs,326 +isort/_future/__pycache__/__init__.cpython-39.pyc,, +isort/_future/__pycache__/_dataclasses.cpython-39.pyc,, +isort/_future/_dataclasses.py,sha256=sjuvr80ZnihMsZ5HBTNplgPfhQ-L5xHIh1aOzEtOscQ,44066 +isort/_vendored/toml/LICENSE,sha256=LZKUgj32yJNXyL5JJ_znk2HWVh5e51MtWSbmOTmqpTY,1252 +isort/_vendored/toml/__init__.py,sha256=gKOk-Amczi2juJsOs1D6UEToaPSIIgNh95Yo5N5gneE,703 +isort/_vendored/toml/__pycache__/__init__.cpython-39.pyc,, +isort/_vendored/toml/__pycache__/decoder.cpython-39.pyc,, +isort/_vendored/toml/__pycache__/encoder.cpython-39.pyc,, +isort/_vendored/toml/__pycache__/ordered.cpython-39.pyc,, +isort/_vendored/toml/__pycache__/tz.cpython-39.pyc,, +isort/_vendored/toml/decoder.py,sha256=5etBKNvVLFAR0rhLCJ9fnRTlqkebI4ZQeoJi_myFbd4,37713 +isort/_vendored/toml/encoder.py,sha256=gQOXYnAWo27Jc_przA1FqLX5AgwbdgN-qDHQtKRx300,9668 +isort/_vendored/toml/ordered.py,sha256=aW5woa5xOqR4BjIz9t10_lghxyhF54KQ7FqUNVv7WJ0,334 +isort/_vendored/toml/tz.py,sha256=8TAiXrTqU08sE0ruz2TXH_pFY2rlwNKE47MSE4rDo8Y,618 +isort/_version.py,sha256=FeLZIE8encwqUtsr94yKhYavIqQmfviy9Ah69YgUhLU,22 +isort/api.py,sha256=QJegKmNa6fo5FABTDK9j16b3OgmNIT9ziIsApeTjYDQ,15705 +isort/comments.py,sha256=23uMZZbUn8y3glMW6_WftnEhECvc-4LW4ysEghpYUUU,962 +isort/core.py,sha256=rKmnMA7nsW9yNLInT-GE2pLtbPOea8U0MyyT3tUSnaA,16417 +isort/deprecated/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +isort/deprecated/__pycache__/__init__.cpython-39.pyc,, +isort/deprecated/__pycache__/finders.cpython-39.pyc,, +isort/deprecated/finders.py,sha256=N-ujofD6auS5ZPjtaeIB5S2lZk-7Dmx17w57DeU0Q_U,14488 +isort/exceptions.py,sha256=Jxk4rfvI4TcaBcmVT2VD5LcEzwCbVQh6BXPfjP_Gmvc,4635 +isort/format.py,sha256=c5jt_mbYBG5uCXRVCTk51YR-BNjtbDVOXJpZQ2XLZR8,4112 +isort/hooks.py,sha256=iO3Pj-rW9GrMTD-znGYUMOr8TA0A8VVhujn6F8d6ILM,2716 +isort/io.py,sha256=30v6ZH7ntl6hAZGAArB5G1uol1FiQ8qb97s1G71Hwt4,1757 +isort/literal.py,sha256=PQRMWSkbbP3pEhj88pFhSjX6Q3IH-_Pn_XdLf4D7a2M,3548 +isort/logo.py,sha256=cL3al79O7O0G2viqRMRfBPp0qtRZmJw2nHSCZw8XWdQ,388 +isort/main.py,sha256=VtJ6tHYe_rfAI0ZGE6RLtfcuqo3DKM2wT3SnAqJVhtY,31757 +isort/output.py,sha256=8x59vLumT2qtgcZ4tGSO3x0Jw7-bTXUjZtQPn2fqocw,22505 +isort/parse.py,sha256=kPr-ekBkrff8FWgUnuQnGMyiwKSV89HuoZWqsgt6-fM,19244 +isort/place.py,sha256=S3eRp3EVsIq7LDgb4QN1jb7-dvtfXXr48EqJsMP54-Y,3289 +isort/profiles.py,sha256=CyCEpF1iOgrfxvC2nnRAjuKxxuojVN5NViyE-OlFciU,1502 +isort/pylama_isort.py,sha256=Qk8XqicFOn7EhVVQl-gmlybh4WVWbKaDYM8koDB8Dg8,897 +isort/sections.py,sha256=xG5bwU4tOIKUmeBBhZ45EIfjP8HgDOx796bPvD5zWCw,297 +isort/settings.py,sha256=foh76t6eWssSJXMIFXm0VCbUas2Oj7wcY2NKrTyRcAU,26573 +isort/setuptools_commands.py,sha256=2EIVYwUYAurcihzYSIDXV6zKHM-DxqxHBW-x7UnI3No,2223 +isort/sorting.py,sha256=DwRFS02vzRv-ZPTwenhYQQ0vV6owTcHQVK6q_nzqtio,2803 +isort/stdlibs/__init__.py,sha256=MgiO4yPeJZ6ieWz5qSw2LuY7pVmRjZUaCqyUaLH5qJQ,64 +isort/stdlibs/__pycache__/__init__.cpython-39.pyc,, +isort/stdlibs/__pycache__/all.cpython-39.pyc,, +isort/stdlibs/__pycache__/py2.cpython-39.pyc,, +isort/stdlibs/__pycache__/py27.cpython-39.pyc,, +isort/stdlibs/__pycache__/py3.cpython-39.pyc,, +isort/stdlibs/__pycache__/py35.cpython-39.pyc,, +isort/stdlibs/__pycache__/py36.cpython-39.pyc,, +isort/stdlibs/__pycache__/py37.cpython-39.pyc,, +isort/stdlibs/__pycache__/py38.cpython-39.pyc,, +isort/stdlibs/__pycache__/py39.cpython-39.pyc,, +isort/stdlibs/all.py,sha256=n8Es1WK6UlupYyVvf1PDjGbionqix-afC3LkY8nzTcw,57 +isort/stdlibs/py2.py,sha256=dTgWTa7ggz1cwN8fuI9eIs9-5nTmkRxG_uO61CGwfXI,41 +isort/stdlibs/py27.py,sha256=-Id4l2pjAOMXUfwDNnIBR2o8I_mW_Ghmuek2b82Bczk,4492 +isort/stdlibs/py3.py,sha256=4NpsSHXy9mU4pc3nazM6GTB9RD7iqN2JV9n6SUA672w,101 +isort/stdlibs/py35.py,sha256=SVZp9jaCVq4kSjbKcVgF8dJttyFCqcl20ydodsmHrqE,3283 +isort/stdlibs/py36.py,sha256=tCGWDZXWlJJI4_845yOhTpIvnU0-a3TouD_xsMEIZ3s,3298 +isort/stdlibs/py37.py,sha256=nYZmN-s3qMmAHHddegQv6U0j4cnAH0e5SmqTiG6mmhQ,3322 +isort/stdlibs/py38.py,sha256=KE_65iAHg7icOv2xSGScdJWjwBZGuSQYfYcTSIoo_d8,3307 +isort/stdlibs/py39.py,sha256=gHmC2xbsvrqqxybV9G7vrKRv7UmZpgt9NybAhR1LANk,3295 +isort/utils.py,sha256=D_NmQoPoQSTmLzy5HLcZF1hMK9DIj7vzlGDkMWR0c5E,980 +isort/wrap.py,sha256=W73QcVU_4d_LZ19Fh-Oh3eRCcjNeWqHvGSioqqRSsqo,5353 +isort/wrap_modes.py,sha256=EOkrjlWnL_m0SI7f0UtLUwsrWjv6lPaUsTnKevxAQLw,10948 diff --git a/venv/Lib/site-packages/isort-5.4.2.dist-info/REQUESTED b/venv/Lib/site-packages/isort-5.4.2.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/isort-5.4.2.dist-info/WHEEL b/venv/Lib/site-packages/isort-5.4.2.dist-info/WHEEL new file mode 100644 index 0000000..bbb3489 --- /dev/null +++ b/venv/Lib/site-packages/isort-5.4.2.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: poetry 1.0.5 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/venv/Lib/site-packages/isort-5.4.2.dist-info/entry_points.txt b/venv/Lib/site-packages/isort-5.4.2.dist-info/entry_points.txt new file mode 100644 index 0000000..ff609bb --- /dev/null +++ b/venv/Lib/site-packages/isort-5.4.2.dist-info/entry_points.txt @@ -0,0 +1,9 @@ +[console_scripts] +isort=isort.main:main + +[distutils.commands] +isort=isort.main:ISortCommand + +[pylama.linter] +isort=isort=isort.pylama_isort:Linter + diff --git a/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/AUTHORS.rst b/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/AUTHORS.rst new file mode 100644 index 0000000..6f2cf90 --- /dev/null +++ b/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/AUTHORS.rst @@ -0,0 +1,11 @@ + +Authors +======= + +* Ionel Cristian Mărieș - https://blog.ionelmc.ro +* Alvin Chow - https://github.com/alvinchow86 +* Astrum Kuo - https://github.com/xowenx +* Erik M. Bray - http://iguananaut.net +* Ran Benita - https://github.com/bluetech +* "hugovk" - https://github.com/hugovk +* Sandro Tosi - https://github.com/sandrotosi diff --git a/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/INSTALLER b/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/LICENSE b/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/LICENSE new file mode 100644 index 0000000..07630f9 --- /dev/null +++ b/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/LICENSE @@ -0,0 +1,20 @@ +BSD 2-Clause License + +Copyright (c) 2014-2023, Ionel Cristian Mărieș. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/METADATA b/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/METADATA new file mode 100644 index 0000000..3adc254 --- /dev/null +++ b/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/METADATA @@ -0,0 +1,234 @@ +Metadata-Version: 2.1 +Name: lazy-object-proxy +Version: 1.9.0 +Summary: A fast and thorough lazy object proxy. +Home-page: https://github.com/ionelmc/python-lazy-object-proxy +Author: Ionel Cristian Mărieș +Author-email: contact@ionelmc.ro +License: BSD-2-Clause +Project-URL: Documentation, https://python-lazy-object-proxy.readthedocs.io/ +Project-URL: Changelog, https://python-lazy-object-proxy.readthedocs.io/en/latest/changelog.html +Project-URL: Issue Tracker, https://github.com/ionelmc/python-lazy-object-proxy/issues +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: Unix +Classifier: Operating System :: POSIX +Classifier: Operating System :: Microsoft :: Windows +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Utilities +Requires-Python: >=3.7 +License-File: LICENSE +License-File: AUTHORS.rst + +======== +Overview +======== + + + +A fast and thorough lazy object proxy. + +* Free software: BSD 2-Clause License + +Note that this is based on `wrapt`_'s ObjectProxy with one big change: it calls a function the first time the proxy object is +used, while `wrapt.ObjectProxy` just forwards the method calls to the target object. + +In other words, you use `lazy-object-proxy` when you only have the object way later and you use `wrapt.ObjectProxy` when you +want to override few methods (by subclassing) and forward everything else to the target object. + +Example:: + + import lazy_object_proxy + + def expensive_func(): + from time import sleep + print('starting calculation') + # just as example for a very slow computation + sleep(2) + print('finished calculation') + # return the result of the calculation + return 10 + + obj = lazy_object_proxy.Proxy(expensive_func) + # function is called only when object is actually used + print(obj) # now expensive_func is called + + print(obj) # the result without calling the expensive_func + +Installation +============ + +:: + + pip install lazy-object-proxy + +Documentation +============= + +https://python-lazy-object-proxy.readthedocs.io/ + +Development +=========== + +To run all the tests run:: + + tox + +Acknowledgements +================ + +This project is based on some code from `wrapt`_ as you can see in the git history. + +.. _wrapt: https://github.com/GrahamDumpleton/wrapt + + +Changelog +========= + +1.9.0 (2023-01-04) +------------------ + +* Added support for matrix multiplication operator (``@``). +* Should have all the wheels now (including the manylinux ones). +* Bumped minimum version requirements for setuptools and setuptools-scm. +* Switched the default pure python fallback implementation to the "simple" one (when you ``from lazy_object_proxy import Proxy`` + and the C extension is not available). + Previously the "slots" implementation was used but as it turns out it is slower on Python 3. + +1.8.0 (2022-10-26) +------------------ + +* Cleaned up use of cPickle. Contributed by Sandro Tosi in `#62 `_. +* Cleaned up more dead Python 2 code. +* Added Python 3.11 wheels. +* Dropped support for Python 3.6. + +1.7.1 (2021-12-15) +------------------ + +* Removed most of the Python 2 support code and fixed ``python_requires`` to require at least Python 3.6. + + Note that 1.7.0 has been yanked because it could not install on Python 2.7. + Installing lazy-object-proxy on Python 2.7 should automatically fall back to the 1.6.0 release now. + +1.7.0 (2021-12-15) +------------------ + +* Switched CI to GitHub Actions, this has a couple consequences: + + * Support for Python 2.7 is dropped. You can still install it there but it's not tested anymore and + Python 2 specific handling will be removed at some point. + * Linux wheels are now provided in `musllinux` and `manylinux2014` variants. + +* Fixed ``__index__`` to fallback to ``int`` if the wrapped object doesn't have an ``__index__`` method. + This prevents situations where code using a proxy would otherwise likely just call ``int`` had the object + not have an ``__index__`` method. + +1.6.0 (2021-03-22) +------------------ + +* Added support for async special methods (``__aiter__``, ``__anext__``, + ``__await__``, ``__aenter__``, ``__aexit__``). + These are used in the ``async for``, ``await` and ``async with`` statements. + + Note that ``__await__`` returns a wrapper that tries to emulate the crazy + stuff going on in the ceval loop, so there will be a small performance overhead. +* Added the ``__resolved__`` property. You can use it to check if the factory has + been called. + +1.5.2 (2020-11-26) +------------------ + +* Added Python 3.9 wheels. +* Removed Python 2.7 Windows wheels + (not supported on newest image with Python 3.9). + +1.5.1 (2020-07-22) +------------------ + +* Added ARM64 wheels (manylinux2014). + +1.5.0 (2020-06-05) +------------------ + +* Added support for ``__fspath__``. +* Dropped support for Python 3.4. + +1.4.3 (2019-10-26) +------------------ + +* Added binary wheels for Python 3.8. +* Fixed license metadata. + +1.4.2 (2019-08-22) +------------------ + +* Included a ``pyproject.toml`` to allow users install the sdist with old python/setuptools, as the + setuptools-scm dep will be fetched by pip instead of setuptools. + Fixes `#30 `_. + +1.4.1 (2019-05-10) +------------------ + +* Fixed wheels being built with ``-coverage`` cflags. No more issues about bogus ``cext.gcda`` files. +* Removed useless C file from wheels. +* Changed ``setup.py`` to use setuptools-scm. + +1.4.0 (2019-05-05) +------------------ + +* Fixed ``__mod__`` for the slots backend. Contributed by Ran Benita in + `#28 `_. +* Dropped support for Python 2.6 and 3.3. Contributed by "hugovk" in + `#24 `_. + +1.3.1 (2017-05-05) +------------------ + +* Fix broken release (``sdist`` had a broken ``MANIFEST.in``). + +1.3.0 (2017-05-02) +------------------ + +* Speed up arithmetic operations involving ``cext.Proxy`` subclasses. + +1.2.2 (2016-04-14) +------------------ + +* Added `manylinux `_ wheels. +* Minor cleanup in readme. + +1.2.1 (2015-08-18) +------------------ + +* Fix a memory leak (the wrapped object would get bogus references). Contributed by Astrum Kuo in + `#10 `_. + +1.2.0 (2015-07-06) +------------------ + +* Don't instantiate the object when __repr__ is called. This aids with debugging (allows one to see exactly in + what state the proxy is). + +1.1.0 (2015-07-05) +------------------ + +* Added support for pickling. The pickled value is going to be the wrapped object *without* any Proxy container. +* Fixed a memory management issue in the C extension (reference cycles weren't garbage collected due to improper + handling in the C extension). Contributed by Alvin Chow in + `#8 `_. + +1.0.2 (2015-04-11) +----------------------------------------- + +* First release on PyPI. diff --git a/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/RECORD b/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/RECORD new file mode 100644 index 0000000..7983a24 --- /dev/null +++ b/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/RECORD @@ -0,0 +1,20 @@ +lazy_object_proxy-1.9.0.dist-info/AUTHORS.rst,sha256=BXzzE754hWsdSKLEA_m3uMCXZ9liwbOi7m4BgP88jXU,335 +lazy_object_proxy-1.9.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +lazy_object_proxy-1.9.0.dist-info/LICENSE,sha256=_daXxLk0Y3hHBaV7P8NemhVFgeAyJfZMhXT_Gqbx7dw,1350 +lazy_object_proxy-1.9.0.dist-info/METADATA,sha256=S_ONLuMkmbHkyWpxt1qPJz4pxbDswTl8M2Dv1lpfaeE,7860 +lazy_object_proxy-1.9.0.dist-info/RECORD,, +lazy_object_proxy-1.9.0.dist-info/WHEEL,sha256=J_4V_gB-O6Y7Pn6lk91K27JaIhI-q07YM5J8Ufzqla4,100 +lazy_object_proxy-1.9.0.dist-info/top_level.txt,sha256=UNH-FQB-j_8bYqPz3gD90kHvaC42TQqY0thHSnbaa0k,18 +lazy_object_proxy/__init__.py,sha256=hdC4Jn4aK-6qexwhxn-nPIyI9Lb4Vf-W0VHPECSyFwE,436 +lazy_object_proxy/__pycache__/__init__.cpython-39.pyc,, +lazy_object_proxy/__pycache__/_version.cpython-39.pyc,, +lazy_object_proxy/__pycache__/compat.cpython-39.pyc,, +lazy_object_proxy/__pycache__/simple.cpython-39.pyc,, +lazy_object_proxy/__pycache__/slots.cpython-39.pyc,, +lazy_object_proxy/__pycache__/utils.cpython-39.pyc,, +lazy_object_proxy/_version.py,sha256=bDWiNOi5QinSMKh-KF9Qhv4NLsMX1JYLEHJGPTrog3Q,164 +lazy_object_proxy/cext.cp39-win_amd64.pyd,sha256=u8alZ84JQQpRbfMfRWvQZHFBG4VYViFoig7qnu9stnc,30720 +lazy_object_proxy/compat.py,sha256=Wc1O82maPd_Cwwb-2AHP3SxACP9V9ByWqkh6jLNh67s,154 +lazy_object_proxy/simple.py,sha256=lZUe5gY8PNLXCFAXf6xO303vBLVbhJBKx_W_8ng7Ot4,8959 +lazy_object_proxy/slots.py,sha256=yBReRTdlObRyeGmC_h6OIu8KE-QS5yYuE1LfLeAClJk,12702 +lazy_object_proxy/utils.py,sha256=cqqNQblVWH-MXtVkzAvEll2b1yO5m0QhM-z6eR2zblU,1273 diff --git a/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/WHEEL b/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/WHEEL new file mode 100644 index 0000000..d22c9ab --- /dev/null +++ b/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.38.4) +Root-Is-Purelib: false +Tag: cp39-cp39-win_amd64 + diff --git a/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/top_level.txt b/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/top_level.txt new file mode 100644 index 0000000..bdf032e --- /dev/null +++ b/venv/Lib/site-packages/lazy_object_proxy-1.9.0.dist-info/top_level.txt @@ -0,0 +1 @@ +lazy_object_proxy diff --git a/venv/Lib/site-packages/mccabe-0.6.1.dist-info/DESCRIPTION.rst b/venv/Lib/site-packages/mccabe-0.6.1.dist-info/DESCRIPTION.rst new file mode 100644 index 0000000..de61068 --- /dev/null +++ b/venv/Lib/site-packages/mccabe-0.6.1.dist-info/DESCRIPTION.rst @@ -0,0 +1,152 @@ +McCabe complexity checker +========================= + +Ned's script to check McCabe complexity. + +This module provides a plugin for ``flake8``, the Python code checker. + + +Installation +------------ + +You can install, upgrade, uninstall ``mccabe`` with these commands:: + + $ pip install mccabe + $ pip install --upgrade mccabe + $ pip uninstall mccabe + + +Standalone script +----------------- + +The complexity checker can be used directly:: + + $ python -m mccabe --min 5 mccabe.py + ("185:1: 'PathGraphingAstVisitor.visitIf'", 5) + ("71:1: 'PathGraph.to_dot'", 5) + ("245:1: 'McCabeChecker.run'", 5) + ("283:1: 'main'", 7) + ("203:1: 'PathGraphingAstVisitor.visitTryExcept'", 5) + ("257:1: 'get_code_complexity'", 5) + + +Plugin for Flake8 +----------------- + +When both ``flake8 2.0`` and ``mccabe`` are installed, the plugin is +available in ``flake8``:: + + $ flake8 --version + 2.0 (pep8: 1.4.2, pyflakes: 0.6.1, mccabe: 0.2) + +By default the plugin is disabled. Use the ``--max-complexity`` switch to +enable it. It will emit a warning if the McCabe complexity of a function is +higher that the value:: + + $ flake8 --max-complexity 10 coolproject + ... + coolproject/mod.py:1204:1: C901 'CoolFactory.prepare' is too complex (14) + +This feature is quite useful to detect over-complex code. According to McCabe, +anything that goes beyond 10 is too complex. + + +Links +----- + +* Feedback and ideas: http://mail.python.org/mailman/listinfo/code-quality + +* Cyclomatic complexity: http://en.wikipedia.org/wiki/Cyclomatic_complexity. + +* Ned Batchelder's script: + http://nedbatchelder.com/blog/200803/python_code_complexity_microtool.html + + +Changes +------- + +0.6.1 - 2017-01-26 +`````````````````` + +* Fix signature for ``PathGraphingAstVisitor.default`` to match the signature + for ``ASTVisitor`` + +0.6.0 - 2017-01-23 +`````````````````` + +* Add support for Python 3.6 + +* Fix handling for missing statement types + +0.5.3 - 2016-12-14 +`````````````````` + +* Report actual column number of violation instead of the start of the line + +0.5.2 - 2016-07-31 +`````````````````` + +* When opening files ourselves, make sure we always name the file variable + +0.5.1 - 2016-07-28 +`````````````````` + +* Set default maximum complexity to -1 on the class itself + +0.5.0 - 2016-05-30 +`````````````````` + +* PyCon 2016 PDX release + +* Add support for Flake8 3.0 + +0.4.0 - 2016-01-27 +`````````````````` + +* Stop testing on Python 3.2 + +* Add support for async/await keywords on Python 3.5 from PEP 0492 + +0.3.1 - 2015-06-14 +`````````````````` + +* Include ``test_mccabe.py`` in releases. + +* Always coerce the ``max_complexity`` value from Flake8's entry-point to an + integer. + +0.3 - 2014-12-17 +```````````````` + +* Computation was wrong: the mccabe complexity starts at 1, not 2. + +* The ``max-complexity`` value is now inclusive. E.g.: if the + value is 10 and the reported complexity is 10, then it passes. + +* Add tests. + + +0.2.1 - 2013-04-03 +`````````````````` + +* Do not require ``setuptools`` in setup.py. It works around an issue + with ``pip`` and Python 3. + + +0.2 - 2013-02-22 +```````````````` + +* Rename project to ``mccabe``. + +* Provide ``flake8.extension`` setuptools entry point. + +* Read ``max-complexity`` from the configuration file. + +* Rename argument ``min_complexity`` to ``threshold``. + + +0.1 - 2013-02-11 +```````````````` +* First release + + diff --git a/venv/Lib/site-packages/mccabe-0.6.1.dist-info/INSTALLER b/venv/Lib/site-packages/mccabe-0.6.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/mccabe-0.6.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/mccabe-0.6.1.dist-info/METADATA b/venv/Lib/site-packages/mccabe-0.6.1.dist-info/METADATA new file mode 100644 index 0000000..f22645f --- /dev/null +++ b/venv/Lib/site-packages/mccabe-0.6.1.dist-info/METADATA @@ -0,0 +1,178 @@ +Metadata-Version: 2.0 +Name: mccabe +Version: 0.6.1 +Summary: McCabe checker, plugin for flake8 +Home-page: https://github.com/pycqa/mccabe +Author: Ian Cordasco +Author-email: graffatcolmingov@gmail.com +License: Expat license +Keywords: flake8 mccabe +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Software Development :: Quality Assurance + +McCabe complexity checker +========================= + +Ned's script to check McCabe complexity. + +This module provides a plugin for ``flake8``, the Python code checker. + + +Installation +------------ + +You can install, upgrade, uninstall ``mccabe`` with these commands:: + + $ pip install mccabe + $ pip install --upgrade mccabe + $ pip uninstall mccabe + + +Standalone script +----------------- + +The complexity checker can be used directly:: + + $ python -m mccabe --min 5 mccabe.py + ("185:1: 'PathGraphingAstVisitor.visitIf'", 5) + ("71:1: 'PathGraph.to_dot'", 5) + ("245:1: 'McCabeChecker.run'", 5) + ("283:1: 'main'", 7) + ("203:1: 'PathGraphingAstVisitor.visitTryExcept'", 5) + ("257:1: 'get_code_complexity'", 5) + + +Plugin for Flake8 +----------------- + +When both ``flake8 2.0`` and ``mccabe`` are installed, the plugin is +available in ``flake8``:: + + $ flake8 --version + 2.0 (pep8: 1.4.2, pyflakes: 0.6.1, mccabe: 0.2) + +By default the plugin is disabled. Use the ``--max-complexity`` switch to +enable it. It will emit a warning if the McCabe complexity of a function is +higher that the value:: + + $ flake8 --max-complexity 10 coolproject + ... + coolproject/mod.py:1204:1: C901 'CoolFactory.prepare' is too complex (14) + +This feature is quite useful to detect over-complex code. According to McCabe, +anything that goes beyond 10 is too complex. + + +Links +----- + +* Feedback and ideas: http://mail.python.org/mailman/listinfo/code-quality + +* Cyclomatic complexity: http://en.wikipedia.org/wiki/Cyclomatic_complexity. + +* Ned Batchelder's script: + http://nedbatchelder.com/blog/200803/python_code_complexity_microtool.html + + +Changes +------- + +0.6.1 - 2017-01-26 +`````````````````` + +* Fix signature for ``PathGraphingAstVisitor.default`` to match the signature + for ``ASTVisitor`` + +0.6.0 - 2017-01-23 +`````````````````` + +* Add support for Python 3.6 + +* Fix handling for missing statement types + +0.5.3 - 2016-12-14 +`````````````````` + +* Report actual column number of violation instead of the start of the line + +0.5.2 - 2016-07-31 +`````````````````` + +* When opening files ourselves, make sure we always name the file variable + +0.5.1 - 2016-07-28 +`````````````````` + +* Set default maximum complexity to -1 on the class itself + +0.5.0 - 2016-05-30 +`````````````````` + +* PyCon 2016 PDX release + +* Add support for Flake8 3.0 + +0.4.0 - 2016-01-27 +`````````````````` + +* Stop testing on Python 3.2 + +* Add support for async/await keywords on Python 3.5 from PEP 0492 + +0.3.1 - 2015-06-14 +`````````````````` + +* Include ``test_mccabe.py`` in releases. + +* Always coerce the ``max_complexity`` value from Flake8's entry-point to an + integer. + +0.3 - 2014-12-17 +```````````````` + +* Computation was wrong: the mccabe complexity starts at 1, not 2. + +* The ``max-complexity`` value is now inclusive. E.g.: if the + value is 10 and the reported complexity is 10, then it passes. + +* Add tests. + + +0.2.1 - 2013-04-03 +`````````````````` + +* Do not require ``setuptools`` in setup.py. It works around an issue + with ``pip`` and Python 3. + + +0.2 - 2013-02-22 +```````````````` + +* Rename project to ``mccabe``. + +* Provide ``flake8.extension`` setuptools entry point. + +* Read ``max-complexity`` from the configuration file. + +* Rename argument ``min_complexity`` to ``threshold``. + + +0.1 - 2013-02-11 +```````````````` +* First release + + diff --git a/venv/Lib/site-packages/mccabe-0.6.1.dist-info/RECORD b/venv/Lib/site-packages/mccabe-0.6.1.dist-info/RECORD new file mode 100644 index 0000000..88d4a9d --- /dev/null +++ b/venv/Lib/site-packages/mccabe-0.6.1.dist-info/RECORD @@ -0,0 +1,10 @@ +__pycache__/mccabe.cpython-39.pyc,, +mccabe-0.6.1.dist-info/DESCRIPTION.rst,sha256=lGHJ-Y3IviuP3DRqLL_TXPUr3wJ2GZ8XJkAV6ve3O58,3302 +mccabe-0.6.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +mccabe-0.6.1.dist-info/METADATA,sha256=jawnTfTVrlzBSmeI-cTXSRIwIlijODtZdj-padBqIv0,4324 +mccabe-0.6.1.dist-info/RECORD,, +mccabe-0.6.1.dist-info/WHEEL,sha256=o2k-Qa-RMNIJmUdIc7KU6VWR_ErNRbWNlxDIpl7lm34,110 +mccabe-0.6.1.dist-info/entry_points.txt,sha256=N2NH182GXTUyTm8r8XMgadb9C-CRa5dUr1k8OC91uGE,47 +mccabe-0.6.1.dist-info/metadata.json,sha256=e508OR4t6_G7h7eO2C6NHlHQqVpPZZH1_DlAPrVECYM,1218 +mccabe-0.6.1.dist-info/top_level.txt,sha256=21cXuqZE-lpcfAqqANvX9EjI1ED1p8zcViv064u3RKA,7 +mccabe.py,sha256=XPMywdQshG_5nSjckb-OzNqnCQuXQvy3FTClspKwGQA,10693 diff --git a/venv/Lib/site-packages/mccabe-0.6.1.dist-info/WHEEL b/venv/Lib/site-packages/mccabe-0.6.1.dist-info/WHEEL new file mode 100644 index 0000000..8b6dd1b --- /dev/null +++ b/venv/Lib/site-packages/mccabe-0.6.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.29.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/mccabe-0.6.1.dist-info/entry_points.txt b/venv/Lib/site-packages/mccabe-0.6.1.dist-info/entry_points.txt new file mode 100644 index 0000000..cc6645b --- /dev/null +++ b/venv/Lib/site-packages/mccabe-0.6.1.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[flake8.extension] +C90 = mccabe:McCabeChecker + diff --git a/venv/Lib/site-packages/mccabe-0.6.1.dist-info/metadata.json b/venv/Lib/site-packages/mccabe-0.6.1.dist-info/metadata.json new file mode 100644 index 0000000..ae04d8f --- /dev/null +++ b/venv/Lib/site-packages/mccabe-0.6.1.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Quality Assurance"], "extensions": {"python.details": {"contacts": [{"email": "graffatcolmingov@gmail.com", "name": "Ian Cordasco", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/pycqa/mccabe"}}, "python.exports": {"flake8.extension": {"C90": "mccabe:McCabeChecker"}}}, "generator": "bdist_wheel (0.29.0)", "keywords": ["flake8", "mccabe"], "license": "Expat license", "metadata_version": "2.0", "name": "mccabe", "summary": "McCabe checker, plugin for flake8", "test_requires": [{"requires": ["pytest"]}], "version": "0.6.1"} \ No newline at end of file diff --git a/venv/Lib/site-packages/mccabe-0.6.1.dist-info/top_level.txt b/venv/Lib/site-packages/mccabe-0.6.1.dist-info/top_level.txt new file mode 100644 index 0000000..8831b36 --- /dev/null +++ b/venv/Lib/site-packages/mccabe-0.6.1.dist-info/top_level.txt @@ -0,0 +1 @@ +mccabe diff --git a/venv/Lib/site-packages/mccabe.py b/venv/Lib/site-packages/mccabe.py new file mode 100644 index 0000000..c0cda75 --- /dev/null +++ b/venv/Lib/site-packages/mccabe.py @@ -0,0 +1,347 @@ +""" Meager code path measurement tool. + Ned Batchelder + http://nedbatchelder.com/blog/200803/python_code_complexity_microtool.html + MIT License. +""" +from __future__ import with_statement + +import optparse +import sys +import tokenize + +from collections import defaultdict +try: + import ast + from ast import iter_child_nodes +except ImportError: # Python 2.5 + from flake8.util import ast, iter_child_nodes + +__version__ = '0.6.1' + + +class ASTVisitor(object): + """Performs a depth-first walk of the AST.""" + + def __init__(self): + self.node = None + self._cache = {} + + def default(self, node, *args): + for child in iter_child_nodes(node): + self.dispatch(child, *args) + + def dispatch(self, node, *args): + self.node = node + klass = node.__class__ + meth = self._cache.get(klass) + if meth is None: + className = klass.__name__ + meth = getattr(self.visitor, 'visit' + className, self.default) + self._cache[klass] = meth + return meth(node, *args) + + def preorder(self, tree, visitor, *args): + """Do preorder walk of tree using visitor""" + self.visitor = visitor + visitor.visit = self.dispatch + self.dispatch(tree, *args) # XXX *args make sense? + + +class PathNode(object): + def __init__(self, name, look="circle"): + self.name = name + self.look = look + + def to_dot(self): + print('node [shape=%s,label="%s"] %d;' % ( + self.look, self.name, self.dot_id())) + + def dot_id(self): + return id(self) + + +class PathGraph(object): + def __init__(self, name, entity, lineno, column=0): + self.name = name + self.entity = entity + self.lineno = lineno + self.column = column + self.nodes = defaultdict(list) + + def connect(self, n1, n2): + self.nodes[n1].append(n2) + # Ensure that the destination node is always counted. + self.nodes[n2] = [] + + def to_dot(self): + print('subgraph {') + for node in self.nodes: + node.to_dot() + for node, nexts in self.nodes.items(): + for next in nexts: + print('%s -- %s;' % (node.dot_id(), next.dot_id())) + print('}') + + def complexity(self): + """ Return the McCabe complexity for the graph. + V-E+2 + """ + num_edges = sum([len(n) for n in self.nodes.values()]) + num_nodes = len(self.nodes) + return num_edges - num_nodes + 2 + + +class PathGraphingAstVisitor(ASTVisitor): + """ A visitor for a parsed Abstract Syntax Tree which finds executable + statements. + """ + + def __init__(self): + super(PathGraphingAstVisitor, self).__init__() + self.classname = "" + self.graphs = {} + self.reset() + + def reset(self): + self.graph = None + self.tail = None + + def dispatch_list(self, node_list): + for node in node_list: + self.dispatch(node) + + def visitFunctionDef(self, node): + + if self.classname: + entity = '%s%s' % (self.classname, node.name) + else: + entity = node.name + + name = '%d:%d: %r' % (node.lineno, node.col_offset, entity) + + if self.graph is not None: + # closure + pathnode = self.appendPathNode(name) + self.tail = pathnode + self.dispatch_list(node.body) + bottom = PathNode("", look='point') + self.graph.connect(self.tail, bottom) + self.graph.connect(pathnode, bottom) + self.tail = bottom + else: + self.graph = PathGraph(name, entity, node.lineno, node.col_offset) + pathnode = PathNode(name) + self.tail = pathnode + self.dispatch_list(node.body) + self.graphs["%s%s" % (self.classname, node.name)] = self.graph + self.reset() + + visitAsyncFunctionDef = visitFunctionDef + + def visitClassDef(self, node): + old_classname = self.classname + self.classname += node.name + "." + self.dispatch_list(node.body) + self.classname = old_classname + + def appendPathNode(self, name): + if not self.tail: + return + pathnode = PathNode(name) + self.graph.connect(self.tail, pathnode) + self.tail = pathnode + return pathnode + + def visitSimpleStatement(self, node): + if node.lineno is None: + lineno = 0 + else: + lineno = node.lineno + name = "Stmt %d" % lineno + self.appendPathNode(name) + + def default(self, node, *args): + if isinstance(node, ast.stmt): + self.visitSimpleStatement(node) + else: + super(PathGraphingAstVisitor, self).default(node, *args) + + def visitLoop(self, node): + name = "Loop %d" % node.lineno + self._subgraph(node, name) + + visitAsyncFor = visitFor = visitWhile = visitLoop + + def visitIf(self, node): + name = "If %d" % node.lineno + self._subgraph(node, name) + + def _subgraph(self, node, name, extra_blocks=()): + """create the subgraphs representing any `if` and `for` statements""" + if self.graph is None: + # global loop + self.graph = PathGraph(name, name, node.lineno, node.col_offset) + pathnode = PathNode(name) + self._subgraph_parse(node, pathnode, extra_blocks) + self.graphs["%s%s" % (self.classname, name)] = self.graph + self.reset() + else: + pathnode = self.appendPathNode(name) + self._subgraph_parse(node, pathnode, extra_blocks) + + def _subgraph_parse(self, node, pathnode, extra_blocks): + """parse the body and any `else` block of `if` and `for` statements""" + loose_ends = [] + self.tail = pathnode + self.dispatch_list(node.body) + loose_ends.append(self.tail) + for extra in extra_blocks: + self.tail = pathnode + self.dispatch_list(extra.body) + loose_ends.append(self.tail) + if node.orelse: + self.tail = pathnode + self.dispatch_list(node.orelse) + loose_ends.append(self.tail) + else: + loose_ends.append(pathnode) + if pathnode: + bottom = PathNode("", look='point') + for le in loose_ends: + self.graph.connect(le, bottom) + self.tail = bottom + + def visitTryExcept(self, node): + name = "TryExcept %d" % node.lineno + self._subgraph(node, name, extra_blocks=node.handlers) + + visitTry = visitTryExcept + + def visitWith(self, node): + name = "With %d" % node.lineno + self.appendPathNode(name) + self.dispatch_list(node.body) + + visitAsyncWith = visitWith + + +class McCabeChecker(object): + """McCabe cyclomatic complexity checker.""" + name = 'mccabe' + version = __version__ + _code = 'C901' + _error_tmpl = "C901 %r is too complex (%d)" + max_complexity = -1 + + def __init__(self, tree, filename): + self.tree = tree + + @classmethod + def add_options(cls, parser): + flag = '--max-complexity' + kwargs = { + 'default': -1, + 'action': 'store', + 'type': 'int', + 'help': 'McCabe complexity threshold', + 'parse_from_config': 'True', + } + config_opts = getattr(parser, 'config_options', None) + if isinstance(config_opts, list): + # Flake8 2.x + kwargs.pop('parse_from_config') + parser.add_option(flag, **kwargs) + parser.config_options.append('max-complexity') + else: + parser.add_option(flag, **kwargs) + + @classmethod + def parse_options(cls, options): + cls.max_complexity = int(options.max_complexity) + + def run(self): + if self.max_complexity < 0: + return + visitor = PathGraphingAstVisitor() + visitor.preorder(self.tree, visitor) + for graph in visitor.graphs.values(): + if graph.complexity() > self.max_complexity: + text = self._error_tmpl % (graph.entity, graph.complexity()) + yield graph.lineno, graph.column, text, type(self) + + +def get_code_complexity(code, threshold=7, filename='stdin'): + try: + tree = compile(code, filename, "exec", ast.PyCF_ONLY_AST) + except SyntaxError: + e = sys.exc_info()[1] + sys.stderr.write("Unable to parse %s: %s\n" % (filename, e)) + return 0 + + complx = [] + McCabeChecker.max_complexity = threshold + for lineno, offset, text, check in McCabeChecker(tree, filename).run(): + complx.append('%s:%d:1: %s' % (filename, lineno, text)) + + if len(complx) == 0: + return 0 + print('\n'.join(complx)) + return len(complx) + + +def get_module_complexity(module_path, threshold=7): + """Returns the complexity of a module""" + with open(module_path, "rU") as mod: + code = mod.read() + return get_code_complexity(code, threshold, filename=module_path) + + +def _read(filename): + if (2, 5) < sys.version_info < (3, 0): + with open(filename, 'rU') as f: + return f.read() + elif (3, 0) <= sys.version_info < (4, 0): + """Read the source code.""" + try: + with open(filename, 'rb') as f: + (encoding, _) = tokenize.detect_encoding(f.readline) + except (LookupError, SyntaxError, UnicodeError): + # Fall back if file encoding is improperly declared + with open(filename, encoding='latin-1') as f: + return f.read() + with open(filename, 'r', encoding=encoding) as f: + return f.read() + + +def main(argv=None): + if argv is None: + argv = sys.argv[1:] + opar = optparse.OptionParser() + opar.add_option("-d", "--dot", dest="dot", + help="output a graphviz dot file", action="store_true") + opar.add_option("-m", "--min", dest="threshold", + help="minimum complexity for output", type="int", + default=1) + + options, args = opar.parse_args(argv) + + code = _read(args[0]) + tree = compile(code, args[0], "exec", ast.PyCF_ONLY_AST) + visitor = PathGraphingAstVisitor() + visitor.preorder(tree, visitor) + + if options.dot: + print('graph {') + for graph in visitor.graphs.values(): + if (not options.threshold or + graph.complexity() >= options.threshold): + graph.to_dot() + print('}') + else: + for graph in visitor.graphs.values(): + if graph.complexity() >= options.threshold: + print(graph.name, graph.complexity()) + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/venv/Lib/site-packages/more_itertools-9.0.0.dist-info/INSTALLER b/venv/Lib/site-packages/more_itertools-9.0.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/more_itertools-9.0.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/more_itertools-9.0.0.dist-info/LICENSE b/venv/Lib/site-packages/more_itertools-9.0.0.dist-info/LICENSE new file mode 100644 index 0000000..0a523be --- /dev/null +++ b/venv/Lib/site-packages/more_itertools-9.0.0.dist-info/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012 Erik Rose + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/venv/Lib/site-packages/more_itertools-9.0.0.dist-info/METADATA b/venv/Lib/site-packages/more_itertools-9.0.0.dist-info/METADATA new file mode 100644 index 0000000..bd98892 --- /dev/null +++ b/venv/Lib/site-packages/more_itertools-9.0.0.dist-info/METADATA @@ -0,0 +1,241 @@ +Metadata-Version: 2.1 +Name: more-itertools +Version: 9.0.0 +Summary: More routines for operating on iterables, beyond itertools +Keywords: itertools,iterator,iteration,filter,peek,peekable,chunk,chunked +Author-email: Erik Rose +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Natural Language :: English +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Software Development :: Libraries +Project-URL: Homepage, https://github.com/more-itertools/more-itertools + +============== +More Itertools +============== + +.. image:: https://readthedocs.org/projects/more-itertools/badge/?version=latest + :target: https://more-itertools.readthedocs.io/en/stable/ + +Python's ``itertools`` library is a gem - you can compose elegant solutions +for a variety of problems with the functions it provides. In ``more-itertools`` +we collect additional building blocks, recipes, and routines for working with +Python iterables. + ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Grouping | `chunked `_, | +| | `ichunked `_, | +| | `chunked_even `_, | +| | `sliced `_, | +| | `constrained_batches `_, | +| | `distribute `_, | +| | `divide `_, | +| | `split_at `_, | +| | `split_before `_, | +| | `split_after `_, | +| | `split_into `_, | +| | `split_when `_, | +| | `bucket `_, | +| | `unzip `_, | +| | `batched `_, | +| | `grouper `_, | +| | `partition `_ | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Lookahead and lookback | `spy `_, | +| | `peekable `_, | +| | `seekable `_ | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Windowing | `windowed `_, | +| | `substrings `_, | +| | `substrings_indexes `_, | +| | `stagger `_, | +| | `windowed_complete `_, | +| | `pairwise `_, | +| | `triplewise `_, | +| | `sliding_window `_, | +| | `subslices `_ | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Augmenting | `count_cycle `_, | +| | `intersperse `_, | +| | `padded `_, | +| | `repeat_each `_, | +| | `mark_ends `_, | +| | `repeat_last `_, | +| | `adjacent `_, | +| | `groupby_transform `_, | +| | `pad_none `_, | +| | `ncycles `_ | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Combining | `collapse `_, | +| | `sort_together `_, | +| | `interleave `_, | +| | `interleave_longest `_, | +| | `interleave_evenly `_, | +| | `zip_offset `_, | +| | `zip_equal `_, | +| | `zip_broadcast `_, | +| | `dotproduct `_, | +| | `convolve `_, | +| | `flatten `_, | +| | `roundrobin `_, | +| | `prepend `_, | +| | `value_chain `_ | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Summarizing | `ilen `_, | +| | `unique_to_each `_, | +| | `sample `_, | +| | `consecutive_groups `_, | +| | `run_length `_, | +| | `map_reduce `_, | +| | `exactly_n `_, | +| | `is_sorted `_, | +| | `all_equal `_, | +| | `all_unique `_, | +| | `minmax `_, | +| | `first_true `_, | +| | `quantify `_, | +| | `iequals `_ | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Selecting | `islice_extended `_, | +| | `first `_, | +| | `last `_, | +| | `one `_, | +| | `only `_, | +| | `strictly_n `_, | +| | `strip `_, | +| | `lstrip `_, | +| | `rstrip `_, | +| | `filter_except `_, | +| | `map_except `_, | +| | `nth_or_last `_, | +| | `unique_in_window `_, | +| | `before_and_after `_, | +| | `nth `_, | +| | `take `_, | +| | `tail `_, | +| | `unique_everseen `_, | +| | `unique_justseen `_, | +| | `duplicates_everseen `_, | +| | `duplicates_justseen `_, | +| | `longest_common_prefix `_ | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Combinatorics | `distinct_permutations `_, | +| | `distinct_combinations `_, | +| | `circular_shifts `_, | +| | `partitions `_, | +| | `set_partitions `_, | +| | `product_index `_, | +| | `combination_index `_, | +| | `permutation_index `_, | +| | `powerset `_, | +| | `random_product `_, | +| | `random_permutation `_, | +| | `random_combination `_, | +| | `random_combination_with_replacement `_, | +| | `nth_product `_, | +| | `nth_permutation `_, | +| | `nth_combination `_ | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Wrapping | `always_iterable `_, | +| | `always_reversible `_, | +| | `countable `_, | +| | `consumer `_, | +| | `with_iter `_, | +| | `iter_except `_ | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Others | `locate `_, | +| | `rlocate `_, | +| | `replace `_, | +| | `numeric_range `_, | +| | `side_effect `_, | +| | `iterate `_, | +| | `difference `_, | +| | `make_decorator `_, | +| | `SequenceView `_, | +| | `time_limited `_, | +| | `map_if `_, | +| | `consume `_, | +| | `tabulate `_, | +| | `repeatfunc `_ | +| | `polynomial_from_roots `_ | +| | `sieve `_ | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +Getting started +=============== + +To get started, install the library with `pip `_: + +.. code-block:: shell + + pip install more-itertools + +The recipes from the `itertools docs `_ +are included in the top-level package: + +.. code-block:: python + + >>> from more_itertools import flatten + >>> iterable = [(0, 1), (2, 3)] + >>> list(flatten(iterable)) + [0, 1, 2, 3] + +Several new recipes are available as well: + +.. code-block:: python + + >>> from more_itertools import chunked + >>> iterable = [0, 1, 2, 3, 4, 5, 6, 7, 8] + >>> list(chunked(iterable, 3)) + [[0, 1, 2], [3, 4, 5], [6, 7, 8]] + + >>> from more_itertools import spy + >>> iterable = (x * x for x in range(1, 6)) + >>> head, iterable = spy(iterable, n=3) + >>> list(head) + [1, 4, 9] + >>> list(iterable) + [1, 4, 9, 16, 25] + + + +For the full listing of functions, see the `API documentation `_. + + +Links elsewhere +=============== + +Blog posts about ``more-itertools``: + +* `Yo, I heard you like decorators `__ +* `Tour of Python Itertools `__ (`Alternate `__) +* `Real-World Python More Itertools `_ + + +Development +=========== + +``more-itertools`` is maintained by `@erikrose `_ +and `@bbayles `_, with help from `many others `_. +If you have a problem or suggestion, please file a bug or pull request in this +repository. Thanks for contributing! + + +Version History +=============== + +The version history can be found in `documentation `_. + diff --git a/venv/Lib/site-packages/more_itertools-9.0.0.dist-info/RECORD b/venv/Lib/site-packages/more_itertools-9.0.0.dist-info/RECORD new file mode 100644 index 0000000..0b7e039 --- /dev/null +++ b/venv/Lib/site-packages/more_itertools-9.0.0.dist-info/RECORD @@ -0,0 +1,15 @@ +more_itertools-9.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +more_itertools-9.0.0.dist-info/LICENSE,sha256=CfHIyelBrz5YTVlkHqm4fYPAyw_QB-te85Gn4mQ8GkY,1053 +more_itertools-9.0.0.dist-info/METADATA,sha256=o71Ks93mbZ7709yvfFg09Vxgj-8t2ZZaYIyUprS8GHw,31266 +more_itertools-9.0.0.dist-info/RECORD,, +more_itertools-9.0.0.dist-info/WHEEL,sha256=4TfKIB_xu-04bc2iKz6_zFt-gEFEEDU_31HGhqzOCE8,81 +more_itertools/__init__.py,sha256=5PNQMpy400s5GB3jcWwzje0RCw8k0bvU9W_C49V0fd0,148 +more_itertools/__init__.pyi,sha256=5B3eTzON1BBuOLob1vCflyEb2lSd6usXQQ-Cv-hXkeA,43 +more_itertools/__pycache__/__init__.cpython-39.pyc,, +more_itertools/__pycache__/more.cpython-39.pyc,, +more_itertools/__pycache__/recipes.cpython-39.pyc,, +more_itertools/more.py,sha256=FmmtkT-j69qILkxEELk5ZRoZK8St1Vg_fOGW0sTFd7g,133336 +more_itertools/more.pyi,sha256=hbf2oqg56wctXwf6yM1B0QLWqsNyDrqtX2znvQRAe3Q,20297 +more_itertools/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +more_itertools/recipes.py,sha256=ZX4-2IfbZKlPIVaDITH2buX_fPuMDe1EVc6e2XSsCz8,22975 +more_itertools/recipes.pyi,sha256=NA6qqcKMbQ2fly9hCyCzMcx46Tn9TLl-9mFnZsRytZM,3851 diff --git a/venv/Lib/site-packages/more_itertools-9.0.0.dist-info/WHEEL b/venv/Lib/site-packages/more_itertools-9.0.0.dist-info/WHEEL new file mode 100644 index 0000000..668ba4d --- /dev/null +++ b/venv/Lib/site-packages/more_itertools-9.0.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.7.1 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/venv/Lib/site-packages/mypy-0.782.dist-info/INSTALLER b/venv/Lib/site-packages/mypy-0.782.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/mypy-0.782.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/mypy-0.782.dist-info/LICENSE b/venv/Lib/site-packages/mypy-0.782.dist-info/LICENSE new file mode 100644 index 0000000..c87e8c7 --- /dev/null +++ b/venv/Lib/site-packages/mypy-0.782.dist-info/LICENSE @@ -0,0 +1,227 @@ +Mypy (and mypyc) are licensed under the terms of the MIT license, reproduced below. + += = = = = + +The MIT License + +Copyright (c) 2015-2019 Jukka Lehtosalo and contributors + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + += = = = = + +Portions of mypy and mypyc are licensed under different licenses. The +files under stdlib-samples as well as the files +mypyc/lib-rt/pythonsupport.h and mypyc/lib-rt/getargs.c are licensed +under the PSF 2 License, reproduced below. + += = = = = + +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +analyze, test, perform and/or display publicly, prepare derivative works, +distribute, and otherwise use Python alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011, 2012 Python Software Foundation; All Rights Reserved" are retained in Python +alone or in any derivative version prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 +------------------------------------------- + +BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 + +1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an +office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the +Individual or Organization ("Licensee") accessing and otherwise using +this software in source or binary form and its associated +documentation ("the Software"). + +2. Subject to the terms and conditions of this BeOpen Python License +Agreement, BeOpen hereby grants Licensee a non-exclusive, +royalty-free, world-wide license to reproduce, analyze, test, perform +and/or display publicly, prepare derivative works, distribute, and +otherwise use the Software alone or in any derivative version, +provided, however, that the BeOpen Python License is retained in the +Software, alone or in any derivative version prepared by Licensee. + +3. BeOpen is making the Software available to Licensee on an "AS IS" +basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE +SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS +AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY +DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +5. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +6. This License Agreement shall be governed by and interpreted in all +respects by the law of the State of California, excluding conflict of +law provisions. Nothing in this License Agreement shall be deemed to +create any relationship of agency, partnership, or joint venture +between BeOpen and Licensee. This License Agreement does not grant +permission to use BeOpen trademarks or trade names in a trademark +sense to endorse or promote products or services of Licensee, or any +third party. As an exception, the "BeOpen Python" logos available at +http://www.pythonlabs.com/logos.html may be used according to the +permissions granted on that web page. + +7. By copying, installing or otherwise using the software, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 +--------------------------------------- + +1. This LICENSE AGREEMENT is between the Corporation for National +Research Initiatives, having an office at 1895 Preston White Drive, +Reston, VA 20191 ("CNRI"), and the Individual or Organization +("Licensee") accessing and otherwise using Python 1.6.1 software in +source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, CNRI +hereby grants Licensee a nonexclusive, royalty-free, world-wide +license to reproduce, analyze, test, perform and/or display publicly, +prepare derivative works, distribute, and otherwise use Python 1.6.1 +alone or in any derivative version, provided, however, that CNRI's +License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) +1995-2001 Corporation for National Research Initiatives; All Rights +Reserved" are retained in Python 1.6.1 alone or in any derivative +version prepared by Licensee. Alternately, in lieu of CNRI's License +Agreement, Licensee may substitute the following text (omitting the +quotes): "Python 1.6.1 is made available subject to the terms and +conditions in CNRI's License Agreement. This Agreement together with +Python 1.6.1 may be located on the Internet using the following +unique, persistent identifier (known as a handle): 1895.22/1013. This +Agreement may also be obtained from a proxy server on the Internet +using the following URL: http://hdl.handle.net/1895.22/1013". + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python 1.6.1 or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python 1.6.1. + +4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" +basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. This License Agreement shall be governed by the federal +intellectual property law of the United States, including without +limitation the federal copyright law, and, to the extent such +U.S. federal law does not apply, by the law of the Commonwealth of +Virginia, excluding Virginia's conflict of law provisions. +Notwithstanding the foregoing, with regard to derivative works based +on Python 1.6.1 that incorporate non-separable material that was +previously distributed under the GNU General Public License (GPL), the +law of the Commonwealth of Virginia shall govern this License +Agreement only as to issues arising under or with respect to +Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this +License Agreement shall be deemed to create any relationship of +agency, partnership, or joint venture between CNRI and Licensee. This +License Agreement does not grant permission to use CNRI trademarks or +trade name in a trademark sense to endorse or promote products or +services of Licensee, or any third party. + +8. By clicking on the "ACCEPT" button where indicated, or by copying, +installing or otherwise using Python 1.6.1, Licensee agrees to be +bound by the terms and conditions of this License Agreement. + + ACCEPT + + +CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 +-------------------------------------------------- + +Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, +The Netherlands. All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/venv/Lib/site-packages/mypy-0.782.dist-info/METADATA b/venv/Lib/site-packages/mypy-0.782.dist-info/METADATA new file mode 100644 index 0000000..d975eae --- /dev/null +++ b/venv/Lib/site-packages/mypy-0.782.dist-info/METADATA @@ -0,0 +1,37 @@ +Metadata-Version: 2.1 +Name: mypy +Version: 0.782 +Summary: Optional static typing for Python +Home-page: http://www.mypy-lang.org/ +Author: Jukka Lehtosalo +Author-email: jukka.lehtosalo@iki.fi +License: MIT License +Platform: UNKNOWN +Classifier: Development Status :: 4 - Beta +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Topic :: Software Development +Requires-Python: >=3.5 +Requires-Dist: typed-ast (<1.5.0,>=1.4.0) +Requires-Dist: typing-extensions (>=3.7.4) +Requires-Dist: mypy-extensions (<0.5.0,>=0.4.3) +Provides-Extra: dmypy +Requires-Dist: psutil (>=4.0) ; extra == 'dmypy' + +Mypy -- Optional Static Typing for Python +========================================= + +Add type annotations to your Python programs, and use mypy to type +check them. Mypy is essentially a Python linter on steroids, and it +can catch many programming errors by analyzing your program, without +actually having to run it. Mypy has a powerful type system with +features such as type inference, gradual typing, generics and union +types. + + diff --git a/venv/Lib/site-packages/mypy-0.782.dist-info/RECORD b/venv/Lib/site-packages/mypy-0.782.dist-info/RECORD new file mode 100644 index 0000000..09fe56c --- /dev/null +++ b/venv/Lib/site-packages/mypy-0.782.dist-info/RECORD @@ -0,0 +1,1771 @@ +../../Scripts/dmypy.exe,sha256=MPsW3h3P_9gwCIQpLa6pOVjy_XBgGPWuFZMs7i0Vu90,108438 +../../Scripts/mypy.exe,sha256=u-YYi7wg3boOVSCF31uzKD6_7cB46h6LVNAxQHbc1Js,108434 +../../Scripts/mypyc,sha256=YpW1HG3mh3dEfHGLxeDOn9na0q9_9udk7K-8ghwmHPc,1482 +../../Scripts/stubgen.exe,sha256=aEGMwZytW2JdzPtnisAFvdv2YtfIDfxjeHUu6NOV_Gk,108415 +../../Scripts/stubtest.exe,sha256=Vv-Q7GgBl5AaOFhh65z8nlvKCJK_dXMAwybnQ_bx7Js,108416 +mypy-0.782.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +mypy-0.782.dist-info/LICENSE,sha256=M9JMU5TY-rc1UlB9CAXBVAPOKlCzPSmf-8wKq8CVb7Q,11305 +mypy-0.782.dist-info/METADATA,sha256=I0194_rmLfvzneBNoFPBB-JO-oEvyuBF0LkFZySFyDc,1351 +mypy-0.782.dist-info/RECORD,, +mypy-0.782.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy-0.782.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92 +mypy-0.782.dist-info/entry_points.txt,sha256=tfxMlv7nvHvdqkvxKGD6ZfICxDBIAzrZkeJq3yj-UkI,152 +mypy-0.782.dist-info/top_level.txt,sha256=gdz5XLe8-vYL_KT_2ka2B7fsxk4bZs6swFIZsuuXEGk,11 +mypy/__init__.py,sha256=4yp43qNAZZ0ViBpVn56Bc7MA4H2UMXe0WTVPdkODP6k,37 +mypy/__main__.py,sha256=BmZeSBBWTTVKOBOJfJtW8wAu8Z0_8HaldViRZ9jB3Vs,220 +mypy/__pycache__/__init__.cpython-39.pyc,, +mypy/__pycache__/__main__.cpython-39.pyc,, +mypy/__pycache__/api.cpython-39.pyc,, +mypy/__pycache__/applytype.cpython-39.pyc,, +mypy/__pycache__/argmap.cpython-39.pyc,, +mypy/__pycache__/binder.cpython-39.pyc,, +mypy/__pycache__/bogus_type.cpython-39.pyc,, +mypy/__pycache__/build.cpython-39.pyc,, +mypy/__pycache__/checker.cpython-39.pyc,, +mypy/__pycache__/checkexpr.cpython-39.pyc,, +mypy/__pycache__/checkmember.cpython-39.pyc,, +mypy/__pycache__/checkstrformat.cpython-39.pyc,, +mypy/__pycache__/config_parser.cpython-39.pyc,, +mypy/__pycache__/constraints.cpython-39.pyc,, +mypy/__pycache__/defaults.cpython-39.pyc,, +mypy/__pycache__/dmypy_os.cpython-39.pyc,, +mypy/__pycache__/dmypy_server.cpython-39.pyc,, +mypy/__pycache__/dmypy_util.cpython-39.pyc,, +mypy/__pycache__/erasetype.cpython-39.pyc,, +mypy/__pycache__/errorcodes.cpython-39.pyc,, +mypy/__pycache__/errors.cpython-39.pyc,, +mypy/__pycache__/expandtype.cpython-39.pyc,, +mypy/__pycache__/exprtotype.cpython-39.pyc,, +mypy/__pycache__/fastparse.cpython-39.pyc,, +mypy/__pycache__/fastparse2.cpython-39.pyc,, +mypy/__pycache__/find_sources.cpython-39.pyc,, +mypy/__pycache__/fixup.cpython-39.pyc,, +mypy/__pycache__/freetree.cpython-39.pyc,, +mypy/__pycache__/fscache.cpython-39.pyc,, +mypy/__pycache__/fswatcher.cpython-39.pyc,, +mypy/__pycache__/gclogger.cpython-39.pyc,, +mypy/__pycache__/git.cpython-39.pyc,, +mypy/__pycache__/indirection.cpython-39.pyc,, +mypy/__pycache__/infer.cpython-39.pyc,, +mypy/__pycache__/ipc.cpython-39.pyc,, +mypy/__pycache__/join.cpython-39.pyc,, +mypy/__pycache__/literals.cpython-39.pyc,, +mypy/__pycache__/lookup.cpython-39.pyc,, +mypy/__pycache__/main.cpython-39.pyc,, +mypy/__pycache__/maptype.cpython-39.pyc,, +mypy/__pycache__/meet.cpython-39.pyc,, +mypy/__pycache__/memprofile.cpython-39.pyc,, +mypy/__pycache__/message_registry.cpython-39.pyc,, +mypy/__pycache__/messages.cpython-39.pyc,, +mypy/__pycache__/metastore.cpython-39.pyc,, +mypy/__pycache__/mixedtraverser.cpython-39.pyc,, +mypy/__pycache__/modulefinder.cpython-39.pyc,, +mypy/__pycache__/moduleinfo.cpython-39.pyc,, +mypy/__pycache__/moduleinspect.cpython-39.pyc,, +mypy/__pycache__/mro.cpython-39.pyc,, +mypy/__pycache__/nodes.cpython-39.pyc,, +mypy/__pycache__/options.cpython-39.pyc,, +mypy/__pycache__/parse.cpython-39.pyc,, +mypy/__pycache__/plugin.cpython-39.pyc,, +mypy/__pycache__/reachability.cpython-39.pyc,, +mypy/__pycache__/renaming.cpython-39.pyc,, +mypy/__pycache__/report.cpython-39.pyc,, +mypy/__pycache__/sametypes.cpython-39.pyc,, +mypy/__pycache__/scope.cpython-39.pyc,, +mypy/__pycache__/semanal.cpython-39.pyc,, +mypy/__pycache__/semanal_classprop.cpython-39.pyc,, +mypy/__pycache__/semanal_enum.cpython-39.pyc,, +mypy/__pycache__/semanal_infer.cpython-39.pyc,, +mypy/__pycache__/semanal_main.cpython-39.pyc,, +mypy/__pycache__/semanal_namedtuple.cpython-39.pyc,, +mypy/__pycache__/semanal_newtype.cpython-39.pyc,, +mypy/__pycache__/semanal_pass1.cpython-39.pyc,, +mypy/__pycache__/semanal_shared.cpython-39.pyc,, +mypy/__pycache__/semanal_typeargs.cpython-39.pyc,, +mypy/__pycache__/semanal_typeddict.cpython-39.pyc,, +mypy/__pycache__/sharedparse.cpython-39.pyc,, +mypy/__pycache__/sitepkgs.cpython-39.pyc,, +mypy/__pycache__/solve.cpython-39.pyc,, +mypy/__pycache__/split_namespace.cpython-39.pyc,, +mypy/__pycache__/state.cpython-39.pyc,, +mypy/__pycache__/stats.cpython-39.pyc,, +mypy/__pycache__/strconv.cpython-39.pyc,, +mypy/__pycache__/stubdoc.cpython-39.pyc,, +mypy/__pycache__/stubgen.cpython-39.pyc,, +mypy/__pycache__/stubgenc.cpython-39.pyc,, +mypy/__pycache__/stubtest.cpython-39.pyc,, +mypy/__pycache__/stubutil.cpython-39.pyc,, +mypy/__pycache__/subtypes.cpython-39.pyc,, +mypy/__pycache__/suggestions.cpython-39.pyc,, +mypy/__pycache__/traverser.cpython-39.pyc,, +mypy/__pycache__/treetransform.cpython-39.pyc,, +mypy/__pycache__/tvar_scope.cpython-39.pyc,, +mypy/__pycache__/type_visitor.cpython-39.pyc,, +mypy/__pycache__/typeanal.cpython-39.pyc,, +mypy/__pycache__/typeops.cpython-39.pyc,, +mypy/__pycache__/types.cpython-39.pyc,, +mypy/__pycache__/typestate.cpython-39.pyc,, +mypy/__pycache__/typetraverser.cpython-39.pyc,, +mypy/__pycache__/typevars.cpython-39.pyc,, +mypy/__pycache__/util.cpython-39.pyc,, +mypy/__pycache__/version.cpython-39.pyc,, +mypy/__pycache__/visitor.cpython-39.pyc,, +mypy/api.py,sha256=HrznkoeYEd_K0uZadyDE2IG-Bot0A3w_YSRxs7QXvIs,2871 +mypy/applytype.py,sha256=xf-_-O7Kd_10acRoeXsR1m94O8-MHk7sQ5kS7687ih4,3664 +mypy/argmap.py,sha256=EW3aUf5Syw-7rklb2FCgq7FlQIpUt3hJyjtwO5FQH3A,9388 +mypy/binder.py,sha256=sJ_O5QNEaSgjTMfLLV0DySEaD6KTPljHZfQ15mUSBj4,17363 +mypy/bogus_type.py,sha256=bTk0-CsLSm_tQZzE3EUM3nZs_z7kt077ZBVPwL0Y-TQ,779 +mypy/build.py,sha256=c8wTYpDZfCm4A_cM6Y0vq4sRaPwwJo2ZIJCK-4zpmzs,138472 +mypy/checker.py,sha256=vUAE95c7drwf8GcSiBICPw2rxwHp24j-G6yBk-SFAv0,280114 +mypy/checkexpr.py,sha256=fA2iztW2qd0zmqNsLRF5UGt7SQ4_iyJseJ6GkKksDas,214633 +mypy/checkmember.py,sha256=Td6mc4BeAqSzdPJDVncTkvCB7EBBfUnlXk6uXHJEREE,44665 +mypy/checkstrformat.py,sha256=Dr5X3w3hRvd863Wwx5fERdvs0Cv3oh6UFxluQJirHjY,47099 +mypy/config_parser.py,sha256=uAUh5tCfoVsLq4KT8kUSvqIX1VOGt7Nz9xkq9eY5gZA,13598 +mypy/constraints.py,sha256=TnA2YM9_SeD2L1xtd4riTiENh2XTyGjzd_m9fNG6bpE,27368 +mypy/defaults.py,sha256=3N15lSLM_MQ6HJ2ahEiqr0KoQJcaDA7cy3IodCF4GJU,1138 +mypy/dmypy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/dmypy/__main__.py,sha256=OPHdXfI4IT9tCNO_ZjoJsAfVck6EiOou_t9RX2AV8mI,92 +mypy/dmypy/__pycache__/__init__.cpython-39.pyc,, +mypy/dmypy/__pycache__/__main__.cpython-39.pyc,, +mypy/dmypy/__pycache__/client.cpython-39.pyc,, +mypy/dmypy/client.py,sha256=1TMyVKoa3Vxmt-Pk6zKHHOjVkypur-mW-k9M2CDQ1R4,21106 +mypy/dmypy_os.py,sha256=8sLBkMG22YyJYWIThFhjX6q8KTSm6stxLeKv5cbpLMs,1208 +mypy/dmypy_server.py,sha256=3pkC018CQuIdeAXsEWglDXWFIIatZWMgPe8GT_1AI_0,37199 +mypy/dmypy_util.py,sha256=sBNJhrj2zysBSK97bNgyhu6QjxznDfEzkAcERDS0BgU,843 +mypy/erasetype.py,sha256=0F1wCHKA5DtgHrYU9u8VmNTT-kNzpSen0eJbClQG1sQ,5576 +mypy/errorcodes.py,sha256=3XF1DrveFQlnEPpztzYXWniVSphWjhnV1uo3Ezf2Tak,5161 +mypy/errors.py,sha256=FnmUxXGRDzdaVN-w0U17WKIJ1wKIetAO5f9BNiLpCEo,29281 +mypy/expandtype.py,sha256=XPQmiU7jpkXuNymHW81gjHyARVnptBD_eTZOnSJFzOs,5545 +mypy/exprtotype.py,sha256=HF7szIuKYlDZrzmlQ3KuEJPfb_syUXA9dEPmge7wTv0,6187 +mypy/fastparse.py,sha256=JZTHf66-rqQAmpqwIjnFRF0OpMLNC6GrtLSOZBPk_QQ,66785 +mypy/fastparse2.py,sha256=o6-g3hTa0_kiVXtyaZB2rwomnxoPqqdQG_iTPN6xbUQ,44265 +mypy/find_sources.py,sha256=B38kYes0k1iM2H7JdzxRtrx57qHGtpr5M_1C7Y7dL2g,6238 +mypy/fixup.py,sha256=nJrYUPAQ4Tg6KTNIV053ue4ypdbECuiO4JKKn5IoxHY,12588 +mypy/freetree.py,sha256=djtzkC5Ly0pJU3jaHKoXvIAcUyCIvoqBZ4vFEMXVEdA,581 +mypy/fscache.py,sha256=lNqFEHEX8Ym1doNtZKtrSNOuGUebltr-WAZRrcTErUU,10379 +mypy/fswatcher.py,sha256=GBGX5rSrRu5Mf5MzMQBmopCI6J6BgG0Q0zh76fC4A2A,4137 +mypy/gclogger.py,sha256=VNozn-ZRd4EIJLRhOsw_PUBlm81ObdYCoZ9MSpbMTV0,1632 +mypy/git.py,sha256=GiTxdCzFR4cHWxkYyokZXaqLkuiFQPeCj7oTi-0WNcA,5008 +mypy/indirection.py,sha256=xUaJEvwnz7zCanjwBfxFRxSvUbPwpoqCnpgMn8LLu94,4111 +mypy/infer.py,sha256=ItgpSK5FD58HPjLm-5-gd_2QU-5BnLpMNleW3MildfM,1951 +mypy/ipc.py,sha256=NW5LfRL3YoUkBeT4xba1N1xTX9SRKDKfxpR3c96PF-s,10573 +mypy/join.py,sha256=r9Z02VLusLN_nzG0G1uedE73QeQrBHlduqK79y0tBXs,22128 +mypy/literals.py,sha256=5xR26WRLwY8vJRaYSQZ6oF6iDBq6zjdNzQe1_uYV7-k,7812 +mypy/lookup.py,sha256=SukfJFiEiA135vaItnmnGgf6UeQqXD98zVJ-EcFJfos,2090 +mypy/main.py,sha256=0nZ0j0HVTgEP875RKtoMxCAiNo0M3fCv0tbHiTFNgr0,45246 +mypy/maptype.py,sha256=WNVuh-Q1Ch1bcLOG1sEetGFoLvNekPGaTmlEh5Rgmn4,4059 +mypy/meet.py,sha256=d7T7TNbK8M70PQiiWKi5XsQWnXCEaBp0b-bzuI-mFoY,34097 +mypy/memprofile.py,sha256=krxvQKAJL41Vq-XeSEdHa8xKZR5OrxLsGGcIMnIBNDw,3906 +mypy/message_registry.py,sha256=MUKAtJmid4RTu_hR1KXvqsd05O0wq16eqxOhEdEgCtk,8374 +mypy/messages.py,sha256=jbVEoRlA2HIh-D7cSwrn_37rbu4NcDa2E7rubcEzqRM,97490 +mypy/metastore.py,sha256=SbvChhQyDky-NZ8tJz4HSPDwtrY2QVEvHMDnnuWdb7Q,6665 +mypy/mixedtraverser.py,sha256=gVUgwRxQ8EX91kkvSwxPZYN7PF_khVm_WoXh8BUh4d8,2841 +mypy/modulefinder.py,sha256=KkR7ac0vSurKjJBKE0NclijP_vj7U62Db5z1qyqFI3I,26610 +mypy/moduleinfo.py,sha256=3GH6wGFnZORBF_VQJKjYEyv8eMRcNtAbaUDJUwbGNBs,6596 +mypy/moduleinspect.py,sha256=t-hJP1tSnzyO96JJKxdgCiyu-SWl44EpoIEpQBtn0m0,6209 +mypy/mro.py,sha256=9nLo776zR9bRvBGMw41SVoH8QncV2EdyuJRDA34Vi_M,2098 +mypy/nodes.py,sha256=d-J_cY4ergAwGhxP9Rh6nqgoruTDf_q56qz4nlFIYhs,113792 +mypy/options.py,sha256=EdnfxHzoNmnWzEiiFbEN31g6LWseHzXZqwI2b0LqePM,16161 +mypy/parse.py,sha256=azOUCE0K3wtErfz33eyKgIxOUN67BEL21Z0fgex-0gc,1363 +mypy/plugin.py,sha256=gMzvmYkdS8a9JstdpKFdTNc2tpCaE-8MG-mbdfR4TcE,32452 +mypy/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/plugins/__pycache__/__init__.cpython-39.pyc,, +mypy/plugins/__pycache__/attrs.cpython-39.pyc,, +mypy/plugins/__pycache__/common.cpython-39.pyc,, +mypy/plugins/__pycache__/ctypes.cpython-39.pyc,, +mypy/plugins/__pycache__/dataclasses.cpython-39.pyc,, +mypy/plugins/__pycache__/default.cpython-39.pyc,, +mypy/plugins/__pycache__/enums.cpython-39.pyc,, +mypy/plugins/attrs.py,sha256=1Aj0QIZZC1y1X_-DMFppNxGJI8IzvdhFgDtWYp9B3mg,28556 +mypy/plugins/common.py,sha256=aE7-zbp1l32HTs0nXg4qV-rnTjmvLwAd_TTz_f_qMp0,5605 +mypy/plugins/ctypes.py,sha256=1K7iqDE6CSoEgcaUHOLTdQwAxIwqEiQwTkVFttY1gkk,10639 +mypy/plugins/dataclasses.py,sha256=gWDTJjvyMhkOGhR3y6PmgboRDpoq1DCL2KXQIOGeAs8,14825 +mypy/plugins/default.py,sha256=M986CqTeA8UVc-BlHcEoQgWddysoXGDzCjGAHqJBWq8,19067 +mypy/plugins/enums.py,sha256=5SaUHLnm0q9IDkvV4GYVgXQy78qyqFUDBg2hV0ULDi4,5365 +mypy/py.typed,sha256=zlBhTdAQBRfJxeJXD-QnlXiZYsiAJYYkr3mbEsmwSac,64 +mypy/reachability.py,sha256=JGo4VmJvG5SXM5udNBO3NMpVEfya3WYZPgCpyeK5-ZM,11148 +mypy/renaming.py,sha256=3TZ8sT8QT-eK9TZfWHRrkUYTv3jOi90-a-vxLpVTkhE,13684 +mypy/report.py,sha256=vGDEmrtLVS_s7_r7nwbFms0UpegwEtvT0kXUQb-wnEA,35649 +mypy/sametypes.py,sha256=bIk4DqeR008MxKOQJvHC2Azf9D2TZV-T3fEqkozCx0E,6608 +mypy/scope.py,sha256=u3_52cB24-FZzyHhTKry68q6puULTEzjlFWt8Ua33A0,4068 +mypy/semanal.py,sha256=P6YYHnUljydgvn8l7s7Br9wZcle9A7iKPx_-DWfb4R8,226840 +mypy/semanal_classprop.py,sha256=rEq4urjmvBK4rCKl5uNyobtJEINWq_LCk4EiDOs-W7E,7273 +mypy/semanal_enum.py,sha256=EQ89ClcqS2byODTph8jj1VYChkcnx7WF-GcUrTUfYg8,7335 +mypy/semanal_infer.py,sha256=fZZ7C9wGlS-_xJiGf_qVBkJKD3bG_Cgoidb1ikXfCHs,5188 +mypy/semanal_main.py,sha256=pCtl0u4oUB6nk4fQU4y8u5qn8dKU35tvok-2CiJt_Mw,17811 +mypy/semanal_namedtuple.py,sha256=dM4Vi7HTlgzMAySo1tzwK6sglFbng_uR3QZbQ7H4eAU,26059 +mypy/semanal_newtype.py,sha256=o3DUcrqXSq5mNTW8njHcPtbzbDVodPoMvV7lMRP3O9Y,9437 +mypy/semanal_pass1.py,sha256=gq9cgTlk-R07CLaMCiG671uc6vjLeSlhYhx1NFTymQU,4434 +mypy/semanal_shared.py,sha256=WrP79WI1I0uP6WmY1BoXJjFuzxWy7LKlTVs55c1lxNM,7628 +mypy/semanal_typeargs.py,sha256=Nw7r9VJ-WcAR8yxemSL2rejg4-WojLaUfjfK9jrrQMI,4915 +mypy/semanal_typeddict.py,sha256=mbU9ls0Jci3oKkzT3zj7_XxRPOnlhEYsMZKyqE8l5z4,15515 +mypy/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/server/__pycache__/__init__.cpython-39.pyc,, +mypy/server/__pycache__/astdiff.cpython-39.pyc,, +mypy/server/__pycache__/astmerge.cpython-39.pyc,, +mypy/server/__pycache__/aststrip.cpython-39.pyc,, +mypy/server/__pycache__/deps.cpython-39.pyc,, +mypy/server/__pycache__/mergecheck.cpython-39.pyc,, +mypy/server/__pycache__/objgraph.cpython-39.pyc,, +mypy/server/__pycache__/subexpr.cpython-39.pyc,, +mypy/server/__pycache__/target.cpython-39.pyc,, +mypy/server/__pycache__/trigger.cpython-39.pyc,, +mypy/server/__pycache__/update.cpython-39.pyc,, +mypy/server/astdiff.py,sha256=os0c9290vEgfDVJhp5GUPNabxyP-4XLBCky4KP-8oh8,16024 +mypy/server/astmerge.py,sha256=NjiWGfWHBfJBdpKjif84i35WGMsw6LFEwGVqC3mxOpw,18620 +mypy/server/aststrip.py,sha256=fCQFIIJjNAsU6CqwEqiELgB8zojhV6Ay1fSV4G-fCHg,10940 +mypy/server/deps.py,sha256=LUVxY8Of9hKWOvipfNEcED7xdLCZyk9yR8QPlaP_tsQ,48476 +mypy/server/mergecheck.py,sha256=4B0x0Aqs0pgkByiVGsD4W6IWJRZgfI0m2sMg79Vzm40,2808 +mypy/server/objgraph.py,sha256=AiIR0FZmPUhbH_CS9j30NM_h4TI3fLCQgJ1exH7ZxSk,3578 +mypy/server/subexpr.py,sha256=9sKKL6UfAQxcgqu2IiuI1NYhnp2YVwj-TsG-pAvi2Kk,5101 +mypy/server/target.py,sha256=UGl5BtedDpJx5McJAGtPlhFxtoZEbbHtxgi6AjY5IA4,236 +mypy/server/trigger.py,sha256=6uZG3M3oKFkld986d5SM2-t2bBKr9XcrAtvV_8UuH8E,784 +mypy/server/update.py,sha256=hpdmGSZOE6uzCEVp4Q5NoeTxH3SDS9JPaDE6oMP9Bcs,51461 +mypy/sharedparse.py,sha256=w_AjYMWjPdkK9AiSQBqmJYewj5qMKTwxtzRd52yzVLE,2082 +mypy/sitepkgs.py,sha256=Am8b40PLTancc2N3fwplfHNEWg_IZF-qS_FmnO37tR4,987 +mypy/solve.py,sha256=od7Cx-ZShxE4qe76QdnTAsQsUgKIa9SLOooOvHQE_yA,2876 +mypy/split_namespace.py,sha256=5kwyOJBHw_5CKnWIO2MoGt617dFWOUMytyOow7yhYbw,1259 +mypy/state.py,sha256=GUWgeqeDPSNvEhH9gTaYtSnSPnXVu_-kBeb5iPSxMTg,497 +mypy/stats.py,sha256=Jxg5JJwlil6YdAIpdpAi_FITcJxfYktTpShWxXDMp-w,17199 +mypy/strconv.py,sha256=7LKvRYAYWkCOH9awJRtBsiNVFZ1FGxWHB38DV1Rdeqo,21297 +mypy/stubdoc.py,sha256=IFbgq5L09VawD4L0209WTKsIuVIrMuRItz14XgBD0ZU,13158 +mypy/stubgen.py,sha256=syI0U1yO_F0ZJcpsBIty_yAxlthdeuSD2kV3nteMySU,64782 +mypy/stubgenc.py,sha256=TqfOZWQSJEhrXa7hokfgF508r0hmfwIvQUxalrN3FPQ,15236 +mypy/stubtest.py,sha256=c0WQR0pWrMDEjAca3Lj1EgVvrvi0bHBuk-61b3utfx4,44833 +mypy/stubutil.py,sha256=LWgLFyYpgBfEPH4TdOQIDi31BwupybxmSP2YgMh7Bgk,9640 +mypy/subtypes.py,sha256=fXrRs72iS98Qz2_9XrZoGqGCC0xZk5606ecjE-vQWHU,63387 +mypy/suggestions.py,sha256=WaRovQ2ohpSE-Ss_8vwhc5IuYqkBtkf0cPYfoh5CKYk,39468 +mypy/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/test/__pycache__/__init__.cpython-39.pyc,, +mypy/test/__pycache__/collect.cpython-39.pyc,, +mypy/test/__pycache__/config.cpython-39.pyc,, +mypy/test/__pycache__/data.cpython-39.pyc,, +mypy/test/__pycache__/helpers.cpython-39.pyc,, +mypy/test/__pycache__/testapi.cpython-39.pyc,, +mypy/test/__pycache__/testargs.cpython-39.pyc,, +mypy/test/__pycache__/testcheck.cpython-39.pyc,, +mypy/test/__pycache__/testcmdline.cpython-39.pyc,, +mypy/test/__pycache__/testdaemon.cpython-39.pyc,, +mypy/test/__pycache__/testdeps.cpython-39.pyc,, +mypy/test/__pycache__/testdiff.cpython-39.pyc,, +mypy/test/__pycache__/testerrorstream.cpython-39.pyc,, +mypy/test/__pycache__/testfinegrained.cpython-39.pyc,, +mypy/test/__pycache__/testfinegrainedcache.cpython-39.pyc,, +mypy/test/__pycache__/testformatter.cpython-39.pyc,, +mypy/test/__pycache__/testgraph.cpython-39.pyc,, +mypy/test/__pycache__/testinfer.cpython-39.pyc,, +mypy/test/__pycache__/testipc.cpython-39.pyc,, +mypy/test/__pycache__/testmerge.cpython-39.pyc,, +mypy/test/__pycache__/testmodulefinder.cpython-39.pyc,, +mypy/test/__pycache__/testmoduleinfo.cpython-39.pyc,, +mypy/test/__pycache__/testmypyc.cpython-39.pyc,, +mypy/test/__pycache__/testparse.cpython-39.pyc,, +mypy/test/__pycache__/testpep561.cpython-39.pyc,, +mypy/test/__pycache__/testpythoneval.cpython-39.pyc,, +mypy/test/__pycache__/testreports.cpython-39.pyc,, +mypy/test/__pycache__/testsamples.cpython-39.pyc,, +mypy/test/__pycache__/testsemanal.cpython-39.pyc,, +mypy/test/__pycache__/testsolve.cpython-39.pyc,, +mypy/test/__pycache__/teststubgen.cpython-39.pyc,, +mypy/test/__pycache__/teststubtest.cpython-39.pyc,, +mypy/test/__pycache__/testsubtypes.cpython-39.pyc,, +mypy/test/__pycache__/testtransform.cpython-39.pyc,, +mypy/test/__pycache__/testtypegen.cpython-39.pyc,, +mypy/test/__pycache__/testtypes.cpython-39.pyc,, +mypy/test/__pycache__/typefixture.cpython-39.pyc,, +mypy/test/__pycache__/update.cpython-39.pyc,, +mypy/test/__pycache__/visitors.cpython-39.pyc,, +mypy/test/collect.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/test/config.py,sha256=F1_0f5DyYKmOaqscpVj3AQuLmHHm8YQaum0JpQUVz4g,793 +mypy/test/data.py,sha256=XLu8bI0T5hCgDUqrXHfppm789XdmrUNWrS2UwEE2Ef8,23488 +mypy/test/helpers.py,sha256=rDS7scg70hitp9x6Rp8xjzC43xNQ7uDH-AoEpw1QWnw,16660 +mypy/test/testapi.py,sha256=---IZm0oD6chHt2Swmjx_56jARDQNI6vVMlMuusZrpU,1413 +mypy/test/testargs.py,sha256=Pj91L1GlG-c_n7bTp1w8Uj5awULxNfpQ_A9euNc1cOA,3251 +mypy/test/testcheck.py,sha256=w9jDjxlK5X5DbIfjwi4kZycpS27NV2hJf3PIZUpUP4c,14439 +mypy/test/testcmdline.py,sha256=al8zE5lDyQ41gM4bXAZlvlSRr2eWgytW4wHsllF_h_g,3940 +mypy/test/testdaemon.py,sha256=zFD5Fy2OO8ZKnFRlZrIzPuWYjWK33Kfp0unteosUJGg,2862 +mypy/test/testdeps.py,sha256=LSG0glToWcRyNG18Yi1DlXCLVdoj0xHEUZNMQ_wL-6o,3951 +mypy/test/testdiff.py,sha256=sp-DxNjvt37sCnU5DjCdjUrvYJmGgL5L-LR2kWLNyko,2544 +mypy/test/testerrorstream.py,sha256=K45CGDUAWyN8licSac2q1W6xVAssdzh_goUjGyyeueo,1482 +mypy/test/testfinegrained.py,sha256=sVOYLZNSFtSedblUZJOe-J_qDetIUy-Yg5ccxXwB2r8,13665 +mypy/test/testfinegrainedcache.py,sha256=uuHzqvpZQ6L_u1q-toqAkLDwMFrkDaFp_msflvKqH5Q,541 +mypy/test/testformatter.py,sha256=HUfVEJ8QiCyN7Hcbdg8jxASBh-3DZ2HZIShcA2CHmZk,2627 +mypy/test/testgraph.py,sha256=flVrlci6WiraGUEElyd3CjT5ZWuOfcQd7fB1v_kwfiI,3165 +mypy/test/testinfer.py,sha256=HjlGYYH0FSGroGKnqWbMJBmUo7uhm5-yLoTMuv3IWeE,15641 +mypy/test/testipc.py,sha256=GiBTpBHnWCqvFrPxfJAo7QNHdsxsfrma9zdJp-bQN90,2273 +mypy/test/testmerge.py,sha256=FfJcpAAlCZUZA7UkHc0ekrU-qSQXZobM1M6QupjHoX0,9226 +mypy/test/testmodulefinder.py,sha256=muwaEFGgmPG2ODYkKh9EIVw_NaC2dUg9cBBE5JnI2CE,11270 +mypy/test/testmoduleinfo.py,sha256=neQ1eIZl9oYtmEuy_neUnDegOuL9yKcUu_KqrGYzT30,636 +mypy/test/testmypyc.py,sha256=X7Pd42QeaJ3HK1mbUaw-C6B6Z12N9XpbsImtdhvqmls,361 +mypy/test/testparse.py,sha256=43_snuVpu_CR2QR5iodpCy96Jga9xd8z1bqNG0Dn08w,2751 +mypy/test/testpep561.py,sha256=VBI2Ze4dsVEKYr3BjV8vdF0Y33mwwkIkC8zsi7jo2jI,8008 +mypy/test/testpythoneval.py,sha256=quoK2z9qfY3C3PqNTMAeMuyaB18YAtk0jy7eh0UUMwA,4219 +mypy/test/testreports.py,sha256=lFGEioqQ228uDOulEULNsr5X5StvLdOcXbTpi_Nf-Q4,1414 +mypy/test/testsamples.py,sha256=It2dxoq4Gr4Y8TXu_QEHpKW7GhTZCwjID2epppWiRl0,2817 +mypy/test/testsemanal.py,sha256=M6M73VxpzF45rlQSEUxZb3mlu_oHMvW8EFfQrB5TRhw,7699 +mypy/test/testsolve.py,sha256=VBYVTZh186lnJgp7wYhMdJhR61g66h6lk1qd9013rHc,5911 +mypy/test/teststubgen.py,sha256=_0r2HgpJx0TF-jhSHTksVmZWd-nacFYwq1TISVg8yNU,34342 +mypy/test/teststubtest.py,sha256=uDyebX2GvfyilLnEAjvEFf5i3bG3HMYwShrm8UY6yqE,23816 +mypy/test/testsubtypes.py,sha256=6OQsoYt8mCVYTNzW4bMAliRW_4jcNohc9mb7bZnCzHM,8842 +mypy/test/testtransform.py,sha256=cuxLtg92SwNY8oeahP003Vt5np5mldK3289Vqq7HoZo,2680 +mypy/test/testtypegen.py,sha256=B8OgZpELsIKlqJ8C6ryXiPX6mfNbl-f4yQ8mSAscXRQ,2945 +mypy/test/testtypes.py,sha256=48h9QKsPc0AxT3zhjvWESGj87mBLng8X1cuFzlpYRX0,44639 +mypy/test/typefixture.py,sha256=ZWj-V3Xb_IPTqmuayiXY8rgATk8L7RNY_WOu2-mb68c,12207 +mypy/test/update.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/test/visitors.py,sha256=gbwtH5Nf9z5UN7WNoeu_9SD8ksM41SSOIJloIYHv72M,2291 +mypy/traverser.py,sha256=HjQGIJHXihRT2mHgFMnMbewvnA0UiCanVYLY8ZyAXzs,10477 +mypy/treetransform.py,sha256=3FPMU9y2UY6FSYi-jsp1ytNMEq288l3cN6cDSYgx2SY,25568 +mypy/tvar_scope.py,sha256=plvYh7Andc1YBQrohlsBcYNAqh4oja7G8eAWl4LdyLs,3551 +mypy/type_visitor.py,sha256=b_lova8Y3rOfwF40EW-7VtblohkEMQ_wfnf9ouXI20c,11160 +mypy/typeanal.py,sha256=CoU8bIOtJtBOSOgFS8mO6Bsez8RZg2E1Rlgi1P7nrGw,56094 +mypy/typeops.py,sha256=IVWlOG6CLcmgXkpw7yBt8h-Br106S3Gs-D27aGdR4j4,28845 +mypy/types.py,sha256=an5qevW-Y3E0kpSIbLm2h4484zDNh9bv-Sgkhc9UOas,89422 +mypy/typeshed/stdlib/2/BaseHTTPServer.pyi,sha256=Vn3aoORkJvQiWROghZboBponUuU0XcmMJUo2B7nnB7k,1864 +mypy/typeshed/stdlib/2/CGIHTTPServer.pyi,sha256=rdxnw2EN6dD6Pg5XTZf35L0pm-REuAx-p4Qlh2Pr3FI,227 +mypy/typeshed/stdlib/2/ConfigParser.pyi,sha256=ho-0DQ8rivi9g0lA2JVkMQz00N0ACtkPvYcBy0Fu6kA,3882 +mypy/typeshed/stdlib/2/Cookie.pyi,sha256=Ke_iU9vRRHFMkJrben9gxXLss3nTR0bw5ZPvN_abYdc,1342 +mypy/typeshed/stdlib/2/HTMLParser.pyi,sha256=V35P__PdBxNcAMqIkcGU5xes5G6TrIRaKwZyTU49_Ok,1067 +mypy/typeshed/stdlib/2/Queue.pyi,sha256=rM6dyHkpzO556CaTq3C2zWROSzHzAPE73o6c89a0q8g,925 +mypy/typeshed/stdlib/2/SimpleHTTPServer.pyi,sha256=f-YKJ8pTFBvLCfzHkdC64Pl68X3z-EzJCzjrFN7GXHw,689 +mypy/typeshed/stdlib/2/SocketServer.pyi,sha256=_QGoTdWUx_MBUg8wbbMy92_CxwP9-yvNlfkmMhfg6Bk,5557 +mypy/typeshed/stdlib/2/StringIO.pyi,sha256=DnD9yzaDJBRmDSO3Izj5iLRz0XhR0ME15_rKmGCzkEE,1179 +mypy/typeshed/stdlib/2/UserDict.pyi,sha256=SyyOjAg89p2GxW2l2Rh5K_LywO0wJOyDIrVDF3yWMx4,1632 +mypy/typeshed/stdlib/2/UserList.pyi,sha256=4QnPyFgdwmENrlNqRPFl_c9h9hGQddDmlyopbCgIYt4,630 +mypy/typeshed/stdlib/2/UserString.pyi,sha256=66KWkG76pLfFet3ZEgeSpKl44Ln9X1tcUeun1eaIJEs,3844 +mypy/typeshed/stdlib/2/__builtin__.pyi,sha256=ES5n7BlrlVsfGTO30LI7aHfcOeEPN9BtbEkUky3fY28,73033 +mypy/typeshed/stdlib/2/_ast.pyi,sha256=bbV7HmKQisI6P_yw61dS8eo5HTSaldhvNTHqNFAONYo,5777 +mypy/typeshed/stdlib/2/_collections.pyi,sha256=-8nglgcAOKkmzv4QZFAYjOczFffnanncc-Jyq9F5XUQ,1478 +mypy/typeshed/stdlib/2/_functools.pyi,sha256=X-Fg8iRti-ZpiUHzjlkBP6aqvy5AsKKUeZebm0fjz4s,645 +mypy/typeshed/stdlib/2/_hotshot.pyi,sha256=FCVHwEb2pK8iC_INUa4h4TM5BuRABrdejrhfx8EvvJM,871 +mypy/typeshed/stdlib/2/_io.pyi,sha256=FoP84phO0WcclH3ScbUqPGhWZR4Xv394BPto6DnVaSQ,7131 +mypy/typeshed/stdlib/2/_json.pyi,sha256=VkdGJetGOhdC1_e-3wjZdqwJtEmmH1oxWkbgvIukvRg,233 +mypy/typeshed/stdlib/2/_md5.pyi,sha256=pGqwb01a_RcSP1QRE8XtVPB0RKaoJOGuRdVk6pwvEag,300 +mypy/typeshed/stdlib/2/_sha.pyi,sha256=32F3_E2nGplztFti0fx5GwfPqobLiyg2rtTLHopfCw4,348 +mypy/typeshed/stdlib/2/_sha256.pyi,sha256=1Z5g4wLOL9-z6gasal2kMoBb7yBHPJMFSCgPts_GTRM,632 +mypy/typeshed/stdlib/2/_sha512.pyi,sha256=6AyOELlW_oDueP9i8yvirht0BdJO0itNx9-deuMYCeA,632 +mypy/typeshed/stdlib/2/_socket.pyi,sha256=6pmY5w0QnTNtTlqoljtwgqRovMX4yAwbO3-7J8tYY8Y,6309 +mypy/typeshed/stdlib/2/_sre.pyi,sha256=mfDfmucypU0R3GTJjHRrvq-N7wUv_0cIIzV3Je2qZG8,1976 +mypy/typeshed/stdlib/2/_struct.pyi,sha256=zB7QQMd3oHSGsrECKXYQM2H1IMlKLh32nktw7uTauLA,811 +mypy/typeshed/stdlib/2/_symtable.pyi,sha256=65zeM2TLj4T1XJ4bUsp4E6y0TQgCIP-plvkrZDtdQio,682 +mypy/typeshed/stdlib/2/_threading_local.pyi,sha256=HHs9DxAPqz-I_dN5h4Bv-Pq0SpYEUxFx-l1iK1jaA3Q,392 +mypy/typeshed/stdlib/2/abc.pyi,sha256=CcNQNUTi82hJu4vM2MwvHX9wbSm_HqozPs54vuvsdXg,1147 +mypy/typeshed/stdlib/2/ast.pyi,sha256=ZeErz44vozLzAXscRgNXeqCOwF8pHv0x6TjeQwOIXzk,1201 +mypy/typeshed/stdlib/2/atexit.pyi,sha256=RXUSKHd__cLe1yzGZ8er9pfHhGDHviF0S1LPNxCLp_Q,117 +mypy/typeshed/stdlib/2/cPickle.pyi,sha256=FVgtWCgzeEdiJJiIWfdEkRI5RKQvILZVdDUpSO8U_P8,801 +mypy/typeshed/stdlib/2/cStringIO.pyi,sha256=Cimh2tfh9f6Q0Tyf5dF6HHSHQf7x4KS6eHl03IolDus,2033 +mypy/typeshed/stdlib/2/collections.pyi,sha256=HUNGPxqJwjTrCe74Sv40zaNIm_SJOqrqa7JGgsxQZ0w,4986 +mypy/typeshed/stdlib/2/commands.pyi,sha256=512BGpfeWNdi0wFAXnH_NLFtmqsRbU3ORvZNyWPjrWg,331 +mypy/typeshed/stdlib/2/compileall.pyi,sha256=wT92EfMkifRVCeE6yMHcqxlOyAf-B9SRYtUjLKVVKOM,660 +mypy/typeshed/stdlib/2/cookielib.pyi,sha256=Q_CQUyeESJMliob9LHzxSHvzlQB5JFpCKaRfVfAaeLw,4521 +mypy/typeshed/stdlib/2/copy_reg.pyi,sha256=BsqFQ_hSsV_oqeJFO_GZ2J1tFl4EpnGZgx-NYmt_ZN0,726 +mypy/typeshed/stdlib/2/dircache.pyi,sha256=MvOj_3F6aQ5wvlvpb5pUJCSMDIknGd5dKJ0qSm4F1Y4,339 +mypy/typeshed/stdlib/2/distutils/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2/distutils/emxccompiler.pyi,sha256=oQAQE8Wj2vo56zJyq3SAO48bGYmQ9nagLIpx5jn90lo,116 +mypy/typeshed/stdlib/2/dummy_thread.pyi,sha256=755Cy6AXyEo3RowYk0pQm5I5mkAIE3yQrkWImnrlHOA,794 +mypy/typeshed/stdlib/2/email/MIMEText.pyi,sha256=4Hjv1f-LZwoj-ihndmbQNHdwpjOy6wUOJoKS_axJmNo,159 +mypy/typeshed/stdlib/2/email/__init__.pyi,sha256=iUDv6ttU1qT359eOAubG1JtxNmrJGu8QxH_aXPvOz9w,270 +mypy/typeshed/stdlib/2/email/_parseaddr.pyi,sha256=oqGaUf13WZALSq7cyULZ0c_6iFKjH8rdnAfAkm6y3Hw,1072 +mypy/typeshed/stdlib/2/email/base64mime.pyi,sha256=hcknR5OsGAU51g8EWtU48rFXHh7z8FaahWJA-7YdIWg,300 +mypy/typeshed/stdlib/2/email/charset.pyi,sha256=VVEUOTe1XZ824-FhBuIBrSCB16hMAnQ1Ygseu3Noc_Q,902 +mypy/typeshed/stdlib/2/email/encoders.pyi,sha256=s8kQE5AG1wvh0h0qbNn3_As6ExYQccVdg6Bx2PKGu8E,143 +mypy/typeshed/stdlib/2/email/feedparser.pyi,sha256=qgmZtVf0k_SLOC5o-l3_tHjV8dfgRYF9rgh0YslJzYM,537 +mypy/typeshed/stdlib/2/email/generator.pyi,sha256=nDbQYgf4oqSinAl-xZl3HxMhGYMjESOV7fZbkjash4g,378 +mypy/typeshed/stdlib/2/email/header.pyi,sha256=mFq0GIZXdDQRBWI9YwfsywG6tAaC8-fF9QtBbZnd_gE,474 +mypy/typeshed/stdlib/2/email/iterators.pyi,sha256=vPq5eJF8HBwFQ1hS--niEmurSl4x42YOrU65TxKk0Jc,256 +mypy/typeshed/stdlib/2/email/message.pyi,sha256=M3XzQbdji1k8_hygt88priwEMJqWKRixQsN4qDLmfeU,1950 +mypy/typeshed/stdlib/2/email/mime/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2/email/mime/application.pyi,sha256=3gseSXbGrYJqwLH7CzlZ6uClMHimFT-Sb4UCC53DXLo,427 +mypy/typeshed/stdlib/2/email/mime/audio.pyi,sha256=O0BQRyRkQpox5M_nbFORkWz7J_ff2o7tWYrRzXRd8hI,177 +mypy/typeshed/stdlib/2/email/mime/base.pyi,sha256=lG1Re_xRHsaw4WRUnLh1Jyneb4M6m8kxqa0NUfwuONg,128 +mypy/typeshed/stdlib/2/email/mime/image.pyi,sha256=i0OQt-93SokQjZ5qISYI1tgH7PWyXuw_fNnGvrtTfQk,177 +mypy/typeshed/stdlib/2/email/mime/message.pyi,sha256=5wSkIz4j47zMsBUkdxeYIHK4GYFlew2kHHlRwuCHhmA,148 +mypy/typeshed/stdlib/2/email/mime/multipart.pyi,sha256=1pTSK5lU6L5AJG5H35PTIQtHYIplMoipa7Kkd_m9HNQ,159 +mypy/typeshed/stdlib/2/email/mime/nonmultipart.pyi,sha256=C9WcyywCzQqkL9MPpSlWHgChmP04r0rrWVw3VlSVHQo,107 +mypy/typeshed/stdlib/2/email/mime/text.pyi,sha256=4Hjv1f-LZwoj-ihndmbQNHdwpjOy6wUOJoKS_axJmNo,159 +mypy/typeshed/stdlib/2/email/parser.pyi,sha256=9QChl7gsm0KPwZHUYy5tR_kZkmQpdSnxCwuZTnp9ceo,415 +mypy/typeshed/stdlib/2/email/quoprimime.pyi,sha256=ZRJzHi-3Fszfa8nRpz6EpGYZdSpLyGc4K3pxr1uyMUA,490 +mypy/typeshed/stdlib/2/email/utils.pyi,sha256=COa7JwpxlpBZAxOU6ThwyYU7o_7Bh5L-39Qxgd9IEdw,823 +mypy/typeshed/stdlib/2/encodings/__init__.pyi,sha256=_RWeuK-suSwb18aIsN6VdIl2hixs-jYJPRdinPdejFk,185 +mypy/typeshed/stdlib/2/encodings/utf_8.pyi,sha256=tgCdNX8etJQWYWmOYAIZhK8lcYm_Kn67kylKJp0SgUo,573 +mypy/typeshed/stdlib/2/exceptions.pyi,sha256=caxfpKrLTonvEEp2cq2fA7CyGbeEE3RdY1G-TzTU7Lc,2640 +mypy/typeshed/stdlib/2/fcntl.pyi,sha256=TYUQrn7NB974TMJYDtPvjSmTpkjBJLqwaDnt0tmCi_k,1612 +mypy/typeshed/stdlib/2/fnmatch.pyi,sha256=8kgI-ZZR0lhAGSuQk0M0kt3cYrYRx29bwhIg9ESvLbs,348 +mypy/typeshed/stdlib/2/functools.pyi,sha256=egCoDsC6ABhatR3U0Eg_OSeMwpjxZ73--xsaVQid5aI,1276 +mypy/typeshed/stdlib/2/future_builtins.pyi,sha256=DbYFW8d39H2GuMb9XI4bXI23GxomislNrLbdhDqpkEo,226 +mypy/typeshed/stdlib/2/gc.pyi,sha256=iAjXpW2_tvA_JLuWswJT_S0UwokgA24kN8_mhR0onYc,787 +mypy/typeshed/stdlib/2/getopt.pyi,sha256=6hPbDzz4CuSglcyFspFGyWCNVW0AKygfMXPTD0LKI8Q,448 +mypy/typeshed/stdlib/2/getpass.pyi,sha256=wXXCl7EPrOCj-zmKjbUKe6wkVcdvECb6pjV91lKnsWE,192 +mypy/typeshed/stdlib/2/gettext.pyi,sha256=s9TQTyU5JIsWXWturgUTZnB6AXIRkdPohmRb-HzdNC8,2284 +mypy/typeshed/stdlib/2/glob.pyi,sha256=7Js1jrnzrtGyNCOKUL5z9RUe0ISki9kCT2ofpZFVutk,375 +mypy/typeshed/stdlib/2/gzip.pyi,sha256=fdKYU2jPcVb0a0XG8bhizK7xg1zoe4mxJMIzNneEKzA,1000 +mypy/typeshed/stdlib/2/hashlib.pyi,sha256=hy7FqcyGH1PYL4iHw1bCAe36_FKEPfNG2coF1e4Oe6I,1004 +mypy/typeshed/stdlib/2/heapq.pyi,sha256=Uwl92Rs8tnmAoEO_SB6UGbNgCoLdlLVkEHyMUZyF8lg,746 +mypy/typeshed/stdlib/2/htmlentitydefs.pyi,sha256=1dyH0i00daNQ_7gDuT-mxXzx-V_nDSRuF4q_vjkSUHg,114 +mypy/typeshed/stdlib/2/httplib.pyi,sha256=K5F-2VPE5Fd-Ym0WHdReg-E43Iycv-zrauPHGxTEhtg,5937 +mypy/typeshed/stdlib/2/imp.pyi,sha256=Nwy9qBm9V00qkJaM-H9cvcI9fTYgrjT1ofYnhLKFdFQ,1325 +mypy/typeshed/stdlib/2/importlib.pyi,sha256=N1OsqmcdpbeN7RTNU4s2zQgnoQhkwECT5z5bv035F-g,134 +mypy/typeshed/stdlib/2/inspect.pyi,sha256=trqtsRvyWdxlILAy3l5iwfVzo4cwW08TEaXV39y7IXI,4653 +mypy/typeshed/stdlib/2/io.pyi,sha256=zU0_W_RPG8ymcyG3GnFdOGt8FGYDxSYQFs5Vv5JYS9Y,1463 +mypy/typeshed/stdlib/2/itertools.pyi,sha256=N6TJn6fkEfAh1QU-UlIErgoK9no0CCuQtM_Hwes5mcs,6619 +mypy/typeshed/stdlib/2/json.pyi,sha256=oucI1k3DW7J2sAsQA3wGNdduGFY3Zxr-n0jSUQVr-5c,3777 +mypy/typeshed/stdlib/2/markupbase.pyi,sha256=spypPmrwD5qV88nR7U1R28WjGvm6TG8gs6N6H4NER0Q,265 +mypy/typeshed/stdlib/2/md5.pyi,sha256=ujmiPT-VQ7K8Y673_oOxDFCFDaVvnRx1Yul5DKxi7EY,118 +mypy/typeshed/stdlib/2/mimetools.pyi,sha256=KBcWPPbifAysN1-9XBAOyscxCcohCiAnBDmr59W4Ibs,703 +mypy/typeshed/stdlib/2/multiprocessing/__init__.pyi,sha256=XpfjArCYhOm_T5Adz62fXLzc8VgA_s9E76M-n8DyJPo,1931 +mypy/typeshed/stdlib/2/multiprocessing/dummy/__init__.pyi,sha256=6AorQihgpvOdhn3sBii5Y6zUXGJ2ZAFWvAsyZG7tnho,1417 +mypy/typeshed/stdlib/2/multiprocessing/dummy/connection.pyi,sha256=Ity8sABpKaHetJvDymCCZcseWDEUqo2uugGYTh-IcFw,674 +mypy/typeshed/stdlib/2/multiprocessing/pool.pyi,sha256=1BSro6BmtU4zWNvO2Y-IwqW8foP-8oE_Re09Lk1fRe0,2276 +mypy/typeshed/stdlib/2/multiprocessing/process.pyi,sha256=JgII3YNCNgvsmGPA1DL6kiA-X9xHWFxQ4Dhxaujfwec,909 +mypy/typeshed/stdlib/2/multiprocessing/util.pyi,sha256=fxZwUYlKqIXEwtNLRKqXRfL17uagU7XyWIvgQcGTyls,758 +mypy/typeshed/stdlib/2/mutex.pyi,sha256=Cqj7xmY36at4nqKKtb7th5v4HXHSVuy_5o8rVnsGIyY,426 +mypy/typeshed/stdlib/2/nturl2path.pyi,sha256=_u8yHiGMMnRRTjQAs37HCefvy5193SJDBUZTw1nZ0I4,115 +mypy/typeshed/stdlib/2/os/__init__.pyi,sha256=2RcZlSEAHZk_NA9WVBuFHnOTsMoT4o9qz_UVWX-MpGo,13406 +mypy/typeshed/stdlib/2/os/path.pyi,sha256=PmZPAETp5VbtmxCto9QouEvVLuRtXgU6JgL1-hoAQtE,6092 +mypy/typeshed/stdlib/2/os2emxpath.pyi,sha256=PmZPAETp5VbtmxCto9QouEvVLuRtXgU6JgL1-hoAQtE,6092 +mypy/typeshed/stdlib/2/pipes.pyi,sha256=65agLGycqLLqBqNqGgiUR79o5joqm6joPBiXATRz_0Q,453 +mypy/typeshed/stdlib/2/platform.pyi,sha256=G_CDGpxhbuvyOSwqmhyXKcNuvJFnsyzCsU_hTQchkDA,1609 +mypy/typeshed/stdlib/2/popen2.pyi,sha256=QH4ryQDmuA0Sysh4YxSzDm7kS-ixHH65XFsJYvvkPn4,1000 +mypy/typeshed/stdlib/2/posix.pyi,sha256=pHacvlf8FcC8z8xc2V5Y6-xC0nIjRnAkveMyUo8E4Uo,6308 +mypy/typeshed/stdlib/2/random.pyi,sha256=iOojzd26HoN_JQBiYjwWL-_Gf2_rcNM82DlUYD7wuR0,3311 +mypy/typeshed/stdlib/2/re.pyi,sha256=5lrtET1RXjmitFM6RuhPG8-SYxQtpgUi4tEmNOOGZ9Y,3804 +mypy/typeshed/stdlib/2/repr.pyi,sha256=-ojmu6--kHSN28a_gJqMAgEpNIs_pkXgY3fo0YypwNo,1094 +mypy/typeshed/stdlib/2/resource.pyi,sha256=NCa0Nk2470P4HcQ_nqubB7OznbVm50B1rNiPKOkMhA0,876 +mypy/typeshed/stdlib/2/rfc822.pyi,sha256=-TJ5oMGTXnzLWDnJKiSDNCsHQWxh74IW8-S2eACyvtQ,2234 +mypy/typeshed/stdlib/2/robotparser.pyi,sha256=IpfpnvNmCtN84yyZR9TmNdCQA7F1M5MQcqbUdkwoPXQ,230 +mypy/typeshed/stdlib/2/runpy.pyi,sha256=D-ttE7Yt0BQGuEMaHf5GUyzWrdW_onB8qwW1Opwrn_E,541 +mypy/typeshed/stdlib/2/sets.pyi,sha256=9V4YpGnjbddzHk12Pvb6Maf3hrLHHqnUZeonRX57KAQ,3003 +mypy/typeshed/stdlib/2/sha.pyi,sha256=1xfyIpQeVx3Ph_U7m2iC6DFoUkb7OpT15sKlyxWe3U4,277 +mypy/typeshed/stdlib/2/shelve.pyi,sha256=4c3UMmwxKA9n_e8harfdZgs016I7J3pqsfz6ql_f72s,1585 +mypy/typeshed/stdlib/2/shlex.pyi,sha256=PmzwDY50DBoojp3Rk9YeX2ZIif1J4tvb29P33sagKmo,1000 +mypy/typeshed/stdlib/2/signal.pyi,sha256=u2h4U_43SsdgRXp9-kL-t1uftTp9S1gWzJ00WkzsB2A,1571 +mypy/typeshed/stdlib/2/smtplib.pyi,sha256=8wiSP1iFF9-l9IKgh8p6S0rGwLuguGQfFH3xyWPh4ec,2542 +mypy/typeshed/stdlib/2/spwd.pyi,sha256=BDoGUDub7DFTKhD_tzXW6DbD3uGX15Ujm2DzuFF_cvA,308 +mypy/typeshed/stdlib/2/sre_constants.pyi,sha256=DBRHOreKuYAN2gehIRjBr585TsiCwmAdTeXqLWh5iO4,1814 +mypy/typeshed/stdlib/2/sre_parse.pyi,sha256=Y5iWkibgX4tyONqkNV7X3MLxnm2tu7dqaVOLAC8TqaI,2377 +mypy/typeshed/stdlib/2/stat.pyi,sha256=gwl9Q2AHQqlIigVb2Zf7gEMNEa-sP2t0V7OgbjIFuK8,993 +mypy/typeshed/stdlib/2/string.pyi,sha256=b-Dal7fHMea8YnOgsf0JTs3nTaEw5muHcWNptTFlBO0,3706 +mypy/typeshed/stdlib/2/stringold.pyi,sha256=8oR2LNkfQvzePY1arCjPxA19Wy4Tn05Yms3G3EPFTkI,2077 +mypy/typeshed/stdlib/2/strop.pyi,sha256=DVsBbcE6F9MGzaej_40MfE-5vk6wgu7Tdp6Sdgi_qYI,1198 +mypy/typeshed/stdlib/2/subprocess.pyi,sha256=kuvwN6je9cSSo5E61HcRehj33twNe3bNnUGiR3b33y8,3859 +mypy/typeshed/stdlib/2/symbol.pyi,sha256=qmqdWz_h1fXHExnPWlZxn83d8OVi5Im98_Kuz110yVo,1372 +mypy/typeshed/stdlib/2/sys.pyi,sha256=kujsO8mbXrbsJjRV8kRGb2uqxkjt2sU0OU99pcixxHE,3665 +mypy/typeshed/stdlib/2/tempfile.pyi,sha256=UFDS8YGUZMBPTJ0gsQGiBSRFDoQd-dEQdy2YoaZbhFU,3758 +mypy/typeshed/stdlib/2/textwrap.pyi,sha256=jd_r9lmNpKCLwpkgWTWCLR0C0xhhSPWpO1ARCRRMYmM,1976 +mypy/typeshed/stdlib/2/thread.pyi,sha256=y3qvJAjEE-elcJx87JdYeoap1OFygoCSW6cAGLESYng,957 +mypy/typeshed/stdlib/2/toaiff.pyi,sha256=zrENv_VOG8LvsszFHcfYAg98QRjT6CEcq_i_zls-Y3Q,337 +mypy/typeshed/stdlib/2/tokenize.pyi,sha256=CWb3mWSzXxKUp7hIgexrWTANJNUf3A0QICQ2HPsTtdo,2770 +mypy/typeshed/stdlib/2/types.pyi,sha256=Y9Y2EkystxLUxQclDAwEarPzTX3_bg2t8ksgE1UrXFs,5316 +mypy/typeshed/stdlib/2/typing.pyi,sha256=14cfkYtkV8mOHfbZG9QEbHZLPad2VVzDe6tUHHg7nm8,17389 +mypy/typeshed/stdlib/2/unittest.pyi,sha256=1pKTDFP-0svSFTX2gndPIIgSpV8E_R1OA_C0bCElrY4,13910 +mypy/typeshed/stdlib/2/urllib.pyi,sha256=G6PTg4wwlOQrlu-NgGYGwwz8IjChndeGAoQt1IuxqWc,4766 +mypy/typeshed/stdlib/2/urllib2.pyi,sha256=QxcOpwAa1fZ4YJr5NXYTpfptQV9nu73CpWXmYAnd7sg,8337 +mypy/typeshed/stdlib/2/urlparse.pyi,sha256=Y6HbLPC_8CCsF1QHE_vYPWlTBRwZvPRpQhpE5yEJP60,2033 +mypy/typeshed/stdlib/2/user.pyi,sha256=VmUsRNZaovrIF5qoRRIADPYkRdRmyADc54WDu6KWG2E,224 +mypy/typeshed/stdlib/2/whichdb.pyi,sha256=L2nM6tJquFezl_wNFb-E3DatgdBdWHeHIF9FusjbwEs,150 +mypy/typeshed/stdlib/2/xmlrpclib.pyi,sha256=BGfW9UUhV4h2vWTk6K2aBuJbHdQgMY3XyHd3_BPceUA,9655 +mypy/typeshed/stdlib/2and3/__future__.pyi,sha256=b7dmNhiJdcJM2cyLfX1i73MNfiVwTUfMmyOdZzBU2fw,587 +mypy/typeshed/stdlib/2and3/_bisect.pyi,sha256=zoT8nzIEekHTw4MTqEDDE-1iZp1ePJqZ36zt_S34dF0,513 +mypy/typeshed/stdlib/2and3/_codecs.pyi,sha256=-VWZl4jnzkCnnG8JSefddmRjZR17FHrh6KgWUTCWjRU,5291 +mypy/typeshed/stdlib/2and3/_csv.pyi,sha256=myUonJ4Cyl478ybDDmb_Z93Svx_QPGjwG_-7l6psnyQ,1575 +mypy/typeshed/stdlib/2and3/_curses.pyi,sha256=_tlp0eQRncbDCPBKOtsYEgaf3QmoDzrqGbRAhstjYJE,13441 +mypy/typeshed/stdlib/2and3/_dummy_threading.pyi,sha256=My5NxnR9Va4j7akJozhHoK5l32-CPF8o_7fY1JjIT-0,6479 +mypy/typeshed/stdlib/2and3/_heapq.pyi,sha256=9TD-IQPBIcpk6YbRPlPjxasMUhQf-3DN-VuIlI73tcc,653 +mypy/typeshed/stdlib/2and3/_msi.pyi,sha256=cfRk9LVfDlcH1QgCxSh4aSBp52bPR0zrhl4X7jTJzDw,2181 +mypy/typeshed/stdlib/2and3/_random.pyi,sha256=EE8bjymxRkUGvQtJPfpn24F1NHmNWOa5N3nh_L-phGc,499 +mypy/typeshed/stdlib/2and3/_types.pyi,sha256=nRmDZwn9NvkgH0D2NpfiWN7tRInF84d4yuIrOGkcQrg,268 +mypy/typeshed/stdlib/2and3/_warnings.pyi,sha256=-7CphU2vuE8ZK8N6bgztfJy3ossy0RN0PCavTPgVeq4,2218 +mypy/typeshed/stdlib/2and3/_weakref.pyi,sha256=dsSravIF0dShEt9xDjdfpo4pVZa3uJ5TgGOsW3XjI7E,1028 +mypy/typeshed/stdlib/2and3/_weakrefset.pyi,sha256=iSw1zz1YN3MV2ostBxZ1EI6fpSMwBbAvF6T0H5vSq2U,2239 +mypy/typeshed/stdlib/2and3/aifc.pyi,sha256=-ct213U0_GzXQ168mpLaSazHYg5rw9umA_zd6dFgeVA,3337 +mypy/typeshed/stdlib/2and3/antigravity.pyi,sha256=lB-a5aBvL40Y_RzoHGr1NcZFAEOchwrhNbwBrz0WTvk,124 +mypy/typeshed/stdlib/2and3/argparse.pyi,sha256=PjNh_HiOs3grizqUcneOHPGpZDokIiE4fekHZrxRp8Q,18795 +mypy/typeshed/stdlib/2and3/array.pyi,sha256=Dw_MaWu8yKLvHgynjzCaTirCalFr8SjKy0qu18TIO8U,3628 +mypy/typeshed/stdlib/2and3/asynchat.pyi,sha256=9tax37YM1fG21kdUs9TKs9HHkHoD2eG3xLuXqExu-qc,1557 +mypy/typeshed/stdlib/2and3/asyncore.pyi,sha256=uYgOIdSTBb-QBi7xHnSymtkTh8Hd52E8MStcyIL2WXU,5614 +mypy/typeshed/stdlib/2and3/audioop.pyi,sha256=9TLDsTMHX8qW-5JkVZEnsOifUXHrnZKlpRsJ-Lg7Oko,2124 +mypy/typeshed/stdlib/2and3/base64.pyi,sha256=UClWK9E192QMDaaA94IlEoUUXI9jjjidZbC9RN4W9_g,1701 +mypy/typeshed/stdlib/2and3/bdb.pyi,sha256=-EqmuD9q2K51F99mNG79WXW2LtE-sFOLrvuBH1EsYSU,4594 +mypy/typeshed/stdlib/2and3/binascii.pyi,sha256=ZV1RJbEKltgsF6-Q0Z4FWGSa_XJq4OFndKvCeErjVJQ,1626 +mypy/typeshed/stdlib/2and3/binhex.pyi,sha256=RdIA0UO1pN5uTqZlDNX24ye1C-HcJqS8gVKVdGGNxTU,1169 +mypy/typeshed/stdlib/2and3/bisect.pyi,sha256=rTQ0KlWUs-hNM6JHHJ6Udktqoz0OCY6c_c6qUIkZbns,85 +mypy/typeshed/stdlib/2and3/builtins.pyi,sha256=ES5n7BlrlVsfGTO30LI7aHfcOeEPN9BtbEkUky3fY28,73033 +mypy/typeshed/stdlib/2and3/bz2.pyi,sha256=LRrbpW9HmJz5JuJSzn6V0ChJWW-3is4CMM3JvTOdzYI,1850 +mypy/typeshed/stdlib/2and3/cProfile.pyi,sha256=SFnHiIY3blPl5sO-lFoT13BRAIvfvmXEchGLYDKiiNw,1284 +mypy/typeshed/stdlib/2and3/calendar.pyi,sha256=rFOCDD2wDoJZUp6rXGsM2SLGe751yufVgO4rUaera1Q,5772 +mypy/typeshed/stdlib/2and3/cgi.pyi,sha256=EQghBMFJYTNSe5_xVL3uQ5F2v1Fvqkj7EV-TX5cm9Fg,5467 +mypy/typeshed/stdlib/2and3/cgitb.pyi,sha256=B8gorWp9OEuFVBvGOQW_YT2440cL2MH-2Mq_93n2iFo,1536 +mypy/typeshed/stdlib/2and3/chunk.pyi,sha256=jowWsUq9mcMGDdmTHlaLlukvEQihCsuqVTVUev7KkIg,755 +mypy/typeshed/stdlib/2and3/cmath.pyi,sha256=yDJCSAME3JlBO7f6Jk0ga5cdJiAL9SVoDGjGbrOC5Q8,1256 +mypy/typeshed/stdlib/2and3/cmd.pyi,sha256=7pF_Cd38Noh73u_vhUgPKg3udqGFXNnwKbQXlHqjoSQ,1694 +mypy/typeshed/stdlib/2and3/code.pyi,sha256=PAczIl94ovoD81xCyBiJvMFAK4vK5nxakMKr7TfaSn8,1646 +mypy/typeshed/stdlib/2and3/codecs.pyi,sha256=BC90TGmUlFXZM8PMLf7QewTRPqjO5J459WnKizk8M5U,12189 +mypy/typeshed/stdlib/2and3/codeop.pyi,sha256=2Ewyo9P3RURy-L9JIjD93vf7tmLu2-rKBkkb780T8_8,633 +mypy/typeshed/stdlib/2and3/colorsys.pyi,sha256=gycPfF1f7H4--FWW-EcrA1xkFbWorJN6GH_Nlp2dK5c,600 +mypy/typeshed/stdlib/2and3/contextlib.pyi,sha256=hP04ak0ehl7qYm-mJGQQXEN3A9NFdTlMnH-06VVbjew,4806 +mypy/typeshed/stdlib/2and3/copy.pyi,sha256=Vn1-_joBr-pkOjjCau3LDjHYnD7bcYWAxkYqNLEx4YY,343 +mypy/typeshed/stdlib/2and3/crypt.pyi,sha256=j5hzsqJ9ZuejqS1NP9QIzaC6N25m_wHpPaLVJlNRfKQ,648 +mypy/typeshed/stdlib/2and3/csv.pyi,sha256=WWB4hHEKOdKgYhd-cT60FK_8Sa1W3e62y8zfF5umqAU,2758 +mypy/typeshed/stdlib/2and3/ctypes/__init__.pyi,sha256=Vszqgs9J-d7RrmRnUZXPpgFFX1IWydUgttAdAEV0caE,11771 +mypy/typeshed/stdlib/2and3/ctypes/util.pyi,sha256=ScneHbPrwdZ3qbY_LD_kDjStl9dMFrmy1NQVtHrjmOs,187 +mypy/typeshed/stdlib/2and3/ctypes/wintypes.pyi,sha256=iFiDsgc33hv7Qh2fnSPH6ZrATxo852KmoGCLRN03f0s,4566 +mypy/typeshed/stdlib/2and3/curses/__init__.pyi,sha256=esUGCXbLy6hPzYYOf1HS6IpbXgfI_U9tfQ9MU2zWvDk,370 +mypy/typeshed/stdlib/2and3/curses/ascii.pyi,sha256=N7W-GodjpobQNyftBWTcdbPJDa50sRve2KRo_-jnYZM,1222 +mypy/typeshed/stdlib/2and3/curses/panel.pyi,sha256=Wsl42xkXk8GQesNABDijIoBVX5Nx8dGm6prO1-gxlyU,801 +mypy/typeshed/stdlib/2and3/curses/textpad.pyi,sha256=V-6r4xPbkITORxiUCAPV-QzWi69JZV0tZwO72HDbuU8,457 +mypy/typeshed/stdlib/2and3/datetime.pyi,sha256=L80sHDqtsqOUftEluZozBTBnPNViVE2adgO3lVQbxIU,12218 +mypy/typeshed/stdlib/2and3/decimal.pyi,sha256=cIYc9W4cpSnSjH7sA6YmXilH-R3r9iaiRYz3g9Thh78,17781 +mypy/typeshed/stdlib/2and3/difflib.pyi,sha256=6cRKvwxWUQn3HddPlvGjpjs7i0owmPDGJlSMUQAnDeM,4763 +mypy/typeshed/stdlib/2and3/dis.pyi,sha256=TNb1GWkdu3Xx4JORIfKKzQKC5msgxbA7S2gVMhFatWs,3103 +mypy/typeshed/stdlib/2and3/distutils/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/distutils/archive_util.pyi,sha256=Cb2sF0yvhbPtCxdz6j_dEF3-9PlXKXPLrHsUiDBKjs4,525 +mypy/typeshed/stdlib/2and3/distutils/bcppcompiler.pyi,sha256=hbYMdSNGfHOUf9_f2vSeFUpg76hFgt71MCBp4ynppwA,115 +mypy/typeshed/stdlib/2and3/distutils/ccompiler.pyi,sha256=1zsRUUGL6p3ltw7nC99tOOjJw-qQqJoqHdWydQ9-kTs,7218 +mypy/typeshed/stdlib/2and3/distutils/cmd.pyi,sha256=zOwZ0rmmnVHhm289F3TnhC1jzTNQe5BPmvoa1HPtJ74,2588 +mypy/typeshed/stdlib/2and3/distutils/command/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/distutils/command/bdist.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/distutils/command/bdist_dumb.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/distutils/command/bdist_msi.pyi,sha256=sDSqH7TRcOiXC5S4VXxJ_YHB-WFPpa1fo8F8g5XeV3Y,182 +mypy/typeshed/stdlib/2and3/distutils/command/bdist_packager.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/distutils/command/bdist_rpm.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/distutils/command/bdist_wininst.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/distutils/command/build.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/distutils/command/build_clib.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/distutils/command/build_ext.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/distutils/command/build_py.pyi,sha256=d8u3XWYYW-TCNOWUqOy3y322trpVj00EUe-9Qmk6VoY,277 +mypy/typeshed/stdlib/2and3/distutils/command/build_scripts.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/distutils/command/check.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/distutils/command/clean.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/distutils/command/config.pyi,sha256=Qc0D1ty5fiKCd-_CZhpJvJCMQ3me_I-IaVZz5TIIn4k,3071 +mypy/typeshed/stdlib/2and3/distutils/command/install.pyi,sha256=9zAI1cDdVfOAA_ZD5SQTRJUbznKwNaGjF_JK8Vom2Ng,340 +mypy/typeshed/stdlib/2and3/distutils/command/install_data.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/distutils/command/install_headers.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/distutils/command/install_lib.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/distutils/command/install_scripts.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/distutils/command/register.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/distutils/command/sdist.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/distutils/core.pyi,sha256=vi8TtqnwDd3SuPnjNJ1s8kVsOf5ycjcKYswDxKM_ttw,1716 +mypy/typeshed/stdlib/2and3/distutils/cygwinccompiler.pyi,sha256=ckHKszxakRQfSAsfxtlwYQOYzbUt5sYCCJ-U3mV2hyw,178 +mypy/typeshed/stdlib/2and3/distutils/debug.pyi,sha256=UTaP07MC1pSK2C1Ku4w_fPVnHoS72N18TmSaZA4Yo2M,41 +mypy/typeshed/stdlib/2and3/distutils/dep_util.pyi,sha256=bXprG0MdGygOD5dR_TMHepwl_8NNnZ8ky5Zk5lpxc8g,303 +mypy/typeshed/stdlib/2and3/distutils/dir_util.pyi,sha256=8pAEw1RcokPtwea8HOct8c7-dRtJ3uWqUecWD8v-UZo,638 +mypy/typeshed/stdlib/2and3/distutils/dist.pyi,sha256=i5pzVnctJsL6wkcv8ArrU5a2VPjh6sdfa0rEjr6FNTU,543 +mypy/typeshed/stdlib/2and3/distutils/errors.pyi,sha256=l1W_FgoP9L-D-hEPFA2BzZuybjN0lV4WBXl0VJ-k7J8,852 +mypy/typeshed/stdlib/2and3/distutils/extension.pyi,sha256=Yj5TMS_T49VhAKunqKt9IeKqXcRTFBqVZlWMb4D6OBM,1851 +mypy/typeshed/stdlib/2and3/distutils/fancy_getopt.pyi,sha256=a4ii8u9VKd7RHfbL7OAH8Qq5A4TuO4PHaDLy0eifZlg,962 +mypy/typeshed/stdlib/2and3/distutils/file_util.pyi,sha256=PkDa6hW8S6oXedW-VdFHtkc8VfTKq6pxiHmzkxY22M4,494 +mypy/typeshed/stdlib/2and3/distutils/filelist.pyi,sha256=lPEMKrnk-y7jIfMpTgJEkf9wgt6UJ8rM5ER0I-uWJHs,52 +mypy/typeshed/stdlib/2and3/distutils/log.pyi,sha256=8W5K1F9OHVk8rQx6NrI6eBUcZ510Cst7ethbRxUYMS4,776 +mypy/typeshed/stdlib/2and3/distutils/msvccompiler.pyi,sha256=XSn5lSllRGmo0x1MAWZfi64t7bLiup7Ic_Aht1PXEQM,115 +mypy/typeshed/stdlib/2and3/distutils/spawn.pyi,sha256=Lx3dQ5YxHa6dMBouciPrZdLZp3a0Mb96zlC6bkR9AWg,286 +mypy/typeshed/stdlib/2and3/distutils/sysconfig.pyi,sha256=nCXDeJFmj1mh0s2zaUApwyARYA7f4lUoS1acJaoQjEY,692 +mypy/typeshed/stdlib/2and3/distutils/text_file.pyi,sha256=y2b0du-gmjUE5wdZGRn9CDM_JlhJ_D-cuCuCpJR8IgE,760 +mypy/typeshed/stdlib/2and3/distutils/unixccompiler.pyi,sha256=Ak9WQSMgsoU-8N03ncUJRTa2hKmaWxVzPGOY61FMcks,117 +mypy/typeshed/stdlib/2and3/distutils/util.pyi,sha256=GxjDiLfzjyBucyKt4rZdjRX_wcvwSMEGaUAUI1VFzo0,892 +mypy/typeshed/stdlib/2and3/distutils/version.pyi,sha256=IdT_89jTuB9bxfgIZE_L9RG9WXP4VAOtl42SoxjFAVM,1884 +mypy/typeshed/stdlib/2and3/doctest.pyi,sha256=Gi867kecW5lAImDHh3m68fBSaL_N3NMm9M7z9WFOhfk,6872 +mypy/typeshed/stdlib/2and3/dummy_threading.pyi,sha256=eUXlP8htlaLQnj2tD0R2_p1b5jZ4f1BBXliphPhUqtM,80 +mypy/typeshed/stdlib/2and3/ensurepip/__init__.pyi,sha256=jtJ8SnDqMaDHvU_dJ__E0-J7pBJFp36dEDxvUbE6a74,444 +mypy/typeshed/stdlib/2and3/errno.pyi,sha256=6dsaKvRQODirtoYdz0wmSMhW-M0ibxf6RoPa2ibdoIw,2041 +mypy/typeshed/stdlib/2and3/filecmp.pyi,sha256=yHy2IHgCDXJkoJpO1x1F8d3SB63syo1TMrYZCqr45Wk,2386 +mypy/typeshed/stdlib/2and3/fileinput.pyi,sha256=Qxycw6jY7dspDmdRZ1eQi9O4Uxm7n3WeT_U3q4kg5is,2672 +mypy/typeshed/stdlib/2and3/formatter.pyi,sha256=c3uuKNVkPA3yE1Vc8_tIq3kqKScTppfAJpg_5bXDSI0,4774 +mypy/typeshed/stdlib/2and3/fractions.pyi,sha256=BKSTLNeHuZu2KIX9nYjYjIraai8Mgwy8n2QFn5wvcr0,3179 +mypy/typeshed/stdlib/2and3/ftplib.pyi,sha256=V6aaNY13KqRsJTBIu8sFQfRDSsJWsJD_xygryKNXHKs,6001 +mypy/typeshed/stdlib/2and3/genericpath.pyi,sha256=hyBC1HQdLMx-fkO_fzZwXJDocMbbdwWfyAJ_f-bV35o,803 +mypy/typeshed/stdlib/2and3/grp.pyi,sha256=fm0JOwvJ8CGCXSVWyqQuXFBPBfoVC8b5CyWTq-5fcvs,295 +mypy/typeshed/stdlib/2and3/hmac.pyi,sha256=LDOblpTV6wgbdj9Egy0_5q69MA_bqFLbM7HLq5Sl_do,1075 +mypy/typeshed/stdlib/2and3/imaplib.pyi,sha256=byWl3v0NnMFm25ruWDpRsBlaHCOGGpXi-CvXax-qsNc,6873 +mypy/typeshed/stdlib/2and3/imghdr.pyi,sha256=F2QuL0zFdi_Z7ZR6WN2nXaB4IAgh9GU_u5ouLhnRscY,605 +mypy/typeshed/stdlib/2and3/keyword.pyi,sha256=GHJis_Ztsrt-hX1HP8g3cu1DXR0oNfhbb8OnZawtIwE,135 +mypy/typeshed/stdlib/2and3/lib2to3/__init__.pyi,sha256=0ggYR5uuGf5bPw2MfRjOV-SlNLTFqvAQI2xyd9d1n5s,33 +mypy/typeshed/stdlib/2and3/lib2to3/pgen2/__init__.pyi,sha256=GCKIgFDXUS4t9oWDYB3TY1U8utGs2GRN7i_Bv4hAo8Y,184 +mypy/typeshed/stdlib/2and3/lib2to3/pgen2/driver.pyi,sha256=I6t6a8rD2kYxTTfPGWQcV7NYmO6hNQdAHOYzh553-T8,1050 +mypy/typeshed/stdlib/2and3/lib2to3/pgen2/grammar.pyi,sha256=T5ogRjiiL8iyCxSqJHPKf4XxgQaH64P6EEJE-7W_6jk,785 +mypy/typeshed/stdlib/2and3/lib2to3/pgen2/literals.pyi,sha256=wOFWATRmrAZ-Epxm6c67kphsmU-Z5REvb3RSynIUUmg,221 +mypy/typeshed/stdlib/2and3/lib2to3/pgen2/parse.pyi,sha256=vHNzZoOdBveIwc4jjDHVaGyM_MLERTWVzEeC1FH0rfU,1160 +mypy/typeshed/stdlib/2and3/lib2to3/pgen2/pgen.pyi,sha256=ktroynzH2GlVHC-OWl7LOBwYGE8nyj0tJnpIzCTyn5A,2165 +mypy/typeshed/stdlib/2and3/lib2to3/pgen2/token.pyi,sha256=rTl8bJ2stp05jnK8xuK-ydeM3fcZzTWFzccTU1UHxlM,1111 +mypy/typeshed/stdlib/2and3/lib2to3/pgen2/tokenize.pyi,sha256=HHAAij2sz6QMDM0tk7IkHf0VFQcV5qCYa1VhMuzXblA,988 +mypy/typeshed/stdlib/2and3/lib2to3/pygram.pyi,sha256=evWU9m1mfMk7l0xWWGpWOygGGAcp0whXRugDyfmZFxA,2272 +mypy/typeshed/stdlib/2and3/lib2to3/pytree.pyi,sha256=ZJxW3lDbZf6TDqb2c95Dx3e8YFKzNA4PqmIl9upXjHU,3254 +mypy/typeshed/stdlib/2and3/linecache.pyi,sha256=Mn3wvI9otFnkJX0ejPEg-QJ-YYNjfVuAulJvf5SBSMw,590 +mypy/typeshed/stdlib/2and3/locale.pyi,sha256=YaZ85d8j4Zy4wQHKUiqE4bitCK6suIf39sdYhtD4UzI,2652 +mypy/typeshed/stdlib/2and3/logging/__init__.pyi,sha256=mGsuqMguo9TiMUncL-5ux_PasPbVDDwqx6g-K-ey0kQ,25886 +mypy/typeshed/stdlib/2and3/logging/config.pyi,sha256=eOtTCSARYosr0CWKLy1B-MUdwHvNkZzJEqa60TaCYsk,1163 +mypy/typeshed/stdlib/2and3/logging/handlers.pyi,sha256=-K_h1gLfxUcLt5XKFvFiQboYrQGKBskBvcr1iwj4Tg8,8096 +mypy/typeshed/stdlib/2and3/macpath.pyi,sha256=DDo6vnmMruu8IGCTOCkGTVv1PHRssAgQEUbJ3LozSy0,5640 +mypy/typeshed/stdlib/2and3/mailbox.pyi,sha256=Vr84jZyOXYaYR3s-QPS17PgHjLdgxoEX78yNGNnINuM,7864 +mypy/typeshed/stdlib/2and3/mailcap.pyi,sha256=tAu_XLnDp7kbJT8epZ1JfFAL8DayNC9VCQ1HpU-Yi74,325 +mypy/typeshed/stdlib/2and3/marshal.pyi,sha256=vNc5SxSiVhknIgqYkJ8Z42KFwPX48G3-Drv5aki0fqM,253 +mypy/typeshed/stdlib/2and3/math.pyi,sha256=ONvTbMV3TDTDHG-g-wxbffY94cA-nlpu8UoxfUxs-Zg,3372 +mypy/typeshed/stdlib/2and3/mimetypes.pyi,sha256=DYJyWB0-peSgJSsci53bL8Dpcml2NcbySkfrdSiJWew,1799 +mypy/typeshed/stdlib/2and3/mmap.pyi,sha256=dTng8OkULVXuiM7-lleMEt3pr2gD5KXqNDZ9gACzhfU,3714 +mypy/typeshed/stdlib/2and3/modulefinder.pyi,sha256=IKJn0TJs7NtRyvkVXQcK36EPYFjIlvj4qU7-OtV8uKA,3502 +mypy/typeshed/stdlib/2and3/msilib/__init__.pyi,sha256=AWRTnQLCgNwzL9TgXJKCOMVUvc2jXXwL626humFU-IM,5409 +mypy/typeshed/stdlib/2and3/msilib/schema.pyi,sha256=vNdndSnA4JYQ4xn1DwAJd0naAtcGJFzh38Yb8OFeAW8,2201 +mypy/typeshed/stdlib/2and3/msilib/sequence.pyi,sha256=Dj8l0qBCy2B4y85QQJY_LrVVtiOwllKCuhY8LdOsOlA,357 +mypy/typeshed/stdlib/2and3/msilib/text.pyi,sha256=mpQf1WqBHhzyuNwtvTjAWjZzK8PyjeYrxv1UVgRa4ho,203 +mypy/typeshed/stdlib/2and3/msvcrt.pyi,sha256=5z3DUoHYt9-FOHMGOF8zFEWr1feG46l5M0vxSiwX2Ho,287 +mypy/typeshed/stdlib/2and3/netrc.pyi,sha256=b-5spr7aL_aO4r3x87Gt2DVPzWUX5DzVQjRRO-ctlLc,466 +mypy/typeshed/stdlib/2and3/nis.pyi,sha256=pkA8pWBwqIP_NKf0chQ-iLvlPayJEFVg5bauHoiOEgg,323 +mypy/typeshed/stdlib/2and3/ntpath.pyi,sha256=PmZPAETp5VbtmxCto9QouEvVLuRtXgU6JgL1-hoAQtE,6092 +mypy/typeshed/stdlib/2and3/numbers.pyi,sha256=GLYOksSFBTyJvuaqADa2Zpt6BCaorlK-tI5zZjSEH_c,4065 +mypy/typeshed/stdlib/2and3/opcode.pyi,sha256=VaxuSzhOg15YJELo_JQPK0oBKwIy2_EOCDss7TDa1D4,609 +mypy/typeshed/stdlib/2and3/operator.pyi,sha256=oWKmFKJhs62xglAsTcPfs4chxQ0aQVhmYlPpnXW31hc,6703 +mypy/typeshed/stdlib/2and3/optparse.pyi,sha256=Hd6jEKKuTqP0PsOt8HCSiHemoEHGHTWzknLtjsXcKDs,10307 +mypy/typeshed/stdlib/2and3/parser.pyi,sha256=xrvGcs2kWdXUCPIqpyUDIBDyxEDxH76pZhWCEa4OAWU,1095 +mypy/typeshed/stdlib/2and3/pdb.pyi,sha256=_-6NDf1y2PLD4JYXbR16Ruqe9GPGM5Y0GFAbdXS1eaw,10345 +mypy/typeshed/stdlib/2and3/pickle.pyi,sha256=lBsSkJ6cE91gAQcdk8g9I1mZyc1kdYGvTUACzto3HSQ,5206 +mypy/typeshed/stdlib/2and3/pickletools.pyi,sha256=9vcrF9ha3uuyJrbZOznxvIA04N99nSCXP1MgttLhCh0,4395 +mypy/typeshed/stdlib/2and3/pkgutil.pyi,sha256=co860uP6jr-cITm5wZvIeqsASwy4MAKXABvhOMKT_So,1369 +mypy/typeshed/stdlib/2and3/plistlib.pyi,sha256=lza7X5YUSazzEREZ-dLA7R2ljnQGCTSGGavzwsVfTso,3459 +mypy/typeshed/stdlib/2and3/poplib.pyi,sha256=8hzOYh0vEt5Icq75jMqYzEq_eOiWSxl8jXWYMjH_6Ig,2492 +mypy/typeshed/stdlib/2and3/posixpath.pyi,sha256=PmZPAETp5VbtmxCto9QouEvVLuRtXgU6JgL1-hoAQtE,6092 +mypy/typeshed/stdlib/2and3/pprint.pyi,sha256=Sg38pz7qwCr0FhPa5PH3IYN9X8ZzTpFpizKYxDYm_Qs,2887 +mypy/typeshed/stdlib/2and3/profile.pyi,sha256=5nCnL_wdprKHDDPDB4Y0VIEFiwxbjTPsS-4IFMFyBs4,1289 +mypy/typeshed/stdlib/2and3/pstats.pyi,sha256=mTFjif4ELEAgTFhktpS03Q778zVdvar6CTMBIzQkCEY,2038 +mypy/typeshed/stdlib/2and3/pty.pyi,sha256=ZdJ4D2e0W3mk2I7kg-niYldKAgMAV-GX66oQx2X6yZE,623 +mypy/typeshed/stdlib/2and3/pwd.pyi,sha256=s48Hp0pbMoMBpWg6glXl1ABEcLU4zLj_wV-PloenVI0,350 +mypy/typeshed/stdlib/2and3/py_compile.pyi,sha256=zoerWecNVSTIjfHRHA46mlUuTZicDyuyDxbftsJVg2s,1534 +mypy/typeshed/stdlib/2and3/pyclbr.pyi,sha256=FgAnJHHLujcqj8UAC0LU1dt688cJp2FTBY7AG5ZQVyE,1170 +mypy/typeshed/stdlib/2and3/pydoc.pyi,sha256=L1cLddBpAjncQer6eYST2Q2DG8unz1yBBWl_yJwx6Yc,10035 +mypy/typeshed/stdlib/2and3/pyexpat/__init__.pyi,sha256=aykjEGyTxd8faCQ4hYq-KZ3ZeYb3jqRUHxX1g9MDnrY,3397 +mypy/typeshed/stdlib/2and3/pyexpat/errors.pyi,sha256=TVdXkdX10ZCjPuBYAy3yNQzUJMo5lCjsl8bv4VJ8PU0,1275 +mypy/typeshed/stdlib/2and3/pyexpat/model.pyi,sha256=LlBMaLvt3TBD1JQSAQTYUrHKAfKNEeQYaDw5GsJA--g,205 +mypy/typeshed/stdlib/2and3/quopri.pyi,sha256=7PML6bBx3UqKF1pHBUxkmo9Q4kh-UYdmQ4SwdQizkgA,380 +mypy/typeshed/stdlib/2and3/readline.pyi,sha256=ayEVs3rdNRotUGelvU7IJ0D6aQtFru5tb0FI7r2YIAU,1525 +mypy/typeshed/stdlib/2and3/rlcompleter.pyi,sha256=uKxlYpHPjzXoce9dIHQH7vg53rn7mKb9m4x0Yx_yjx8,334 +mypy/typeshed/stdlib/2and3/sched.pyi,sha256=RgJRmcHjdTx-DUDWjX0b2EsdiEKvbJhVCKec8QVQe-E,1332 +mypy/typeshed/stdlib/2and3/select.pyi,sha256=1Gp4pZr6-2Z5kNkxtMsKpmRMyLrcbYsjeugvnMEdknA,4638 +mypy/typeshed/stdlib/2and3/shutil.pyi,sha256=XtH3WySX405PXo6s7wihsA4ZaxSwcnJEbqRj708ELUc,6652 +mypy/typeshed/stdlib/2and3/site.pyi,sha256=jIbFW1pDqUze5Td1FOOFFkF9-KU_5RtT-5R58eVqkQw,482 +mypy/typeshed/stdlib/2and3/smtpd.pyi,sha256=HrEx9a0iON3Xz95TWg0y17zEX25w9eoBjSV5BOUtl2Q,2856 +mypy/typeshed/stdlib/2and3/sndhdr.pyi,sha256=98gAwwLN2qVXRZ-Fz5fpK75WOEsikMMIhQiIsPr1n58,635 +mypy/typeshed/stdlib/2and3/socket.pyi,sha256=VTMPEalZTlaXvqnhimypBD3xEBdw_ru0a47_5udBZrc,22362 +mypy/typeshed/stdlib/2and3/sqlite3/__init__.pyi,sha256=aJu9MCNl8y9HCykdUpo1Z-LSiP3mxRSxrWkCsMxemYI,43 +mypy/typeshed/stdlib/2and3/sqlite3/dbapi2.pyi,sha256=r1LWC9FqfvCPh9NpofOv0VXctECUt3jLePjs2y1YCrs,11276 +mypy/typeshed/stdlib/2and3/sre_compile.pyi,sha256=Ab61wAZxIintArRZdq1PW_RDhb3HIfG8QAb3QO4VBjg,635 +mypy/typeshed/stdlib/2and3/ssl.pyi,sha256=XlSGlJrO-rXkDzxIBJKrwEmKnuEb79oj67LrqVRGKYg,13956 +mypy/typeshed/stdlib/2and3/stringprep.pyi,sha256=aEQorjm1j79Czrsv5Sroc2UOlw1GW6mlx8M0raDASS4,858 +mypy/typeshed/stdlib/2and3/struct.pyi,sha256=UX7YRFZikA7uPpyGXeb8sU1KM-LcHpYlqqVz-fNPnRQ,1704 +mypy/typeshed/stdlib/2and3/sunau.pyi,sha256=GSTfxmlaf6DJfazXRCcjZfsAbJCbxr8dMBepX0hPzJc,3120 +mypy/typeshed/stdlib/2and3/symtable.pyi,sha256=P_OBxtiTKgCXgdc6__elUMlO4ambO7LCYd4x0uBiNuo,1645 +mypy/typeshed/stdlib/2and3/sysconfig.pyi,sha256=E6dMDDKqJUYBFZ-kIoEcNOMH_m_pUMwK-YdYNFMEy80,873 +mypy/typeshed/stdlib/2and3/syslog.pyi,sha256=bEQi8JxzO7mGssGe-QrfBPZt0jLOrmp76odixNhxfHw,822 +mypy/typeshed/stdlib/2and3/tabnanny.pyi,sha256=JC-r81-1nac5wCgEBmhdBNriPaVan4jQF0af-5m699U,593 +mypy/typeshed/stdlib/2and3/tarfile.pyi,sha256=_hqMD1yJzhtIJRm7jE-CcKlwPWGpTbfFl-8K8H54VHM,8300 +mypy/typeshed/stdlib/2and3/telnetlib.pyi,sha256=bzFdnfOV3rSWVuxXtItqi5x8vf00essbXBLAD6x71rY,2723 +mypy/typeshed/stdlib/2and3/termios.pyi,sha256=dd_kI88y14jCzgztgOOraAyZxEtqtWStc9AtP_iI1v8,3505 +mypy/typeshed/stdlib/2and3/this.pyi,sha256=r1JNm3vNPoIMp_MTkYGL7VIrjQlOhcvZTicC7KJl0Oc,51 +mypy/typeshed/stdlib/2and3/threading.pyi,sha256=My5NxnR9Va4j7akJozhHoK5l32-CPF8o_7fY1JjIT-0,6479 +mypy/typeshed/stdlib/2and3/time.pyi,sha256=ok1yJEun-KIOdsPP3zO1ZcPDMLgWpDP9_0a1FIXdYx0,3929 +mypy/typeshed/stdlib/2and3/timeit.pyi,sha256=6r_rYvSdn5Y-oOEQL5Fcn8eqjoh8ftfDcVIevF_w9io,1634 +mypy/typeshed/stdlib/2and3/token.pyi,sha256=2CwxTAON40xXJfWuZVtX8LU057DaeqsS_B0QVFzdhyQ,1430 +mypy/typeshed/stdlib/2and3/trace.pyi,sha256=PFKnnYS9-v6K0CaDBmiUSNNxbcbMH2ipeqG6TxqpOWo,2048 +mypy/typeshed/stdlib/2and3/traceback.pyi,sha256=5azGN_UMAmPB2Exw8jUWcWmx2Pk4dIVRV4peo2zCoNo,5852 +mypy/typeshed/stdlib/2and3/tty.pyi,sha256=19RemvpbjAwcd4lC2bUPrtWzAgqPBPEeW11rUzC0jf4,305 +mypy/typeshed/stdlib/2and3/turtle.pyi,sha256=R-tomX4iX1P80cnS0W67ig9Yz6JYAD81yhRiu4iUl8Q,19201 +mypy/typeshed/stdlib/2and3/unicodedata.pyi,sha256=agOIGVwcxG8qK9zzUb3zK57v23WemcejDKcdjAtD74g,1900 +mypy/typeshed/stdlib/2and3/uu.pyi,sha256=evhpL6gjY62CXtOHbYwFtxnbThFL2wSIYNdRYPbX1AI,565 +mypy/typeshed/stdlib/2and3/uuid.pyi,sha256=M4vrGty5aW9jE640a_GeD5FLBgNHt3Y2gu4OCE-WL6c,3507 +mypy/typeshed/stdlib/2and3/warnings.pyi,sha256=59x5OCFaA7r-C67pBw8poF321PaJNR5b9Df-eijfsRc,2494 +mypy/typeshed/stdlib/2and3/wave.pyi,sha256=24acKfHFtDa_C-EmRxFn_NOjYs_3YDhJdP--dhbir4E,2693 +mypy/typeshed/stdlib/2and3/weakref.pyi,sha256=a7APR87XeauDS9OYux558cSmWaNZAZSt6-_yz8sPQ4U,4288 +mypy/typeshed/stdlib/2and3/webbrowser.pyi,sha256=xU_gF2UjxUqxOumCOb7c7iCaTAU5vz-UvuCwuio-cwA,3271 +mypy/typeshed/stdlib/2and3/winsound.pyi,sha256=Rbo1sNjqmRYE6o1rPpPdJ0GzteayYUVO4pyO-EJOEyU,885 +mypy/typeshed/stdlib/2and3/wsgiref/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/wsgiref/handlers.pyi,sha256=l0A6fhIcMFXTABDRawRTYzr3j068FgWBYbNy8MtN9pE,3100 +mypy/typeshed/stdlib/2and3/wsgiref/headers.pyi,sha256=eDrVTuY32OcH89OxOrEaW2IFVu4f6-5K5TCR86FKuHA,1250 +mypy/typeshed/stdlib/2and3/wsgiref/simple_server.pyi,sha256=uqXNuh-pntkPVTutUSKdCT9nCmdBQxsCwtu-gjpRVj4,1523 +mypy/typeshed/stdlib/2and3/wsgiref/types.pyi,sha256=ZFIK0Lidrc_3N9E9XUFwAskcpmejtSnjKjbSDmmp1W4,1742 +mypy/typeshed/stdlib/2and3/wsgiref/util.pyi,sha256=9ssIjy_7yKdPjdHO6emPKCzHRcTvoiyPI4KlHfxXlfA,886 +mypy/typeshed/stdlib/2and3/wsgiref/validate.pyi,sha256=4LfN9O2sxYoap7vzm9Nyz59usGRnjs3SX-SgUrSG3V8,1861 +mypy/typeshed/stdlib/2and3/xdrlib.pyi,sha256=fVlQwIUUmlgknTh3Tvsc5VaVEpRcSf-vV31l47kldlA,2353 +mypy/typeshed/stdlib/2and3/xml/__init__.pyi,sha256=BqMXnsXiYPoalMzEakn6mYDxgyW5N2UPF0Ao7xPuGVY,30 +mypy/typeshed/stdlib/2and3/xml/dom/NodeFilter.pyi,sha256=vp2FDwRbJq0-w8LOim2I7Bayvcf-579qKUZ3efaMueU,458 +mypy/typeshed/stdlib/2and3/xml/dom/__init__.pyi,sha256=AYeyX7Iv9WE7I9QHWFt10mBa6xTltK5sLPo5499qIqo,1691 +mypy/typeshed/stdlib/2and3/xml/dom/minidom.pyi,sha256=wI_eu1G8yaaquRHmZ9mYRgjy4zNNhJC385TjSMoamRg,77 +mypy/typeshed/stdlib/2and3/xml/dom/pulldom.pyi,sha256=wI_eu1G8yaaquRHmZ9mYRgjy4zNNhJC385TjSMoamRg,77 +mypy/typeshed/stdlib/2and3/xml/etree/ElementInclude.pyi,sha256=SMvMdOvolo1Zx5RloVzWKykCJsMP3cmpiK1w6y23R-Q,833 +mypy/typeshed/stdlib/2and3/xml/etree/ElementPath.pyi,sha256=dJVKR-ynJ-WwlNzDuKa7pzlwgU80RdBCPsb2b4l8WY8,1603 +mypy/typeshed/stdlib/2and3/xml/etree/ElementTree.pyi,sha256=zj9EP8sGl7NpFUqFp-_1tkWG05CSLqhdNQrSszh89CM,14733 +mypy/typeshed/stdlib/2and3/xml/etree/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/2and3/xml/etree/cElementTree.pyi,sha256=ifHKVHIVZ_xrUmLINR6pD596HPTOoTjRIJ1FxAlDBiQ,99 +mypy/typeshed/stdlib/2and3/xml/parsers/__init__.pyi,sha256=FHZYB9bXDrj4RiKUgrctpkuf7_Rms9PqQrGyjkn0EE4,34 +mypy/typeshed/stdlib/2and3/xml/parsers/expat/__init__.pyi,sha256=qmz8tuPGbZ2rBfRrfYANxDZNxn9BTQXdd9AugF5wDW0,22 +mypy/typeshed/stdlib/2and3/xml/parsers/expat/errors.pyi,sha256=mH9YRZuV4quzksDMLEmxiisAFgNhMOhl8p07ZzlS2XE,29 +mypy/typeshed/stdlib/2and3/xml/parsers/expat/model.pyi,sha256=M7GVdd-AxOh6oGw6zfONEATLMsxAIYW2y9kROXnn-Zg,28 +mypy/typeshed/stdlib/2and3/xml/sax/__init__.pyi,sha256=VU5PGd-iL5mznYU_lOOBPkxiYYq9X9IyMhk7Fj4_TwI,1552 +mypy/typeshed/stdlib/2and3/xml/sax/handler.pyi,sha256=lzRvfmcsC4Px11th3C-OB53OJgrSxHHTkgWKkFnYYII,1391 +mypy/typeshed/stdlib/2and3/xml/sax/saxutils.pyi,sha256=8DHQtoUneXNGFSFKonHXrRiturb45aRk60P-3P9YdyU,2775 +mypy/typeshed/stdlib/2and3/xml/sax/xmlreader.pyi,sha256=fUi7mG_pRgCoD0nq-QSMk6f58dC_IgGQK8DmZIxJFK0,2478 +mypy/typeshed/stdlib/2and3/zipfile.pyi,sha256=sDw9CwxQe8x32fOXfaoWFPrKEp7_gq3THKrdUefgD-8,7040 +mypy/typeshed/stdlib/2and3/zipimport.pyi,sha256=b0SSy7kRZWmILpeCLvhizDY0qUMRE94ypLwIMAi-_Fo,1266 +mypy/typeshed/stdlib/2and3/zlib.pyi,sha256=DQ_VHHmJm58yYvlqFbUY4TON8ijMwppCPhvaf629RdU,1739 +mypy/typeshed/stdlib/3.6/secrets.pyi,sha256=q-xshPkX_1lb3hmaf4PocheAhSPBFo39IaafSr46x1s,501 +mypy/typeshed/stdlib/3.7/contextvars.pyi,sha256=pB3s9rSQNfwqsPqxzsibNl7X0urHvfbXBuP5Cx-3614,1123 +mypy/typeshed/stdlib/3.7/dataclasses.pyi,sha256=qUX_mJDPAvLPEzQHczLg6sgdmiLVjTnHylggXp2cAyo,2462 +mypy/typeshed/stdlib/3.9/zoneinfo/__init__.pyi,sha256=1_T7dB1-Fh1s7f2zNa1QrP9pO_aBHemeaIiJBPQz3Fs,1234 +mypy/typeshed/stdlib/3/_ast.pyi,sha256=bRw9GT-pnP9VvpIEtJevgpve_-srqTVFnuTSdLO2WvE,8371 +mypy/typeshed/stdlib/3/_bootlocale.pyi,sha256=lYGEvIsyEW6g1kpLTzdjDbAMpHZHvigzjnKXVFAwoj0,64 +mypy/typeshed/stdlib/3/_compat_pickle.pyi,sha256=5u-8wo23H6tjqEgFH2D31IgbeE27qDbuTd0QiDUnPbI,436 +mypy/typeshed/stdlib/3/_compression.pyi,sha256=-xFRzAVd4S_frwekEk9VCGlX_dr5zxgW-3OqwBIulYM,445 +mypy/typeshed/stdlib/3/_decimal.pyi,sha256=mo-c1ZFsPlV6aBcfsSp-2n8dj5a9fm-i3tV-eo-IOvk,23 +mypy/typeshed/stdlib/3/_dummy_thread.pyi,sha256=eurqRwuKXCugsXKBB_45dhYwMfGsEOI3JM36MU0_38c,800 +mypy/typeshed/stdlib/3/_imp.pyi,sha256=k-Xgdpet7bnbAGQeIt5zPBLmnaBGP3Nov7bSa9qpMhU,737 +mypy/typeshed/stdlib/3/_importlib_modulespec.pyi,sha256=rwHCcZq_YPTzkGuMT1DmexStrex3EY_21-p3jPEmDVE,1557 +mypy/typeshed/stdlib/3/_json.pyi,sha256=eHGHbRZlkgrYwpRoKPuF-YJpiU7hSllBsE0KbqcCpvg,1112 +mypy/typeshed/stdlib/3/_markupbase.pyi,sha256=_U0_k8QBbLZfh7SWSoKwFzGIcM87JSINbQ8xpc003us,257 +mypy/typeshed/stdlib/3/_operator.pyi,sha256=U8YT6v8bfAwbpc-Y2_EWLHVN1F8Gmi1Fu3ZS1KI8u1g,1347 +mypy/typeshed/stdlib/3/_osx_support.pyi,sha256=jCi4CvI-23xJexNoGxMX1HF-wuJdlVwp0daQ35dwuhk,1792 +mypy/typeshed/stdlib/3/_posixsubprocess.pyi,sha256=MF9OFcdbTVeggcxZAhpgu9es-ABRTTdNl4Vhgh-OySc,600 +mypy/typeshed/stdlib/3/_pydecimal.pyi,sha256=6tL77nizoqxumGGBDkd0xbpoaK18i7anqsG-rUNHMvI,158 +mypy/typeshed/stdlib/3/_stat.pyi,sha256=TN1v47l-n5g6KYdAZEoxisqhqGhPUnMUGACM4M2hOxI,1222 +mypy/typeshed/stdlib/3/_thread.pyi,sha256=EfDgcqQB5dzuAM2GLb-vu6L_EaiJTtXp5QdCtAvB-e4,1337 +mypy/typeshed/stdlib/3/_threading_local.pyi,sha256=OTIwB9dVrg_cmS0Wqf25DOAlo8Vq1b9EIohc7pmjkCE,570 +mypy/typeshed/stdlib/3/_tracemalloc.pyi,sha256=c_1Fr_96JVx5kDJ6X78o9hrfZNCSGCtEB5X-6WCpbOc,609 +mypy/typeshed/stdlib/3/_winapi.pyi,sha256=wEs3gK145zisoAS-JIo_nAV80U_74dmoxVwRjGbPEkY,4408 +mypy/typeshed/stdlib/3/abc.pyi,sha256=nlQT-4gAz5QCKtxIHb2l_N2EinIRNGPD_PNkY94XNW4,613 +mypy/typeshed/stdlib/3/ast.pyi,sha256=q7fwV1zC1qmJVDXyufL1ixkmAcplxEoNIu1LLIdgdgU,9067 +mypy/typeshed/stdlib/3/asyncio/__init__.pyi,sha256=R9g8NPCe8z9FaJiP86vM8a8dKtQB-zCT2WDAatLig-E,4530 +mypy/typeshed/stdlib/3/asyncio/base_events.pyi,sha256=dPgrP8533gjXLptRFNTe9GNpWAWb4frWeFvgigFA_TM,13755 +mypy/typeshed/stdlib/3/asyncio/constants.pyi,sha256=SMXg_0Yr8YefkAJe5TIcqXBU-ckzbQEpnUYLFwkSO04,363 +mypy/typeshed/stdlib/3/asyncio/coroutines.pyi,sha256=sUo7_LdL-0tyiCwTjNjyaPbFRlADqzF389CbTM1nJpk,226 +mypy/typeshed/stdlib/3/asyncio/events.pyi,sha256=Jsemlu73HncsIGcgjEW0Dd2x1LMcZf5ujQsnkWHsN7s,17317 +mypy/typeshed/stdlib/3/asyncio/exceptions.pyi,sha256=dROhdLRjCGhqH7bI3_yUbPBr7aIKBM1Ks_iWi-7HOq0,562 +mypy/typeshed/stdlib/3/asyncio/futures.pyi,sha256=vwNjQGsZ1tGtXxSNiQF9ICBTO3Rcv3Fy1nPwpXxVnWM,2428 +mypy/typeshed/stdlib/3/asyncio/locks.pyi,sha256=QoLx-np8_R8OiUnRljImJK4yY8m0y6t1gAXCnrCaDs4,2677 +mypy/typeshed/stdlib/3/asyncio/proactor_events.pyi,sha256=lO3X3rnZjGWQPYU3Ml2fk5a6WNI6rqGZ5qqWuMkXMdk,2684 +mypy/typeshed/stdlib/3/asyncio/protocols.pyi,sha256=k3kr_lW_uPfNyHvR9UTL5bDMexTryAZ-jp4BnP84nN0,1079 +mypy/typeshed/stdlib/3/asyncio/queues.pyi,sha256=T8MiwNavDf0zpKn7r8Ka47CdsSMOaerxnIVcYt-BVsw,984 +mypy/typeshed/stdlib/3/asyncio/runners.pyi,sha256=F8x4Ck2ExF6a-0x6iVno1JBkvfh56wYQ5eH24jMv9HI,177 +mypy/typeshed/stdlib/3/asyncio/selector_events.pyi,sha256=gmgSsEJDzsEUeI7YFUCnrUqF6YISCRd7fw2cLKTkTe0,392 +mypy/typeshed/stdlib/3/asyncio/streams.pyi,sha256=fVww1IT9zWu67_7bO6GNdFfbR9-lx9etw00O_Oah004,3949 +mypy/typeshed/stdlib/3/asyncio/subprocess.pyi,sha256=eToXmnWfXOBZXnJRkOslohadkYSVWKTiXd-OCc1H_QI,2226 +mypy/typeshed/stdlib/3/asyncio/tasks.pyi,sha256=PIlADphsgdZ4Yj1QecZm6QrebDtAHDjpcSwGL9Lvj4M,6852 +mypy/typeshed/stdlib/3/asyncio/transports.pyi,sha256=SWcEx5fYc2lXq0csxa71J6WIgIAcdkUr2bFdy8fKdps,1943 +mypy/typeshed/stdlib/3/asyncio/unix_events.pyi,sha256=WZzdjJYjfzZWELwpjbIcoKAPxfK_k0p5WbwpNqx0S84,2144 +mypy/typeshed/stdlib/3/asyncio/windows_events.pyi,sha256=fh4B9NNsf89bC0MJzNKbFekmQ1jbY9HXp4E3cborSGE,3272 +mypy/typeshed/stdlib/3/asyncio/windows_utils.pyi,sha256=WqkVC7o0FeJCN-SUzlJcqXxCHMT5A3krM2-QP4jy9s4,680 +mypy/typeshed/stdlib/3/atexit.pyi,sha256=o1Mr2qp3jBDvHFG0uFRVvNoFUKxPA1LdKJ75BAAuMhE,313 +mypy/typeshed/stdlib/3/collections/__init__.pyi,sha256=msreSWW0Bkfl5L2rFv27ncBCJgyjz1zwiXvJkARbKvc,14552 +mypy/typeshed/stdlib/3/collections/abc.pyi,sha256=sOPDwaNtsb9MSOGrPXF8kEXezw292skChTdS84xbBwg,945 +mypy/typeshed/stdlib/3/compileall.pyi,sha256=7x1O8qguaGoNivvjGsgjRwfE9jYelyjygpYd5zIUNZA,2237 +mypy/typeshed/stdlib/3/concurrent/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/3/concurrent/futures/__init__.pyi,sha256=IVt99_QuSJnMo1uDtCJGYVaVFX_KExPEuIJSJD8AV40,627 +mypy/typeshed/stdlib/3/concurrent/futures/_base.pyi,sha256=3FuuWkfizI9ccKTR0lmdufr2acFjsF-7c3fubkETSjw,3994 +mypy/typeshed/stdlib/3/concurrent/futures/process.pyi,sha256=do5VM0TqGKuazjWLdr1zQ4QyhShz1z6K8K4WtVxXHAY,819 +mypy/typeshed/stdlib/3/concurrent/futures/thread.pyi,sha256=-9Rr7NHNi5rqHq3aJ3LIdZHWQ0HAkYsWrAhNpdzOJq4,1162 +mypy/typeshed/stdlib/3/configparser.pyi,sha256=CGEvfUUctn44yqSyuzDjc4zm-VNlvyHKwHOAfik_cwE,8690 +mypy/typeshed/stdlib/3/copyreg.pyi,sha256=BsqFQ_hSsV_oqeJFO_GZ2J1tFl4EpnGZgx-NYmt_ZN0,726 +mypy/typeshed/stdlib/3/dbm/__init__.pyi,sha256=3XJoWz6dQlI04-rFHKeWwHBijlUlDzPmZBOOg-BdKYM,272 +mypy/typeshed/stdlib/3/dbm/dumb.pyi,sha256=gBv0VqUbLPqusL7fkOaDrpsBgVYIdmcG3M5mGfmJ5bw,1116 +mypy/typeshed/stdlib/3/dbm/gnu.pyi,sha256=aIkN5L-ZAgrulXZNEzmGB11WSl-6iTCpsMRuxdxRmLI,1371 +mypy/typeshed/stdlib/3/dbm/ndbm.pyi,sha256=0h_ojQrlFSsSUwRIuzGW52euAbImP92U_JTlMB8L2f0,1245 +mypy/typeshed/stdlib/3/email/__init__.pyi,sha256=Xo_lp7ixhhAwFvtgnPEXPmIERZ3op3Ti0uof--_6oOY,789 +mypy/typeshed/stdlib/3/email/charset.pyi,sha256=7xr1qNw_tZCNKyXcqQUlI7pB4rPJBb_OmvNEpFcXSQc,1156 +mypy/typeshed/stdlib/3/email/contentmanager.pyi,sha256=M_3Fikh96bTv0zlSHxWBd4okSCHLBiC1tGWbIZ0vINQ,580 +mypy/typeshed/stdlib/3/email/encoders.pyi,sha256=H9sVxzOu1oJhhXXaJKeQ7xKLhdGhpLhpfGS5q9oYG9g,255 +mypy/typeshed/stdlib/3/email/errors.pyi,sha256=j8OUen6c7Kd8vpaEHy5i4h9BHaXnWBziRqkUd0JamEg,873 +mypy/typeshed/stdlib/3/email/feedparser.pyi,sha256=IVbXnZjO63KWCM4dT6N8eIYQv6ZOM_zsEXHDUC5CJXE,574 +mypy/typeshed/stdlib/3/email/generator.pyi,sha256=8cWDdVOlgsCeEFXEugyfFhe0fcjjdKYt3yQMVgYrGOA,1126 +mypy/typeshed/stdlib/3/email/header.pyi,sha256=hhVBaR7C9X37lLczfVP_s92NRmyfS43RZi4vrmx6uWU,1143 +mypy/typeshed/stdlib/3/email/headerregistry.pyi,sha256=m0uAXcR22FBoB3u4WBnK5BUHTf4EIyOeUUwNY-kLpJY,2977 +mypy/typeshed/stdlib/3/email/iterators.pyi,sha256=lMAAWZXQdBXMcDNa491poQk8gr7RGK8xC-juMvSl93M,335 +mypy/typeshed/stdlib/3/email/message.pyi,sha256=eylsIb9ejdVYVxcSm101ntyLqDH4uIyKMdnhLNZ-J4w,5084 +mypy/typeshed/stdlib/3/email/mime/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/3/email/mime/application.pyi,sha256=VnDWXSLASX2YvwVf_4Qh2H7nbRioCwwtXBk8z2TwJYw,873 +mypy/typeshed/stdlib/3/email/mime/audio.pyi,sha256=KmLoCpBArEF5A-RVs2naNCQl6XpjSRbJHGMSzMZVTX4,879 +mypy/typeshed/stdlib/3/email/mime/base.pyi,sha256=MjlIf3p_QSZd0S0XZXZj8KGhnVzciXCIIfdPjawD_xU,522 +mypy/typeshed/stdlib/3/email/mime/image.pyi,sha256=mmVYpPWqhQWt7bDRb8_u4xSn03b217neLxbPvL2rgWA,879 +mypy/typeshed/stdlib/3/email/mime/message.pyi,sha256=T8NunjNBHMjIhspW_Jl0AimoP7e4JMGzV1FX1uH1UmU,473 +mypy/typeshed/stdlib/3/email/mime/multipart.pyi,sha256=fEAsaP4O1Z67rB--FVgw6Uc0EDMGhYIWHhRNe4HNLzY,879 +mypy/typeshed/stdlib/3/email/mime/nonmultipart.pyi,sha256=mov35SsLNY80sOlSPdEne6qbL7ZXLMHIRYqd16hVJ_Q,126 +mypy/typeshed/stdlib/3/email/mime/text.pyi,sha256=3W6Zn-EfYAjsKemdUP67nrg3TDKzZtfTg2cYCkTVoTE,511 +mypy/typeshed/stdlib/3/email/parser.pyi,sha256=XfKs52r2VQm4rX00u-Xc_6EDGI27hDjsHvvMdqQTbus,1435 +mypy/typeshed/stdlib/3/email/policy.pyi,sha256=UKQ2m1qZGCREgJDqSgGtjW4zZOa29j3R-CoVKnreG3o,2316 +mypy/typeshed/stdlib/3/email/utils.pyi,sha256=IFnz0Y7AFu7d4OAjBs6z8sQKez1hpDtJv1c5ZLdxUIc,1630 +mypy/typeshed/stdlib/3/encodings/__init__.pyi,sha256=_RWeuK-suSwb18aIsN6VdIl2hixs-jYJPRdinPdejFk,185 +mypy/typeshed/stdlib/3/encodings/utf_8.pyi,sha256=tgCdNX8etJQWYWmOYAIZhK8lcYm_Kn67kylKJp0SgUo,573 +mypy/typeshed/stdlib/3/enum.pyi,sha256=XfR_R8MKBIaJWSF_3yL5xvM_ALBsqaC_t0h2V307f3w,2890 +mypy/typeshed/stdlib/3/faulthandler.pyi,sha256=pK-Ffg5tIK9ibbxWXAlRAaVwQfiem0A2w9HaZCrLFLk,685 +mypy/typeshed/stdlib/3/fcntl.pyi,sha256=SpQ0kaJ8kzdDaurjwgbfj8zf5TTVaLV8tLFd2ErKRog,2434 +mypy/typeshed/stdlib/3/fnmatch.pyi,sha256=Ln-5P7VzP4o9hsxGqoj46sUM53RTiMeC_CNP2lVTf_I,366 +mypy/typeshed/stdlib/3/functools.pyi,sha256=igZMtZiFQOcw3rCOgM-SSMu7ZnXAeunl9Ky5SxcfgwY,4638 +mypy/typeshed/stdlib/3/gc.pyi,sha256=RuqiB7rLguS1EMfgCO87lwbLWvbVkUW5Lwjt7iyfmek,955 +mypy/typeshed/stdlib/3/getopt.pyi,sha256=AcIuaBf6F9jiBKpgm1bDOqC1jZamW-ylbcTOKU3VZyQ,431 +mypy/typeshed/stdlib/3/getpass.pyi,sha256=s81upYZ38jmRD5q6dCSCCupnROWOT0VWEnwDdwj57S8,203 +mypy/typeshed/stdlib/3/gettext.pyi,sha256=JnFLBgV-on1ucRc6a-i4LxpderPJFIXy5X6KP9CZP1Q,3206 +mypy/typeshed/stdlib/3/glob.pyi,sha256=pnwHkg2RH5a_zHEKSMOc7vQf0tP3SD-8uO6z0ELg5BU,640 +mypy/typeshed/stdlib/3/gzip.pyi,sha256=AN9zrmfKdt_J6oXOe5j2mxkT0pUEtamkFUfl-LulhrQ,2052 +mypy/typeshed/stdlib/3/hashlib.pyi,sha256=MWTjyaubCg4PGwjrwN7WYposBe3Xxz0kDqHrXhpyzoA,3790 +mypy/typeshed/stdlib/3/heapq.pyi,sha256=Tsiv0VHLhvJ5DEdVKdafRVr5K-mRuTFVb_GH_Qf5Aow,776 +mypy/typeshed/stdlib/3/html/__init__.pyi,sha256=qKsbjN2OJn_AoUr9a4zdFC8juUG9ii6rqYp3EQTSG-Q,122 +mypy/typeshed/stdlib/3/html/entities.pyi,sha256=ap6jI6Fw355WC0vSd-WGc957p_KpAJDGONUeAlItYzI,136 +mypy/typeshed/stdlib/3/html/parser.pyi,sha256=TdQPkBuvp-Fh_Yy6iU8Urzh3HOD8vh6kZWit6ESBW-o,1036 +mypy/typeshed/stdlib/3/http/__init__.pyi,sha256=c0my7SsnnPaa_hag_DcalGUFH-zjZb-pL_pxCIyfeVk,2012 +mypy/typeshed/stdlib/3/http/client.pyi,sha256=y3bK3ynTwvbMz0zYsRGtGgE7qGrv4mKlw1N8a1nGfps,6309 +mypy/typeshed/stdlib/3/http/cookiejar.pyi,sha256=i3aBSwndDm3qmSMR2YBEM-g3onqRqOlKgfK0H4FxaQ8,5176 +mypy/typeshed/stdlib/3/http/cookies.pyi,sha256=jVfZRuhvKgYTJXRUph2fhtvUtcXPGQ9HNSN0Mx7IlHI,1433 +mypy/typeshed/stdlib/3/http/server.pyi,sha256=BvGjOrkkhk2dO-X3gRYZijpj24QHfiuLlPCQ3eVsR1A,3171 +mypy/typeshed/stdlib/3/imp.pyi,sha256=afomvRTfKCmVYpgaXPDmlU9VpL3cykp9RfUzA3V3F98,2138 +mypy/typeshed/stdlib/3/importlib/__init__.pyi,sha256=pBPYg6Efnw7acEBh85gu8hHTewc65QfQeXPPPJhthL8,597 +mypy/typeshed/stdlib/3/importlib/abc.pyi,sha256=XCoHncv6qlrF2Egmw9--dstAwdu9gr9mBNrnq9OShlI,3522 +mypy/typeshed/stdlib/3/importlib/machinery.pyi,sha256=i2VouKwa_r0umqnwxYjOYspO47C5KhOFwvRB4gUT0YE,4345 +mypy/typeshed/stdlib/3/importlib/metadata.pyi,sha256=e-uCY4Q7Su-dTeeUl-sGUF9F7-70Vd2hf_CQ2Y0IT9k,3786 +mypy/typeshed/stdlib/3/importlib/resources.pyi,sha256=i5PzvUdz_keDjFVGCv87VASWmPm5_tHPy1hx3xin3jQ,1009 +mypy/typeshed/stdlib/3/importlib/util.pyi,sha256=GIWsvb7GYbQCEQIOhyfW11vtKQyeGFIFDq-M-l1UL-s,1871 +mypy/typeshed/stdlib/3/inspect.pyi,sha256=dM6MOz9HFjSQzOEE9VgQcJZBy0vYFRvyssdmEUqBui0,10095 +mypy/typeshed/stdlib/3/io.pyi,sha256=QFAOndBXzmA4Uu4-D-GBVtKzC01HeMXvjpkei7XmG0I,9204 +mypy/typeshed/stdlib/3/ipaddress.pyi,sha256=QXCOikptZCBy6a8TyksRdieXbjucjJyonLDldI2RWeI,5280 +mypy/typeshed/stdlib/3/itertools.pyi,sha256=nvmrhZDujPmvQv5Im-2XEpFE0ljTvEWuq-G9VmxIve4,4490 +mypy/typeshed/stdlib/3/json/__init__.pyi,sha256=9XKlq4tbPYCKl9wUrEubz7tNF9o1hKGzXTR3QE_rzQg,2259 +mypy/typeshed/stdlib/3/json/decoder.pyi,sha256=-plBprOxA3M6zU58UzEdJ6Qeu-7CwXX3MdeZ2ax3Tco,1634 +mypy/typeshed/stdlib/3/json/encoder.pyi,sha256=lSVKtZs1AZL_kmFMae-l35GEbeLxUCh07jr295nhuIA,1283 +mypy/typeshed/stdlib/3/lzma.pyi,sha256=VJ0RWmhVqpUUGFYli4I4IlYjQVL7GDzKSo2OLMKk8Wk,3273 +mypy/typeshed/stdlib/3/macurl2path.pyi,sha256=_y9VTKhbZ4X8-k_HwedDP__Oeo0C_1nMOs9MFpIZd6U,227 +mypy/typeshed/stdlib/3/multiprocessing/__init__.pyi,sha256=wM5f7YoZTFPIYpSH8SbhrIo7VAOY1-8RhZtA7MDgfMM,4385 +mypy/typeshed/stdlib/3/multiprocessing/connection.pyi,sha256=tezMsdHbsHK5muoAnfzjb6cAQsO9K62W7OERlHS75qI,2612 +mypy/typeshed/stdlib/3/multiprocessing/context.pyi,sha256=rq1_xqQv13KZXB2k6P_e3Kcgh_jj0R1C6Pctu5zsIr8,7163 +mypy/typeshed/stdlib/3/multiprocessing/dummy/__init__.pyi,sha256=p1cuOM_HB1QqijgTdT0hSfgR5CYc1MzBXmJ3nVs1Nik,1165 +mypy/typeshed/stdlib/3/multiprocessing/dummy/connection.pyi,sha256=QS9PgiQv0pJnI7nwIDdgyN62Ee_Ls3C7aVOQcjsN_RY,1097 +mypy/typeshed/stdlib/3/multiprocessing/managers.pyi,sha256=qOZnYPmi2eW1CzaJqZAJ0ycoUeB3Kdo54nCFjbj6EzY,4470 +mypy/typeshed/stdlib/3/multiprocessing/pool.pyi,sha256=Pn61xU1MG9Oh0nQ0kUH6iNE_23ygvYDGD4Pw8rHY_4g,3452 +mypy/typeshed/stdlib/3/multiprocessing/process.pyi,sha256=xgr63P0b4blFVTbP7ykriwyobBorYk9Ityc-CEKMvTY,1142 +mypy/typeshed/stdlib/3/multiprocessing/queues.pyi,sha256=52WIBRL6l01X-T1AwIwNXOkccN7EhfV2AVtCiWStXPw,1109 +mypy/typeshed/stdlib/3/multiprocessing/shared_memory.pyi,sha256=fCHuNppwEErwyGziuVwur1MuwLMwizkmWOx4Pk9HvPQ,1121 +mypy/typeshed/stdlib/3/multiprocessing/spawn.pyi,sha256=uy0-49duOwkv58ijeWCk1s36EgljQIuqvOdYlnnHHZ8,687 +mypy/typeshed/stdlib/3/multiprocessing/synchronize.pyi,sha256=YOlndD_kan5uhROrJL0mpAO4Dt96VDazKVSIYmQstIg,2072 +mypy/typeshed/stdlib/3/nntplib.pyi,sha256=VUK-TJtwRFk8DNr193mFTOyY6gAOAURzmXL2nui23nk,4285 +mypy/typeshed/stdlib/3/nturl2path.pyi,sha256=E4_g6cF1KbaY3WxuH-K0-fdoY_Awea4D2Q0hQCFf3pQ,76 +mypy/typeshed/stdlib/3/os/__init__.pyi,sha256=0voIa1kqL_qDa100u2t5p4r1InuJixV5ToIs9EOa0Gw,27290 +mypy/typeshed/stdlib/3/os/path.pyi,sha256=PmZPAETp5VbtmxCto9QouEvVLuRtXgU6JgL1-hoAQtE,6092 +mypy/typeshed/stdlib/3/pathlib.pyi,sha256=lYZvp2k1HmYT5TvhQkNV8wEQavqCYEtVzwfqY8A_9vs,5888 +mypy/typeshed/stdlib/3/pipes.pyi,sha256=D1sF3sIscYyvbhc_PKpM2WvIrmtc7L-MefgDHoNlmlI,595 +mypy/typeshed/stdlib/3/platform.pyi,sha256=qqSoc0KokU2aPHETPp0ALZnN-Tv5BXr0At407T9Izhs,2180 +mypy/typeshed/stdlib/3/posix.pyi,sha256=RE2b2rBLm46j8jnXKuHGXFV5ychUMCh30gF8HKCw07c,2234 +mypy/typeshed/stdlib/3/queue.pyi,sha256=ulBHkdUldVz6jTeHIuSD5evBFj7Bqrap1q1z-2xYXmY,1656 +mypy/typeshed/stdlib/3/random.pyi,sha256=xUt2tUMJ8VZoOiIxFUi4rXzb2ksjgiNRRa9tXKDeBiQ,3849 +mypy/typeshed/stdlib/3/re.pyi,sha256=M0wH3pu3JlJhNA3U7F79oc3QOS9g3DqofGFSQmZEzos,5127 +mypy/typeshed/stdlib/3/reprlib.pyi,sha256=pbEZSwWDo29vTb6s1dLTOp44KDzj45f9wvfyDNAyDb0,1259 +mypy/typeshed/stdlib/3/resource.pyi,sha256=RgU4m0mHN_sdRuSjluGrYoyCpPr6gmNvt3lAKiD9A6s,1181 +mypy/typeshed/stdlib/3/runpy.pyi,sha256=JeImZ6lLwXaVkjIHS1DbD_kUk1edxu4hNAUfxeRN5Tw,694 +mypy/typeshed/stdlib/3/selectors.pyi,sha256=0k7ZsloGvR6hv13WIq7g7XqvpdqIt8eUJuhGXmvMEUg,3728 +mypy/typeshed/stdlib/3/shelve.pyi,sha256=36Bo_Ohg-kQnwI6Ysd3D_T1Tc_5AKgEvRkGiK3iPv5U,1578 +mypy/typeshed/stdlib/3/shlex.pyi,sha256=G2SVpArVj8eOkdcbH2ah6CBG30wArYN6ZAsoqC_4INk,1552 +mypy/typeshed/stdlib/3/signal.pyi,sha256=QIpwHLQ5kBjZHzCLosdy8X2IcriO9thyCAUMp5c_ijk,5124 +mypy/typeshed/stdlib/3/smtplib.pyi,sha256=UPifdCgI7NhD-OK9nRkrVreWUXQjywLzclc9nQFEg0E,5604 +mypy/typeshed/stdlib/3/socketserver.pyi,sha256=_QGoTdWUx_MBUg8wbbMy92_CxwP9-yvNlfkmMhfg6Bk,5557 +mypy/typeshed/stdlib/3/spwd.pyi,sha256=aAmkS56-90q7hfKMkpAmUifbEQy32e2c-gW_KVHTEn8,310 +mypy/typeshed/stdlib/3/sre_constants.pyi,sha256=2u_vRIwIqqM6Thr2BnFNCE2oLwZCFOiGzu5538-acm8,3427 +mypy/typeshed/stdlib/3/sre_parse.pyi,sha256=pLlqkegrzl1Lp7nVEZhPdp06t0hAQZ6F33o1_XSPhvw,3667 +mypy/typeshed/stdlib/3/stat.pyi,sha256=gF7bA3x50cH0bspmkUah1KqlXvWddcS_SBKCKCszaHk,1885 +mypy/typeshed/stdlib/3/statistics.pyi,sha256=tih7lIaJZ3xxpIHgmXRyZSf1lWSUnI9OXtQ64n2odDw,3208 +mypy/typeshed/stdlib/3/string.pyi,sha256=_MsfC2ua7UEvTAmRaPXC4fOrioxOjM4jK-1KRXaR1Pg,1587 +mypy/typeshed/stdlib/3/subprocess.pyi,sha256=Y9DvuHVfDtzh7NCcs8JrPfNnsuzj4HkHbh0sgI1zK8Y,46682 +mypy/typeshed/stdlib/3/symbol.pyi,sha256=8qlz7ijaYuwRgx7Thyobse_R0jHdXp3H1V3yLpplQmk,1460 +mypy/typeshed/stdlib/3/sys.pyi,sha256=UfUk_smb3AV2rNFB_6YJVikT_Fc98UwxGESvcTx6I6I,5962 +mypy/typeshed/stdlib/3/tempfile.pyi,sha256=aNNEXNZz8rX903Z4pRepoLtulbgeRD1ixs8VR9eyyRI,11105 +mypy/typeshed/stdlib/3/textwrap.pyi,sha256=LimdjG2Bqwgs2v8-IC9O-H_MFJIseiVz5wvQIPMHRwU,3485 +mypy/typeshed/stdlib/3/tkinter/__init__.pyi,sha256=82sifJM1WoBVzuIR4BqI81FnoCqxedHkZ1d2RD3V7t8,25886 +mypy/typeshed/stdlib/3/tkinter/commondialog.pyi,sha256=GXUxL-Y2G2Y3DgfMNMNpCUzuRnZ746Iij-R56ZXCu6E,277 +mypy/typeshed/stdlib/3/tkinter/constants.pyi,sha256=nEpwKcTYIZWguP1vAzLXfcrUnG6IbCKrUdu3C08JWB8,880 +mypy/typeshed/stdlib/3/tkinter/dialog.pyi,sha256=nfHISRyWWZ1vA7sHLW1AjOPeTMq_H09SXOnf7ryWB14,291 +mypy/typeshed/stdlib/3/tkinter/filedialog.pyi,sha256=6_6Zuq-pC24IdnGatIyf1Kyu_bu6a5myFeTe_1h_a7U,2233 +mypy/typeshed/stdlib/3/tkinter/messagebox.pyi,sha256=Q0-rK5wXBbbzvx4Mpf92dITPgL7Lwjw8t4CLfpYV0hw,1150 +mypy/typeshed/stdlib/3/tkinter/ttk.pyi,sha256=AOZj8wd3NyxKg6t6raQbqWC-zSiz5mTJlWNOdBAXIy0,6355 +mypy/typeshed/stdlib/3/tokenize.pyi,sha256=JLrj996vKnHq3GCr2-xx4VldHd-WgF5Lqv13AWpAwDg,3329 +mypy/typeshed/stdlib/3/tracemalloc.pyi,sha256=L1XS34EDDwssrPzyFk_CAIC4bwfpZLo22PQQRXeRBFk,3410 +mypy/typeshed/stdlib/3/types.pyi,sha256=AEhYQPAqSqM2OQUd3KEh1lniBbKdnVOhgLJxlUkBF1Q,10093 +mypy/typeshed/stdlib/3/typing.pyi,sha256=_M0vW76gzZWNccplCTdXuK6tZ4Ti1HRTLIxBFrMmUR8,23899 +mypy/typeshed/stdlib/3/unittest/__init__.pyi,sha256=Q2I8iuTG1dCbBxGAjtV_xsfbB1de3NolMniKCvO3XZE,1057 +mypy/typeshed/stdlib/3/unittest/async_case.pyi,sha256=q_NoN53bOPfBS4wDcA6nwqXRQ8L-wjT9N4l5yPul7Js,371 +mypy/typeshed/stdlib/3/unittest/case.pyi,sha256=vuVSyqgnaRjocml9oFgtJnpccBS6gXtOfnyjQEk6Pv4,13078 +mypy/typeshed/stdlib/3/unittest/loader.pyi,sha256=VuSbtNEBaVKStX15-B3W5T9OelHno_DEudNC7AFNYVc,1222 +mypy/typeshed/stdlib/3/unittest/mock.pyi,sha256=HqQLTaHo-_Gl6YAMouW9oDA6JGt3qqXDL8PaVMBbrw4,7893 +mypy/typeshed/stdlib/3/unittest/result.pyi,sha256=sGOubAZ38sYmpFsONaY9WrRzi19Ovi37jIPKuzkJd_w,1711 +mypy/typeshed/stdlib/3/unittest/runner.pyi,sha256=D5NxBq9pBflD7rsLqQohp4EPD1Q6HmHssBchk9LGc5M,1349 +mypy/typeshed/stdlib/3/unittest/signals.pyi,sha256=A3-SvVwavp_iZRc3Ibiegd6ZmvnfkpEigGIRkbdc07E,388 +mypy/typeshed/stdlib/3/unittest/suite.pyi,sha256=--mzq9jrdkyd_GIvh9-lxkUlpXuq-U0GtDYx77mRcP4,791 +mypy/typeshed/stdlib/3/unittest/util.pyi,sha256=Uq5zG5zmTjLxd9A9j3BKX5K08z28VtNVNMmPOoAKbyE,921 +mypy/typeshed/stdlib/3/urllib/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/3/urllib/error.pyi,sha256=w9_xafGchG3KKvyc-SiPw5OGX9u7YWPInY35h0f_8wg,317 +mypy/typeshed/stdlib/3/urllib/parse.pyi,sha256=XaBDTZfsElBgSi6noejEj1WgJVB9_jn4m9Iy4pZ0hoc,5307 +mypy/typeshed/stdlib/3/urllib/request.pyi,sha256=MG5KAs3dRrqwLnf3NZ_j-Af9OIBSSTyiNPQwpHBJjRo,9998 +mypy/typeshed/stdlib/3/urllib/response.pyi,sha256=n2tffJxxDD2I84lj69TBozAnUCq5FhDO7gdibbZR5VU,1682 +mypy/typeshed/stdlib/3/urllib/robotparser.pyi,sha256=SPqL0fFUUXQg03pW-shC8QEaBdAcgsfXL-_f4pCg9Ek,792 +mypy/typeshed/stdlib/3/venv/__init__.pyi,sha256=O4peb__yK8u_4txUAaYgOa2XWdPmDDkX5IQmc3q8D_s,2692 +mypy/typeshed/stdlib/3/xmlrpc/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/stdlib/3/xmlrpc/client.pyi,sha256=gpKsAiVZdqSzwrHtyp4fmbwFM6_eu_lJHfeDa0iO5NM,11998 +mypy/typeshed/stdlib/3/xmlrpc/server.pyi,sha256=jgnSVg1MmGF47TLHF66XVui-_rL9ZvxKX1vN-M_u6h4,5557 +mypy/typeshed/stdlib/3/zipapp.pyi,sha256=t0yhNzeCGDPLUfpXlH3i6cIAFmBt-T1MJXuFddiJs6w,664 +mypy/typeshed/tests/__pycache__/check_consistent.cpython-39.pyc,, +mypy/typeshed/tests/__pycache__/mypy_selftest.cpython-39.pyc,, +mypy/typeshed/tests/__pycache__/mypy_test.cpython-39.pyc,, +mypy/typeshed/tests/__pycache__/pytype_test.cpython-39.pyc,, +mypy/typeshed/tests/__pycache__/stubtest_test.cpython-39.pyc,, +mypy/typeshed/tests/check_consistent.py,sha256=wYihSzbqq-G2nV10fbeRzbDokEgzuWt2Ua7lJ0pih-Q,2570 +mypy/typeshed/tests/mypy_selftest.py,sha256=12O7OptTZKmltMj_K5OhOl2iephDyPAaGTXPf1oyjFo,1196 +mypy/typeshed/tests/mypy_test.py,sha256=ruBUtg9itU8sC0_Rz4zXA8XVMYplevkt9UViKxD1V54,5822 +mypy/typeshed/tests/pytype_test.py,sha256=mNo9P3pE5i5Zb65U9QH3I6im9OyUfG7F1XdOaXWkQZs,7993 +mypy/typeshed/tests/stubtest_test.py,sha256=1CA-voHdANpuGqXv25Wat6Mg-iQKKyh3QJAgMIv2SIE,2526 +mypy/typeshed/third_party/2/OpenSSL/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2/OpenSSL/crypto.pyi,sha256=ap-fqiGpCMjTyMMQQW9tKQ7QmTEK38_mr1urwX4T0Zs,7644 +mypy/typeshed/third_party/2/concurrent/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2/concurrent/futures/__init__.pyi,sha256=IVt99_QuSJnMo1uDtCJGYVaVFX_KExPEuIJSJD8AV40,627 +mypy/typeshed/third_party/2/concurrent/futures/_base.pyi,sha256=3FuuWkfizI9ccKTR0lmdufr2acFjsF-7c3fubkETSjw,3994 +mypy/typeshed/third_party/2/concurrent/futures/process.pyi,sha256=do5VM0TqGKuazjWLdr1zQ4QyhShz1z6K8K4WtVxXHAY,819 +mypy/typeshed/third_party/2/concurrent/futures/thread.pyi,sha256=-9Rr7NHNi5rqHq3aJ3LIdZHWQ0HAkYsWrAhNpdzOJq4,1162 +mypy/typeshed/third_party/2/enum.pyi,sha256=XfR_R8MKBIaJWSF_3yL5xvM_ALBsqaC_t0h2V307f3w,2890 +mypy/typeshed/third_party/2/fb303/FacebookService.pyi,sha256=F2XAcOQaQfY25ZBQBzLUf9zbcKMZx4Tk2Guz3QeOOVg,8691 +mypy/typeshed/third_party/2/fb303/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2/ipaddress.pyi,sha256=QXCOikptZCBy6a8TyksRdieXbjucjJyonLDldI2RWeI,5280 +mypy/typeshed/third_party/2/kazoo/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2/kazoo/client.pyi,sha256=Y1V3wfUp0eiTP3zQ0B-pEahZas9lqUBODu9IYjlVtWM,3310 +mypy/typeshed/third_party/2/kazoo/exceptions.pyi,sha256=7DhQ3xMt63lVinoWQv0vwI6VmG2IfNPlMpLRGu_gq-s,2054 +mypy/typeshed/third_party/2/kazoo/recipe/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2/kazoo/recipe/watchers.pyi,sha256=Pxdwrx10R_orsLVINsoCsy-TL6a96EumRsENf2G11BE,551 +mypy/typeshed/third_party/2/pathlib2.pyi,sha256=lYZvp2k1HmYT5TvhQkNV8wEQavqCYEtVzwfqY8A_9vs,5888 +mypy/typeshed/third_party/2/pymssql.pyi,sha256=WhikYOS5kK7POYcelOOkDMaLZLEMQOLB2yZZtZ43xfw,1876 +mypy/typeshed/third_party/2/routes/__init__.pyi,sha256=G9OldbNFqOLKbDGv0kLJQGDpmWkeXtacGmA5pT7lRpk,377 +mypy/typeshed/third_party/2/routes/mapper.pyi,sha256=YFVazTh_FfeitJBAncVwWzDN25Vj8i6U85r_rTL-8fE,2294 +mypy/typeshed/third_party/2/routes/util.pyi,sha256=U9AvEa_p8Q1eq1zmIMKpGMjYqFbd9YSvTbv7W1Ez49Y,576 +mypy/typeshed/third_party/2/scribe/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2/scribe/scribe.pyi,sha256=XWXeARcek8qxl0QIw0UcuFE3Tba-cr8bvruheKR_tpI,1215 +mypy/typeshed/third_party/2/scribe/ttypes.pyi,sha256=Ub8_sHFFbDuMouo-wUU4bkr-WhUpSOVLBJ6zb9amqBs,383 +mypy/typeshed/third_party/2/six/__init__.pyi,sha256=hNdSkpZ2EP70_9-tmJXY4Eep1bao2jWoPgN45pInx-4,4371 +mypy/typeshed/third_party/2/six/moves/BaseHTTPServer.pyi,sha256=tGipj5ccgHt3EnzbxpPyQGUVnvu7RltrUOqgqWNGwpw,29 +mypy/typeshed/third_party/2/six/moves/CGIHTTPServer.pyi,sha256=omAocPqXteLJkGtdobdZjdzXynzCtn0jCFwBBlc3LUc,28 +mypy/typeshed/third_party/2/six/moves/SimpleHTTPServer.pyi,sha256=nC0fjp9wrhSnJMI8N2QD7ovWp1CW-dJWLyaV4K_Ql54,31 +mypy/typeshed/third_party/2/six/moves/__init__.pyi,sha256=VCGQ9wX9M4r3KqOwBRwGJgC3Xs2MZr_Al32oZyepLdI,2383 +mypy/typeshed/third_party/2/six/moves/_dummy_thread.pyi,sha256=Va4LPdV5kK4luB-1NlkmycnVpXD4kKeYFD5QmmNqE8U,27 +mypy/typeshed/third_party/2/six/moves/_thread.pyi,sha256=9194lgQXs2W3sR00kP7Zn9gx9WWl0C49GEsbvzshDy0,21 +mypy/typeshed/third_party/2/six/moves/cPickle.pyi,sha256=hS7yIew9WYdHI_b6XwIlHAfRFRpUTKj7IokSZcpJ4PY,22 +mypy/typeshed/third_party/2/six/moves/collections_abc.pyi,sha256=Fcq1sut9OLQ824MQ69luYDJSzEB0LroJqTsXWgWGcDo,26 +mypy/typeshed/third_party/2/six/moves/configparser.pyi,sha256=r3G3JXE9Yo34AASn9AoNcielq9KuyQ3xrtElpnhRJYc,27 +mypy/typeshed/third_party/2/six/moves/email_mime_base.pyi,sha256=WcWEleCKHROrfdXpRuKABrT_Va1hx90NY_kxYeul3Sk,30 +mypy/typeshed/third_party/2/six/moves/email_mime_multipart.pyi,sha256=HRKWFU9qh95-mEE22_2NzEKL6lx7ynvhcfHjUcYWuZ8,35 +mypy/typeshed/third_party/2/six/moves/email_mime_nonmultipart.pyi,sha256=n5hD7R_rktJj3hiHYzEqr3CJCHSW4ikfObKHmUrXBw0,38 +mypy/typeshed/third_party/2/six/moves/email_mime_text.pyi,sha256=55VzBSQimrZf6UgotoXMiJDvqbKXly6-E_IXo6Ix22c,29 +mypy/typeshed/third_party/2/six/moves/html_entities.pyi,sha256=I0BI00vvC21L_BgnCbpjio-s1jqF4ARTt-qaol7mGig,29 +mypy/typeshed/third_party/2/six/moves/html_parser.pyi,sha256=hivJeBkqiAIZ6mvO1v4tOC9Mg6MzMR08P9tzsODdul4,25 +mypy/typeshed/third_party/2/six/moves/http_client.pyi,sha256=P8tgtt5Icp-ksHij6yPb_zuKk7ckcAHt_HM3aO0WrSM,22 +mypy/typeshed/third_party/2/six/moves/http_cookiejar.pyi,sha256=HUlF3MydQRX2Vv5G6KtN_Q6iCS48LBDggoDuPbEQUCc,24 +mypy/typeshed/third_party/2/six/moves/http_cookies.pyi,sha256=itzb5D5Mp66bx7hjyI3u-hri4h9jgqVzZyMfz4xNu2k,21 +mypy/typeshed/third_party/2/six/moves/queue.pyi,sha256=6Llng-UlZW_9HSWFgmIgW2q9YhaZ-Nzh2zJ8hkqoaZA,20 +mypy/typeshed/third_party/2/six/moves/reprlib.pyi,sha256=SWZYhGRU6moFAVBo5dUFUB9kyY6TO_kgrIqxzqDQ3C0,19 +mypy/typeshed/third_party/2/six/moves/socketserver.pyi,sha256=oeRnmecMYQfMmwRFVydatyCfs_HLrJYZvf5p7nm_ryE,27 +mypy/typeshed/third_party/2/six/moves/urllib/__init__.pyi,sha256=F_1V8NcR4jGkws85IUurYLi4JnGh7_HttdVHvj8cQZM,217 +mypy/typeshed/third_party/2/six/moves/urllib/error.pyi,sha256=zssV6Test1CzUPpuq9yzsf9pndbhrb2eC1aqNSbY1_8,148 +mypy/typeshed/third_party/2/six/moves/urllib/parse.pyi,sha256=FAlhSmh83GfQAKThmNAFCDYv_X5F9Az6uXToaAKAj3o,1102 +mypy/typeshed/third_party/2/six/moves/urllib/request.pyi,sha256=EmFJ7eWBbRlgAsm7HaKSZxX55lpoo5ozOFVjEfI0Xos,1960 +mypy/typeshed/third_party/2/six/moves/urllib/response.pyi,sha256=vlC9X8P4ry421TmzI06mdtx5vGDxEyFfbpXp3R6IblE,206 +mypy/typeshed/third_party/2/six/moves/urllib/robotparser.pyi,sha256=C8_E9lApZyMQpHflnHpYeyAgvQ_vFSuKon9Gl5DM3Q0,59 +mypy/typeshed/third_party/2/six/moves/urllib_error.pyi,sha256=7RTGNFpeUX5KEap9vyjA1Xc3Twfkut431Nu5290po1U,28 +mypy/typeshed/third_party/2/six/moves/urllib_parse.pyi,sha256=Q3BVGITL1UwlTmBsFD9iLf2pggJgTE5bG32QANdkMvo,28 +mypy/typeshed/third_party/2/six/moves/urllib_request.pyi,sha256=8WFe7ycArSuM6wJfgcXWLDRKNsymd0UlxWlflszb2yk,30 +mypy/typeshed/third_party/2/six/moves/urllib_response.pyi,sha256=dokFMleMVEVFVxBgSkrcn4f4yM7RhR3zkk0iDQGOC_U,31 +mypy/typeshed/third_party/2/six/moves/urllib_robotparser.pyi,sha256=8c26GW8MTI6cxDTD65N_18NRQcqWY4P9v8mrQm8c-oI,26 +mypy/typeshed/third_party/2/six/moves/xmlrpc_client.pyi,sha256=hL_FNiBles8aoJq0XQLbEHvWX1AedYbQopgRVQlbCEI,24 +mypy/typeshed/third_party/2and3/Crypto/Cipher/AES.pyi,sha256=iCmveVmaj7qRIKsyuMnAcIy6JVHf9r8hv-AfkmGQ-EY,397 +mypy/typeshed/third_party/2and3/Crypto/Cipher/ARC2.pyi,sha256=onALw-kGR8GP9Z-CCf_Df2ChYg_ootEoQD_ggkPxX44,397 +mypy/typeshed/third_party/2and3/Crypto/Cipher/ARC4.pyi,sha256=4f_6BZx4pw37UoULNQTW9J0jAJFpq_26SEwReXffH6Y,368 +mypy/typeshed/third_party/2and3/Crypto/Cipher/Blowfish.pyi,sha256=KPV9dZNuzV6sJlOS8f8JtdFyS-dnY7wkYj-soQDGKOk,407 +mypy/typeshed/third_party/2and3/Crypto/Cipher/CAST.pyi,sha256=AD-EnUle8COT29lZSFeZJi4HcWc1JMM2pQhp55Jt2No,405 +mypy/typeshed/third_party/2and3/Crypto/Cipher/DES.pyi,sha256=jBJ9fv4VdSPq8ZyhGHYa8FcrbyCweAC3uHUEXGl-vWA,397 +mypy/typeshed/third_party/2and3/Crypto/Cipher/DES3.pyi,sha256=EjoZZuQu_KTKuXxCkGkgIiATngTGghGplkFty3Sww5s,400 +mypy/typeshed/third_party/2and3/Crypto/Cipher/PKCS1_OAEP.pyi,sha256=0k9RQdPQpy--TwahoJ2iMpQcFOf8I5Qgr6jfWpakLuo,504 +mypy/typeshed/third_party/2and3/Crypto/Cipher/PKCS1_v1_5.pyi,sha256=RTLnu5HRC5v4a9h_xy7pX_I4X2TkjNFJncIH3P3gv70,414 +mypy/typeshed/third_party/2and3/Crypto/Cipher/XOR.pyi,sha256=4ywSjUWy1uMemS5ztupHYN12A9puX67jZBnmYMOyPhQ,412 +mypy/typeshed/third_party/2and3/Crypto/Cipher/__init__.pyi,sha256=-RaU1eIo3IolWB3cbL9Q1O7uhGmjuoHT_oNr4D9quSY,142 +mypy/typeshed/third_party/2and3/Crypto/Cipher/blockalgo.pyi,sha256=TlpV_iPQfHQFqXdyyrOxwQ0sq_YIf90n-whlIYvPO18,417 +mypy/typeshed/third_party/2and3/Crypto/Hash/HMAC.pyi,sha256=4aCDQk1kJfTyrj9byUHxYaxRD57XMtu6Pr36bOU_CVs,420 +mypy/typeshed/third_party/2and3/Crypto/Hash/MD2.pyi,sha256=fMf8AspycjggIfx8KzUxNHRgBNxErvfiabtUJfNKNSo,327 +mypy/typeshed/third_party/2and3/Crypto/Hash/MD4.pyi,sha256=nL0utx1iyvHNP0jMtZ0Bj6L8lKKQfpW6IB4QrnvfRGw,327 +mypy/typeshed/third_party/2and3/Crypto/Hash/MD5.pyi,sha256=N5g_skXab7nw-FreklwfCFFFNJryOBBU9AB0BFp6UBs,327 +mypy/typeshed/third_party/2and3/Crypto/Hash/RIPEMD.pyi,sha256=g1lpaNqudb16T6r9vgLBIj3muBUJo0537JrdiaMQUeQ,333 +mypy/typeshed/third_party/2and3/Crypto/Hash/SHA.pyi,sha256=ywEEh9h798xKrrQ3PTG1DJL2jBOVqAZ2CuM73kKBdqQ,328 +mypy/typeshed/third_party/2and3/Crypto/Hash/SHA224.pyi,sha256=qvBjdTc08JNR0W2t2VhoChf5SvZtRcBKjBT1BbB36DE,330 +mypy/typeshed/third_party/2and3/Crypto/Hash/SHA256.pyi,sha256=zoxaUBz3cuIOpZHeIfukDhLEAKVhZKktVRAG18tf1dg,330 +mypy/typeshed/third_party/2and3/Crypto/Hash/SHA384.pyi,sha256=WvhhOrsXPKcYmco74jBAjoQ8riJQdaCunBL8hrQWDP4,330 +mypy/typeshed/third_party/2and3/Crypto/Hash/SHA512.pyi,sha256=gQLOFMP3GZiFvhP4eSpeMjVvJp7pX_F1OCf9YyAjQSE,330 +mypy/typeshed/third_party/2and3/Crypto/Hash/__init__.pyi,sha256=ABwod6wAy2lE4nSyAQTSvDtiLmwPJYYA_Z1TVTg9nfE,135 +mypy/typeshed/third_party/2and3/Crypto/Hash/hashalgo.pyi,sha256=tcMcipeK3Fwj3qrCBlYgfnDLqSJQqR7DoX6URfQjTj8,328 +mypy/typeshed/third_party/2and3/Crypto/Protocol/AllOrNothing.pyi,sha256=B1R2GRvP3TwcTfM8ALMk0ndgrwBL89-tTuNU-Z-_GH4,262 +mypy/typeshed/third_party/2and3/Crypto/Protocol/Chaffing.pyi,sha256=xkwQipSvTvHDwnJ_9au5rFpG7-7G4uoAe3I3ypghHbY,144 +mypy/typeshed/third_party/2and3/Crypto/Protocol/KDF.pyi,sha256=mL1WnzCsLTGDHW-VobrN5dpgenQljsSVka6mW-gJnYY,271 +mypy/typeshed/third_party/2and3/Crypto/Protocol/__init__.pyi,sha256=i_pjEe_DNHzNgnFn8t86rZsg-qHDjxKD4TD8mEU37VY,77 +mypy/typeshed/third_party/2and3/Crypto/PublicKey/DSA.pyi,sha256=U1G1lDDYHBE0bVfGyubQhhWcBpJlMbDwl1EJupPu1xQ,741 +mypy/typeshed/third_party/2and3/Crypto/PublicKey/ElGamal.pyi,sha256=RM1JyKY2fejhkunAoRFdH5Flj8XVm34-Z6SpujxmH_E,531 +mypy/typeshed/third_party/2and3/Crypto/PublicKey/RSA.pyi,sha256=0C2qT6H9srCsOzQsC68r9XeWVb2iV9UoWQikY6HBSJA,1092 +mypy/typeshed/third_party/2and3/Crypto/PublicKey/__init__.pyi,sha256=dt8H8yWS5t1mFC7GQySzf-Ku3OwVSAKuT3Fttkpkmd0,67 +mypy/typeshed/third_party/2and3/Crypto/PublicKey/pubkey.pyi,sha256=cyn-llQZXLeq-2eref9FWu5E_O4832tsMWcr5Ob4r3k,611 +mypy/typeshed/third_party/2and3/Crypto/Random/Fortuna/FortunaAccumulator.pyi,sha256=HD6M8QAwAlgyq17nPBK4biGZXKJpMeZCO-AOShJIpcw,570 +mypy/typeshed/third_party/2and3/Crypto/Random/Fortuna/FortunaGenerator.pyi,sha256=toNF4nzDDnVvgxt9rdQ2B5N8z8j4pWmYzeABeraAuZY,357 +mypy/typeshed/third_party/2and3/Crypto/Random/Fortuna/SHAd256.pyi,sha256=enLv6jIUo1b5i9pv0zOFh_4Bz7njdGK6JCMSS7Fx3LE,314 +mypy/typeshed/third_party/2and3/Crypto/Random/Fortuna/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2and3/Crypto/Random/OSRNG/__init__.pyi,sha256=jXXBXYvuIE2PDmo7uK-FmI5FFbZC_C9eQ8yzigobKhA,18 +mypy/typeshed/third_party/2and3/Crypto/Random/OSRNG/fallback.pyi,sha256=N3XI3BqfcvDxFhUOHuhFBvCkNC6_9khXYEoicykQbNo,116 +mypy/typeshed/third_party/2and3/Crypto/Random/OSRNG/posix.pyi,sha256=azk7olXSZObod2vgHmKjhn6ZN-coL0ElsIDBxFFwtHc,174 +mypy/typeshed/third_party/2and3/Crypto/Random/OSRNG/rng_base.pyi,sha256=iPv13PRUzWPJMxVa-oh7dVH4LZ7ag6XiWNmp00lJv7Y,259 +mypy/typeshed/third_party/2and3/Crypto/Random/__init__.pyi,sha256=ON3fV7wR4UJS49CtNlziDhIm_TWVISrDbYH0U3tv91I,133 +mypy/typeshed/third_party/2and3/Crypto/Random/random.pyi,sha256=sOpvUcD79tcPbuy_KH8X7txcGKYoo9djAXIuWuJMnvk,825 +mypy/typeshed/third_party/2and3/Crypto/Signature/PKCS1_PSS.pyi,sha256=q_jiqBELyfBKFy_dPCBM0eNoKAVVRCu0UQdXTlBXDpg,286 +mypy/typeshed/third_party/2and3/Crypto/Signature/PKCS1_v1_5.pyi,sha256=LaNUrDSbT9vtpFVwLMAyWSyejEaj-phuIfcIOFmW0uU,180 +mypy/typeshed/third_party/2and3/Crypto/Signature/__init__.pyi,sha256=aMnJbvb3z5OYvKdLldQoi58Qiisd1UcSG3ksa29RXik,68 +mypy/typeshed/third_party/2and3/Crypto/Util/Counter.pyi,sha256=AlnEpoHHdpsXWB0g7DnPK7_N2mBq6CcayqqFoXRA40Y,216 +mypy/typeshed/third_party/2and3/Crypto/Util/RFC1751.pyi,sha256=i9GtVbf9gM8ZArAevQdIthPLuTI3T7bnzi2RBpd_qwQ,126 +mypy/typeshed/third_party/2and3/Crypto/Util/__init__.pyi,sha256=fpqy46NnFyKmTDKWTbRYpqybU3mDR7FxhaQw7PA6rjE,95 +mypy/typeshed/third_party/2and3/Crypto/Util/asn1.pyi,sha256=-q-Vn8ihp0Aomsp-NGaBJBctywykbZvk_JdnrMeHe3k,1412 +mypy/typeshed/third_party/2and3/Crypto/Util/number.pyi,sha256=fCRXejxvofqCYSlbxaT5ExmJvnkxDQBtjH8Y56N86ek,801 +mypy/typeshed/third_party/2and3/Crypto/Util/randpool.pyi,sha256=A5tkW9h3qmACTLGBq5hkym9Ha1f-YVJCK126DDC33rM,533 +mypy/typeshed/third_party/2and3/Crypto/Util/strxor.pyi,sha256=Ntpcyy0sjl27q5xj6aCZRv9SFaLC-OX7G4Ct7Rxjkgc,68 +mypy/typeshed/third_party/2and3/Crypto/__init__.pyi,sha256=AELMqI9p1hqB-vQuNuSuGNIETs5FKgCpHT3wgaR3iwU,109 +mypy/typeshed/third_party/2and3/Crypto/pct_warnings.pyi,sha256=s8_64lsflPPLoiObVVicpf_zgc2yPs9BzQXXU_U624k,412 +mypy/typeshed/third_party/2and3/atomicwrites/__init__.pyi,sha256=w8S11MVNxRRoO-iwNRXN_-SrDeP2NSK50IIXo20xT4o,1005 +mypy/typeshed/third_party/2and3/attr/__init__.pyi,sha256=fOnMRTF00b5J23PYPF74u66UVhVzzm0KYVxzmVXHPw0,8257 +mypy/typeshed/third_party/2and3/attr/_version_info.pyi,sha256=x_M3L3WuB7r_ULXAWjx959udKQ4HLB8l-hsc1FDGNvk,209 +mypy/typeshed/third_party/2and3/attr/converters.pyi,sha256=wAhCoOT1MFV8t323rpD87O7bxQ8CYLTPiBQd-29BieI,351 +mypy/typeshed/third_party/2and3/attr/exceptions.pyi,sha256=4zuaJyl2axxWbqnZgxo_2oTpPNbyowEw3A4hqV5PmAc,458 +mypy/typeshed/third_party/2and3/attr/filters.pyi,sha256=xDpmKQlFdssgxGa5tsl1ADh_3zwAwAT4vUhd8h-8-Tk,214 +mypy/typeshed/third_party/2and3/attr/validators.pyi,sha256=vZgsJqUwrJevh4v_Hd7_RSXqDrBctE6-3AEZ7uYKodo,1868 +mypy/typeshed/third_party/2and3/backports/__init__.pyi,sha256=CKeVKOomLpAIZH2ipts0a2F9ugydH1mCvfIGlfvtEbc,109 +mypy/typeshed/third_party/2and3/backports/ssl_match_hostname.pyi,sha256=jAdLMMvdxdszZCIdVGxRZw7i5waIBqb4RqwketJqMr4,81 +mypy/typeshed/third_party/2and3/backports_abc.pyi,sha256=z8KwJUh51HVvBluyv29D8TM7-fSQNZf_WPXGvddzV3M,220 +mypy/typeshed/third_party/2and3/bleach/__init__.pyi,sha256=qmdri9dnecUBPOej9Rbk9I3fw8B3G-MLoIuPwRrjcjk,877 +mypy/typeshed/third_party/2and3/bleach/callbacks.pyi,sha256=YKn650zM3mOna2R5f0mgSJZUgqEz0eB_DN_NKGVSRdk,206 +mypy/typeshed/third_party/2and3/bleach/linkifier.pyi,sha256=vQleEwvJ8ucOi0oyBhRnOXj6dAGZe_2bHRHX8UqRFPA,978 +mypy/typeshed/third_party/2and3/bleach/sanitizer.pyi,sha256=mfqdfFhtly5zL2q12cCrWUYKW5IiArlul5-g_McX6VI,1154 +mypy/typeshed/third_party/2and3/bleach/utils.pyi,sha256=Ftxlir0EZOrnI3bon565egk--LDeL_UJmaLeDLdbyRM,286 +mypy/typeshed/third_party/2and3/boto/__init__.pyi,sha256=ylWEDlB8mT8muA3A3u1kPAuc6jqB550LaYlc0dOK9sA,7072 +mypy/typeshed/third_party/2and3/boto/auth.pyi,sha256=c-mkaHStcHPANLvKiEv7p3yeSs2mIfPe8tSSWu0o9PQ,4140 +mypy/typeshed/third_party/2and3/boto/auth_handler.pyi,sha256=3wvvgy2r7upUjbx-Pwqj9PPMpaDucUFL__sqb7QclFE,250 +mypy/typeshed/third_party/2and3/boto/compat.pyi,sha256=PrTSpuprfRuYeIHYW9wbNmq_L5Dptcl0nhXX3A6DKW4,402 +mypy/typeshed/third_party/2and3/boto/connection.pyi,sha256=6MjMVWW0N9LFJtZzN77IupzK5dhmXTUJLDBFWQ3fjYw,5230 +mypy/typeshed/third_party/2and3/boto/ec2/__init__.pyi,sha256=mJotwEhqx0uTOkp7ABAXmgruW432cmd_CLfyqwIdh7c,256 +mypy/typeshed/third_party/2and3/boto/elb/__init__.pyi,sha256=HITLeUBB4LmfGQggnybJgfX9gkLFegAKvjYZ3BXODXk,2479 +mypy/typeshed/third_party/2and3/boto/exception.pyi,sha256=Me21Rb4OUdrBuQ12Pv_sD_LrMHjA0on7PFw35YZKs3w,4568 +mypy/typeshed/third_party/2and3/boto/kms/__init__.pyi,sha256=vP3EwRB7SB3wfJTb9tAW-pKOSEUaQnabY9wpDL15DUA,156 +mypy/typeshed/third_party/2and3/boto/kms/exceptions.pyi,sha256=WKhoeQKeApIczWPJz3vC5A7K03AmbNAM4bnBuVuNVCw,829 +mypy/typeshed/third_party/2and3/boto/kms/layer1.pyi,sha256=jUb_36aJon7wVJvbfMSSW7RDAj1A7ui403T7woZO1Tk,3629 +mypy/typeshed/third_party/2and3/boto/plugin.pyi,sha256=rquBCp_gv_wSNNcWYijFPURhXO48ELzf5XItCuPv7nI,235 +mypy/typeshed/third_party/2and3/boto/regioninfo.pyi,sha256=CGAoGanKLcJZw5dZNvWdNy944NgfjercUeDhHbTYiLI,654 +mypy/typeshed/third_party/2and3/boto/s3/__init__.pyi,sha256=hzHCleNd-rhKff1HEuncGwpVwRAVJpuAkcY9MBRJotQ,495 +mypy/typeshed/third_party/2and3/boto/s3/acl.pyi,sha256=6ygxWrnHtKy5t-yGmGu0sRFNq9rY_kHEdzfxb8BNd7Y,1622 +mypy/typeshed/third_party/2and3/boto/s3/bucket.pyi,sha256=_UvS1PPCY4yL_bUrLjEF6d_Vrr3mbt90IT3rvPLyXVE,8030 +mypy/typeshed/third_party/2and3/boto/s3/bucketlistresultset.pyi,sha256=bBiFHpk2u-8LOO0GBYt6BvpquwP7c61P7Z1pSYAP5z8,1803 +mypy/typeshed/third_party/2and3/boto/s3/bucketlogging.pyi,sha256=3A-6a-73DgObYEzBbcUcknHJQyw4e3ihu0NDL4qRmGQ,400 +mypy/typeshed/third_party/2and3/boto/s3/connection.pyi,sha256=pEV-wfmCJES1x61OyjFHuqIr_jnkgtPBLP-dxZCzCeU,4354 +mypy/typeshed/third_party/2and3/boto/s3/cors.pyi,sha256=MWUrqlt-gXUPaEkRcBcnKnQnzyTAGkNA6_G5FO98pjY,962 +mypy/typeshed/third_party/2and3/boto/s3/deletemarker.pyi,sha256=T6AWOwNnW391UjVpzJ8tfbaOtM_hSaNa2wyJV02f5wQ,366 +mypy/typeshed/third_party/2and3/boto/s3/key.pyi,sha256=ZBqfaNilLMqcrorZQkc2HWEX5p9m4EDwTZ0HyVZN-xA,8309 +mypy/typeshed/third_party/2and3/boto/s3/keyfile.pyi,sha256=EcfBooXpPExAghucYEM6sxPVsp32wueqK_-5Kk-66rI,684 +mypy/typeshed/third_party/2and3/boto/s3/lifecycle.pyi,sha256=RyrE3lLleL-fghPbTPbgQEHS2Bhk7c56CF4hXNjlTUQ,1874 +mypy/typeshed/third_party/2and3/boto/s3/multidelete.pyi,sha256=QeIn0Sf7WHGYl2PsqaMWk0-p2ZEub5-eOvnfaVr_FAg,1014 +mypy/typeshed/third_party/2and3/boto/s3/multipart.pyi,sha256=uiV07VlvjmYkafuVbPOrdkitZNWcOT7itrC4mMPdqvc,1833 +mypy/typeshed/third_party/2and3/boto/s3/prefix.pyi,sha256=UDLPJn1XiSFLXxd0RdeOMzUfzEyYUnCAiGPACntnkkI,324 +mypy/typeshed/third_party/2and3/boto/s3/tagging.pyi,sha256=JgNFPHTLi7TR0HbeasYlSnbVA-GzNXzYJ9H6sBmLz0c,748 +mypy/typeshed/third_party/2and3/boto/s3/user.pyi,sha256=nFbH3dOf5SfNoaTyNwkiu2q3ZR82iPYVr-LfXzUGzYg,362 +mypy/typeshed/third_party/2and3/boto/s3/website.pyi,sha256=9tQ2ckXvJcfcaT2NM_YN19mQwqHhYUWwKlqwoeI4ZJg,2492 +mypy/typeshed/third_party/2and3/boto/utils.pyi,sha256=IkAe4S88QhOzjQ8pCzfZ75mEtQ2-Q_OU1juZXvKLVEQ,6201 +mypy/typeshed/third_party/2and3/certifi.pyi,sha256=L-Idpv54Z5MALmou6rENZOu7F_jAFD5CPo1hb5amF2s,24 +mypy/typeshed/third_party/2and3/characteristic/__init__.pyi,sha256=tTDLA5WcBLHvJdgbcNLqDBY9nnvlO22KSZY3gfWSBME,1323 +mypy/typeshed/third_party/2and3/chardet/__init__.pyi,sha256=sM6mS4FwTiSHVWl3G5vxC7g3TBGkPCatDvo3a5AngLs,147 +mypy/typeshed/third_party/2and3/chardet/universaldetector.pyi,sha256=a5HKCYsYOLHOfzUjQCgGI0nb2QuJLcel4VunmLXjVIA,836 +mypy/typeshed/third_party/2and3/click/__init__.pyi,sha256=xO24zrwFPylRwnTrLlnnk6FZ1lP_fWUid_U-JVGKvWU,2872 +mypy/typeshed/third_party/2and3/click/_termui_impl.pyi,sha256=pJZm5thjg6ANosLsXOu2JbVX1ugzptbzURePwDTazZE,476 +mypy/typeshed/third_party/2and3/click/core.pyi,sha256=2J5evs9r1RDHkyQJSD3Edb2aouNb1Wp-u6IGoiJ3yz0,11944 +mypy/typeshed/third_party/2and3/click/decorators.pyi,sha256=roi3RevUYC3yXYqQTqaVspAPpDdhse6sgmtIqoGpdMI,9266 +mypy/typeshed/third_party/2and3/click/exceptions.pyi,sha256=b1pZ6QTM194-1Zu501TGCbWGfrH5WXLjdiJwYcbwwlk,2068 +mypy/typeshed/third_party/2and3/click/formatting.pyi,sha256=R1n2vJVyjKTSg1NaBcFhsZ29pWX-KD53po-8wT97WQc,1615 +mypy/typeshed/third_party/2and3/click/globals.pyi,sha256=Gzjjl8GqPGor-_qDGe7Fb2U792EsdzizOsE-Vhv-tmA,296 +mypy/typeshed/third_party/2and3/click/parser.pyi,sha256=tHDYOkhrupvqvF-DLim09PNT1wZp43fL9uMb4jyRO5E,2141 +mypy/typeshed/third_party/2and3/click/termui.pyi,sha256=OTFo2qtEhMclfmTCZnYbceFQaYGHEgKnz4tuxJ_mNSo,3501 +mypy/typeshed/third_party/2and3/click/testing.pyi,sha256=lrConQvTuPK9Tx4X2hk67RuP1emxqi9RTCZnDHVw2Us,2207 +mypy/typeshed/third_party/2and3/click/types.pyi,sha256=vc9TTLB-B31gMs7cS2n8gka25hUUcluh0dwoXntPtQc,5502 +mypy/typeshed/third_party/2and3/click/utils.pyi,sha256=-CrBHup5WqRgmk6X3FuLMjHje-W3_FgzmS4LVGhCvaU,1915 +mypy/typeshed/third_party/2and3/croniter.pyi,sha256=jKrZ6-ury0VrkHQf4dLkmcunDx7F5c8Kl6S5xQARd40,1920 +mypy/typeshed/third_party/2and3/cryptography/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2and3/cryptography/exceptions.pyi,sha256=CpK5HtZvigk1U7yYLlqYcXGJaOzknyfhUUittXFuKiM,262 +mypy/typeshed/third_party/2and3/cryptography/fernet.pyi,sha256=Pp3Z4pSFA6YSlupDtKwITgfGrffp2x6TYsaNsOKSh7c,666 +mypy/typeshed/third_party/2and3/cryptography/hazmat/__init__.pyi,sha256=3fBxcSppJr6EOEcUojvflG3Eegg7lv2Qp0dNQQILrP4,63 +mypy/typeshed/third_party/2and3/cryptography/hazmat/backends/__init__.pyi,sha256=dKFUFhsHmSbNrHdG2a_5CErfvQu9hdnIWMA1vys9LaI,124 +mypy/typeshed/third_party/2and3/cryptography/hazmat/backends/interfaces.pyi,sha256=B6ll_f3g9smOyhOZR8hRLJcc891y2yr57KPSVQYb1PI,8238 +mypy/typeshed/third_party/2and3/cryptography/hazmat/bindings/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2and3/cryptography/hazmat/bindings/openssl/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2and3/cryptography/hazmat/bindings/openssl/binding.pyi,sha256=QHIbjl0Q39fxas4DabuLytXjjBZrfqNkft0H_nWwXr4,148 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/__init__.pyi,sha256=3fBxcSppJr6EOEcUojvflG3Eegg7lv2Qp0dNQQILrP4,63 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/asymmetric/__init__.pyi,sha256=3fBxcSppJr6EOEcUojvflG3Eegg7lv2Qp0dNQQILrP4,63 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/asymmetric/dh.pyi,sha256=J1E0wvF1zKW0QWqC_O9jxecnRA7RLidzwLGYhz6Gbrk,2490 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/asymmetric/dsa.pyi,sha256=mAZqxcJ_6i-_8dyJ26tyVxAZXriIx5tKT7DDJQ_AYo0,2911 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/asymmetric/ec.pyi,sha256=EBYJvv-j8KQHe4pYQ5jo1TBIknYTfMfZkkcUBVoCdDY,6246 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/asymmetric/ed25519.pyi,sha256=OiE4CJcNDIaqd_VzdmQGn28WPdT5PBQ5jVKfq_ZRc3k,985 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/asymmetric/ed448.pyi,sha256=Mw-p07GDyttBXKaNB5Su5hw01DQXZgjEZe5M1e7PlhE,973 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/asymmetric/padding.pyi,sha256=g1sB5wpH6yoi9LrLUSHOejKdt8xiLmkPvDdUn6Cm1UY,787 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/asymmetric/rsa.pyi,sha256=ekOBYH33l7YM544w_cfxrCRCG5VL2KxoEZcRkvD2CtY,3204 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/asymmetric/utils.pyi,sha256=ZW37Se6Ha3p6vokm8YH7qVyQEcv311kh01VtHOK6Re8,430 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/asymmetric/x25519.pyi,sha256=JHX8lIJN0j94AsHIS4jQWCrlcOgLdb3Ud2QznMRXOC0,919 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/asymmetric/x448.pyi,sha256=efSTvyRkpVAcxtAwzYymDbnOQPA-dJW7YAliRVA5_cc,905 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/ciphers/__init__.pyi,sha256=-xan17g8RAlduSmIveURYCyHfm0gJ6Ql2CyS0do-MeY,1336 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/ciphers/aead.pyi,sha256=MhkfsUnaMVEi6oRrcfTgp6h1_1QCS8bvxtwoE6bqZS4,1065 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/ciphers/algorithms.pyi,sha256=GMUwzAx9Ethln8PfX0lFjvcACQUpUsaDhC9oN6RQY9I,2244 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/ciphers/modes.pyi,sha256=3rIwa-kj4k0wj8YfZeesqX6jEJhHtUZth6-ivi76etE,3089 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/cmac.pyi,sha256=sxR_sEWpez075f7f9QE_iJW7xrl6Jp8Yl_UpvJFJnbI,416 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/constant_time.pyi,sha256=47ogru9j6XG5mLMDsl2iGKxhZjsH_bKhWYBt4c1jQk0,46 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/hashes.pyi,sha256=-DqcJeGNcqJPlwSICyy5Q7Y2XfSOenNr5058wIPt4ZI,1298 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/hmac.pyi,sha256=YzFx7XKdaQhSIDjYyPalMHTCk_WwQfaVbMOEr1P3v2A,412 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/kdf/__init__.pyi,sha256=fymJGVYF4JGsuO5IUacyuYb4Xunrps4mFrJ0XFEUdfU,261 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/kdf/concatkdf.pyi,sha256=GpWU9N_dvQzFm9ce-Y9EUCPzAuRNYpHCmmGQpvVySeE,864 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/kdf/hkdf.pyi,sha256=F15ggnuIHFQE0062q6LG6n8Pli8mOjpb-jtEOvy5E18,829 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/kdf/kbkdf.pyi,sha256=AGlbgHZXt9LMnylvlwAAWSJkjsvq8vaL95pKz5MB2ww,851 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/kdf/pbkdf2.pyi,sha256=VpadnXqKkWIgf4rDtQXDzanTlvKB3A5peRpUzgoEMDo,502 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/kdf/scrypt.pyi,sha256=imUgjixAkgL6HYvysmILAwvIbrSgRBwt8_y73gJ3gqQ,407 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/kdf/x963kdf.pyi,sha256=M6zkKxW87Rj5-dNtJXjmscmAPQP5mrTwNoysHT8KbFU,515 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/keywrap.pyi,sha256=zv8HE00Oa_2z__RjkJLOOfk3eNFXafum9XCRPafmi_M,518 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/padding.pyi,sha256=RYc1U9k5Vw4NzpT-JXi_AwRiPXwzu7XLVyG6HtDy_gM,540 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/poly1305.pyi,sha256=PdifWqHODjsrzkqExOetFF5g529I0gF9SvNIoCcozZ4,504 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/serialization/__init__.pyi,sha256=G1HBtYCQdgRLxBBffk6MiR_T3YaOOJoH_2F5dLMvDLY,1006 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/serialization/pkcs12.pyi,sha256=5kXsc7TiX4tUB4zO_aqZuh5bE05KrIkog4_5Pkam6CI,113 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/twofactor/__init__.pyi,sha256=MV00ZbBi-FKgHi9PYY2ZS7tneV2rghu2eVi1KgxRZzs,35 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/twofactor/hotp.pyi,sha256=ibl6C1ISmQ5H6nmmT_axuSuhPmPUn7YBx7A4i5PoFbY,540 +mypy/typeshed/third_party/2and3/cryptography/hazmat/primitives/twofactor/totp.pyi,sha256=p2rGTlM-DzrBmqLnYQKklWHjJJbDwQ0yf_J1BfJqf8g,585 +mypy/typeshed/third_party/2and3/cryptography/x509.pyi,sha256=DO2WXJWvd_hru-WibpiuoPPWo9Gc7aYX4mrgp8W7ZcU,13382 +mypy/typeshed/third_party/2and3/datetimerange/__init__.pyi,sha256=P_nQE115ODhNu36iObJsJtqzHE6u-c8jnzQVt36mrgw,1913 +mypy/typeshed/third_party/2and3/dateutil/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2and3/dateutil/_common.pyi,sha256=QLZOnmpLNlXPSgrW2LW7lqb50t8jaHqguHflcJjTrEg,345 +mypy/typeshed/third_party/2and3/dateutil/easter.pyi,sha256=ck2QU-ikLqs1HsaF9IhVFhUkk4xvRWyHCDTNxPiB_fg,297 +mypy/typeshed/third_party/2and3/dateutil/parser.pyi,sha256=1090xD1CdLm9K6AwthbmrTN3_SQNL25wH23ClhgrC34,1741 +mypy/typeshed/third_party/2and3/dateutil/relativedelta.pyi,sha256=RsR55UlJYF3y05p_j6H5UBIGtgKVh5VwKqAFDNiHS2M,3328 +mypy/typeshed/third_party/2and3/dateutil/rrule.pyi,sha256=MDhmPyD-85M9RuyZxtVPHDU_lSjL5cn0p2ZqfwKiELs,3360 +mypy/typeshed/third_party/2and3/dateutil/tz/__init__.pyi,sha256=9jaCdzJu4Hb_z2vNz7LKV1J4qtQ_cZC4bJQ1flgQDzc,340 +mypy/typeshed/third_party/2and3/dateutil/tz/_common.pyi,sha256=-sVS4o6Pz2bBRViwyMEk3yZpDVWq9BGahTarrYdOCsA,818 +mypy/typeshed/third_party/2and3/dateutil/tz/tz.pyi,sha256=4uttciwPJfFzSqQ3T6ICiI1kSPn5XIsBw4xuk1IfP1U,3929 +mypy/typeshed/third_party/2and3/dateutil/utils.pyi,sha256=lj3N8C7ivm_iFakRu1V7Crwl1VNuLS7O0uEmdNMtkSE,282 +mypy/typeshed/third_party/2and3/decorator.pyi,sha256=EvtPa9joVMu-PgY0mttNy_1nzucjC1VE58_mEn792gc,2807 +mypy/typeshed/third_party/2and3/emoji.pyi,sha256=ETMKl8Nf8ruXmmeMddYW7AVKK6waF_NLV8lJnPQfbu4,395 +mypy/typeshed/third_party/2and3/first.pyi,sha256=pcPE8-5davQ3ElewRYJK8q2Cfpgv-yFwz2jfRQMeTQo,482 +mypy/typeshed/third_party/2and3/flask/__init__.pyi,sha256=t9Ow_Nw0zmpJDLytn4gFNR5Vw_x5k6-vHdJPwcXQLPg,2217 +mypy/typeshed/third_party/2and3/flask/app.pyi,sha256=mwTQYasfOr3dfzNvy6oYoPhE0dFkUjTL9BiObYYTux8,8645 +mypy/typeshed/third_party/2and3/flask/blueprints.pyi,sha256=2Wa1Z8QAwDXliN0OlAznsx1RDG3ZGdTswbbe3yK4kuA,3575 +mypy/typeshed/third_party/2and3/flask/cli.pyi,sha256=B0pE7XSG663dAGgiinR9uxauzsBkM_DRm4-ITNh_p3Y,2342 +mypy/typeshed/third_party/2and3/flask/config.pyi,sha256=SKOg0TWDw1gDFgH4IfrJIkNE8NuC_EE9N71XwEbcA0M,988 +mypy/typeshed/third_party/2and3/flask/ctx.pyi,sha256=EymBtSTL_orlB-hsjZyKcIZfWPPFdyZqm-WcMZ4Mf3g,1563 +mypy/typeshed/third_party/2and3/flask/debughelpers.pyi,sha256=BhBUhXBTMZGDRK_QUNwZ5cGm2vTqk5MhFcYlBYIuh0Y,727 +mypy/typeshed/third_party/2and3/flask/globals.pyi,sha256=nZbnEIGEdlpneOIPYkZyt8imn4m5Hb-XaPCNWFPhf1A,438 +mypy/typeshed/third_party/2and3/flask/helpers.pyi,sha256=q7QTvxrXs3T21Zpv2AeW3P9Tt1axkpB6XlfTPvyVR1s,2218 +mypy/typeshed/third_party/2and3/flask/json/__init__.pyi,sha256=eVf12af_0ORzPtYeURN7YWBzLLdRZ4KVOwpQQtW1daA,689 +mypy/typeshed/third_party/2and3/flask/json/tag.pyi,sha256=jauBEQjkrDDHX4kwhUsKufTI7pe--SC2V4MqvXNzcdE,2037 +mypy/typeshed/third_party/2and3/flask/logging.pyi,sha256=i2Q5tH2evybUWFQiXnfRAuOudW7u5Cdt5BUwjsyrLN4,297 +mypy/typeshed/third_party/2and3/flask/sessions.pyi,sha256=uyr05P-fbLXSA5PtKnuhfBySRdlA0rjXx-vQoP3TOwo,2135 +mypy/typeshed/third_party/2and3/flask/signals.pyi,sha256=HfIh1SQ4ywJ7L8NUtv16yVje4RGb7HB3WX733j2c9ao,836 +mypy/typeshed/third_party/2and3/flask/templating.pyi,sha256=QzgLyAVY9wMPLZzRfuW7X1baGCJhl5UvxZpZ0aR3RBQ,853 +mypy/typeshed/third_party/2and3/flask/testing.pyi,sha256=A9f18OUVa7dK59isStKpfCsSEHlHJHBa0rAx-23dhpM,1500 +mypy/typeshed/third_party/2and3/flask/views.pyi,sha256=toPfnrVkyXOovaUNdlq1TsyHcjWLdKF2TbPVr8DyoB0,675 +mypy/typeshed/third_party/2and3/flask/wrappers.pyi,sha256=406hvfdyJbN7LHCOyegdvhR2fWm0z8OHnum9HaflgW4,1253 +mypy/typeshed/third_party/2and3/geoip2/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2and3/geoip2/database.pyi,sha256=OyVxPg_2c0rNEvWKJj4XNgj8QeEWiCjIKYf0ieEahy8,1094 +mypy/typeshed/third_party/2and3/geoip2/errors.pyi,sha256=cLNX8vwSGpvguuJgpfn1ww5OSP4jIy-XK1hCa_EsYes,498 +mypy/typeshed/third_party/2and3/geoip2/mixins.pyi,sha256=ZpggdVI7qLOYVHt91mL8uPwWq4E07MxpN_UfAgoPcB8,120 +mypy/typeshed/third_party/2and3/geoip2/models.pyi,sha256=xB5Co15gOcoT76LTg6CC-is3b1B6iK9kV06eDLByG3c,1870 +mypy/typeshed/third_party/2and3/geoip2/records.pyi,sha256=3-gke4nBlwnk09iOiT8tRdusFPi6CewrJn9foXKvI_M,2071 +mypy/typeshed/third_party/2and3/gflags.pyi,sha256=HC6AcYQ_gxX3XdC3UUSNBiBC_dUJiLXYyBFGIVVw9y8,11004 +mypy/typeshed/third_party/2and3/google/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2and3/google/protobuf/__init__.pyi,sha256=U54VfsG7-8DG_1f27w_Gmz8NunTjIR0iCWEXUCuKKVA,19 +mypy/typeshed/third_party/2and3/google/protobuf/any_pb2.pyi,sha256=BQ4N0a7Bo8tXC549k2Ya56ummWquea5vHZXPH08kTFA,311 +mypy/typeshed/third_party/2and3/google/protobuf/any_test_pb2.pyi,sha256=qUl8GPa_BUxtQueFEvH5aQlt1xGAUs7GP8VRMbalk00,557 +mypy/typeshed/third_party/2and3/google/protobuf/api_pb2.pyi,sha256=XydzdTUxzuoyjzedZ7IveUxGUF8a-cr4wRo7Y77ze1c,1814 +mypy/typeshed/third_party/2and3/google/protobuf/compiler/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2and3/google/protobuf/compiler/plugin_pb2.pyi,sha256=U0puKUI8uP2h4XPWXWfdmTslwOgHBbqwAl2YQqZPog0,1593 +mypy/typeshed/third_party/2and3/google/protobuf/descriptor.pyi,sha256=Y6Q812FNTwN0iaA-8KQbdA57yytUVO6UQnb4_dS1-wg,7157 +mypy/typeshed/third_party/2and3/google/protobuf/descriptor_pb2.pyi,sha256=IpTksPGmIrIHouoTK0adFYN215JMgREq6H_AvVaCkog,18261 +mypy/typeshed/third_party/2and3/google/protobuf/descriptor_pool.pyi,sha256=dsqeewyqydUwYE9sNscI2qvYE1h5huXeZQ9igxjQD8I,744 +mypy/typeshed/third_party/2and3/google/protobuf/duration_pb2.pyi,sha256=nK4WXkRMXqpNRPenTkbh7RhBuAyXM1osM870i6L4VLY,306 +mypy/typeshed/third_party/2and3/google/protobuf/empty_pb2.pyi,sha256=4_bi63PpIZQ317OVOud88q9NiyKfpiYcGwd7y1tuitU,104 +mypy/typeshed/third_party/2and3/google/protobuf/field_mask_pb2.pyi,sha256=t2uM1ycxTLZmBGHFgc6nUFrCYuLHB6ZrmeSPlrYEBbU,396 +mypy/typeshed/third_party/2and3/google/protobuf/internal/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2and3/google/protobuf/internal/containers.pyi,sha256=AshIc8UDrBzqYv8hOoSM9oENO6dpx3oreIHx06hSKOw,2751 +mypy/typeshed/third_party/2and3/google/protobuf/internal/decoder.pyi,sha256=roJK89CkgjVKjRJbEnQ5ik1KdfXhwxymSyRIg7c5WW0,860 +mypy/typeshed/third_party/2and3/google/protobuf/internal/encoder.pyi,sha256=3rRgqC6ceJ7LtL7Qo5YiAK6CwE_HigHMsj9l-oa_5iE,1045 +mypy/typeshed/third_party/2and3/google/protobuf/internal/enum_type_wrapper.pyi,sha256=3NnQ6BBOj_vJdF6jMa_7r2Sy9KiDyx3qQGI-0w0r2kQ,656 +mypy/typeshed/third_party/2and3/google/protobuf/internal/message_listener.pyi,sha256=EiRlRR-kzJlKV3NXoYtYrGhMS3lZ2oWwQdq77h1cY8E,148 +mypy/typeshed/third_party/2and3/google/protobuf/internal/well_known_types.pyi,sha256=OGh7Kg5Mo8TZFytfoZcCI8nm5VwmpdpSybFHz6e_ngo,3696 +mypy/typeshed/third_party/2and3/google/protobuf/internal/wire_format.pyi,sha256=ncrIlZeBjytfWeG9rQX8VdHO8YvS3EmqBJ4rIbaZVxw,1554 +mypy/typeshed/third_party/2and3/google/protobuf/json_format.pyi,sha256=c4vQdlP5KGT-ofrdbX-0fzsunf2sMz3zDpQx6MKfJpU,913 +mypy/typeshed/third_party/2and3/google/protobuf/map_proto2_unittest_pb2.pyi,sha256=XULZXNlQUxdjsaECuEbQr1QAFTmirHgq0BGzpZRJrG0,8186 +mypy/typeshed/third_party/2and3/google/protobuf/map_unittest_pb2.pyi,sha256=KVeeaH4Y1iPk7ua9MUv6wXrsKcVeeA0O4O_3BqAJpTM,16465 +mypy/typeshed/third_party/2and3/google/protobuf/message.pyi,sha256=HaGmFLBUoqXEtiN8tqoX-p85htO_GRlWqkOsPx8BTww,2144 +mypy/typeshed/third_party/2and3/google/protobuf/message_factory.pyi,sha256=Obh5s9vE_rbWKoEAiMY7NgKKL5c_c0lPuz4TX0OPkv0,515 +mypy/typeshed/third_party/2and3/google/protobuf/reflection.pyi,sha256=VahfyfCz4LzllaCNcv6qXVMa6sWQZ9PEbM9yTKrC9d0,230 +mypy/typeshed/third_party/2and3/google/protobuf/service.pyi,sha256=khFSQ7jbdMgCZRnhTDDIXnaDvS_GsjhllVxiJpDu9yg,1371 +mypy/typeshed/third_party/2and3/google/protobuf/source_context_pb2.pyi,sha256=liRJY3zKYnRNHwN52JRpdpo_YU84hrJkWdRht7CDulM,198 +mypy/typeshed/third_party/2and3/google/protobuf/struct_pb2.pyi,sha256=Oa_R4PAVxxaxFxVezkLPX8cJpbO9cYgma8ejTnfQGv8,1820 +mypy/typeshed/third_party/2and3/google/protobuf/symbol_database.pyi,sha256=1ktBl9DdQkOMYYopafAwWmyzcKzAahFwCIRLjiQGqCg,648 +mypy/typeshed/third_party/2and3/google/protobuf/test_messages_proto2_pb2.pyi,sha256=NTHTXCbaGv-F_vH3a1B-L5s7Y4267cgH7iMm94gosKw,15413 +mypy/typeshed/third_party/2and3/google/protobuf/test_messages_proto3_pb2.pyi,sha256=FKxTNMikHXyxWFE4yMrW9c2IUEf9Jb8kOe1rNjt2cjk,19384 +mypy/typeshed/third_party/2and3/google/protobuf/timestamp_pb2.pyi,sha256=D6z490JXQA2Oxd1S8M7iNQQyTa8NOX8aTd8l_9ftgz4,308 +mypy/typeshed/third_party/2and3/google/protobuf/type_pb2.pyi,sha256=pUSYUIjWP1o8DzodUxCxWlaOedq7Lx9bAB5yxQ6whHE,4683 +mypy/typeshed/third_party/2and3/google/protobuf/unittest_arena_pb2.pyi,sha256=NGhIR6x_-zig4xSSp7P4NsmFwY4xR0_2uELoEHu6Tn4,835 +mypy/typeshed/third_party/2and3/google/protobuf/unittest_custom_options_pb2.pyi,sha256=oEgaVcI2w-BpkK6gyuvmM5mkm0TA7XSjjdvQf1JabRs,7704 +mypy/typeshed/third_party/2and3/google/protobuf/unittest_import_pb2.pyi,sha256=bYBmdBsohg0jT_q042cLfZMGyUiGNmanCqZk_4tl6P0,1050 +mypy/typeshed/third_party/2and3/google/protobuf/unittest_import_public_pb2.pyi,sha256=CIQ0EkEEaHmu6uFMrxrzSIaoK5AKGYQNYJS1d2BZyTs,180 +mypy/typeshed/third_party/2and3/google/protobuf/unittest_mset_pb2.pyi,sha256=-RdoQZXtojAoJZ-UoGF7rSXVQiVEZFAI86WHx9r4yxg,1027 +mypy/typeshed/third_party/2and3/google/protobuf/unittest_mset_wire_format_pb2.pyi,sha256=OMBHvrAOO1c4IBe0Y16U2b555ymhBp7uaz4p6l8iyas,336 +mypy/typeshed/third_party/2and3/google/protobuf/unittest_no_arena_import_pb2.pyi,sha256=OehFdc6cdhswv8SzJmRzAe_BySaxQbBQ3Wg7gYXPHLA,187 +mypy/typeshed/third_party/2and3/google/protobuf/unittest_no_arena_pb2.pyi,sha256=_nVolT2sQFjyTN3EsRfwXno9qnB2HTT034TZStb0TNg,9917 +mypy/typeshed/third_party/2and3/google/protobuf/unittest_no_generic_services_pb2.pyi,sha256=troHCyTDMbKENPmWLeXVkRokIjnP6GphAZm-nAyaQSU,544 +mypy/typeshed/third_party/2and3/google/protobuf/unittest_pb2.pyi,sha256=zLkZGwdscSiCrPkUQYk1BCNTuA2hsqsr_5p5fazbTyM,40921 +mypy/typeshed/third_party/2and3/google/protobuf/unittest_proto3_arena_pb2.pyi,sha256=Qw06SVjUSkDZTfYY4p2LGo18An2TRQevVxk_LQl8beo,11273 +mypy/typeshed/third_party/2and3/google/protobuf/util/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2and3/google/protobuf/util/json_format_proto3_pb2.pyi,sha256=RZAGK5FdUKX0RfE9eGWH9mq1Luv3nYlnAVqZV01En0k,13487 +mypy/typeshed/third_party/2and3/google/protobuf/wrappers_pb2.pyi,sha256=vDFeMzGD3hF7YXI-2HQ-yCIeY19M-cLxAW6t0KG95sE,1060 +mypy/typeshed/third_party/2and3/itsdangerous.pyi,sha256=BK1g6F3P4RAYHhE5W3581NGThesgBimW6urttOsZDXQ,8323 +mypy/typeshed/third_party/2and3/jinja2/__init__.pyi,sha256=_U5yLFi5KkpYNHQLTGGclbBdgosMiHoA8w6Spq9um3c,1371 +mypy/typeshed/third_party/2and3/jinja2/_compat.pyi,sha256=VnnpKEB1OIUEmrMArkmfEc4P7KGhrlQEMhGaS1UTA2U,644 +mypy/typeshed/third_party/2and3/jinja2/_stringdefs.pyi,sha256=_gw2yhYfWIlqy06ve5t93z3SIVXX2j5Md3rz58LIKjE,360 +mypy/typeshed/third_party/2and3/jinja2/bccache.pyi,sha256=ypfXFrP5k-Phe6dJ3jLwn3yhRMzDSYPHTpsJT4Hx56M,1396 +mypy/typeshed/third_party/2and3/jinja2/compiler.pyi,sha256=JvszhGHn4u4CfrGplkLVGmXaW8ukjYAMTHgZswoDGLk,6362 +mypy/typeshed/third_party/2and3/jinja2/constants.pyi,sha256=seJNAMX1_sGZ8wi8SB5qbZtSUvYiQMelMpXMyxl-AR4,23 +mypy/typeshed/third_party/2and3/jinja2/debug.pyi,sha256=6XZeMpZjfFUP-Mh5tEof8P8UANNgJ7lsBq1RUbjL_M4,1018 +mypy/typeshed/third_party/2and3/jinja2/defaults.pyi,sha256=BK5FNrsIsq7ee26gK1xu5bY0T4KZ3i8cD5-Op-5QyPQ,515 +mypy/typeshed/third_party/2and3/jinja2/environment.pyi,sha256=DtUDJMLugxxWXlUIQIxi4eDP5xhFb-qIY2UGb0BK0-g,8049 +mypy/typeshed/third_party/2and3/jinja2/exceptions.pyi,sha256=P52TnpizVoU2vAeayt4MZlTYMnhJYiMrWxiLMWP1LeQ,1050 +mypy/typeshed/third_party/2and3/jinja2/ext.pyi,sha256=_LmaAViWI_plPMqg0cvHea4QJbFCmkkGlQcD7ba6W1k,1621 +mypy/typeshed/third_party/2and3/jinja2/filters.pyi,sha256=OxR24skT1uz7n2J-h3voluptB-l21pQ9KTx0CQnGsVU,2425 +mypy/typeshed/third_party/2and3/jinja2/lexer.pyi,sha256=evBj10x_89jlfuVacpADTOynp2XF9n8d2vQf5lZg-pE,2764 +mypy/typeshed/third_party/2and3/jinja2/loaders.pyi,sha256=22nkWvTG2IKVWToZtsDXswtjXnsk9Nl_ar77rg5-JVs,2924 +mypy/typeshed/third_party/2and3/jinja2/meta.pyi,sha256=N37MkSqVyUYoXfktXzJgeQHUz8udiqUDGvt9wlBQHno,338 +mypy/typeshed/third_party/2and3/jinja2/nodes.pyi,sha256=-86WsO5Cbws9IqXBSZidnIVlKesGmV2VFdhIUMrK8Vs,5271 +mypy/typeshed/third_party/2and3/jinja2/optimizer.pyi,sha256=wfBoNO5HMlQci-CKbQoZzrfJSNSIdnEedbyTwz85fFA,660 +mypy/typeshed/third_party/2and3/jinja2/parser.pyi,sha256=e0iwmMMAzWjYb-NAyZwj3rY6fFS4eGz3MVGrEhX4OrA,2515 +mypy/typeshed/third_party/2and3/jinja2/runtime.pyi,sha256=sLNmF-6AK6ScAAshdloUJ2F9HZ1FCm65-h-Fv2SBZME,3449 +mypy/typeshed/third_party/2and3/jinja2/sandbox.pyi,sha256=lShECmYWOh54kmQdqyk-Cq27hBXHVeMjmDzHV3nWzjg,1145 +mypy/typeshed/third_party/2and3/jinja2/tests.pyi,sha256=dixzMe9BiHnvbL8KyR-KY9LLX-VD1-pgbWXC6Mwc4LA,561 +mypy/typeshed/third_party/2and3/jinja2/utils.pyi,sha256=NeyxqWfHu_iLsik8vMacNkWAcv2YPyP0HOCJNzJay9M,2027 +mypy/typeshed/third_party/2and3/jinja2/visitor.pyi,sha256=yeJ6g3RC5bitP3tG-btWLOZn954E_e9RxKPtgsiwcVc,306 +mypy/typeshed/third_party/2and3/markupsafe/__init__.pyi,sha256=NqkNgINf5Mm0Gm-U_2Uy9vg08zkrl8udryG_mrqQKEM,2825 +mypy/typeshed/third_party/2and3/markupsafe/_compat.pyi,sha256=Av8j9PxEoDMV9y8RC7NjMryo6PzwduQb6-qzjDk1wHM,440 +mypy/typeshed/third_party/2and3/markupsafe/_constants.pyi,sha256=rqhicI0bgAim40njcEhbGT6Njas1XNwFxB5bRTz3fjs,67 +mypy/typeshed/third_party/2and3/markupsafe/_native.pyi,sha256=E4ZKi3H5V--WDC6t5o8PmwH7iLJg9D0n4skTIYOsmDY,255 +mypy/typeshed/third_party/2and3/markupsafe/_speedups.pyi,sha256=E4ZKi3H5V--WDC6t5o8PmwH7iLJg9D0n4skTIYOsmDY,255 +mypy/typeshed/third_party/2and3/maxminddb/__init__.pyi,sha256=vbjT_Vx7eN_rVyGUwT4VLQikSVvYbW67whwfFcxjOGM,178 +mypy/typeshed/third_party/2and3/maxminddb/compat.pyi,sha256=Jo_mka6ORT9NnnmNb8TptvQrXPn23b6QNGLLT600LPs,242 +mypy/typeshed/third_party/2and3/maxminddb/const.pyi,sha256=c1LWH0XYtbcs9T0mJz5lyj6ZAVBwU2zZJdRk7Dd4Fc0,130 +mypy/typeshed/third_party/2and3/maxminddb/decoder.pyi,sha256=lZIOBE8OKJGu1fMmiH_n0b46qbmDxnXNsCq2Ed9oxzA,215 +mypy/typeshed/third_party/2and3/maxminddb/errors.pyi,sha256=ifm1u-yPLyPC5KPPF7F5vswnJ2X-TeGc5EgYXvWvn30,46 +mypy/typeshed/third_party/2and3/maxminddb/extension.pyi,sha256=k7yLS2l266OjFQfh4zmzOwO-46LpvnT3KM9FnvrZybU,1122 +mypy/typeshed/third_party/2and3/maxminddb/reader.pyi,sha256=meT6j-__y-R77hPoIOTGslhQwng24sCxYqTp12kzgzE,1231 +mypy/typeshed/third_party/2and3/mock.pyi,sha256=HqQLTaHo-_Gl6YAMouW9oDA6JGt3qqXDL8PaVMBbrw4,7893 +mypy/typeshed/third_party/2and3/mypy_extensions.pyi,sha256=HxBY21fhn_SC33mqmvaiMZqzUxeHfkPIsQnu07UbsLA,2213 +mypy/typeshed/third_party/2and3/pyVmomi/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2and3/pyVmomi/vim/__init__.pyi,sha256=dW0O0FNDSHynjywkV8IU_hlcWB3KJMnktR3Dfpwa6Nk,1789 +mypy/typeshed/third_party/2and3/pyVmomi/vim/event.pyi,sha256=tsD5Uodys0JRc26SfN1DFe3olT1V_nIMXvTigWzCiBc,336 +mypy/typeshed/third_party/2and3/pyVmomi/vim/fault.pyi,sha256=gGS8hYnJdez4lDNuz4FKHnliUGgQ9-V06SwhWIMKvwY,82 +mypy/typeshed/third_party/2and3/pyVmomi/vim/option.pyi,sha256=OXsoDX2hMC2muAnp1BXiCxTjXuvjpXOaNFqrf1simxU,150 +mypy/typeshed/third_party/2and3/pyVmomi/vim/view.pyi,sha256=ibVeMNPd_qMWRDRAjcqDVqglVz-m4IKYs9g9awzipN0,541 +mypy/typeshed/third_party/2and3/pyVmomi/vmodl/__init__.pyi,sha256=2gWHwzhogVUwBQI8my0gMtRiDAeJTejYXgbBCH-tG1U,115 +mypy/typeshed/third_party/2and3/pyVmomi/vmodl/fault.pyi,sha256=0AUfVEIh30Gx7JvrdjnZt1V6G-DLvxSeiyD_RNrCEPE,38 +mypy/typeshed/third_party/2and3/pyVmomi/vmodl/query.pyi,sha256=0cQAk-knAyxrD2vprwCUsyZ_ccdL23UO-HpwkXzWVYE,1156 +mypy/typeshed/third_party/2and3/pycurl.pyi,sha256=WpMP6cWHznIrSWdyxBWQAdbCzxzO0KCK02JI7ePMReA,13756 +mypy/typeshed/third_party/2and3/pymysql/__init__.pyi,sha256=6dpZ8Et4c7z_-w_X2jbLMQNuZtMPn8MIPKo2_ebbzh4,1630 +mypy/typeshed/third_party/2and3/pymysql/charset.pyi,sha256=8pQ9uIfBVCKgQE42rgAV8Oc1RAUiR7c8k2z4w64zVso,327 +mypy/typeshed/third_party/2and3/pymysql/connections.pyi,sha256=THprXj0v33F1B92J_Brwh1Tg7IXZAf3snRiGXZu7nyE,4869 +mypy/typeshed/third_party/2and3/pymysql/constants/CLIENT.pyi,sha256=vnIE4D-CCZ2-TwRYvficDcBx-luonNhHmsuxq8M0V6U,308 +mypy/typeshed/third_party/2and3/pymysql/constants/COMMAND.pyi,sha256=SAol0UV6ttKwz1i9DUn_DydO1HByeSodgDC3Qyv1BTA,407 +mypy/typeshed/third_party/2and3/pymysql/constants/ER.pyi,sha256=0O0FmmEhzeeEUmlkmSNluHuZVhhlTOIEHq1Yc-hXLFY,11280 +mypy/typeshed/third_party/2and3/pymysql/constants/FIELD_TYPE.pyi,sha256=112f_ZZ3GXSiGv5q3fY04FLq-NMWWh8zDSsneoGKfzE,354 +mypy/typeshed/third_party/2and3/pymysql/constants/FLAG.pyi,sha256=LJ19iNTKdV_tqShn5GyJbTc3JtGr7IesoCQy058KPx0,226 +mypy/typeshed/third_party/2and3/pymysql/constants/SERVER_STATUS.pyi,sha256=uoVJx08QJpMZzBiyZXTG1Hr7zcSahGx2zR89eOtYxec,331 +mypy/typeshed/third_party/2and3/pymysql/constants/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2and3/pymysql/converters.pyi,sha256=zLdUk6ZhznsuXvsKtNA-qTpzUsZFeKa_bQ3YgvSPrSs,1330 +mypy/typeshed/third_party/2and3/pymysql/cursors.pyi,sha256=Y4gAW5htoSYTy2XkBbhfLjVOER0a4x_gyz-qiqPxgYM,2180 +mypy/typeshed/third_party/2and3/pymysql/err.pyi,sha256=UUCOmIGk6StSwRf9VvINDe-5_rKPK0s6oh0QSJUfBOw,571 +mypy/typeshed/third_party/2and3/pymysql/times.pyi,sha256=N3iYLkF3MEtwRa8muKj4ViRXS7ON8fcW5XANu2VMxXo,170 +mypy/typeshed/third_party/2and3/pymysql/util.pyi,sha256=fKG9sTGCjyLG5L-n5K8STqna8XVfKzQ2a-X46ozbk20,66 +mypy/typeshed/third_party/2and3/pynamodb/__init__.pyi,sha256=qp8cF6TlhBd5820jKiBRcrR-qumnONUUlUKCzf4rib0,17 +mypy/typeshed/third_party/2and3/pynamodb/attributes.pyi,sha256=B4sA8pkgog-Ei258lHvXhZxHY4MiO6uPHBNFKp-zEdw,4194 +mypy/typeshed/third_party/2and3/pynamodb/connection/__init__.pyi,sha256=tIcusRqjD5cbw9gURA6V6gJS3kotd6qBxua-WeuUSfg,135 +mypy/typeshed/third_party/2and3/pynamodb/connection/base.pyi,sha256=sxYoLMeE_H8AnA4h5jg3wk10NTFhjwW26X-5sYAGh0A,5688 +mypy/typeshed/third_party/2and3/pynamodb/connection/table.pyi,sha256=1x1g_cKw7jsLSyundv4lilx-J9cqbOSZHx5-BAG8ehI,3117 +mypy/typeshed/third_party/2and3/pynamodb/connection/util.pyi,sha256=VelfJ8xvQieSdjx4hkp5g0W73tyArG2qobRxY2xccWs,67 +mypy/typeshed/third_party/2and3/pynamodb/constants.pyi,sha256=2DxSY2CwYrKx_uT0QKHorzmekcf6bcKWxQ5lZp6PRco,3038 +mypy/typeshed/third_party/2and3/pynamodb/exceptions.pyi,sha256=oN2x-x1qyp5WVRK-jF9rVjzQIHiUjNO5RAwfRTQSRdA,887 +mypy/typeshed/third_party/2and3/pynamodb/indexes.pyi,sha256=mhokZF-5d0rhjRKYeBW-32YKGP__WEI6JH-EaIL04sA,982 +mypy/typeshed/third_party/2and3/pynamodb/models.pyi,sha256=lBQYUpOzjMyeUE0iwvXAXU_cKSUivSOlD8RJavjIXfc,5315 +mypy/typeshed/third_party/2and3/pynamodb/settings.pyi,sha256=nfytWdsaKGyoTVPsIi0B-15yecRvNQ61Y3L_sT0qpvo,145 +mypy/typeshed/third_party/2and3/pynamodb/throttle.pyi,sha256=Xnxx2caEi3AgLinoHSCVZUkuEPV5XxwMw83tpUaUvRk,472 +mypy/typeshed/third_party/2and3/pynamodb/types.pyi,sha256=BCI-zF5K_mOWPzGVixMvVXqISqSxWokGjR0aVosyvK0,57 +mypy/typeshed/third_party/2and3/pyre_extensions.pyi,sha256=CJ0jUa1yruR4a_cVqcFRpORBpYGea9C5vQ5lwGfWUZI,267 +mypy/typeshed/third_party/2and3/pytz/__init__.pyi,sha256=kmVXgRYG38uW2M6cYXejTeREJRtLefdLmepFmeRKBrM,1891 +mypy/typeshed/third_party/2and3/redis/__init__.pyi,sha256=cQcQyMinLIVsLOGskELjv_Agufbrs2L8MmALlSmIT-o,868 +mypy/typeshed/third_party/2and3/redis/client.pyi,sha256=lKi09cOXTFrZASS94jRaPPFFuoFx7qeCah2iAiujUd0,15673 +mypy/typeshed/third_party/2and3/redis/connection.pyi,sha256=UP7WarBfiWN6599FjBIf2NV9q3s4BayxXceAlb3G33M,4153 +mypy/typeshed/third_party/2and3/redis/exceptions.pyi,sha256=d2fmJa9u5GrrAaST8JgdfpFsBxKupvKLb2iH9VgP7Wg,569 +mypy/typeshed/third_party/2and3/redis/utils.pyi,sha256=a5cyDCASB0E1ZuBKK33dZI7ZBcr2rISkiWU5alhjJbA,136 +mypy/typeshed/third_party/2and3/requests/__init__.pyi,sha256=KtUpzptRMgOijMC-6PbKESwpNWOnGTELcxq1RXjJezs,1224 +mypy/typeshed/third_party/2and3/requests/adapters.pyi,sha256=si1mMQFxITVPc7mxlP1KLfpe8PCmmQo9hxYNl5gUZks,3163 +mypy/typeshed/third_party/2and3/requests/api.pyi,sha256=41gP52QREK0ycP7eHwCmIzOD967PEEsWHMMmVG9DEd8,1345 +mypy/typeshed/third_party/2and3/requests/auth.pyi,sha256=sk4UbsbZ8Wza_Dpe9oqV4Mjj3I2stPIYg6CtAz5N_pY,1223 +mypy/typeshed/third_party/2and3/requests/compat.pyi,sha256=G6ucuepQZdex0HVSb9sTjwtWX3zb8NqFyOWiPED5HNc,123 +mypy/typeshed/third_party/2and3/requests/cookies.pyi,sha256=MwbAWME5WUYBFuSG33q_LVqFTRQa3xl59ve1wnwFjVA,2084 +mypy/typeshed/third_party/2and3/requests/exceptions.pyi,sha256=YozRqkXsLqpB5UmK-NDcAAvy0_Pa4ZU14mjy8YOO1zc,1003 +mypy/typeshed/third_party/2and3/requests/hooks.pyi,sha256=nlXP0EjXm6kzDw2tNbpR7vMa9lhLJRzQI8ooUOwsjD4,156 +mypy/typeshed/third_party/2and3/requests/models.pyi,sha256=7kWuctaIuitDUUmW9pzH6pvoRwbvPi4-KBnS1fmb2IA,4885 +mypy/typeshed/third_party/2and3/requests/packages/__init__.pyi,sha256=cnNTJT8mNb7zJ8vT6jKdpiWxIYAZMw3Qz6frelGgzbs,158 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/__init__.pyi,sha256=lP97SDuYECOVOETj3ds6o_mkJ3lm1qxeyDuRsHNsfts,914 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/_collections.pyi,sha256=zZTO16DSyaA6eqcEThzClmGNF-64eyq13qW5HW0iRuM,1535 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/connection.pyi,sha256=pwGiy0YSD6aS74mh0r1wWNzyzshH-qpiOBgus_krxAg,2056 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/connectionpool.pyi,sha256=6uHs5h-j4ZbT4Mer3tW4VwtBXQrB3qxWq1-npazB2JA,2934 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/contrib/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/exceptions.pyi,sha256=TxvMswYXJdgim9frBpmQbC5q_Cu8SM37vW2ZFrfvH20,1413 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/fields.pyi,sha256=1SH-QByYVWYsk8qB4OE1Q69pEF4TNPkyFvQeLz1v9Yo,524 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/filepost.pyi,sha256=1MxypGegFd4ivHA31bKHZ5w59LK1zOUkql9bSbzsZNM,327 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/packages/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/packages/ssl_match_hostname/__init__.pyi,sha256=8-WNQ8HsF7JWBeN1n0qoPU84HsAouCrHj4R5qrGKrVQ,88 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/packages/ssl_match_hostname/_implementation.pyi,sha256=jAdLMMvdxdszZCIdVGxRZw7i5waIBqb4RqwketJqMr4,81 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/poolmanager.pyi,sha256=VW-eCOt6qlsNSSumYcyh8o3Dhevdl6bxvsd-Ko1o5ao,1308 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/request.pyi,sha256=CLxsSA6nOdRfFUtMIPMNIKf08cGNG4tavx56ujogr6s,520 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/response.pyi,sha256=jtWTDNoEUiBcXS1o7HJurIzYfdN3a3cxAydumNndRtE,1697 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/util/__init__.pyi,sha256=gdALWU7cUUfHw66q9C1KuTgv0Zz7Pu18dVbxAt1yAPI,692 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/util/connection.pyi,sha256=XaFYtI2YyZGnOVivtXsLW6jMSb6FKpfIh3aIQInJLR0,188 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/util/request.pyi,sha256=FwrIbRsbuRdpckHVaQmhVJk_cIdVUw5_6B_PTdnM6Ys,220 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/util/response.pyi,sha256=Q0CWgpQG5zMPxwc0LOr5eQOEfmOqglfpydPfBVxiStc,27 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/util/retry.pyi,sha256=9sIauBI6frxfOykUlxZAMB2kleUEtwqVuoggz1NNoe8,1097 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/util/ssl_.pyi,sha256=yLzaH5LRfBw1bUIxxUGib64ZYGRcjF2ExHs9p_iPEiA,671 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/util/timeout.pyi,sha256=65GBiXGM86KUHgU_U1sA-zV2cDmU8B2K2Dn8oRCOGEI,498 +mypy/typeshed/third_party/2and3/requests/packages/urllib3/util/url.pyi,sha256=WEV3oz9Xl0fmcPfmRYC7U728W1KD8xOEfN23aN-Ul-4,491 +mypy/typeshed/third_party/2and3/requests/sessions.pyi,sha256=pL1ZL0r5LI5_SbKsuUv6K6oiXjpw0O5DAvAN5AhHpuI,5040 +mypy/typeshed/third_party/2and3/requests/status_codes.pyi,sha256=k4doi8u1F4oB1LklkAWib0etH3GU_iXHdaUT6HK8upk,70 +mypy/typeshed/third_party/2and3/requests/structures.pyi,sha256=CmGKEIE3d8rPuMxPFWdZqBTJpyWksz8Amdq0ZYzVZIw,968 +mypy/typeshed/third_party/2and3/requests/utils.pyi,sha256=c_6jLe2gxrc4luT5Op4IkLIE5IOwmmO_-4RsnvBXx20,1771 +mypy/typeshed/third_party/2and3/simplejson/__init__.pyi,sha256=FEB2fWn0G_qYvOWJRgimTocRsxmUlyaTv0e6rDVioUw,539 +mypy/typeshed/third_party/2and3/simplejson/decoder.pyi,sha256=TU5Z2CC1DqO-CIm9ehGmxYl7rTNlnFG98uK2eJsX1yU,234 +mypy/typeshed/third_party/2and3/simplejson/encoder.pyi,sha256=wYlToo_rgl5vJIZTQBAlBvskSIP-g8JVWqtoNEV1nvE,268 +mypy/typeshed/third_party/2and3/simplejson/scanner.pyi,sha256=_AUT1GJRNYopQ98J8rRXtig5nCunjXLoiCf5gN9dpXo,262 +mypy/typeshed/third_party/2and3/singledispatch.pyi,sha256=Afo6MbRNe98wIsDONLYsaqNu62dgo-JvXGO4UFvxlJ8,636 +mypy/typeshed/third_party/2and3/tabulate.pyi,sha256=0xadduNLKRLBczuzd-yw28ataHy9CHknhYlGgtosUVQ,1455 +mypy/typeshed/third_party/2and3/termcolor.pyi,sha256=5SEyDxfbA3hHIeFi-2kadnFUFH4zEZF0V8yuHr7yvaE,452 +mypy/typeshed/third_party/2and3/toml.pyi,sha256=TcGqBh_wJul9FtFNlW7Noq_IY-58LCNTnK6SFOt1TfE,816 +mypy/typeshed/third_party/2and3/tornado/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2and3/tornado/concurrent.pyi,sha256=THaUUH9XW_opc-G528IhDDrf-cOBVx9ZJAQKAgoqr34,1016 +mypy/typeshed/third_party/2and3/tornado/gen.pyi,sha256=WPudybrtny-geS69g62Hkv-NApwTukIA8BrPCn5QzVg,2785 +mypy/typeshed/third_party/2and3/tornado/httpclient.pyi,sha256=XLgPdXTM3eN2gGRk62Lv8ekwUwvLbH7X6V6g8tPV2zA,3035 +mypy/typeshed/third_party/2and3/tornado/httpserver.pyi,sha256=ysryZ2jqWX1DT5Q1KgdDH6o8AJRYHReYl3OHUaqG56Y,1535 +mypy/typeshed/third_party/2and3/tornado/httputil.pyi,sha256=PXOItRr1pVsFu-bYQtyEswgewzVrs9UdnvrCiExCB1U,2856 +mypy/typeshed/third_party/2and3/tornado/ioloop.pyi,sha256=0TA4AI6glp8s6iw66lu2IiEJjAn1_PzjkcEaMmynshM,2797 +mypy/typeshed/third_party/2and3/tornado/locks.pyi,sha256=6LDrW8nuBZLsAe90h1UYs92k_41UjcxE8vpEhc_LBzM,1279 +mypy/typeshed/third_party/2and3/tornado/netutil.pyi,sha256=yhT00BrDQgVukDfek6GB2JfOSfT0Gn8Xm45TKM2ut6I,1349 +mypy/typeshed/third_party/2and3/tornado/process.pyi,sha256=NsnEzaGJtchXD3_1d5-cZ-C2q-h9ocucfLvT575cbrg,662 +mypy/typeshed/third_party/2and3/tornado/tcpserver.pyi,sha256=1N0cm3HUZlN3dfsgzrdYTNMEN3nvGu7r2UsE7WuJQ9Y,556 +mypy/typeshed/third_party/2and3/tornado/testing.pyi,sha256=EFFQ1ZzKA6dq2rfHes_bkkE8gBo3SyEGJvXST4boPlQ,1865 +mypy/typeshed/third_party/2and3/tornado/util.pyi,sha256=8eT1IqgZQAG2ffDTCdkAufpPxgtarCEPwbDua2Nuuqg,1072 +mypy/typeshed/third_party/2and3/tornado/web.pyi,sha256=t7B0ysh9zNmYwdgqwl7E_7MyoBzzj3psqqBOzXroEx0,8851 +mypy/typeshed/third_party/2and3/typing_extensions.pyi,sha256=hVOYEh8HDdmHMZXK72u64Fr2Tdln-xhcaqRVbpHvRZQ,2891 +mypy/typeshed/third_party/2and3/tzlocal/__init__.pyi,sha256=MXyNyx0zUGh3xEdqrx8KqDhfGdt3iySSTYonQEejQQE,105 +mypy/typeshed/third_party/2and3/ujson.pyi,sha256=pbov8VSejaAzkjPPTfUXO2zcDP50A7vCNImIQ5lIZB0,1046 +mypy/typeshed/third_party/2and3/werkzeug/__init__.pyi,sha256=I9BN_q8i2pffnKnhd6Y6riiud3i84JcYaKFMgdJk4nE,5539 +mypy/typeshed/third_party/2and3/werkzeug/_compat.pyi,sha256=Tn3bH2jOVtwItr1zELMKxSOumjLbGJkrCFwxBMfep-E,1139 +mypy/typeshed/third_party/2and3/werkzeug/_internal.pyi,sha256=Xq4DnZz9K5VENC8SpioShEBkyRNovJ1fuvW7cokZjL0,598 +mypy/typeshed/third_party/2and3/werkzeug/_reloader.pyi,sha256=QCQ4dGw3MM4rhwKmKntyLJ7JB-neMbnRuRrm2scpZgE,826 +mypy/typeshed/third_party/2and3/werkzeug/contrib/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2and3/werkzeug/contrib/atom.pyi,sha256=LAPRofmeDhSpU418KTzoATp5cB2D9daWgcgP_A2YrDI,1136 +mypy/typeshed/third_party/2and3/werkzeug/contrib/cache.pyi,sha256=qgcpW-CL-UYiRhzy4fjDOFCxsNI58V4CoTHIrdbL4MQ,3321 +mypy/typeshed/third_party/2and3/werkzeug/contrib/fixers.pyi,sha256=o3bHN0CkC0PHKzXHhU4jADVLNgg7rCDKoYM5p8FC6Go,1660 +mypy/typeshed/third_party/2and3/werkzeug/contrib/iterio.pyi,sha256=2yRg8voINYQF23YfRkpGPXaaaX4jpupooKthKwfX4kU,1202 +mypy/typeshed/third_party/2and3/werkzeug/contrib/jsrouting.pyi,sha256=4s_tRK57Yu_n1O1Zk85Nty48UaBHu6AsgeHHxLTS0ko,325 +mypy/typeshed/third_party/2and3/werkzeug/contrib/limiter.pyi,sha256=qLbYIPMTBsgaYe74m3NerbQ1AkW_57LKwY0iW_zaIXU,192 +mypy/typeshed/third_party/2and3/werkzeug/contrib/lint.pyi,sha256=vnPiJs5jXekVZmugPlmkXITga2URy2gh6vngdxkn_Ls,32 +mypy/typeshed/third_party/2and3/werkzeug/contrib/profiler.pyi,sha256=vxg-JniWQ1JqncYfCJgoIPTB_q5cDd_QDXBI7Do3wCs,449 +mypy/typeshed/third_party/2and3/werkzeug/contrib/securecookie.pyi,sha256=iP2XeB1GU55Yy78HYQ01bGHx1KaoSYeytLp9AbUcQTk,1156 +mypy/typeshed/third_party/2and3/werkzeug/contrib/sessions.pyi,sha256=bJGLH1m0c97ZE8lilpCLYpJRcf-yF0-hXk-FQx2NoWM,1974 +mypy/typeshed/third_party/2and3/werkzeug/contrib/testtools.pyi,sha256=qkbfF22aou-S4L0zODpwyHgKAtzjBGRFNPCaWQVh8Ac,211 +mypy/typeshed/third_party/2and3/werkzeug/contrib/wrappers.pyi,sha256=AdT0yvz1TaiY0mn6zlt_ET3DKsTywVVjkErC769c6L0,603 +mypy/typeshed/third_party/2and3/werkzeug/datastructures.pyi,sha256=2poB8iPWctfuycqosbI2sH03CAckB2WOYQXyLegqSyw,15655 +mypy/typeshed/third_party/2and3/werkzeug/debug/__init__.pyi,sha256=39SwOU3Sbt4KTclv3rvOMAy4YLuUA4YyCQQQDTrVPAw,1330 +mypy/typeshed/third_party/2and3/werkzeug/debug/console.pyi,sha256=i6SUF4dZiIVncm8-LrP5zDqW9UrdsCHKaaE_apnGXdE,1207 +mypy/typeshed/third_party/2and3/werkzeug/debug/repr.pyi,sha256=dqtVFNOfcjINAMzaJ-tHiW6SO37ZwVtVT1J7SS7yWh0,846 +mypy/typeshed/third_party/2and3/werkzeug/debug/tbtools.pyi,sha256=tbrAcENEbWQEOxxSrEKr_5GA3i-OaKn7K5QPA4Sk6TU,1687 +mypy/typeshed/third_party/2and3/werkzeug/exceptions.pyi,sha256=2fkLGhxzQ1pWm6kKtfgH4RAAzHu8Qkdv4fl9TXld9TU,4773 +mypy/typeshed/third_party/2and3/werkzeug/filesystem.pyi,sha256=te3jyfyiDfsnFU0MEYw-wB5jBgWgw4VAbIpQzGAs9Vs,169 +mypy/typeshed/third_party/2and3/werkzeug/formparser.pyi,sha256=cUYLp379rFe85GpYntbHkQ530s5PJ7H624ZmlvD0_B4,3645 +mypy/typeshed/third_party/2and3/werkzeug/http.pyi,sha256=NE-9-1RtHCURH3GT6yVAwfA_yVBvr0LFh-AkxRv5y18,5403 +mypy/typeshed/third_party/2and3/werkzeug/local.pyi,sha256=ZWdRsm--5mtPjtmAH_7-0JBQmvQUfAba_VbReVyAVIg,2315 +mypy/typeshed/third_party/2and3/werkzeug/middleware/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/2and3/werkzeug/middleware/dispatcher.pyi,sha256=LPPa3TX_-SAc1LT1fLZrPOKiab20UscrVyB4SEe6Q3w,455 +mypy/typeshed/third_party/2and3/werkzeug/middleware/http_proxy.pyi,sha256=fOHPrA5Xd1fw4lhKzspqsQmu5Ut3WJyKXWBrIOVESsU,684 +mypy/typeshed/third_party/2and3/werkzeug/middleware/lint.pyi,sha256=9htWl9zsn36wWsOuLdhxChhhF2erFNTP87D1MbyvJEQ,2418 +mypy/typeshed/third_party/2and3/werkzeug/middleware/profiler.pyi,sha256=KQLdRGbOCpeCuKx5w8THQrCUrTbKOxqFL9kwgfstW7M,568 +mypy/typeshed/third_party/2and3/werkzeug/middleware/proxy_fix.pyi,sha256=O9gG_aBKl2x_sdr3-pIlOAKt-bxLdjVOQYsSMYLWu9A,711 +mypy/typeshed/third_party/2and3/werkzeug/middleware/shared_data.pyi,sha256=_2cBW8iHxc0uLMIS-Pik84Ef-xdartbB1Ld2evJFFe8,1294 +mypy/typeshed/third_party/2and3/werkzeug/posixemulation.pyi,sha256=btuSFNg5J9BRiGFeYouO0aEhzYDknmVPvhG_jeLkPRY,198 +mypy/typeshed/third_party/2and3/werkzeug/routing.pyi,sha256=Evphz-4zRBki86RSjQ3c4BMDvvnVllUb6OANhE5My-o,6549 +mypy/typeshed/third_party/2and3/werkzeug/script.pyi,sha256=oYohDSwI8nN9OMby_fj490kvJzELXzdUu-bvGxt2b2M,759 +mypy/typeshed/third_party/2and3/werkzeug/security.pyi,sha256=utyGUghv_u_Rsb4p48VUyXuDJuLo621MJZuafdW4Gd4,524 +mypy/typeshed/third_party/2and3/werkzeug/serving.pyi,sha256=W2P0h6k-asBEe41ub-wSORym8YpsWD8Lrwmi3QcczA8,3706 +mypy/typeshed/third_party/2and3/werkzeug/test.pyi,sha256=pSq4ptcQl1fWr1uZfZ4cwrFikHcNgGZT5TVZxlmcBDs,5957 +mypy/typeshed/third_party/2and3/werkzeug/testapp.pyi,sha256=cscEIXiBYut8yb9dHOzJNsRXY8NqdWfhr4e3skmSVVI,225 +mypy/typeshed/third_party/2and3/werkzeug/urls.pyi,sha256=O_8nH87_Um6aL9wY2wOrqcm-rCK-HAPK7h3F0mSknYI,2887 +mypy/typeshed/third_party/2and3/werkzeug/useragents.pyi,sha256=StrHnvNpfRdxMousAfvxyIAvakN1U4f80KPCYHPmxlM,311 +mypy/typeshed/third_party/2and3/werkzeug/utils.pyi,sha256=74f-taqm60Q8NNsJLY817NCWRfAfdjmlkUONT60esgQ,1942 +mypy/typeshed/third_party/2and3/werkzeug/wrappers.pyi,sha256=EAT__SYxLHhD93nXDNljAy0Ivzgd9Qk3USpGv23WEoY,9108 +mypy/typeshed/third_party/2and3/werkzeug/wsgi.pyi,sha256=N6O9gsVz-6yBc0vUDkiGgTvjGFlLW8-RpkzYu8e_uQE,3082 +mypy/typeshed/third_party/2and3/yaml/__init__.pyi,sha256=nqan2VliSYGqY78fr59aaIzrYJwlQfaKPybGEgdW9T0,5600 +mypy/typeshed/third_party/2and3/yaml/composer.pyi,sha256=ctqdzrSyhbw96dgmXwwstva2sa2eYBwkM8YwgU0EbyQ,595 +mypy/typeshed/third_party/2and3/yaml/constructor.pyi,sha256=cY4NAFmX1nG1wlozNcy5CWH9i80Ug3_Nw_IMQStcd-Y,3703 +mypy/typeshed/third_party/2and3/yaml/cyaml.pyi,sha256=Ab0qQBwsb_nkkacQdTsxcJ7gQU2fFVcJrOakwv0L4q4,2300 +mypy/typeshed/third_party/2and3/yaml/dumper.pyi,sha256=ZMJrjJHEZXqit17aKmVJeEfOXiZKJxASIIk2XNTdCJc,1167 +mypy/typeshed/third_party/2and3/yaml/emitter.pyi,sha256=9TyaKDoT6xQhrY1nldsCE4BAEGM5JMeMVXd6FPLghiw,3787 +mypy/typeshed/third_party/2and3/yaml/error.pyi,sha256=kYhKOUoSrnEQLvgIvG_qmPKgMQ53ADqFHOPPDTlRTs4,535 +mypy/typeshed/third_party/2and3/yaml/events.pyi,sha256=IXJuqeHbEQtHZ4mD36QQ1-CAQaLbKua8JEZ-qh7jPKg,1662 +mypy/typeshed/third_party/2and3/yaml/loader.pyi,sha256=INimmEGx0nrelNWKadpItu9SGDya3bRjxu3f68XU4is,767 +mypy/typeshed/third_party/2and3/yaml/nodes.pyi,sha256=HXEU6EM5Z7O0WqO8hCQbRXW_BCGYAzK68xKTZC5yDJs,685 +mypy/typeshed/third_party/2and3/yaml/parser.pyi,sha256=IeuaYcjmpxrfmFJbGhaqNSZWT3znUhIgo1B7AfX-uCM,1663 +mypy/typeshed/third_party/2and3/yaml/reader.pyi,sha256=mXEQfsWd2gLgND9OEHdjAIj34nATz5ZVpM46hotHzEc,831 +mypy/typeshed/third_party/2and3/yaml/representer.pyi,sha256=3WMYU7TIX_3n1R1Ddk2VhZoFzbI1P1EsdRHAtKBwXEs,2184 +mypy/typeshed/third_party/2and3/yaml/resolver.pyi,sha256=Do-jJBCJlZ0s0bQ3PVJhHomO37BSKhKirCiSWO3_D14,785 +mypy/typeshed/third_party/2and3/yaml/scanner.pyi,sha256=C5zS3RgeC27q0jrqXoGdD-a2S3E6jbsYOJGS_bv-o2Q,3572 +mypy/typeshed/third_party/2and3/yaml/serializer.pyi,sha256=W7c34cgxIFm2Sfu1FKlVlDx1z_7qhFsCyDgL-7xlBFM,665 +mypy/typeshed/third_party/2and3/yaml/tokens.pyi,sha256=lRuHaCHbPMRTOm3WEhanBssRRnJHUiGh1mjNmE4CND8,1792 +mypy/typeshed/third_party/3/contextvars.pyi,sha256=pB3s9rSQNfwqsPqxzsibNl7X0urHvfbXBuP5Cx-3614,1123 +mypy/typeshed/third_party/3/dataclasses.pyi,sha256=qUX_mJDPAvLPEzQHczLg6sgdmiLVjTnHylggXp2cAyo,2462 +mypy/typeshed/third_party/3/docutils/__init__.pyi,sha256=BQVUCzV8lCylnmLCtnN0Yz_ttlqyzcLc-BZx2KPXPzM,58 +mypy/typeshed/third_party/3/docutils/examples.pyi,sha256=RBIGH7W0f-yOurXh3ZpXGqhFduPpIVoocbIqpJZZWs4,75 +mypy/typeshed/third_party/3/docutils/nodes.pyi,sha256=pOUg3TzCxxJkcmJ-hsGH_KVreBYXb7Elac53v1zZEto,261 +mypy/typeshed/third_party/3/docutils/parsers/__init__.pyi,sha256=BQVUCzV8lCylnmLCtnN0Yz_ttlqyzcLc-BZx2KPXPzM,58 +mypy/typeshed/third_party/3/docutils/parsers/rst/__init__.pyi,sha256=BQVUCzV8lCylnmLCtnN0Yz_ttlqyzcLc-BZx2KPXPzM,58 +mypy/typeshed/third_party/3/docutils/parsers/rst/nodes.pyi,sha256=BQVUCzV8lCylnmLCtnN0Yz_ttlqyzcLc-BZx2KPXPzM,58 +mypy/typeshed/third_party/3/docutils/parsers/rst/roles.pyi,sha256=TdLW8iyQsN45UF7uCsAYrBGcGPULB6ryN8GnU0_DLaw,419 +mypy/typeshed/third_party/3/docutils/parsers/rst/states.pyi,sha256=RmwcJ4RredmyyFezVwZcD4EwFs6tMXN7XcA04ATDptg,132 +mypy/typeshed/third_party/3/jwt/__init__.pyi,sha256=Gv5iYc-jrWMZ1qCZkZYprHCn16KrFNM516j3rvBny_g,1731 +mypy/typeshed/third_party/3/jwt/algorithms.pyi,sha256=rUxR3pI7cQCMx7kIWxv413ttGxUHnlDTWEZjQrqgbds,2865 +mypy/typeshed/third_party/3/jwt/contrib/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypy/typeshed/third_party/3/jwt/contrib/algorithms/__init__.pyi,sha256=hsCmJQgbRtOrzfpJiSuaGHMOEESmc0gKKaBVMQ_D4Sk,38 +mypy/typeshed/third_party/3/jwt/contrib/algorithms/py_ecdsa.pyi,sha256=WrXDR-ZMe4rsKs8INAW4nvEcaQJWXvz1qk98NWDIh4s,239 +mypy/typeshed/third_party/3/jwt/contrib/algorithms/pycrypto.pyi,sha256=mXxjdkl2_nbD0h69rPF9Jr4qmNZdYcsjvJs4yfbZ0vo,240 +mypy/typeshed/third_party/3/orjson.pyi,sha256=nqG3AeuXH8nyyOSkMTglea9DJdnCAFbe-_yMr-C4QuM,557 +mypy/typeshed/third_party/3/pkg_resources/__init__.pyi,sha256=L2DtQMwU20JjT9PcHR7qN5iHMl2E2khEMk2HSFD3ceg,11971 +mypy/typeshed/third_party/3/pkg_resources/py31compat.pyi,sha256=7C0GC70rjSIh0YBWg7rwrflnvOSx_FYZ0YdA4ZKKd2g,91 +mypy/typeshed/third_party/3/six/__init__.pyi,sha256=ICP2eDswSr-rXomRHEin3_oe3G5EQK4_ppq-0-1clVk,4184 +mypy/typeshed/third_party/3/six/moves/BaseHTTPServer.pyi,sha256=vtBUJUabTrIVK97Cn0MhLUhHSlbmHB8QgQlWwadH-6w,26 +mypy/typeshed/third_party/3/six/moves/CGIHTTPServer.pyi,sha256=vtBUJUabTrIVK97Cn0MhLUhHSlbmHB8QgQlWwadH-6w,26 +mypy/typeshed/third_party/3/six/moves/SimpleHTTPServer.pyi,sha256=vtBUJUabTrIVK97Cn0MhLUhHSlbmHB8QgQlWwadH-6w,26 +mypy/typeshed/third_party/3/six/moves/__init__.pyi,sha256=Ny26MEEbEL3itX3L7pTrP10BVYG4axRCa_OvRpmgSbU,2302 +mypy/typeshed/third_party/3/six/moves/_dummy_thread.pyi,sha256=QcsaN0JxBr9ArwQnzhmN06G8dMTpqIuIbapJvWWr8IQ,28 +mypy/typeshed/third_party/3/six/moves/_thread.pyi,sha256=An3Es1KPMtE47GK-HKV_WnuG7kfoT5bh-bn_SfOQ5Pc,22 +mypy/typeshed/third_party/3/six/moves/builtins.pyi,sha256=VVjpGGLJ2CYwC3lYePGY6TLTEhwcdru3YV-nV2ZAzL8,23 +mypy/typeshed/third_party/3/six/moves/cPickle.pyi,sha256=pezOsQZrW9XS1R09Ote5u1Wtw9FHC0k8Kjp4g44_PgI,21 +mypy/typeshed/third_party/3/six/moves/collections_abc.pyi,sha256=9kznK-Qq5Rqt-V--bq6awTNs5NISIlTFiOZLVI4BvBA,30 +mypy/typeshed/third_party/3/six/moves/configparser.pyi,sha256=Wp5Y7Z134PHLahfawLJDB7WyIBpdLooaGKLQmEr7veQ,27 +mypy/typeshed/third_party/3/six/moves/email_mime_base.pyi,sha256=WcWEleCKHROrfdXpRuKABrT_Va1hx90NY_kxYeul3Sk,30 +mypy/typeshed/third_party/3/six/moves/email_mime_multipart.pyi,sha256=HRKWFU9qh95-mEE22_2NzEKL6lx7ynvhcfHjUcYWuZ8,35 +mypy/typeshed/third_party/3/six/moves/email_mime_nonmultipart.pyi,sha256=n5hD7R_rktJj3hiHYzEqr3CJCHSW4ikfObKHmUrXBw0,38 +mypy/typeshed/third_party/3/six/moves/email_mime_text.pyi,sha256=M7mb9V3f5JUut8yf8UfL3rG4XPr-Lr692DGjk1OR9d4,30 +mypy/typeshed/third_party/3/six/moves/html_entities.pyi,sha256=YkFcpA-UjTm7ps8gp1Xs6Ye9eu-fRHUlSrZPc00LZuk,28 +mypy/typeshed/third_party/3/six/moves/html_parser.pyi,sha256=EhnBFGx0nBd-ZHMy53ihoemWud0xnNYYYzQDrqWZ7SM,26 +mypy/typeshed/third_party/3/six/moves/http_client.pyi,sha256=a-UAXTgUTrJNFFiQWThbgVvOsqCJXXiFTxjOG4QgbiE,26 +mypy/typeshed/third_party/3/six/moves/http_cookiejar.pyi,sha256=_qfFwqs5DnvAOqLWCAdCzWjnwVFi2tkRjypRcow1Kgw,29 +mypy/typeshed/third_party/3/six/moves/http_cookies.pyi,sha256=dKSPvohzW_QPkOUb0gxj3rsshfRDYb9krTqjID3wN68,27 +mypy/typeshed/third_party/3/six/moves/queue.pyi,sha256=_rNUYjj1lkl5pRaQP4GWCuWEHBSetCgHhvSnWjgBuhk,20 +mypy/typeshed/third_party/3/six/moves/reprlib.pyi,sha256=gzyGHWv3b10R17IbpgllskSTyulpq6RWGb7I5KAbSh0,22 +mypy/typeshed/third_party/3/six/moves/socketserver.pyi,sha256=GWp7BzDMpq3JNfA3H3Pn0iyENzAcy5ufcvuvlkEzmFg,27 +mypy/typeshed/third_party/3/six/moves/tkinter.pyi,sha256=R-kj-ZjyE6cnPhkAhJLQIA2zyggMRHyf4azpH_WtXNo,22 +mypy/typeshed/third_party/3/six/moves/tkinter_commondialog.pyi,sha256=piW_7DIKFPiFl8awGTKEBkW-toBwMu7ySfSgxT39Qsc,35 +mypy/typeshed/third_party/3/six/moves/tkinter_constants.pyi,sha256=sB-tEEYJXZlnQEvgUxsHYFp3yyp3F7NtblS3_hRFVFM,32 +mypy/typeshed/third_party/3/six/moves/tkinter_dialog.pyi,sha256=Lk_TOa4m8kLSRZRs2-zLtgFnpbtkGcs2eu1YgCjNzmM,29 +mypy/typeshed/third_party/3/six/moves/tkinter_filedialog.pyi,sha256=znHuWqubMwXiONWP1bhNRmAXUVcHdXn9B8AqoJu4EgY,33 +mypy/typeshed/third_party/3/six/moves/tkinter_tkfiledialog.pyi,sha256=znHuWqubMwXiONWP1bhNRmAXUVcHdXn9B8AqoJu4EgY,33 +mypy/typeshed/third_party/3/six/moves/tkinter_ttk.pyi,sha256=4JCeiL-sndFy8xykanaUTbW3-ESBr4w8Dd1gOMAvrag,26 +mypy/typeshed/third_party/3/six/moves/urllib/__init__.pyi,sha256=F_1V8NcR4jGkws85IUurYLi4JnGh7_HttdVHvj8cQZM,217 +mypy/typeshed/third_party/3/six/moves/urllib/error.pyi,sha256=Z7qLiQr0btCqsOVy3cAgY_IupiTPQbC1l-5Wh4GEHY0,164 +mypy/typeshed/third_party/3/six/moves/urllib/parse.pyi,sha256=aKLBKufXpDAcEVh2fjisQ2y7PxaYuAzJdfjNAIruQo0,1372 +mypy/typeshed/third_party/3/six/moves/urllib/request.pyi,sha256=sWtUUa1c1wJ0fsqRNJfPMigUCzHwUi3MnWNmwqhtfrM,2356 +mypy/typeshed/third_party/3/six/moves/urllib/response.pyi,sha256=MLuhuwcVdryiGU6pB2rkOWjdFnFcm7NsXJxqFt9-YlI,389 +mypy/typeshed/third_party/3/six/moves/urllib/robotparser.pyi,sha256=WK-Nrt7QFCWmAxfbrK0Mecw9NZur54H8AoYbslX6vSg,66 +mypy/typeshed/third_party/3/six/moves/urllib_error.pyi,sha256=ZLiDEtiqtoYYbNDYF4LjnxKRd_uFft6Yi5QQyNEkZm8,27 +mypy/typeshed/third_party/3/six/moves/urllib_parse.pyi,sha256=PQR8avzMMvUSLV96WLv3J4leuJpKEUBoo7vDzP6M848,27 +mypy/typeshed/third_party/3/six/moves/urllib_request.pyi,sha256=8WFe7ycArSuM6wJfgcXWLDRKNsymd0UlxWlflszb2yk,30 +mypy/typeshed/third_party/3/six/moves/urllib_response.pyi,sha256=dokFMleMVEVFVxBgSkrcn4f4yM7RhR3zkk0iDQGOC_U,31 +mypy/typeshed/third_party/3/six/moves/urllib_robotparser.pyi,sha256=BiNO0kuoX9quQRDQsnPLr04VZLHOj57CmrJJN5OuBn4,33 +mypy/typeshed/third_party/3/typed_ast/__init__.pyi,sha256=HrvIFkUnxFkfLUsfazOwsJcxX79YIiDsZGBb-DhTKhc,124 +mypy/typeshed/third_party/3/typed_ast/ast27.pyi,sha256=qxorPpe4C0c4AQBH0GDWl-9uI1AXn7qnRaEf9Bz6KOE,6985 +mypy/typeshed/third_party/3/typed_ast/ast3.pyi,sha256=ZTn_jD8kGkW_h8FFpCGWJhlManpAy1mEZM-h1qrl6_o,8014 +mypy/typeshed/third_party/3/typed_ast/conversions.pyi,sha256=9kma3lgrje8fPNOjOP-gIHf-rVuyfCdcwD8Jgh4LqWc,84 +mypy/typeshed/third_party/3/waitress/__init__.pyi,sha256=bvVdkmWxz6BQThDvaxKeewWf--LyzW_LuVGxyOO2dfw,290 +mypy/typeshed/third_party/3/waitress/adjustments.pyi,sha256=9uNmjazswFIEUfPlfjHli2xOOP1TRYAZI5EUcHLuH_g,2102 +mypy/typeshed/third_party/3/waitress/buffers.pyi,sha256=BAUmNMbRRvJmXspos4XTqxpGuPcG-m8_52-ZzP1RsBU,2179 +mypy/typeshed/third_party/3/waitress/channel.pyi,sha256=d35mqRX08ZpyE5rf8yUqWMtm5Z682S_-L3OVn98wURo,1923 +mypy/typeshed/third_party/3/waitress/compat.pyi,sha256=aMRkBpVM_IA8NipBmrC55cJnqGCIr7S5iRV9ME5dd38,810 +mypy/typeshed/third_party/3/waitress/parser.pyi,sha256=pswmv9sRI7S5oxXjysroxASBBF5OY3wmo8LPhiG1wrI,1675 +mypy/typeshed/third_party/3/waitress/proxy_headers.pyi,sha256=ayiqnpm4_UrOGjDVKuc7rQgz5MLIKzfESm19Beel9h4,1103 +mypy/typeshed/third_party/3/waitress/receiver.pyi,sha256=4DHTun4Lz9uK5CmWuDdxCmB5WBj0aQRaWRVR4sABYGI,1064 +mypy/typeshed/third_party/3/waitress/rfc7230.pyi,sha256=SB4eh_wX7XEvwTlYoqWNKA03PJ6-XV98kC_3Qp3FI7I,214 +mypy/typeshed/third_party/3/waitress/runner.pyi,sha256=bJ_ck4vArqTuTB_enWPvweWPogFmzl_L4DjNqYH67Cc,488 +mypy/typeshed/third_party/3/waitress/server.pyi,sha256=kZOhtiV2ocgZBOQzFx9DpQNm8wzdWW99n_T0oPoCEeI,3684 +mypy/typeshed/third_party/3/waitress/task.pyi,sha256=MUwHq2_IC3sx8v2DDvK3Jv_KVV-gbN8pKs7yLY4cCrE,2336 +mypy/typeshed/third_party/3/waitress/trigger.pyi,sha256=_qDAwOIp3DrACAVfASNW2Umh49ewraIdkBVO4f10L8w,1078 +mypy/typeshed/third_party/3/waitress/utilities.pyi,sha256=isgM7ODRTX6fqS_tOCBQhI6I6wXRJUf2ah_GoHRO3qI,1853 +mypy/typeshed/third_party/3/waitress/wasyncore.pyi,sha256=hUH5RgtyrTBdvWozB7W1QaXFeCg_43HotNrdfDKkZGQ,4035 +mypy/typestate.py,sha256=Nz96R8wlhXtsQ99L_CKL-91Qd3ocZWK0ddmQS02K67U,12966 +mypy/typetraverser.py,sha256=KptsYvSWufj_fHpLcWAcr-Nqri6e-tmcCmGxyBbPGl4,3097 +mypy/typevars.py,sha256=RnfVHsl1aKOsljlAOkPWDnKcTep7ks8b0CzCxhNn8jw,1694 +mypy/util.py,sha256=wyABXa4T9NvA8-RfIsM2XH3ZLeJHz4MgDSUkl1zA6Sw,26541 +mypy/version.py,sha256=H2b2tpjHBGzSIsNFBLTpmKKklM_Wk1Oj65Z-AacHilg,22 +mypy/visitor.py,sha256=Otb6Jh53FAAzDzo8lzbxgYOcaS3QrehiZSzM44qnTAU,14274 +mypy/xml/mypy-html.css,sha256=-e3IQLmSIuw_RVP8BzyIIsgGg-eOsefWawOg2b3H2KY,1409 +mypy/xml/mypy-html.xslt,sha256=19QUoO3-8HArENuzA1n5sgTiIuUHQEl1YuFy9pJCd3M,3824 +mypy/xml/mypy-txt.xslt,sha256=r94I7UBJQRb-QVytQdPlpRVi4R1AZ49vgf1HN-DPp4k,4686 +mypy/xml/mypy.xsd,sha256=RQw6a6mG9eTaXDT5p2xxLX8rRhfDUyCMCeyDrmLIhdE,2173 +mypyc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypyc/__pycache__/__init__.cpython-39.pyc,, +mypyc/__pycache__/analysis.cpython-39.pyc,, +mypyc/__pycache__/build.cpython-39.pyc,, +mypyc/__pycache__/common.cpython-39.pyc,, +mypyc/__pycache__/crash.cpython-39.pyc,, +mypyc/__pycache__/errors.cpython-39.pyc,, +mypyc/__pycache__/namegen.cpython-39.pyc,, +mypyc/__pycache__/options.cpython-39.pyc,, +mypyc/__pycache__/rt_subtype.cpython-39.pyc,, +mypyc/__pycache__/sametype.cpython-39.pyc,, +mypyc/__pycache__/subtype.cpython-39.pyc,, +mypyc/analysis.py,sha256=DS8aFyhmATbH2Vi1aHxRjgtcdBArjGUPD1aDjsmxM3Y,16784 +mypyc/build.py,sha256=vi9AaFoISzqnyjnkRzht8Ym2jMc-wn7txmdyWsa_98Y,20863 +mypyc/codegen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypyc/codegen/__pycache__/__init__.cpython-39.pyc,, +mypyc/codegen/__pycache__/cstring.cpython-39.pyc,, +mypyc/codegen/__pycache__/emit.cpython-39.pyc,, +mypyc/codegen/__pycache__/emitclass.cpython-39.pyc,, +mypyc/codegen/__pycache__/emitfunc.cpython-39.pyc,, +mypyc/codegen/__pycache__/emitmodule.cpython-39.pyc,, +mypyc/codegen/__pycache__/emitwrapper.cpython-39.pyc,, +mypyc/codegen/cstring.py,sha256=hhvgxZuK_eb55MUmOgMPYSejbiGo_P5YAs2rJTFqj7E,1940 +mypyc/codegen/emit.py,sha256=yFbovP7bI9HcXuSAuppHuRPmb2ezTvKXK2_Mpa5ACnI,33520 +mypyc/codegen/emitclass.py,sha256=yCB_i4V5PQgWILvtOBumMp8HV3354KZnJxZqmju5ItM,33776 +mypyc/codegen/emitfunc.py,sha256=jpFkQupSGavL0ydU9HuJgLqhW9XPnlG3geHpxKSvTPA,18776 +mypyc/codegen/emitmodule.py,sha256=6gZSgst2i5YHtoR4YTtxovk0GWRjvEaFRzxztTQeM-s,43315 +mypyc/codegen/emitwrapper.py,sha256=xwvy7EaFr8aZy4DPtCyvkUg79Xgd2DekMCPMhBGT20A,13188 +mypyc/common.py,sha256=sJUzsaZPG0YzXz7xAkPITsdx2wNX8HNWAIuglOgsfZg,1817 +mypyc/crash.py,sha256=3tjR8gkf3ZaefQZJuEz6-r6V5zpsMceRfFTPc5V05pU,935 +mypyc/doc/Makefile,sha256=i2WHuFlgfyAPEW4ssEP8NY4cOibDJrVjvzSEU8_Ggwc,634 +mypyc/doc/__pycache__/conf.cpython-39.pyc,, +mypyc/doc/bool_operations.rst,sha256=wJPFzR26eSaqxtPopRiGw9f_zC-q1-RIE8W2u36b9Ro,373 +mypyc/doc/compilation_units.rst,sha256=TXycr64XYsR8fCkDo5EI0wugy_UA8bQieM_Mh8dhdKw,826 +mypyc/doc/conf.py,sha256=sHaoCmcXmY6D-s3lGjAk79PYK1Ahuimj_lrI43JoiVI,1851 +mypyc/doc/cpython-timings.md,sha256=XX2UCU8eITd8NbQ6hPaw5WyOMiIfugZFCIUYtOKhHrM,830 +mypyc/doc/dev-intro.md,sha256=bZfoodwAMU8GNyPhJp2GpnQboCWK0KFEa9o-f5TjDlo,19778 +mypyc/doc/dict_operations.rst,sha256=EC6_2t8gd9AEqp_pihLQC-M_RAeQa-Zekfc1IC8XRmc,725 +mypyc/doc/differences_from_python.rst,sha256=BUxTMdt31DjCUEN2fOs6-lDkz4HI6JnrGQMf1FErx1c,8406 +mypyc/doc/float_operations.rst,sha256=Eb1aik7RFFIM2tE24qbtJQ-JI4I2Z3JmpUmFJtyiwqY,378 +mypyc/doc/future.md,sha256=b7HAYGmE6hoLMUG_sGZK7EvNAZa-yG2NYSCdFAO4ekw,1431 +mypyc/doc/getting_started.rst,sha256=EbNOggMLeW9l0bdUnmZYXbN87C5FTD6mwhGl8G570GQ,5611 +mypyc/doc/index.rst,sha256=M-Od_0H_p524nIDx35R3xIz54RCUaHNF-u8Cd9kMiHE,762 +mypyc/doc/int_operations.rst,sha256=t-uWq1VshP_weYZOt7g-JFT7bBrdUEwEXnoE36Jm_ic,873 +mypyc/doc/introduction.rst,sha256=P75IKvKkwK57eOzqq3vtGZ9mXI0-fgv1mCjSEZD-Jao,7109 +mypyc/doc/list_operations.rst,sha256=t6yjI0d0I7EohvWhixVXTIEy6Od4W_4cfuG5E-rrVEE,815 +mypyc/doc/make.bat,sha256=tZPNHaGTFKQ9uaCFT2-S8sWSF1cVAtozIflJjAL6Fsg,795 +mypyc/doc/native_classes.rst,sha256=Pp-t7CaGi0_vZw8h3egB5IMeqIkZbhCtNHojcQkCCzk,4461 +mypyc/doc/native_operations.rst,sha256=GlwS6Vdxvk_O_b2Y5uitTkr7VSBe9ONbc_WZ9p3P7ok,1175 +mypyc/doc/performance_tips_and_tricks.rst,sha256=V7xyh-C8LsqsmcpGh1ssay0dHSxQUBX6UZdf7OCRv_o,8299 +mypyc/doc/set_operations.rst,sha256=u5mposJ9vbUi6uyv1lrK-86O4MUEUVybUNzcTWny_4o,672 +mypyc/doc/str_operations.rst,sha256=aNAtvqhAzHf57RdQTizEKunAn2b8WoOpwwe133E567c,566 +mypyc/doc/tuple_operations.rst,sha256=qt2rQFxaVUMNNRyP1ldTulWOfe3mz3Mt7RROoYun9UQ,681 +mypyc/doc/using_type_annotations.rst,sha256=eRKhp-i6UO5dsu0slKXxXV2aRhQ-PwDAvJKnH_k7Njg,11070 +mypyc/errors.py,sha256=o2bKiFMAnWDRba16pXXYy4yuQkmChaPsnIry7M5F7ak,719 +mypyc/external/googletest/LICENSE,sha256=lwLefkEXqOKyDa-rEf_aWMGYrt4GZAZJa-9nDUCiITg,1475 +mypyc/external/googletest/include/gtest/gtest-death-test.h,sha256=oEAXpmp8n6BNppNEOdWJ5SFx6TsTHx9Ooilzu6pvd7A,11523 +mypyc/external/googletest/include/gtest/gtest-message.h,sha256=ZinCUfHjDlLyLei-DRUMLEO3v2x1iO6Dse8IaRvcIQo,9186 +mypyc/external/googletest/include/gtest/gtest-param-test.h,sha256=qfY-n6X0BZJmdAgfgtEl2e89jco1EKIeNCZ4SFxLOlI,77062 +mypyc/external/googletest/include/gtest/gtest-param-test.h.pump,sha256=NpyIfKfS1aiReGrDVwF0g1kZfb7H46dnOx2V1LL6OzQ,20042 +mypyc/external/googletest/include/gtest/gtest-printers.h,sha256=4xoLRppoMmDFco3penSRrfIfeniw8rwNrUbEKd4nF1k,36806 +mypyc/external/googletest/include/gtest/gtest-spi.h,sha256=URXVqM7TaiC4zsA0gS97DSrCDVEaFH-b7qmw7yfZS1Y,9952 +mypyc/external/googletest/include/gtest/gtest-test-part.h,sha256=UbiqNBwPxmdu8nwpcwv9ist_EVH_6z1iWdwC-E4m1lc,6509 +mypyc/external/googletest/include/gtest/gtest-typed-test.h,sha256=Z86zBBVbIko-TQUfa3UTwrPFUEqBfdSbUbyCFZ3PXyA,10459 +mypyc/external/googletest/include/gtest/gtest.h,sha256=YR-JIlT5RmQ_sfoFo4LZMgPrbcnQTS8RZmHY9bprHfc,85459 +mypyc/external/googletest/include/gtest/gtest_pred_impl.h,sha256=O4O-7-rsRr_-QPxziHCzEKhlF_9DahV-TH5dzVGUrWU,15145 +mypyc/external/googletest/include/gtest/gtest_prod.h,sha256=Spmj2YakW01tmzr1SAnwFcVKqYJ0eTpK4XP1AQ0K0zw,2324 +mypyc/external/googletest/include/gtest/internal/custom/gtest-port.h,sha256=bxpA0nM8YLVd-LFDycgUfpSw88hFonF-tFxCnY-VizI,3143 +mypyc/external/googletest/include/gtest/internal/custom/gtest-printers.h,sha256=UhZH8767CA5tdvbOuXaTdySmVroCsqSR6ga4drHSk7w,2099 +mypyc/external/googletest/include/gtest/internal/custom/gtest.h,sha256=d9pZKYTaGQGi8ZrlaG8z8j5_5ma27M7WyQYH9CsfV9k,1995 +mypyc/external/googletest/include/gtest/internal/gtest-death-test-internal.h,sha256=pH-Yt0nFOuGSo9UOMpouliTV_jLfQt9pISjxeiNz_qs,13429 +mypyc/external/googletest/include/gtest/internal/gtest-filepath.h,sha256=ITSxHGDTFSN-jrr5WsTsR6X8SK41zCG-I4v3XmTdUSM,9603 +mypyc/external/googletest/include/gtest/internal/gtest-internal.h,sha256=k3o-3UCdXmdGL6iR6BnultJQSm8q-y9ynBkCBdh2f_I,47284 +mypyc/external/googletest/include/gtest/internal/gtest-linked_ptr.h,sha256=E1eNfe1J3hQOvx15nt5TXy7Xr7DDxhUcHepURGNjE6w,8424 +mypyc/external/googletest/include/gtest/internal/gtest-param-util-generated.h,sha256=M080D-k0YIwk0URIfMIuVmNX4wl24cks6FoARFPdr-k,192177 +mypyc/external/googletest/include/gtest/internal/gtest-param-util-generated.h.pump,sha256=1vBEXfV8A9hDH8UZGz7O0OIC4c_tOkW7xHjMBip_gX4,9107 +mypyc/external/googletest/include/gtest/internal/gtest-param-util.h,sha256=s2epfRNAs6GAYFD44u0YEjMEFTCj0vL3LguF_gB4dLg,27892 +mypyc/external/googletest/include/gtest/internal/gtest-port-arch.h,sha256=0w_3w9C720YzqfrUfRKHLFV9e_40sgYTM8gzDM7ceiE,3471 +mypyc/external/googletest/include/gtest/internal/gtest-port.h,sha256=UzvP2W4v_SY3iKh56J_tICcS7xWdxvPwOpTfJdzSK3c,90022 +mypyc/external/googletest/include/gtest/internal/gtest-string.h,sha256=b3V_AjXC4N96oGvKZNDQWlsoJsHFzHT5ApjUaN9QtEQ,6968 +mypyc/external/googletest/include/gtest/internal/gtest-tuple.h,sha256=tWJY6_-meMw_DO-_yLRK7OBuCZw-mfaZQBHzvMLWFOw,28617 +mypyc/external/googletest/include/gtest/internal/gtest-tuple.h.pump,sha256=dRNxezLu4o3s-ImlghK6aHwlH5Lw1eyNDwsLRvRId6g,9620 +mypyc/external/googletest/include/gtest/internal/gtest-type-util.h,sha256=fCjK3R_2eofApDo6BtW-2YGaegpfKQIvtpK5iRDs4fM,185666 +mypyc/external/googletest/include/gtest/internal/gtest-type-util.h.pump,sha256=hnSm--oNlLE4imhstBWvnV1NwaSc8pLhRXefDCFO-f0,9317 +mypyc/external/googletest/make/Makefile,sha256=uEze2Zn577H-Noy4YpRoBUKk0MUWRaEvioyWKyp95f4,2045 +mypyc/external/googletest/src/gtest-all.cc,sha256=VorBGfXmQY8fvPvfGF1yRlfX81ObR4ItoimsXQFWJrI,2161 +mypyc/external/googletest/src/gtest-death-test.cc,sha256=dMzpg4yQnBrtozU4BLDHPLXS-cvedFhLT_vCGmw1rQo,50942 +mypyc/external/googletest/src/gtest-filepath.cc,sha256=05oi5GoRLWlzPzaB5j4YmOkBneI5sctPTGGtesLotYA,14553 +mypyc/external/googletest/src/gtest-internal-inl.h,sha256=CZx7w7raKAVq1INo4ziPFuZSvurmXTbq5ppdim7D4Qc,45475 +mypyc/external/googletest/src/gtest-port.cc,sha256=zGE4VEMYbGEqFw0YfZdtnq2qJ7RigoOWwHWyNsEdQKk,42985 +mypyc/external/googletest/src/gtest-printers.cc,sha256=TisATnhXjqHwvy05beB8qTuRYuF0h8etw09mslZLwN0,12625 +mypyc/external/googletest/src/gtest-test-part.cc,sha256=CIP7dtg-ULF6U-ylbW3n5l_MHTmB_Lc24Sm59dAyfAk,4163 +mypyc/external/googletest/src/gtest-typed-test.cc,sha256=vzF19TTkXlZeegs7mur5dLCnLRqDwoChUKAfvGV39AI,3960 +mypyc/external/googletest/src/gtest.cc,sha256=paFL0Z5CjSmSTB-FqAR5zi7AcVShmdLpL7_rTS0Fz-8,195751 +mypyc/external/googletest/src/gtest_main.cc,sha256=oTO8TSAEXgIZqqJEFhoAJuN0h0pVsRZ6JZGYjr-_x18,1765 +mypyc/ir/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypyc/ir/__pycache__/__init__.cpython-39.pyc,, +mypyc/ir/__pycache__/class_ir.cpython-39.pyc,, +mypyc/ir/__pycache__/func_ir.cpython-39.pyc,, +mypyc/ir/__pycache__/module_ir.cpython-39.pyc,, +mypyc/ir/__pycache__/ops.cpython-39.pyc,, +mypyc/ir/__pycache__/rtypes.cpython-39.pyc,, +mypyc/ir/class_ir.py,sha256=mGMjVhskcaCRB0Xi32qVdxVicPC5U7_5BslRCGIbsWk,17687 +mypyc/ir/func_ir.py,sha256=eTLbI0riGj5DHbZkHUV_5y7U3yXdeRwO7MXmVU2SnY8,8413 +mypyc/ir/module_ir.py,sha256=SH0ixc5L12x-HRAN0sxIShbs4xJEF9bXBVChPy8p6Cc,3459 +mypyc/ir/ops.py,sha256=Ck14dmYIE3JsG_Ce9vrx_LSRHs66Wzd1JViaO-Wjcjc,39691 +mypyc/ir/rtypes.py,sha256=17qbisZWmdtOs4eBKYbDRp8BE7SX9UaNdJD8yO7jpJ0,18299 +mypyc/irbuild/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypyc/irbuild/__pycache__/__init__.cpython-39.pyc,, +mypyc/irbuild/__pycache__/builder.cpython-39.pyc,, +mypyc/irbuild/__pycache__/callable_class.cpython-39.pyc,, +mypyc/irbuild/__pycache__/classdef.cpython-39.pyc,, +mypyc/irbuild/__pycache__/context.cpython-39.pyc,, +mypyc/irbuild/__pycache__/env_class.cpython-39.pyc,, +mypyc/irbuild/__pycache__/expression.cpython-39.pyc,, +mypyc/irbuild/__pycache__/for_helpers.cpython-39.pyc,, +mypyc/irbuild/__pycache__/function.cpython-39.pyc,, +mypyc/irbuild/__pycache__/generator.cpython-39.pyc,, +mypyc/irbuild/__pycache__/ll_builder.cpython-39.pyc,, +mypyc/irbuild/__pycache__/main.cpython-39.pyc,, +mypyc/irbuild/__pycache__/mapper.cpython-39.pyc,, +mypyc/irbuild/__pycache__/nonlocalcontrol.cpython-39.pyc,, +mypyc/irbuild/__pycache__/prebuildvisitor.cpython-39.pyc,, +mypyc/irbuild/__pycache__/prepare.cpython-39.pyc,, +mypyc/irbuild/__pycache__/specialize.cpython-39.pyc,, +mypyc/irbuild/__pycache__/statement.cpython-39.pyc,, +mypyc/irbuild/__pycache__/util.cpython-39.pyc,, +mypyc/irbuild/__pycache__/visitor.cpython-39.pyc,, +mypyc/irbuild/__pycache__/vtable.cpython-39.pyc,, +mypyc/irbuild/builder.py,sha256=Nx0fykdOSSIycdNXAZJEsonbdzIPOu4g9e72fPJUcaA,42034 +mypyc/irbuild/callable_class.py,sha256=qaQL9c53RgFzwh67ANdLyBwP-lAG-8y4X9rW4DYd_5U,7871 +mypyc/irbuild/classdef.py,sha256=CO4i5JC7kJjq6QWW-T4rSk-N-FxDy2nf-1P6Gj-Sw0k,22761 +mypyc/irbuild/context.py,sha256=0S1xr_73LIDOqHUvjztDeYPvNkUVkj2v8wn31UqHIAo,6824 +mypyc/irbuild/env_class.py,sha256=XJvknx_4TWYJujknnsSPdkgPJRIjBR9pjcsxFBJA-LM,8684 +mypyc/irbuild/expression.py,sha256=-yN19hRAN94xx0FU1RSpZdq1kZCpUDSwFBZDLOWnNBI,21545 +mypyc/irbuild/for_helpers.py,sha256=Vui3BEOsvZqQHTgm5OqwNjZ_hPJS4a59CzdiZRNIVgs,31409 +mypyc/irbuild/function.py,sha256=SpIVW6bWtxHiC_ZF-aPSc1a46mG6VrcgaSKVo975es8,30246 +mypyc/irbuild/generator.py,sha256=NOg1pN9TWYbWvWA7GLY2Wjw4JrVdIlpyTnABs5fA0HU,15650 +mypyc/irbuild/ll_builder.py,sha256=778dyU06y075gCi2p16RbqzHLfcY2p0iF8RgENObk4U,35824 +mypyc/irbuild/main.py,sha256=VvUQ4-YZI0r_EJmH_N1Zw0_KDj39LZwMWdc2YcaEiKw,4187 +mypyc/irbuild/mapper.py,sha256=ILtGBmMWCbvY-HgHRBJFwexOxv9QSqxuo7_H3J0nifk,6655 +mypyc/irbuild/nonlocalcontrol.py,sha256=pIstL0QSy0co6JXrcmtdzl72bjiiR-pVVQLzcu82ZNc,7395 +mypyc/irbuild/prebuildvisitor.py,sha256=GhK9NQYbKHz8W6jBlF0OHHbOXqhdEN1MCzB2d7fAMa0,6153 +mypyc/irbuild/prepare.py,sha256=rlkHXLeSfNIYfIHmg5pK2zdq0khpDZyAoFZWIgEYsic,12914 +mypyc/irbuild/specialize.py,sha256=RMp1FIJGdF3h1XSqBuCxvcOwmA3f7YYSUsxTqSZY4r4,10432 +mypyc/irbuild/statement.py,sha256=g0uMqdCGFrNVswN9wQeBCB8a5Yo7XDNNtNTmqXbwD0c,24957 +mypyc/irbuild/util.py,sha256=WhNT2tdJaQ2noAbeFChsej8VAQe4dIh7-M4SwhBiZnU,4614 +mypyc/irbuild/visitor.py,sha256=OGcRFNwGzq5IpTf0N5nNfXtNEaBUNtRxf_TjrvMJBPw,12390 +mypyc/irbuild/vtable.py,sha256=boTzs-IzGekwYpaACh4bYVizoYsJrTz9DGJAAoy0LGI,3149 +mypyc/lib-rt/CPy.c,sha256=l4BchCCs_SLdx4Jsx7h_JEoTz5rWrJj3Iqje7ES0KAU,751 +mypyc/lib-rt/CPy.cc,sha256=l4BchCCs_SLdx4Jsx7h_JEoTz5rWrJj3Iqje7ES0KAU,751 +mypyc/lib-rt/CPy.h,sha256=f5_7wfzpOossewb8GKwu5MxgwccXoNLF6l11DekLjMI,58543 +mypyc/lib-rt/__pycache__/setup.cpython-39.pyc,, +mypyc/lib-rt/getargs.c,sha256=DX_CDg69oVroYBlRiUwLqo3gvBed-g1GSVHl7oUhkBY,53147 +mypyc/lib-rt/module_shim.tmpl,sha256=jOXsy3GTuo7uA4hBCNWWAZrwSz03Gc6EHiJR--t7PkA,522 +mypyc/lib-rt/mypyc_util.h,sha256=2n7h-CeX0OqjVW60wbMqs-zQ-dEq3SWB8LD-efKJE1Y,1521 +mypyc/lib-rt/pythonsupport.h,sha256=EaRwnnS3G67gqRw3qasL4BA9tA3jpVNWic7se4JK5rs,11260 +mypyc/lib-rt/setup.py,sha256=2sszWEWBrSaArucZTYk11QsAuMZwgKqVmO4MNxxVqak,518 +mypyc/lib-rt/test_capi.cc,sha256=m9BcwiGWaegosfT5WOIhnvAlv0tMMTAIxCTUNDRMRd0,19484 +mypyc/namegen.py,sha256=Pr3o2YOUdGkaQ1zuLuryROwerZxXzV6zt8i-zTfw90M,4414 +mypyc/options.py,sha256=s02nqa5f3Rj6A-FXhHxqXUjbzXu1rl1DDBHyThJz3jY,690 +mypyc/primitives/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypyc/primitives/__pycache__/__init__.cpython-39.pyc,, +mypyc/primitives/__pycache__/dict_ops.cpython-39.pyc,, +mypyc/primitives/__pycache__/exc_ops.cpython-39.pyc,, +mypyc/primitives/__pycache__/generic_ops.cpython-39.pyc,, +mypyc/primitives/__pycache__/int_ops.cpython-39.pyc,, +mypyc/primitives/__pycache__/list_ops.cpython-39.pyc,, +mypyc/primitives/__pycache__/misc_ops.cpython-39.pyc,, +mypyc/primitives/__pycache__/registry.cpython-39.pyc,, +mypyc/primitives/__pycache__/set_ops.cpython-39.pyc,, +mypyc/primitives/__pycache__/str_ops.cpython-39.pyc,, +mypyc/primitives/__pycache__/tuple_ops.cpython-39.pyc,, +mypyc/primitives/dict_ops.py,sha256=R45vTwLR_e-Vrbteu5DRzveerf5OShWRz7BYeHo8sQw,7184 +mypyc/primitives/exc_ops.py,sha256=2N2dBHuRRiSBYwKj6Jj1t7IznJycPQOZV5RbjreanEg,4094 +mypyc/primitives/generic_ops.py,sha256=0HbYDBlqf1mtTacB1XgGTgYJXf-Cpzf2Sa5R6w_jLxY,9419 +mypyc/primitives/int_ops.py,sha256=21mlWDq6X8P3wStNPAkfOXuNw07qQMXkUns7yedpxAI,4580 +mypyc/primitives/list_ops.py,sha256=Vw0Rf2bqx4Y4NaD552Cs59w-bFsOVC2YTgqImK5HSSk,4976 +mypyc/primitives/misc_ops.py,sha256=ZHWQ9nIK_LqxiwZdOlX9InVf705lWNi1YHOPjrTkJrE,8529 +mypyc/primitives/registry.py,sha256=4qcJHE0u5Dy5TFkNHD3HHVd-ONsvoYRFwvFrZJEk7W0,13264 +mypyc/primitives/set_ops.py,sha256=dmCbVvsdeTdSerhX4z7z1Rwb3P8Be6EqV0F-DrsFw-o,2973 +mypyc/primitives/str_ops.py,sha256=E7ArZa5xTbT0vTODRvAKHycfDCilveAoXzeYa8CoqzY,3349 +mypyc/primitives/tuple_ops.py,sha256=sAj1iEJQA9px3f4uoQnNd_zmQYUv9M1pNSc1sSMCBpU,2020 +mypyc/rt_subtype.py,sha256=i2CyJs9OREEtl1URc7mOlAU2Mkd0IvDCCPAoAGPui78,1956 +mypyc/sametype.py,sha256=g7kYzHXb0h_XLpVkV5EJqX7si7EUiCWYiXWiszLsaOc,2020 +mypyc/subtype.py,sha256=RH6kcsTpHr_WDe3G6o_YnLv5iwEqki7OSmpif3djdd8,2099 +mypyc/test-data/analysis.test,sha256=caDAKXsGAtV87mGr_IgchHtxhkT5TK1aKIvrMcy2RqM,12795 +mypyc/test-data/commandline.test,sha256=ZtgeR8kFG7r6bMxR0IMiMKDDKJQgtdOqEr3XyF_n8CE,4183 +mypyc/test-data/exceptions.test,sha256=IOHJvgAfj5VqUi2jfdV5Qu-9eM_PCvspU8nLnNrvJqE,9887 +mypyc/test-data/fixtures/__pycache__/ir.cpython-39.pyc,, +mypyc/test-data/fixtures/__pycache__/testutil.cpython-39.pyc,, +mypyc/test-data/fixtures/ir.py,sha256=gabhwyOVc6VsHpVTsTvSE0rj8BZzsBuYeEbqEUIm_h0,7962 +mypyc/test-data/fixtures/testutil.py,sha256=7Ghl08Cq85KJZEN3PJOApQJvRZCvEiOnFFE8tEEqiHM,1247 +mypyc/test-data/fixtures/typing-full.pyi,sha256=nHmkB-qJXQq2EqxpQBySqwwFjRptJ2tjqvCDGih76YM,4831 +mypyc/test-data/irbuild-any.test,sha256=AnPPh0MoIZp9jrXDZbu21mt7qw9ogYbAmAe8U9bI7GE,2958 +mypyc/test-data/irbuild-basic.test,sha256=FixYovDXIN9gk3IFJFyf8Jg4VgQLRU4Xj7sCEJ1660s,64545 +mypyc/test-data/irbuild-classes.test,sha256=3lRKnlOQen78DW4RyK24X-t6nnRYyric70UNrv9fe2w,20191 +mypyc/test-data/irbuild-dict.test,sha256=I2BIVlP8NxZr6_OAbeLRcZWHYNz8VPS-lTiuVYcxn6E,5636 +mypyc/test-data/irbuild-generics.test,sha256=WBa5pd5VjihH95vx7ZtZ7jgc_844ul8CEeNe75ZZD0w,2350 +mypyc/test-data/irbuild-lists.test,sha256=p5XrrOSyhYc-P8RtZbjHvi0e-kKnQ0DncM4lpiXe2aY,3824 +mypyc/test-data/irbuild-nested.test,sha256=hdhH9_e2Vb5VkJnjkz4BZ9vPrv-LFQyql-BQTXcLu24,20323 +mypyc/test-data/irbuild-optional.test,sha256=sW-Dmud13gJcrxilp8xTHOgJ1HlLUdV6L3fpuXEX3SE,9454 +mypyc/test-data/irbuild-set.test,sha256=qNpNFLVlSuUkOORYyjwaTEXHryipzo8fM7E8-ap7uPM,4219 +mypyc/test-data/irbuild-statements.test,sha256=4ZQGQRpXdGw_AC3AoAdqszWtJu9ZfmBbrU36_lU5lVc,17695 +mypyc/test-data/irbuild-strip-asserts.test,sha256=VzWURCE2cNGgNvVzm8-htWB-sRp7QpXsj9PzzISomI4,241 +mypyc/test-data/irbuild-try.test,sha256=9IkSphyPI7T9a23hyQJdZZ0Q-nlwfMSSc2_wAAadndM,8616 +mypyc/test-data/irbuild-tuple.test,sha256=BnZRpFDhtQ10GPWQN75MPI3n1icO4YWdyQxA0gxMmJ8,3350 +mypyc/test-data/refcount.test,sha256=d_towsevMtIDRdDxYxXCYVLXIaX6moXWsy9TZRKo9eQ,12904 +mypyc/test-data/run-bench.test,sha256=dCKvWAGTVQrMCYG8cHzGtum05nTBTK6IcFHpDVHP0u0,5633 +mypyc/test-data/run-classes.test,sha256=tLNK4x0ZOt5Kj4J66RFgreAzsKQAaR5lJMVcD1O_18U,26670 +mypyc/test-data/run-functions.test,sha256=TfJCYphhAbPSOJH579m-d0565xh9kxGNTsTUBtquUcw,5013 +mypyc/test-data/run-multimodule.test,sha256=iL2_oCgam-rrRV9G3JIn48ggSs3NgtorJMV8bOi8YQE,12874 +mypyc/test-data/run-mypy-sim.test,sha256=gEFbly0ydcW6ks-ZlIIRdLrszt1UTH1bqpYiXX5611o,3984 +mypyc/test-data/run-traits.test,sha256=QJ45E2HxE0REEyoR5V__pGu0hI-gXUe6FC6yYdJCQl8,5475 +mypyc/test-data/run.test,sha256=2aqYr33FwqmZ-CnyiwX-QtfPdMBH0NlCSABrMdGX3WQ,102713 +mypyc/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypyc/test/__pycache__/__init__.cpython-39.pyc,, +mypyc/test/__pycache__/config.cpython-39.pyc,, +mypyc/test/__pycache__/test_analysis.cpython-39.pyc,, +mypyc/test/__pycache__/test_commandline.cpython-39.pyc,, +mypyc/test/__pycache__/test_emit.cpython-39.pyc,, +mypyc/test/__pycache__/test_emitfunc.cpython-39.pyc,, +mypyc/test/__pycache__/test_emitwrapper.cpython-39.pyc,, +mypyc/test/__pycache__/test_exceptions.cpython-39.pyc,, +mypyc/test/__pycache__/test_external.cpython-39.pyc,, +mypyc/test/__pycache__/test_irbuild.cpython-39.pyc,, +mypyc/test/__pycache__/test_namegen.cpython-39.pyc,, +mypyc/test/__pycache__/test_refcount.cpython-39.pyc,, +mypyc/test/__pycache__/test_run.cpython-39.pyc,, +mypyc/test/__pycache__/test_serialization.cpython-39.pyc,, +mypyc/test/__pycache__/test_tuplename.cpython-39.pyc,, +mypyc/test/__pycache__/testutil.cpython-39.pyc,, +mypyc/test/config.py,sha256=3UpcwPUeyAQLgUlSYGTboB85GA0mvnaiAtX45HycELc,262 +mypyc/test/test_analysis.py,sha256=cc-Eux68F1aY6_R6ngMAvuAzUKdIka_LJQPvwu9Bwus,3178 +mypyc/test/test_commandline.py,sha256=eW2iVxCCRx8JvgqbGW3xuOzHM5YAJt1W56nqX-ToSd0,2457 +mypyc/test/test_emit.py,sha256=q74sOBNpdFkEVBDBe4h7gfSdEIts6oOVqHX923VP2xU,1097 +mypyc/test/test_emitfunc.py,sha256=ERyJHV5jaDJzjgjXUuKpqHXyJsWvnB2TNIFLVyqgJwA,13044 +mypyc/test/test_emitwrapper.py,sha256=MrX-_-jCnVKfuYSy6UCwNGdx-GViUrq_QQfq28IE0uY,2081 +mypyc/test/test_exceptions.py,sha256=S1jIY6qXGIll1cGdUzKHdaJowjSRGMDWFhQRgW_rWc4,1842 +mypyc/test/test_external.py,sha256=N8eRo5YOoUIA9YYUDgi1KOcUPj0i7R8QDals3n6cd3Q,1893 +mypyc/test/test_irbuild.py,sha256=yN4-QHg7j_bdMcg2x79ZWnkaZ3bnFgvk-ESIo2CRroA,1960 +mypyc/test/test_namegen.py,sha256=FLGjyXUb49f0jQlZJWv6Ftir7M_LhP9Arrw-6-xTrQU,1873 +mypyc/test/test_refcount.py,sha256=pCgDtPHe14Da5-XcPbmPruRdn8zpSlGyMPuauitKqUE,1678 +mypyc/test/test_run.py,sha256=38VOekTAkSr8uzrA62_eIiz7gf0kgICUkRRU4HajGXo,11982 +mypyc/test/test_serialization.py,sha256=AOsMfbCwE7BD11zR-NGUaQRC-X8O9ShO_i8wd0Pq4jY,3951 +mypyc/test/test_tuplename.py,sha256=MSAgrfpwFc96pWFfNVJtqNgfXsH0YZPYuXv5fjb6m10,974 +mypyc/test/testutil.py,sha256=y1alr6PcDfCr8cABSzPIkaDWkYj-yDqCxidZGqZcfGI,6955 +mypyc/transform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mypyc/transform/__pycache__/__init__.cpython-39.pyc,, +mypyc/transform/__pycache__/exceptions.cpython-39.pyc,, +mypyc/transform/__pycache__/refcount.cpython-39.pyc,, +mypyc/transform/__pycache__/uninit.cpython-39.pyc,, +mypyc/transform/exceptions.py,sha256=OVrm9R1KcG6d4gy5c485Washg0yYy7Kn7BBMqXxIbaE,3516 +mypyc/transform/refcount.py,sha256=VojuJiE6h8ZcRFtcb8xgRYDMhKhRtTYhcugBnDOgSSs,10165 +mypyc/transform/uninit.py,sha256=EhIBL0uadKQ7Pnj2pyMMydqp0urU5RhxQolzNjXobew,2810 diff --git a/venv/Lib/site-packages/mypy-0.782.dist-info/REQUESTED b/venv/Lib/site-packages/mypy-0.782.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/mypy-0.782.dist-info/WHEEL b/venv/Lib/site-packages/mypy-0.782.dist-info/WHEEL new file mode 100644 index 0000000..b552003 --- /dev/null +++ b/venv/Lib/site-packages/mypy-0.782.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/mypy-0.782.dist-info/entry_points.txt b/venv/Lib/site-packages/mypy-0.782.dist-info/entry_points.txt new file mode 100644 index 0000000..af2634c --- /dev/null +++ b/venv/Lib/site-packages/mypy-0.782.dist-info/entry_points.txt @@ -0,0 +1,6 @@ +[console_scripts] +dmypy = mypy.dmypy.client:console_entry +mypy = mypy.__main__:console_entry +stubgen = mypy.stubgen:main +stubtest = mypy.stubtest:main + diff --git a/venv/Lib/site-packages/mypy-0.782.dist-info/top_level.txt b/venv/Lib/site-packages/mypy-0.782.dist-info/top_level.txt new file mode 100644 index 0000000..a08a669 --- /dev/null +++ b/venv/Lib/site-packages/mypy-0.782.dist-info/top_level.txt @@ -0,0 +1,2 @@ +mypy +mypyc diff --git a/venv/Lib/site-packages/mypy_extensions-0.4.3.dist-info/INSTALLER b/venv/Lib/site-packages/mypy_extensions-0.4.3.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/mypy_extensions-0.4.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/mypy_extensions-0.4.3.dist-info/LICENSE b/venv/Lib/site-packages/mypy_extensions-0.4.3.dist-info/LICENSE new file mode 100644 index 0000000..bdb7786 --- /dev/null +++ b/venv/Lib/site-packages/mypy_extensions-0.4.3.dist-info/LICENSE @@ -0,0 +1,27 @@ +Mypy extensions are licensed under the terms of the MIT license, reproduced below. + += = = = = + +The MIT License + +Copyright (c) 2016-2017 Jukka Lehtosalo and contributors + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + += = = = = diff --git a/venv/Lib/site-packages/mypy_extensions-0.4.3.dist-info/METADATA b/venv/Lib/site-packages/mypy_extensions-0.4.3.dist-info/METADATA new file mode 100644 index 0000000..8892543 --- /dev/null +++ b/venv/Lib/site-packages/mypy_extensions-0.4.3.dist-info/METADATA @@ -0,0 +1,31 @@ +Metadata-Version: 2.1 +Name: mypy-extensions +Version: 0.4.3 +Summary: Experimental type system extensions for programs checked with the mypy typechecker. +Home-page: https://github.com/python/mypy_extensions +Author: The mypy developers +Author-email: jukka.lehtosalo@iki.fi +License: MIT License +Platform: UNKNOWN +Classifier: Development Status :: 2 - Pre-Alpha +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Topic :: Software Development +Requires-Dist: typing (>=3.5.3) ; python_version < "3.5" + +Mypy Extensions +=============== + +The "mypy_extensions" module defines experimental extensions to the +standard "typing" module that are supported by the mypy typechecker. + + diff --git a/venv/Lib/site-packages/mypy_extensions-0.4.3.dist-info/RECORD b/venv/Lib/site-packages/mypy_extensions-0.4.3.dist-info/RECORD new file mode 100644 index 0000000..38f0383 --- /dev/null +++ b/venv/Lib/site-packages/mypy_extensions-0.4.3.dist-info/RECORD @@ -0,0 +1,8 @@ +__pycache__/mypy_extensions.cpython-39.pyc,, +mypy_extensions-0.4.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +mypy_extensions-0.4.3.dist-info/LICENSE,sha256=pQRQ2h1TzXd7gM7XfFj_lqvgzNh5cGvRQsPsIOJF8LQ,1204 +mypy_extensions-0.4.3.dist-info/METADATA,sha256=6AEHeULt1o9wXmnlSNSu3QeQcx4Ywq8OKhB689SG0p4,1155 +mypy_extensions-0.4.3.dist-info/RECORD,, +mypy_extensions-0.4.3.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110 +mypy_extensions-0.4.3.dist-info/top_level.txt,sha256=TllnGWqDoFMhKyTiX9peoF1VC1wmkRgILHdebnubEb8,16 +mypy_extensions.py,sha256=zuwlHRPtDPLvzoQv9-FSryoLKAkKaDIpu14-js2gHOE,5078 diff --git a/venv/Lib/site-packages/mypy_extensions-0.4.3.dist-info/WHEEL b/venv/Lib/site-packages/mypy_extensions-0.4.3.dist-info/WHEEL new file mode 100644 index 0000000..8b701e9 --- /dev/null +++ b/venv/Lib/site-packages/mypy_extensions-0.4.3.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.33.6) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/mypy_extensions-0.4.3.dist-info/top_level.txt b/venv/Lib/site-packages/mypy_extensions-0.4.3.dist-info/top_level.txt new file mode 100644 index 0000000..ee21665 --- /dev/null +++ b/venv/Lib/site-packages/mypy_extensions-0.4.3.dist-info/top_level.txt @@ -0,0 +1 @@ +mypy_extensions diff --git a/venv/Lib/site-packages/mypy_extensions.py b/venv/Lib/site-packages/mypy_extensions.py new file mode 100644 index 0000000..5f9d88e --- /dev/null +++ b/venv/Lib/site-packages/mypy_extensions.py @@ -0,0 +1,166 @@ +"""Defines experimental extensions to the standard "typing" module that are +supported by the mypy typechecker. + +Example usage: + from mypy_extensions import TypedDict +""" + +from typing import Any + +# NOTE: This module must support Python 2.7 in addition to Python 3.x + +import sys +# _type_check is NOT a part of public typing API, it is used here only to mimic +# the (convenient) behavior of types provided by typing module. +from typing import _type_check # type: ignore + + +def _check_fails(cls, other): + try: + if sys._getframe(1).f_globals['__name__'] not in ['abc', 'functools', 'typing']: + # Typed dicts are only for static structural subtyping. + raise TypeError('TypedDict does not support instance and class checks') + except (AttributeError, ValueError): + pass + return False + + +def _dict_new(cls, *args, **kwargs): + return dict(*args, **kwargs) + + +def _typeddict_new(cls, _typename, _fields=None, **kwargs): + total = kwargs.pop('total', True) + if _fields is None: + _fields = kwargs + elif kwargs: + raise TypeError("TypedDict takes either a dict or keyword arguments," + " but not both") + + ns = {'__annotations__': dict(_fields), '__total__': total} + try: + # Setting correct module is necessary to make typed dict classes pickleable. + ns['__module__'] = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + pass + + return _TypedDictMeta(_typename, (), ns) + + +class _TypedDictMeta(type): + def __new__(cls, name, bases, ns, total=True): + # Create new typed dict class object. + # This method is called directly when TypedDict is subclassed, + # or via _typeddict_new when TypedDict is instantiated. This way + # TypedDict supports all three syntaxes described in its docstring. + # Subclasses and instances of TypedDict return actual dictionaries + # via _dict_new. + ns['__new__'] = _typeddict_new if name == 'TypedDict' else _dict_new + tp_dict = super(_TypedDictMeta, cls).__new__(cls, name, (dict,), ns) + + anns = ns.get('__annotations__', {}) + msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" + anns = {n: _type_check(tp, msg) for n, tp in anns.items()} + for base in bases: + anns.update(base.__dict__.get('__annotations__', {})) + tp_dict.__annotations__ = anns + if not hasattr(tp_dict, '__total__'): + tp_dict.__total__ = total + return tp_dict + + __instancecheck__ = __subclasscheck__ = _check_fails + + +TypedDict = _TypedDictMeta('TypedDict', (dict,), {}) +TypedDict.__module__ = __name__ +TypedDict.__doc__ = \ + """A simple typed name space. At runtime it is equivalent to a plain dict. + + TypedDict creates a dictionary type that expects all of its + instances to have a certain set of keys, with each key + associated with a value of a consistent type. This expectation + is not checked at runtime but is only enforced by typecheckers. + Usage:: + + Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str}) + a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK + b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check + assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first') + + The type info could be accessed via Point2D.__annotations__. TypedDict + supports two additional equivalent forms:: + + Point2D = TypedDict('Point2D', x=int, y=int, label=str) + + class Point2D(TypedDict): + x: int + y: int + label: str + + The latter syntax is only supported in Python 3.6+, while two other + syntax forms work for Python 2.7 and 3.2+ + """ + +# Argument constructors for making more-detailed Callables. These all just +# return their type argument, to make them complete noops in terms of the +# `typing` module. + + +def Arg(type=Any, name=None): + """A normal positional argument""" + return type + + +def DefaultArg(type=Any, name=None): + """A positional argument with a default value""" + return type + + +def NamedArg(type=Any, name=None): + """A keyword-only argument""" + return type + + +def DefaultNamedArg(type=Any, name=None): + """A keyword-only argument with a default value""" + return type + + +def VarArg(type=Any): + """A *args-style variadic positional argument""" + return type + + +def KwArg(type=Any): + """A **kwargs-style variadic keyword argument""" + return type + + +# Return type that indicates a function does not return +class NoReturn: pass + + +def trait(cls): + return cls + + +def mypyc_attr(*attrs, **kwattrs): + return lambda x: x + + +# TODO: We may want to try to properly apply this to any type +# variables left over... +class _FlexibleAliasClsApplied: + def __init__(self, val): + self.val = val + + def __getitem__(self, args): + return self.val + + +class _FlexibleAliasCls: + def __getitem__(self, args): + return _FlexibleAliasClsApplied(args[-1]) + + +FlexibleAlias = _FlexibleAliasCls() diff --git a/venv/Lib/site-packages/packaging-23.0.dist-info/INSTALLER b/venv/Lib/site-packages/packaging-23.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/packaging-23.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/packaging-23.0.dist-info/LICENSE b/venv/Lib/site-packages/packaging-23.0.dist-info/LICENSE new file mode 100644 index 0000000..6f62d44 --- /dev/null +++ b/venv/Lib/site-packages/packaging-23.0.dist-info/LICENSE @@ -0,0 +1,3 @@ +This software is made available under the terms of *either* of the licenses +found in LICENSE.APACHE or LICENSE.BSD. Contributions to this software is made +under the terms of *both* these licenses. diff --git a/venv/Lib/site-packages/packaging-23.0.dist-info/LICENSE.APACHE b/venv/Lib/site-packages/packaging-23.0.dist-info/LICENSE.APACHE new file mode 100644 index 0000000..f433b1a --- /dev/null +++ b/venv/Lib/site-packages/packaging-23.0.dist-info/LICENSE.APACHE @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/venv/Lib/site-packages/packaging-23.0.dist-info/LICENSE.BSD b/venv/Lib/site-packages/packaging-23.0.dist-info/LICENSE.BSD new file mode 100644 index 0000000..42ce7b7 --- /dev/null +++ b/venv/Lib/site-packages/packaging-23.0.dist-info/LICENSE.BSD @@ -0,0 +1,23 @@ +Copyright (c) Donald Stufft and individual contributors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/Lib/site-packages/packaging-23.0.dist-info/METADATA b/venv/Lib/site-packages/packaging-23.0.dist-info/METADATA new file mode 100644 index 0000000..7c5087a --- /dev/null +++ b/venv/Lib/site-packages/packaging-23.0.dist-info/METADATA @@ -0,0 +1,98 @@ +Metadata-Version: 2.1 +Name: packaging +Version: 23.0 +Summary: Core utilities for Python packages +Author-email: Donald Stufft +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Apache Software License +Classifier: License :: OSI Approved :: BSD License +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Project-URL: Documentation, https://packaging.pypa.io/ +Project-URL: Source, https://github.com/pypa/packaging + +packaging +========= + +.. start-intro + +Reusable core utilities for various Python Packaging +`interoperability specifications `_. + +This library provides utilities that implement the interoperability +specifications which have clearly one correct behaviour (eg: :pep:`440`) +or benefit greatly from having a single shared implementation (eg: :pep:`425`). + +.. end-intro + +The ``packaging`` project includes the following: version handling, specifiers, +markers, requirements, tags, utilities. + +Documentation +------------- + +The `documentation`_ provides information and the API for the following: + +- Version Handling +- Specifiers +- Markers +- Requirements +- Tags +- Utilities + +Installation +------------ + +Use ``pip`` to install these utilities:: + + pip install packaging + +Discussion +---------- + +If you run into bugs, you can file them in our `issue tracker`_. + +You can also join ``#pypa`` on Freenode to ask questions or get involved. + + +.. _`documentation`: https://packaging.pypa.io/ +.. _`issue tracker`: https://github.com/pypa/packaging/issues + + +Code of Conduct +--------------- + +Everyone interacting in the packaging project's codebases, issue trackers, chat +rooms, and mailing lists is expected to follow the `PSF Code of Conduct`_. + +.. _PSF Code of Conduct: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md + +Contributing +------------ + +The ``CONTRIBUTING.rst`` file outlines how to contribute to this project as +well as how to report a potential security issue. The documentation for this +project also covers information about `project development`_ and `security`_. + +.. _`project development`: https://packaging.pypa.io/en/latest/development/ +.. _`security`: https://packaging.pypa.io/en/latest/security/ + +Project History +--------------- + +Please review the ``CHANGELOG.rst`` file or the `Changelog documentation`_ for +recent changes and project history. + +.. _`Changelog documentation`: https://packaging.pypa.io/en/latest/changelog/ + diff --git a/venv/Lib/site-packages/packaging-23.0.dist-info/RECORD b/venv/Lib/site-packages/packaging-23.0.dist-info/RECORD new file mode 100644 index 0000000..c62960b --- /dev/null +++ b/venv/Lib/site-packages/packaging-23.0.dist-info/RECORD @@ -0,0 +1,34 @@ +packaging-23.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +packaging-23.0.dist-info/LICENSE,sha256=ytHvW9NA1z4HS6YU0m996spceUDD2MNIUuZcSQlobEg,197 +packaging-23.0.dist-info/LICENSE.APACHE,sha256=DVQuDIgE45qn836wDaWnYhSdxoLXgpRRKH4RuTjpRZQ,10174 +packaging-23.0.dist-info/LICENSE.BSD,sha256=tw5-m3QvHMb5SLNMFqo5_-zpQZY2S8iP8NIYDwAo-sU,1344 +packaging-23.0.dist-info/METADATA,sha256=RFXOWcbEEITO7DWWyhtk55j4BGh7QaKb2VqL0TF8Y_4,3054 +packaging-23.0.dist-info/RECORD,, +packaging-23.0.dist-info/WHEEL,sha256=rSgq_JpHF9fHR1lx53qwg_1-2LypZE_qmcuXbVUq948,81 +packaging/__init__.py,sha256=7BlJ_DcIt1zv01UQcZLozidczzNcivKj66zIBkRL3R4,501 +packaging/__pycache__/__init__.cpython-39.pyc,, +packaging/__pycache__/_elffile.cpython-39.pyc,, +packaging/__pycache__/_manylinux.cpython-39.pyc,, +packaging/__pycache__/_musllinux.cpython-39.pyc,, +packaging/__pycache__/_parser.cpython-39.pyc,, +packaging/__pycache__/_structures.cpython-39.pyc,, +packaging/__pycache__/_tokenizer.cpython-39.pyc,, +packaging/__pycache__/markers.cpython-39.pyc,, +packaging/__pycache__/requirements.cpython-39.pyc,, +packaging/__pycache__/specifiers.cpython-39.pyc,, +packaging/__pycache__/tags.cpython-39.pyc,, +packaging/__pycache__/utils.cpython-39.pyc,, +packaging/__pycache__/version.cpython-39.pyc,, +packaging/_elffile.py,sha256=hbmK8OD6Z7fY6hwinHEUcD1by7czkGiNYu7ShnFEk2k,3266 +packaging/_manylinux.py,sha256=uZ821PBqQrokhUbwe7E0UodEraMHqzoSgTvfJ8MIl30,8813 +packaging/_musllinux.py,sha256=mvPk7FNjjILKRLIdMxR7IvJ1uggLgCszo-L9rjfpi0M,2524 +packaging/_parser.py,sha256=jjFjSqNf7W2-Ta6YUkywK0P4d2i0Bz_MqLOfl7O1Tkw,9399 +packaging/_structures.py,sha256=q3eVNmbWJGG_S0Dit_S3Ao8qQqz_5PYTXFAKBZe5yr4,1431 +packaging/_tokenizer.py,sha256=czGibL-4oPofx1pCSt_hrozNbHlOPrqGv6m-0d-iTdo,5148 +packaging/markers.py,sha256=HDPXE0_MPBSwsw_9upez8t8mdrqUGrgiOG_qyQy-W30,8161 +packaging/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +packaging/requirements.py,sha256=4nOKheaBbVEQXTGSqaOGTy1Tkg7J_sEno3u8jxC-baw,3264 +packaging/specifiers.py,sha256=-3ajZ5CkQrjNW5H8NPjvCV2RBgr-w9wcYBdb8kjPBfg,39046 +packaging/tags.py,sha256=fOKnZVfiU3oc9CPSzjJUsMk5VTfgOfpNhWobUH0sAlg,18065 +packaging/utils.py,sha256=es0cCezKspzriQ-3V88h3yJzxz028euV2sUwM61kE-o,4355 +packaging/version.py,sha256=_ULefmddLDLJ9VKRFAXhshEd0zP8OYPhcjCPfYolUbo,16295 diff --git a/venv/Lib/site-packages/packaging-23.0.dist-info/WHEEL b/venv/Lib/site-packages/packaging-23.0.dist-info/WHEEL new file mode 100644 index 0000000..db4a255 --- /dev/null +++ b/venv/Lib/site-packages/packaging-23.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.8.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/venv/Lib/site-packages/pathspec-0.10.3.dist-info/INSTALLER b/venv/Lib/site-packages/pathspec-0.10.3.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/pathspec-0.10.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/pathspec-0.10.3.dist-info/LICENSE b/venv/Lib/site-packages/pathspec-0.10.3.dist-info/LICENSE new file mode 100644 index 0000000..14e2f77 --- /dev/null +++ b/venv/Lib/site-packages/pathspec-0.10.3.dist-info/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/venv/Lib/site-packages/pathspec-0.10.3.dist-info/METADATA b/venv/Lib/site-packages/pathspec-0.10.3.dist-info/METADATA new file mode 100644 index 0000000..c7c8906 --- /dev/null +++ b/venv/Lib/site-packages/pathspec-0.10.3.dist-info/METADATA @@ -0,0 +1,553 @@ +Metadata-Version: 2.1 +Name: pathspec +Version: 0.10.3 +Summary: Utility library for gitignore style pattern matching of file paths. +Home-page: https://github.com/cpburnz/python-pathspec +Author: Caleb P. Burns +Author-email: "Caleb P. Burns" +License: MPL 2.0 +Project-URL: Source Code, https://github.com/cpburnz/python-pathspec +Project-URL: Documentation, https://python-path-specification.readthedocs.io/en/latest/index.html +Project-URL: Issue Tracker, https://github.com/cpburnz/python-pathspec/issues +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Utilities +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE + + +PathSpec +======== + +*pathspec* is a utility library for pattern matching of file paths. So +far this only includes Git's wildmatch pattern matching which itself is +derived from Rsync's wildmatch. Git uses wildmatch for its `gitignore`_ +files. + +.. _`gitignore`: http://git-scm.com/docs/gitignore + + +Tutorial +-------- + +Say you have a "Projects" directory and you want to back it up, but only +certain files, and ignore others depending on certain conditions:: + + >>> import pathspec + >>> # The gitignore-style patterns for files to select, but we're including + >>> # instead of ignoring. + >>> spec_text = """ + ... + ... # This is a comment because the line begins with a hash: "#" + ... + ... # Include several project directories (and all descendants) relative to + ... # the current directory. To reference a directory you must end with a + ... # slash: "/" + ... /project-a/ + ... /project-b/ + ... /project-c/ + ... + ... # Patterns can be negated by prefixing with exclamation mark: "!" + ... + ... # Ignore temporary files beginning or ending with "~" and ending with + ... # ".swp". + ... !~* + ... !*~ + ... !*.swp + ... + ... # These are python projects so ignore compiled python files from + ... # testing. + ... !*.pyc + ... + ... # Ignore the build directories but only directly under the project + ... # directories. + ... !/*/build/ + ... + ... """ + +We want to use the ``GitWildMatchPattern`` class to compile our patterns. The +``PathSpec`` class provides an interface around pattern implementations:: + + >>> spec = pathspec.PathSpec.from_lines(pathspec.patterns.GitWildMatchPattern, spec_text.splitlines()) + +That may be a mouthful but it allows for additional patterns to be implemented +in the future without them having to deal with anything but matching the paths +sent to them. ``GitWildMatchPattern`` is the implementation of the actual +pattern which internally gets converted into a regular expression. ``PathSpec`` +is a simple wrapper around a list of compiled patterns. + +To make things simpler, we can use the registered name for a pattern class +instead of always having to provide a reference to the class itself. The +``GitWildMatchPattern`` class is registered as **gitwildmatch**:: + + >>> spec = pathspec.PathSpec.from_lines('gitwildmatch', spec_text.splitlines()) + +If we wanted to manually compile the patterns we can just do the following:: + + >>> patterns = map(pathspec.patterns.GitWildMatchPattern, spec_text.splitlines()) + >>> spec = PathSpec(patterns) + +``PathSpec.from_lines()`` is simply a class method which does just that. + +If you want to load the patterns from file, you can pass the file instance +directly as well:: + + >>> with open('patterns.list', 'r') as fh: + >>> spec = pathspec.PathSpec.from_lines('gitwildmatch', fh) + +You can perform matching on a whole directory tree with:: + + >>> matches = spec.match_tree('path/to/directory') + +Or you can perform matching on a specific set of file paths with:: + + >>> matches = spec.match_files(file_paths) + +Or check to see if an individual file matches:: + + >>> is_matched = spec.match_file(file_path) + +There is a specialized class, ``pathspec.GitIgnoreSpec``, which more closely +implements the behavior of **gitignore**. This uses ``GitWildMatchPattern`` +pattern by default and handles some edge cases differently from the generic +``PathSpec`` class. ``GitIgnoreSpec`` can be used without specifying the pattern +factory:: + + >>> spec = pathspec.GitIgnoreSpec.from_lines(spec_text.splitlines()) + + +License +------- + +*pathspec* is licensed under the `Mozilla Public License Version 2.0`_. See +`LICENSE`_ or the `FAQ`_ for more information. + +In summary, you may use *pathspec* with any closed or open source project +without affecting the license of the larger work so long as you: + +- give credit where credit is due, + +- and release any custom changes made to *pathspec*. + +.. _`Mozilla Public License Version 2.0`: http://www.mozilla.org/MPL/2.0 +.. _`LICENSE`: LICENSE +.. _`FAQ`: http://www.mozilla.org/MPL/2.0/FAQ.html + + +Source +------ + +The source code for *pathspec* is available from the GitHub repo +`cpburnz/python-pathspec`_. + +.. _`cpburnz/python-pathspec`: https://github.com/cpburnz/python-pathspec + + +Installation +------------ + +*pathspec* is available for install through `PyPI`_:: + + pip install pathspec + +*pathspec* can also be built from source. The following packages will be +required: + +- `build`_ (>=0.6.0) +- `setuptools`_ (>=40.8.0) + +*pathspec* can then be built and installed with:: + + python -m build + pip install dist/pathspec-*-py3-none-any.whl + +.. _`PyPI`: http://pypi.python.org/pypi/pathspec +.. _`build`: https://pypi.org/project/build/ +.. _`setuptools`: https://pypi.org/project/setuptools/ + + +Documentation +------------- + +Documentation for *pathspec* is available on `Read the Docs`_. + +.. _`Read the Docs`: https://python-path-specification.readthedocs.io + + +Other Languages +--------------- + +The related project `pathspec-ruby`_ (by *highb*) provides a similar library as +a `Ruby gem`_. + +.. _`pathspec-ruby`: https://github.com/highb/pathspec-ruby +.. _`Ruby gem`: https://rubygems.org/gems/pathspec + + + +Change History +============== + + +0.10.3 (2022-12-09) +------------------- + +New features: + +- Added utility function `pathspec.util.append_dir_sep()` to aid in distinguishing between directories and files on the file-system. See `Issue #65`_. + +Bug fixes: + +- `Issue #66`_/`Pull #67`_: Package not marked as py.typed. +- `Issue #68`_: Exports are considered private. +- `Issue #70`_/`Pull #71`_: 'Self' string literal type is Unknown in pyright. + +Improvements: + +- `Issue #65`_: Checking directories via match_file() does not work on Path objects. + + +.. _`Issue #65`: https://github.com/cpburnz/python-pathspec/issues/65 +.. _`Issue #66`: https://github.com/cpburnz/python-pathspec/issues/66 +.. _`Pull #67`: https://github.com/cpburnz/python-pathspec/pull/67 +.. _`Issue #68`: https://github.com/cpburnz/python-pathspec/issues/68 +.. _`Issue #70`: https://github.com/cpburnz/python-pathspec/issues/70 +.. _`Pull #71`: https://github.com/cpburnz/python-pathspec/pull/71 + + +0.10.2 (2022-11-12) +------------------- + +Bug fixes: + +- Fix failing tests on Windows. +- Type hint on *root* parameter on `pathspec.pathspec.PathSpec.match_tree_entries()`. +- Type hint on *root* parameter on `pathspec.pathspec.PathSpec.match_tree_files()`. +- Type hint on *root* parameter on `pathspec.util.iter_tree_entries()`. +- Type hint on *root* parameter on `pathspec.util.iter_tree_files()`. +- `Issue #64`_: IndexError with my .gitignore file when trying to build a Python package. + +Improvements: + +- `Pull #58`_: CI: add GitHub Actions test workflow. + + +.. _`Pull #58`: https://github.com/cpburnz/python-pathspec/pull/58 +.. _`Issue #64`: https://github.com/cpburnz/python-pathspec/issues/64 + + +0.10.1 (2022-09-02) +------------------- + +Bug fixes: + +- Fix documentation on `pathspec.pattern.RegexPattern.match_file()`. +- `Pull #60`_: Remove redundant wheel dep from pyproject.toml. +- `Issue #61`_: Dist failure for Fedora, CentOS, EPEL. +- `Issue #62`_: Since version 0.10.0 pure wildcard does not work in some cases. + +Improvements: + +- Restore support for legacy installations using `setup.py`. See `Issue #61`_. + + +.. _`Pull #60`: https://github.com/cpburnz/python-pathspec/pull/60 +.. _`Issue #61`: https://github.com/cpburnz/python-pathspec/issues/61 +.. _`Issue #62`: https://github.com/cpburnz/python-pathspec/issues/62 + + +0.10.0 (2022-08-30) +------------------- + +Major changes: + +- Dropped support of EOL Python 2.7, 3.5, 3.6. See `Issue #47`_. +- The *gitwildmatch* pattern `dir/*` is now handled the same as `dir/`. This means `dir/*` will now match all descendants rather than only direct children. See `Issue #19`_. +- Added `pathspec.GitIgnoreSpec` class (see new features). +- Changed build system to `pyproject.toml`_ and build backend to `setuptools.build_meta`_ which may have unforeseen consequences. +- Renamed GitHub project from `python-path-specification`_ to `python-pathspec`_. See `Issue #35`_. + +API changes: + +- Deprecated: `pathspec.util.match_files()` is an old function no longer used. +- Deprecated: `pathspec.match_files()` is an old function no longer used. +- Deprecated: `pathspec.util.normalize_files()` is no longer used. +- Deprecated: `pathspec.util.iter_tree()` is an alias for `pathspec.util.iter_tree_files()`. +- Deprecated: `pathspec.iter_tree()` is an alias for `pathspec.util.iter_tree_files()`. +- Deprecated: `pathspec.pattern.Pattern.match()` is no longer used. Use or implement + `pathspec.pattern.Pattern.match_file()`. + +New features: + +- Added class `pathspec.gitignore.GitIgnoreSpec` (with alias `pathspec.GitIgnoreSpec`) to implement *gitignore* behavior not possible with standard `PathSpec` class. The particular *gitignore* behavior implemented is prioritizing patterns matching the file directly over matching an ancestor directory. + +Bug fixes: + +- `Issue #19`_: Files inside an ignored sub-directory are not matched. +- `Issue #41`_: Incorrectly (?) matches files inside directories that do match. +- `Pull #51`_: Refactor deprecated unittest aliases for Python 3.11 compatibility. +- `Issue #53`_: Symlink pathspec_meta.py breaks Windows. +- `Issue #54`_: test_util.py uses os.symlink which can fail on Windows. +- `Issue #55`_: Backslashes at start of pattern not handled correctly. +- `Pull #56`_: pyproject.toml: include subpackages in setuptools config +- `Issue #57`_: `!` doesn't exclude files in directories if the pattern doesn't have a trailing slash. + +Improvements: + +- Support Python 3.10, 3.11. +- Modernize code to Python 3.7. +- `Issue #52`_: match_files() is not a pure generator function, and it impacts tree_*() gravely. + + +.. _`python-path-specification`: https://github.com/cpburnz/python-path-specification +.. _`python-pathspec`: https://github.com/cpburnz/python-pathspec +.. _`pyproject.toml`: https://pip.pypa.io/en/stable/reference/build-system/pyproject-toml/ +.. _`setuptools.build_meta`: https://setuptools.pypa.io/en/latest/build_meta.html +.. _`Issue #19`: https://github.com/cpburnz/python-pathspec/issues/19 +.. _`Issue #35`: https://github.com/cpburnz/python-pathspec/issues/35 +.. _`Issue #41`: https://github.com/cpburnz/python-pathspec/issues/41 +.. _`Issue #47`: https://github.com/cpburnz/python-pathspec/issues/47 +.. _`Pull #51`: https://github.com/cpburnz/python-pathspec/pull/51 +.. _`Issue #52`: https://github.com/cpburnz/python-pathspec/issues/52 +.. _`Issue #53`: https://github.com/cpburnz/python-pathspec/issues/53 +.. _`Issue #54`: https://github.com/cpburnz/python-pathspec/issues/54 +.. _`Issue #55`: https://github.com/cpburnz/python-pathspec/issues/55 +.. _`Pull #56`: https://github.com/cpburnz/python-pathspec/pull/56 +.. _`Issue #57`: https://github.com/cpburnz/python-pathspec/issues/57 + + +0.9.0 (2021-07-17) +------------------ + +- `Issue #44`_/`Pull #50`_: Raise `GitWildMatchPatternError` for invalid git patterns. +- `Pull #45`_: Fix for duplicate leading double-asterisk, and edge cases. +- `Issue #46`_: Fix matching absolute paths. +- API change: `util.normalize_files()` now returns a `Dict[str, List[pathlike]]` instead of a `Dict[str, pathlike]`. +- Added type hinting. + +.. _`Issue #44`: https://github.com/cpburnz/python-pathspec/issues/44 +.. _`Pull #45`: https://github.com/cpburnz/python-pathspec/pull/45 +.. _`Issue #46`: https://github.com/cpburnz/python-pathspec/issues/46 +.. _`Pull #50`: https://github.com/cpburnz/python-pathspec/pull/50 + + +0.8.1 (2020-11-07) +------------------ + +- `Pull #43`_: Add support for addition operator. + +.. _`Pull #43`: https://github.com/cpburnz/python-pathspec/pull/43 + + +0.8.0 (2020-04-09) +------------------ + +- `Issue #30`_: Expose what patterns matched paths. Added `util.detailed_match_files()`. +- `Issue #31`_: `match_tree()` doesn't return symlinks. +- `Issue #34`_: Support `pathlib.Path`\ s. +- Add `PathSpec.match_tree_entries` and `util.iter_tree_entries()` to support directories and symlinks. +- API change: `match_tree()` has been renamed to `match_tree_files()`. The old name `match_tree()` is still available as an alias. +- API change: `match_tree_files()` now returns symlinks. This is a bug fix but it will change the returned results. + +.. _`Issue #30`: https://github.com/cpburnz/python-pathspec/issues/30 +.. _`Issue #31`: https://github.com/cpburnz/python-pathspec/issues/31 +.. _`Issue #34`: https://github.com/cpburnz/python-pathspec/issues/34 + + +0.7.0 (2019-12-27) +------------------ + +- `Pull #28`_: Add support for Python 3.8, and drop Python 3.4. +- `Pull #29`_: Publish bdist wheel. + +.. _`Pull #28`: https://github.com/cpburnz/python-pathspec/pull/28 +.. _`Pull #29`: https://github.com/cpburnz/python-pathspec/pull/29 + + +0.6.0 (2019-10-03) +------------------ + +- `Pull #24`_: Drop support for Python 2.6, 3.2, and 3.3. +- `Pull #25`_: Update README.rst. +- `Pull #26`_: Method to escape gitwildmatch. + +.. _`Pull #24`: https://github.com/cpburnz/python-pathspec/pull/24 +.. _`Pull #25`: https://github.com/cpburnz/python-pathspec/pull/25 +.. _`Pull #26`: https://github.com/cpburnz/python-pathspec/pull/26 + + +0.5.9 (2018-09-15) +------------------ + +- Fixed file system error handling. + + +0.5.8 (2018-09-15) +------------------ + +- Improved type checking. +- Created scripts to test Python 2.6 because Tox removed support for it. +- Improved byte string handling in Python 3. +- `Issue #22`_: Handle dangling symlinks. + +.. _`Issue #22`: https://github.com/cpburnz/python-pathspec/issues/22 + + +0.5.7 (2018-08-14) +------------------ + +- `Issue #21`_: Fix collections deprecation warning. + +.. _`Issue #21`: https://github.com/cpburnz/python-pathspec/issues/21 + + +0.5.6 (2018-04-06) +------------------ + +- Improved unit tests. +- Improved type checking. +- `Issue #20`_: Support current directory prefix. + +.. _`Issue #20`: https://github.com/cpburnz/python-pathspec/issues/20 + + +0.5.5 (2017-09-09) +------------------ + +- Add documentation link to README. + + +0.5.4 (2017-09-09) +------------------ + +- `Pull #17`_: Add link to Ruby implementation of *pathspec*. +- Add sphinx documentation. + +.. _`Pull #17`: https://github.com/cpburnz/python-pathspec/pull/17 + + +0.5.3 (2017-07-01) +------------------ + +- `Issue #14`_: Fix byte strings for Python 3. +- `Pull #15`_: Include "LICENSE" in source package. +- `Issue #16`_: Support Python 2.6. + +.. _`Issue #14`: https://github.com/cpburnz/python-pathspec/issues/14 +.. _`Pull #15`: https://github.com/cpburnz/python-pathspec/pull/15 +.. _`Issue #16`: https://github.com/cpburnz/python-pathspec/issues/16 + + +0.5.2 (2017-04-04) +------------------ + +- Fixed change log. + + +0.5.1 (2017-04-04) +------------------ + +- `Pull #13`_: Add equality methods to `PathSpec` and `RegexPattern`. + +.. _`Pull #13`: https://github.com/cpburnz/python-pathspec/pull/13 + + +0.5.0 (2016-08-22) +------------------ + +- `Issue #12`_: Add `PathSpec.match_file()`. +- Renamed `gitignore.GitIgnorePattern` to `patterns.gitwildmatch.GitWildMatchPattern`. +- Deprecated `gitignore.GitIgnorePattern`. + +.. _`Issue #12`: https://github.com/cpburnz/python-pathspec/issues/12 + + +0.4.0 (2016-07-15) +------------------ + +- `Issue #11`_: Support converting patterns into regular expressions without compiling them. +- API change: Subclasses of `RegexPattern` should implement `pattern_to_regex()`. + +.. _`Issue #11`: https://github.com/cpburnz/python-pathspec/issues/11 + + +0.3.4 (2015-08-24) +------------------ + +- `Pull #7`_: Fixed non-recursive links. +- `Pull #8`_: Fixed edge cases in gitignore patterns. +- `Pull #9`_: Fixed minor usage documentation. +- Fixed recursion detection. +- Fixed trivial incompatibility with Python 3.2. + +.. _`Pull #7`: https://github.com/cpburnz/python-pathspec/pull/7 +.. _`Pull #8`: https://github.com/cpburnz/python-pathspec/pull/8 +.. _`Pull #9`: https://github.com/cpburnz/python-pathspec/pull/9 + + +0.3.3 (2014-11-21) +------------------ + +- Improved documentation. + + +0.3.2 (2014-11-08) +------------------ + +- `Pull #5`_: Use tox for testing. +- `Issue #6`_: Fixed matching Windows paths. +- Improved documentation. +- API change: `spec.match_tree()` and `spec.match_files()` now return iterators instead of sets. + +.. _`Pull #5`: https://github.com/cpburnz/python-pathspec/pull/5 +.. _`Issue #6`: https://github.com/cpburnz/python-pathspec/issues/6 + + +0.3.1 (2014-09-17) +------------------ + +- Updated README. + + +0.3.0 (2014-09-17) +------------------ + +- `Pull #3`_: Fixed trailing slash in gitignore patterns. +- `Pull #4`_: Fixed test for trailing slash in gitignore patterns. +- Added registered patterns. + +.. _`Pull #3`: https://github.com/cpburnz/python-pathspec/pull/3 +.. _`Pull #4`: https://github.com/cpburnz/python-pathspec/pull/4 + + +0.2.2 (2013-12-17) +------------------ + +- Fixed setup.py. + + +0.2.1 (2013-12-17) +------------------ + +- Added tests. +- Fixed comment gitignore patterns. +- Fixed relative path gitignore patterns. + + +0.2.0 (2013-12-07) +------------------ + +- Initial release. diff --git a/venv/Lib/site-packages/pathspec-0.10.3.dist-info/RECORD b/venv/Lib/site-packages/pathspec-0.10.3.dist-info/RECORD new file mode 100644 index 0000000..f4b5520 --- /dev/null +++ b/venv/Lib/site-packages/pathspec-0.10.3.dist-info/RECORD @@ -0,0 +1,23 @@ +pathspec-0.10.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pathspec-0.10.3.dist-info/LICENSE,sha256=-rPda9qyJvHAhjCx3ZF-Efy07F4eAg4sFvg6ChOGPoU,16726 +pathspec-0.10.3.dist-info/METADATA,sha256=zOqsCQOlPmVqWm8rFotNQ7xHKC71LeOZ7Xj7loeUzI4,18106 +pathspec-0.10.3.dist-info/RECORD,, +pathspec-0.10.3.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92 +pathspec-0.10.3.dist-info/top_level.txt,sha256=0NA6IbW6iCUZ4p402IRSyZpvx4yqoltHzMoAxVQHI1M,9 +pathspec/__init__.py,sha256=7SXysmS-FbGnfonqXtaSm6aUKdepQCXdvd4ArWAMJak,1630 +pathspec/__pycache__/__init__.cpython-39.pyc,, +pathspec/__pycache__/_meta.cpython-39.pyc,, +pathspec/__pycache__/gitignore.cpython-39.pyc,, +pathspec/__pycache__/pathspec.cpython-39.pyc,, +pathspec/__pycache__/pattern.cpython-39.pyc,, +pathspec/__pycache__/util.cpython-39.pyc,, +pathspec/_meta.py,sha256=GuiFhU3FrZ5n3__a3jEMW_KdIt6NDQmWEvMxaaHmv4U,2100 +pathspec/gitignore.py,sha256=FWqAgFNwKMCGQdwuUyasYrA_JDKQ6p8X86jaD3rVe0k,3789 +pathspec/pathspec.py,sha256=bV9Ghs8L8Hy-hQuiDThMAX4eG7EtdZMNWnElb-wEjig,8319 +pathspec/pattern.py,sha256=HVpwUuGMAW7WOtgPOkZUmJY-lg84BtWVvkVXcc_ha28,5784 +pathspec/patterns/__init__.py,sha256=vAzIEqBc2KsvWsiszsLCeYQwQVWXIHzbHNgq5TNrPdk,302 +pathspec/patterns/__pycache__/__init__.cpython-39.pyc,, +pathspec/patterns/__pycache__/gitwildmatch.cpython-39.pyc,, +pathspec/patterns/gitwildmatch.py,sha256=nv2Mhwg-QSurHHm0Nw8HLTdOT4NIbNKtFXO0C_aRNhY,12126 +pathspec/py.typed,sha256=wq7wwDeyBungK6DsiV4O-IujgKzARwHz94uQshdpdEU,68 +pathspec/util.py,sha256=RKiojdVtoTmzE90Ya_zz8-kAeW4WJJnk3Y9bLr4PBJg,20184 diff --git a/venv/Lib/site-packages/pathspec-0.10.3.dist-info/WHEEL b/venv/Lib/site-packages/pathspec-0.10.3.dist-info/WHEEL new file mode 100644 index 0000000..57e3d84 --- /dev/null +++ b/venv/Lib/site-packages/pathspec-0.10.3.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.38.4) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/pathspec-0.10.3.dist-info/top_level.txt b/venv/Lib/site-packages/pathspec-0.10.3.dist-info/top_level.txt new file mode 100644 index 0000000..6486958 --- /dev/null +++ b/venv/Lib/site-packages/pathspec-0.10.3.dist-info/top_level.txt @@ -0,0 +1 @@ +pathspec diff --git a/venv/Lib/site-packages/pip-22.3.1.dist-info/INSTALLER b/venv/Lib/site-packages/pip-22.3.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/pip-22.3.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/pip-22.3.1.dist-info/LICENSE.txt b/venv/Lib/site-packages/pip-22.3.1.dist-info/LICENSE.txt new file mode 100644 index 0000000..8e7b65e --- /dev/null +++ b/venv/Lib/site-packages/pip-22.3.1.dist-info/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2008-present The pip developers (see AUTHORS.txt file) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/Lib/site-packages/pip-22.3.1.dist-info/METADATA b/venv/Lib/site-packages/pip-22.3.1.dist-info/METADATA new file mode 100644 index 0000000..e935e1a --- /dev/null +++ b/venv/Lib/site-packages/pip-22.3.1.dist-info/METADATA @@ -0,0 +1,88 @@ +Metadata-Version: 2.1 +Name: pip +Version: 22.3.1 +Summary: The PyPA recommended tool for installing Python packages. +Home-page: https://pip.pypa.io/ +Author: The pip developers +Author-email: distutils-sig@python.org +License: MIT +Project-URL: Documentation, https://pip.pypa.io +Project-URL: Source, https://github.com/pypa/pip +Project-URL: Changelog, https://pip.pypa.io/en/stable/news/ +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Topic :: Software Development :: Build Tools +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Requires-Python: >=3.7 +License-File: LICENSE.txt + +pip - The Python Package Installer +================================== + +.. image:: https://img.shields.io/pypi/v/pip.svg + :target: https://pypi.org/project/pip/ + +.. image:: https://readthedocs.org/projects/pip/badge/?version=latest + :target: https://pip.pypa.io/en/latest + +pip is the `package installer`_ for Python. You can use pip to install packages from the `Python Package Index`_ and other indexes. + +Please take a look at our documentation for how to install and use pip: + +* `Installation`_ +* `Usage`_ + +We release updates regularly, with a new version every 3 months. Find more details in our documentation: + +* `Release notes`_ +* `Release process`_ + +In pip 20.3, we've `made a big improvement to the heart of pip`_; `learn more`_. We want your input, so `sign up for our user experience research studies`_ to help us do it right. + +**Note**: pip 21.0, in January 2021, removed Python 2 support, per pip's `Python 2 support policy`_. Please migrate to Python 3. + +If you find bugs, need help, or want to talk to the developers, please use our mailing lists or chat rooms: + +* `Issue tracking`_ +* `Discourse channel`_ +* `User IRC`_ + +If you want to get involved head over to GitHub to get the source code, look at our development documentation and feel free to jump on the developer mailing lists and chat rooms: + +* `GitHub page`_ +* `Development documentation`_ +* `Development IRC`_ + +Code of Conduct +--------------- + +Everyone interacting in the pip project's codebases, issue trackers, chat +rooms, and mailing lists is expected to follow the `PSF Code of Conduct`_. + +.. _package installer: https://packaging.python.org/guides/tool-recommendations/ +.. _Python Package Index: https://pypi.org +.. _Installation: https://pip.pypa.io/en/stable/installation/ +.. _Usage: https://pip.pypa.io/en/stable/ +.. _Release notes: https://pip.pypa.io/en/stable/news.html +.. _Release process: https://pip.pypa.io/en/latest/development/release-process/ +.. _GitHub page: https://github.com/pypa/pip +.. _Development documentation: https://pip.pypa.io/en/latest/development +.. _made a big improvement to the heart of pip: https://pyfound.blogspot.com/2020/11/pip-20-3-new-resolver.html +.. _learn more: https://pip.pypa.io/en/latest/user_guide/#changes-to-the-pip-dependency-resolver-in-20-3-2020 +.. _sign up for our user experience research studies: https://pyfound.blogspot.com/2020/03/new-pip-resolver-to-roll-out-this-year.html +.. _Python 2 support policy: https://pip.pypa.io/en/latest/development/release-process/#python-2-support +.. _Issue tracking: https://github.com/pypa/pip/issues +.. _Discourse channel: https://discuss.python.org/c/packaging +.. _User IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa +.. _Development IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa-dev +.. _PSF Code of Conduct: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md diff --git a/venv/Lib/site-packages/pip-22.3.1.dist-info/RECORD b/venv/Lib/site-packages/pip-22.3.1.dist-info/RECORD new file mode 100644 index 0000000..6559f97 --- /dev/null +++ b/venv/Lib/site-packages/pip-22.3.1.dist-info/RECORD @@ -0,0 +1,992 @@ +../../Scripts/pip.exe,sha256=9efudWDM8zKho1TB6TaLwxoyRWUc07EAyDRpVxGtMq8,106377 +../../Scripts/pip3.10.exe,sha256=9efudWDM8zKho1TB6TaLwxoyRWUc07EAyDRpVxGtMq8,106377 +../../Scripts/pip3.9.exe,sha256=9efudWDM8zKho1TB6TaLwxoyRWUc07EAyDRpVxGtMq8,106377 +../../Scripts/pip3.exe,sha256=9efudWDM8zKho1TB6TaLwxoyRWUc07EAyDRpVxGtMq8,106377 +pip-22.3.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pip-22.3.1.dist-info/LICENSE.txt,sha256=Y0MApmnUmurmWxLGxIySTFGkzfPR_whtw0VtyLyqIQQ,1093 +pip-22.3.1.dist-info/METADATA,sha256=a9COYc5qzklDgbGlrKYkypMXon4A6IDgpeUTWLr7zzY,4072 +pip-22.3.1.dist-info/RECORD,, +pip-22.3.1.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +pip-22.3.1.dist-info/entry_points.txt,sha256=ynZN1_707_L23Oa8_O5LOxEoccj1nDa4xHT5galfN7o,125 +pip-22.3.1.dist-info/top_level.txt,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pip/__init__.py,sha256=Z2hXGRMvmdhpmmqr0OW1fA2Jje8tnmU0uzibRoUF-w8,357 +pip/__main__.py,sha256=mXwWDftNLMKfwVqKFWGE_uuBZvGSIiUELhLkeysIuZc,1198 +pip/__pip-runner__.py,sha256=EnrfKmKMzWAdqg_JicLCOP9Y95Ux7zHh4ObvqLtQcjo,1444 +pip/__pycache__/__init__.cpython-39.pyc,, +pip/__pycache__/__main__.cpython-39.pyc,, +pip/__pycache__/__pip-runner__.cpython-39.pyc,, +pip/_internal/__init__.py,sha256=nnFCuxrPMgALrIDxSoy-H6Zj4W4UY60D-uL1aJyq0pc,573 +pip/_internal/__pycache__/__init__.cpython-39.pyc,, +pip/_internal/__pycache__/build_env.cpython-39.pyc,, +pip/_internal/__pycache__/cache.cpython-39.pyc,, +pip/_internal/__pycache__/configuration.cpython-39.pyc,, +pip/_internal/__pycache__/exceptions.cpython-39.pyc,, +pip/_internal/__pycache__/main.cpython-39.pyc,, +pip/_internal/__pycache__/pyproject.cpython-39.pyc,, +pip/_internal/__pycache__/self_outdated_check.cpython-39.pyc,, +pip/_internal/__pycache__/wheel_builder.cpython-39.pyc,, +pip/_internal/build_env.py,sha256=gEAT8R6SuWbg2mcrsmOTKWMw_x5pedMzvSTxQS57JZs,10234 +pip/_internal/cache.py,sha256=C3n78VnBga9rjPXZqht_4A4d-T25poC7K0qBM7FHDhU,10734 +pip/_internal/cli/__init__.py,sha256=FkHBgpxxb-_gd6r1FjnNhfMOzAUYyXoXKJ6abijfcFU,132 +pip/_internal/cli/__pycache__/__init__.cpython-39.pyc,, +pip/_internal/cli/__pycache__/autocompletion.cpython-39.pyc,, +pip/_internal/cli/__pycache__/base_command.cpython-39.pyc,, +pip/_internal/cli/__pycache__/cmdoptions.cpython-39.pyc,, +pip/_internal/cli/__pycache__/command_context.cpython-39.pyc,, +pip/_internal/cli/__pycache__/main.cpython-39.pyc,, +pip/_internal/cli/__pycache__/main_parser.cpython-39.pyc,, +pip/_internal/cli/__pycache__/parser.cpython-39.pyc,, +pip/_internal/cli/__pycache__/progress_bars.cpython-39.pyc,, +pip/_internal/cli/__pycache__/req_command.cpython-39.pyc,, +pip/_internal/cli/__pycache__/spinners.cpython-39.pyc,, +pip/_internal/cli/__pycache__/status_codes.cpython-39.pyc,, +pip/_internal/cli/autocompletion.py,sha256=wY2JPZY2Eji1vhR7bVo-yCBPJ9LCy6P80iOAhZD1Vi8,6676 +pip/_internal/cli/base_command.py,sha256=t1D5x40Hfn9HnPnMt-iSxvqL14nht2olBCacW74pc-k,7842 +pip/_internal/cli/cmdoptions.py,sha256=Jlarlzz9qv9tC_tCaEbcc_jVvrPreFLBBUnDgoyWflw,29381 +pip/_internal/cli/command_context.py,sha256=RHgIPwtObh5KhMrd3YZTkl8zbVG-6Okml7YbFX4Ehg0,774 +pip/_internal/cli/main.py,sha256=ioJ8IVlb2K1qLOxR-tXkee9lURhYV89CDM71MKag7YY,2472 +pip/_internal/cli/main_parser.py,sha256=laDpsuBDl6kyfywp9eMMA9s84jfH2TJJn-vmL0GG90w,4338 +pip/_internal/cli/parser.py,sha256=tWP-K1uSxnJyXu3WE0kkH3niAYRBeuUaxeydhzOdhL4,10817 +pip/_internal/cli/progress_bars.py,sha256=So4mPoSjXkXiSHiTzzquH3VVyVD_njXlHJSExYPXAow,1968 +pip/_internal/cli/req_command.py,sha256=ypTutLv4j_efxC2f6C6aCQufxre-zaJdi5m_tWlLeBk,18172 +pip/_internal/cli/spinners.py,sha256=hIJ83GerdFgFCdobIA23Jggetegl_uC4Sp586nzFbPE,5118 +pip/_internal/cli/status_codes.py,sha256=sEFHUaUJbqv8iArL3HAtcztWZmGOFX01hTesSytDEh0,116 +pip/_internal/commands/__init__.py,sha256=5oRO9O3dM2vGuh0bFw4HOVletryrz5HHMmmPWwJrH9U,3882 +pip/_internal/commands/__pycache__/__init__.cpython-39.pyc,, +pip/_internal/commands/__pycache__/cache.cpython-39.pyc,, +pip/_internal/commands/__pycache__/check.cpython-39.pyc,, +pip/_internal/commands/__pycache__/completion.cpython-39.pyc,, +pip/_internal/commands/__pycache__/configuration.cpython-39.pyc,, +pip/_internal/commands/__pycache__/debug.cpython-39.pyc,, +pip/_internal/commands/__pycache__/download.cpython-39.pyc,, +pip/_internal/commands/__pycache__/freeze.cpython-39.pyc,, +pip/_internal/commands/__pycache__/hash.cpython-39.pyc,, +pip/_internal/commands/__pycache__/help.cpython-39.pyc,, +pip/_internal/commands/__pycache__/index.cpython-39.pyc,, +pip/_internal/commands/__pycache__/inspect.cpython-39.pyc,, +pip/_internal/commands/__pycache__/install.cpython-39.pyc,, +pip/_internal/commands/__pycache__/list.cpython-39.pyc,, +pip/_internal/commands/__pycache__/search.cpython-39.pyc,, +pip/_internal/commands/__pycache__/show.cpython-39.pyc,, +pip/_internal/commands/__pycache__/uninstall.cpython-39.pyc,, +pip/_internal/commands/__pycache__/wheel.cpython-39.pyc,, +pip/_internal/commands/cache.py,sha256=muaT0mbL-ZUpn6AaushVAipzTiMwE4nV2BLbJBwt_KQ,7582 +pip/_internal/commands/check.py,sha256=0gjXR7j36xJT5cs2heYU_dfOfpnFfzX8OoPNNoKhqdM,1685 +pip/_internal/commands/completion.py,sha256=H0TJvGrdsoleuIyQKzJbicLFppYx2OZA0BLNpQDeFjI,4129 +pip/_internal/commands/configuration.py,sha256=NB5uf8HIX8-li95YLoZO09nALIWlLCHDF5aifSKcBn8,9815 +pip/_internal/commands/debug.py,sha256=kVjn-O1ixLk0webD0w9vfFFq_GCTUTd2hmLOnYtDCig,6573 +pip/_internal/commands/download.py,sha256=LwKEyYMG2L67nQRyGo8hQdNEeMU2bmGWqJfcB8JDXas,5289 +pip/_internal/commands/freeze.py,sha256=gCjoD6foBZPBAAYx5t8zZLkJhsF_ZRtnb3dPuD7beO8,2951 +pip/_internal/commands/hash.py,sha256=EVVOuvGtoPEdFi8SNnmdqlCQrhCxV-kJsdwtdcCnXGQ,1703 +pip/_internal/commands/help.py,sha256=gcc6QDkcgHMOuAn5UxaZwAStsRBrnGSn_yxjS57JIoM,1132 +pip/_internal/commands/index.py,sha256=1VVXXj5MsI2qH-N7uniQQyVkg-KCn_RdjiyiUmkUS5U,4762 +pip/_internal/commands/inspect.py,sha256=mRJ9aIkBQN0IJ7Um8pzaxAzVPIgL8KfWHx1fWKJgUAQ,3374 +pip/_internal/commands/install.py,sha256=_XbW0PyxtZCMMNqo8mDaOq3TBRiJNFM-94CR27mburc,31726 +pip/_internal/commands/list.py,sha256=Fk1TSxB33NlRS4qlLQ0xwnytnF9-zkQJbKQYv2xc4Q4,12343 +pip/_internal/commands/search.py,sha256=sbBZiARRc050QquOKcCvOr2K3XLsoYebLKZGRi__iUI,5697 +pip/_internal/commands/show.py,sha256=CJI8q4SSY0X346K1hi4Th8Nbyhl4nxPTBJUuzOlTaYE,6129 +pip/_internal/commands/uninstall.py,sha256=0JQhifYxecNrJAwoILFwjm9V1V3liXzNT-y4bgRXXPw,3680 +pip/_internal/commands/wheel.py,sha256=mbFJd4dmUfrVFJkQbK8n2zHyRcD3AI91f7EUo9l3KYg,7396 +pip/_internal/configuration.py,sha256=uBKTus43pDIO6IzT2mLWQeROmHhtnoabhniKNjPYvD0,13529 +pip/_internal/distributions/__init__.py,sha256=Hq6kt6gXBgjNit5hTTWLAzeCNOKoB-N0pGYSqehrli8,858 +pip/_internal/distributions/__pycache__/__init__.cpython-39.pyc,, +pip/_internal/distributions/__pycache__/base.cpython-39.pyc,, +pip/_internal/distributions/__pycache__/installed.cpython-39.pyc,, +pip/_internal/distributions/__pycache__/sdist.cpython-39.pyc,, +pip/_internal/distributions/__pycache__/wheel.cpython-39.pyc,, +pip/_internal/distributions/base.py,sha256=jrF1Vi7eGyqFqMHrieh1PIOrGU7KeCxhYPZnbvtmvGY,1221 +pip/_internal/distributions/installed.py,sha256=NI2OgsgH9iBq9l5vB-56vOg5YsybOy-AU4VE5CSCO2I,729 +pip/_internal/distributions/sdist.py,sha256=SQBdkatXSigKGG_SaD0U0p1Jwdfrg26UCNcHgkXZfdA,6494 +pip/_internal/distributions/wheel.py,sha256=m-J4XO-gvFerlYsFzzSXYDvrx8tLZlJFTCgDxctn8ig,1164 +pip/_internal/exceptions.py,sha256=BfvcyN2iEv3Sf00SVmSk59lEeZEBHELqkuoN2KeIWKc,20942 +pip/_internal/index/__init__.py,sha256=vpt-JeTZefh8a-FC22ZeBSXFVbuBcXSGiILhQZJaNpQ,30 +pip/_internal/index/__pycache__/__init__.cpython-39.pyc,, +pip/_internal/index/__pycache__/collector.cpython-39.pyc,, +pip/_internal/index/__pycache__/package_finder.cpython-39.pyc,, +pip/_internal/index/__pycache__/sources.cpython-39.pyc,, +pip/_internal/index/collector.py,sha256=Pb9FW9STH2lwaApCIdMCivsbPP5pSYQp5bh3nLQBkDU,16503 +pip/_internal/index/package_finder.py,sha256=kmcMu5_i-BP6v3NQGY0_am1ezxM2Gk4t00arZMmm4sc,37596 +pip/_internal/index/sources.py,sha256=SVyPitv08-Qalh2_Bk5diAJ9GAA_d-a93koouQodAG0,6557 +pip/_internal/locations/__init__.py,sha256=QhB-Y6TNyaU010cimm2T4wM5loe8oRdjLwJ6xmsGc-k,17552 +pip/_internal/locations/__pycache__/__init__.cpython-39.pyc,, +pip/_internal/locations/__pycache__/_distutils.cpython-39.pyc,, +pip/_internal/locations/__pycache__/_sysconfig.cpython-39.pyc,, +pip/_internal/locations/__pycache__/base.cpython-39.pyc,, +pip/_internal/locations/_distutils.py,sha256=wgHDvHGNZHtlcHkQjYovHzkEUBzisR0iOh7OqCIkB5g,6302 +pip/_internal/locations/_sysconfig.py,sha256=nM-DiVHXWTxippdmN0MGVl5r7OIfIMy3vgDMlo8c_oo,7867 +pip/_internal/locations/base.py,sha256=ufyDqPwZ4jLbScD44u8AwTVI-3ft8O78UGrroQI5f68,2573 +pip/_internal/main.py,sha256=r-UnUe8HLo5XFJz8inTcOOTiu_sxNhgHb6VwlGUllOI,340 +pip/_internal/metadata/__init__.py,sha256=84j1dPJaIoz5Q2ZTPi0uB1iaDAHiUNfKtYSGQCfFKpo,4280 +pip/_internal/metadata/__pycache__/__init__.cpython-39.pyc,, +pip/_internal/metadata/__pycache__/_json.cpython-39.pyc,, +pip/_internal/metadata/__pycache__/base.cpython-39.pyc,, +pip/_internal/metadata/__pycache__/pkg_resources.cpython-39.pyc,, +pip/_internal/metadata/_json.py,sha256=BTkWfFDrWFwuSodImjtbAh8wCL3isecbnjTb5E6UUDI,2595 +pip/_internal/metadata/base.py,sha256=vIwIo1BtoqegehWMAXhNrpLGYBq245rcaCNkBMPnTU8,25277 +pip/_internal/metadata/importlib/__init__.py,sha256=9ZVO8BoE7NEZPmoHp5Ap_NJo0HgNIezXXg-TFTtt3Z4,107 +pip/_internal/metadata/importlib/__pycache__/__init__.cpython-39.pyc,, +pip/_internal/metadata/importlib/__pycache__/_compat.cpython-39.pyc,, +pip/_internal/metadata/importlib/__pycache__/_dists.cpython-39.pyc,, +pip/_internal/metadata/importlib/__pycache__/_envs.cpython-39.pyc,, +pip/_internal/metadata/importlib/_compat.py,sha256=GAe_prIfCE4iUylrnr_2dJRlkkBVRUbOidEoID7LPoE,1882 +pip/_internal/metadata/importlib/_dists.py,sha256=BUV8y6D0PePZrEN3vfJL-m1FDqZ6YPRgAiBeBinHhNg,8181 +pip/_internal/metadata/importlib/_envs.py,sha256=7BxanCh3T7arusys__O2ZHJdnmDhQXFmfU7x1-jB5xI,7457 +pip/_internal/metadata/pkg_resources.py,sha256=WjwiNdRsvxqxL4MA5Tb5a_q3Q3sUhdpbZF8wGLtPMI0,9773 +pip/_internal/models/__init__.py,sha256=3DHUd_qxpPozfzouoqa9g9ts1Czr5qaHfFxbnxriepM,63 +pip/_internal/models/__pycache__/__init__.cpython-39.pyc,, +pip/_internal/models/__pycache__/candidate.cpython-39.pyc,, +pip/_internal/models/__pycache__/direct_url.cpython-39.pyc,, +pip/_internal/models/__pycache__/format_control.cpython-39.pyc,, +pip/_internal/models/__pycache__/index.cpython-39.pyc,, +pip/_internal/models/__pycache__/installation_report.cpython-39.pyc,, +pip/_internal/models/__pycache__/link.cpython-39.pyc,, +pip/_internal/models/__pycache__/scheme.cpython-39.pyc,, +pip/_internal/models/__pycache__/search_scope.cpython-39.pyc,, +pip/_internal/models/__pycache__/selection_prefs.cpython-39.pyc,, +pip/_internal/models/__pycache__/target_python.cpython-39.pyc,, +pip/_internal/models/__pycache__/wheel.cpython-39.pyc,, +pip/_internal/models/candidate.py,sha256=6pcABsaR7CfIHlbJbr2_kMkVJFL_yrYjTx6SVWUnCPQ,990 +pip/_internal/models/direct_url.py,sha256=HLO0sL2aYB6n45bwmd72TDN05sLHJlOQI8M01l2SH3I,5877 +pip/_internal/models/format_control.py,sha256=DJpMYjxeYKKQdwNcML2_F0vtAh-qnKTYe-CpTxQe-4g,2520 +pip/_internal/models/index.py,sha256=tYnL8oxGi4aSNWur0mG8DAP7rC6yuha_MwJO8xw0crI,1030 +pip/_internal/models/installation_report.py,sha256=ad1arqtxrSFBvWnm6mRqmG12HLV3pZZcZcHrlTFIiqU,2617 +pip/_internal/models/link.py,sha256=9HWL14UQTMxRCnY6dmAz09rGElJrMAcHn2OJZCBx0tk,18083 +pip/_internal/models/scheme.py,sha256=3EFQp_ICu_shH1-TBqhl0QAusKCPDFOlgHFeN4XowWs,738 +pip/_internal/models/search_scope.py,sha256=iGPQQ6a4Lau8oGQ_FWj8aRLik8A21o03SMO5KnSt-Cg,4644 +pip/_internal/models/selection_prefs.py,sha256=KZdi66gsR-_RUXUr9uejssk3rmTHrQVJWeNA2sV-VSY,1907 +pip/_internal/models/target_python.py,sha256=qKpZox7J8NAaPmDs5C_aniwfPDxzvpkrCKqfwndG87k,3858 +pip/_internal/models/wheel.py,sha256=YqazoIZyma_Q1ejFa1C7NHKQRRWlvWkdK96VRKmDBeI,3600 +pip/_internal/network/__init__.py,sha256=jf6Tt5nV_7zkARBrKojIXItgejvoegVJVKUbhAa5Ioc,50 +pip/_internal/network/__pycache__/__init__.cpython-39.pyc,, +pip/_internal/network/__pycache__/auth.cpython-39.pyc,, +pip/_internal/network/__pycache__/cache.cpython-39.pyc,, +pip/_internal/network/__pycache__/download.cpython-39.pyc,, +pip/_internal/network/__pycache__/lazy_wheel.cpython-39.pyc,, +pip/_internal/network/__pycache__/session.cpython-39.pyc,, +pip/_internal/network/__pycache__/utils.cpython-39.pyc,, +pip/_internal/network/__pycache__/xmlrpc.cpython-39.pyc,, +pip/_internal/network/auth.py,sha256=a3C7Xaa8kTJjXkdi_wrUjqaySc8Z9Yz7U6QIbXfzMyc,12190 +pip/_internal/network/cache.py,sha256=hgXftU-eau4MWxHSLquTMzepYq5BPC2zhCkhN3glBy8,2145 +pip/_internal/network/download.py,sha256=HvDDq9bVqaN3jcS3DyVJHP7uTqFzbShdkf7NFSoHfkw,6096 +pip/_internal/network/lazy_wheel.py,sha256=PbPyuleNhtEq6b2S7rufoGXZWMD15FAGL4XeiAQ8FxA,7638 +pip/_internal/network/session.py,sha256=BpDOJ7_Xw5VkgPYWsePzcaqOfcyRZcB2AW7W0HGBST0,18443 +pip/_internal/network/utils.py,sha256=6A5SrUJEEUHxbGtbscwU2NpCyz-3ztiDlGWHpRRhsJ8,4073 +pip/_internal/network/xmlrpc.py,sha256=AzQgG4GgS152_cqmGr_Oz2MIXsCal-xfsis7fA7nmU0,1791 +pip/_internal/operations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_internal/operations/__pycache__/__init__.cpython-39.pyc,, +pip/_internal/operations/__pycache__/check.cpython-39.pyc,, +pip/_internal/operations/__pycache__/freeze.cpython-39.pyc,, +pip/_internal/operations/__pycache__/prepare.cpython-39.pyc,, +pip/_internal/operations/build/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_internal/operations/build/__pycache__/__init__.cpython-39.pyc,, +pip/_internal/operations/build/__pycache__/build_tracker.cpython-39.pyc,, +pip/_internal/operations/build/__pycache__/metadata.cpython-39.pyc,, +pip/_internal/operations/build/__pycache__/metadata_editable.cpython-39.pyc,, +pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-39.pyc,, +pip/_internal/operations/build/__pycache__/wheel.cpython-39.pyc,, +pip/_internal/operations/build/__pycache__/wheel_editable.cpython-39.pyc,, +pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-39.pyc,, +pip/_internal/operations/build/build_tracker.py,sha256=vf81EwomN3xe9G8qRJED0VGqNikmRQRQoobNsxi5Xrs,4133 +pip/_internal/operations/build/metadata.py,sha256=ES_uRmAvhrNm_nDTpZxshBfUsvnXtkj-g_4rZrH9Rww,1404 +pip/_internal/operations/build/metadata_editable.py,sha256=_Rai0VZjxoeJUkjkuICrq45LtjwFoDOveosMYH43rKc,1456 +pip/_internal/operations/build/metadata_legacy.py,sha256=o-eU21As175hDC7dluM1fJJ_FqokTIShyWpjKaIpHZw,2198 +pip/_internal/operations/build/wheel.py,sha256=AO9XnTGhTgHtZmU8Dkbfo1OGr41rBuSDjIgAa4zUKgE,1063 +pip/_internal/operations/build/wheel_editable.py,sha256=TVETY-L_M_dSEKBhTIcQOP75zKVXw8tuq1U354Mm30A,1405 +pip/_internal/operations/build/wheel_legacy.py,sha256=C9j6rukgQI1n_JeQLoZGuDdfUwzCXShyIdPTp6edbMQ,3064 +pip/_internal/operations/check.py,sha256=ca4O9CkPt9Em9sLCf3H0iVt1GIcW7M8C0U5XooaBuT4,5109 +pip/_internal/operations/freeze.py,sha256=mwTZ2uML8aQgo3k8MR79a7SZmmmvdAJqdyaknKbavmg,9784 +pip/_internal/operations/install/__init__.py,sha256=mX7hyD2GNBO2mFGokDQ30r_GXv7Y_PLdtxcUv144e-s,51 +pip/_internal/operations/install/__pycache__/__init__.cpython-39.pyc,, +pip/_internal/operations/install/__pycache__/editable_legacy.cpython-39.pyc,, +pip/_internal/operations/install/__pycache__/legacy.cpython-39.pyc,, +pip/_internal/operations/install/__pycache__/wheel.cpython-39.pyc,, +pip/_internal/operations/install/editable_legacy.py,sha256=ee4kfJHNuzTdKItbfAsNOSEwq_vD7DRPGkBdK48yBhU,1354 +pip/_internal/operations/install/legacy.py,sha256=cHdcHebyzf8w7OaOLwcsTNSMSSV8WBoAPFLay_9CjE8,4105 +pip/_internal/operations/install/wheel.py,sha256=CxzEg2wTPX4SxNTPIx0ozTqF1X7LhpCyP3iM2FjcKUE,27407 +pip/_internal/operations/prepare.py,sha256=BeYXrLFpRoV5XBnRXQHxRA2plyC36kK9Pms5D9wjCo4,25091 +pip/_internal/pyproject.py,sha256=ob0Gb0l12YLZNxjdpZGRfWHgjqhZTnSVv96RuJyNOfs,7074 +pip/_internal/req/__init__.py,sha256=rUQ9d_Sh3E5kNYqX9pkN0D06YL-LrtcbJQ-LiIonq08,2807 +pip/_internal/req/__pycache__/__init__.cpython-39.pyc,, +pip/_internal/req/__pycache__/constructors.cpython-39.pyc,, +pip/_internal/req/__pycache__/req_file.cpython-39.pyc,, +pip/_internal/req/__pycache__/req_install.cpython-39.pyc,, +pip/_internal/req/__pycache__/req_set.cpython-39.pyc,, +pip/_internal/req/__pycache__/req_uninstall.cpython-39.pyc,, +pip/_internal/req/constructors.py,sha256=ypjtq1mOQ3d2mFkFPMf_6Mr8SLKeHQk3tUKHA1ddG0U,16611 +pip/_internal/req/req_file.py,sha256=N6lPO3c0to_G73YyGAnk7VUYmed5jV4Qxgmt1xtlXVg,17646 +pip/_internal/req/req_install.py,sha256=4tzyVGPHJ1-GXowm6PBT52BGIlbc4w7fhVqf-55bmRg,35600 +pip/_internal/req/req_set.py,sha256=j3esG0s6SzoVReX9rWn4rpYNtyET_fwxbwJPRimvRxo,2858 +pip/_internal/req/req_uninstall.py,sha256=ZFQfgSNz6H1BMsgl87nQNr2iaQCcbFcmXpW8rKVQcic,24045 +pip/_internal/resolution/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_internal/resolution/__pycache__/__init__.cpython-39.pyc,, +pip/_internal/resolution/__pycache__/base.cpython-39.pyc,, +pip/_internal/resolution/base.py,sha256=qlmh325SBVfvG6Me9gc5Nsh5sdwHBwzHBq6aEXtKsLA,583 +pip/_internal/resolution/legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_internal/resolution/legacy/__pycache__/__init__.cpython-39.pyc,, +pip/_internal/resolution/legacy/__pycache__/resolver.cpython-39.pyc,, +pip/_internal/resolution/legacy/resolver.py,sha256=9em8D5TcSsEN4xZM1WreaRShOnyM4LlvhMSHpUPsocE,24129 +pip/_internal/resolution/resolvelib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-39.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/base.cpython-39.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-39.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-39.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-39.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-39.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-39.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-39.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-39.pyc,, +pip/_internal/resolution/resolvelib/base.py,sha256=u1O4fkvCO4mhmu5i32xrDv9AX5NgUci_eYVyBDQhTIM,5220 +pip/_internal/resolution/resolvelib/candidates.py,sha256=6kQZeMzwibnL4lO6bW0hUQQjNEvXfADdFphRRkRvOtc,18963 +pip/_internal/resolution/resolvelib/factory.py,sha256=OnjkLIgyk5Tol7uOOqapA1D4qiRHWmPU18DF1yN5N8o,27878 +pip/_internal/resolution/resolvelib/found_candidates.py,sha256=hvL3Hoa9VaYo-qEOZkBi2Iqw251UDxPz-uMHVaWmLpE,5705 +pip/_internal/resolution/resolvelib/provider.py,sha256=Vd4jW_NnyifB-HMkPYtZIO70M3_RM0MbL5YV6XyBM-w,9914 +pip/_internal/resolution/resolvelib/reporter.py,sha256=3ZVVYrs5PqvLFJkGLcuXoMK5mTInFzl31xjUpDBpZZk,2526 +pip/_internal/resolution/resolvelib/requirements.py,sha256=B1ndvKPSuyyyTEXt9sKhbwminViSWnBrJa7qO2ln4Z0,5455 +pip/_internal/resolution/resolvelib/resolver.py,sha256=nYZ9bTFXj5c1ILKnkSgU7tUCTYyo5V5J-J0sKoA7Wzg,11533 +pip/_internal/self_outdated_check.py,sha256=R3MmjCyUt_lkUNMc6p3xVSx7vX28XiDh3VDs5OrYn6Q,8020 +pip/_internal/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_internal/utils/__pycache__/__init__.cpython-39.pyc,, +pip/_internal/utils/__pycache__/_log.cpython-39.pyc,, +pip/_internal/utils/__pycache__/appdirs.cpython-39.pyc,, +pip/_internal/utils/__pycache__/compat.cpython-39.pyc,, +pip/_internal/utils/__pycache__/compatibility_tags.cpython-39.pyc,, +pip/_internal/utils/__pycache__/datetime.cpython-39.pyc,, +pip/_internal/utils/__pycache__/deprecation.cpython-39.pyc,, +pip/_internal/utils/__pycache__/direct_url_helpers.cpython-39.pyc,, +pip/_internal/utils/__pycache__/distutils_args.cpython-39.pyc,, +pip/_internal/utils/__pycache__/egg_link.cpython-39.pyc,, +pip/_internal/utils/__pycache__/encoding.cpython-39.pyc,, +pip/_internal/utils/__pycache__/entrypoints.cpython-39.pyc,, +pip/_internal/utils/__pycache__/filesystem.cpython-39.pyc,, +pip/_internal/utils/__pycache__/filetypes.cpython-39.pyc,, +pip/_internal/utils/__pycache__/glibc.cpython-39.pyc,, +pip/_internal/utils/__pycache__/hashes.cpython-39.pyc,, +pip/_internal/utils/__pycache__/inject_securetransport.cpython-39.pyc,, +pip/_internal/utils/__pycache__/logging.cpython-39.pyc,, +pip/_internal/utils/__pycache__/misc.cpython-39.pyc,, +pip/_internal/utils/__pycache__/models.cpython-39.pyc,, +pip/_internal/utils/__pycache__/packaging.cpython-39.pyc,, +pip/_internal/utils/__pycache__/setuptools_build.cpython-39.pyc,, +pip/_internal/utils/__pycache__/subprocess.cpython-39.pyc,, +pip/_internal/utils/__pycache__/temp_dir.cpython-39.pyc,, +pip/_internal/utils/__pycache__/unpacking.cpython-39.pyc,, +pip/_internal/utils/__pycache__/urls.cpython-39.pyc,, +pip/_internal/utils/__pycache__/virtualenv.cpython-39.pyc,, +pip/_internal/utils/__pycache__/wheel.cpython-39.pyc,, +pip/_internal/utils/_log.py,sha256=-jHLOE_THaZz5BFcCnoSL9EYAtJ0nXem49s9of4jvKw,1015 +pip/_internal/utils/appdirs.py,sha256=swgcTKOm3daLeXTW6v5BUS2Ti2RvEnGRQYH_yDXklAo,1665 +pip/_internal/utils/compat.py,sha256=ACyBfLgj3_XG-iA5omEDrXqDM0cQKzi8h8HRBInzG6Q,1884 +pip/_internal/utils/compatibility_tags.py,sha256=ydin8QG8BHqYRsPY4OL6cmb44CbqXl1T0xxS97VhHkk,5377 +pip/_internal/utils/datetime.py,sha256=m21Y3wAtQc-ji6Veb6k_M5g6A0ZyFI4egchTdnwh-pQ,242 +pip/_internal/utils/deprecation.py,sha256=OLc7GzDwPob9y8jscDYCKUNBV-9CWwqFplBOJPLOpBM,5764 +pip/_internal/utils/direct_url_helpers.py,sha256=6F1tc2rcKaCZmgfVwsE6ObIe_Pux23mUVYA-2D9wCFc,3206 +pip/_internal/utils/distutils_args.py,sha256=bYUt4wfFJRaeGO4VHia6FNaA8HlYXMcKuEq1zYijY5g,1115 +pip/_internal/utils/egg_link.py,sha256=5MVlpz5LirT4iLQq86OYzjXaYF0D4Qk1dprEI7ThST4,2203 +pip/_internal/utils/encoding.py,sha256=qqsXDtiwMIjXMEiIVSaOjwH5YmirCaK-dIzb6-XJsL0,1169 +pip/_internal/utils/entrypoints.py,sha256=YlhLTRl2oHBAuqhc-zmL7USS67TPWVHImjeAQHreZTQ,3064 +pip/_internal/utils/filesystem.py,sha256=RhMIXUaNVMGjc3rhsDahWQ4MavvEQDdqXqgq-F6fpw8,5122 +pip/_internal/utils/filetypes.py,sha256=i8XAQ0eFCog26Fw9yV0Yb1ygAqKYB1w9Cz9n0fj8gZU,716 +pip/_internal/utils/glibc.py,sha256=tDfwVYnJCOC0BNVpItpy8CGLP9BjkxFHdl0mTS0J7fc,3110 +pip/_internal/utils/hashes.py,sha256=1WhkVNIHNfuYLafBHThIjVKGplxFJXSlQtuG2mXNlJI,4831 +pip/_internal/utils/inject_securetransport.py,sha256=o-QRVMGiENrTJxw3fAhA7uxpdEdw6M41TjHYtSVRrcg,795 +pip/_internal/utils/logging.py,sha256=U2q0i1n8hPS2gQh8qcocAg5dovGAa_bR24akmXMzrk4,11632 +pip/_internal/utils/misc.py,sha256=49Rs2NgrD4JGTKFt0farCm7FIAi-rjyoxgioArhCW_0,21617 +pip/_internal/utils/models.py,sha256=5GoYU586SrxURMvDn_jBMJInitviJg4O5-iOU-6I0WY,1193 +pip/_internal/utils/packaging.py,sha256=5Wm6_x7lKrlqVjPI5MBN_RurcRHwVYoQ7Ksrs84de7s,2108 +pip/_internal/utils/setuptools_build.py,sha256=4i3CuS34yNrkePnZ73rR47pyDzpZBo-SX9V5PNDSSHY,5662 +pip/_internal/utils/subprocess.py,sha256=MYySbvY7qBevRxq_RFfOsDqG4vMqrB4vDoL_eyPE6Bo,9197 +pip/_internal/utils/temp_dir.py,sha256=aCX489gRa4Nu0dMKRFyGhV6maJr60uEynu5uCbKR4Qg,7702 +pip/_internal/utils/unpacking.py,sha256=SBb2iV1crb89MDRTEKY86R4A_UOWApTQn9VQVcMDOlE,8821 +pip/_internal/utils/urls.py,sha256=AhaesUGl-9it6uvG6fsFPOr9ynFpGaTMk4t5XTX7Z_Q,1759 +pip/_internal/utils/virtualenv.py,sha256=4_48qMzCwB_F5jIK5BC_ua7uiAMVifmQWU9NdaGUoVA,3459 +pip/_internal/utils/wheel.py,sha256=lXOgZyTlOm5HmK8tw5iw0A3_5A6wRzsXHOaQkIvvloU,4549 +pip/_internal/vcs/__init__.py,sha256=UAqvzpbi0VbZo3Ub6skEeZAw-ooIZR-zX_WpCbxyCoU,596 +pip/_internal/vcs/__pycache__/__init__.cpython-39.pyc,, +pip/_internal/vcs/__pycache__/bazaar.cpython-39.pyc,, +pip/_internal/vcs/__pycache__/git.cpython-39.pyc,, +pip/_internal/vcs/__pycache__/mercurial.cpython-39.pyc,, +pip/_internal/vcs/__pycache__/subversion.cpython-39.pyc,, +pip/_internal/vcs/__pycache__/versioncontrol.cpython-39.pyc,, +pip/_internal/vcs/bazaar.py,sha256=zq-Eu2NtJffc6kOsyv2kmRTnKg9qeIXE-KH5JeKck70,3518 +pip/_internal/vcs/git.py,sha256=mjhwudCx9WlLNkxZ6_kOKmueF0rLoU2i1xeASKF6yiQ,18116 +pip/_internal/vcs/mercurial.py,sha256=Bzbd518Jsx-EJI0IhIobiQqiRsUv5TWYnrmRIFWE0Gw,5238 +pip/_internal/vcs/subversion.py,sha256=AeUVE9d9qp-0QSOMiUvuFHy1TK950E3QglN7ipP13sI,11728 +pip/_internal/vcs/versioncontrol.py,sha256=KUOc-hN51em9jrqxKwUR3JnkgSE-xSOqMiiJcSaL6B8,22811 +pip/_internal/wheel_builder.py,sha256=8cObBCu4mIsMJqZM7xXI9DO3vldiAnRNa1Gt6izPPTs,13079 +pip/_vendor/__init__.py,sha256=fNxOSVD0auElsD8fN9tuq5psfgMQ-RFBtD4X5gjlRkg,4966 +pip/_vendor/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/__pycache__/six.cpython-39.pyc,, +pip/_vendor/__pycache__/typing_extensions.cpython-39.pyc,, +pip/_vendor/cachecontrol/__init__.py,sha256=hrxlv3q7upsfyMw8k3gQ9vagBax1pYHSGGqYlZ0Zk0M,465 +pip/_vendor/cachecontrol/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-39.pyc,, +pip/_vendor/cachecontrol/__pycache__/adapter.cpython-39.pyc,, +pip/_vendor/cachecontrol/__pycache__/cache.cpython-39.pyc,, +pip/_vendor/cachecontrol/__pycache__/compat.cpython-39.pyc,, +pip/_vendor/cachecontrol/__pycache__/controller.cpython-39.pyc,, +pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-39.pyc,, +pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-39.pyc,, +pip/_vendor/cachecontrol/__pycache__/serialize.cpython-39.pyc,, +pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-39.pyc,, +pip/_vendor/cachecontrol/_cmd.py,sha256=lxUXqfNTVx84zf6tcWbkLZHA6WVBRtJRpfeA9ZqhaAY,1379 +pip/_vendor/cachecontrol/adapter.py,sha256=ew9OYEQHEOjvGl06ZsuX8W3DAvHWsQKHwWAxISyGug8,5033 +pip/_vendor/cachecontrol/cache.py,sha256=Tty45fOjH40fColTGkqKQvQQmbYsMpk-nCyfLcv2vG4,1535 +pip/_vendor/cachecontrol/caches/__init__.py,sha256=h-1cUmOz6mhLsjTjOrJ8iPejpGdLCyG4lzTftfGZvLg,242 +pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-39.pyc,, +pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-39.pyc,, +pip/_vendor/cachecontrol/caches/file_cache.py,sha256=GpexcE29LoY4MaZwPUTcUBZaDdcsjqyLxZFznk8Hbr4,5271 +pip/_vendor/cachecontrol/caches/redis_cache.py,sha256=mp-QWonP40I3xJGK3XVO-Gs9a3UjzlqqEmp9iLJH9F4,1033 +pip/_vendor/cachecontrol/compat.py,sha256=LNx7vqBndYdHU8YuJt53ab_8rzMGTXVrvMb7CZJkxG0,778 +pip/_vendor/cachecontrol/controller.py,sha256=bAYrt7x_VH4toNpI066LQxbHpYGpY1MxxmZAhspplvw,16416 +pip/_vendor/cachecontrol/filewrapper.py,sha256=X4BAQOO26GNOR7nH_fhTzAfeuct2rBQcx_15MyFBpcs,3946 +pip/_vendor/cachecontrol/heuristics.py,sha256=8kAyuZLSCyEIgQr6vbUwfhpqg9ows4mM0IV6DWazevI,4154 +pip/_vendor/cachecontrol/serialize.py,sha256=_U1NU_C-SDgFzkbAxAsPDgMTHeTWZZaHCQnZN_jh0U8,7105 +pip/_vendor/cachecontrol/wrapper.py,sha256=X3-KMZ20Ho3VtqyVaXclpeQpFzokR5NE8tZSfvKVaB8,774 +pip/_vendor/certifi/__init__.py,sha256=luDjIGxDSrQ9O0zthdz5Lnt069Z_7eR1GIEefEaf-Ys,94 +pip/_vendor/certifi/__main__.py,sha256=1k3Cr95vCxxGRGDljrW3wMdpZdL3Nhf0u1n-k2qdsCY,255 +pip/_vendor/certifi/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/certifi/__pycache__/__main__.cpython-39.pyc,, +pip/_vendor/certifi/__pycache__/core.cpython-39.pyc,, +pip/_vendor/certifi/cacert.pem,sha256=3l8CcWt_qL42030rGieD3SLufICFX0bYtGhDl_EXVPI,286370 +pip/_vendor/certifi/core.py,sha256=ZwiOsv-sD_ouU1ft8wy_xZ3LQ7UbcVzyqj2XNyrsZis,4279 +pip/_vendor/chardet/__init__.py,sha256=9-r0i294avRciob2HKVcKf6GJmXPHpgMqIijVrqHBDU,3705 +pip/_vendor/chardet/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/big5freq.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/big5prober.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/chardistribution.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/charsetgroupprober.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/charsetprober.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/codingstatemachine.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/cp949prober.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/enums.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/escprober.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/escsm.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/eucjpprober.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/euckrfreq.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/euckrprober.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/euctwfreq.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/euctwprober.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/gb2312freq.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/gb2312prober.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/hebrewprober.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/jisfreq.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/johabfreq.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/johabprober.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/jpcntx.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/langbulgarianmodel.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/langgreekmodel.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/langhebrewmodel.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/langhungarianmodel.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/langrussianmodel.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/langthaimodel.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/langturkishmodel.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/latin1prober.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/mbcharsetprober.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/mbcsgroupprober.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/mbcssm.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/sbcharsetprober.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/sbcsgroupprober.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/sjisprober.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/universaldetector.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/utf1632prober.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/utf8prober.cpython-39.pyc,, +pip/_vendor/chardet/__pycache__/version.cpython-39.pyc,, +pip/_vendor/chardet/big5freq.py,sha256=ltcfP-3PjlNHCoo5e4a7C4z-2DhBTXRfY6jbMbB7P30,31274 +pip/_vendor/chardet/big5prober.py,sha256=neUXIlq35507yibstiznZWFzyNcMn6EXrqJaUJVPWKg,1741 +pip/_vendor/chardet/chardistribution.py,sha256=M9NTKdM72KieFKy4TT5eml4PP0WaVcXuY5PpWSFD0FA,9608 +pip/_vendor/chardet/charsetgroupprober.py,sha256=CaIBAmNitEsYuSgMvgAsMREN4cLxMj5OYwMhVo6MAxk,3817 +pip/_vendor/chardet/charsetprober.py,sha256=Eo3w8sCmbvnVKOGNW1iy50KATVs8xV-gF7cQ0VG85dQ,4801 +pip/_vendor/chardet/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/chardet/cli/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/chardet/cli/__pycache__/chardetect.cpython-39.pyc,, +pip/_vendor/chardet/cli/chardetect.py,sha256=1qMxT3wrp5vP6ugSf1-Zz3BWwlbCWJ0jzeCuhgX85vw,2406 +pip/_vendor/chardet/codingstatemachine.py,sha256=BiGR9kgTYbS4gJI5qBmE52HMOBOR_roDvXf7aIehdEk,3559 +pip/_vendor/chardet/cp949prober.py,sha256=kCQEaOCzMntqv7pAyXEobWTRgIUxYfoiUr0btXO1nI8,1838 +pip/_vendor/chardet/enums.py,sha256=Rodw4p61Vg9U-oCo6eUuT7uDzKwIbCaA15HwbvCoCNk,1619 +pip/_vendor/chardet/escprober.py,sha256=girD61r3NsQLnMQXsWWBU4hHuRJzTH3V7-VfTUr-nQY,3864 +pip/_vendor/chardet/escsm.py,sha256=0Vs4iPPovberMoSxxnK5pI161Xf-mtKgOl14g5Xc7zg,12021 +pip/_vendor/chardet/eucjpprober.py,sha256=pGgs4lINwCEDV2bxqIZ6hXpaj2j4l2oLsMx6kuOK_zQ,3676 +pip/_vendor/chardet/euckrfreq.py,sha256=3mHuRvXfsq_QcQysDQFb8qSudvTiol71C6Ic2w57tKM,13566 +pip/_vendor/chardet/euckrprober.py,sha256=qBuSS2zXWaoUmGdzz3owAnD1GNhuKR_8bYzDC3yxe6I,1731 +pip/_vendor/chardet/euctwfreq.py,sha256=2alILE1Lh5eqiFJZjzRkMQXolNJRHY5oBQd-vmZYFFM,36913 +pip/_vendor/chardet/euctwprober.py,sha256=SLnCoJC94jZL8PJio60Q8PZACJA1rVPtUdWMa1W8Pwk,1731 +pip/_vendor/chardet/gb2312freq.py,sha256=49OrdXzD-HXqwavkqjo8Z7gvs58hONNzDhAyMENNkvY,20735 +pip/_vendor/chardet/gb2312prober.py,sha256=NS_i52jZE0TnWGkKqFduvu9fzW0nMcS2XbYJ8qSX8hY,1737 +pip/_vendor/chardet/hebrewprober.py,sha256=1l1hXF8-2IWDrPkf85UvAO1GVtMfY1r11kDgOqa-gU4,13919 +pip/_vendor/chardet/jisfreq.py,sha256=mm8tfrwqhpOd3wzZKS4NJqkYBQVcDfTM2JiQ5aW932E,25796 +pip/_vendor/chardet/johabfreq.py,sha256=dBpOYG34GRX6SL8k_LbS9rxZPMjLjoMlgZ03Pz5Hmqc,42498 +pip/_vendor/chardet/johabprober.py,sha256=C18osd4vMPfy9facw-Y1Lor_9UrW0PeV-zxM2fu441c,1730 +pip/_vendor/chardet/jpcntx.py,sha256=m1gDpPkRca4EDwym8XSL5YdoILFnFsDbNBYMQV7_-NE,26797 +pip/_vendor/chardet/langbulgarianmodel.py,sha256=vmbvYFP8SZkSxoBvLkFqKiH1sjma5ihk3PTpdy71Rr4,104562 +pip/_vendor/chardet/langgreekmodel.py,sha256=JfB7bupjjJH2w3X_mYnQr9cJA_7EuITC2cRW13fUjeI,98484 +pip/_vendor/chardet/langhebrewmodel.py,sha256=3HXHaLQPNAGcXnJjkIJfozNZLTvTJmf4W5Awi6zRRKc,98196 +pip/_vendor/chardet/langhungarianmodel.py,sha256=WxbeQIxkv8YtApiNqxQcvj-tMycsoI4Xy-fwkDHpP_Y,101363 +pip/_vendor/chardet/langrussianmodel.py,sha256=s395bTZ87ESTrZCOdgXbEjZ9P1iGPwCl_8xSsac_DLY,128035 +pip/_vendor/chardet/langthaimodel.py,sha256=7bJlQitRpTnVGABmbSznHnJwOHDy3InkTvtFUx13WQI,102774 +pip/_vendor/chardet/langturkishmodel.py,sha256=XY0eGdTIy4eQ9Xg1LVPZacb-UBhHBR-cq0IpPVHowKc,95372 +pip/_vendor/chardet/latin1prober.py,sha256=u_iGcQMUcZLXvj4B_WXx4caA0C5oaE2Qj1KTpz_RQ1I,5260 +pip/_vendor/chardet/mbcharsetprober.py,sha256=iKKuB6o_FF80NynRLBDT0UtwOnpLqmL_OspRPMib7CM,3367 +pip/_vendor/chardet/mbcsgroupprober.py,sha256=1D_kp9nv2_NQRddq9I2WDvB35OJh7Tfpo-OYTnL3B5o,2056 +pip/_vendor/chardet/mbcssm.py,sha256=EfORNu1WXgnFvpFarU8uJHS8KFif63xmgrHOB4DdDdY,30068 +pip/_vendor/chardet/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/chardet/metadata/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/chardet/metadata/__pycache__/languages.cpython-39.pyc,, +pip/_vendor/chardet/metadata/languages.py,sha256=HcaBygWtZq3gR8prIkJp_etvkhm2V4pUIToqjPZhgrc,13280 +pip/_vendor/chardet/sbcharsetprober.py,sha256=VvtWiNRLbHDZ5xgnofsmP1u8VQIkkaAuw3Ir9m1zDzQ,6199 +pip/_vendor/chardet/sbcsgroupprober.py,sha256=mekr4E3hgT4onmwi8oi1iEGW1CN-Z-BArG6kOtCunJw,4129 +pip/_vendor/chardet/sjisprober.py,sha256=sLfWS25PVFr5cDGhEf6h_s-RJsyeSteA-4ynsTl_UvA,3749 +pip/_vendor/chardet/universaldetector.py,sha256=BHeNWt1kn0yQgnR6xNtLAjiNmEQpSHYlKEvuZ9QyR1k,13288 +pip/_vendor/chardet/utf1632prober.py,sha256=N42YJEOkVDB67c38t5aJhXMG1QvnyWWDMNY5ERzniU0,8289 +pip/_vendor/chardet/utf8prober.py,sha256=mnLaSBV4gg-amt2WmxKFKWy4vVBedMNgjdbvgzBo0Dc,2709 +pip/_vendor/chardet/version.py,sha256=u_QYi-DXU1s7fyC_Rwa0I0-UcxMVmH7Co6c7QGKbe3g,242 +pip/_vendor/colorama/__init__.py,sha256=ihDoWQOkapwF7sqQ99AoDoEF3vGYm40OtmgW211cLZw,239 +pip/_vendor/colorama/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/colorama/__pycache__/ansi.cpython-39.pyc,, +pip/_vendor/colorama/__pycache__/ansitowin32.cpython-39.pyc,, +pip/_vendor/colorama/__pycache__/initialise.cpython-39.pyc,, +pip/_vendor/colorama/__pycache__/win32.cpython-39.pyc,, +pip/_vendor/colorama/__pycache__/winterm.cpython-39.pyc,, +pip/_vendor/colorama/ansi.py,sha256=Top4EeEuaQdBWdteKMEcGOTeKeF19Q-Wo_6_Cj5kOzQ,2522 +pip/_vendor/colorama/ansitowin32.py,sha256=gGrO7MVtwc-j1Sq3jKfZpERT1JWmYSOsTVDiTnFbZU4,10830 +pip/_vendor/colorama/initialise.py,sha256=PprovDNxMTrvoNHFcL2NZjpH2XzDc8BLxLxiErfUl4k,1915 +pip/_vendor/colorama/win32.py,sha256=bJ8Il9jwaBN5BJ8bmN6FoYZ1QYuMKv2j8fGrXh7TJjw,5404 +pip/_vendor/colorama/winterm.py,sha256=2y_2b7Zsv34feAsP67mLOVc-Bgq51mdYGo571VprlrM,6438 +pip/_vendor/distlib/__init__.py,sha256=acgfseOC55dNrVAzaBKpUiH3Z6V7Q1CaxsiQ3K7pC-E,581 +pip/_vendor/distlib/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/distlib/__pycache__/compat.cpython-39.pyc,, +pip/_vendor/distlib/__pycache__/database.cpython-39.pyc,, +pip/_vendor/distlib/__pycache__/index.cpython-39.pyc,, +pip/_vendor/distlib/__pycache__/locators.cpython-39.pyc,, +pip/_vendor/distlib/__pycache__/manifest.cpython-39.pyc,, +pip/_vendor/distlib/__pycache__/markers.cpython-39.pyc,, +pip/_vendor/distlib/__pycache__/metadata.cpython-39.pyc,, +pip/_vendor/distlib/__pycache__/resources.cpython-39.pyc,, +pip/_vendor/distlib/__pycache__/scripts.cpython-39.pyc,, +pip/_vendor/distlib/__pycache__/util.cpython-39.pyc,, +pip/_vendor/distlib/__pycache__/version.cpython-39.pyc,, +pip/_vendor/distlib/__pycache__/wheel.cpython-39.pyc,, +pip/_vendor/distlib/compat.py,sha256=tfoMrj6tujk7G4UC2owL6ArgDuCKabgBxuJRGZSmpko,41259 +pip/_vendor/distlib/database.py,sha256=o_mw0fAr93NDAHHHfqG54Y1Hi9Rkfrp2BX15XWZYK50,51697 +pip/_vendor/distlib/index.py,sha256=HFiDG7LMoaBs829WuotrfIwcErOOExUOR_AeBtw_TCU,20834 +pip/_vendor/distlib/locators.py,sha256=wNzG-zERzS_XGls-nBPVVyLRHa2skUlkn0-5n0trMWA,51991 +pip/_vendor/distlib/manifest.py,sha256=nQEhYmgoreaBZzyFzwYsXxJARu3fo4EkunU163U16iE,14811 +pip/_vendor/distlib/markers.py,sha256=TpHHHLgkzyT7YHbwj-2i6weRaq-Ivy2-MUnrDkjau-U,5058 +pip/_vendor/distlib/metadata.py,sha256=g_DIiu8nBXRzA-mWPRpatHGbmFZqaFoss7z9TG7QSUU,39801 +pip/_vendor/distlib/resources.py,sha256=LwbPksc0A1JMbi6XnuPdMBUn83X7BPuFNWqPGEKI698,10820 +pip/_vendor/distlib/scripts.py,sha256=BmkTKmiTk4m2cj-iueliatwz3ut_9SsABBW51vnQnZU,18102 +pip/_vendor/distlib/t32.exe,sha256=a0GV5kCoWsMutvliiCKmIgV98eRZ33wXoS-XrqvJQVs,97792 +pip/_vendor/distlib/t64-arm.exe,sha256=68TAa32V504xVBnufojh0PcenpR3U4wAqTqf-MZqbPw,182784 +pip/_vendor/distlib/t64.exe,sha256=gaYY8hy4fbkHYTTnA4i26ct8IQZzkBG2pRdy0iyuBrc,108032 +pip/_vendor/distlib/util.py,sha256=31dPXn3Rfat0xZLeVoFpuniyhe6vsbl9_QN-qd9Lhlk,66262 +pip/_vendor/distlib/version.py,sha256=WG__LyAa2GwmA6qSoEJtvJE8REA1LZpbSizy8WvhJLk,23513 +pip/_vendor/distlib/w32.exe,sha256=R4csx3-OGM9kL4aPIzQKRo5TfmRSHZo6QWyLhDhNBks,91648 +pip/_vendor/distlib/w64-arm.exe,sha256=xdyYhKj0WDcVUOCb05blQYvzdYIKMbmJn2SZvzkcey4,168448 +pip/_vendor/distlib/w64.exe,sha256=ejGf-rojoBfXseGLpya6bFTFPWRG21X5KvU8J5iU-K0,101888 +pip/_vendor/distlib/wheel.py,sha256=Rgqs658VsJ3R2845qwnZD8XQryV2CzWw2mghwLvxxsI,43898 +pip/_vendor/distro/__init__.py,sha256=2fHjF-SfgPvjyNZ1iHh_wjqWdR_Yo5ODHwZC0jLBPhc,981 +pip/_vendor/distro/__main__.py,sha256=bu9d3TifoKciZFcqRBuygV3GSuThnVD_m2IK4cz96Vs,64 +pip/_vendor/distro/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/distro/__pycache__/__main__.cpython-39.pyc,, +pip/_vendor/distro/__pycache__/distro.cpython-39.pyc,, +pip/_vendor/distro/distro.py,sha256=UYQG_9H_iSOt422uasA92HlY7aXeTnWKdV-IhsSAdwQ,48841 +pip/_vendor/idna/__init__.py,sha256=KJQN1eQBr8iIK5SKrJ47lXvxG0BJ7Lm38W4zT0v_8lk,849 +pip/_vendor/idna/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/idna/__pycache__/codec.cpython-39.pyc,, +pip/_vendor/idna/__pycache__/compat.cpython-39.pyc,, +pip/_vendor/idna/__pycache__/core.cpython-39.pyc,, +pip/_vendor/idna/__pycache__/idnadata.cpython-39.pyc,, +pip/_vendor/idna/__pycache__/intranges.cpython-39.pyc,, +pip/_vendor/idna/__pycache__/package_data.cpython-39.pyc,, +pip/_vendor/idna/__pycache__/uts46data.cpython-39.pyc,, +pip/_vendor/idna/codec.py,sha256=6ly5odKfqrytKT9_7UrlGklHnf1DSK2r9C6cSM4sa28,3374 +pip/_vendor/idna/compat.py,sha256=0_sOEUMT4CVw9doD3vyRhX80X19PwqFoUBs7gWsFME4,321 +pip/_vendor/idna/core.py,sha256=1JxchwKzkxBSn7R_oCE12oBu3eVux0VzdxolmIad24M,12950 +pip/_vendor/idna/idnadata.py,sha256=xUjqKqiJV8Ho_XzBpAtv5JFoVPSupK-SUXvtjygUHqw,44375 +pip/_vendor/idna/intranges.py,sha256=YBr4fRYuWH7kTKS2tXlFjM24ZF1Pdvcir-aywniInqg,1881 +pip/_vendor/idna/package_data.py,sha256=C_jHJzmX8PI4xq0jpzmcTMxpb5lDsq4o5VyxQzlVrZE,21 +pip/_vendor/idna/uts46data.py,sha256=zvjZU24s58_uAS850Mcd0NnD0X7_gCMAMjzWNIeUJdc,206539 +pip/_vendor/msgpack/__init__.py,sha256=NryGaKLDk_Egd58ZxXpnuI7OWO27AXz7S6CBFRM3sAY,1132 +pip/_vendor/msgpack/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/msgpack/__pycache__/exceptions.cpython-39.pyc,, +pip/_vendor/msgpack/__pycache__/ext.cpython-39.pyc,, +pip/_vendor/msgpack/__pycache__/fallback.cpython-39.pyc,, +pip/_vendor/msgpack/exceptions.py,sha256=dCTWei8dpkrMsQDcjQk74ATl9HsIBH0ybt8zOPNqMYc,1081 +pip/_vendor/msgpack/ext.py,sha256=TuldJPkYu8Wo_Xh0tFGL2l06-gY88NSR8tOje9fo2Wg,6080 +pip/_vendor/msgpack/fallback.py,sha256=OORDn86-fHBPlu-rPlMdM10KzkH6S_Rx9CHN1b7o4cg,34557 +pip/_vendor/packaging/__about__.py,sha256=ugASIO2w1oUyH8_COqQ2X_s0rDhjbhQC3yJocD03h2c,661 +pip/_vendor/packaging/__init__.py,sha256=b9Kk5MF7KxhhLgcDmiUWukN-LatWFxPdNug0joPhHSk,497 +pip/_vendor/packaging/__pycache__/__about__.cpython-39.pyc,, +pip/_vendor/packaging/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/packaging/__pycache__/_manylinux.cpython-39.pyc,, +pip/_vendor/packaging/__pycache__/_musllinux.cpython-39.pyc,, +pip/_vendor/packaging/__pycache__/_structures.cpython-39.pyc,, +pip/_vendor/packaging/__pycache__/markers.cpython-39.pyc,, +pip/_vendor/packaging/__pycache__/requirements.cpython-39.pyc,, +pip/_vendor/packaging/__pycache__/specifiers.cpython-39.pyc,, +pip/_vendor/packaging/__pycache__/tags.cpython-39.pyc,, +pip/_vendor/packaging/__pycache__/utils.cpython-39.pyc,, +pip/_vendor/packaging/__pycache__/version.cpython-39.pyc,, +pip/_vendor/packaging/_manylinux.py,sha256=XcbiXB-qcjv3bcohp6N98TMpOP4_j3m-iOA8ptK2GWY,11488 +pip/_vendor/packaging/_musllinux.py,sha256=_KGgY_qc7vhMGpoqss25n2hiLCNKRtvz9mCrS7gkqyc,4378 +pip/_vendor/packaging/_structures.py,sha256=q3eVNmbWJGG_S0Dit_S3Ao8qQqz_5PYTXFAKBZe5yr4,1431 +pip/_vendor/packaging/markers.py,sha256=AJBOcY8Oq0kYc570KuuPTkvuqjAlhufaE2c9sCUbm64,8487 +pip/_vendor/packaging/requirements.py,sha256=NtDlPBtojpn1IUC85iMjPNsUmufjpSlwnNA-Xb4m5NA,4676 +pip/_vendor/packaging/specifiers.py,sha256=LRQ0kFsHrl5qfcFNEEJrIFYsnIHQUJXY9fIsakTrrqE,30110 +pip/_vendor/packaging/tags.py,sha256=lmsnGNiJ8C4D_Pf9PbM0qgbZvD9kmB9lpZBQUZa3R_Y,15699 +pip/_vendor/packaging/utils.py,sha256=dJjeat3BS-TYn1RrUFVwufUMasbtzLfYRoy_HXENeFQ,4200 +pip/_vendor/packaging/version.py,sha256=_fLRNrFrxYcHVfyo8vk9j8s6JM8N_xsSxVFr6RJyco8,14665 +pip/_vendor/pep517/__init__.py,sha256=QJpRfzTpk6YSPgjcxp9-MCAiS5dEdzf9Bh0UXophG6c,130 +pip/_vendor/pep517/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/pep517/__pycache__/_compat.cpython-39.pyc,, +pip/_vendor/pep517/__pycache__/build.cpython-39.pyc,, +pip/_vendor/pep517/__pycache__/check.cpython-39.pyc,, +pip/_vendor/pep517/__pycache__/colorlog.cpython-39.pyc,, +pip/_vendor/pep517/__pycache__/dirtools.cpython-39.pyc,, +pip/_vendor/pep517/__pycache__/envbuild.cpython-39.pyc,, +pip/_vendor/pep517/__pycache__/meta.cpython-39.pyc,, +pip/_vendor/pep517/__pycache__/wrappers.cpython-39.pyc,, +pip/_vendor/pep517/_compat.py,sha256=by6evrYnqkisiM-MQcvOKs5bgDMzlOSgZqRHNqf04zE,138 +pip/_vendor/pep517/build.py,sha256=VLtq0hOvNWCfX0FkdvTKEr-TmyrbaX0UqghpU7bHO1w,3443 +pip/_vendor/pep517/check.py,sha256=o0Mp_PX1yOM2WNq1ZdDph3YA7RObj2UGQUCUF-46RaU,6083 +pip/_vendor/pep517/colorlog.py,sha256=eCV1W52xzBjA-sOlKzUcvabRiFa11Y7hA791u-85_c8,3994 +pip/_vendor/pep517/dirtools.py,sha256=JiZ1Hlt2LNaLZEhNa_pm1YyG3MUoRh7KxY6hJ8ac-w0,607 +pip/_vendor/pep517/envbuild.py,sha256=nkTt1ZY7MXVgYOhPTyTr-VOxQ-q_Qc1touXfQgM56Bs,6081 +pip/_vendor/pep517/in_process/__init__.py,sha256=4yDanGyKTXQtLhqRo9eEZ1CsLFezEAEZMfqEd88xrvY,872 +pip/_vendor/pep517/in_process/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/pep517/in_process/__pycache__/_in_process.cpython-39.pyc,, +pip/_vendor/pep517/in_process/_in_process.py,sha256=JDpTxlKMDN1QfN_ey4IDtE6ZVSWtzP0_WLSqt1TyGaA,10801 +pip/_vendor/pep517/meta.py,sha256=budDWsV3I2OnnpSvXQ_ycuTqxh8G7DABoazAq-j8OlQ,2520 +pip/_vendor/pep517/wrappers.py,sha256=jcxIy-1Kl8I2xAZgbr6qNjF5b_6Q5gTndf9cxF0p5gM,12721 +pip/_vendor/pkg_resources/__init__.py,sha256=NnpQ3g6BCHzpMgOR_OLBmYtniY4oOzdKpwqghfq_6ug,108287 +pip/_vendor/pkg_resources/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/pkg_resources/__pycache__/py31compat.cpython-39.pyc,, +pip/_vendor/pkg_resources/py31compat.py,sha256=CRk8fkiPRDLsbi5pZcKsHI__Pbmh_94L8mr9Qy9Ab2U,562 +pip/_vendor/platformdirs/__init__.py,sha256=x0aUmmovXXuRFVrVQBtwIiovX12B7rUkdV4F9UlLz0Y,12831 +pip/_vendor/platformdirs/__main__.py,sha256=ZmsnTxEOxtTvwa-Y_Vfab_JN3X4XCVeN8X0yyy9-qnc,1176 +pip/_vendor/platformdirs/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/platformdirs/__pycache__/__main__.cpython-39.pyc,, +pip/_vendor/platformdirs/__pycache__/android.cpython-39.pyc,, +pip/_vendor/platformdirs/__pycache__/api.cpython-39.pyc,, +pip/_vendor/platformdirs/__pycache__/macos.cpython-39.pyc,, +pip/_vendor/platformdirs/__pycache__/unix.cpython-39.pyc,, +pip/_vendor/platformdirs/__pycache__/version.cpython-39.pyc,, +pip/_vendor/platformdirs/__pycache__/windows.cpython-39.pyc,, +pip/_vendor/platformdirs/android.py,sha256=GKizhyS7ESRiU67u8UnBJLm46goau9937EchXWbPBlk,4068 +pip/_vendor/platformdirs/api.py,sha256=MXKHXOL3eh_-trSok-JUTjAR_zjmmKF3rjREVABjP8s,4910 +pip/_vendor/platformdirs/macos.py,sha256=-3UXQewbT0yMhMdkzRXfXGAntmLIH7Qt4a9Hlf8I5_Y,2655 +pip/_vendor/platformdirs/unix.py,sha256=b4aVYTz0qZ50HntwOXo8r6tp82jAa3qTjxw-WlnC2yc,6910 +pip/_vendor/platformdirs/version.py,sha256=tsBKKPDX3LLh39yHXeTYauGRbRd-AmOJr9SwKldlFIU,78 +pip/_vendor/platformdirs/windows.py,sha256=ISruopR5UGBePC0BxCxXevkZYfjJsIZc49YWU5iYfQ4,6439 +pip/_vendor/pygments/__init__.py,sha256=5oLcMLXD0cTG8YcHBPITtK1fS0JBASILEvEnWkTezgE,2999 +pip/_vendor/pygments/__main__.py,sha256=p0_rz3JZmNZMNZBOqDojaEx1cr9wmA9FQZX_TYl74lQ,353 +pip/_vendor/pygments/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/pygments/__pycache__/__main__.cpython-39.pyc,, +pip/_vendor/pygments/__pycache__/cmdline.cpython-39.pyc,, +pip/_vendor/pygments/__pycache__/console.cpython-39.pyc,, +pip/_vendor/pygments/__pycache__/filter.cpython-39.pyc,, +pip/_vendor/pygments/__pycache__/formatter.cpython-39.pyc,, +pip/_vendor/pygments/__pycache__/lexer.cpython-39.pyc,, +pip/_vendor/pygments/__pycache__/modeline.cpython-39.pyc,, +pip/_vendor/pygments/__pycache__/plugin.cpython-39.pyc,, +pip/_vendor/pygments/__pycache__/regexopt.cpython-39.pyc,, +pip/_vendor/pygments/__pycache__/scanner.cpython-39.pyc,, +pip/_vendor/pygments/__pycache__/sphinxext.cpython-39.pyc,, +pip/_vendor/pygments/__pycache__/style.cpython-39.pyc,, +pip/_vendor/pygments/__pycache__/token.cpython-39.pyc,, +pip/_vendor/pygments/__pycache__/unistring.cpython-39.pyc,, +pip/_vendor/pygments/__pycache__/util.cpython-39.pyc,, +pip/_vendor/pygments/cmdline.py,sha256=rc0fah4eknRqFgn1wKNEwkq0yWnSqYOGaA4PaIeOxVY,23685 +pip/_vendor/pygments/console.py,sha256=hQfqCFuOlGk7DW2lPQYepsw-wkOH1iNt9ylNA1eRymM,1697 +pip/_vendor/pygments/filter.py,sha256=NglMmMPTRRv-zuRSE_QbWid7JXd2J4AvwjCW2yWALXU,1938 +pip/_vendor/pygments/filters/__init__.py,sha256=b5YuXB9rampSy2-cMtKxGQoMDfrG4_DcvVwZrzTlB6w,40386 +pip/_vendor/pygments/filters/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/pygments/formatter.py,sha256=6-TS2Y8pUMeWIUolWwr1O8ruC-U6HydWDwOdbAiJgJQ,2917 +pip/_vendor/pygments/formatters/__init__.py,sha256=YTqGeHS17fNXCLMZpf7oCxBCKLB9YLsZ8IAsjGhawyg,4810 +pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-39.pyc,, +pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-39.pyc,, +pip/_vendor/pygments/formatters/__pycache__/groff.cpython-39.pyc,, +pip/_vendor/pygments/formatters/__pycache__/html.cpython-39.pyc,, +pip/_vendor/pygments/formatters/__pycache__/img.cpython-39.pyc,, +pip/_vendor/pygments/formatters/__pycache__/irc.cpython-39.pyc,, +pip/_vendor/pygments/formatters/__pycache__/latex.cpython-39.pyc,, +pip/_vendor/pygments/formatters/__pycache__/other.cpython-39.pyc,, +pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-39.pyc,, +pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-39.pyc,, +pip/_vendor/pygments/formatters/__pycache__/svg.cpython-39.pyc,, +pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-39.pyc,, +pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-39.pyc,, +pip/_vendor/pygments/formatters/_mapping.py,sha256=fCZgvsM6UEuZUG7J6lr47eVss5owKd_JyaNbDfxeqmQ,4104 +pip/_vendor/pygments/formatters/bbcode.py,sha256=JrL4ITjN-KzPcuQpPMBf1pm33eW2sDUNr8WzSoAJsJA,3314 +pip/_vendor/pygments/formatters/groff.py,sha256=xrOFoLbafSA9uHsSLRogy79_Zc4GWJ8tMK2hCdTJRsw,5086 +pip/_vendor/pygments/formatters/html.py,sha256=QNt9prPgxmbKx2M-nfDwoR1bIg06-sNouQuWnE434Wc,35441 +pip/_vendor/pygments/formatters/img.py,sha256=h75Y7IRZLZxDEIwyoOsdRLTwm7kLVPbODKkgEiJ0iKI,21938 +pip/_vendor/pygments/formatters/irc.py,sha256=iwk5tDJOxbCV64SCmOFyvk__x6RD60ay0nUn7ko9n7U,5871 +pip/_vendor/pygments/formatters/latex.py,sha256=thPbytJCIs2AUXsO3NZwqKtXJ-upOlcXP4CXsx94G4w,19351 +pip/_vendor/pygments/formatters/other.py,sha256=PczqK1Rms43lz6iucOLPeBMxIncPKOGBt-195w1ynII,5073 +pip/_vendor/pygments/formatters/pangomarkup.py,sha256=ZZzMsKJKXrsDniFeMTkIpe7aQ4VZYRHu0idWmSiUJ2U,2212 +pip/_vendor/pygments/formatters/rtf.py,sha256=abrKlWjipBkQvhIICxtjYTUNv6WME0iJJObFvqVuudE,5014 +pip/_vendor/pygments/formatters/svg.py,sha256=6MM9YyO8NhU42RTQfTWBiagWMnsf9iG5gwhqSriHORE,7335 +pip/_vendor/pygments/formatters/terminal.py,sha256=NpEGvwkC6LgMLQTjVzGrJXji3XcET1sb5JCunSCzoRo,4674 +pip/_vendor/pygments/formatters/terminal256.py,sha256=4v4OVizvsxtwWBpIy_Po30zeOzE5oJg_mOc1-rCjMDk,11753 +pip/_vendor/pygments/lexer.py,sha256=ZPB_TGn_qzrXodRFwEdPzzJk6LZBo9BlfSy3lacc6zg,32005 +pip/_vendor/pygments/lexers/__init__.py,sha256=8d80-XfL5UKDCC1wRD1a_ZBZDkZ2HOe7Zul8SsnNYFE,11174 +pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-39.pyc,, +pip/_vendor/pygments/lexers/__pycache__/python.cpython-39.pyc,, +pip/_vendor/pygments/lexers/_mapping.py,sha256=zEiCV5FPiBioMJQJjw9kk7IJ5Y9GwknS4VJPYlcNchs,70232 +pip/_vendor/pygments/lexers/python.py,sha256=gZROs9iNSOA18YyVghP1cUCD0OwYZ04a6PCwgSOCeSA,53376 +pip/_vendor/pygments/modeline.py,sha256=gIbMSYrjSWPk0oATz7W9vMBYkUyTK2OcdVyKjioDRvA,986 +pip/_vendor/pygments/plugin.py,sha256=5rPxEoB_89qQMpOs0nI4KyLOzAHNlbQiwEMOKxqNmv8,2591 +pip/_vendor/pygments/regexopt.py,sha256=c6xcXGpGgvCET_3VWawJJqAnOp0QttFpQEdOPNY2Py0,3072 +pip/_vendor/pygments/scanner.py,sha256=F2T2G6cpkj-yZtzGQr-sOBw5w5-96UrJWveZN6va2aM,3092 +pip/_vendor/pygments/sphinxext.py,sha256=F8L0211sPnXaiWutN0lkSUajWBwlgDMIEFFAbMWOvZY,4630 +pip/_vendor/pygments/style.py,sha256=RRnussX1YiK9Z7HipIvKorImxu3-HnkdpPCO4u925T0,6257 +pip/_vendor/pygments/styles/__init__.py,sha256=iZDZ7PBKb55SpGlE1--cx9cbmWx5lVTH4bXO87t2Vok,3419 +pip/_vendor/pygments/styles/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/pygments/token.py,sha256=vA2yNHGJBHfq4jNQSah7C9DmIOp34MmYHPA8P-cYAHI,6184 +pip/_vendor/pygments/unistring.py,sha256=gP3gK-6C4oAFjjo9HvoahsqzuV4Qz0jl0E0OxfDerHI,63187 +pip/_vendor/pygments/util.py,sha256=KgwpWWC3By5AiNwxGTI7oI9aXupH2TyZWukafBJe0Mg,9110 +pip/_vendor/pyparsing/__init__.py,sha256=ZPdI7pPo4IYXcABw-51AcqOzsxVvDtqnQbyn_qYWZvo,9171 +pip/_vendor/pyparsing/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/pyparsing/__pycache__/actions.cpython-39.pyc,, +pip/_vendor/pyparsing/__pycache__/common.cpython-39.pyc,, +pip/_vendor/pyparsing/__pycache__/core.cpython-39.pyc,, +pip/_vendor/pyparsing/__pycache__/exceptions.cpython-39.pyc,, +pip/_vendor/pyparsing/__pycache__/helpers.cpython-39.pyc,, +pip/_vendor/pyparsing/__pycache__/results.cpython-39.pyc,, +pip/_vendor/pyparsing/__pycache__/testing.cpython-39.pyc,, +pip/_vendor/pyparsing/__pycache__/unicode.cpython-39.pyc,, +pip/_vendor/pyparsing/__pycache__/util.cpython-39.pyc,, +pip/_vendor/pyparsing/actions.py,sha256=wU9i32e0y1ymxKE3OUwSHO-SFIrt1h_wv6Ws0GQjpNU,6426 +pip/_vendor/pyparsing/common.py,sha256=lFL97ooIeR75CmW5hjURZqwDCTgruqltcTCZ-ulLO2Q,12936 +pip/_vendor/pyparsing/core.py,sha256=AzTm1KFT1FIhiw2zvXZJmrpQoAwB0wOmeDCiR6SYytw,213344 +pip/_vendor/pyparsing/diagram/__init__.py,sha256=KW0PV_TvWKnL7jysz0pQbZ24nzWWu2ZfNaeyUIIywIg,23685 +pip/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/pyparsing/exceptions.py,sha256=3LbSafD32NYb1Tzt85GHNkhEAU1eZkTtNSk24cPMemo,9023 +pip/_vendor/pyparsing/helpers.py,sha256=QpUOjW0-psvueMwWb9bQpU2noqKCv98_wnw1VSzSdVo,39129 +pip/_vendor/pyparsing/results.py,sha256=HgNvWVXBdQP-Q6PtJfoCEeOJk2nwEvG-2KVKC5sGA30,25341 +pip/_vendor/pyparsing/testing.py,sha256=7tu4Abp4uSeJV0N_yEPRmmNUhpd18ZQP3CrX41DM814,13402 +pip/_vendor/pyparsing/unicode.py,sha256=fwuhMj30SQ165Cv7HJpu-rSxGbRm93kN9L4Ei7VGc1Y,10787 +pip/_vendor/pyparsing/util.py,sha256=kq772O5YSeXOSdP-M31EWpbH_ayj7BMHImBYo9xPD5M,6805 +pip/_vendor/requests/__init__.py,sha256=3XN75ZS4slWy3TQsEGF7-Q6l2R146teU-s2_rXNhxhU,5178 +pip/_vendor/requests/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/requests/__pycache__/__version__.cpython-39.pyc,, +pip/_vendor/requests/__pycache__/_internal_utils.cpython-39.pyc,, +pip/_vendor/requests/__pycache__/adapters.cpython-39.pyc,, +pip/_vendor/requests/__pycache__/api.cpython-39.pyc,, +pip/_vendor/requests/__pycache__/auth.cpython-39.pyc,, +pip/_vendor/requests/__pycache__/certs.cpython-39.pyc,, +pip/_vendor/requests/__pycache__/compat.cpython-39.pyc,, +pip/_vendor/requests/__pycache__/cookies.cpython-39.pyc,, +pip/_vendor/requests/__pycache__/exceptions.cpython-39.pyc,, +pip/_vendor/requests/__pycache__/help.cpython-39.pyc,, +pip/_vendor/requests/__pycache__/hooks.cpython-39.pyc,, +pip/_vendor/requests/__pycache__/models.cpython-39.pyc,, +pip/_vendor/requests/__pycache__/packages.cpython-39.pyc,, +pip/_vendor/requests/__pycache__/sessions.cpython-39.pyc,, +pip/_vendor/requests/__pycache__/status_codes.cpython-39.pyc,, +pip/_vendor/requests/__pycache__/structures.cpython-39.pyc,, +pip/_vendor/requests/__pycache__/utils.cpython-39.pyc,, +pip/_vendor/requests/__version__.py,sha256=nJVa3ef2yRyeYMhy7yHnRyjjpnNTDykZsE4Sp9irBC4,440 +pip/_vendor/requests/_internal_utils.py,sha256=aSPlF4uDhtfKxEayZJJ7KkAxtormeTfpwKSBSwtmAUw,1397 +pip/_vendor/requests/adapters.py,sha256=GFEz5koZaMZD86v0SHXKVB5SE9MgslEjkCQzldkNwVM,21443 +pip/_vendor/requests/api.py,sha256=dyvkDd5itC9z2g0wHl_YfD1yf6YwpGWLO7__8e21nks,6377 +pip/_vendor/requests/auth.py,sha256=h-HLlVx9j8rKV5hfSAycP2ApOSglTz77R0tz7qCbbEE,10187 +pip/_vendor/requests/certs.py,sha256=PVPooB0jP5hkZEULSCwC074532UFbR2Ptgu0I5zwmCs,575 +pip/_vendor/requests/compat.py,sha256=IhK9quyX0RRuWTNcg6d2JGSAOUbM6mym2p_2XjLTwf4,1286 +pip/_vendor/requests/cookies.py,sha256=kD3kNEcCj-mxbtf5fJsSaT86eGoEYpD3X0CSgpzl7BM,18560 +pip/_vendor/requests/exceptions.py,sha256=FA-_kVwBZ2jhXauRctN_ewHVK25b-fj0Azyz1THQ0Kk,3823 +pip/_vendor/requests/help.py,sha256=FnAAklv8MGm_qb2UilDQgS6l0cUttiCFKUjx0zn2XNA,3879 +pip/_vendor/requests/hooks.py,sha256=CiuysiHA39V5UfcCBXFIx83IrDpuwfN9RcTUgv28ftQ,733 +pip/_vendor/requests/models.py,sha256=GZRMMrGwDOLVvVfFHLUq0qTfIWDla3NcFHa1f5xs9Q8,35287 +pip/_vendor/requests/packages.py,sha256=njJmVifY4aSctuW3PP5EFRCxjEwMRDO6J_feG2dKWsI,695 +pip/_vendor/requests/sessions.py,sha256=KUqJcRRLovNefUs7ScOXSUVCcfSayTFWtbiJ7gOSlTI,30180 +pip/_vendor/requests/status_codes.py,sha256=FvHmT5uH-_uimtRz5hH9VCbt7VV-Nei2J9upbej6j8g,4235 +pip/_vendor/requests/structures.py,sha256=-IbmhVz06S-5aPSZuUthZ6-6D9XOjRuTXHOabY041XM,2912 +pip/_vendor/requests/utils.py,sha256=0gzSOcx9Ya4liAbHnHuwt4jM78lzCZZoDFgkmsInNUg,33240 +pip/_vendor/resolvelib/__init__.py,sha256=UL-B2BDI0_TRIqkfGwLHKLxY-LjBlomz7941wDqzB1I,537 +pip/_vendor/resolvelib/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/resolvelib/__pycache__/providers.cpython-39.pyc,, +pip/_vendor/resolvelib/__pycache__/reporters.cpython-39.pyc,, +pip/_vendor/resolvelib/__pycache__/resolvers.cpython-39.pyc,, +pip/_vendor/resolvelib/__pycache__/structs.cpython-39.pyc,, +pip/_vendor/resolvelib/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-39.pyc,, +pip/_vendor/resolvelib/compat/collections_abc.py,sha256=uy8xUZ-NDEw916tugUXm8HgwCGiMO0f-RcdnpkfXfOs,156 +pip/_vendor/resolvelib/providers.py,sha256=roVmFBItQJ0TkhNua65h8LdNny7rmeqVEXZu90QiP4o,5872 +pip/_vendor/resolvelib/reporters.py,sha256=fW91NKf-lK8XN7i6Yd_rczL5QeOT3sc6AKhpaTEnP3E,1583 +pip/_vendor/resolvelib/resolvers.py,sha256=2wYzVGBGerbmcIpH8cFmgSKgLSETz8jmwBMGjCBMHG4,17592 +pip/_vendor/resolvelib/structs.py,sha256=IVIYof6sA_N4ZEiE1C1UhzTX495brCNnyCdgq6CYq28,4794 +pip/_vendor/rich/__init__.py,sha256=zREyQ22R3zKg8gMdhiikczdVQYtZNeayHNrbBg5scm0,5944 +pip/_vendor/rich/__main__.py,sha256=BmTmBWI93ytq75IEPi1uAAdeRYzFfDbgaAXjsX1ogig,8808 +pip/_vendor/rich/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/__main__.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/_cell_widths.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/_emoji_codes.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/_emoji_replace.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/_export_format.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/_extension.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/_inspect.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/_log_render.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/_loop.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/_palettes.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/_pick.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/_ratio.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/_spinners.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/_stack.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/_timer.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/_win32_console.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/_windows.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/_windows_renderer.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/_wrap.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/abc.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/align.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/ansi.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/bar.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/box.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/cells.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/color.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/color_triplet.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/columns.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/console.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/constrain.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/containers.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/control.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/default_styles.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/diagnose.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/emoji.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/errors.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/file_proxy.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/filesize.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/highlighter.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/json.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/jupyter.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/layout.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/live.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/live_render.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/logging.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/markup.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/measure.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/padding.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/pager.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/palette.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/panel.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/pretty.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/progress.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/progress_bar.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/prompt.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/protocol.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/region.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/repr.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/rule.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/scope.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/screen.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/segment.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/spinner.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/status.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/style.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/styled.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/syntax.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/table.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/terminal_theme.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/text.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/theme.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/themes.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/traceback.cpython-39.pyc,, +pip/_vendor/rich/__pycache__/tree.cpython-39.pyc,, +pip/_vendor/rich/_cell_widths.py,sha256=2n4EiJi3X9sqIq0O16kUZ_zy6UYMd3xFfChlKfnW1Hc,10096 +pip/_vendor/rich/_emoji_codes.py,sha256=hu1VL9nbVdppJrVoijVshRlcRRe_v3dju3Mmd2sKZdY,140235 +pip/_vendor/rich/_emoji_replace.py,sha256=n-kcetsEUx2ZUmhQrfeMNc-teeGhpuSQ5F8VPBsyvDo,1064 +pip/_vendor/rich/_export_format.py,sha256=nHArqOljIlYn6NruhWsAsh-fHo7oJC3y9BDJyAa-QYQ,2114 +pip/_vendor/rich/_extension.py,sha256=Xt47QacCKwYruzjDi-gOBq724JReDj9Cm9xUi5fr-34,265 +pip/_vendor/rich/_inspect.py,sha256=oZJGw31e64dwXSCmrDnvZbwVb1ZKhWfU8wI3VWohjJk,9695 +pip/_vendor/rich/_log_render.py,sha256=1ByI0PA1ZpxZY3CGJOK54hjlq4X-Bz_boIjIqCd8Kns,3225 +pip/_vendor/rich/_loop.py,sha256=hV_6CLdoPm0va22Wpw4zKqM0RYsz3TZxXj0PoS-9eDQ,1236 +pip/_vendor/rich/_palettes.py,sha256=cdev1JQKZ0JvlguV9ipHgznTdnvlIzUFDBb0It2PzjI,7063 +pip/_vendor/rich/_pick.py,sha256=evDt8QN4lF5CiwrUIXlOJCntitBCOsI3ZLPEIAVRLJU,423 +pip/_vendor/rich/_ratio.py,sha256=2lLSliL025Y-YMfdfGbutkQDevhcyDqc-DtUYW9mU70,5472 +pip/_vendor/rich/_spinners.py,sha256=U2r1_g_1zSjsjiUdAESc2iAMc3i4ri_S8PYP6kQ5z1I,19919 +pip/_vendor/rich/_stack.py,sha256=-C8OK7rxn3sIUdVwxZBBpeHhIzX0eI-VM3MemYfaXm0,351 +pip/_vendor/rich/_timer.py,sha256=zelxbT6oPFZnNrwWPpc1ktUeAT-Vc4fuFcRZLQGLtMI,417 +pip/_vendor/rich/_win32_console.py,sha256=P0vxI2fcndym1UU1S37XAzQzQnkyY7YqAKmxm24_gug,22820 +pip/_vendor/rich/_windows.py,sha256=dvNl9TmfPzNVxiKk5WDFihErZ5796g2UC9-KGGyfXmk,1926 +pip/_vendor/rich/_windows_renderer.py,sha256=t74ZL3xuDCP3nmTp9pH1L5LiI2cakJuQRQleHCJerlk,2783 +pip/_vendor/rich/_wrap.py,sha256=xfV_9t0Sg6rzimmrDru8fCVmUlalYAcHLDfrJZnbbwQ,1840 +pip/_vendor/rich/abc.py,sha256=ON-E-ZqSSheZ88VrKX2M3PXpFbGEUUZPMa_Af0l-4f0,890 +pip/_vendor/rich/align.py,sha256=FV6_GS-8uhIyViMng3hkIWSFaTgMohK1Oqyjl8I8mGE,10368 +pip/_vendor/rich/ansi.py,sha256=HtaPG7dvgL6_yo0sQmx5CM05DJ4_1goY5SWXXOYNaKs,6820 +pip/_vendor/rich/bar.py,sha256=a7UD303BccRCrEhGjfMElpv5RFYIinaAhAuqYqhUvmw,3264 +pip/_vendor/rich/box.py,sha256=1Iv1sUWqjtp5XwLwGH-AJ8HgyXZ7dRFUkO0z3M_bRl8,9864 +pip/_vendor/rich/cells.py,sha256=zMjFI15wCpgjLR14lHdfFMVC6qMDi5OsKIB0PYZBBMk,4503 +pip/_vendor/rich/color.py,sha256=kp87L8V4-3qayE6CUxtW_nP8Ujfew_-DAhNwYMXBMOY,17957 +pip/_vendor/rich/color_triplet.py,sha256=3lhQkdJbvWPoLDO-AnYImAWmJvV5dlgYNCVZ97ORaN4,1054 +pip/_vendor/rich/columns.py,sha256=HUX0KcMm9dsKNi11fTbiM_h2iDtl8ySCaVcxlalEzq8,7131 +pip/_vendor/rich/console.py,sha256=bTT9DNX03V4cQXefg22d-gLSs_e_ZY2zdCvLIlEyU2Q,95885 +pip/_vendor/rich/constrain.py,sha256=1VIPuC8AgtKWrcncQrjBdYqA3JVWysu6jZo1rrh7c7Q,1288 +pip/_vendor/rich/containers.py,sha256=aKgm5UDHn5Nmui6IJaKdsZhbHClh_X7D-_Wg8Ehrr7s,5497 +pip/_vendor/rich/control.py,sha256=DSkHTUQLorfSERAKE_oTAEUFefZnZp4bQb4q8rHbKws,6630 +pip/_vendor/rich/default_styles.py,sha256=WqVh-RPNEsx0Wxf3fhS_fCn-wVqgJ6Qfo-Zg7CoCsLE,7954 +pip/_vendor/rich/diagnose.py,sha256=an6uouwhKPAlvQhYpNNpGq9EJysfMIOvvCbO3oSoR24,972 +pip/_vendor/rich/emoji.py,sha256=omTF9asaAnsM4yLY94eR_9dgRRSm1lHUszX20D1yYCQ,2501 +pip/_vendor/rich/errors.py,sha256=5pP3Kc5d4QJ_c0KFsxrfyhjiPVe7J1zOqSFbFAzcV-Y,642 +pip/_vendor/rich/file_proxy.py,sha256=4gCbGRXg0rW35Plaf0UVvj3dfENHuzc_n8I_dBqxI7o,1616 +pip/_vendor/rich/filesize.py,sha256=yShoVpARafJBreyZFaAhC4OhnJ6ydC1WXR-Ez4wU_YQ,2507 +pip/_vendor/rich/highlighter.py,sha256=3WW6PACGlq0e3YDjfqiMBQ0dYZwu7pcoFYUgJy01nb0,9585 +pip/_vendor/rich/json.py,sha256=RCm4lXBXrjvXHpqrWPH8wdGP0jEo4IohLmkddlhRY18,5051 +pip/_vendor/rich/jupyter.py,sha256=QyoKoE_8IdCbrtiSHp9TsTSNyTHY0FO5whE7jOTd9UE,3252 +pip/_vendor/rich/layout.py,sha256=E3xJ4fomizUADwime3VA0lBXoMSPl9blEokIzVBjO0Q,14074 +pip/_vendor/rich/live.py,sha256=emVaLUua-FKSYqZXmtJJjBIstO99CqMOuA6vMAKVkO0,14172 +pip/_vendor/rich/live_render.py,sha256=zElm3PrfSIvjOce28zETHMIUf9pFYSUA5o0AflgUP64,3667 +pip/_vendor/rich/logging.py,sha256=10j13lPr-QuYqEEBz_2aRJp8gNYvSN2wmCUlUqJcPLM,11471 +pip/_vendor/rich/markup.py,sha256=xzF4uAafiEeEYDJYt_vUnJOGoTU8RrH-PH7WcWYXjCg,8198 +pip/_vendor/rich/measure.py,sha256=HmrIJX8sWRTHbgh8MxEay_83VkqNW_70s8aKP5ZcYI8,5305 +pip/_vendor/rich/padding.py,sha256=kTFGsdGe0os7tXLnHKpwTI90CXEvrceeZGCshmJy5zw,4970 +pip/_vendor/rich/pager.py,sha256=SO_ETBFKbg3n_AgOzXm41Sv36YxXAyI3_R-KOY2_uSc,828 +pip/_vendor/rich/palette.py,sha256=lInvR1ODDT2f3UZMfL1grq7dY_pDdKHw4bdUgOGaM4Y,3396 +pip/_vendor/rich/panel.py,sha256=CzdojkDAjxAKgvDxis47nWzUh1V2NniOqkJJQajosG8,8744 +pip/_vendor/rich/pretty.py,sha256=CalVLVW3mvTn1hvI9Pgi2v-y4S-5zUWBK-PH7SlVs-U,36576 +pip/_vendor/rich/progress.py,sha256=zjQRwd3TmDnAvSjTPsNPHFjmqE9GOEX3bf0Lj56hIL8,59746 +pip/_vendor/rich/progress_bar.py,sha256=zHHaFPEfIhW2fq6Fnl5vBY7AUpP1N0HVGElISUHsnqw,8161 +pip/_vendor/rich/prompt.py,sha256=x0mW-pIPodJM4ry6grgmmLrl8VZp99kqcmdnBe70YYA,11303 +pip/_vendor/rich/protocol.py,sha256=5hHHDDNHckdk8iWH5zEbi-zuIVSF5hbU2jIo47R7lTE,1391 +pip/_vendor/rich/region.py,sha256=rNT9xZrVZTYIXZC0NYn41CJQwYNbR-KecPOxTgQvB8Y,166 +pip/_vendor/rich/repr.py,sha256=Je91CIrZN_av9L3FRCKCs5yoX2LvczrCNKqUbVsjUvQ,4449 +pip/_vendor/rich/rule.py,sha256=V6AWI0wCb6DB0rvN967FRMlQrdlG7HoZdfEAHyeG8CM,4773 +pip/_vendor/rich/scope.py,sha256=HX13XsJfqzQHpPfw4Jn9JmJjCsRj9uhHxXQEqjkwyLA,2842 +pip/_vendor/rich/screen.py,sha256=YoeReESUhx74grqb0mSSb9lghhysWmFHYhsbMVQjXO8,1591 +pip/_vendor/rich/segment.py,sha256=6XdX0MfL18tUCaUWDWncIqx0wpq3GiaqzhYP779JvRA,24224 +pip/_vendor/rich/spinner.py,sha256=7b8MCleS4fa46HX0AzF98zfu6ZM6fAL0UgYzPOoakF4,4374 +pip/_vendor/rich/status.py,sha256=gJsIXIZeSo3urOyxRUjs6VrhX5CZrA0NxIQ-dxhCnwo,4425 +pip/_vendor/rich/style.py,sha256=4WnUEkHNMp9Tfmd8cmbxWGby7QeTk2LUTQzFSs46EQc,26240 +pip/_vendor/rich/styled.py,sha256=eZNnzGrI4ki_54pgY3Oj0T-x3lxdXTYh4_ryDB24wBU,1258 +pip/_vendor/rich/syntax.py,sha256=_M08KbE11nNWNBPooFLKAA7lWkThPzlGUsuesxQYsuA,34697 +pip/_vendor/rich/table.py,sha256=r_lahmj45cINCWLYaIjq9yEv3gve8E6bkYTP8NDqApE,39515 +pip/_vendor/rich/terminal_theme.py,sha256=1j5-ufJfnvlAo5Qsi_ACZiXDmwMXzqgmFByObT9-yJY,3370 +pip/_vendor/rich/text.py,sha256=oajdGIeHcLcSdOwbC48_20ylDsHAS5fsPZD_Ih0clyA,44666 +pip/_vendor/rich/theme.py,sha256=GKNtQhDBZKAzDaY0vQVQQFzbc0uWfFe6CJXA-syT7zQ,3627 +pip/_vendor/rich/themes.py,sha256=0xgTLozfabebYtcJtDdC5QkX5IVUEaviqDUJJh4YVFk,102 +pip/_vendor/rich/traceback.py,sha256=MORQpXH7AvhAAThW8oIbtwffXb8M6XRkSkcJ52JuA3g,26060 +pip/_vendor/rich/tree.py,sha256=BMbUYNjS9uodNPfvtY_odmU09GA5QzcMbQ5cJZhllQI,9169 +pip/_vendor/six.py,sha256=TOOfQi7nFGfMrIvtdr6wX4wyHH8M7aknmuLfo2cBBrM,34549 +pip/_vendor/tenacity/__init__.py,sha256=rjcWJVq5PcNJNC42rt-TAGGskM-RUEkZbDKu1ra7IPo,18364 +pip/_vendor/tenacity/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/tenacity/__pycache__/_asyncio.cpython-39.pyc,, +pip/_vendor/tenacity/__pycache__/_utils.cpython-39.pyc,, +pip/_vendor/tenacity/__pycache__/after.cpython-39.pyc,, +pip/_vendor/tenacity/__pycache__/before.cpython-39.pyc,, +pip/_vendor/tenacity/__pycache__/before_sleep.cpython-39.pyc,, +pip/_vendor/tenacity/__pycache__/nap.cpython-39.pyc,, +pip/_vendor/tenacity/__pycache__/retry.cpython-39.pyc,, +pip/_vendor/tenacity/__pycache__/stop.cpython-39.pyc,, +pip/_vendor/tenacity/__pycache__/tornadoweb.cpython-39.pyc,, +pip/_vendor/tenacity/__pycache__/wait.cpython-39.pyc,, +pip/_vendor/tenacity/_asyncio.py,sha256=HEb0BVJEeBJE9P-m9XBxh1KcaF96BwoeqkJCL5sbVcQ,3314 +pip/_vendor/tenacity/_utils.py,sha256=-y68scDcyoqvTJuJJ0GTfjdSCljEYlbCYvgk7nM4NdM,1944 +pip/_vendor/tenacity/after.py,sha256=dlmyxxFy2uqpLXDr838DiEd7jgv2AGthsWHGYcGYsaI,1496 +pip/_vendor/tenacity/before.py,sha256=7XtvRmO0dRWUp8SVn24OvIiGFj8-4OP5muQRUiWgLh0,1376 +pip/_vendor/tenacity/before_sleep.py,sha256=ThyDvqKU5yle_IvYQz_b6Tp6UjUS0PhVp6zgqYl9U6Y,1908 +pip/_vendor/tenacity/nap.py,sha256=fRWvnz1aIzbIq9Ap3gAkAZgDH6oo5zxMrU6ZOVByq0I,1383 +pip/_vendor/tenacity/retry.py,sha256=Cy504Ss3UrRV7lnYgvymF66WD1wJ2dbM869kDcjuDes,7550 +pip/_vendor/tenacity/stop.py,sha256=sKHmHaoSaW6sKu3dTxUVKr1-stVkY7lw4Y9yjZU30zQ,2790 +pip/_vendor/tenacity/tornadoweb.py,sha256=E8lWO2nwe6dJgoB-N2HhQprYLDLB_UdSgFnv-EN6wKE,2145 +pip/_vendor/tenacity/wait.py,sha256=tdLTESRm5E237VHG0SxCDXRa0DHKPKVq285kslHVURc,8011 +pip/_vendor/tomli/__init__.py,sha256=JhUwV66DB1g4Hvt1UQCVMdfCu-IgAV8FXmvDU9onxd4,396 +pip/_vendor/tomli/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/tomli/__pycache__/_parser.cpython-39.pyc,, +pip/_vendor/tomli/__pycache__/_re.cpython-39.pyc,, +pip/_vendor/tomli/__pycache__/_types.cpython-39.pyc,, +pip/_vendor/tomli/_parser.py,sha256=g9-ENaALS-B8dokYpCuzUFalWlog7T-SIYMjLZSWrtM,22633 +pip/_vendor/tomli/_re.py,sha256=dbjg5ChZT23Ka9z9DHOXfdtSpPwUfdgMXnj8NOoly-w,2943 +pip/_vendor/tomli/_types.py,sha256=-GTG2VUqkpxwMqzmVO4F7ybKddIbAnuAHXfmWQcTi3Q,254 +pip/_vendor/typing_extensions.py,sha256=VKZ_nHsuzDbKOVUY2CTdavwBgfZ2EXRyluZHRzUYAbg,80114 +pip/_vendor/urllib3/__init__.py,sha256=iXLcYiJySn0GNbWOOZDDApgBL1JgP44EZ8i1760S8Mc,3333 +pip/_vendor/urllib3/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/urllib3/__pycache__/_collections.cpython-39.pyc,, +pip/_vendor/urllib3/__pycache__/_version.cpython-39.pyc,, +pip/_vendor/urllib3/__pycache__/connection.cpython-39.pyc,, +pip/_vendor/urllib3/__pycache__/connectionpool.cpython-39.pyc,, +pip/_vendor/urllib3/__pycache__/exceptions.cpython-39.pyc,, +pip/_vendor/urllib3/__pycache__/fields.cpython-39.pyc,, +pip/_vendor/urllib3/__pycache__/filepost.cpython-39.pyc,, +pip/_vendor/urllib3/__pycache__/poolmanager.cpython-39.pyc,, +pip/_vendor/urllib3/__pycache__/request.cpython-39.pyc,, +pip/_vendor/urllib3/__pycache__/response.cpython-39.pyc,, +pip/_vendor/urllib3/_collections.py,sha256=Rp1mVyBgc_UlAcp6M3at1skJBXR5J43NawRTvW2g_XY,10811 +pip/_vendor/urllib3/_version.py,sha256=GhuGBUT_MtRxHEHDb-LYs5yLPeYWlCwFBPjGZmVJbVg,64 +pip/_vendor/urllib3/connection.py,sha256=8976wL6sGeVMW0JnXvx5mD00yXu87uQjxtB9_VL8dx8,20070 +pip/_vendor/urllib3/connectionpool.py,sha256=vEzk1iJEw1qR2vHBo7m3Y98iDfna6rKkUz3AyK5lJKQ,39093 +pip/_vendor/urllib3/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-39.pyc,, +pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-39.pyc,, +pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-39.pyc,, +pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-39.pyc,, +pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-39.pyc,, +pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-39.pyc,, +pip/_vendor/urllib3/contrib/_appengine_environ.py,sha256=bDbyOEhW2CKLJcQqAKAyrEHN-aklsyHFKq6vF8ZFsmk,957 +pip/_vendor/urllib3/contrib/_securetransport/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-39.pyc,, +pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-39.pyc,, +pip/_vendor/urllib3/contrib/_securetransport/bindings.py,sha256=4Xk64qIkPBt09A5q-RIFUuDhNc9mXilVapm7WnYnzRw,17632 +pip/_vendor/urllib3/contrib/_securetransport/low_level.py,sha256=B2JBB2_NRP02xK6DCa1Pa9IuxrPwxzDzZbixQkb7U9M,13922 +pip/_vendor/urllib3/contrib/appengine.py,sha256=lfzpHFmJiO82shClLEm3QB62SYgHWnjpZOH_2JhU5Tc,11034 +pip/_vendor/urllib3/contrib/ntlmpool.py,sha256=ej9gGvfAb2Gt00lafFp45SIoRz-QwrQ4WChm6gQmAlM,4538 +pip/_vendor/urllib3/contrib/pyopenssl.py,sha256=rt9NEIP8iMBLxxRhH0jLnmshW-OFP83jEayxMSqu2MU,17182 +pip/_vendor/urllib3/contrib/securetransport.py,sha256=yhZdmVjY6PI6EeFbp7qYOp6-vp1Rkv2NMuOGaEj7pmc,34448 +pip/_vendor/urllib3/contrib/socks.py,sha256=aRi9eWXo9ZEb95XUxef4Z21CFlnnjbEiAo9HOseoMt4,7097 +pip/_vendor/urllib3/exceptions.py,sha256=0Mnno3KHTNfXRfY7638NufOPkUb6mXOm-Lqj-4x2w8A,8217 +pip/_vendor/urllib3/fields.py,sha256=kvLDCg_JmH1lLjUUEY_FLS8UhY7hBvDPuVETbY8mdrM,8579 +pip/_vendor/urllib3/filepost.py,sha256=5b_qqgRHVlL7uLtdAYBzBh-GHmU5AfJVt_2N0XS3PeY,2440 +pip/_vendor/urllib3/packages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/urllib3/packages/__pycache__/six.cpython-39.pyc,, +pip/_vendor/urllib3/packages/backports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-39.pyc,, +pip/_vendor/urllib3/packages/backports/makefile.py,sha256=nbzt3i0agPVP07jqqgjhaYjMmuAi_W5E0EywZivVO8E,1417 +pip/_vendor/urllib3/packages/six.py,sha256=b9LM0wBXv7E7SrbCjAm4wwN-hrH-iNxv18LgWNMMKPo,34665 +pip/_vendor/urllib3/poolmanager.py,sha256=0KOOJECoeLYVjUHvv-0h4Oq3FFQQ2yb-Fnjkbj8gJO0,19786 +pip/_vendor/urllib3/request.py,sha256=ZFSIqX0C6WizixecChZ3_okyu7BEv0lZu1VT0s6h4SM,5985 +pip/_vendor/urllib3/response.py,sha256=p3VBYPhwBca77wCZfmoXvEDVVC3SdF7yxQ6TXuxy1BI,30109 +pip/_vendor/urllib3/util/__init__.py,sha256=JEmSmmqqLyaw8P51gUImZh8Gwg9i1zSe-DoqAitn2nc,1155 +pip/_vendor/urllib3/util/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/urllib3/util/__pycache__/connection.cpython-39.pyc,, +pip/_vendor/urllib3/util/__pycache__/proxy.cpython-39.pyc,, +pip/_vendor/urllib3/util/__pycache__/queue.cpython-39.pyc,, +pip/_vendor/urllib3/util/__pycache__/request.cpython-39.pyc,, +pip/_vendor/urllib3/util/__pycache__/response.cpython-39.pyc,, +pip/_vendor/urllib3/util/__pycache__/retry.cpython-39.pyc,, +pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-39.pyc,, +pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-39.pyc,, +pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-39.pyc,, +pip/_vendor/urllib3/util/__pycache__/timeout.cpython-39.pyc,, +pip/_vendor/urllib3/util/__pycache__/url.cpython-39.pyc,, +pip/_vendor/urllib3/util/__pycache__/wait.cpython-39.pyc,, +pip/_vendor/urllib3/util/connection.py,sha256=5Lx2B1PW29KxBn2T0xkN1CBgRBa3gGVJBKoQoRogEVk,4901 +pip/_vendor/urllib3/util/proxy.py,sha256=zUvPPCJrp6dOF0N4GAVbOcl6o-4uXKSrGiTkkr5vUS4,1605 +pip/_vendor/urllib3/util/queue.py,sha256=nRgX8_eX-_VkvxoX096QWoz8Ps0QHUAExILCY_7PncM,498 +pip/_vendor/urllib3/util/request.py,sha256=C0OUt2tcU6LRiQJ7YYNP9GvPrSvl7ziIBekQ-5nlBZk,3997 +pip/_vendor/urllib3/util/response.py,sha256=GJpg3Egi9qaJXRwBh5wv-MNuRWan5BIu40oReoxWP28,3510 +pip/_vendor/urllib3/util/retry.py,sha256=iESg2PvViNdXBRY4MpL4h0kqwOOkHkxmLn1kkhFHPU8,22001 +pip/_vendor/urllib3/util/ssl_.py,sha256=X4-AqW91aYPhPx6-xbf66yHFQKbqqfC_5Zt4WkLX1Hc,17177 +pip/_vendor/urllib3/util/ssl_match_hostname.py,sha256=Ir4cZVEjmAk8gUAIHWSi7wtOO83UCYABY2xFD1Ql_WA,5758 +pip/_vendor/urllib3/util/ssltransport.py,sha256=NA-u5rMTrDFDFC8QzRKUEKMG0561hOD4qBTr3Z4pv6E,6895 +pip/_vendor/urllib3/util/timeout.py,sha256=QSbBUNOB9yh6AnDn61SrLQ0hg5oz0I9-uXEG91AJuIg,10003 +pip/_vendor/urllib3/util/url.py,sha256=49HwObaTUUjqVe4qvSUvIjZyf3ghgNA6-OLm3kmkFKM,14287 +pip/_vendor/urllib3/util/wait.py,sha256=fOX0_faozG2P7iVojQoE1mbydweNyTcm-hXEfFrTtLI,5403 +pip/_vendor/vendor.txt,sha256=07gLL_CcEHdl1XM0g4PH2L4gsTTMlJr8WWIC11yEyMo,469 +pip/_vendor/webencodings/__init__.py,sha256=qOBJIuPy_4ByYH6W_bNgJF-qYQ2DoU-dKsDu5yRWCXg,10579 +pip/_vendor/webencodings/__pycache__/__init__.cpython-39.pyc,, +pip/_vendor/webencodings/__pycache__/labels.cpython-39.pyc,, +pip/_vendor/webencodings/__pycache__/mklabels.cpython-39.pyc,, +pip/_vendor/webencodings/__pycache__/tests.cpython-39.pyc,, +pip/_vendor/webencodings/__pycache__/x_user_defined.cpython-39.pyc,, +pip/_vendor/webencodings/labels.py,sha256=4AO_KxTddqGtrL9ns7kAPjb0CcN6xsCIxbK37HY9r3E,8979 +pip/_vendor/webencodings/mklabels.py,sha256=GYIeywnpaLnP0GSic8LFWgd0UVvO_l1Nc6YoF-87R_4,1305 +pip/_vendor/webencodings/tests.py,sha256=OtGLyjhNY1fvkW1GvLJ_FV9ZoqC9Anyjr7q3kxTbzNs,6563 +pip/_vendor/webencodings/x_user_defined.py,sha256=yOqWSdmpytGfUgh_Z6JYgDNhoc-BAHyyeeT15Fr42tM,4307 +pip/py.typed,sha256=EBVvvPRTn_eIpz5e5QztSCdrMX7Qwd7VP93RSoIlZ2I,286 diff --git a/venv/Lib/site-packages/pip-22.3.1.dist-info/WHEEL b/venv/Lib/site-packages/pip-22.3.1.dist-info/WHEEL new file mode 100644 index 0000000..becc9a6 --- /dev/null +++ b/venv/Lib/site-packages/pip-22.3.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/pip-22.3.1.dist-info/entry_points.txt b/venv/Lib/site-packages/pip-22.3.1.dist-info/entry_points.txt new file mode 100644 index 0000000..5367846 --- /dev/null +++ b/venv/Lib/site-packages/pip-22.3.1.dist-info/entry_points.txt @@ -0,0 +1,4 @@ +[console_scripts] +pip = pip._internal.cli.main:main +pip3 = pip._internal.cli.main:main +pip3.10 = pip._internal.cli.main:main diff --git a/venv/Lib/site-packages/pip-22.3.1.dist-info/top_level.txt b/venv/Lib/site-packages/pip-22.3.1.dist-info/top_level.txt new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/pip-22.3.1.dist-info/top_level.txt @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/pip/__pip-runner__.py b/venv/Lib/site-packages/pip/__pip-runner__.py new file mode 100644 index 0000000..49a148a --- /dev/null +++ b/venv/Lib/site-packages/pip/__pip-runner__.py @@ -0,0 +1,50 @@ +"""Execute exactly this copy of pip, within a different environment. + +This file is named as it is, to ensure that this module can't be imported via +an import statement. +""" + +# /!\ This version compatibility check section must be Python 2 compatible. /!\ + +import sys + +# Copied from setup.py +PYTHON_REQUIRES = (3, 7) + + +def version_str(version): # type: ignore + return ".".join(str(v) for v in version) + + +if sys.version_info[:2] < PYTHON_REQUIRES: + raise SystemExit( + "This version of pip does not support python {} (requires >={}).".format( + version_str(sys.version_info[:2]), version_str(PYTHON_REQUIRES) + ) + ) + +# From here on, we can use Python 3 features, but the syntax must remain +# Python 2 compatible. + +import runpy # noqa: E402 +from importlib.machinery import PathFinder # noqa: E402 +from os.path import dirname # noqa: E402 + +PIP_SOURCES_ROOT = dirname(dirname(__file__)) + + +class PipImportRedirectingFinder: + @classmethod + def find_spec(self, fullname, path=None, target=None): # type: ignore + if fullname != "pip": + return None + + spec = PathFinder.find_spec(fullname, [PIP_SOURCES_ROOT], target) + assert spec, (PIP_SOURCES_ROOT, fullname) + return spec + + +sys.meta_path.insert(0, PipImportRedirectingFinder()) + +assert __name__ == "__main__", "Cannot run __pip-runner__.py as a non-main module" +runpy.run_module("pip", run_name="__main__", alter_sys=True) diff --git a/venv/Lib/site-packages/pip/_internal/commands/index.py b/venv/Lib/site-packages/pip/_internal/commands/index.py new file mode 100644 index 0000000..b4bf0ac --- /dev/null +++ b/venv/Lib/site-packages/pip/_internal/commands/index.py @@ -0,0 +1,138 @@ +import logging +from optparse import Values +from typing import Any, Iterable, List, Optional, Union + +from pip._vendor.packaging.version import LegacyVersion, Version + +from pip._internal.cli import cmdoptions +from pip._internal.cli.req_command import IndexGroupCommand +from pip._internal.cli.status_codes import ERROR, SUCCESS +from pip._internal.commands.search import print_dist_installation_info +from pip._internal.exceptions import CommandError, DistributionNotFound, PipError +from pip._internal.index.collector import LinkCollector +from pip._internal.index.package_finder import PackageFinder +from pip._internal.models.selection_prefs import SelectionPreferences +from pip._internal.models.target_python import TargetPython +from pip._internal.network.session import PipSession +from pip._internal.utils.misc import write_output + +logger = logging.getLogger(__name__) + + +class IndexCommand(IndexGroupCommand): + """ + Inspect information available from package indexes. + """ + + usage = """ + %prog versions + """ + + def add_options(self) -> None: + cmdoptions.add_target_python_options(self.cmd_opts) + + self.cmd_opts.add_option(cmdoptions.ignore_requires_python()) + self.cmd_opts.add_option(cmdoptions.pre()) + self.cmd_opts.add_option(cmdoptions.no_binary()) + self.cmd_opts.add_option(cmdoptions.only_binary()) + + index_opts = cmdoptions.make_option_group( + cmdoptions.index_group, + self.parser, + ) + + self.parser.insert_option_group(0, index_opts) + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options: Values, args: List[str]) -> int: + handlers = { + "versions": self.get_available_package_versions, + } + + logger.warning( + "pip index is currently an experimental command. " + "It may be removed/changed in a future release " + "without prior warning." + ) + + # Determine action + if not args or args[0] not in handlers: + logger.error( + "Need an action (%s) to perform.", + ", ".join(sorted(handlers)), + ) + return ERROR + + action = args[0] + + # Error handling happens here, not in the action-handlers. + try: + handlers[action](options, args[1:]) + except PipError as e: + logger.error(e.args[0]) + return ERROR + + return SUCCESS + + def _build_package_finder( + self, + options: Values, + session: PipSession, + target_python: Optional[TargetPython] = None, + ignore_requires_python: Optional[bool] = None, + ) -> PackageFinder: + """ + Create a package finder appropriate to the index command. + """ + link_collector = LinkCollector.create(session, options=options) + + # Pass allow_yanked=False to ignore yanked versions. + selection_prefs = SelectionPreferences( + allow_yanked=False, + allow_all_prereleases=options.pre, + ignore_requires_python=ignore_requires_python, + ) + + return PackageFinder.create( + link_collector=link_collector, + selection_prefs=selection_prefs, + target_python=target_python, + ) + + def get_available_package_versions(self, options: Values, args: List[Any]) -> None: + if len(args) != 1: + raise CommandError("You need to specify exactly one argument") + + target_python = cmdoptions.make_target_python(options) + query = args[0] + + with self._build_session(options) as session: + finder = self._build_package_finder( + options=options, + session=session, + target_python=target_python, + ignore_requires_python=options.ignore_requires_python, + ) + + versions: Iterable[Union[LegacyVersion, Version]] = ( + candidate.version for candidate in finder.find_all_candidates(query) + ) + + if not options.pre: + # Remove prereleases + versions = ( + version for version in versions if not version.is_prerelease + ) + versions = set(versions) + + if not versions: + raise DistributionNotFound( + "No matching distribution found for {}".format(query) + ) + + formatted_versions = [str(ver) for ver in sorted(versions, reverse=True)] + latest = formatted_versions[0] + + write_output("{} ({})".format(query, latest)) + write_output("Available versions: {}".format(", ".join(formatted_versions))) + print_dist_installation_info(query, latest) diff --git a/venv/Lib/site-packages/pip/_internal/commands/inspect.py b/venv/Lib/site-packages/pip/_internal/commands/inspect.py new file mode 100644 index 0000000..a4e3599 --- /dev/null +++ b/venv/Lib/site-packages/pip/_internal/commands/inspect.py @@ -0,0 +1,97 @@ +import logging +from optparse import Values +from typing import Any, Dict, List + +from pip._vendor.packaging.markers import default_environment +from pip._vendor.rich import print_json + +from pip import __version__ +from pip._internal.cli import cmdoptions +from pip._internal.cli.req_command import Command +from pip._internal.cli.status_codes import SUCCESS +from pip._internal.metadata import BaseDistribution, get_environment +from pip._internal.utils.compat import stdlib_pkgs +from pip._internal.utils.urls import path_to_url + +logger = logging.getLogger(__name__) + + +class InspectCommand(Command): + """ + Inspect the content of a Python environment and produce a report in JSON format. + """ + + ignore_require_venv = True + usage = """ + %prog [options]""" + + def add_options(self) -> None: + self.cmd_opts.add_option( + "--local", + action="store_true", + default=False, + help=( + "If in a virtualenv that has global access, do not list " + "globally-installed packages." + ), + ) + self.cmd_opts.add_option( + "--user", + dest="user", + action="store_true", + default=False, + help="Only output packages installed in user-site.", + ) + self.cmd_opts.add_option(cmdoptions.list_path()) + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options: Values, args: List[str]) -> int: + logger.warning( + "pip inspect is currently an experimental command. " + "The output format may change in a future release without prior warning." + ) + + cmdoptions.check_list_path_option(options) + dists = get_environment(options.path).iter_installed_distributions( + local_only=options.local, + user_only=options.user, + skip=set(stdlib_pkgs), + ) + output = { + "version": "0", + "pip_version": __version__, + "installed": [self._dist_to_dict(dist) for dist in dists], + "environment": default_environment(), + # TODO tags? scheme? + } + print_json(data=output) + return SUCCESS + + def _dist_to_dict(self, dist: BaseDistribution) -> Dict[str, Any]: + res: Dict[str, Any] = { + "metadata": dist.metadata_dict, + "metadata_location": dist.info_location, + } + # direct_url. Note that we don't have download_info (as in the installation + # report) since it is not recorded in installed metadata. + direct_url = dist.direct_url + if direct_url is not None: + res["direct_url"] = direct_url.to_dict() + else: + # Emulate direct_url for legacy editable installs. + editable_project_location = dist.editable_project_location + if editable_project_location is not None: + res["direct_url"] = { + "url": path_to_url(editable_project_location), + "dir_info": { + "editable": True, + }, + } + # installer + installer = dist.installer + if dist.installer: + res["installer"] = installer + # requested + if dist.installed_with_dist_info: + res["requested"] = dist.requested + return res diff --git a/venv/Lib/site-packages/pip/_internal/index/sources.py b/venv/Lib/site-packages/pip/_internal/index/sources.py new file mode 100644 index 0000000..eec3f12 --- /dev/null +++ b/venv/Lib/site-packages/pip/_internal/index/sources.py @@ -0,0 +1,224 @@ +import logging +import mimetypes +import os +import pathlib +from typing import Callable, Iterable, Optional, Tuple + +from pip._internal.models.candidate import InstallationCandidate +from pip._internal.models.link import Link +from pip._internal.utils.urls import path_to_url, url_to_path +from pip._internal.vcs import is_url + +logger = logging.getLogger(__name__) + +FoundCandidates = Iterable[InstallationCandidate] +FoundLinks = Iterable[Link] +CandidatesFromPage = Callable[[Link], Iterable[InstallationCandidate]] +PageValidator = Callable[[Link], bool] + + +class LinkSource: + @property + def link(self) -> Optional[Link]: + """Returns the underlying link, if there's one.""" + raise NotImplementedError() + + def page_candidates(self) -> FoundCandidates: + """Candidates found by parsing an archive listing HTML file.""" + raise NotImplementedError() + + def file_links(self) -> FoundLinks: + """Links found by specifying archives directly.""" + raise NotImplementedError() + + +def _is_html_file(file_url: str) -> bool: + return mimetypes.guess_type(file_url, strict=False)[0] == "text/html" + + +class _FlatDirectorySource(LinkSource): + """Link source specified by ``--find-links=``. + + This looks the content of the directory, and returns: + + * ``page_candidates``: Links listed on each HTML file in the directory. + * ``file_candidates``: Archives in the directory. + """ + + def __init__( + self, + candidates_from_page: CandidatesFromPage, + path: str, + ) -> None: + self._candidates_from_page = candidates_from_page + self._path = pathlib.Path(os.path.realpath(path)) + + @property + def link(self) -> Optional[Link]: + return None + + def page_candidates(self) -> FoundCandidates: + for path in self._path.iterdir(): + url = path_to_url(str(path)) + if not _is_html_file(url): + continue + yield from self._candidates_from_page(Link(url)) + + def file_links(self) -> FoundLinks: + for path in self._path.iterdir(): + url = path_to_url(str(path)) + if _is_html_file(url): + continue + yield Link(url) + + +class _LocalFileSource(LinkSource): + """``--find-links=`` or ``--[extra-]index-url=``. + + If a URL is supplied, it must be a ``file:`` URL. If a path is supplied to + the option, it is converted to a URL first. This returns: + + * ``page_candidates``: Links listed on an HTML file. + * ``file_candidates``: The non-HTML file. + """ + + def __init__( + self, + candidates_from_page: CandidatesFromPage, + link: Link, + ) -> None: + self._candidates_from_page = candidates_from_page + self._link = link + + @property + def link(self) -> Optional[Link]: + return self._link + + def page_candidates(self) -> FoundCandidates: + if not _is_html_file(self._link.url): + return + yield from self._candidates_from_page(self._link) + + def file_links(self) -> FoundLinks: + if _is_html_file(self._link.url): + return + yield self._link + + +class _RemoteFileSource(LinkSource): + """``--find-links=`` or ``--[extra-]index-url=``. + + This returns: + + * ``page_candidates``: Links listed on an HTML file. + * ``file_candidates``: The non-HTML file. + """ + + def __init__( + self, + candidates_from_page: CandidatesFromPage, + page_validator: PageValidator, + link: Link, + ) -> None: + self._candidates_from_page = candidates_from_page + self._page_validator = page_validator + self._link = link + + @property + def link(self) -> Optional[Link]: + return self._link + + def page_candidates(self) -> FoundCandidates: + if not self._page_validator(self._link): + return + yield from self._candidates_from_page(self._link) + + def file_links(self) -> FoundLinks: + yield self._link + + +class _IndexDirectorySource(LinkSource): + """``--[extra-]index-url=``. + + This is treated like a remote URL; ``candidates_from_page`` contains logic + for this by appending ``index.html`` to the link. + """ + + def __init__( + self, + candidates_from_page: CandidatesFromPage, + link: Link, + ) -> None: + self._candidates_from_page = candidates_from_page + self._link = link + + @property + def link(self) -> Optional[Link]: + return self._link + + def page_candidates(self) -> FoundCandidates: + yield from self._candidates_from_page(self._link) + + def file_links(self) -> FoundLinks: + return () + + +def build_source( + location: str, + *, + candidates_from_page: CandidatesFromPage, + page_validator: PageValidator, + expand_dir: bool, + cache_link_parsing: bool, +) -> Tuple[Optional[str], Optional[LinkSource]]: + + path: Optional[str] = None + url: Optional[str] = None + if os.path.exists(location): # Is a local path. + url = path_to_url(location) + path = location + elif location.startswith("file:"): # A file: URL. + url = location + path = url_to_path(location) + elif is_url(location): + url = location + + if url is None: + msg = ( + "Location '%s' is ignored: " + "it is either a non-existing path or lacks a specific scheme." + ) + logger.warning(msg, location) + return (None, None) + + if path is None: + source: LinkSource = _RemoteFileSource( + candidates_from_page=candidates_from_page, + page_validator=page_validator, + link=Link(url, cache_link_parsing=cache_link_parsing), + ) + return (url, source) + + if os.path.isdir(path): + if expand_dir: + source = _FlatDirectorySource( + candidates_from_page=candidates_from_page, + path=path, + ) + else: + source = _IndexDirectorySource( + candidates_from_page=candidates_from_page, + link=Link(url, cache_link_parsing=cache_link_parsing), + ) + return (url, source) + elif os.path.isfile(path): + source = _LocalFileSource( + candidates_from_page=candidates_from_page, + link=Link(url, cache_link_parsing=cache_link_parsing), + ) + return (url, source) + logger.warning( + "Location '%s' is ignored: it is neither a file nor a directory.", + location, + ) + return (url, None) diff --git a/venv/Lib/site-packages/pip/_internal/models/installation_report.py b/venv/Lib/site-packages/pip/_internal/models/installation_report.py new file mode 100644 index 0000000..965f095 --- /dev/null +++ b/venv/Lib/site-packages/pip/_internal/models/installation_report.py @@ -0,0 +1,53 @@ +from typing import Any, Dict, Sequence + +from pip._vendor.packaging.markers import default_environment + +from pip import __version__ +from pip._internal.req.req_install import InstallRequirement + + +class InstallationReport: + def __init__(self, install_requirements: Sequence[InstallRequirement]): + self._install_requirements = install_requirements + + @classmethod + def _install_req_to_dict(cls, ireq: InstallRequirement) -> Dict[str, Any]: + assert ireq.download_info, f"No download_info for {ireq}" + res = { + # PEP 610 json for the download URL. download_info.archive_info.hash may + # be absent when the requirement was installed from the wheel cache + # and the cache entry was populated by an older pip version that did not + # record origin.json. + "download_info": ireq.download_info.to_dict(), + # is_direct is true if the requirement was a direct URL reference (which + # includes editable requirements), and false if the requirement was + # downloaded from a PEP 503 index or --find-links. + "is_direct": bool(ireq.original_link), + # requested is true if the requirement was specified by the user (aka + # top level requirement), and false if it was installed as a dependency of a + # requirement. https://peps.python.org/pep-0376/#requested + "requested": ireq.user_supplied, + # PEP 566 json encoding for metadata + # https://www.python.org/dev/peps/pep-0566/#json-compatible-metadata + "metadata": ireq.get_dist().metadata_dict, + } + if ireq.user_supplied and ireq.extras: + # For top level requirements, the list of requested extras, if any. + res["requested_extras"] = list(sorted(ireq.extras)) + return res + + def to_dict(self) -> Dict[str, Any]: + return { + "version": "0", + "pip_version": __version__, + "install": [ + self._install_req_to_dict(ireq) for ireq in self._install_requirements + ], + # https://peps.python.org/pep-0508/#environment-markers + # TODO: currently, the resolver uses the default environment to evaluate + # environment markers, so that is what we report here. In the future, it + # should also take into account options such as --python-version or + # --platform, perhaps under the form of an environment_override field? + # https://github.com/pypa/pip/issues/11198 + "environment": default_environment(), + } diff --git a/venv/Lib/site-packages/pip/_internal/operations/build/build_tracker.py b/venv/Lib/site-packages/pip/_internal/operations/build/build_tracker.py new file mode 100644 index 0000000..6621549 --- /dev/null +++ b/venv/Lib/site-packages/pip/_internal/operations/build/build_tracker.py @@ -0,0 +1,124 @@ +import contextlib +import hashlib +import logging +import os +from types import TracebackType +from typing import Dict, Generator, Optional, Set, Type, Union + +from pip._internal.models.link import Link +from pip._internal.req.req_install import InstallRequirement +from pip._internal.utils.temp_dir import TempDirectory + +logger = logging.getLogger(__name__) + + +@contextlib.contextmanager +def update_env_context_manager(**changes: str) -> Generator[None, None, None]: + target = os.environ + + # Save values from the target and change them. + non_existent_marker = object() + saved_values: Dict[str, Union[object, str]] = {} + for name, new_value in changes.items(): + try: + saved_values[name] = target[name] + except KeyError: + saved_values[name] = non_existent_marker + target[name] = new_value + + try: + yield + finally: + # Restore original values in the target. + for name, original_value in saved_values.items(): + if original_value is non_existent_marker: + del target[name] + else: + assert isinstance(original_value, str) # for mypy + target[name] = original_value + + +@contextlib.contextmanager +def get_build_tracker() -> Generator["BuildTracker", None, None]: + root = os.environ.get("PIP_BUILD_TRACKER") + with contextlib.ExitStack() as ctx: + if root is None: + root = ctx.enter_context(TempDirectory(kind="build-tracker")).path + ctx.enter_context(update_env_context_manager(PIP_BUILD_TRACKER=root)) + logger.debug("Initialized build tracking at %s", root) + + with BuildTracker(root) as tracker: + yield tracker + + +class BuildTracker: + def __init__(self, root: str) -> None: + self._root = root + self._entries: Set[InstallRequirement] = set() + logger.debug("Created build tracker: %s", self._root) + + def __enter__(self) -> "BuildTracker": + logger.debug("Entered build tracker: %s", self._root) + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + self.cleanup() + + def _entry_path(self, link: Link) -> str: + hashed = hashlib.sha224(link.url_without_fragment.encode()).hexdigest() + return os.path.join(self._root, hashed) + + def add(self, req: InstallRequirement) -> None: + """Add an InstallRequirement to build tracking.""" + + assert req.link + # Get the file to write information about this requirement. + entry_path = self._entry_path(req.link) + + # Try reading from the file. If it exists and can be read from, a build + # is already in progress, so a LookupError is raised. + try: + with open(entry_path) as fp: + contents = fp.read() + except FileNotFoundError: + pass + else: + message = "{} is already being built: {}".format(req.link, contents) + raise LookupError(message) + + # If we're here, req should really not be building already. + assert req not in self._entries + + # Start tracking this requirement. + with open(entry_path, "w", encoding="utf-8") as fp: + fp.write(str(req)) + self._entries.add(req) + + logger.debug("Added %s to build tracker %r", req, self._root) + + def remove(self, req: InstallRequirement) -> None: + """Remove an InstallRequirement from build tracking.""" + + assert req.link + # Delete the created file and the corresponding entries. + os.unlink(self._entry_path(req.link)) + self._entries.remove(req) + + logger.debug("Removed %s from build tracker %r", req, self._root) + + def cleanup(self) -> None: + for req in set(self._entries): + self.remove(req) + + logger.debug("Removed build tracker: %r", self._root) + + @contextlib.contextmanager + def track(self, req: InstallRequirement) -> Generator[None, None, None]: + self.add(req) + yield + self.remove(req) diff --git a/venv/Lib/site-packages/pip/_internal/operations/build/metadata_editable.py b/venv/Lib/site-packages/pip/_internal/operations/build/metadata_editable.py new file mode 100644 index 0000000..4c3f48b --- /dev/null +++ b/venv/Lib/site-packages/pip/_internal/operations/build/metadata_editable.py @@ -0,0 +1,41 @@ +"""Metadata generation logic for source distributions. +""" + +import os + +from pip._vendor.pep517.wrappers import Pep517HookCaller + +from pip._internal.build_env import BuildEnvironment +from pip._internal.exceptions import ( + InstallationSubprocessError, + MetadataGenerationFailed, +) +from pip._internal.utils.subprocess import runner_with_spinner_message +from pip._internal.utils.temp_dir import TempDirectory + + +def generate_editable_metadata( + build_env: BuildEnvironment, backend: Pep517HookCaller, details: str +) -> str: + """Generate metadata using mechanisms described in PEP 660. + + Returns the generated metadata directory. + """ + metadata_tmpdir = TempDirectory(kind="modern-metadata", globally_managed=True) + + metadata_dir = metadata_tmpdir.path + + with build_env: + # Note that Pep517HookCaller implements a fallback for + # prepare_metadata_for_build_wheel/editable, so we don't have to + # consider the possibility that this hook doesn't exist. + runner = runner_with_spinner_message( + "Preparing editable metadata (pyproject.toml)" + ) + with backend.subprocess_runner(runner): + try: + distinfo_dir = backend.prepare_metadata_for_build_editable(metadata_dir) + except InstallationSubprocessError as error: + raise MetadataGenerationFailed(package_details=details) from error + + return os.path.join(metadata_dir, distinfo_dir) diff --git a/venv/Lib/site-packages/pip/_internal/operations/build/wheel_editable.py b/venv/Lib/site-packages/pip/_internal/operations/build/wheel_editable.py new file mode 100644 index 0000000..cf7b01a --- /dev/null +++ b/venv/Lib/site-packages/pip/_internal/operations/build/wheel_editable.py @@ -0,0 +1,46 @@ +import logging +import os +from typing import Optional + +from pip._vendor.pep517.wrappers import HookMissing, Pep517HookCaller + +from pip._internal.utils.subprocess import runner_with_spinner_message + +logger = logging.getLogger(__name__) + + +def build_wheel_editable( + name: str, + backend: Pep517HookCaller, + metadata_directory: str, + tempd: str, +) -> Optional[str]: + """Build one InstallRequirement using the PEP 660 build process. + + Returns path to wheel if successfully built. Otherwise, returns None. + """ + assert metadata_directory is not None + try: + logger.debug("Destination directory: %s", tempd) + + runner = runner_with_spinner_message( + f"Building editable for {name} (pyproject.toml)" + ) + with backend.subprocess_runner(runner): + try: + wheel_name = backend.build_editable( + tempd, + metadata_directory=metadata_directory, + ) + except HookMissing as e: + logger.error( + "Cannot build editable %s because the build " + "backend does not have the %s hook", + name, + e, + ) + return None + except Exception: + logger.error("Failed building editable for %s", name) + return None + return os.path.join(tempd, wheel_name) diff --git a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py new file mode 100644 index 0000000..8663097 --- /dev/null +++ b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py @@ -0,0 +1,155 @@ +"""Utilities to lazily create and visit candidates found. + +Creating and visiting a candidate is a *very* costly operation. It involves +fetching, extracting, potentially building modules from source, and verifying +distribution metadata. It is therefore crucial for performance to keep +everything here lazy all the way down, so we only touch candidates that we +absolutely need, and not "download the world" when we only need one version of +something. +""" + +import functools +from collections.abc import Sequence +from typing import TYPE_CHECKING, Any, Callable, Iterator, Optional, Set, Tuple + +from pip._vendor.packaging.version import _BaseVersion + +from .base import Candidate + +IndexCandidateInfo = Tuple[_BaseVersion, Callable[[], Optional[Candidate]]] + +if TYPE_CHECKING: + SequenceCandidate = Sequence[Candidate] +else: + # For compatibility: Python before 3.9 does not support using [] on the + # Sequence class. + # + # >>> from collections.abc import Sequence + # >>> Sequence[str] + # Traceback (most recent call last): + # File "", line 1, in + # TypeError: 'ABCMeta' object is not subscriptable + # + # TODO: Remove this block after dropping Python 3.8 support. + SequenceCandidate = Sequence + + +def _iter_built(infos: Iterator[IndexCandidateInfo]) -> Iterator[Candidate]: + """Iterator for ``FoundCandidates``. + + This iterator is used when the package is not already installed. Candidates + from index come later in their normal ordering. + """ + versions_found: Set[_BaseVersion] = set() + for version, func in infos: + if version in versions_found: + continue + candidate = func() + if candidate is None: + continue + yield candidate + versions_found.add(version) + + +def _iter_built_with_prepended( + installed: Candidate, infos: Iterator[IndexCandidateInfo] +) -> Iterator[Candidate]: + """Iterator for ``FoundCandidates``. + + This iterator is used when the resolver prefers the already-installed + candidate and NOT to upgrade. The installed candidate is therefore + always yielded first, and candidates from index come later in their + normal ordering, except skipped when the version is already installed. + """ + yield installed + versions_found: Set[_BaseVersion] = {installed.version} + for version, func in infos: + if version in versions_found: + continue + candidate = func() + if candidate is None: + continue + yield candidate + versions_found.add(version) + + +def _iter_built_with_inserted( + installed: Candidate, infos: Iterator[IndexCandidateInfo] +) -> Iterator[Candidate]: + """Iterator for ``FoundCandidates``. + + This iterator is used when the resolver prefers to upgrade an + already-installed package. Candidates from index are returned in their + normal ordering, except replaced when the version is already installed. + + The implementation iterates through and yields other candidates, inserting + the installed candidate exactly once before we start yielding older or + equivalent candidates, or after all other candidates if they are all newer. + """ + versions_found: Set[_BaseVersion] = set() + for version, func in infos: + if version in versions_found: + continue + # If the installed candidate is better, yield it first. + if installed.version >= version: + yield installed + versions_found.add(installed.version) + candidate = func() + if candidate is None: + continue + yield candidate + versions_found.add(version) + + # If the installed candidate is older than all other candidates. + if installed.version not in versions_found: + yield installed + + +class FoundCandidates(SequenceCandidate): + """A lazy sequence to provide candidates to the resolver. + + The intended usage is to return this from `find_matches()` so the resolver + can iterate through the sequence multiple times, but only access the index + page when remote packages are actually needed. This improve performances + when suitable candidates are already installed on disk. + """ + + def __init__( + self, + get_infos: Callable[[], Iterator[IndexCandidateInfo]], + installed: Optional[Candidate], + prefers_installed: bool, + incompatible_ids: Set[int], + ): + self._get_infos = get_infos + self._installed = installed + self._prefers_installed = prefers_installed + self._incompatible_ids = incompatible_ids + + def __getitem__(self, index: Any) -> Any: + # Implemented to satisfy the ABC check. This is not needed by the + # resolver, and should not be used by the provider either (for + # performance reasons). + raise NotImplementedError("don't do this") + + def __iter__(self) -> Iterator[Candidate]: + infos = self._get_infos() + if not self._installed: + iterator = _iter_built(infos) + elif self._prefers_installed: + iterator = _iter_built_with_prepended(self._installed, infos) + else: + iterator = _iter_built_with_inserted(self._installed, infos) + return (c for c in iterator if id(c) not in self._incompatible_ids) + + def __len__(self) -> int: + # Implemented to satisfy the ABC check. This is not needed by the + # resolver, and should not be used by the provider either (for + # performance reasons). + raise NotImplementedError("don't do this") + + @functools.lru_cache(maxsize=1) + def __bool__(self) -> bool: + if self._prefers_installed and self._installed: + return True + return any(self) diff --git a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/reporter.py b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/reporter.py new file mode 100644 index 0000000..6ced532 --- /dev/null +++ b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/reporter.py @@ -0,0 +1,68 @@ +from collections import defaultdict +from logging import getLogger +from typing import Any, DefaultDict + +from pip._vendor.resolvelib.reporters import BaseReporter + +from .base import Candidate, Requirement + +logger = getLogger(__name__) + + +class PipReporter(BaseReporter): + def __init__(self) -> None: + self.backtracks_by_package: DefaultDict[str, int] = defaultdict(int) + + self._messages_at_backtrack = { + 1: ( + "pip is looking at multiple versions of {package_name} to " + "determine which version is compatible with other " + "requirements. This could take a while." + ), + 8: ( + "pip is looking at multiple versions of {package_name} to " + "determine which version is compatible with other " + "requirements. This could take a while." + ), + 13: ( + "This is taking longer than usual. You might need to provide " + "the dependency resolver with stricter constraints to reduce " + "runtime. See https://pip.pypa.io/warnings/backtracking for " + "guidance. If you want to abort this run, press Ctrl + C." + ), + } + + def backtracking(self, candidate: Candidate) -> None: + self.backtracks_by_package[candidate.name] += 1 + + count = self.backtracks_by_package[candidate.name] + if count not in self._messages_at_backtrack: + return + + message = self._messages_at_backtrack[count] + logger.info("INFO: %s", message.format(package_name=candidate.name)) + + +class PipDebuggingReporter(BaseReporter): + """A reporter that does an info log for every event it sees.""" + + def starting(self) -> None: + logger.info("Reporter.starting()") + + def starting_round(self, index: int) -> None: + logger.info("Reporter.starting_round(%r)", index) + + def ending_round(self, index: int, state: Any) -> None: + logger.info("Reporter.ending_round(%r, state)", index) + + def ending(self, state: Any) -> None: + logger.info("Reporter.ending(%r)", state) + + def adding_requirement(self, requirement: Requirement, parent: Candidate) -> None: + logger.info("Reporter.adding_requirement(%r, %r)", requirement, parent) + + def backtracking(self, candidate: Candidate) -> None: + logger.info("Reporter.backtracking(%r)", candidate) + + def pinning(self, candidate: Candidate) -> None: + logger.info("Reporter.pinning(%r)", candidate) diff --git a/venv/Lib/site-packages/pip/_internal/utils/_log.py b/venv/Lib/site-packages/pip/_internal/utils/_log.py new file mode 100644 index 0000000..92c4c6a --- /dev/null +++ b/venv/Lib/site-packages/pip/_internal/utils/_log.py @@ -0,0 +1,38 @@ +"""Customize logging + +Defines custom logger class for the `logger.verbose(...)` method. + +init_logging() must be called before any other modules that call logging.getLogger. +""" + +import logging +from typing import Any, cast + +# custom log level for `--verbose` output +# between DEBUG and INFO +VERBOSE = 15 + + +class VerboseLogger(logging.Logger): + """Custom Logger, defining a verbose log-level + + VERBOSE is between INFO and DEBUG. + """ + + def verbose(self, msg: str, *args: Any, **kwargs: Any) -> None: + return self.log(VERBOSE, msg, *args, **kwargs) + + +def getLogger(name: str) -> VerboseLogger: + """logging.getLogger, but ensures our VerboseLogger class is returned""" + return cast(VerboseLogger, logging.getLogger(name)) + + +def init_logging() -> None: + """Register our VerboseLogger and VERBOSE log level. + + Should be called before any calls to getLogger(), + i.e. in pip._internal.__init__ + """ + logging.setLoggerClass(VerboseLogger) + logging.addLevelName(VERBOSE, "VERBOSE") diff --git a/venv/Lib/site-packages/pip/_internal/utils/egg_link.py b/venv/Lib/site-packages/pip/_internal/utils/egg_link.py new file mode 100644 index 0000000..9e0da8d --- /dev/null +++ b/venv/Lib/site-packages/pip/_internal/utils/egg_link.py @@ -0,0 +1,75 @@ +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +import os +import re +import sys +from typing import Optional + +from pip._internal.locations import site_packages, user_site +from pip._internal.utils.virtualenv import ( + running_under_virtualenv, + virtualenv_no_global, +) + +__all__ = [ + "egg_link_path_from_sys_path", + "egg_link_path_from_location", +] + + +def _egg_link_name(raw_name: str) -> str: + """ + Convert a Name metadata value to a .egg-link name, by applying + the same substitution as pkg_resources's safe_name function. + Note: we cannot use canonicalize_name because it has a different logic. + """ + return re.sub("[^A-Za-z0-9.]+", "-", raw_name) + ".egg-link" + + +def egg_link_path_from_sys_path(raw_name: str) -> Optional[str]: + """ + Look for a .egg-link file for project name, by walking sys.path. + """ + egg_link_name = _egg_link_name(raw_name) + for path_item in sys.path: + egg_link = os.path.join(path_item, egg_link_name) + if os.path.isfile(egg_link): + return egg_link + return None + + +def egg_link_path_from_location(raw_name: str) -> Optional[str]: + """ + Return the path for the .egg-link file if it exists, otherwise, None. + + There's 3 scenarios: + 1) not in a virtualenv + try to find in site.USER_SITE, then site_packages + 2) in a no-global virtualenv + try to find in site_packages + 3) in a yes-global virtualenv + try to find in site_packages, then site.USER_SITE + (don't look in global location) + + For #1 and #3, there could be odd cases, where there's an egg-link in 2 + locations. + + This method will just return the first one found. + """ + sites = [] + if running_under_virtualenv(): + sites.append(site_packages) + if not virtualenv_no_global() and user_site: + sites.append(user_site) + else: + if user_site: + sites.append(user_site) + sites.append(site_packages) + + egg_link_name = _egg_link_name(raw_name) + for site in sites: + egglink = os.path.join(site, egg_link_name) + if os.path.isfile(egglink): + return egglink + return None diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/johabfreq.py b/venv/Lib/site-packages/pip/_vendor/chardet/johabfreq.py new file mode 100644 index 0000000..c129699 --- /dev/null +++ b/venv/Lib/site-packages/pip/_vendor/chardet/johabfreq.py @@ -0,0 +1,2382 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# The frequency data itself is the same as euc-kr. +# This is just a mapping table to euc-kr. + +JOHAB_TO_EUCKR_ORDER_TABLE = { + 0x8861: 0, + 0x8862: 1, + 0x8865: 2, + 0x8868: 3, + 0x8869: 4, + 0x886A: 5, + 0x886B: 6, + 0x8871: 7, + 0x8873: 8, + 0x8874: 9, + 0x8875: 10, + 0x8876: 11, + 0x8877: 12, + 0x8878: 13, + 0x8879: 14, + 0x887B: 15, + 0x887C: 16, + 0x887D: 17, + 0x8881: 18, + 0x8882: 19, + 0x8885: 20, + 0x8889: 21, + 0x8891: 22, + 0x8893: 23, + 0x8895: 24, + 0x8896: 25, + 0x8897: 26, + 0x88A1: 27, + 0x88A2: 28, + 0x88A5: 29, + 0x88A9: 30, + 0x88B5: 31, + 0x88B7: 32, + 0x88C1: 33, + 0x88C5: 34, + 0x88C9: 35, + 0x88E1: 36, + 0x88E2: 37, + 0x88E5: 38, + 0x88E8: 39, + 0x88E9: 40, + 0x88EB: 41, + 0x88F1: 42, + 0x88F3: 43, + 0x88F5: 44, + 0x88F6: 45, + 0x88F7: 46, + 0x88F8: 47, + 0x88FB: 48, + 0x88FC: 49, + 0x88FD: 50, + 0x8941: 51, + 0x8945: 52, + 0x8949: 53, + 0x8951: 54, + 0x8953: 55, + 0x8955: 56, + 0x8956: 57, + 0x8957: 58, + 0x8961: 59, + 0x8962: 60, + 0x8963: 61, + 0x8965: 62, + 0x8968: 63, + 0x8969: 64, + 0x8971: 65, + 0x8973: 66, + 0x8975: 67, + 0x8976: 68, + 0x8977: 69, + 0x897B: 70, + 0x8981: 71, + 0x8985: 72, + 0x8989: 73, + 0x8993: 74, + 0x8995: 75, + 0x89A1: 76, + 0x89A2: 77, + 0x89A5: 78, + 0x89A8: 79, + 0x89A9: 80, + 0x89AB: 81, + 0x89AD: 82, + 0x89B0: 83, + 0x89B1: 84, + 0x89B3: 85, + 0x89B5: 86, + 0x89B7: 87, + 0x89B8: 88, + 0x89C1: 89, + 0x89C2: 90, + 0x89C5: 91, + 0x89C9: 92, + 0x89CB: 93, + 0x89D1: 94, + 0x89D3: 95, + 0x89D5: 96, + 0x89D7: 97, + 0x89E1: 98, + 0x89E5: 99, + 0x89E9: 100, + 0x89F3: 101, + 0x89F6: 102, + 0x89F7: 103, + 0x8A41: 104, + 0x8A42: 105, + 0x8A45: 106, + 0x8A49: 107, + 0x8A51: 108, + 0x8A53: 109, + 0x8A55: 110, + 0x8A57: 111, + 0x8A61: 112, + 0x8A65: 113, + 0x8A69: 114, + 0x8A73: 115, + 0x8A75: 116, + 0x8A81: 117, + 0x8A82: 118, + 0x8A85: 119, + 0x8A88: 120, + 0x8A89: 121, + 0x8A8A: 122, + 0x8A8B: 123, + 0x8A90: 124, + 0x8A91: 125, + 0x8A93: 126, + 0x8A95: 127, + 0x8A97: 128, + 0x8A98: 129, + 0x8AA1: 130, + 0x8AA2: 131, + 0x8AA5: 132, + 0x8AA9: 133, + 0x8AB6: 134, + 0x8AB7: 135, + 0x8AC1: 136, + 0x8AD5: 137, + 0x8AE1: 138, + 0x8AE2: 139, + 0x8AE5: 140, + 0x8AE9: 141, + 0x8AF1: 142, + 0x8AF3: 143, + 0x8AF5: 144, + 0x8B41: 145, + 0x8B45: 146, + 0x8B49: 147, + 0x8B61: 148, + 0x8B62: 149, + 0x8B65: 150, + 0x8B68: 151, + 0x8B69: 152, + 0x8B6A: 153, + 0x8B71: 154, + 0x8B73: 155, + 0x8B75: 156, + 0x8B77: 157, + 0x8B81: 158, + 0x8BA1: 159, + 0x8BA2: 160, + 0x8BA5: 161, + 0x8BA8: 162, + 0x8BA9: 163, + 0x8BAB: 164, + 0x8BB1: 165, + 0x8BB3: 166, + 0x8BB5: 167, + 0x8BB7: 168, + 0x8BB8: 169, + 0x8BBC: 170, + 0x8C61: 171, + 0x8C62: 172, + 0x8C63: 173, + 0x8C65: 174, + 0x8C69: 175, + 0x8C6B: 176, + 0x8C71: 177, + 0x8C73: 178, + 0x8C75: 179, + 0x8C76: 180, + 0x8C77: 181, + 0x8C7B: 182, + 0x8C81: 183, + 0x8C82: 184, + 0x8C85: 185, + 0x8C89: 186, + 0x8C91: 187, + 0x8C93: 188, + 0x8C95: 189, + 0x8C96: 190, + 0x8C97: 191, + 0x8CA1: 192, + 0x8CA2: 193, + 0x8CA9: 194, + 0x8CE1: 195, + 0x8CE2: 196, + 0x8CE3: 197, + 0x8CE5: 198, + 0x8CE9: 199, + 0x8CF1: 200, + 0x8CF3: 201, + 0x8CF5: 202, + 0x8CF6: 203, + 0x8CF7: 204, + 0x8D41: 205, + 0x8D42: 206, + 0x8D45: 207, + 0x8D51: 208, + 0x8D55: 209, + 0x8D57: 210, + 0x8D61: 211, + 0x8D65: 212, + 0x8D69: 213, + 0x8D75: 214, + 0x8D76: 215, + 0x8D7B: 216, + 0x8D81: 217, + 0x8DA1: 218, + 0x8DA2: 219, + 0x8DA5: 220, + 0x8DA7: 221, + 0x8DA9: 222, + 0x8DB1: 223, + 0x8DB3: 224, + 0x8DB5: 225, + 0x8DB7: 226, + 0x8DB8: 227, + 0x8DB9: 228, + 0x8DC1: 229, + 0x8DC2: 230, + 0x8DC9: 231, + 0x8DD6: 232, + 0x8DD7: 233, + 0x8DE1: 234, + 0x8DE2: 235, + 0x8DF7: 236, + 0x8E41: 237, + 0x8E45: 238, + 0x8E49: 239, + 0x8E51: 240, + 0x8E53: 241, + 0x8E57: 242, + 0x8E61: 243, + 0x8E81: 244, + 0x8E82: 245, + 0x8E85: 246, + 0x8E89: 247, + 0x8E90: 248, + 0x8E91: 249, + 0x8E93: 250, + 0x8E95: 251, + 0x8E97: 252, + 0x8E98: 253, + 0x8EA1: 254, + 0x8EA9: 255, + 0x8EB6: 256, + 0x8EB7: 257, + 0x8EC1: 258, + 0x8EC2: 259, + 0x8EC5: 260, + 0x8EC9: 261, + 0x8ED1: 262, + 0x8ED3: 263, + 0x8ED6: 264, + 0x8EE1: 265, + 0x8EE5: 266, + 0x8EE9: 267, + 0x8EF1: 268, + 0x8EF3: 269, + 0x8F41: 270, + 0x8F61: 271, + 0x8F62: 272, + 0x8F65: 273, + 0x8F67: 274, + 0x8F69: 275, + 0x8F6B: 276, + 0x8F70: 277, + 0x8F71: 278, + 0x8F73: 279, + 0x8F75: 280, + 0x8F77: 281, + 0x8F7B: 282, + 0x8FA1: 283, + 0x8FA2: 284, + 0x8FA5: 285, + 0x8FA9: 286, + 0x8FB1: 287, + 0x8FB3: 288, + 0x8FB5: 289, + 0x8FB7: 290, + 0x9061: 291, + 0x9062: 292, + 0x9063: 293, + 0x9065: 294, + 0x9068: 295, + 0x9069: 296, + 0x906A: 297, + 0x906B: 298, + 0x9071: 299, + 0x9073: 300, + 0x9075: 301, + 0x9076: 302, + 0x9077: 303, + 0x9078: 304, + 0x9079: 305, + 0x907B: 306, + 0x907D: 307, + 0x9081: 308, + 0x9082: 309, + 0x9085: 310, + 0x9089: 311, + 0x9091: 312, + 0x9093: 313, + 0x9095: 314, + 0x9096: 315, + 0x9097: 316, + 0x90A1: 317, + 0x90A2: 318, + 0x90A5: 319, + 0x90A9: 320, + 0x90B1: 321, + 0x90B7: 322, + 0x90E1: 323, + 0x90E2: 324, + 0x90E4: 325, + 0x90E5: 326, + 0x90E9: 327, + 0x90EB: 328, + 0x90EC: 329, + 0x90F1: 330, + 0x90F3: 331, + 0x90F5: 332, + 0x90F6: 333, + 0x90F7: 334, + 0x90FD: 335, + 0x9141: 336, + 0x9142: 337, + 0x9145: 338, + 0x9149: 339, + 0x9151: 340, + 0x9153: 341, + 0x9155: 342, + 0x9156: 343, + 0x9157: 344, + 0x9161: 345, + 0x9162: 346, + 0x9165: 347, + 0x9169: 348, + 0x9171: 349, + 0x9173: 350, + 0x9176: 351, + 0x9177: 352, + 0x917A: 353, + 0x9181: 354, + 0x9185: 355, + 0x91A1: 356, + 0x91A2: 357, + 0x91A5: 358, + 0x91A9: 359, + 0x91AB: 360, + 0x91B1: 361, + 0x91B3: 362, + 0x91B5: 363, + 0x91B7: 364, + 0x91BC: 365, + 0x91BD: 366, + 0x91C1: 367, + 0x91C5: 368, + 0x91C9: 369, + 0x91D6: 370, + 0x9241: 371, + 0x9245: 372, + 0x9249: 373, + 0x9251: 374, + 0x9253: 375, + 0x9255: 376, + 0x9261: 377, + 0x9262: 378, + 0x9265: 379, + 0x9269: 380, + 0x9273: 381, + 0x9275: 382, + 0x9277: 383, + 0x9281: 384, + 0x9282: 385, + 0x9285: 386, + 0x9288: 387, + 0x9289: 388, + 0x9291: 389, + 0x9293: 390, + 0x9295: 391, + 0x9297: 392, + 0x92A1: 393, + 0x92B6: 394, + 0x92C1: 395, + 0x92E1: 396, + 0x92E5: 397, + 0x92E9: 398, + 0x92F1: 399, + 0x92F3: 400, + 0x9341: 401, + 0x9342: 402, + 0x9349: 403, + 0x9351: 404, + 0x9353: 405, + 0x9357: 406, + 0x9361: 407, + 0x9362: 408, + 0x9365: 409, + 0x9369: 410, + 0x936A: 411, + 0x936B: 412, + 0x9371: 413, + 0x9373: 414, + 0x9375: 415, + 0x9377: 416, + 0x9378: 417, + 0x937C: 418, + 0x9381: 419, + 0x9385: 420, + 0x9389: 421, + 0x93A1: 422, + 0x93A2: 423, + 0x93A5: 424, + 0x93A9: 425, + 0x93AB: 426, + 0x93B1: 427, + 0x93B3: 428, + 0x93B5: 429, + 0x93B7: 430, + 0x93BC: 431, + 0x9461: 432, + 0x9462: 433, + 0x9463: 434, + 0x9465: 435, + 0x9468: 436, + 0x9469: 437, + 0x946A: 438, + 0x946B: 439, + 0x946C: 440, + 0x9470: 441, + 0x9471: 442, + 0x9473: 443, + 0x9475: 444, + 0x9476: 445, + 0x9477: 446, + 0x9478: 447, + 0x9479: 448, + 0x947D: 449, + 0x9481: 450, + 0x9482: 451, + 0x9485: 452, + 0x9489: 453, + 0x9491: 454, + 0x9493: 455, + 0x9495: 456, + 0x9496: 457, + 0x9497: 458, + 0x94A1: 459, + 0x94E1: 460, + 0x94E2: 461, + 0x94E3: 462, + 0x94E5: 463, + 0x94E8: 464, + 0x94E9: 465, + 0x94EB: 466, + 0x94EC: 467, + 0x94F1: 468, + 0x94F3: 469, + 0x94F5: 470, + 0x94F7: 471, + 0x94F9: 472, + 0x94FC: 473, + 0x9541: 474, + 0x9542: 475, + 0x9545: 476, + 0x9549: 477, + 0x9551: 478, + 0x9553: 479, + 0x9555: 480, + 0x9556: 481, + 0x9557: 482, + 0x9561: 483, + 0x9565: 484, + 0x9569: 485, + 0x9576: 486, + 0x9577: 487, + 0x9581: 488, + 0x9585: 489, + 0x95A1: 490, + 0x95A2: 491, + 0x95A5: 492, + 0x95A8: 493, + 0x95A9: 494, + 0x95AB: 495, + 0x95AD: 496, + 0x95B1: 497, + 0x95B3: 498, + 0x95B5: 499, + 0x95B7: 500, + 0x95B9: 501, + 0x95BB: 502, + 0x95C1: 503, + 0x95C5: 504, + 0x95C9: 505, + 0x95E1: 506, + 0x95F6: 507, + 0x9641: 508, + 0x9645: 509, + 0x9649: 510, + 0x9651: 511, + 0x9653: 512, + 0x9655: 513, + 0x9661: 514, + 0x9681: 515, + 0x9682: 516, + 0x9685: 517, + 0x9689: 518, + 0x9691: 519, + 0x9693: 520, + 0x9695: 521, + 0x9697: 522, + 0x96A1: 523, + 0x96B6: 524, + 0x96C1: 525, + 0x96D7: 526, + 0x96E1: 527, + 0x96E5: 528, + 0x96E9: 529, + 0x96F3: 530, + 0x96F5: 531, + 0x96F7: 532, + 0x9741: 533, + 0x9745: 534, + 0x9749: 535, + 0x9751: 536, + 0x9757: 537, + 0x9761: 538, + 0x9762: 539, + 0x9765: 540, + 0x9768: 541, + 0x9769: 542, + 0x976B: 543, + 0x9771: 544, + 0x9773: 545, + 0x9775: 546, + 0x9777: 547, + 0x9781: 548, + 0x97A1: 549, + 0x97A2: 550, + 0x97A5: 551, + 0x97A8: 552, + 0x97A9: 553, + 0x97B1: 554, + 0x97B3: 555, + 0x97B5: 556, + 0x97B6: 557, + 0x97B7: 558, + 0x97B8: 559, + 0x9861: 560, + 0x9862: 561, + 0x9865: 562, + 0x9869: 563, + 0x9871: 564, + 0x9873: 565, + 0x9875: 566, + 0x9876: 567, + 0x9877: 568, + 0x987D: 569, + 0x9881: 570, + 0x9882: 571, + 0x9885: 572, + 0x9889: 573, + 0x9891: 574, + 0x9893: 575, + 0x9895: 576, + 0x9896: 577, + 0x9897: 578, + 0x98E1: 579, + 0x98E2: 580, + 0x98E5: 581, + 0x98E9: 582, + 0x98EB: 583, + 0x98EC: 584, + 0x98F1: 585, + 0x98F3: 586, + 0x98F5: 587, + 0x98F6: 588, + 0x98F7: 589, + 0x98FD: 590, + 0x9941: 591, + 0x9942: 592, + 0x9945: 593, + 0x9949: 594, + 0x9951: 595, + 0x9953: 596, + 0x9955: 597, + 0x9956: 598, + 0x9957: 599, + 0x9961: 600, + 0x9976: 601, + 0x99A1: 602, + 0x99A2: 603, + 0x99A5: 604, + 0x99A9: 605, + 0x99B7: 606, + 0x99C1: 607, + 0x99C9: 608, + 0x99E1: 609, + 0x9A41: 610, + 0x9A45: 611, + 0x9A81: 612, + 0x9A82: 613, + 0x9A85: 614, + 0x9A89: 615, + 0x9A90: 616, + 0x9A91: 617, + 0x9A97: 618, + 0x9AC1: 619, + 0x9AE1: 620, + 0x9AE5: 621, + 0x9AE9: 622, + 0x9AF1: 623, + 0x9AF3: 624, + 0x9AF7: 625, + 0x9B61: 626, + 0x9B62: 627, + 0x9B65: 628, + 0x9B68: 629, + 0x9B69: 630, + 0x9B71: 631, + 0x9B73: 632, + 0x9B75: 633, + 0x9B81: 634, + 0x9B85: 635, + 0x9B89: 636, + 0x9B91: 637, + 0x9B93: 638, + 0x9BA1: 639, + 0x9BA5: 640, + 0x9BA9: 641, + 0x9BB1: 642, + 0x9BB3: 643, + 0x9BB5: 644, + 0x9BB7: 645, + 0x9C61: 646, + 0x9C62: 647, + 0x9C65: 648, + 0x9C69: 649, + 0x9C71: 650, + 0x9C73: 651, + 0x9C75: 652, + 0x9C76: 653, + 0x9C77: 654, + 0x9C78: 655, + 0x9C7C: 656, + 0x9C7D: 657, + 0x9C81: 658, + 0x9C82: 659, + 0x9C85: 660, + 0x9C89: 661, + 0x9C91: 662, + 0x9C93: 663, + 0x9C95: 664, + 0x9C96: 665, + 0x9C97: 666, + 0x9CA1: 667, + 0x9CA2: 668, + 0x9CA5: 669, + 0x9CB5: 670, + 0x9CB7: 671, + 0x9CE1: 672, + 0x9CE2: 673, + 0x9CE5: 674, + 0x9CE9: 675, + 0x9CF1: 676, + 0x9CF3: 677, + 0x9CF5: 678, + 0x9CF6: 679, + 0x9CF7: 680, + 0x9CFD: 681, + 0x9D41: 682, + 0x9D42: 683, + 0x9D45: 684, + 0x9D49: 685, + 0x9D51: 686, + 0x9D53: 687, + 0x9D55: 688, + 0x9D57: 689, + 0x9D61: 690, + 0x9D62: 691, + 0x9D65: 692, + 0x9D69: 693, + 0x9D71: 694, + 0x9D73: 695, + 0x9D75: 696, + 0x9D76: 697, + 0x9D77: 698, + 0x9D81: 699, + 0x9D85: 700, + 0x9D93: 701, + 0x9D95: 702, + 0x9DA1: 703, + 0x9DA2: 704, + 0x9DA5: 705, + 0x9DA9: 706, + 0x9DB1: 707, + 0x9DB3: 708, + 0x9DB5: 709, + 0x9DB7: 710, + 0x9DC1: 711, + 0x9DC5: 712, + 0x9DD7: 713, + 0x9DF6: 714, + 0x9E41: 715, + 0x9E45: 716, + 0x9E49: 717, + 0x9E51: 718, + 0x9E53: 719, + 0x9E55: 720, + 0x9E57: 721, + 0x9E61: 722, + 0x9E65: 723, + 0x9E69: 724, + 0x9E73: 725, + 0x9E75: 726, + 0x9E77: 727, + 0x9E81: 728, + 0x9E82: 729, + 0x9E85: 730, + 0x9E89: 731, + 0x9E91: 732, + 0x9E93: 733, + 0x9E95: 734, + 0x9E97: 735, + 0x9EA1: 736, + 0x9EB6: 737, + 0x9EC1: 738, + 0x9EE1: 739, + 0x9EE2: 740, + 0x9EE5: 741, + 0x9EE9: 742, + 0x9EF1: 743, + 0x9EF5: 744, + 0x9EF7: 745, + 0x9F41: 746, + 0x9F42: 747, + 0x9F45: 748, + 0x9F49: 749, + 0x9F51: 750, + 0x9F53: 751, + 0x9F55: 752, + 0x9F57: 753, + 0x9F61: 754, + 0x9F62: 755, + 0x9F65: 756, + 0x9F69: 757, + 0x9F71: 758, + 0x9F73: 759, + 0x9F75: 760, + 0x9F77: 761, + 0x9F78: 762, + 0x9F7B: 763, + 0x9F7C: 764, + 0x9FA1: 765, + 0x9FA2: 766, + 0x9FA5: 767, + 0x9FA9: 768, + 0x9FB1: 769, + 0x9FB3: 770, + 0x9FB5: 771, + 0x9FB7: 772, + 0xA061: 773, + 0xA062: 774, + 0xA065: 775, + 0xA067: 776, + 0xA068: 777, + 0xA069: 778, + 0xA06A: 779, + 0xA06B: 780, + 0xA071: 781, + 0xA073: 782, + 0xA075: 783, + 0xA077: 784, + 0xA078: 785, + 0xA07B: 786, + 0xA07D: 787, + 0xA081: 788, + 0xA082: 789, + 0xA085: 790, + 0xA089: 791, + 0xA091: 792, + 0xA093: 793, + 0xA095: 794, + 0xA096: 795, + 0xA097: 796, + 0xA098: 797, + 0xA0A1: 798, + 0xA0A2: 799, + 0xA0A9: 800, + 0xA0B7: 801, + 0xA0E1: 802, + 0xA0E2: 803, + 0xA0E5: 804, + 0xA0E9: 805, + 0xA0EB: 806, + 0xA0F1: 807, + 0xA0F3: 808, + 0xA0F5: 809, + 0xA0F7: 810, + 0xA0F8: 811, + 0xA0FD: 812, + 0xA141: 813, + 0xA142: 814, + 0xA145: 815, + 0xA149: 816, + 0xA151: 817, + 0xA153: 818, + 0xA155: 819, + 0xA156: 820, + 0xA157: 821, + 0xA161: 822, + 0xA162: 823, + 0xA165: 824, + 0xA169: 825, + 0xA175: 826, + 0xA176: 827, + 0xA177: 828, + 0xA179: 829, + 0xA181: 830, + 0xA1A1: 831, + 0xA1A2: 832, + 0xA1A4: 833, + 0xA1A5: 834, + 0xA1A9: 835, + 0xA1AB: 836, + 0xA1B1: 837, + 0xA1B3: 838, + 0xA1B5: 839, + 0xA1B7: 840, + 0xA1C1: 841, + 0xA1C5: 842, + 0xA1D6: 843, + 0xA1D7: 844, + 0xA241: 845, + 0xA245: 846, + 0xA249: 847, + 0xA253: 848, + 0xA255: 849, + 0xA257: 850, + 0xA261: 851, + 0xA265: 852, + 0xA269: 853, + 0xA273: 854, + 0xA275: 855, + 0xA281: 856, + 0xA282: 857, + 0xA283: 858, + 0xA285: 859, + 0xA288: 860, + 0xA289: 861, + 0xA28A: 862, + 0xA28B: 863, + 0xA291: 864, + 0xA293: 865, + 0xA295: 866, + 0xA297: 867, + 0xA29B: 868, + 0xA29D: 869, + 0xA2A1: 870, + 0xA2A5: 871, + 0xA2A9: 872, + 0xA2B3: 873, + 0xA2B5: 874, + 0xA2C1: 875, + 0xA2E1: 876, + 0xA2E5: 877, + 0xA2E9: 878, + 0xA341: 879, + 0xA345: 880, + 0xA349: 881, + 0xA351: 882, + 0xA355: 883, + 0xA361: 884, + 0xA365: 885, + 0xA369: 886, + 0xA371: 887, + 0xA375: 888, + 0xA3A1: 889, + 0xA3A2: 890, + 0xA3A5: 891, + 0xA3A8: 892, + 0xA3A9: 893, + 0xA3AB: 894, + 0xA3B1: 895, + 0xA3B3: 896, + 0xA3B5: 897, + 0xA3B6: 898, + 0xA3B7: 899, + 0xA3B9: 900, + 0xA3BB: 901, + 0xA461: 902, + 0xA462: 903, + 0xA463: 904, + 0xA464: 905, + 0xA465: 906, + 0xA468: 907, + 0xA469: 908, + 0xA46A: 909, + 0xA46B: 910, + 0xA46C: 911, + 0xA471: 912, + 0xA473: 913, + 0xA475: 914, + 0xA477: 915, + 0xA47B: 916, + 0xA481: 917, + 0xA482: 918, + 0xA485: 919, + 0xA489: 920, + 0xA491: 921, + 0xA493: 922, + 0xA495: 923, + 0xA496: 924, + 0xA497: 925, + 0xA49B: 926, + 0xA4A1: 927, + 0xA4A2: 928, + 0xA4A5: 929, + 0xA4B3: 930, + 0xA4E1: 931, + 0xA4E2: 932, + 0xA4E5: 933, + 0xA4E8: 934, + 0xA4E9: 935, + 0xA4EB: 936, + 0xA4F1: 937, + 0xA4F3: 938, + 0xA4F5: 939, + 0xA4F7: 940, + 0xA4F8: 941, + 0xA541: 942, + 0xA542: 943, + 0xA545: 944, + 0xA548: 945, + 0xA549: 946, + 0xA551: 947, + 0xA553: 948, + 0xA555: 949, + 0xA556: 950, + 0xA557: 951, + 0xA561: 952, + 0xA562: 953, + 0xA565: 954, + 0xA569: 955, + 0xA573: 956, + 0xA575: 957, + 0xA576: 958, + 0xA577: 959, + 0xA57B: 960, + 0xA581: 961, + 0xA585: 962, + 0xA5A1: 963, + 0xA5A2: 964, + 0xA5A3: 965, + 0xA5A5: 966, + 0xA5A9: 967, + 0xA5B1: 968, + 0xA5B3: 969, + 0xA5B5: 970, + 0xA5B7: 971, + 0xA5C1: 972, + 0xA5C5: 973, + 0xA5D6: 974, + 0xA5E1: 975, + 0xA5F6: 976, + 0xA641: 977, + 0xA642: 978, + 0xA645: 979, + 0xA649: 980, + 0xA651: 981, + 0xA653: 982, + 0xA661: 983, + 0xA665: 984, + 0xA681: 985, + 0xA682: 986, + 0xA685: 987, + 0xA688: 988, + 0xA689: 989, + 0xA68A: 990, + 0xA68B: 991, + 0xA691: 992, + 0xA693: 993, + 0xA695: 994, + 0xA697: 995, + 0xA69B: 996, + 0xA69C: 997, + 0xA6A1: 998, + 0xA6A9: 999, + 0xA6B6: 1000, + 0xA6C1: 1001, + 0xA6E1: 1002, + 0xA6E2: 1003, + 0xA6E5: 1004, + 0xA6E9: 1005, + 0xA6F7: 1006, + 0xA741: 1007, + 0xA745: 1008, + 0xA749: 1009, + 0xA751: 1010, + 0xA755: 1011, + 0xA757: 1012, + 0xA761: 1013, + 0xA762: 1014, + 0xA765: 1015, + 0xA769: 1016, + 0xA771: 1017, + 0xA773: 1018, + 0xA775: 1019, + 0xA7A1: 1020, + 0xA7A2: 1021, + 0xA7A5: 1022, + 0xA7A9: 1023, + 0xA7AB: 1024, + 0xA7B1: 1025, + 0xA7B3: 1026, + 0xA7B5: 1027, + 0xA7B7: 1028, + 0xA7B8: 1029, + 0xA7B9: 1030, + 0xA861: 1031, + 0xA862: 1032, + 0xA865: 1033, + 0xA869: 1034, + 0xA86B: 1035, + 0xA871: 1036, + 0xA873: 1037, + 0xA875: 1038, + 0xA876: 1039, + 0xA877: 1040, + 0xA87D: 1041, + 0xA881: 1042, + 0xA882: 1043, + 0xA885: 1044, + 0xA889: 1045, + 0xA891: 1046, + 0xA893: 1047, + 0xA895: 1048, + 0xA896: 1049, + 0xA897: 1050, + 0xA8A1: 1051, + 0xA8A2: 1052, + 0xA8B1: 1053, + 0xA8E1: 1054, + 0xA8E2: 1055, + 0xA8E5: 1056, + 0xA8E8: 1057, + 0xA8E9: 1058, + 0xA8F1: 1059, + 0xA8F5: 1060, + 0xA8F6: 1061, + 0xA8F7: 1062, + 0xA941: 1063, + 0xA957: 1064, + 0xA961: 1065, + 0xA962: 1066, + 0xA971: 1067, + 0xA973: 1068, + 0xA975: 1069, + 0xA976: 1070, + 0xA977: 1071, + 0xA9A1: 1072, + 0xA9A2: 1073, + 0xA9A5: 1074, + 0xA9A9: 1075, + 0xA9B1: 1076, + 0xA9B3: 1077, + 0xA9B7: 1078, + 0xAA41: 1079, + 0xAA61: 1080, + 0xAA77: 1081, + 0xAA81: 1082, + 0xAA82: 1083, + 0xAA85: 1084, + 0xAA89: 1085, + 0xAA91: 1086, + 0xAA95: 1087, + 0xAA97: 1088, + 0xAB41: 1089, + 0xAB57: 1090, + 0xAB61: 1091, + 0xAB65: 1092, + 0xAB69: 1093, + 0xAB71: 1094, + 0xAB73: 1095, + 0xABA1: 1096, + 0xABA2: 1097, + 0xABA5: 1098, + 0xABA9: 1099, + 0xABB1: 1100, + 0xABB3: 1101, + 0xABB5: 1102, + 0xABB7: 1103, + 0xAC61: 1104, + 0xAC62: 1105, + 0xAC64: 1106, + 0xAC65: 1107, + 0xAC68: 1108, + 0xAC69: 1109, + 0xAC6A: 1110, + 0xAC6B: 1111, + 0xAC71: 1112, + 0xAC73: 1113, + 0xAC75: 1114, + 0xAC76: 1115, + 0xAC77: 1116, + 0xAC7B: 1117, + 0xAC81: 1118, + 0xAC82: 1119, + 0xAC85: 1120, + 0xAC89: 1121, + 0xAC91: 1122, + 0xAC93: 1123, + 0xAC95: 1124, + 0xAC96: 1125, + 0xAC97: 1126, + 0xACA1: 1127, + 0xACA2: 1128, + 0xACA5: 1129, + 0xACA9: 1130, + 0xACB1: 1131, + 0xACB3: 1132, + 0xACB5: 1133, + 0xACB7: 1134, + 0xACC1: 1135, + 0xACC5: 1136, + 0xACC9: 1137, + 0xACD1: 1138, + 0xACD7: 1139, + 0xACE1: 1140, + 0xACE2: 1141, + 0xACE3: 1142, + 0xACE4: 1143, + 0xACE5: 1144, + 0xACE8: 1145, + 0xACE9: 1146, + 0xACEB: 1147, + 0xACEC: 1148, + 0xACF1: 1149, + 0xACF3: 1150, + 0xACF5: 1151, + 0xACF6: 1152, + 0xACF7: 1153, + 0xACFC: 1154, + 0xAD41: 1155, + 0xAD42: 1156, + 0xAD45: 1157, + 0xAD49: 1158, + 0xAD51: 1159, + 0xAD53: 1160, + 0xAD55: 1161, + 0xAD56: 1162, + 0xAD57: 1163, + 0xAD61: 1164, + 0xAD62: 1165, + 0xAD65: 1166, + 0xAD69: 1167, + 0xAD71: 1168, + 0xAD73: 1169, + 0xAD75: 1170, + 0xAD76: 1171, + 0xAD77: 1172, + 0xAD81: 1173, + 0xAD85: 1174, + 0xAD89: 1175, + 0xAD97: 1176, + 0xADA1: 1177, + 0xADA2: 1178, + 0xADA3: 1179, + 0xADA5: 1180, + 0xADA9: 1181, + 0xADAB: 1182, + 0xADB1: 1183, + 0xADB3: 1184, + 0xADB5: 1185, + 0xADB7: 1186, + 0xADBB: 1187, + 0xADC1: 1188, + 0xADC2: 1189, + 0xADC5: 1190, + 0xADC9: 1191, + 0xADD7: 1192, + 0xADE1: 1193, + 0xADE5: 1194, + 0xADE9: 1195, + 0xADF1: 1196, + 0xADF5: 1197, + 0xADF6: 1198, + 0xAE41: 1199, + 0xAE45: 1200, + 0xAE49: 1201, + 0xAE51: 1202, + 0xAE53: 1203, + 0xAE55: 1204, + 0xAE61: 1205, + 0xAE62: 1206, + 0xAE65: 1207, + 0xAE69: 1208, + 0xAE71: 1209, + 0xAE73: 1210, + 0xAE75: 1211, + 0xAE77: 1212, + 0xAE81: 1213, + 0xAE82: 1214, + 0xAE85: 1215, + 0xAE88: 1216, + 0xAE89: 1217, + 0xAE91: 1218, + 0xAE93: 1219, + 0xAE95: 1220, + 0xAE97: 1221, + 0xAE99: 1222, + 0xAE9B: 1223, + 0xAE9C: 1224, + 0xAEA1: 1225, + 0xAEB6: 1226, + 0xAEC1: 1227, + 0xAEC2: 1228, + 0xAEC5: 1229, + 0xAEC9: 1230, + 0xAED1: 1231, + 0xAED7: 1232, + 0xAEE1: 1233, + 0xAEE2: 1234, + 0xAEE5: 1235, + 0xAEE9: 1236, + 0xAEF1: 1237, + 0xAEF3: 1238, + 0xAEF5: 1239, + 0xAEF7: 1240, + 0xAF41: 1241, + 0xAF42: 1242, + 0xAF49: 1243, + 0xAF51: 1244, + 0xAF55: 1245, + 0xAF57: 1246, + 0xAF61: 1247, + 0xAF62: 1248, + 0xAF65: 1249, + 0xAF69: 1250, + 0xAF6A: 1251, + 0xAF71: 1252, + 0xAF73: 1253, + 0xAF75: 1254, + 0xAF77: 1255, + 0xAFA1: 1256, + 0xAFA2: 1257, + 0xAFA5: 1258, + 0xAFA8: 1259, + 0xAFA9: 1260, + 0xAFB0: 1261, + 0xAFB1: 1262, + 0xAFB3: 1263, + 0xAFB5: 1264, + 0xAFB7: 1265, + 0xAFBC: 1266, + 0xB061: 1267, + 0xB062: 1268, + 0xB064: 1269, + 0xB065: 1270, + 0xB069: 1271, + 0xB071: 1272, + 0xB073: 1273, + 0xB076: 1274, + 0xB077: 1275, + 0xB07D: 1276, + 0xB081: 1277, + 0xB082: 1278, + 0xB085: 1279, + 0xB089: 1280, + 0xB091: 1281, + 0xB093: 1282, + 0xB096: 1283, + 0xB097: 1284, + 0xB0B7: 1285, + 0xB0E1: 1286, + 0xB0E2: 1287, + 0xB0E5: 1288, + 0xB0E9: 1289, + 0xB0EB: 1290, + 0xB0F1: 1291, + 0xB0F3: 1292, + 0xB0F6: 1293, + 0xB0F7: 1294, + 0xB141: 1295, + 0xB145: 1296, + 0xB149: 1297, + 0xB185: 1298, + 0xB1A1: 1299, + 0xB1A2: 1300, + 0xB1A5: 1301, + 0xB1A8: 1302, + 0xB1A9: 1303, + 0xB1AB: 1304, + 0xB1B1: 1305, + 0xB1B3: 1306, + 0xB1B7: 1307, + 0xB1C1: 1308, + 0xB1C2: 1309, + 0xB1C5: 1310, + 0xB1D6: 1311, + 0xB1E1: 1312, + 0xB1F6: 1313, + 0xB241: 1314, + 0xB245: 1315, + 0xB249: 1316, + 0xB251: 1317, + 0xB253: 1318, + 0xB261: 1319, + 0xB281: 1320, + 0xB282: 1321, + 0xB285: 1322, + 0xB289: 1323, + 0xB291: 1324, + 0xB293: 1325, + 0xB297: 1326, + 0xB2A1: 1327, + 0xB2B6: 1328, + 0xB2C1: 1329, + 0xB2E1: 1330, + 0xB2E5: 1331, + 0xB357: 1332, + 0xB361: 1333, + 0xB362: 1334, + 0xB365: 1335, + 0xB369: 1336, + 0xB36B: 1337, + 0xB370: 1338, + 0xB371: 1339, + 0xB373: 1340, + 0xB381: 1341, + 0xB385: 1342, + 0xB389: 1343, + 0xB391: 1344, + 0xB3A1: 1345, + 0xB3A2: 1346, + 0xB3A5: 1347, + 0xB3A9: 1348, + 0xB3B1: 1349, + 0xB3B3: 1350, + 0xB3B5: 1351, + 0xB3B7: 1352, + 0xB461: 1353, + 0xB462: 1354, + 0xB465: 1355, + 0xB466: 1356, + 0xB467: 1357, + 0xB469: 1358, + 0xB46A: 1359, + 0xB46B: 1360, + 0xB470: 1361, + 0xB471: 1362, + 0xB473: 1363, + 0xB475: 1364, + 0xB476: 1365, + 0xB477: 1366, + 0xB47B: 1367, + 0xB47C: 1368, + 0xB481: 1369, + 0xB482: 1370, + 0xB485: 1371, + 0xB489: 1372, + 0xB491: 1373, + 0xB493: 1374, + 0xB495: 1375, + 0xB496: 1376, + 0xB497: 1377, + 0xB4A1: 1378, + 0xB4A2: 1379, + 0xB4A5: 1380, + 0xB4A9: 1381, + 0xB4AC: 1382, + 0xB4B1: 1383, + 0xB4B3: 1384, + 0xB4B5: 1385, + 0xB4B7: 1386, + 0xB4BB: 1387, + 0xB4BD: 1388, + 0xB4C1: 1389, + 0xB4C5: 1390, + 0xB4C9: 1391, + 0xB4D3: 1392, + 0xB4E1: 1393, + 0xB4E2: 1394, + 0xB4E5: 1395, + 0xB4E6: 1396, + 0xB4E8: 1397, + 0xB4E9: 1398, + 0xB4EA: 1399, + 0xB4EB: 1400, + 0xB4F1: 1401, + 0xB4F3: 1402, + 0xB4F4: 1403, + 0xB4F5: 1404, + 0xB4F6: 1405, + 0xB4F7: 1406, + 0xB4F8: 1407, + 0xB4FA: 1408, + 0xB4FC: 1409, + 0xB541: 1410, + 0xB542: 1411, + 0xB545: 1412, + 0xB549: 1413, + 0xB551: 1414, + 0xB553: 1415, + 0xB555: 1416, + 0xB557: 1417, + 0xB561: 1418, + 0xB562: 1419, + 0xB563: 1420, + 0xB565: 1421, + 0xB569: 1422, + 0xB56B: 1423, + 0xB56C: 1424, + 0xB571: 1425, + 0xB573: 1426, + 0xB574: 1427, + 0xB575: 1428, + 0xB576: 1429, + 0xB577: 1430, + 0xB57B: 1431, + 0xB57C: 1432, + 0xB57D: 1433, + 0xB581: 1434, + 0xB585: 1435, + 0xB589: 1436, + 0xB591: 1437, + 0xB593: 1438, + 0xB595: 1439, + 0xB596: 1440, + 0xB5A1: 1441, + 0xB5A2: 1442, + 0xB5A5: 1443, + 0xB5A9: 1444, + 0xB5AA: 1445, + 0xB5AB: 1446, + 0xB5AD: 1447, + 0xB5B0: 1448, + 0xB5B1: 1449, + 0xB5B3: 1450, + 0xB5B5: 1451, + 0xB5B7: 1452, + 0xB5B9: 1453, + 0xB5C1: 1454, + 0xB5C2: 1455, + 0xB5C5: 1456, + 0xB5C9: 1457, + 0xB5D1: 1458, + 0xB5D3: 1459, + 0xB5D5: 1460, + 0xB5D6: 1461, + 0xB5D7: 1462, + 0xB5E1: 1463, + 0xB5E2: 1464, + 0xB5E5: 1465, + 0xB5F1: 1466, + 0xB5F5: 1467, + 0xB5F7: 1468, + 0xB641: 1469, + 0xB642: 1470, + 0xB645: 1471, + 0xB649: 1472, + 0xB651: 1473, + 0xB653: 1474, + 0xB655: 1475, + 0xB657: 1476, + 0xB661: 1477, + 0xB662: 1478, + 0xB665: 1479, + 0xB669: 1480, + 0xB671: 1481, + 0xB673: 1482, + 0xB675: 1483, + 0xB677: 1484, + 0xB681: 1485, + 0xB682: 1486, + 0xB685: 1487, + 0xB689: 1488, + 0xB68A: 1489, + 0xB68B: 1490, + 0xB691: 1491, + 0xB693: 1492, + 0xB695: 1493, + 0xB697: 1494, + 0xB6A1: 1495, + 0xB6A2: 1496, + 0xB6A5: 1497, + 0xB6A9: 1498, + 0xB6B1: 1499, + 0xB6B3: 1500, + 0xB6B6: 1501, + 0xB6B7: 1502, + 0xB6C1: 1503, + 0xB6C2: 1504, + 0xB6C5: 1505, + 0xB6C9: 1506, + 0xB6D1: 1507, + 0xB6D3: 1508, + 0xB6D7: 1509, + 0xB6E1: 1510, + 0xB6E2: 1511, + 0xB6E5: 1512, + 0xB6E9: 1513, + 0xB6F1: 1514, + 0xB6F3: 1515, + 0xB6F5: 1516, + 0xB6F7: 1517, + 0xB741: 1518, + 0xB742: 1519, + 0xB745: 1520, + 0xB749: 1521, + 0xB751: 1522, + 0xB753: 1523, + 0xB755: 1524, + 0xB757: 1525, + 0xB759: 1526, + 0xB761: 1527, + 0xB762: 1528, + 0xB765: 1529, + 0xB769: 1530, + 0xB76F: 1531, + 0xB771: 1532, + 0xB773: 1533, + 0xB775: 1534, + 0xB777: 1535, + 0xB778: 1536, + 0xB779: 1537, + 0xB77A: 1538, + 0xB77B: 1539, + 0xB77C: 1540, + 0xB77D: 1541, + 0xB781: 1542, + 0xB785: 1543, + 0xB789: 1544, + 0xB791: 1545, + 0xB795: 1546, + 0xB7A1: 1547, + 0xB7A2: 1548, + 0xB7A5: 1549, + 0xB7A9: 1550, + 0xB7AA: 1551, + 0xB7AB: 1552, + 0xB7B0: 1553, + 0xB7B1: 1554, + 0xB7B3: 1555, + 0xB7B5: 1556, + 0xB7B6: 1557, + 0xB7B7: 1558, + 0xB7B8: 1559, + 0xB7BC: 1560, + 0xB861: 1561, + 0xB862: 1562, + 0xB865: 1563, + 0xB867: 1564, + 0xB868: 1565, + 0xB869: 1566, + 0xB86B: 1567, + 0xB871: 1568, + 0xB873: 1569, + 0xB875: 1570, + 0xB876: 1571, + 0xB877: 1572, + 0xB878: 1573, + 0xB881: 1574, + 0xB882: 1575, + 0xB885: 1576, + 0xB889: 1577, + 0xB891: 1578, + 0xB893: 1579, + 0xB895: 1580, + 0xB896: 1581, + 0xB897: 1582, + 0xB8A1: 1583, + 0xB8A2: 1584, + 0xB8A5: 1585, + 0xB8A7: 1586, + 0xB8A9: 1587, + 0xB8B1: 1588, + 0xB8B7: 1589, + 0xB8C1: 1590, + 0xB8C5: 1591, + 0xB8C9: 1592, + 0xB8E1: 1593, + 0xB8E2: 1594, + 0xB8E5: 1595, + 0xB8E9: 1596, + 0xB8EB: 1597, + 0xB8F1: 1598, + 0xB8F3: 1599, + 0xB8F5: 1600, + 0xB8F7: 1601, + 0xB8F8: 1602, + 0xB941: 1603, + 0xB942: 1604, + 0xB945: 1605, + 0xB949: 1606, + 0xB951: 1607, + 0xB953: 1608, + 0xB955: 1609, + 0xB957: 1610, + 0xB961: 1611, + 0xB965: 1612, + 0xB969: 1613, + 0xB971: 1614, + 0xB973: 1615, + 0xB976: 1616, + 0xB977: 1617, + 0xB981: 1618, + 0xB9A1: 1619, + 0xB9A2: 1620, + 0xB9A5: 1621, + 0xB9A9: 1622, + 0xB9AB: 1623, + 0xB9B1: 1624, + 0xB9B3: 1625, + 0xB9B5: 1626, + 0xB9B7: 1627, + 0xB9B8: 1628, + 0xB9B9: 1629, + 0xB9BD: 1630, + 0xB9C1: 1631, + 0xB9C2: 1632, + 0xB9C9: 1633, + 0xB9D3: 1634, + 0xB9D5: 1635, + 0xB9D7: 1636, + 0xB9E1: 1637, + 0xB9F6: 1638, + 0xB9F7: 1639, + 0xBA41: 1640, + 0xBA45: 1641, + 0xBA49: 1642, + 0xBA51: 1643, + 0xBA53: 1644, + 0xBA55: 1645, + 0xBA57: 1646, + 0xBA61: 1647, + 0xBA62: 1648, + 0xBA65: 1649, + 0xBA77: 1650, + 0xBA81: 1651, + 0xBA82: 1652, + 0xBA85: 1653, + 0xBA89: 1654, + 0xBA8A: 1655, + 0xBA8B: 1656, + 0xBA91: 1657, + 0xBA93: 1658, + 0xBA95: 1659, + 0xBA97: 1660, + 0xBAA1: 1661, + 0xBAB6: 1662, + 0xBAC1: 1663, + 0xBAE1: 1664, + 0xBAE2: 1665, + 0xBAE5: 1666, + 0xBAE9: 1667, + 0xBAF1: 1668, + 0xBAF3: 1669, + 0xBAF5: 1670, + 0xBB41: 1671, + 0xBB45: 1672, + 0xBB49: 1673, + 0xBB51: 1674, + 0xBB61: 1675, + 0xBB62: 1676, + 0xBB65: 1677, + 0xBB69: 1678, + 0xBB71: 1679, + 0xBB73: 1680, + 0xBB75: 1681, + 0xBB77: 1682, + 0xBBA1: 1683, + 0xBBA2: 1684, + 0xBBA5: 1685, + 0xBBA8: 1686, + 0xBBA9: 1687, + 0xBBAB: 1688, + 0xBBB1: 1689, + 0xBBB3: 1690, + 0xBBB5: 1691, + 0xBBB7: 1692, + 0xBBB8: 1693, + 0xBBBB: 1694, + 0xBBBC: 1695, + 0xBC61: 1696, + 0xBC62: 1697, + 0xBC65: 1698, + 0xBC67: 1699, + 0xBC69: 1700, + 0xBC6C: 1701, + 0xBC71: 1702, + 0xBC73: 1703, + 0xBC75: 1704, + 0xBC76: 1705, + 0xBC77: 1706, + 0xBC81: 1707, + 0xBC82: 1708, + 0xBC85: 1709, + 0xBC89: 1710, + 0xBC91: 1711, + 0xBC93: 1712, + 0xBC95: 1713, + 0xBC96: 1714, + 0xBC97: 1715, + 0xBCA1: 1716, + 0xBCA5: 1717, + 0xBCB7: 1718, + 0xBCE1: 1719, + 0xBCE2: 1720, + 0xBCE5: 1721, + 0xBCE9: 1722, + 0xBCF1: 1723, + 0xBCF3: 1724, + 0xBCF5: 1725, + 0xBCF6: 1726, + 0xBCF7: 1727, + 0xBD41: 1728, + 0xBD57: 1729, + 0xBD61: 1730, + 0xBD76: 1731, + 0xBDA1: 1732, + 0xBDA2: 1733, + 0xBDA5: 1734, + 0xBDA9: 1735, + 0xBDB1: 1736, + 0xBDB3: 1737, + 0xBDB5: 1738, + 0xBDB7: 1739, + 0xBDB9: 1740, + 0xBDC1: 1741, + 0xBDC2: 1742, + 0xBDC9: 1743, + 0xBDD6: 1744, + 0xBDE1: 1745, + 0xBDF6: 1746, + 0xBE41: 1747, + 0xBE45: 1748, + 0xBE49: 1749, + 0xBE51: 1750, + 0xBE53: 1751, + 0xBE77: 1752, + 0xBE81: 1753, + 0xBE82: 1754, + 0xBE85: 1755, + 0xBE89: 1756, + 0xBE91: 1757, + 0xBE93: 1758, + 0xBE97: 1759, + 0xBEA1: 1760, + 0xBEB6: 1761, + 0xBEB7: 1762, + 0xBEE1: 1763, + 0xBF41: 1764, + 0xBF61: 1765, + 0xBF71: 1766, + 0xBF75: 1767, + 0xBF77: 1768, + 0xBFA1: 1769, + 0xBFA2: 1770, + 0xBFA5: 1771, + 0xBFA9: 1772, + 0xBFB1: 1773, + 0xBFB3: 1774, + 0xBFB7: 1775, + 0xBFB8: 1776, + 0xBFBD: 1777, + 0xC061: 1778, + 0xC062: 1779, + 0xC065: 1780, + 0xC067: 1781, + 0xC069: 1782, + 0xC071: 1783, + 0xC073: 1784, + 0xC075: 1785, + 0xC076: 1786, + 0xC077: 1787, + 0xC078: 1788, + 0xC081: 1789, + 0xC082: 1790, + 0xC085: 1791, + 0xC089: 1792, + 0xC091: 1793, + 0xC093: 1794, + 0xC095: 1795, + 0xC096: 1796, + 0xC097: 1797, + 0xC0A1: 1798, + 0xC0A5: 1799, + 0xC0A7: 1800, + 0xC0A9: 1801, + 0xC0B1: 1802, + 0xC0B7: 1803, + 0xC0E1: 1804, + 0xC0E2: 1805, + 0xC0E5: 1806, + 0xC0E9: 1807, + 0xC0F1: 1808, + 0xC0F3: 1809, + 0xC0F5: 1810, + 0xC0F6: 1811, + 0xC0F7: 1812, + 0xC141: 1813, + 0xC142: 1814, + 0xC145: 1815, + 0xC149: 1816, + 0xC151: 1817, + 0xC153: 1818, + 0xC155: 1819, + 0xC157: 1820, + 0xC161: 1821, + 0xC165: 1822, + 0xC176: 1823, + 0xC181: 1824, + 0xC185: 1825, + 0xC197: 1826, + 0xC1A1: 1827, + 0xC1A2: 1828, + 0xC1A5: 1829, + 0xC1A9: 1830, + 0xC1B1: 1831, + 0xC1B3: 1832, + 0xC1B5: 1833, + 0xC1B7: 1834, + 0xC1C1: 1835, + 0xC1C5: 1836, + 0xC1C9: 1837, + 0xC1D7: 1838, + 0xC241: 1839, + 0xC245: 1840, + 0xC249: 1841, + 0xC251: 1842, + 0xC253: 1843, + 0xC255: 1844, + 0xC257: 1845, + 0xC261: 1846, + 0xC271: 1847, + 0xC281: 1848, + 0xC282: 1849, + 0xC285: 1850, + 0xC289: 1851, + 0xC291: 1852, + 0xC293: 1853, + 0xC295: 1854, + 0xC297: 1855, + 0xC2A1: 1856, + 0xC2B6: 1857, + 0xC2C1: 1858, + 0xC2C5: 1859, + 0xC2E1: 1860, + 0xC2E5: 1861, + 0xC2E9: 1862, + 0xC2F1: 1863, + 0xC2F3: 1864, + 0xC2F5: 1865, + 0xC2F7: 1866, + 0xC341: 1867, + 0xC345: 1868, + 0xC349: 1869, + 0xC351: 1870, + 0xC357: 1871, + 0xC361: 1872, + 0xC362: 1873, + 0xC365: 1874, + 0xC369: 1875, + 0xC371: 1876, + 0xC373: 1877, + 0xC375: 1878, + 0xC377: 1879, + 0xC3A1: 1880, + 0xC3A2: 1881, + 0xC3A5: 1882, + 0xC3A8: 1883, + 0xC3A9: 1884, + 0xC3AA: 1885, + 0xC3B1: 1886, + 0xC3B3: 1887, + 0xC3B5: 1888, + 0xC3B7: 1889, + 0xC461: 1890, + 0xC462: 1891, + 0xC465: 1892, + 0xC469: 1893, + 0xC471: 1894, + 0xC473: 1895, + 0xC475: 1896, + 0xC477: 1897, + 0xC481: 1898, + 0xC482: 1899, + 0xC485: 1900, + 0xC489: 1901, + 0xC491: 1902, + 0xC493: 1903, + 0xC495: 1904, + 0xC496: 1905, + 0xC497: 1906, + 0xC4A1: 1907, + 0xC4A2: 1908, + 0xC4B7: 1909, + 0xC4E1: 1910, + 0xC4E2: 1911, + 0xC4E5: 1912, + 0xC4E8: 1913, + 0xC4E9: 1914, + 0xC4F1: 1915, + 0xC4F3: 1916, + 0xC4F5: 1917, + 0xC4F6: 1918, + 0xC4F7: 1919, + 0xC541: 1920, + 0xC542: 1921, + 0xC545: 1922, + 0xC549: 1923, + 0xC551: 1924, + 0xC553: 1925, + 0xC555: 1926, + 0xC557: 1927, + 0xC561: 1928, + 0xC565: 1929, + 0xC569: 1930, + 0xC571: 1931, + 0xC573: 1932, + 0xC575: 1933, + 0xC576: 1934, + 0xC577: 1935, + 0xC581: 1936, + 0xC5A1: 1937, + 0xC5A2: 1938, + 0xC5A5: 1939, + 0xC5A9: 1940, + 0xC5B1: 1941, + 0xC5B3: 1942, + 0xC5B5: 1943, + 0xC5B7: 1944, + 0xC5C1: 1945, + 0xC5C2: 1946, + 0xC5C5: 1947, + 0xC5C9: 1948, + 0xC5D1: 1949, + 0xC5D7: 1950, + 0xC5E1: 1951, + 0xC5F7: 1952, + 0xC641: 1953, + 0xC649: 1954, + 0xC661: 1955, + 0xC681: 1956, + 0xC682: 1957, + 0xC685: 1958, + 0xC689: 1959, + 0xC691: 1960, + 0xC693: 1961, + 0xC695: 1962, + 0xC697: 1963, + 0xC6A1: 1964, + 0xC6A5: 1965, + 0xC6A9: 1966, + 0xC6B7: 1967, + 0xC6C1: 1968, + 0xC6D7: 1969, + 0xC6E1: 1970, + 0xC6E2: 1971, + 0xC6E5: 1972, + 0xC6E9: 1973, + 0xC6F1: 1974, + 0xC6F3: 1975, + 0xC6F5: 1976, + 0xC6F7: 1977, + 0xC741: 1978, + 0xC745: 1979, + 0xC749: 1980, + 0xC751: 1981, + 0xC761: 1982, + 0xC762: 1983, + 0xC765: 1984, + 0xC769: 1985, + 0xC771: 1986, + 0xC773: 1987, + 0xC777: 1988, + 0xC7A1: 1989, + 0xC7A2: 1990, + 0xC7A5: 1991, + 0xC7A9: 1992, + 0xC7B1: 1993, + 0xC7B3: 1994, + 0xC7B5: 1995, + 0xC7B7: 1996, + 0xC861: 1997, + 0xC862: 1998, + 0xC865: 1999, + 0xC869: 2000, + 0xC86A: 2001, + 0xC871: 2002, + 0xC873: 2003, + 0xC875: 2004, + 0xC876: 2005, + 0xC877: 2006, + 0xC881: 2007, + 0xC882: 2008, + 0xC885: 2009, + 0xC889: 2010, + 0xC891: 2011, + 0xC893: 2012, + 0xC895: 2013, + 0xC896: 2014, + 0xC897: 2015, + 0xC8A1: 2016, + 0xC8B7: 2017, + 0xC8E1: 2018, + 0xC8E2: 2019, + 0xC8E5: 2020, + 0xC8E9: 2021, + 0xC8EB: 2022, + 0xC8F1: 2023, + 0xC8F3: 2024, + 0xC8F5: 2025, + 0xC8F6: 2026, + 0xC8F7: 2027, + 0xC941: 2028, + 0xC942: 2029, + 0xC945: 2030, + 0xC949: 2031, + 0xC951: 2032, + 0xC953: 2033, + 0xC955: 2034, + 0xC957: 2035, + 0xC961: 2036, + 0xC965: 2037, + 0xC976: 2038, + 0xC981: 2039, + 0xC985: 2040, + 0xC9A1: 2041, + 0xC9A2: 2042, + 0xC9A5: 2043, + 0xC9A9: 2044, + 0xC9B1: 2045, + 0xC9B3: 2046, + 0xC9B5: 2047, + 0xC9B7: 2048, + 0xC9BC: 2049, + 0xC9C1: 2050, + 0xC9C5: 2051, + 0xC9E1: 2052, + 0xCA41: 2053, + 0xCA45: 2054, + 0xCA55: 2055, + 0xCA57: 2056, + 0xCA61: 2057, + 0xCA81: 2058, + 0xCA82: 2059, + 0xCA85: 2060, + 0xCA89: 2061, + 0xCA91: 2062, + 0xCA93: 2063, + 0xCA95: 2064, + 0xCA97: 2065, + 0xCAA1: 2066, + 0xCAB6: 2067, + 0xCAC1: 2068, + 0xCAE1: 2069, + 0xCAE2: 2070, + 0xCAE5: 2071, + 0xCAE9: 2072, + 0xCAF1: 2073, + 0xCAF3: 2074, + 0xCAF7: 2075, + 0xCB41: 2076, + 0xCB45: 2077, + 0xCB49: 2078, + 0xCB51: 2079, + 0xCB57: 2080, + 0xCB61: 2081, + 0xCB62: 2082, + 0xCB65: 2083, + 0xCB68: 2084, + 0xCB69: 2085, + 0xCB6B: 2086, + 0xCB71: 2087, + 0xCB73: 2088, + 0xCB75: 2089, + 0xCB81: 2090, + 0xCB85: 2091, + 0xCB89: 2092, + 0xCB91: 2093, + 0xCB93: 2094, + 0xCBA1: 2095, + 0xCBA2: 2096, + 0xCBA5: 2097, + 0xCBA9: 2098, + 0xCBB1: 2099, + 0xCBB3: 2100, + 0xCBB5: 2101, + 0xCBB7: 2102, + 0xCC61: 2103, + 0xCC62: 2104, + 0xCC63: 2105, + 0xCC65: 2106, + 0xCC69: 2107, + 0xCC6B: 2108, + 0xCC71: 2109, + 0xCC73: 2110, + 0xCC75: 2111, + 0xCC76: 2112, + 0xCC77: 2113, + 0xCC7B: 2114, + 0xCC81: 2115, + 0xCC82: 2116, + 0xCC85: 2117, + 0xCC89: 2118, + 0xCC91: 2119, + 0xCC93: 2120, + 0xCC95: 2121, + 0xCC96: 2122, + 0xCC97: 2123, + 0xCCA1: 2124, + 0xCCA2: 2125, + 0xCCE1: 2126, + 0xCCE2: 2127, + 0xCCE5: 2128, + 0xCCE9: 2129, + 0xCCF1: 2130, + 0xCCF3: 2131, + 0xCCF5: 2132, + 0xCCF6: 2133, + 0xCCF7: 2134, + 0xCD41: 2135, + 0xCD42: 2136, + 0xCD45: 2137, + 0xCD49: 2138, + 0xCD51: 2139, + 0xCD53: 2140, + 0xCD55: 2141, + 0xCD57: 2142, + 0xCD61: 2143, + 0xCD65: 2144, + 0xCD69: 2145, + 0xCD71: 2146, + 0xCD73: 2147, + 0xCD76: 2148, + 0xCD77: 2149, + 0xCD81: 2150, + 0xCD89: 2151, + 0xCD93: 2152, + 0xCD95: 2153, + 0xCDA1: 2154, + 0xCDA2: 2155, + 0xCDA5: 2156, + 0xCDA9: 2157, + 0xCDB1: 2158, + 0xCDB3: 2159, + 0xCDB5: 2160, + 0xCDB7: 2161, + 0xCDC1: 2162, + 0xCDD7: 2163, + 0xCE41: 2164, + 0xCE45: 2165, + 0xCE61: 2166, + 0xCE65: 2167, + 0xCE69: 2168, + 0xCE73: 2169, + 0xCE75: 2170, + 0xCE81: 2171, + 0xCE82: 2172, + 0xCE85: 2173, + 0xCE88: 2174, + 0xCE89: 2175, + 0xCE8B: 2176, + 0xCE91: 2177, + 0xCE93: 2178, + 0xCE95: 2179, + 0xCE97: 2180, + 0xCEA1: 2181, + 0xCEB7: 2182, + 0xCEE1: 2183, + 0xCEE5: 2184, + 0xCEE9: 2185, + 0xCEF1: 2186, + 0xCEF5: 2187, + 0xCF41: 2188, + 0xCF45: 2189, + 0xCF49: 2190, + 0xCF51: 2191, + 0xCF55: 2192, + 0xCF57: 2193, + 0xCF61: 2194, + 0xCF65: 2195, + 0xCF69: 2196, + 0xCF71: 2197, + 0xCF73: 2198, + 0xCF75: 2199, + 0xCFA1: 2200, + 0xCFA2: 2201, + 0xCFA5: 2202, + 0xCFA9: 2203, + 0xCFB1: 2204, + 0xCFB3: 2205, + 0xCFB5: 2206, + 0xCFB7: 2207, + 0xD061: 2208, + 0xD062: 2209, + 0xD065: 2210, + 0xD069: 2211, + 0xD06E: 2212, + 0xD071: 2213, + 0xD073: 2214, + 0xD075: 2215, + 0xD077: 2216, + 0xD081: 2217, + 0xD082: 2218, + 0xD085: 2219, + 0xD089: 2220, + 0xD091: 2221, + 0xD093: 2222, + 0xD095: 2223, + 0xD096: 2224, + 0xD097: 2225, + 0xD0A1: 2226, + 0xD0B7: 2227, + 0xD0E1: 2228, + 0xD0E2: 2229, + 0xD0E5: 2230, + 0xD0E9: 2231, + 0xD0EB: 2232, + 0xD0F1: 2233, + 0xD0F3: 2234, + 0xD0F5: 2235, + 0xD0F7: 2236, + 0xD141: 2237, + 0xD142: 2238, + 0xD145: 2239, + 0xD149: 2240, + 0xD151: 2241, + 0xD153: 2242, + 0xD155: 2243, + 0xD157: 2244, + 0xD161: 2245, + 0xD162: 2246, + 0xD165: 2247, + 0xD169: 2248, + 0xD171: 2249, + 0xD173: 2250, + 0xD175: 2251, + 0xD176: 2252, + 0xD177: 2253, + 0xD181: 2254, + 0xD185: 2255, + 0xD189: 2256, + 0xD193: 2257, + 0xD1A1: 2258, + 0xD1A2: 2259, + 0xD1A5: 2260, + 0xD1A9: 2261, + 0xD1AE: 2262, + 0xD1B1: 2263, + 0xD1B3: 2264, + 0xD1B5: 2265, + 0xD1B7: 2266, + 0xD1BB: 2267, + 0xD1C1: 2268, + 0xD1C2: 2269, + 0xD1C5: 2270, + 0xD1C9: 2271, + 0xD1D5: 2272, + 0xD1D7: 2273, + 0xD1E1: 2274, + 0xD1E2: 2275, + 0xD1E5: 2276, + 0xD1F5: 2277, + 0xD1F7: 2278, + 0xD241: 2279, + 0xD242: 2280, + 0xD245: 2281, + 0xD249: 2282, + 0xD253: 2283, + 0xD255: 2284, + 0xD257: 2285, + 0xD261: 2286, + 0xD265: 2287, + 0xD269: 2288, + 0xD273: 2289, + 0xD275: 2290, + 0xD281: 2291, + 0xD282: 2292, + 0xD285: 2293, + 0xD289: 2294, + 0xD28E: 2295, + 0xD291: 2296, + 0xD295: 2297, + 0xD297: 2298, + 0xD2A1: 2299, + 0xD2A5: 2300, + 0xD2A9: 2301, + 0xD2B1: 2302, + 0xD2B7: 2303, + 0xD2C1: 2304, + 0xD2C2: 2305, + 0xD2C5: 2306, + 0xD2C9: 2307, + 0xD2D7: 2308, + 0xD2E1: 2309, + 0xD2E2: 2310, + 0xD2E5: 2311, + 0xD2E9: 2312, + 0xD2F1: 2313, + 0xD2F3: 2314, + 0xD2F5: 2315, + 0xD2F7: 2316, + 0xD341: 2317, + 0xD342: 2318, + 0xD345: 2319, + 0xD349: 2320, + 0xD351: 2321, + 0xD355: 2322, + 0xD357: 2323, + 0xD361: 2324, + 0xD362: 2325, + 0xD365: 2326, + 0xD367: 2327, + 0xD368: 2328, + 0xD369: 2329, + 0xD36A: 2330, + 0xD371: 2331, + 0xD373: 2332, + 0xD375: 2333, + 0xD377: 2334, + 0xD37B: 2335, + 0xD381: 2336, + 0xD385: 2337, + 0xD389: 2338, + 0xD391: 2339, + 0xD393: 2340, + 0xD397: 2341, + 0xD3A1: 2342, + 0xD3A2: 2343, + 0xD3A5: 2344, + 0xD3A9: 2345, + 0xD3B1: 2346, + 0xD3B3: 2347, + 0xD3B5: 2348, + 0xD3B7: 2349, +} diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/johabprober.py b/venv/Lib/site-packages/pip/_vendor/chardet/johabprober.py new file mode 100644 index 0000000..6f359d1 --- /dev/null +++ b/venv/Lib/site-packages/pip/_vendor/chardet/johabprober.py @@ -0,0 +1,47 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .chardistribution import JOHABDistributionAnalysis +from .codingstatemachine import CodingStateMachine +from .mbcharsetprober import MultiByteCharSetProber +from .mbcssm import JOHAB_SM_MODEL + + +class JOHABProber(MultiByteCharSetProber): + def __init__(self): + super().__init__() + self.coding_sm = CodingStateMachine(JOHAB_SM_MODEL) + self.distribution_analyzer = JOHABDistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "Johab" + + @property + def language(self): + return "Korean" diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/langrussianmodel.py b/venv/Lib/site-packages/pip/_vendor/chardet/langrussianmodel.py new file mode 100644 index 0000000..39a5388 --- /dev/null +++ b/venv/Lib/site-packages/pip/_vendor/chardet/langrussianmodel.py @@ -0,0 +1,5725 @@ +from pip._vendor.chardet.sbcharsetprober import SingleByteCharSetModel + +# 3: Positive +# 2: Likely +# 1: Unlikely +# 0: Negative + +RUSSIAN_LANG_MODEL = { + 37: { # 'А' + 37: 0, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 1, # 'Ж' + 51: 1, # 'З' + 42: 1, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 2, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 1, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 1, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 1, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 0, # 'е' + 24: 1, # 'ж' + 20: 1, # 'з' + 4: 0, # 'и' + 23: 1, # 'й' + 11: 2, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 0, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 2, # 'у' + 39: 2, # 'ф' + 26: 2, # 'х' + 28: 0, # 'ц' + 22: 1, # 'ч' + 25: 2, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 44: { # 'Б' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 1, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 2, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 33: { # 'В' + 37: 2, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 1, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 2, # 'а' + 21: 1, # 'б' + 10: 1, # 'в' + 19: 1, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 2, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 2, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 1, # 'ц' + 22: 2, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 1, # 'ъ' + 18: 3, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 0, # 'ю' + 16: 1, # 'я' + }, + 46: { # 'Г' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 2, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 1, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 1, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 41: { # 'Д' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 2, # 'Е' + 56: 1, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 2, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 3, # 'ж' + 20: 1, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 1, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 48: { # 'Е' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 1, # 'Ж' + 51: 1, # 'З' + 42: 1, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 2, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 2, # 'Р' + 32: 2, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 1, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 0, # 'а' + 21: 0, # 'б' + 10: 2, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 2, # 'е' + 24: 1, # 'ж' + 20: 1, # 'з' + 4: 0, # 'и' + 23: 2, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 1, # 'н' + 1: 0, # 'о' + 15: 1, # 'п' + 9: 1, # 'р' + 7: 3, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 2, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 56: { # 'Ж' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 1, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 1, # 'б' + 10: 0, # 'в' + 19: 1, # 'г' + 13: 1, # 'д' + 2: 2, # 'е' + 24: 1, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 1, # 'м' + 5: 0, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 2, # 'ю' + 16: 0, # 'я' + }, + 51: { # 'З' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 0, # 'г' + 13: 2, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 1, # 'л' + 12: 1, # 'м' + 5: 2, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 1, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 1, # 'я' + }, + 42: { # 'И' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 2, # 'Е' + 56: 1, # 'Ж' + 51: 1, # 'З' + 42: 1, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 2, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 1, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 1, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 2, # 'з' + 4: 1, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 1, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 1, # 'у' + 39: 1, # 'ф' + 26: 2, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 60: { # 'Й' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 1, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 0, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 36: { # 'К' + 37: 2, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 1, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 2, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 1, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 0, # 'м' + 5: 1, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 49: { # 'Л' + 37: 2, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 1, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 1, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 0, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 0, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 1, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 1, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 1, # 'л' + 12: 0, # 'м' + 5: 1, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 2, # 'ю' + 16: 1, # 'я' + }, + 38: { # 'М' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 1, # 'Ф' + 55: 1, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 0, # 'Ь' + 47: 1, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 1, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 1, # 'л' + 12: 1, # 'м' + 5: 2, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 1, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 31: { # 'Н' + 37: 2, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 1, # 'З' + 42: 2, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 1, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 1, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 3, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 2, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 34: { # 'О' + 37: 0, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 2, # 'Д' + 48: 1, # 'Е' + 56: 1, # 'Ж' + 51: 1, # 'З' + 42: 1, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 2, # 'Л' + 38: 1, # 'М' + 31: 2, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 2, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 1, # 'Ф' + 55: 1, # 'Х' + 58: 0, # 'Ц' + 50: 1, # 'Ч' + 57: 1, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 1, # 'а' + 21: 2, # 'б' + 10: 1, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 0, # 'е' + 24: 1, # 'ж' + 20: 1, # 'з' + 4: 0, # 'и' + 23: 1, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 3, # 'н' + 1: 0, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 1, # 'у' + 39: 1, # 'ф' + 26: 2, # 'х' + 28: 1, # 'ц' + 22: 2, # 'ч' + 25: 2, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 35: { # 'П' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 2, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 0, # 'м' + 5: 1, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 3, # 'р' + 7: 1, # 'с' + 6: 1, # 'т' + 14: 2, # 'у' + 39: 1, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 2, # 'ь' + 30: 1, # 'э' + 27: 0, # 'ю' + 16: 2, # 'я' + }, + 45: { # 'Р' + 37: 2, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 2, # 'Е' + 56: 1, # 'Ж' + 51: 0, # 'З' + 42: 2, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 2, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 1, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 1, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 1, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 2, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 2, # 'я' + }, + 32: { # 'С' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 2, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 1, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 1, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 2, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 1, # 'ж' + 20: 1, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 2, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 1, # 'с' + 6: 3, # 'т' + 14: 2, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 1, # 'ц' + 22: 1, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 1, # 'ъ' + 18: 1, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 40: { # 'Т' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 2, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 1, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 1, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 1, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 52: { # 'У' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 1, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 0, # 'Ц' + 50: 1, # 'Ч' + 57: 1, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 1, # 'Ю' + 43: 0, # 'Я' + 3: 1, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 2, # 'д' + 2: 1, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 2, # 'и' + 23: 1, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 1, # 'н' + 1: 2, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 0, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 1, # 'ц' + 22: 2, # 'ч' + 25: 1, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 53: { # 'Ф' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 0, # 'с' + 6: 1, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 55: { # 'Х' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 2, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 0, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 1, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 1, # 'ь' + 30: 1, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 58: { # 'Ц' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 1, # 'а' + 21: 0, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 0, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 1, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 50: { # 'Ч' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 1, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 1, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 1, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 3, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 1, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 57: { # 'Ш' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 1, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 1, # 'н' + 1: 2, # 'о' + 15: 2, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 2, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 63: { # 'Щ' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 1, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 1, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 1, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 1, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 1, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 62: { # 'Ы' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 0, # 'Ч' + 57: 1, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 0, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 0, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 0, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 61: { # 'Ь' + 37: 0, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 0, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 1, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 1, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 1, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 0, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 0, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 0, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 0, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 47: { # 'Э' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 1, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 2, # 'д' + 2: 0, # 'е' + 24: 1, # 'ж' + 20: 0, # 'з' + 4: 0, # 'и' + 23: 2, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 0, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 1, # 'с' + 6: 3, # 'т' + 14: 1, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 59: { # 'Ю' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 0, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 1, # 'б' + 10: 0, # 'в' + 19: 1, # 'г' + 13: 1, # 'д' + 2: 0, # 'е' + 24: 1, # 'ж' + 20: 0, # 'з' + 4: 0, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 2, # 'н' + 1: 0, # 'о' + 15: 1, # 'п' + 9: 1, # 'р' + 7: 1, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 43: { # 'Я' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 0, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 0, # 'а' + 21: 1, # 'б' + 10: 1, # 'в' + 19: 1, # 'г' + 13: 1, # 'д' + 2: 0, # 'е' + 24: 0, # 'ж' + 20: 1, # 'з' + 4: 0, # 'и' + 23: 1, # 'й' + 11: 1, # 'к' + 8: 1, # 'л' + 12: 1, # 'м' + 5: 2, # 'н' + 1: 0, # 'о' + 15: 1, # 'п' + 9: 1, # 'р' + 7: 1, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 3: { # 'а' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 3, # 'з' + 4: 3, # 'и' + 23: 3, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 2, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 3, # 'ц' + 22: 3, # 'ч' + 25: 3, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 2, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 21: { # 'б' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 1, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 0, # 'ф' + 26: 2, # 'х' + 28: 1, # 'ц' + 22: 1, # 'ч' + 25: 2, # 'ш' + 29: 3, # 'щ' + 54: 2, # 'ъ' + 18: 3, # 'ы' + 17: 2, # 'ь' + 30: 1, # 'э' + 27: 2, # 'ю' + 16: 3, # 'я' + }, + 10: { # 'в' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 2, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 1, # 'ж' + 20: 3, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 2, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 3, # 'ш' + 29: 2, # 'щ' + 54: 2, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 3, # 'я' + }, + 19: { # 'г' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 3, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 1, # 'ц' + 22: 2, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 1, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 13: { # 'д' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 3, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 2, # 'х' + 28: 3, # 'ц' + 22: 2, # 'ч' + 25: 2, # 'ш' + 29: 1, # 'щ' + 54: 2, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 1, # 'э' + 27: 2, # 'ю' + 16: 3, # 'я' + }, + 2: { # 'е' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 3, # 'з' + 4: 2, # 'и' + 23: 3, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 2, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 3, # 'ц' + 22: 3, # 'ч' + 25: 3, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 2, # 'ю' + 16: 3, # 'я' + }, + 24: { # 'ж' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 1, # 'в' + 19: 2, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 3, # 'н' + 1: 2, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 1, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 0, # 'х' + 28: 1, # 'ц' + 22: 2, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 2, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 20: { # 'з' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 3, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 1, # 'ц' + 22: 2, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 2, # 'ъ' + 18: 3, # 'ы' + 17: 2, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 3, # 'я' + }, + 4: { # 'и' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 3, # 'з' + 4: 3, # 'и' + 23: 3, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 2, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 3, # 'ц' + 22: 3, # 'ч' + 25: 3, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 2, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 23: { # 'й' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 1, # 'а' + 21: 1, # 'б' + 10: 1, # 'в' + 19: 2, # 'г' + 13: 3, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 2, # 'з' + 4: 1, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 2, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 1, # 'у' + 39: 2, # 'ф' + 26: 1, # 'х' + 28: 2, # 'ц' + 22: 3, # 'ч' + 25: 2, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 2, # 'я' + }, + 11: { # 'к' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 3, # 'в' + 19: 1, # 'г' + 13: 1, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 3, # 'л' + 12: 1, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 2, # 'х' + 28: 2, # 'ц' + 22: 1, # 'ч' + 25: 2, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 1, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 8: { # 'л' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 3, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 1, # 'р' + 7: 3, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 2, # 'х' + 28: 1, # 'ц' + 22: 3, # 'ч' + 25: 2, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 1, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 12: { # 'м' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 2, # 'г' + 13: 1, # 'д' + 2: 3, # 'е' + 24: 1, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 2, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 1, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 2, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 3, # 'я' + }, + 5: { # 'н' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 2, # 'х' + 28: 3, # 'ц' + 22: 3, # 'ч' + 25: 2, # 'ш' + 29: 2, # 'щ' + 54: 1, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 1, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 1: { # 'о' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 3, # 'з' + 4: 3, # 'и' + 23: 3, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 2, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 2, # 'ц' + 22: 3, # 'ч' + 25: 3, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 2, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 15: { # 'п' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 3, # 'л' + 12: 1, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 3, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 0, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 1, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 2, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 3, # 'я' + }, + 9: { # 'р' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 2, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 3, # 'ш' + 29: 2, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 2, # 'э' + 27: 2, # 'ю' + 16: 3, # 'я' + }, + 7: { # 'с' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 1, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 3, # 'в' + 19: 2, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 2, # 'ц' + 22: 3, # 'ч' + 25: 2, # 'ш' + 29: 1, # 'щ' + 54: 2, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 2, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 6: { # 'т' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 3, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 1, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 2, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 2, # 'ш' + 29: 2, # 'щ' + 54: 2, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 2, # 'э' + 27: 2, # 'ю' + 16: 3, # 'я' + }, + 14: { # 'у' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 3, # 'з' + 4: 2, # 'и' + 23: 2, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 2, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 1, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 2, # 'ц' + 22: 3, # 'ч' + 25: 3, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 2, # 'э' + 27: 3, # 'ю' + 16: 2, # 'я' + }, + 39: { # 'ф' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 0, # 'в' + 19: 1, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 1, # 'н' + 1: 3, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 2, # 'у' + 39: 2, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 1, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 2, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 26: { # 'х' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 3, # 'в' + 19: 1, # 'г' + 13: 1, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 1, # 'п' + 9: 3, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 2, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 1, # 'ц' + 22: 1, # 'ч' + 25: 2, # 'ш' + 29: 0, # 'щ' + 54: 1, # 'ъ' + 18: 0, # 'ы' + 17: 1, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 28: { # 'ц' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 1, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 1, # 'л' + 12: 1, # 'м' + 5: 1, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 1, # 'т' + 14: 3, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 1, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 1, # 'ь' + 30: 0, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 22: { # 'ч' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 1, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 3, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 1, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 1, # 'ч' + 25: 2, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 3, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 25: { # 'ш' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 1, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 1, # 'х' + 28: 1, # 'ц' + 22: 1, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 3, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 29: { # 'щ' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 1, # 'м' + 5: 2, # 'н' + 1: 1, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 2, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 54: { # 'ъ' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 0, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 0, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 1, # 'ю' + 16: 2, # 'я' + }, + 18: { # 'ы' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 2, # 'и' + 23: 3, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 1, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 1, # 'у' + 39: 0, # 'ф' + 26: 3, # 'х' + 28: 2, # 'ц' + 22: 3, # 'ч' + 25: 3, # 'ш' + 29: 2, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 2, # 'я' + }, + 17: { # 'ь' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 1, # 'ж' + 20: 3, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 0, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 2, # 'о' + 15: 2, # 'п' + 9: 1, # 'р' + 7: 3, # 'с' + 6: 2, # 'т' + 14: 0, # 'у' + 39: 2, # 'ф' + 26: 1, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 3, # 'ш' + 29: 2, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 30: { # 'э' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 1, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 1, # 'б' + 10: 1, # 'в' + 19: 1, # 'г' + 13: 2, # 'д' + 2: 1, # 'е' + 24: 0, # 'ж' + 20: 1, # 'з' + 4: 0, # 'и' + 23: 2, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 0, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 3, # 'т' + 14: 1, # 'у' + 39: 2, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 27: { # 'ю' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 3, # 'б' + 10: 1, # 'в' + 19: 2, # 'г' + 13: 3, # 'д' + 2: 1, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 1, # 'и' + 23: 1, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 1, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 0, # 'у' + 39: 1, # 'ф' + 26: 2, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 2, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 2, # 'ю' + 16: 1, # 'я' + }, + 16: { # 'я' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 2, # 'б' + 10: 3, # 'в' + 19: 2, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 3, # 'з' + 4: 2, # 'и' + 23: 2, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 0, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 1, # 'у' + 39: 1, # 'ф' + 26: 3, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 2, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 2, # 'ю' + 16: 2, # 'я' + }, +} + +# 255: Undefined characters that did not exist in training text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 +# 251: Control characters + +# Character Mapping Table(s): +IBM866_RUSSIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 37, # 'А' + 129: 44, # 'Б' + 130: 33, # 'В' + 131: 46, # 'Г' + 132: 41, # 'Д' + 133: 48, # 'Е' + 134: 56, # 'Ж' + 135: 51, # 'З' + 136: 42, # 'И' + 137: 60, # 'Й' + 138: 36, # 'К' + 139: 49, # 'Л' + 140: 38, # 'М' + 141: 31, # 'Н' + 142: 34, # 'О' + 143: 35, # 'П' + 144: 45, # 'Р' + 145: 32, # 'С' + 146: 40, # 'Т' + 147: 52, # 'У' + 148: 53, # 'Ф' + 149: 55, # 'Х' + 150: 58, # 'Ц' + 151: 50, # 'Ч' + 152: 57, # 'Ш' + 153: 63, # 'Щ' + 154: 70, # 'Ъ' + 155: 62, # 'Ы' + 156: 61, # 'Ь' + 157: 47, # 'Э' + 158: 59, # 'Ю' + 159: 43, # 'Я' + 160: 3, # 'а' + 161: 21, # 'б' + 162: 10, # 'в' + 163: 19, # 'г' + 164: 13, # 'д' + 165: 2, # 'е' + 166: 24, # 'ж' + 167: 20, # 'з' + 168: 4, # 'и' + 169: 23, # 'й' + 170: 11, # 'к' + 171: 8, # 'л' + 172: 12, # 'м' + 173: 5, # 'н' + 174: 1, # 'о' + 175: 15, # 'п' + 176: 191, # '░' + 177: 192, # '▒' + 178: 193, # '▓' + 179: 194, # '│' + 180: 195, # '┤' + 181: 196, # '╡' + 182: 197, # '╢' + 183: 198, # '╖' + 184: 199, # '╕' + 185: 200, # '╣' + 186: 201, # '║' + 187: 202, # '╗' + 188: 203, # '╝' + 189: 204, # '╜' + 190: 205, # '╛' + 191: 206, # '┐' + 192: 207, # '└' + 193: 208, # '┴' + 194: 209, # '┬' + 195: 210, # '├' + 196: 211, # '─' + 197: 212, # '┼' + 198: 213, # '╞' + 199: 214, # '╟' + 200: 215, # '╚' + 201: 216, # '╔' + 202: 217, # '╩' + 203: 218, # '╦' + 204: 219, # '╠' + 205: 220, # '═' + 206: 221, # '╬' + 207: 222, # '╧' + 208: 223, # '╨' + 209: 224, # '╤' + 210: 225, # '╥' + 211: 226, # '╙' + 212: 227, # '╘' + 213: 228, # '╒' + 214: 229, # '╓' + 215: 230, # '╫' + 216: 231, # '╪' + 217: 232, # '┘' + 218: 233, # '┌' + 219: 234, # '█' + 220: 235, # '▄' + 221: 236, # '▌' + 222: 237, # '▐' + 223: 238, # '▀' + 224: 9, # 'р' + 225: 7, # 'с' + 226: 6, # 'т' + 227: 14, # 'у' + 228: 39, # 'ф' + 229: 26, # 'х' + 230: 28, # 'ц' + 231: 22, # 'ч' + 232: 25, # 'ш' + 233: 29, # 'щ' + 234: 54, # 'ъ' + 235: 18, # 'ы' + 236: 17, # 'ь' + 237: 30, # 'э' + 238: 27, # 'ю' + 239: 16, # 'я' + 240: 239, # 'Ё' + 241: 68, # 'ё' + 242: 240, # 'Є' + 243: 241, # 'є' + 244: 242, # 'Ї' + 245: 243, # 'ї' + 246: 244, # 'Ў' + 247: 245, # 'ў' + 248: 246, # '°' + 249: 247, # '∙' + 250: 248, # '·' + 251: 249, # '√' + 252: 250, # '№' + 253: 251, # '¤' + 254: 252, # '■' + 255: 255, # '\xa0' +} + +IBM866_RUSSIAN_MODEL = SingleByteCharSetModel( + charset_name="IBM866", + language="Russian", + char_to_order_map=IBM866_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet="ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё", +) + +WINDOWS_1251_RUSSIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 191, # 'Ђ' + 129: 192, # 'Ѓ' + 130: 193, # '‚' + 131: 194, # 'ѓ' + 132: 195, # '„' + 133: 196, # '…' + 134: 197, # '†' + 135: 198, # '‡' + 136: 199, # '€' + 137: 200, # '‰' + 138: 201, # 'Љ' + 139: 202, # '‹' + 140: 203, # 'Њ' + 141: 204, # 'Ќ' + 142: 205, # 'Ћ' + 143: 206, # 'Џ' + 144: 207, # 'ђ' + 145: 208, # '‘' + 146: 209, # '’' + 147: 210, # '“' + 148: 211, # '”' + 149: 212, # '•' + 150: 213, # '–' + 151: 214, # '—' + 152: 215, # None + 153: 216, # '™' + 154: 217, # 'љ' + 155: 218, # '›' + 156: 219, # 'њ' + 157: 220, # 'ќ' + 158: 221, # 'ћ' + 159: 222, # 'џ' + 160: 223, # '\xa0' + 161: 224, # 'Ў' + 162: 225, # 'ў' + 163: 226, # 'Ј' + 164: 227, # '¤' + 165: 228, # 'Ґ' + 166: 229, # '¦' + 167: 230, # '§' + 168: 231, # 'Ё' + 169: 232, # '©' + 170: 233, # 'Є' + 171: 234, # '«' + 172: 235, # '¬' + 173: 236, # '\xad' + 174: 237, # '®' + 175: 238, # 'Ї' + 176: 239, # '°' + 177: 240, # '±' + 178: 241, # 'І' + 179: 242, # 'і' + 180: 243, # 'ґ' + 181: 244, # 'µ' + 182: 245, # '¶' + 183: 246, # '·' + 184: 68, # 'ё' + 185: 247, # '№' + 186: 248, # 'є' + 187: 249, # '»' + 188: 250, # 'ј' + 189: 251, # 'Ѕ' + 190: 252, # 'ѕ' + 191: 253, # 'ї' + 192: 37, # 'А' + 193: 44, # 'Б' + 194: 33, # 'В' + 195: 46, # 'Г' + 196: 41, # 'Д' + 197: 48, # 'Е' + 198: 56, # 'Ж' + 199: 51, # 'З' + 200: 42, # 'И' + 201: 60, # 'Й' + 202: 36, # 'К' + 203: 49, # 'Л' + 204: 38, # 'М' + 205: 31, # 'Н' + 206: 34, # 'О' + 207: 35, # 'П' + 208: 45, # 'Р' + 209: 32, # 'С' + 210: 40, # 'Т' + 211: 52, # 'У' + 212: 53, # 'Ф' + 213: 55, # 'Х' + 214: 58, # 'Ц' + 215: 50, # 'Ч' + 216: 57, # 'Ш' + 217: 63, # 'Щ' + 218: 70, # 'Ъ' + 219: 62, # 'Ы' + 220: 61, # 'Ь' + 221: 47, # 'Э' + 222: 59, # 'Ю' + 223: 43, # 'Я' + 224: 3, # 'а' + 225: 21, # 'б' + 226: 10, # 'в' + 227: 19, # 'г' + 228: 13, # 'д' + 229: 2, # 'е' + 230: 24, # 'ж' + 231: 20, # 'з' + 232: 4, # 'и' + 233: 23, # 'й' + 234: 11, # 'к' + 235: 8, # 'л' + 236: 12, # 'м' + 237: 5, # 'н' + 238: 1, # 'о' + 239: 15, # 'п' + 240: 9, # 'р' + 241: 7, # 'с' + 242: 6, # 'т' + 243: 14, # 'у' + 244: 39, # 'ф' + 245: 26, # 'х' + 246: 28, # 'ц' + 247: 22, # 'ч' + 248: 25, # 'ш' + 249: 29, # 'щ' + 250: 54, # 'ъ' + 251: 18, # 'ы' + 252: 17, # 'ь' + 253: 30, # 'э' + 254: 27, # 'ю' + 255: 16, # 'я' +} + +WINDOWS_1251_RUSSIAN_MODEL = SingleByteCharSetModel( + charset_name="windows-1251", + language="Russian", + char_to_order_map=WINDOWS_1251_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet="ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё", +) + +IBM855_RUSSIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 191, # 'ђ' + 129: 192, # 'Ђ' + 130: 193, # 'ѓ' + 131: 194, # 'Ѓ' + 132: 68, # 'ё' + 133: 195, # 'Ё' + 134: 196, # 'є' + 135: 197, # 'Є' + 136: 198, # 'ѕ' + 137: 199, # 'Ѕ' + 138: 200, # 'і' + 139: 201, # 'І' + 140: 202, # 'ї' + 141: 203, # 'Ї' + 142: 204, # 'ј' + 143: 205, # 'Ј' + 144: 206, # 'љ' + 145: 207, # 'Љ' + 146: 208, # 'њ' + 147: 209, # 'Њ' + 148: 210, # 'ћ' + 149: 211, # 'Ћ' + 150: 212, # 'ќ' + 151: 213, # 'Ќ' + 152: 214, # 'ў' + 153: 215, # 'Ў' + 154: 216, # 'џ' + 155: 217, # 'Џ' + 156: 27, # 'ю' + 157: 59, # 'Ю' + 158: 54, # 'ъ' + 159: 70, # 'Ъ' + 160: 3, # 'а' + 161: 37, # 'А' + 162: 21, # 'б' + 163: 44, # 'Б' + 164: 28, # 'ц' + 165: 58, # 'Ц' + 166: 13, # 'д' + 167: 41, # 'Д' + 168: 2, # 'е' + 169: 48, # 'Е' + 170: 39, # 'ф' + 171: 53, # 'Ф' + 172: 19, # 'г' + 173: 46, # 'Г' + 174: 218, # '«' + 175: 219, # '»' + 176: 220, # '░' + 177: 221, # '▒' + 178: 222, # '▓' + 179: 223, # '│' + 180: 224, # '┤' + 181: 26, # 'х' + 182: 55, # 'Х' + 183: 4, # 'и' + 184: 42, # 'И' + 185: 225, # '╣' + 186: 226, # '║' + 187: 227, # '╗' + 188: 228, # '╝' + 189: 23, # 'й' + 190: 60, # 'Й' + 191: 229, # '┐' + 192: 230, # '└' + 193: 231, # '┴' + 194: 232, # '┬' + 195: 233, # '├' + 196: 234, # '─' + 197: 235, # '┼' + 198: 11, # 'к' + 199: 36, # 'К' + 200: 236, # '╚' + 201: 237, # '╔' + 202: 238, # '╩' + 203: 239, # '╦' + 204: 240, # '╠' + 205: 241, # '═' + 206: 242, # '╬' + 207: 243, # '¤' + 208: 8, # 'л' + 209: 49, # 'Л' + 210: 12, # 'м' + 211: 38, # 'М' + 212: 5, # 'н' + 213: 31, # 'Н' + 214: 1, # 'о' + 215: 34, # 'О' + 216: 15, # 'п' + 217: 244, # '┘' + 218: 245, # '┌' + 219: 246, # '█' + 220: 247, # '▄' + 221: 35, # 'П' + 222: 16, # 'я' + 223: 248, # '▀' + 224: 43, # 'Я' + 225: 9, # 'р' + 226: 45, # 'Р' + 227: 7, # 'с' + 228: 32, # 'С' + 229: 6, # 'т' + 230: 40, # 'Т' + 231: 14, # 'у' + 232: 52, # 'У' + 233: 24, # 'ж' + 234: 56, # 'Ж' + 235: 10, # 'в' + 236: 33, # 'В' + 237: 17, # 'ь' + 238: 61, # 'Ь' + 239: 249, # '№' + 240: 250, # '\xad' + 241: 18, # 'ы' + 242: 62, # 'Ы' + 243: 20, # 'з' + 244: 51, # 'З' + 245: 25, # 'ш' + 246: 57, # 'Ш' + 247: 30, # 'э' + 248: 47, # 'Э' + 249: 29, # 'щ' + 250: 63, # 'Щ' + 251: 22, # 'ч' + 252: 50, # 'Ч' + 253: 251, # '§' + 254: 252, # '■' + 255: 255, # '\xa0' +} + +IBM855_RUSSIAN_MODEL = SingleByteCharSetModel( + charset_name="IBM855", + language="Russian", + char_to_order_map=IBM855_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet="ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё", +) + +KOI8_R_RUSSIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 191, # '─' + 129: 192, # '│' + 130: 193, # '┌' + 131: 194, # '┐' + 132: 195, # '└' + 133: 196, # '┘' + 134: 197, # '├' + 135: 198, # '┤' + 136: 199, # '┬' + 137: 200, # '┴' + 138: 201, # '┼' + 139: 202, # '▀' + 140: 203, # '▄' + 141: 204, # '█' + 142: 205, # '▌' + 143: 206, # '▐' + 144: 207, # '░' + 145: 208, # '▒' + 146: 209, # '▓' + 147: 210, # '⌠' + 148: 211, # '■' + 149: 212, # '∙' + 150: 213, # '√' + 151: 214, # '≈' + 152: 215, # '≤' + 153: 216, # '≥' + 154: 217, # '\xa0' + 155: 218, # '⌡' + 156: 219, # '°' + 157: 220, # '²' + 158: 221, # '·' + 159: 222, # '÷' + 160: 223, # '═' + 161: 224, # '║' + 162: 225, # '╒' + 163: 68, # 'ё' + 164: 226, # '╓' + 165: 227, # '╔' + 166: 228, # '╕' + 167: 229, # '╖' + 168: 230, # '╗' + 169: 231, # '╘' + 170: 232, # '╙' + 171: 233, # '╚' + 172: 234, # '╛' + 173: 235, # '╜' + 174: 236, # '╝' + 175: 237, # '╞' + 176: 238, # '╟' + 177: 239, # '╠' + 178: 240, # '╡' + 179: 241, # 'Ё' + 180: 242, # '╢' + 181: 243, # '╣' + 182: 244, # '╤' + 183: 245, # '╥' + 184: 246, # '╦' + 185: 247, # '╧' + 186: 248, # '╨' + 187: 249, # '╩' + 188: 250, # '╪' + 189: 251, # '╫' + 190: 252, # '╬' + 191: 253, # '©' + 192: 27, # 'ю' + 193: 3, # 'а' + 194: 21, # 'б' + 195: 28, # 'ц' + 196: 13, # 'д' + 197: 2, # 'е' + 198: 39, # 'ф' + 199: 19, # 'г' + 200: 26, # 'х' + 201: 4, # 'и' + 202: 23, # 'й' + 203: 11, # 'к' + 204: 8, # 'л' + 205: 12, # 'м' + 206: 5, # 'н' + 207: 1, # 'о' + 208: 15, # 'п' + 209: 16, # 'я' + 210: 9, # 'р' + 211: 7, # 'с' + 212: 6, # 'т' + 213: 14, # 'у' + 214: 24, # 'ж' + 215: 10, # 'в' + 216: 17, # 'ь' + 217: 18, # 'ы' + 218: 20, # 'з' + 219: 25, # 'ш' + 220: 30, # 'э' + 221: 29, # 'щ' + 222: 22, # 'ч' + 223: 54, # 'ъ' + 224: 59, # 'Ю' + 225: 37, # 'А' + 226: 44, # 'Б' + 227: 58, # 'Ц' + 228: 41, # 'Д' + 229: 48, # 'Е' + 230: 53, # 'Ф' + 231: 46, # 'Г' + 232: 55, # 'Х' + 233: 42, # 'И' + 234: 60, # 'Й' + 235: 36, # 'К' + 236: 49, # 'Л' + 237: 38, # 'М' + 238: 31, # 'Н' + 239: 34, # 'О' + 240: 35, # 'П' + 241: 43, # 'Я' + 242: 45, # 'Р' + 243: 32, # 'С' + 244: 40, # 'Т' + 245: 52, # 'У' + 246: 56, # 'Ж' + 247: 33, # 'В' + 248: 61, # 'Ь' + 249: 62, # 'Ы' + 250: 51, # 'З' + 251: 57, # 'Ш' + 252: 47, # 'Э' + 253: 63, # 'Щ' + 254: 50, # 'Ч' + 255: 70, # 'Ъ' +} + +KOI8_R_RUSSIAN_MODEL = SingleByteCharSetModel( + charset_name="KOI8-R", + language="Russian", + char_to_order_map=KOI8_R_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet="ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё", +) + +MACCYRILLIC_RUSSIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 37, # 'А' + 129: 44, # 'Б' + 130: 33, # 'В' + 131: 46, # 'Г' + 132: 41, # 'Д' + 133: 48, # 'Е' + 134: 56, # 'Ж' + 135: 51, # 'З' + 136: 42, # 'И' + 137: 60, # 'Й' + 138: 36, # 'К' + 139: 49, # 'Л' + 140: 38, # 'М' + 141: 31, # 'Н' + 142: 34, # 'О' + 143: 35, # 'П' + 144: 45, # 'Р' + 145: 32, # 'С' + 146: 40, # 'Т' + 147: 52, # 'У' + 148: 53, # 'Ф' + 149: 55, # 'Х' + 150: 58, # 'Ц' + 151: 50, # 'Ч' + 152: 57, # 'Ш' + 153: 63, # 'Щ' + 154: 70, # 'Ъ' + 155: 62, # 'Ы' + 156: 61, # 'Ь' + 157: 47, # 'Э' + 158: 59, # 'Ю' + 159: 43, # 'Я' + 160: 191, # '†' + 161: 192, # '°' + 162: 193, # 'Ґ' + 163: 194, # '£' + 164: 195, # '§' + 165: 196, # '•' + 166: 197, # '¶' + 167: 198, # 'І' + 168: 199, # '®' + 169: 200, # '©' + 170: 201, # '™' + 171: 202, # 'Ђ' + 172: 203, # 'ђ' + 173: 204, # '≠' + 174: 205, # 'Ѓ' + 175: 206, # 'ѓ' + 176: 207, # '∞' + 177: 208, # '±' + 178: 209, # '≤' + 179: 210, # '≥' + 180: 211, # 'і' + 181: 212, # 'µ' + 182: 213, # 'ґ' + 183: 214, # 'Ј' + 184: 215, # 'Є' + 185: 216, # 'є' + 186: 217, # 'Ї' + 187: 218, # 'ї' + 188: 219, # 'Љ' + 189: 220, # 'љ' + 190: 221, # 'Њ' + 191: 222, # 'њ' + 192: 223, # 'ј' + 193: 224, # 'Ѕ' + 194: 225, # '¬' + 195: 226, # '√' + 196: 227, # 'ƒ' + 197: 228, # '≈' + 198: 229, # '∆' + 199: 230, # '«' + 200: 231, # '»' + 201: 232, # '…' + 202: 233, # '\xa0' + 203: 234, # 'Ћ' + 204: 235, # 'ћ' + 205: 236, # 'Ќ' + 206: 237, # 'ќ' + 207: 238, # 'ѕ' + 208: 239, # '–' + 209: 240, # '—' + 210: 241, # '“' + 211: 242, # '”' + 212: 243, # '‘' + 213: 244, # '’' + 214: 245, # '÷' + 215: 246, # '„' + 216: 247, # 'Ў' + 217: 248, # 'ў' + 218: 249, # 'Џ' + 219: 250, # 'џ' + 220: 251, # '№' + 221: 252, # 'Ё' + 222: 68, # 'ё' + 223: 16, # 'я' + 224: 3, # 'а' + 225: 21, # 'б' + 226: 10, # 'в' + 227: 19, # 'г' + 228: 13, # 'д' + 229: 2, # 'е' + 230: 24, # 'ж' + 231: 20, # 'з' + 232: 4, # 'и' + 233: 23, # 'й' + 234: 11, # 'к' + 235: 8, # 'л' + 236: 12, # 'м' + 237: 5, # 'н' + 238: 1, # 'о' + 239: 15, # 'п' + 240: 9, # 'р' + 241: 7, # 'с' + 242: 6, # 'т' + 243: 14, # 'у' + 244: 39, # 'ф' + 245: 26, # 'х' + 246: 28, # 'ц' + 247: 22, # 'ч' + 248: 25, # 'ш' + 249: 29, # 'щ' + 250: 54, # 'ъ' + 251: 18, # 'ы' + 252: 17, # 'ь' + 253: 30, # 'э' + 254: 27, # 'ю' + 255: 255, # '€' +} + +MACCYRILLIC_RUSSIAN_MODEL = SingleByteCharSetModel( + charset_name="MacCyrillic", + language="Russian", + char_to_order_map=MACCYRILLIC_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet="ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё", +) + +ISO_8859_5_RUSSIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 191, # '\x80' + 129: 192, # '\x81' + 130: 193, # '\x82' + 131: 194, # '\x83' + 132: 195, # '\x84' + 133: 196, # '\x85' + 134: 197, # '\x86' + 135: 198, # '\x87' + 136: 199, # '\x88' + 137: 200, # '\x89' + 138: 201, # '\x8a' + 139: 202, # '\x8b' + 140: 203, # '\x8c' + 141: 204, # '\x8d' + 142: 205, # '\x8e' + 143: 206, # '\x8f' + 144: 207, # '\x90' + 145: 208, # '\x91' + 146: 209, # '\x92' + 147: 210, # '\x93' + 148: 211, # '\x94' + 149: 212, # '\x95' + 150: 213, # '\x96' + 151: 214, # '\x97' + 152: 215, # '\x98' + 153: 216, # '\x99' + 154: 217, # '\x9a' + 155: 218, # '\x9b' + 156: 219, # '\x9c' + 157: 220, # '\x9d' + 158: 221, # '\x9e' + 159: 222, # '\x9f' + 160: 223, # '\xa0' + 161: 224, # 'Ё' + 162: 225, # 'Ђ' + 163: 226, # 'Ѓ' + 164: 227, # 'Є' + 165: 228, # 'Ѕ' + 166: 229, # 'І' + 167: 230, # 'Ї' + 168: 231, # 'Ј' + 169: 232, # 'Љ' + 170: 233, # 'Њ' + 171: 234, # 'Ћ' + 172: 235, # 'Ќ' + 173: 236, # '\xad' + 174: 237, # 'Ў' + 175: 238, # 'Џ' + 176: 37, # 'А' + 177: 44, # 'Б' + 178: 33, # 'В' + 179: 46, # 'Г' + 180: 41, # 'Д' + 181: 48, # 'Е' + 182: 56, # 'Ж' + 183: 51, # 'З' + 184: 42, # 'И' + 185: 60, # 'Й' + 186: 36, # 'К' + 187: 49, # 'Л' + 188: 38, # 'М' + 189: 31, # 'Н' + 190: 34, # 'О' + 191: 35, # 'П' + 192: 45, # 'Р' + 193: 32, # 'С' + 194: 40, # 'Т' + 195: 52, # 'У' + 196: 53, # 'Ф' + 197: 55, # 'Х' + 198: 58, # 'Ц' + 199: 50, # 'Ч' + 200: 57, # 'Ш' + 201: 63, # 'Щ' + 202: 70, # 'Ъ' + 203: 62, # 'Ы' + 204: 61, # 'Ь' + 205: 47, # 'Э' + 206: 59, # 'Ю' + 207: 43, # 'Я' + 208: 3, # 'а' + 209: 21, # 'б' + 210: 10, # 'в' + 211: 19, # 'г' + 212: 13, # 'д' + 213: 2, # 'е' + 214: 24, # 'ж' + 215: 20, # 'з' + 216: 4, # 'и' + 217: 23, # 'й' + 218: 11, # 'к' + 219: 8, # 'л' + 220: 12, # 'м' + 221: 5, # 'н' + 222: 1, # 'о' + 223: 15, # 'п' + 224: 9, # 'р' + 225: 7, # 'с' + 226: 6, # 'т' + 227: 14, # 'у' + 228: 39, # 'ф' + 229: 26, # 'х' + 230: 28, # 'ц' + 231: 22, # 'ч' + 232: 25, # 'ш' + 233: 29, # 'щ' + 234: 54, # 'ъ' + 235: 18, # 'ы' + 236: 17, # 'ь' + 237: 30, # 'э' + 238: 27, # 'ю' + 239: 16, # 'я' + 240: 239, # '№' + 241: 68, # 'ё' + 242: 240, # 'ђ' + 243: 241, # 'ѓ' + 244: 242, # 'є' + 245: 243, # 'ѕ' + 246: 244, # 'і' + 247: 245, # 'ї' + 248: 246, # 'ј' + 249: 247, # 'љ' + 250: 248, # 'њ' + 251: 249, # 'ћ' + 252: 250, # 'ќ' + 253: 251, # '§' + 254: 252, # 'ў' + 255: 255, # 'џ' +} + +ISO_8859_5_RUSSIAN_MODEL = SingleByteCharSetModel( + charset_name="ISO-8859-5", + language="Russian", + char_to_order_map=ISO_8859_5_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet="ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё", +) diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/utf1632prober.py b/venv/Lib/site-packages/pip/_vendor/chardet/utf1632prober.py new file mode 100644 index 0000000..9fd1580 --- /dev/null +++ b/venv/Lib/site-packages/pip/_vendor/chardet/utf1632prober.py @@ -0,0 +1,223 @@ +######################## BEGIN LICENSE BLOCK ######################## +# +# Contributor(s): +# Jason Zavaglia +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### +from .charsetprober import CharSetProber +from .enums import ProbingState + + +class UTF1632Prober(CharSetProber): + """ + This class simply looks for occurrences of zero bytes, and infers + whether the file is UTF16 or UTF32 (low-endian or big-endian) + For instance, files looking like ( \0 \0 \0 [nonzero] )+ + have a good probability to be UTF32BE. Files looking like ( \0 [nonzero] )+ + may be guessed to be UTF16BE, and inversely for little-endian varieties. + """ + + # how many logical characters to scan before feeling confident of prediction + MIN_CHARS_FOR_DETECTION = 20 + # a fixed constant ratio of expected zeros or non-zeros in modulo-position. + EXPECTED_RATIO = 0.94 + + def __init__(self): + super().__init__() + self.position = 0 + self.zeros_at_mod = [0] * 4 + self.nonzeros_at_mod = [0] * 4 + self._state = ProbingState.DETECTING + self.quad = [0, 0, 0, 0] + self.invalid_utf16be = False + self.invalid_utf16le = False + self.invalid_utf32be = False + self.invalid_utf32le = False + self.first_half_surrogate_pair_detected_16be = False + self.first_half_surrogate_pair_detected_16le = False + self.reset() + + def reset(self): + super().reset() + self.position = 0 + self.zeros_at_mod = [0] * 4 + self.nonzeros_at_mod = [0] * 4 + self._state = ProbingState.DETECTING + self.invalid_utf16be = False + self.invalid_utf16le = False + self.invalid_utf32be = False + self.invalid_utf32le = False + self.first_half_surrogate_pair_detected_16be = False + self.first_half_surrogate_pair_detected_16le = False + self.quad = [0, 0, 0, 0] + + @property + def charset_name(self): + if self.is_likely_utf32be(): + return "utf-32be" + if self.is_likely_utf32le(): + return "utf-32le" + if self.is_likely_utf16be(): + return "utf-16be" + if self.is_likely_utf16le(): + return "utf-16le" + # default to something valid + return "utf-16" + + @property + def language(self): + return "" + + def approx_32bit_chars(self): + return max(1.0, self.position / 4.0) + + def approx_16bit_chars(self): + return max(1.0, self.position / 2.0) + + def is_likely_utf32be(self): + approx_chars = self.approx_32bit_chars() + return approx_chars >= self.MIN_CHARS_FOR_DETECTION and ( + self.zeros_at_mod[0] / approx_chars > self.EXPECTED_RATIO + and self.zeros_at_mod[1] / approx_chars > self.EXPECTED_RATIO + and self.zeros_at_mod[2] / approx_chars > self.EXPECTED_RATIO + and self.nonzeros_at_mod[3] / approx_chars > self.EXPECTED_RATIO + and not self.invalid_utf32be + ) + + def is_likely_utf32le(self): + approx_chars = self.approx_32bit_chars() + return approx_chars >= self.MIN_CHARS_FOR_DETECTION and ( + self.nonzeros_at_mod[0] / approx_chars > self.EXPECTED_RATIO + and self.zeros_at_mod[1] / approx_chars > self.EXPECTED_RATIO + and self.zeros_at_mod[2] / approx_chars > self.EXPECTED_RATIO + and self.zeros_at_mod[3] / approx_chars > self.EXPECTED_RATIO + and not self.invalid_utf32le + ) + + def is_likely_utf16be(self): + approx_chars = self.approx_16bit_chars() + return approx_chars >= self.MIN_CHARS_FOR_DETECTION and ( + (self.nonzeros_at_mod[1] + self.nonzeros_at_mod[3]) / approx_chars + > self.EXPECTED_RATIO + and (self.zeros_at_mod[0] + self.zeros_at_mod[2]) / approx_chars + > self.EXPECTED_RATIO + and not self.invalid_utf16be + ) + + def is_likely_utf16le(self): + approx_chars = self.approx_16bit_chars() + return approx_chars >= self.MIN_CHARS_FOR_DETECTION and ( + (self.nonzeros_at_mod[0] + self.nonzeros_at_mod[2]) / approx_chars + > self.EXPECTED_RATIO + and (self.zeros_at_mod[1] + self.zeros_at_mod[3]) / approx_chars + > self.EXPECTED_RATIO + and not self.invalid_utf16le + ) + + def validate_utf32_characters(self, quad): + """ + Validate if the quad of bytes is valid UTF-32. + + UTF-32 is valid in the range 0x00000000 - 0x0010FFFF + excluding 0x0000D800 - 0x0000DFFF + + https://en.wikipedia.org/wiki/UTF-32 + """ + if ( + quad[0] != 0 + or quad[1] > 0x10 + or (quad[0] == 0 and quad[1] == 0 and 0xD8 <= quad[2] <= 0xDF) + ): + self.invalid_utf32be = True + if ( + quad[3] != 0 + or quad[2] > 0x10 + or (quad[3] == 0 and quad[2] == 0 and 0xD8 <= quad[1] <= 0xDF) + ): + self.invalid_utf32le = True + + def validate_utf16_characters(self, pair): + """ + Validate if the pair of bytes is valid UTF-16. + + UTF-16 is valid in the range 0x0000 - 0xFFFF excluding 0xD800 - 0xFFFF + with an exception for surrogate pairs, which must be in the range + 0xD800-0xDBFF followed by 0xDC00-0xDFFF + + https://en.wikipedia.org/wiki/UTF-16 + """ + if not self.first_half_surrogate_pair_detected_16be: + if 0xD8 <= pair[0] <= 0xDB: + self.first_half_surrogate_pair_detected_16be = True + elif 0xDC <= pair[0] <= 0xDF: + self.invalid_utf16be = True + else: + if 0xDC <= pair[0] <= 0xDF: + self.first_half_surrogate_pair_detected_16be = False + else: + self.invalid_utf16be = True + + if not self.first_half_surrogate_pair_detected_16le: + if 0xD8 <= pair[1] <= 0xDB: + self.first_half_surrogate_pair_detected_16le = True + elif 0xDC <= pair[1] <= 0xDF: + self.invalid_utf16le = True + else: + if 0xDC <= pair[1] <= 0xDF: + self.first_half_surrogate_pair_detected_16le = False + else: + self.invalid_utf16le = True + + def feed(self, byte_str): + for c in byte_str: + mod4 = self.position % 4 + self.quad[mod4] = c + if mod4 == 3: + self.validate_utf32_characters(self.quad) + self.validate_utf16_characters(self.quad[0:2]) + self.validate_utf16_characters(self.quad[2:4]) + if c == 0: + self.zeros_at_mod[mod4] += 1 + else: + self.nonzeros_at_mod[mod4] += 1 + self.position += 1 + return self.state + + @property + def state(self): + if self._state in {ProbingState.NOT_ME, ProbingState.FOUND_IT}: + # terminal, decided states + return self._state + if self.get_confidence() > 0.80: + self._state = ProbingState.FOUND_IT + elif self.position > 4 * 1024: + # if we get to 4kb into the file, and we can't conclude it's UTF, + # let's give up + self._state = ProbingState.NOT_ME + return self._state + + def get_confidence(self): + return ( + 0.85 + if ( + self.is_likely_utf16le() + or self.is_likely_utf16be() + or self.is_likely_utf32le() + or self.is_likely_utf32be() + ) + else 0.00 + ) diff --git a/venv/Lib/site-packages/pip/_vendor/distlib/t64-arm.exe b/venv/Lib/site-packages/pip/_vendor/distlib/t64-arm.exe new file mode 100644 index 0000000..e1ab8f8 Binary files /dev/null and b/venv/Lib/site-packages/pip/_vendor/distlib/t64-arm.exe differ diff --git a/venv/Lib/site-packages/pip/_vendor/distlib/w64-arm.exe b/venv/Lib/site-packages/pip/_vendor/distlib/w64-arm.exe new file mode 100644 index 0000000..951d581 Binary files /dev/null and b/venv/Lib/site-packages/pip/_vendor/distlib/w64-arm.exe differ diff --git a/venv/Lib/site-packages/pip/_vendor/packaging/_manylinux.py b/venv/Lib/site-packages/pip/_vendor/packaging/_manylinux.py new file mode 100644 index 0000000..4c379aa --- /dev/null +++ b/venv/Lib/site-packages/pip/_vendor/packaging/_manylinux.py @@ -0,0 +1,301 @@ +import collections +import functools +import os +import re +import struct +import sys +import warnings +from typing import IO, Dict, Iterator, NamedTuple, Optional, Tuple + + +# Python does not provide platform information at sufficient granularity to +# identify the architecture of the running executable in some cases, so we +# determine it dynamically by reading the information from the running +# process. This only applies on Linux, which uses the ELF format. +class _ELFFileHeader: + # https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header + class _InvalidELFFileHeader(ValueError): + """ + An invalid ELF file header was found. + """ + + ELF_MAGIC_NUMBER = 0x7F454C46 + ELFCLASS32 = 1 + ELFCLASS64 = 2 + ELFDATA2LSB = 1 + ELFDATA2MSB = 2 + EM_386 = 3 + EM_S390 = 22 + EM_ARM = 40 + EM_X86_64 = 62 + EF_ARM_ABIMASK = 0xFF000000 + EF_ARM_ABI_VER5 = 0x05000000 + EF_ARM_ABI_FLOAT_HARD = 0x00000400 + + def __init__(self, file: IO[bytes]) -> None: + def unpack(fmt: str) -> int: + try: + data = file.read(struct.calcsize(fmt)) + result: Tuple[int, ...] = struct.unpack(fmt, data) + except struct.error: + raise _ELFFileHeader._InvalidELFFileHeader() + return result[0] + + self.e_ident_magic = unpack(">I") + if self.e_ident_magic != self.ELF_MAGIC_NUMBER: + raise _ELFFileHeader._InvalidELFFileHeader() + self.e_ident_class = unpack("B") + if self.e_ident_class not in {self.ELFCLASS32, self.ELFCLASS64}: + raise _ELFFileHeader._InvalidELFFileHeader() + self.e_ident_data = unpack("B") + if self.e_ident_data not in {self.ELFDATA2LSB, self.ELFDATA2MSB}: + raise _ELFFileHeader._InvalidELFFileHeader() + self.e_ident_version = unpack("B") + self.e_ident_osabi = unpack("B") + self.e_ident_abiversion = unpack("B") + self.e_ident_pad = file.read(7) + format_h = "H" + format_i = "I" + format_q = "Q" + format_p = format_i if self.e_ident_class == self.ELFCLASS32 else format_q + self.e_type = unpack(format_h) + self.e_machine = unpack(format_h) + self.e_version = unpack(format_i) + self.e_entry = unpack(format_p) + self.e_phoff = unpack(format_p) + self.e_shoff = unpack(format_p) + self.e_flags = unpack(format_i) + self.e_ehsize = unpack(format_h) + self.e_phentsize = unpack(format_h) + self.e_phnum = unpack(format_h) + self.e_shentsize = unpack(format_h) + self.e_shnum = unpack(format_h) + self.e_shstrndx = unpack(format_h) + + +def _get_elf_header() -> Optional[_ELFFileHeader]: + try: + with open(sys.executable, "rb") as f: + elf_header = _ELFFileHeader(f) + except (OSError, TypeError, _ELFFileHeader._InvalidELFFileHeader): + return None + return elf_header + + +def _is_linux_armhf() -> bool: + # hard-float ABI can be detected from the ELF header of the running + # process + # https://static.docs.arm.com/ihi0044/g/aaelf32.pdf + elf_header = _get_elf_header() + if elf_header is None: + return False + result = elf_header.e_ident_class == elf_header.ELFCLASS32 + result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB + result &= elf_header.e_machine == elf_header.EM_ARM + result &= ( + elf_header.e_flags & elf_header.EF_ARM_ABIMASK + ) == elf_header.EF_ARM_ABI_VER5 + result &= ( + elf_header.e_flags & elf_header.EF_ARM_ABI_FLOAT_HARD + ) == elf_header.EF_ARM_ABI_FLOAT_HARD + return result + + +def _is_linux_i686() -> bool: + elf_header = _get_elf_header() + if elf_header is None: + return False + result = elf_header.e_ident_class == elf_header.ELFCLASS32 + result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB + result &= elf_header.e_machine == elf_header.EM_386 + return result + + +def _have_compatible_abi(arch: str) -> bool: + if arch == "armv7l": + return _is_linux_armhf() + if arch == "i686": + return _is_linux_i686() + return arch in {"x86_64", "aarch64", "ppc64", "ppc64le", "s390x"} + + +# If glibc ever changes its major version, we need to know what the last +# minor version was, so we can build the complete list of all versions. +# For now, guess what the highest minor version might be, assume it will +# be 50 for testing. Once this actually happens, update the dictionary +# with the actual value. +_LAST_GLIBC_MINOR: Dict[int, int] = collections.defaultdict(lambda: 50) + + +class _GLibCVersion(NamedTuple): + major: int + minor: int + + +def _glibc_version_string_confstr() -> Optional[str]: + """ + Primary implementation of glibc_version_string using os.confstr. + """ + # os.confstr is quite a bit faster than ctypes.DLL. It's also less likely + # to be broken or missing. This strategy is used in the standard library + # platform module. + # https://github.com/python/cpython/blob/fcf1d003bf4f0100c/Lib/platform.py#L175-L183 + try: + # os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17". + version_string = os.confstr("CS_GNU_LIBC_VERSION") + assert version_string is not None + _, version = version_string.split() + except (AssertionError, AttributeError, OSError, ValueError): + # os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)... + return None + return version + + +def _glibc_version_string_ctypes() -> Optional[str]: + """ + Fallback implementation of glibc_version_string using ctypes. + """ + try: + import ctypes + except ImportError: + return None + + # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen + # manpage says, "If filename is NULL, then the returned handle is for the + # main program". This way we can let the linker do the work to figure out + # which libc our process is actually using. + # + # We must also handle the special case where the executable is not a + # dynamically linked executable. This can occur when using musl libc, + # for example. In this situation, dlopen() will error, leading to an + # OSError. Interestingly, at least in the case of musl, there is no + # errno set on the OSError. The single string argument used to construct + # OSError comes from libc itself and is therefore not portable to + # hard code here. In any case, failure to call dlopen() means we + # can proceed, so we bail on our attempt. + try: + process_namespace = ctypes.CDLL(None) + except OSError: + return None + + try: + gnu_get_libc_version = process_namespace.gnu_get_libc_version + except AttributeError: + # Symbol doesn't exist -> therefore, we are not linked to + # glibc. + return None + + # Call gnu_get_libc_version, which returns a string like "2.5" + gnu_get_libc_version.restype = ctypes.c_char_p + version_str: str = gnu_get_libc_version() + # py2 / py3 compatibility: + if not isinstance(version_str, str): + version_str = version_str.decode("ascii") + + return version_str + + +def _glibc_version_string() -> Optional[str]: + """Returns glibc version string, or None if not using glibc.""" + return _glibc_version_string_confstr() or _glibc_version_string_ctypes() + + +def _parse_glibc_version(version_str: str) -> Tuple[int, int]: + """Parse glibc version. + + We use a regexp instead of str.split because we want to discard any + random junk that might come after the minor version -- this might happen + in patched/forked versions of glibc (e.g. Linaro's version of glibc + uses version strings like "2.20-2014.11"). See gh-3588. + """ + m = re.match(r"(?P[0-9]+)\.(?P[0-9]+)", version_str) + if not m: + warnings.warn( + "Expected glibc version with 2 components major.minor," + " got: %s" % version_str, + RuntimeWarning, + ) + return -1, -1 + return int(m.group("major")), int(m.group("minor")) + + +@functools.lru_cache() +def _get_glibc_version() -> Tuple[int, int]: + version_str = _glibc_version_string() + if version_str is None: + return (-1, -1) + return _parse_glibc_version(version_str) + + +# From PEP 513, PEP 600 +def _is_compatible(name: str, arch: str, version: _GLibCVersion) -> bool: + sys_glibc = _get_glibc_version() + if sys_glibc < version: + return False + # Check for presence of _manylinux module. + try: + import _manylinux # noqa + except ImportError: + return True + if hasattr(_manylinux, "manylinux_compatible"): + result = _manylinux.manylinux_compatible(version[0], version[1], arch) + if result is not None: + return bool(result) + return True + if version == _GLibCVersion(2, 5): + if hasattr(_manylinux, "manylinux1_compatible"): + return bool(_manylinux.manylinux1_compatible) + if version == _GLibCVersion(2, 12): + if hasattr(_manylinux, "manylinux2010_compatible"): + return bool(_manylinux.manylinux2010_compatible) + if version == _GLibCVersion(2, 17): + if hasattr(_manylinux, "manylinux2014_compatible"): + return bool(_manylinux.manylinux2014_compatible) + return True + + +_LEGACY_MANYLINUX_MAP = { + # CentOS 7 w/ glibc 2.17 (PEP 599) + (2, 17): "manylinux2014", + # CentOS 6 w/ glibc 2.12 (PEP 571) + (2, 12): "manylinux2010", + # CentOS 5 w/ glibc 2.5 (PEP 513) + (2, 5): "manylinux1", +} + + +def platform_tags(linux: str, arch: str) -> Iterator[str]: + if not _have_compatible_abi(arch): + return + # Oldest glibc to be supported regardless of architecture is (2, 17). + too_old_glibc2 = _GLibCVersion(2, 16) + if arch in {"x86_64", "i686"}: + # On x86/i686 also oldest glibc to be supported is (2, 5). + too_old_glibc2 = _GLibCVersion(2, 4) + current_glibc = _GLibCVersion(*_get_glibc_version()) + glibc_max_list = [current_glibc] + # We can assume compatibility across glibc major versions. + # https://sourceware.org/bugzilla/show_bug.cgi?id=24636 + # + # Build a list of maximum glibc versions so that we can + # output the canonical list of all glibc from current_glibc + # down to too_old_glibc2, including all intermediary versions. + for glibc_major in range(current_glibc.major - 1, 1, -1): + glibc_minor = _LAST_GLIBC_MINOR[glibc_major] + glibc_max_list.append(_GLibCVersion(glibc_major, glibc_minor)) + for glibc_max in glibc_max_list: + if glibc_max.major == too_old_glibc2.major: + min_minor = too_old_glibc2.minor + else: + # For other glibc major versions oldest supported is (x, 0). + min_minor = -1 + for glibc_minor in range(glibc_max.minor, min_minor, -1): + glibc_version = _GLibCVersion(glibc_max.major, glibc_minor) + tag = "manylinux_{}_{}".format(*glibc_version) + if _is_compatible(tag, arch, glibc_version): + yield linux.replace("linux", tag) + # Handle the legacy manylinux1, manylinux2010, manylinux2014 tags. + if glibc_version in _LEGACY_MANYLINUX_MAP: + legacy_tag = _LEGACY_MANYLINUX_MAP[glibc_version] + if _is_compatible(legacy_tag, arch, glibc_version): + yield linux.replace("linux", legacy_tag) diff --git a/venv/Lib/site-packages/pip/_vendor/packaging/_musllinux.py b/venv/Lib/site-packages/pip/_vendor/packaging/_musllinux.py new file mode 100644 index 0000000..8ac3059 --- /dev/null +++ b/venv/Lib/site-packages/pip/_vendor/packaging/_musllinux.py @@ -0,0 +1,136 @@ +"""PEP 656 support. + +This module implements logic to detect if the currently running Python is +linked against musl, and what musl version is used. +""" + +import contextlib +import functools +import operator +import os +import re +import struct +import subprocess +import sys +from typing import IO, Iterator, NamedTuple, Optional, Tuple + + +def _read_unpacked(f: IO[bytes], fmt: str) -> Tuple[int, ...]: + return struct.unpack(fmt, f.read(struct.calcsize(fmt))) + + +def _parse_ld_musl_from_elf(f: IO[bytes]) -> Optional[str]: + """Detect musl libc location by parsing the Python executable. + + Based on: https://gist.github.com/lyssdod/f51579ae8d93c8657a5564aefc2ffbca + ELF header: https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html + """ + f.seek(0) + try: + ident = _read_unpacked(f, "16B") + except struct.error: + return None + if ident[:4] != tuple(b"\x7fELF"): # Invalid magic, not ELF. + return None + f.seek(struct.calcsize("HHI"), 1) # Skip file type, machine, and version. + + try: + # e_fmt: Format for program header. + # p_fmt: Format for section header. + # p_idx: Indexes to find p_type, p_offset, and p_filesz. + e_fmt, p_fmt, p_idx = { + 1: ("IIIIHHH", "IIIIIIII", (0, 1, 4)), # 32-bit. + 2: ("QQQIHHH", "IIQQQQQQ", (0, 2, 5)), # 64-bit. + }[ident[4]] + except KeyError: + return None + else: + p_get = operator.itemgetter(*p_idx) + + # Find the interpreter section and return its content. + try: + _, e_phoff, _, _, _, e_phentsize, e_phnum = _read_unpacked(f, e_fmt) + except struct.error: + return None + for i in range(e_phnum + 1): + f.seek(e_phoff + e_phentsize * i) + try: + p_type, p_offset, p_filesz = p_get(_read_unpacked(f, p_fmt)) + except struct.error: + return None + if p_type != 3: # Not PT_INTERP. + continue + f.seek(p_offset) + interpreter = os.fsdecode(f.read(p_filesz)).strip("\0") + if "musl" not in interpreter: + return None + return interpreter + return None + + +class _MuslVersion(NamedTuple): + major: int + minor: int + + +def _parse_musl_version(output: str) -> Optional[_MuslVersion]: + lines = [n for n in (n.strip() for n in output.splitlines()) if n] + if len(lines) < 2 or lines[0][:4] != "musl": + return None + m = re.match(r"Version (\d+)\.(\d+)", lines[1]) + if not m: + return None + return _MuslVersion(major=int(m.group(1)), minor=int(m.group(2))) + + +@functools.lru_cache() +def _get_musl_version(executable: str) -> Optional[_MuslVersion]: + """Detect currently-running musl runtime version. + + This is done by checking the specified executable's dynamic linking + information, and invoking the loader to parse its output for a version + string. If the loader is musl, the output would be something like:: + + musl libc (x86_64) + Version 1.2.2 + Dynamic Program Loader + """ + with contextlib.ExitStack() as stack: + try: + f = stack.enter_context(open(executable, "rb")) + except OSError: + return None + ld = _parse_ld_musl_from_elf(f) + if not ld: + return None + proc = subprocess.run([ld], stderr=subprocess.PIPE, universal_newlines=True) + return _parse_musl_version(proc.stderr) + + +def platform_tags(arch: str) -> Iterator[str]: + """Generate musllinux tags compatible to the current platform. + + :param arch: Should be the part of platform tag after the ``linux_`` + prefix, e.g. ``x86_64``. The ``linux_`` prefix is assumed as a + prerequisite for the current platform to be musllinux-compatible. + + :returns: An iterator of compatible musllinux tags. + """ + sys_musl = _get_musl_version(sys.executable) + if sys_musl is None: # Python not dynamically linked against musl. + return + for minor in range(sys_musl.minor, -1, -1): + yield f"musllinux_{sys_musl.major}_{minor}_{arch}" + + +if __name__ == "__main__": # pragma: no cover + import sysconfig + + plat = sysconfig.get_platform() + assert plat.startswith("linux-"), "not linux" + + print("plat:", plat) + print("musl:", _get_musl_version(sys.executable)) + print("tags:", end=" ") + for t in platform_tags(re.sub(r"[.-]", "_", plat.split("-", 1)[-1])): + print(t, end="\n ") diff --git a/venv/Lib/site-packages/pip/_vendor/pep517/_compat.py b/venv/Lib/site-packages/pip/_vendor/pep517/_compat.py new file mode 100644 index 0000000..95e509c --- /dev/null +++ b/venv/Lib/site-packages/pip/_vendor/pep517/_compat.py @@ -0,0 +1,8 @@ +__all__ = ("tomllib",) + +import sys + +if sys.version_info >= (3, 11): + import tomllib +else: + from pip._vendor import tomli as tomllib diff --git a/venv/Lib/site-packages/pip/_vendor/typing_extensions.py b/venv/Lib/site-packages/pip/_vendor/typing_extensions.py new file mode 100644 index 0000000..34199c2 --- /dev/null +++ b/venv/Lib/site-packages/pip/_vendor/typing_extensions.py @@ -0,0 +1,2209 @@ +import abc +import collections +import collections.abc +import functools +import operator +import sys +import types as _types +import typing + + +__all__ = [ + # Super-special typing primitives. + 'Any', + 'ClassVar', + 'Concatenate', + 'Final', + 'LiteralString', + 'ParamSpec', + 'ParamSpecArgs', + 'ParamSpecKwargs', + 'Self', + 'Type', + 'TypeVar', + 'TypeVarTuple', + 'Unpack', + + # ABCs (from collections.abc). + 'Awaitable', + 'AsyncIterator', + 'AsyncIterable', + 'Coroutine', + 'AsyncGenerator', + 'AsyncContextManager', + 'ChainMap', + + # Concrete collection types. + 'ContextManager', + 'Counter', + 'Deque', + 'DefaultDict', + 'NamedTuple', + 'OrderedDict', + 'TypedDict', + + # Structural checks, a.k.a. protocols. + 'SupportsIndex', + + # One-off things. + 'Annotated', + 'assert_never', + 'assert_type', + 'clear_overloads', + 'dataclass_transform', + 'get_overloads', + 'final', + 'get_args', + 'get_origin', + 'get_type_hints', + 'IntVar', + 'is_typeddict', + 'Literal', + 'NewType', + 'overload', + 'override', + 'Protocol', + 'reveal_type', + 'runtime', + 'runtime_checkable', + 'Text', + 'TypeAlias', + 'TypeGuard', + 'TYPE_CHECKING', + 'Never', + 'NoReturn', + 'Required', + 'NotRequired', +] + +# for backward compatibility +PEP_560 = True +GenericMeta = type + +# The functions below are modified copies of typing internal helpers. +# They are needed by _ProtocolMeta and they provide support for PEP 646. + +_marker = object() + + +def _check_generic(cls, parameters, elen=_marker): + """Check correct count for parameters of a generic cls (internal helper). + This gives a nice error message in case of count mismatch. + """ + if not elen: + raise TypeError(f"{cls} is not a generic class") + if elen is _marker: + if not hasattr(cls, "__parameters__") or not cls.__parameters__: + raise TypeError(f"{cls} is not a generic class") + elen = len(cls.__parameters__) + alen = len(parameters) + if alen != elen: + if hasattr(cls, "__parameters__"): + parameters = [p for p in cls.__parameters__ if not _is_unpack(p)] + num_tv_tuples = sum(isinstance(p, TypeVarTuple) for p in parameters) + if (num_tv_tuples > 0) and (alen >= elen - num_tv_tuples): + return + raise TypeError(f"Too {'many' if alen > elen else 'few'} parameters for {cls};" + f" actual {alen}, expected {elen}") + + +if sys.version_info >= (3, 10): + def _should_collect_from_parameters(t): + return isinstance( + t, (typing._GenericAlias, _types.GenericAlias, _types.UnionType) + ) +elif sys.version_info >= (3, 9): + def _should_collect_from_parameters(t): + return isinstance(t, (typing._GenericAlias, _types.GenericAlias)) +else: + def _should_collect_from_parameters(t): + return isinstance(t, typing._GenericAlias) and not t._special + + +def _collect_type_vars(types, typevar_types=None): + """Collect all type variable contained in types in order of + first appearance (lexicographic order). For example:: + + _collect_type_vars((T, List[S, T])) == (T, S) + """ + if typevar_types is None: + typevar_types = typing.TypeVar + tvars = [] + for t in types: + if ( + isinstance(t, typevar_types) and + t not in tvars and + not _is_unpack(t) + ): + tvars.append(t) + if _should_collect_from_parameters(t): + tvars.extend([t for t in t.__parameters__ if t not in tvars]) + return tuple(tvars) + + +NoReturn = typing.NoReturn + +# Some unconstrained type variables. These are used by the container types. +# (These are not for export.) +T = typing.TypeVar('T') # Any type. +KT = typing.TypeVar('KT') # Key type. +VT = typing.TypeVar('VT') # Value type. +T_co = typing.TypeVar('T_co', covariant=True) # Any type covariant containers. +T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant. + + +if sys.version_info >= (3, 11): + from typing import Any +else: + + class _AnyMeta(type): + def __instancecheck__(self, obj): + if self is Any: + raise TypeError("typing_extensions.Any cannot be used with isinstance()") + return super().__instancecheck__(obj) + + def __repr__(self): + if self is Any: + return "typing_extensions.Any" + return super().__repr__() + + class Any(metaclass=_AnyMeta): + """Special type indicating an unconstrained type. + - Any is compatible with every type. + - Any assumed to have all methods. + - All values assumed to be instances of Any. + Note that all the above statements are true from the point of view of + static type checkers. At runtime, Any should not be used with instance + checks. + """ + def __new__(cls, *args, **kwargs): + if cls is Any: + raise TypeError("Any cannot be instantiated") + return super().__new__(cls, *args, **kwargs) + + +ClassVar = typing.ClassVar + +# On older versions of typing there is an internal class named "Final". +# 3.8+ +if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7): + Final = typing.Final +# 3.7 +else: + class _FinalForm(typing._SpecialForm, _root=True): + + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + Final = _FinalForm('Final', + doc="""A special typing construct to indicate that a name + cannot be re-assigned or overridden in a subclass. + For example: + + MAX_SIZE: Final = 9000 + MAX_SIZE += 1 # Error reported by type checker + + class Connection: + TIMEOUT: Final[int] = 10 + class FastConnector(Connection): + TIMEOUT = 1 # Error reported by type checker + + There is no runtime checking of these properties.""") + +if sys.version_info >= (3, 11): + final = typing.final +else: + # @final exists in 3.8+, but we backport it for all versions + # before 3.11 to keep support for the __final__ attribute. + # See https://bugs.python.org/issue46342 + def final(f): + """This decorator can be used to indicate to type checkers that + the decorated method cannot be overridden, and decorated class + cannot be subclassed. For example: + + class Base: + @final + def done(self) -> None: + ... + class Sub(Base): + def done(self) -> None: # Error reported by type checker + ... + @final + class Leaf: + ... + class Other(Leaf): # Error reported by type checker + ... + + There is no runtime checking of these properties. The decorator + sets the ``__final__`` attribute to ``True`` on the decorated object + to allow runtime introspection. + """ + try: + f.__final__ = True + except (AttributeError, TypeError): + # Skip the attribute silently if it is not writable. + # AttributeError happens if the object has __slots__ or a + # read-only property, TypeError if it's a builtin class. + pass + return f + + +def IntVar(name): + return typing.TypeVar(name) + + +# 3.8+: +if hasattr(typing, 'Literal'): + Literal = typing.Literal +# 3.7: +else: + class _LiteralForm(typing._SpecialForm, _root=True): + + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + return typing._GenericAlias(self, parameters) + + Literal = _LiteralForm('Literal', + doc="""A type that can be used to indicate to type checkers + that the corresponding value has a value literally equivalent + to the provided parameter. For example: + + var: Literal[4] = 4 + + The type checker understands that 'var' is literally equal to + the value 4 and no other value. + + Literal[...] cannot be subclassed. There is no runtime + checking verifying that the parameter is actually a value + instead of a type.""") + + +_overload_dummy = typing._overload_dummy # noqa + + +if hasattr(typing, "get_overloads"): # 3.11+ + overload = typing.overload + get_overloads = typing.get_overloads + clear_overloads = typing.clear_overloads +else: + # {module: {qualname: {firstlineno: func}}} + _overload_registry = collections.defaultdict( + functools.partial(collections.defaultdict, dict) + ) + + def overload(func): + """Decorator for overloaded functions/methods. + + In a stub file, place two or more stub definitions for the same + function in a row, each decorated with @overload. For example: + + @overload + def utf8(value: None) -> None: ... + @overload + def utf8(value: bytes) -> bytes: ... + @overload + def utf8(value: str) -> bytes: ... + + In a non-stub file (i.e. a regular .py file), do the same but + follow it with an implementation. The implementation should *not* + be decorated with @overload. For example: + + @overload + def utf8(value: None) -> None: ... + @overload + def utf8(value: bytes) -> bytes: ... + @overload + def utf8(value: str) -> bytes: ... + def utf8(value): + # implementation goes here + + The overloads for a function can be retrieved at runtime using the + get_overloads() function. + """ + # classmethod and staticmethod + f = getattr(func, "__func__", func) + try: + _overload_registry[f.__module__][f.__qualname__][ + f.__code__.co_firstlineno + ] = func + except AttributeError: + # Not a normal function; ignore. + pass + return _overload_dummy + + def get_overloads(func): + """Return all defined overloads for *func* as a sequence.""" + # classmethod and staticmethod + f = getattr(func, "__func__", func) + if f.__module__ not in _overload_registry: + return [] + mod_dict = _overload_registry[f.__module__] + if f.__qualname__ not in mod_dict: + return [] + return list(mod_dict[f.__qualname__].values()) + + def clear_overloads(): + """Clear all overloads in the registry.""" + _overload_registry.clear() + + +# This is not a real generic class. Don't use outside annotations. +Type = typing.Type + +# Various ABCs mimicking those in collections.abc. +# A few are simply re-exported for completeness. + + +Awaitable = typing.Awaitable +Coroutine = typing.Coroutine +AsyncIterable = typing.AsyncIterable +AsyncIterator = typing.AsyncIterator +Deque = typing.Deque +ContextManager = typing.ContextManager +AsyncContextManager = typing.AsyncContextManager +DefaultDict = typing.DefaultDict + +# 3.7.2+ +if hasattr(typing, 'OrderedDict'): + OrderedDict = typing.OrderedDict +# 3.7.0-3.7.2 +else: + OrderedDict = typing._alias(collections.OrderedDict, (KT, VT)) + +Counter = typing.Counter +ChainMap = typing.ChainMap +AsyncGenerator = typing.AsyncGenerator +NewType = typing.NewType +Text = typing.Text +TYPE_CHECKING = typing.TYPE_CHECKING + + +_PROTO_WHITELIST = ['Callable', 'Awaitable', + 'Iterable', 'Iterator', 'AsyncIterable', 'AsyncIterator', + 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', + 'ContextManager', 'AsyncContextManager'] + + +def _get_protocol_attrs(cls): + attrs = set() + for base in cls.__mro__[:-1]: # without object + if base.__name__ in ('Protocol', 'Generic'): + continue + annotations = getattr(base, '__annotations__', {}) + for attr in list(base.__dict__.keys()) + list(annotations.keys()): + if (not attr.startswith('_abc_') and attr not in ( + '__abstractmethods__', '__annotations__', '__weakref__', + '_is_protocol', '_is_runtime_protocol', '__dict__', + '__args__', '__slots__', + '__next_in_mro__', '__parameters__', '__origin__', + '__orig_bases__', '__extra__', '__tree_hash__', + '__doc__', '__subclasshook__', '__init__', '__new__', + '__module__', '_MutableMapping__marker', '_gorg')): + attrs.add(attr) + return attrs + + +def _is_callable_members_only(cls): + return all(callable(getattr(cls, attr, None)) for attr in _get_protocol_attrs(cls)) + + +def _maybe_adjust_parameters(cls): + """Helper function used in Protocol.__init_subclass__ and _TypedDictMeta.__new__. + + The contents of this function are very similar + to logic found in typing.Generic.__init_subclass__ + on the CPython main branch. + """ + tvars = [] + if '__orig_bases__' in cls.__dict__: + tvars = typing._collect_type_vars(cls.__orig_bases__) + # Look for Generic[T1, ..., Tn] or Protocol[T1, ..., Tn]. + # If found, tvars must be a subset of it. + # If not found, tvars is it. + # Also check for and reject plain Generic, + # and reject multiple Generic[...] and/or Protocol[...]. + gvars = None + for base in cls.__orig_bases__: + if (isinstance(base, typing._GenericAlias) and + base.__origin__ in (typing.Generic, Protocol)): + # for error messages + the_base = base.__origin__.__name__ + if gvars is not None: + raise TypeError( + "Cannot inherit from Generic[...]" + " and/or Protocol[...] multiple types.") + gvars = base.__parameters__ + if gvars is None: + gvars = tvars + else: + tvarset = set(tvars) + gvarset = set(gvars) + if not tvarset <= gvarset: + s_vars = ', '.join(str(t) for t in tvars if t not in gvarset) + s_args = ', '.join(str(g) for g in gvars) + raise TypeError(f"Some type variables ({s_vars}) are" + f" not listed in {the_base}[{s_args}]") + tvars = gvars + cls.__parameters__ = tuple(tvars) + + +# 3.8+ +if hasattr(typing, 'Protocol'): + Protocol = typing.Protocol +# 3.7 +else: + + def _no_init(self, *args, **kwargs): + if type(self)._is_protocol: + raise TypeError('Protocols cannot be instantiated') + + class _ProtocolMeta(abc.ABCMeta): # noqa: B024 + # This metaclass is a bit unfortunate and exists only because of the lack + # of __instancehook__. + def __instancecheck__(cls, instance): + # We need this method for situations where attributes are + # assigned in __init__. + if ((not getattr(cls, '_is_protocol', False) or + _is_callable_members_only(cls)) and + issubclass(instance.__class__, cls)): + return True + if cls._is_protocol: + if all(hasattr(instance, attr) and + (not callable(getattr(cls, attr, None)) or + getattr(instance, attr) is not None) + for attr in _get_protocol_attrs(cls)): + return True + return super().__instancecheck__(instance) + + class Protocol(metaclass=_ProtocolMeta): + # There is quite a lot of overlapping code with typing.Generic. + # Unfortunately it is hard to avoid this while these live in two different + # modules. The duplicated code will be removed when Protocol is moved to typing. + """Base class for protocol classes. Protocol classes are defined as:: + + class Proto(Protocol): + def meth(self) -> int: + ... + + Such classes are primarily used with static type checkers that recognize + structural subtyping (static duck-typing), for example:: + + class C: + def meth(self) -> int: + return 0 + + def func(x: Proto) -> int: + return x.meth() + + func(C()) # Passes static type check + + See PEP 544 for details. Protocol classes decorated with + @typing_extensions.runtime act as simple-minded runtime protocol that checks + only the presence of given attributes, ignoring their type signatures. + + Protocol classes can be generic, they are defined as:: + + class GenProto(Protocol[T]): + def meth(self) -> T: + ... + """ + __slots__ = () + _is_protocol = True + + def __new__(cls, *args, **kwds): + if cls is Protocol: + raise TypeError("Type Protocol cannot be instantiated; " + "it can only be used as a base class") + return super().__new__(cls) + + @typing._tp_cache + def __class_getitem__(cls, params): + if not isinstance(params, tuple): + params = (params,) + if not params and cls is not typing.Tuple: + raise TypeError( + f"Parameter list to {cls.__qualname__}[...] cannot be empty") + msg = "Parameters to generic types must be types." + params = tuple(typing._type_check(p, msg) for p in params) # noqa + if cls is Protocol: + # Generic can only be subscripted with unique type variables. + if not all(isinstance(p, typing.TypeVar) for p in params): + i = 0 + while isinstance(params[i], typing.TypeVar): + i += 1 + raise TypeError( + "Parameters to Protocol[...] must all be type variables." + f" Parameter {i + 1} is {params[i]}") + if len(set(params)) != len(params): + raise TypeError( + "Parameters to Protocol[...] must all be unique") + else: + # Subscripting a regular Generic subclass. + _check_generic(cls, params, len(cls.__parameters__)) + return typing._GenericAlias(cls, params) + + def __init_subclass__(cls, *args, **kwargs): + if '__orig_bases__' in cls.__dict__: + error = typing.Generic in cls.__orig_bases__ + else: + error = typing.Generic in cls.__bases__ + if error: + raise TypeError("Cannot inherit from plain Generic") + _maybe_adjust_parameters(cls) + + # Determine if this is a protocol or a concrete subclass. + if not cls.__dict__.get('_is_protocol', None): + cls._is_protocol = any(b is Protocol for b in cls.__bases__) + + # Set (or override) the protocol subclass hook. + def _proto_hook(other): + if not cls.__dict__.get('_is_protocol', None): + return NotImplemented + if not getattr(cls, '_is_runtime_protocol', False): + if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']: + return NotImplemented + raise TypeError("Instance and class checks can only be used with" + " @runtime protocols") + if not _is_callable_members_only(cls): + if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']: + return NotImplemented + raise TypeError("Protocols with non-method members" + " don't support issubclass()") + if not isinstance(other, type): + # Same error as for issubclass(1, int) + raise TypeError('issubclass() arg 1 must be a class') + for attr in _get_protocol_attrs(cls): + for base in other.__mro__: + if attr in base.__dict__: + if base.__dict__[attr] is None: + return NotImplemented + break + annotations = getattr(base, '__annotations__', {}) + if (isinstance(annotations, typing.Mapping) and + attr in annotations and + isinstance(other, _ProtocolMeta) and + other._is_protocol): + break + else: + return NotImplemented + return True + if '__subclasshook__' not in cls.__dict__: + cls.__subclasshook__ = _proto_hook + + # We have nothing more to do for non-protocols. + if not cls._is_protocol: + return + + # Check consistency of bases. + for base in cls.__bases__: + if not (base in (object, typing.Generic) or + base.__module__ == 'collections.abc' and + base.__name__ in _PROTO_WHITELIST or + isinstance(base, _ProtocolMeta) and base._is_protocol): + raise TypeError('Protocols can only inherit from other' + f' protocols, got {repr(base)}') + cls.__init__ = _no_init + + +# 3.8+ +if hasattr(typing, 'runtime_checkable'): + runtime_checkable = typing.runtime_checkable +# 3.7 +else: + def runtime_checkable(cls): + """Mark a protocol class as a runtime protocol, so that it + can be used with isinstance() and issubclass(). Raise TypeError + if applied to a non-protocol class. + + This allows a simple-minded structural check very similar to the + one-offs in collections.abc such as Hashable. + """ + if not isinstance(cls, _ProtocolMeta) or not cls._is_protocol: + raise TypeError('@runtime_checkable can be only applied to protocol classes,' + f' got {cls!r}') + cls._is_runtime_protocol = True + return cls + + +# Exists for backwards compatibility. +runtime = runtime_checkable + + +# 3.8+ +if hasattr(typing, 'SupportsIndex'): + SupportsIndex = typing.SupportsIndex +# 3.7 +else: + @runtime_checkable + class SupportsIndex(Protocol): + __slots__ = () + + @abc.abstractmethod + def __index__(self) -> int: + pass + + +if hasattr(typing, "Required"): + # The standard library TypedDict in Python 3.8 does not store runtime information + # about which (if any) keys are optional. See https://bugs.python.org/issue38834 + # The standard library TypedDict in Python 3.9.0/1 does not honour the "total" + # keyword with old-style TypedDict(). See https://bugs.python.org/issue42059 + # The standard library TypedDict below Python 3.11 does not store runtime + # information about optional and required keys when using Required or NotRequired. + # Generic TypedDicts are also impossible using typing.TypedDict on Python <3.11. + TypedDict = typing.TypedDict + _TypedDictMeta = typing._TypedDictMeta + is_typeddict = typing.is_typeddict +else: + def _check_fails(cls, other): + try: + if sys._getframe(1).f_globals['__name__'] not in ['abc', + 'functools', + 'typing']: + # Typed dicts are only for static structural subtyping. + raise TypeError('TypedDict does not support instance and class checks') + except (AttributeError, ValueError): + pass + return False + + def _dict_new(*args, **kwargs): + if not args: + raise TypeError('TypedDict.__new__(): not enough arguments') + _, args = args[0], args[1:] # allow the "cls" keyword be passed + return dict(*args, **kwargs) + + _dict_new.__text_signature__ = '($cls, _typename, _fields=None, /, **kwargs)' + + def _typeddict_new(*args, total=True, **kwargs): + if not args: + raise TypeError('TypedDict.__new__(): not enough arguments') + _, args = args[0], args[1:] # allow the "cls" keyword be passed + if args: + typename, args = args[0], args[1:] # allow the "_typename" keyword be passed + elif '_typename' in kwargs: + typename = kwargs.pop('_typename') + import warnings + warnings.warn("Passing '_typename' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + raise TypeError("TypedDict.__new__() missing 1 required positional " + "argument: '_typename'") + if args: + try: + fields, = args # allow the "_fields" keyword be passed + except ValueError: + raise TypeError('TypedDict.__new__() takes from 2 to 3 ' + f'positional arguments but {len(args) + 2} ' + 'were given') + elif '_fields' in kwargs and len(kwargs) == 1: + fields = kwargs.pop('_fields') + import warnings + warnings.warn("Passing '_fields' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + fields = None + + if fields is None: + fields = kwargs + elif kwargs: + raise TypeError("TypedDict takes either a dict or keyword arguments," + " but not both") + + ns = {'__annotations__': dict(fields)} + try: + # Setting correct module is necessary to make typed dict classes pickleable. + ns['__module__'] = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + pass + + return _TypedDictMeta(typename, (), ns, total=total) + + _typeddict_new.__text_signature__ = ('($cls, _typename, _fields=None,' + ' /, *, total=True, **kwargs)') + + class _TypedDictMeta(type): + def __init__(cls, name, bases, ns, total=True): + super().__init__(name, bases, ns) + + def __new__(cls, name, bases, ns, total=True): + # Create new typed dict class object. + # This method is called directly when TypedDict is subclassed, + # or via _typeddict_new when TypedDict is instantiated. This way + # TypedDict supports all three syntaxes described in its docstring. + # Subclasses and instances of TypedDict return actual dictionaries + # via _dict_new. + ns['__new__'] = _typeddict_new if name == 'TypedDict' else _dict_new + # Don't insert typing.Generic into __bases__ here, + # or Generic.__init_subclass__ will raise TypeError + # in the super().__new__() call. + # Instead, monkey-patch __bases__ onto the class after it's been created. + tp_dict = super().__new__(cls, name, (dict,), ns) + + if any(issubclass(base, typing.Generic) for base in bases): + tp_dict.__bases__ = (typing.Generic, dict) + _maybe_adjust_parameters(tp_dict) + + annotations = {} + own_annotations = ns.get('__annotations__', {}) + msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" + own_annotations = { + n: typing._type_check(tp, msg) for n, tp in own_annotations.items() + } + required_keys = set() + optional_keys = set() + + for base in bases: + annotations.update(base.__dict__.get('__annotations__', {})) + required_keys.update(base.__dict__.get('__required_keys__', ())) + optional_keys.update(base.__dict__.get('__optional_keys__', ())) + + annotations.update(own_annotations) + for annotation_key, annotation_type in own_annotations.items(): + annotation_origin = get_origin(annotation_type) + if annotation_origin is Annotated: + annotation_args = get_args(annotation_type) + if annotation_args: + annotation_type = annotation_args[0] + annotation_origin = get_origin(annotation_type) + + if annotation_origin is Required: + required_keys.add(annotation_key) + elif annotation_origin is NotRequired: + optional_keys.add(annotation_key) + elif total: + required_keys.add(annotation_key) + else: + optional_keys.add(annotation_key) + + tp_dict.__annotations__ = annotations + tp_dict.__required_keys__ = frozenset(required_keys) + tp_dict.__optional_keys__ = frozenset(optional_keys) + if not hasattr(tp_dict, '__total__'): + tp_dict.__total__ = total + return tp_dict + + __instancecheck__ = __subclasscheck__ = _check_fails + + TypedDict = _TypedDictMeta('TypedDict', (dict,), {}) + TypedDict.__module__ = __name__ + TypedDict.__doc__ = \ + """A simple typed name space. At runtime it is equivalent to a plain dict. + + TypedDict creates a dictionary type that expects all of its + instances to have a certain set of keys, with each key + associated with a value of a consistent type. This expectation + is not checked at runtime but is only enforced by type checkers. + Usage:: + + class Point2D(TypedDict): + x: int + y: int + label: str + + a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK + b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check + + assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first') + + The type info can be accessed via the Point2D.__annotations__ dict, and + the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets. + TypedDict supports two additional equivalent forms:: + + Point2D = TypedDict('Point2D', x=int, y=int, label=str) + Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str}) + + The class syntax is only supported in Python 3.6+, while two other + syntax forms work for Python 2.7 and 3.2+ + """ + + if hasattr(typing, "_TypedDictMeta"): + _TYPEDDICT_TYPES = (typing._TypedDictMeta, _TypedDictMeta) + else: + _TYPEDDICT_TYPES = (_TypedDictMeta,) + + def is_typeddict(tp): + """Check if an annotation is a TypedDict class + + For example:: + class Film(TypedDict): + title: str + year: int + + is_typeddict(Film) # => True + is_typeddict(Union[list, str]) # => False + """ + return isinstance(tp, tuple(_TYPEDDICT_TYPES)) + + +if hasattr(typing, "assert_type"): + assert_type = typing.assert_type + +else: + def assert_type(__val, __typ): + """Assert (to the type checker) that the value is of the given type. + + When the type checker encounters a call to assert_type(), it + emits an error if the value is not of the specified type:: + + def greet(name: str) -> None: + assert_type(name, str) # ok + assert_type(name, int) # type checker error + + At runtime this returns the first argument unchanged and otherwise + does nothing. + """ + return __val + + +if hasattr(typing, "Required"): + get_type_hints = typing.get_type_hints +else: + import functools + import types + + # replaces _strip_annotations() + def _strip_extras(t): + """Strips Annotated, Required and NotRequired from a given type.""" + if isinstance(t, _AnnotatedAlias): + return _strip_extras(t.__origin__) + if hasattr(t, "__origin__") and t.__origin__ in (Required, NotRequired): + return _strip_extras(t.__args__[0]) + if isinstance(t, typing._GenericAlias): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return t.copy_with(stripped_args) + if hasattr(types, "GenericAlias") and isinstance(t, types.GenericAlias): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return types.GenericAlias(t.__origin__, stripped_args) + if hasattr(types, "UnionType") and isinstance(t, types.UnionType): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return functools.reduce(operator.or_, stripped_args) + + return t + + def get_type_hints(obj, globalns=None, localns=None, include_extras=False): + """Return type hints for an object. + + This is often the same as obj.__annotations__, but it handles + forward references encoded as string literals, adds Optional[t] if a + default value equal to None is set and recursively replaces all + 'Annotated[T, ...]', 'Required[T]' or 'NotRequired[T]' with 'T' + (unless 'include_extras=True'). + + The argument may be a module, class, method, or function. The annotations + are returned as a dictionary. For classes, annotations include also + inherited members. + + TypeError is raised if the argument is not of a type that can contain + annotations, and an empty dictionary is returned if no annotations are + present. + + BEWARE -- the behavior of globalns and localns is counterintuitive + (unless you are familiar with how eval() and exec() work). The + search order is locals first, then globals. + + - If no dict arguments are passed, an attempt is made to use the + globals from obj (or the respective module's globals for classes), + and these are also used as the locals. If the object does not appear + to have globals, an empty dictionary is used. + + - If one dict argument is passed, it is used for both globals and + locals. + + - If two dict arguments are passed, they specify globals and + locals, respectively. + """ + if hasattr(typing, "Annotated"): + hint = typing.get_type_hints( + obj, globalns=globalns, localns=localns, include_extras=True + ) + else: + hint = typing.get_type_hints(obj, globalns=globalns, localns=localns) + if include_extras: + return hint + return {k: _strip_extras(t) for k, t in hint.items()} + + +# Python 3.9+ has PEP 593 (Annotated) +if hasattr(typing, 'Annotated'): + Annotated = typing.Annotated + # Not exported and not a public API, but needed for get_origin() and get_args() + # to work. + _AnnotatedAlias = typing._AnnotatedAlias +# 3.7-3.8 +else: + class _AnnotatedAlias(typing._GenericAlias, _root=True): + """Runtime representation of an annotated type. + + At its core 'Annotated[t, dec1, dec2, ...]' is an alias for the type 't' + with extra annotations. The alias behaves like a normal typing alias, + instantiating is the same as instantiating the underlying type, binding + it to types is also the same. + """ + def __init__(self, origin, metadata): + if isinstance(origin, _AnnotatedAlias): + metadata = origin.__metadata__ + metadata + origin = origin.__origin__ + super().__init__(origin, origin) + self.__metadata__ = metadata + + def copy_with(self, params): + assert len(params) == 1 + new_type = params[0] + return _AnnotatedAlias(new_type, self.__metadata__) + + def __repr__(self): + return (f"typing_extensions.Annotated[{typing._type_repr(self.__origin__)}, " + f"{', '.join(repr(a) for a in self.__metadata__)}]") + + def __reduce__(self): + return operator.getitem, ( + Annotated, (self.__origin__,) + self.__metadata__ + ) + + def __eq__(self, other): + if not isinstance(other, _AnnotatedAlias): + return NotImplemented + if self.__origin__ != other.__origin__: + return False + return self.__metadata__ == other.__metadata__ + + def __hash__(self): + return hash((self.__origin__, self.__metadata__)) + + class Annotated: + """Add context specific metadata to a type. + + Example: Annotated[int, runtime_check.Unsigned] indicates to the + hypothetical runtime_check module that this type is an unsigned int. + Every other consumer of this type can ignore this metadata and treat + this type as int. + + The first argument to Annotated must be a valid type (and will be in + the __origin__ field), the remaining arguments are kept as a tuple in + the __extra__ field. + + Details: + + - It's an error to call `Annotated` with less than two arguments. + - Nested Annotated are flattened:: + + Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] + + - Instantiating an annotated type is equivalent to instantiating the + underlying type:: + + Annotated[C, Ann1](5) == C(5) + + - Annotated can be used as a generic type alias:: + + Optimized = Annotated[T, runtime.Optimize()] + Optimized[int] == Annotated[int, runtime.Optimize()] + + OptimizedList = Annotated[List[T], runtime.Optimize()] + OptimizedList[int] == Annotated[List[int], runtime.Optimize()] + """ + + __slots__ = () + + def __new__(cls, *args, **kwargs): + raise TypeError("Type Annotated cannot be instantiated.") + + @typing._tp_cache + def __class_getitem__(cls, params): + if not isinstance(params, tuple) or len(params) < 2: + raise TypeError("Annotated[...] should be used " + "with at least two arguments (a type and an " + "annotation).") + allowed_special_forms = (ClassVar, Final) + if get_origin(params[0]) in allowed_special_forms: + origin = params[0] + else: + msg = "Annotated[t, ...]: t must be a type." + origin = typing._type_check(params[0], msg) + metadata = tuple(params[1:]) + return _AnnotatedAlias(origin, metadata) + + def __init_subclass__(cls, *args, **kwargs): + raise TypeError( + f"Cannot subclass {cls.__module__}.Annotated" + ) + +# Python 3.8 has get_origin() and get_args() but those implementations aren't +# Annotated-aware, so we can't use those. Python 3.9's versions don't support +# ParamSpecArgs and ParamSpecKwargs, so only Python 3.10's versions will do. +if sys.version_info[:2] >= (3, 10): + get_origin = typing.get_origin + get_args = typing.get_args +# 3.7-3.9 +else: + try: + # 3.9+ + from typing import _BaseGenericAlias + except ImportError: + _BaseGenericAlias = typing._GenericAlias + try: + # 3.9+ + from typing import GenericAlias as _typing_GenericAlias + except ImportError: + _typing_GenericAlias = typing._GenericAlias + + def get_origin(tp): + """Get the unsubscripted version of a type. + + This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar + and Annotated. Return None for unsupported types. Examples:: + + get_origin(Literal[42]) is Literal + get_origin(int) is None + get_origin(ClassVar[int]) is ClassVar + get_origin(Generic) is Generic + get_origin(Generic[T]) is Generic + get_origin(Union[T, int]) is Union + get_origin(List[Tuple[T, T]][int]) == list + get_origin(P.args) is P + """ + if isinstance(tp, _AnnotatedAlias): + return Annotated + if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias, _BaseGenericAlias, + ParamSpecArgs, ParamSpecKwargs)): + return tp.__origin__ + if tp is typing.Generic: + return typing.Generic + return None + + def get_args(tp): + """Get type arguments with all substitutions performed. + + For unions, basic simplifications used by Union constructor are performed. + Examples:: + get_args(Dict[str, int]) == (str, int) + get_args(int) == () + get_args(Union[int, Union[T, int], str][int]) == (int, str) + get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) + get_args(Callable[[], T][int]) == ([], int) + """ + if isinstance(tp, _AnnotatedAlias): + return (tp.__origin__,) + tp.__metadata__ + if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias)): + if getattr(tp, "_special", False): + return () + res = tp.__args__ + if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis: + res = (list(res[:-1]), res[-1]) + return res + return () + + +# 3.10+ +if hasattr(typing, 'TypeAlias'): + TypeAlias = typing.TypeAlias +# 3.9 +elif sys.version_info[:2] >= (3, 9): + class _TypeAliasForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + @_TypeAliasForm + def TypeAlias(self, parameters): + """Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example above. + """ + raise TypeError(f"{self} is not subscriptable") +# 3.7-3.8 +else: + class _TypeAliasForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + TypeAlias = _TypeAliasForm('TypeAlias', + doc="""Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example + above.""") + + +class _DefaultMixin: + """Mixin for TypeVarLike defaults.""" + + __slots__ = () + + def __init__(self, default): + if isinstance(default, (tuple, list)): + self.__default__ = tuple((typing._type_check(d, "Default must be a type") + for d in default)) + elif default: + self.__default__ = typing._type_check(default, "Default must be a type") + else: + self.__default__ = None + + +# Add default and infer_variance parameters from PEP 696 and 695 +class TypeVar(typing.TypeVar, _DefaultMixin, _root=True): + """Type variable.""" + + __module__ = 'typing' + + def __init__(self, name, *constraints, bound=None, + covariant=False, contravariant=False, + default=None, infer_variance=False): + super().__init__(name, *constraints, bound=bound, covariant=covariant, + contravariant=contravariant) + _DefaultMixin.__init__(self, default) + self.__infer_variance__ = infer_variance + + # for pickling: + try: + def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + def_mod = None + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + +# Python 3.10+ has PEP 612 +if hasattr(typing, 'ParamSpecArgs'): + ParamSpecArgs = typing.ParamSpecArgs + ParamSpecKwargs = typing.ParamSpecKwargs +# 3.7-3.9 +else: + class _Immutable: + """Mixin to indicate that object should not be copied.""" + __slots__ = () + + def __copy__(self): + return self + + def __deepcopy__(self, memo): + return self + + class ParamSpecArgs(_Immutable): + """The args for a ParamSpec object. + + Given a ParamSpec object P, P.args is an instance of ParamSpecArgs. + + ParamSpecArgs objects have a reference back to their ParamSpec: + + P.args.__origin__ is P + + This type is meant for runtime introspection and has no special meaning to + static type checkers. + """ + def __init__(self, origin): + self.__origin__ = origin + + def __repr__(self): + return f"{self.__origin__.__name__}.args" + + def __eq__(self, other): + if not isinstance(other, ParamSpecArgs): + return NotImplemented + return self.__origin__ == other.__origin__ + + class ParamSpecKwargs(_Immutable): + """The kwargs for a ParamSpec object. + + Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs. + + ParamSpecKwargs objects have a reference back to their ParamSpec: + + P.kwargs.__origin__ is P + + This type is meant for runtime introspection and has no special meaning to + static type checkers. + """ + def __init__(self, origin): + self.__origin__ = origin + + def __repr__(self): + return f"{self.__origin__.__name__}.kwargs" + + def __eq__(self, other): + if not isinstance(other, ParamSpecKwargs): + return NotImplemented + return self.__origin__ == other.__origin__ + +# 3.10+ +if hasattr(typing, 'ParamSpec'): + + # Add default Parameter - PEP 696 + class ParamSpec(typing.ParamSpec, _DefaultMixin, _root=True): + """Parameter specification variable.""" + + __module__ = 'typing' + + def __init__(self, name, *, bound=None, covariant=False, contravariant=False, + default=None): + super().__init__(name, bound=bound, covariant=covariant, + contravariant=contravariant) + _DefaultMixin.__init__(self, default) + + # for pickling: + try: + def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + def_mod = None + if def_mod != 'typing_extensions': + self.__module__ = def_mod + +# 3.7-3.9 +else: + + # Inherits from list as a workaround for Callable checks in Python < 3.9.2. + class ParamSpec(list, _DefaultMixin): + """Parameter specification variable. + + Usage:: + + P = ParamSpec('P') + + Parameter specification variables exist primarily for the benefit of static + type checkers. They are used to forward the parameter types of one + callable to another callable, a pattern commonly found in higher order + functions and decorators. They are only valid when used in ``Concatenate``, + or s the first argument to ``Callable``. In Python 3.10 and higher, + they are also supported in user-defined Generics at runtime. + See class Generic for more information on generic types. An + example for annotating a decorator:: + + T = TypeVar('T') + P = ParamSpec('P') + + def add_logging(f: Callable[P, T]) -> Callable[P, T]: + '''A type-safe decorator to add logging to a function.''' + def inner(*args: P.args, **kwargs: P.kwargs) -> T: + logging.info(f'{f.__name__} was called') + return f(*args, **kwargs) + return inner + + @add_logging + def add_two(x: float, y: float) -> float: + '''Add two numbers together.''' + return x + y + + Parameter specification variables defined with covariant=True or + contravariant=True can be used to declare covariant or contravariant + generic types. These keyword arguments are valid, but their actual semantics + are yet to be decided. See PEP 612 for details. + + Parameter specification variables can be introspected. e.g.: + + P.__name__ == 'T' + P.__bound__ == None + P.__covariant__ == False + P.__contravariant__ == False + + Note that only parameter specification variables defined in global scope can + be pickled. + """ + + # Trick Generic __parameters__. + __class__ = typing.TypeVar + + @property + def args(self): + return ParamSpecArgs(self) + + @property + def kwargs(self): + return ParamSpecKwargs(self) + + def __init__(self, name, *, bound=None, covariant=False, contravariant=False, + default=None): + super().__init__([self]) + self.__name__ = name + self.__covariant__ = bool(covariant) + self.__contravariant__ = bool(contravariant) + if bound: + self.__bound__ = typing._type_check(bound, 'Bound must be a type.') + else: + self.__bound__ = None + _DefaultMixin.__init__(self, default) + + # for pickling: + try: + def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + def_mod = None + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + def __repr__(self): + if self.__covariant__: + prefix = '+' + elif self.__contravariant__: + prefix = '-' + else: + prefix = '~' + return prefix + self.__name__ + + def __hash__(self): + return object.__hash__(self) + + def __eq__(self, other): + return self is other + + def __reduce__(self): + return self.__name__ + + # Hack to get typing._type_check to pass. + def __call__(self, *args, **kwargs): + pass + + +# 3.7-3.9 +if not hasattr(typing, 'Concatenate'): + # Inherits from list as a workaround for Callable checks in Python < 3.9.2. + class _ConcatenateGenericAlias(list): + + # Trick Generic into looking into this for __parameters__. + __class__ = typing._GenericAlias + + # Flag in 3.8. + _special = False + + def __init__(self, origin, args): + super().__init__(args) + self.__origin__ = origin + self.__args__ = args + + def __repr__(self): + _type_repr = typing._type_repr + return (f'{_type_repr(self.__origin__)}' + f'[{", ".join(_type_repr(arg) for arg in self.__args__)}]') + + def __hash__(self): + return hash((self.__origin__, self.__args__)) + + # Hack to get typing._type_check to pass in Generic. + def __call__(self, *args, **kwargs): + pass + + @property + def __parameters__(self): + return tuple( + tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec)) + ) + + +# 3.7-3.9 +@typing._tp_cache +def _concatenate_getitem(self, parameters): + if parameters == (): + raise TypeError("Cannot take a Concatenate of no types.") + if not isinstance(parameters, tuple): + parameters = (parameters,) + if not isinstance(parameters[-1], ParamSpec): + raise TypeError("The last parameter to Concatenate should be a " + "ParamSpec variable.") + msg = "Concatenate[arg, ...]: each arg must be a type." + parameters = tuple(typing._type_check(p, msg) for p in parameters) + return _ConcatenateGenericAlias(self, parameters) + + +# 3.10+ +if hasattr(typing, 'Concatenate'): + Concatenate = typing.Concatenate + _ConcatenateGenericAlias = typing._ConcatenateGenericAlias # noqa +# 3.9 +elif sys.version_info[:2] >= (3, 9): + @_TypeAliasForm + def Concatenate(self, parameters): + """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a + higher order function which adds, removes or transforms parameters of a + callable. + + For example:: + + Callable[Concatenate[int, P], int] + + See PEP 612 for detailed information. + """ + return _concatenate_getitem(self, parameters) +# 3.7-8 +else: + class _ConcatenateForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + return _concatenate_getitem(self, parameters) + + Concatenate = _ConcatenateForm( + 'Concatenate', + doc="""Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a + higher order function which adds, removes or transforms parameters of a + callable. + + For example:: + + Callable[Concatenate[int, P], int] + + See PEP 612 for detailed information. + """) + +# 3.10+ +if hasattr(typing, 'TypeGuard'): + TypeGuard = typing.TypeGuard +# 3.9 +elif sys.version_info[:2] >= (3, 9): + class _TypeGuardForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + @_TypeGuardForm + def TypeGuard(self, parameters): + """Special typing form used to annotate the return type of a user-defined + type guard function. ``TypeGuard`` only accepts a single type argument. + At runtime, functions marked this way should return a boolean. + + ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static + type checkers to determine a more precise type of an expression within a + program's code flow. Usually type narrowing is done by analyzing + conditional code flow and applying the narrowing to a block of code. The + conditional expression here is sometimes referred to as a "type guard". + + Sometimes it would be convenient to use a user-defined boolean function + as a type guard. Such a function should use ``TypeGuard[...]`` as its + return type to alert static type checkers to this intention. + + Using ``-> TypeGuard`` tells the static type checker that for a given + function: + + 1. The return value is a boolean. + 2. If the return value is ``True``, the type of its argument + is the type inside ``TypeGuard``. + + For example:: + + def is_str(val: Union[str, float]): + # "isinstance" type guard + if isinstance(val, str): + # Type of ``val`` is narrowed to ``str`` + ... + else: + # Else, type of ``val`` is narrowed to ``float``. + ... + + Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower + form of ``TypeA`` (it can even be a wider form) and this may lead to + type-unsafe results. The main reason is to allow for things like + narrowing ``List[object]`` to ``List[str]`` even though the latter is not + a subtype of the former, since ``List`` is invariant. The responsibility of + writing type-safe type guards is left to the user. + + ``TypeGuard`` also works with type variables. For more information, see + PEP 647 (User-Defined Type Guards). + """ + item = typing._type_check(parameters, f'{self} accepts only a single type.') + return typing._GenericAlias(self, (item,)) +# 3.7-3.8 +else: + class _TypeGuardForm(typing._SpecialForm, _root=True): + + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type') + return typing._GenericAlias(self, (item,)) + + TypeGuard = _TypeGuardForm( + 'TypeGuard', + doc="""Special typing form used to annotate the return type of a user-defined + type guard function. ``TypeGuard`` only accepts a single type argument. + At runtime, functions marked this way should return a boolean. + + ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static + type checkers to determine a more precise type of an expression within a + program's code flow. Usually type narrowing is done by analyzing + conditional code flow and applying the narrowing to a block of code. The + conditional expression here is sometimes referred to as a "type guard". + + Sometimes it would be convenient to use a user-defined boolean function + as a type guard. Such a function should use ``TypeGuard[...]`` as its + return type to alert static type checkers to this intention. + + Using ``-> TypeGuard`` tells the static type checker that for a given + function: + + 1. The return value is a boolean. + 2. If the return value is ``True``, the type of its argument + is the type inside ``TypeGuard``. + + For example:: + + def is_str(val: Union[str, float]): + # "isinstance" type guard + if isinstance(val, str): + # Type of ``val`` is narrowed to ``str`` + ... + else: + # Else, type of ``val`` is narrowed to ``float``. + ... + + Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower + form of ``TypeA`` (it can even be a wider form) and this may lead to + type-unsafe results. The main reason is to allow for things like + narrowing ``List[object]`` to ``List[str]`` even though the latter is not + a subtype of the former, since ``List`` is invariant. The responsibility of + writing type-safe type guards is left to the user. + + ``TypeGuard`` also works with type variables. For more information, see + PEP 647 (User-Defined Type Guards). + """) + + +# Vendored from cpython typing._SpecialFrom +class _SpecialForm(typing._Final, _root=True): + __slots__ = ('_name', '__doc__', '_getitem') + + def __init__(self, getitem): + self._getitem = getitem + self._name = getitem.__name__ + self.__doc__ = getitem.__doc__ + + def __getattr__(self, item): + if item in {'__name__', '__qualname__'}: + return self._name + + raise AttributeError(item) + + def __mro_entries__(self, bases): + raise TypeError(f"Cannot subclass {self!r}") + + def __repr__(self): + return f'typing_extensions.{self._name}' + + def __reduce__(self): + return self._name + + def __call__(self, *args, **kwds): + raise TypeError(f"Cannot instantiate {self!r}") + + def __or__(self, other): + return typing.Union[self, other] + + def __ror__(self, other): + return typing.Union[other, self] + + def __instancecheck__(self, obj): + raise TypeError(f"{self} cannot be used with isinstance()") + + def __subclasscheck__(self, cls): + raise TypeError(f"{self} cannot be used with issubclass()") + + @typing._tp_cache + def __getitem__(self, parameters): + return self._getitem(self, parameters) + + +if hasattr(typing, "LiteralString"): + LiteralString = typing.LiteralString +else: + @_SpecialForm + def LiteralString(self, params): + """Represents an arbitrary literal string. + + Example:: + + from pip._vendor.typing_extensions import LiteralString + + def query(sql: LiteralString) -> ...: + ... + + query("SELECT * FROM table") # ok + query(f"SELECT * FROM {input()}") # not ok + + See PEP 675 for details. + + """ + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, "Self"): + Self = typing.Self +else: + @_SpecialForm + def Self(self, params): + """Used to spell the type of "self" in classes. + + Example:: + + from typing import Self + + class ReturnsSelf: + def parse(self, data: bytes) -> Self: + ... + return self + + """ + + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, "Never"): + Never = typing.Never +else: + @_SpecialForm + def Never(self, params): + """The bottom type, a type that has no members. + + This can be used to define a function that should never be + called, or a function that never returns:: + + from pip._vendor.typing_extensions import Never + + def never_call_me(arg: Never) -> None: + pass + + def int_or_str(arg: int | str) -> None: + never_call_me(arg) # type checker error + match arg: + case int(): + print("It's an int") + case str(): + print("It's a str") + case _: + never_call_me(arg) # ok, arg is of type Never + + """ + + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, 'Required'): + Required = typing.Required + NotRequired = typing.NotRequired +elif sys.version_info[:2] >= (3, 9): + class _ExtensionsSpecialForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + @_ExtensionsSpecialForm + def Required(self, parameters): + """A special typing construct to mark a key of a total=False TypedDict + as required. For example: + + class Movie(TypedDict, total=False): + title: Required[str] + year: int + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + + There is no runtime checking that a required key is actually provided + when instantiating a related TypedDict. + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + @_ExtensionsSpecialForm + def NotRequired(self, parameters): + """A special typing construct to mark a key of a TypedDict as + potentially missing. For example: + + class Movie(TypedDict): + title: str + year: NotRequired[int] + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + +else: + class _RequiredForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + Required = _RequiredForm( + 'Required', + doc="""A special typing construct to mark a key of a total=False TypedDict + as required. For example: + + class Movie(TypedDict, total=False): + title: Required[str] + year: int + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + + There is no runtime checking that a required key is actually provided + when instantiating a related TypedDict. + """) + NotRequired = _RequiredForm( + 'NotRequired', + doc="""A special typing construct to mark a key of a TypedDict as + potentially missing. For example: + + class Movie(TypedDict): + title: str + year: NotRequired[int] + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + """) + + +if hasattr(typing, "Unpack"): # 3.11+ + Unpack = typing.Unpack +elif sys.version_info[:2] >= (3, 9): + class _UnpackSpecialForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + class _UnpackAlias(typing._GenericAlias, _root=True): + __class__ = typing.TypeVar + + @_UnpackSpecialForm + def Unpack(self, parameters): + """A special typing construct to unpack a variadic type. For example: + + Shape = TypeVarTuple('Shape') + Batch = NewType('Batch', int) + + def add_batch_axis( + x: Array[Unpack[Shape]] + ) -> Array[Batch, Unpack[Shape]]: ... + + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return _UnpackAlias(self, (item,)) + + def _is_unpack(obj): + return isinstance(obj, _UnpackAlias) + +else: + class _UnpackAlias(typing._GenericAlias, _root=True): + __class__ = typing.TypeVar + + class _UnpackForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type.') + return _UnpackAlias(self, (item,)) + + Unpack = _UnpackForm( + 'Unpack', + doc="""A special typing construct to unpack a variadic type. For example: + + Shape = TypeVarTuple('Shape') + Batch = NewType('Batch', int) + + def add_batch_axis( + x: Array[Unpack[Shape]] + ) -> Array[Batch, Unpack[Shape]]: ... + + """) + + def _is_unpack(obj): + return isinstance(obj, _UnpackAlias) + + +if hasattr(typing, "TypeVarTuple"): # 3.11+ + + # Add default Parameter - PEP 696 + class TypeVarTuple(typing.TypeVarTuple, _DefaultMixin, _root=True): + """Type variable tuple.""" + + def __init__(self, name, *, default=None): + super().__init__(name) + _DefaultMixin.__init__(self, default) + + # for pickling: + try: + def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + def_mod = None + if def_mod != 'typing_extensions': + self.__module__ = def_mod + +else: + class TypeVarTuple(_DefaultMixin): + """Type variable tuple. + + Usage:: + + Ts = TypeVarTuple('Ts') + + In the same way that a normal type variable is a stand-in for a single + type such as ``int``, a type variable *tuple* is a stand-in for a *tuple* + type such as ``Tuple[int, str]``. + + Type variable tuples can be used in ``Generic`` declarations. + Consider the following example:: + + class Array(Generic[*Ts]): ... + + The ``Ts`` type variable tuple here behaves like ``tuple[T1, T2]``, + where ``T1`` and ``T2`` are type variables. To use these type variables + as type parameters of ``Array``, we must *unpack* the type variable tuple using + the star operator: ``*Ts``. The signature of ``Array`` then behaves + as if we had simply written ``class Array(Generic[T1, T2]): ...``. + In contrast to ``Generic[T1, T2]``, however, ``Generic[*Shape]`` allows + us to parameterise the class with an *arbitrary* number of type parameters. + + Type variable tuples can be used anywhere a normal ``TypeVar`` can. + This includes class definitions, as shown above, as well as function + signatures and variable annotations:: + + class Array(Generic[*Ts]): + + def __init__(self, shape: Tuple[*Ts]): + self._shape: Tuple[*Ts] = shape + + def get_shape(self) -> Tuple[*Ts]: + return self._shape + + shape = (Height(480), Width(640)) + x: Array[Height, Width] = Array(shape) + y = abs(x) # Inferred type is Array[Height, Width] + z = x + x # ... is Array[Height, Width] + x.get_shape() # ... is tuple[Height, Width] + + """ + + # Trick Generic __parameters__. + __class__ = typing.TypeVar + + def __iter__(self): + yield self.__unpacked__ + + def __init__(self, name, *, default=None): + self.__name__ = name + _DefaultMixin.__init__(self, default) + + # for pickling: + try: + def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + def_mod = None + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + self.__unpacked__ = Unpack[self] + + def __repr__(self): + return self.__name__ + + def __hash__(self): + return object.__hash__(self) + + def __eq__(self, other): + return self is other + + def __reduce__(self): + return self.__name__ + + def __init_subclass__(self, *args, **kwds): + if '_root' not in kwds: + raise TypeError("Cannot subclass special typing classes") + + +if hasattr(typing, "reveal_type"): + reveal_type = typing.reveal_type +else: + def reveal_type(__obj: T) -> T: + """Reveal the inferred type of a variable. + + When a static type checker encounters a call to ``reveal_type()``, + it will emit the inferred type of the argument:: + + x: int = 1 + reveal_type(x) + + Running a static type checker (e.g., ``mypy``) on this example + will produce output similar to 'Revealed type is "builtins.int"'. + + At runtime, the function prints the runtime type of the + argument and returns it unchanged. + + """ + print(f"Runtime type is {type(__obj).__name__!r}", file=sys.stderr) + return __obj + + +if hasattr(typing, "assert_never"): + assert_never = typing.assert_never +else: + def assert_never(__arg: Never) -> Never: + """Assert to the type checker that a line of code is unreachable. + + Example:: + + def int_or_str(arg: int | str) -> None: + match arg: + case int(): + print("It's an int") + case str(): + print("It's a str") + case _: + assert_never(arg) + + If a type checker finds that a call to assert_never() is + reachable, it will emit an error. + + At runtime, this throws an exception when called. + + """ + raise AssertionError("Expected code to be unreachable") + + +if hasattr(typing, 'dataclass_transform'): + dataclass_transform = typing.dataclass_transform +else: + def dataclass_transform( + *, + eq_default: bool = True, + order_default: bool = False, + kw_only_default: bool = False, + field_specifiers: typing.Tuple[ + typing.Union[typing.Type[typing.Any], typing.Callable[..., typing.Any]], + ... + ] = (), + **kwargs: typing.Any, + ) -> typing.Callable[[T], T]: + """Decorator that marks a function, class, or metaclass as providing + dataclass-like behavior. + + Example: + + from pip._vendor.typing_extensions import dataclass_transform + + _T = TypeVar("_T") + + # Used on a decorator function + @dataclass_transform() + def create_model(cls: type[_T]) -> type[_T]: + ... + return cls + + @create_model + class CustomerModel: + id: int + name: str + + # Used on a base class + @dataclass_transform() + class ModelBase: ... + + class CustomerModel(ModelBase): + id: int + name: str + + # Used on a metaclass + @dataclass_transform() + class ModelMeta(type): ... + + class ModelBase(metaclass=ModelMeta): ... + + class CustomerModel(ModelBase): + id: int + name: str + + Each of the ``CustomerModel`` classes defined in this example will now + behave similarly to a dataclass created with the ``@dataclasses.dataclass`` + decorator. For example, the type checker will synthesize an ``__init__`` + method. + + The arguments to this decorator can be used to customize this behavior: + - ``eq_default`` indicates whether the ``eq`` parameter is assumed to be + True or False if it is omitted by the caller. + - ``order_default`` indicates whether the ``order`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``kw_only_default`` indicates whether the ``kw_only`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``field_specifiers`` specifies a static list of supported classes + or functions that describe fields, similar to ``dataclasses.field()``. + + At runtime, this decorator records its arguments in the + ``__dataclass_transform__`` attribute on the decorated object. + + See PEP 681 for details. + + """ + def decorator(cls_or_fn): + cls_or_fn.__dataclass_transform__ = { + "eq_default": eq_default, + "order_default": order_default, + "kw_only_default": kw_only_default, + "field_specifiers": field_specifiers, + "kwargs": kwargs, + } + return cls_or_fn + return decorator + + +if hasattr(typing, "override"): + override = typing.override +else: + _F = typing.TypeVar("_F", bound=typing.Callable[..., typing.Any]) + + def override(__arg: _F) -> _F: + """Indicate that a method is intended to override a method in a base class. + + Usage: + + class Base: + def method(self) -> None: ... + pass + + class Child(Base): + @override + def method(self) -> None: + super().method() + + When this decorator is applied to a method, the type checker will + validate that it overrides a method with the same name on a base class. + This helps prevent bugs that may occur when a base class is changed + without an equivalent change to a child class. + + See PEP 698 for details. + + """ + return __arg + + +# We have to do some monkey patching to deal with the dual nature of +# Unpack/TypeVarTuple: +# - We want Unpack to be a kind of TypeVar so it gets accepted in +# Generic[Unpack[Ts]] +# - We want it to *not* be treated as a TypeVar for the purposes of +# counting generic parameters, so that when we subscript a generic, +# the runtime doesn't try to substitute the Unpack with the subscripted type. +if not hasattr(typing, "TypeVarTuple"): + typing._collect_type_vars = _collect_type_vars + typing._check_generic = _check_generic + + +# Backport typing.NamedTuple as it exists in Python 3.11. +# In 3.11, the ability to define generic `NamedTuple`s was supported. +# This was explicitly disallowed in 3.9-3.10, and only half-worked in <=3.8. +if sys.version_info >= (3, 11): + NamedTuple = typing.NamedTuple +else: + def _caller(): + try: + return sys._getframe(2).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): # For platforms without _getframe() + return None + + def _make_nmtuple(name, types, module, defaults=()): + fields = [n for n, t in types] + annotations = {n: typing._type_check(t, f"field {n} annotation must be a type") + for n, t in types} + nm_tpl = collections.namedtuple(name, fields, + defaults=defaults, module=module) + nm_tpl.__annotations__ = nm_tpl.__new__.__annotations__ = annotations + # The `_field_types` attribute was removed in 3.9; + # in earlier versions, it is the same as the `__annotations__` attribute + if sys.version_info < (3, 9): + nm_tpl._field_types = annotations + return nm_tpl + + _prohibited_namedtuple_fields = typing._prohibited + _special_namedtuple_fields = frozenset({'__module__', '__name__', '__annotations__'}) + + class _NamedTupleMeta(type): + def __new__(cls, typename, bases, ns): + assert _NamedTuple in bases + for base in bases: + if base is not _NamedTuple and base is not typing.Generic: + raise TypeError( + 'can only inherit from a NamedTuple type and Generic') + bases = tuple(tuple if base is _NamedTuple else base for base in bases) + types = ns.get('__annotations__', {}) + default_names = [] + for field_name in types: + if field_name in ns: + default_names.append(field_name) + elif default_names: + raise TypeError(f"Non-default namedtuple field {field_name} " + f"cannot follow default field" + f"{'s' if len(default_names) > 1 else ''} " + f"{', '.join(default_names)}") + nm_tpl = _make_nmtuple( + typename, types.items(), + defaults=[ns[n] for n in default_names], + module=ns['__module__'] + ) + nm_tpl.__bases__ = bases + if typing.Generic in bases: + class_getitem = typing.Generic.__class_getitem__.__func__ + nm_tpl.__class_getitem__ = classmethod(class_getitem) + # update from user namespace without overriding special namedtuple attributes + for key in ns: + if key in _prohibited_namedtuple_fields: + raise AttributeError("Cannot overwrite NamedTuple attribute " + key) + elif key not in _special_namedtuple_fields and key not in nm_tpl._fields: + setattr(nm_tpl, key, ns[key]) + if typing.Generic in bases: + nm_tpl.__init_subclass__() + return nm_tpl + + def NamedTuple(__typename, __fields=None, **kwargs): + if __fields is None: + __fields = kwargs.items() + elif kwargs: + raise TypeError("Either list of fields or keywords" + " can be provided to NamedTuple, not both") + return _make_nmtuple(__typename, __fields, module=_caller()) + + NamedTuple.__doc__ = typing.NamedTuple.__doc__ + _NamedTuple = type.__new__(_NamedTupleMeta, 'NamedTuple', (), {}) + + # On 3.8+, alter the signature so that it matches typing.NamedTuple. + # The signature of typing.NamedTuple on >=3.8 is invalid syntax in Python 3.7, + # so just leave the signature as it is on 3.7. + if sys.version_info >= (3, 8): + NamedTuple.__text_signature__ = '(typename, fields=None, /, **kwargs)' + + def _namedtuple_mro_entries(bases): + assert NamedTuple in bases + return (_NamedTuple,) + + NamedTuple.__mro_entries__ = _namedtuple_mro_entries diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/_version.py b/venv/Lib/site-packages/pip/_vendor/urllib3/_version.py new file mode 100644 index 0000000..6fbc84b --- /dev/null +++ b/venv/Lib/site-packages/pip/_vendor/urllib3/_version.py @@ -0,0 +1,2 @@ +# This file is protected via CODEOWNERS +__version__ = "1.26.12" diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/util/proxy.py b/venv/Lib/site-packages/pip/_vendor/urllib3/util/proxy.py new file mode 100644 index 0000000..2199cc7 --- /dev/null +++ b/venv/Lib/site-packages/pip/_vendor/urllib3/util/proxy.py @@ -0,0 +1,57 @@ +from .ssl_ import create_urllib3_context, resolve_cert_reqs, resolve_ssl_version + + +def connection_requires_http_tunnel( + proxy_url=None, proxy_config=None, destination_scheme=None +): + """ + Returns True if the connection requires an HTTP CONNECT through the proxy. + + :param URL proxy_url: + URL of the proxy. + :param ProxyConfig proxy_config: + Proxy configuration from poolmanager.py + :param str destination_scheme: + The scheme of the destination. (i.e https, http, etc) + """ + # If we're not using a proxy, no way to use a tunnel. + if proxy_url is None: + return False + + # HTTP destinations never require tunneling, we always forward. + if destination_scheme == "http": + return False + + # Support for forwarding with HTTPS proxies and HTTPS destinations. + if ( + proxy_url.scheme == "https" + and proxy_config + and proxy_config.use_forwarding_for_https + ): + return False + + # Otherwise always use a tunnel. + return True + + +def create_proxy_ssl_context( + ssl_version, cert_reqs, ca_certs=None, ca_cert_dir=None, ca_cert_data=None +): + """ + Generates a default proxy ssl context if one hasn't been provided by the + user. + """ + ssl_context = create_urllib3_context( + ssl_version=resolve_ssl_version(ssl_version), + cert_reqs=resolve_cert_reqs(cert_reqs), + ) + + if ( + not ca_certs + and not ca_cert_dir + and not ca_cert_data + and hasattr(ssl_context, "load_default_certs") + ): + ssl_context.load_default_certs() + + return ssl_context diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssl_match_hostname.py b/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssl_match_hostname.py new file mode 100644 index 0000000..1dd950c --- /dev/null +++ b/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssl_match_hostname.py @@ -0,0 +1,159 @@ +"""The match_hostname() function from Python 3.3.3, essential when using SSL.""" + +# Note: This file is under the PSF license as the code comes from the python +# stdlib. http://docs.python.org/3/license.html + +import re +import sys + +# ipaddress has been backported to 2.6+ in pypi. If it is installed on the +# system, use it to handle IPAddress ServerAltnames (this was added in +# python-3.5) otherwise only do DNS matching. This allows +# util.ssl_match_hostname to continue to be used in Python 2.7. +try: + import ipaddress +except ImportError: + ipaddress = None + +__version__ = "3.5.0.1" + + +class CertificateError(ValueError): + pass + + +def _dnsname_match(dn, hostname, max_wildcards=1): + """Matching according to RFC 6125, section 6.4.3 + + http://tools.ietf.org/html/rfc6125#section-6.4.3 + """ + pats = [] + if not dn: + return False + + # Ported from python3-syntax: + # leftmost, *remainder = dn.split(r'.') + parts = dn.split(r".") + leftmost = parts[0] + remainder = parts[1:] + + wildcards = leftmost.count("*") + if wildcards > max_wildcards: + # Issue #17980: avoid denials of service by refusing more + # than one wildcard per fragment. A survey of established + # policy among SSL implementations showed it to be a + # reasonable choice. + raise CertificateError( + "too many wildcards in certificate DNS name: " + repr(dn) + ) + + # speed up common case w/o wildcards + if not wildcards: + return dn.lower() == hostname.lower() + + # RFC 6125, section 6.4.3, subitem 1. + # The client SHOULD NOT attempt to match a presented identifier in which + # the wildcard character comprises a label other than the left-most label. + if leftmost == "*": + # When '*' is a fragment by itself, it matches a non-empty dotless + # fragment. + pats.append("[^.]+") + elif leftmost.startswith("xn--") or hostname.startswith("xn--"): + # RFC 6125, section 6.4.3, subitem 3. + # The client SHOULD NOT attempt to match a presented identifier + # where the wildcard character is embedded within an A-label or + # U-label of an internationalized domain name. + pats.append(re.escape(leftmost)) + else: + # Otherwise, '*' matches any dotless string, e.g. www* + pats.append(re.escape(leftmost).replace(r"\*", "[^.]*")) + + # add the remaining fragments, ignore any wildcards + for frag in remainder: + pats.append(re.escape(frag)) + + pat = re.compile(r"\A" + r"\.".join(pats) + r"\Z", re.IGNORECASE) + return pat.match(hostname) + + +def _to_unicode(obj): + if isinstance(obj, str) and sys.version_info < (3,): + # ignored flake8 # F821 to support python 2.7 function + obj = unicode(obj, encoding="ascii", errors="strict") # noqa: F821 + return obj + + +def _ipaddress_match(ipname, host_ip): + """Exact matching of IP addresses. + + RFC 6125 explicitly doesn't define an algorithm for this + (section 1.7.2 - "Out of Scope"). + """ + # OpenSSL may add a trailing newline to a subjectAltName's IP address + # Divergence from upstream: ipaddress can't handle byte str + ip = ipaddress.ip_address(_to_unicode(ipname).rstrip()) + return ip == host_ip + + +def match_hostname(cert, hostname): + """Verify that *cert* (in decoded format as returned by + SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125 + rules are followed, but IP addresses are not accepted for *hostname*. + + CertificateError is raised on failure. On success, the function + returns nothing. + """ + if not cert: + raise ValueError( + "empty or no certificate, match_hostname needs a " + "SSL socket or SSL context with either " + "CERT_OPTIONAL or CERT_REQUIRED" + ) + try: + # Divergence from upstream: ipaddress can't handle byte str + host_ip = ipaddress.ip_address(_to_unicode(hostname)) + except (UnicodeError, ValueError): + # ValueError: Not an IP address (common case) + # UnicodeError: Divergence from upstream: Have to deal with ipaddress not taking + # byte strings. addresses should be all ascii, so we consider it not + # an ipaddress in this case + host_ip = None + except AttributeError: + # Divergence from upstream: Make ipaddress library optional + if ipaddress is None: + host_ip = None + else: # Defensive + raise + dnsnames = [] + san = cert.get("subjectAltName", ()) + for key, value in san: + if key == "DNS": + if host_ip is None and _dnsname_match(value, hostname): + return + dnsnames.append(value) + elif key == "IP Address": + if host_ip is not None and _ipaddress_match(value, host_ip): + return + dnsnames.append(value) + if not dnsnames: + # The subject is only checked when there is no dNSName entry + # in subjectAltName + for sub in cert.get("subject", ()): + for key, value in sub: + # XXX according to RFC 2818, the most specific Common Name + # must be used. + if key == "commonName": + if _dnsname_match(value, hostname): + return + dnsnames.append(value) + if len(dnsnames) > 1: + raise CertificateError( + "hostname %r " + "doesn't match either of %s" % (hostname, ", ".join(map(repr, dnsnames))) + ) + elif len(dnsnames) == 1: + raise CertificateError("hostname %r doesn't match %r" % (hostname, dnsnames[0])) + else: + raise CertificateError( + "no appropriate commonName or subjectAltName fields were found" + ) diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssltransport.py b/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssltransport.py new file mode 100644 index 0000000..4a7105d --- /dev/null +++ b/venv/Lib/site-packages/pip/_vendor/urllib3/util/ssltransport.py @@ -0,0 +1,221 @@ +import io +import socket +import ssl + +from ..exceptions import ProxySchemeUnsupported +from ..packages import six + +SSL_BLOCKSIZE = 16384 + + +class SSLTransport: + """ + The SSLTransport wraps an existing socket and establishes an SSL connection. + + Contrary to Python's implementation of SSLSocket, it allows you to chain + multiple TLS connections together. It's particularly useful if you need to + implement TLS within TLS. + + The class supports most of the socket API operations. + """ + + @staticmethod + def _validate_ssl_context_for_tls_in_tls(ssl_context): + """ + Raises a ProxySchemeUnsupported if the provided ssl_context can't be used + for TLS in TLS. + + The only requirement is that the ssl_context provides the 'wrap_bio' + methods. + """ + + if not hasattr(ssl_context, "wrap_bio"): + if six.PY2: + raise ProxySchemeUnsupported( + "TLS in TLS requires SSLContext.wrap_bio() which isn't " + "supported on Python 2" + ) + else: + raise ProxySchemeUnsupported( + "TLS in TLS requires SSLContext.wrap_bio() which isn't " + "available on non-native SSLContext" + ) + + def __init__( + self, socket, ssl_context, server_hostname=None, suppress_ragged_eofs=True + ): + """ + Create an SSLTransport around socket using the provided ssl_context. + """ + self.incoming = ssl.MemoryBIO() + self.outgoing = ssl.MemoryBIO() + + self.suppress_ragged_eofs = suppress_ragged_eofs + self.socket = socket + + self.sslobj = ssl_context.wrap_bio( + self.incoming, self.outgoing, server_hostname=server_hostname + ) + + # Perform initial handshake. + self._ssl_io_loop(self.sslobj.do_handshake) + + def __enter__(self): + return self + + def __exit__(self, *_): + self.close() + + def fileno(self): + return self.socket.fileno() + + def read(self, len=1024, buffer=None): + return self._wrap_ssl_read(len, buffer) + + def recv(self, len=1024, flags=0): + if flags != 0: + raise ValueError("non-zero flags not allowed in calls to recv") + return self._wrap_ssl_read(len) + + def recv_into(self, buffer, nbytes=None, flags=0): + if flags != 0: + raise ValueError("non-zero flags not allowed in calls to recv_into") + if buffer and (nbytes is None): + nbytes = len(buffer) + elif nbytes is None: + nbytes = 1024 + return self.read(nbytes, buffer) + + def sendall(self, data, flags=0): + if flags != 0: + raise ValueError("non-zero flags not allowed in calls to sendall") + count = 0 + with memoryview(data) as view, view.cast("B") as byte_view: + amount = len(byte_view) + while count < amount: + v = self.send(byte_view[count:]) + count += v + + def send(self, data, flags=0): + if flags != 0: + raise ValueError("non-zero flags not allowed in calls to send") + response = self._ssl_io_loop(self.sslobj.write, data) + return response + + def makefile( + self, mode="r", buffering=None, encoding=None, errors=None, newline=None + ): + """ + Python's httpclient uses makefile and buffered io when reading HTTP + messages and we need to support it. + + This is unfortunately a copy and paste of socket.py makefile with small + changes to point to the socket directly. + """ + if not set(mode) <= {"r", "w", "b"}: + raise ValueError("invalid mode %r (only r, w, b allowed)" % (mode,)) + + writing = "w" in mode + reading = "r" in mode or not writing + assert reading or writing + binary = "b" in mode + rawmode = "" + if reading: + rawmode += "r" + if writing: + rawmode += "w" + raw = socket.SocketIO(self, rawmode) + self.socket._io_refs += 1 + if buffering is None: + buffering = -1 + if buffering < 0: + buffering = io.DEFAULT_BUFFER_SIZE + if buffering == 0: + if not binary: + raise ValueError("unbuffered streams must be binary") + return raw + if reading and writing: + buffer = io.BufferedRWPair(raw, raw, buffering) + elif reading: + buffer = io.BufferedReader(raw, buffering) + else: + assert writing + buffer = io.BufferedWriter(raw, buffering) + if binary: + return buffer + text = io.TextIOWrapper(buffer, encoding, errors, newline) + text.mode = mode + return text + + def unwrap(self): + self._ssl_io_loop(self.sslobj.unwrap) + + def close(self): + self.socket.close() + + def getpeercert(self, binary_form=False): + return self.sslobj.getpeercert(binary_form) + + def version(self): + return self.sslobj.version() + + def cipher(self): + return self.sslobj.cipher() + + def selected_alpn_protocol(self): + return self.sslobj.selected_alpn_protocol() + + def selected_npn_protocol(self): + return self.sslobj.selected_npn_protocol() + + def shared_ciphers(self): + return self.sslobj.shared_ciphers() + + def compression(self): + return self.sslobj.compression() + + def settimeout(self, value): + self.socket.settimeout(value) + + def gettimeout(self): + return self.socket.gettimeout() + + def _decref_socketios(self): + self.socket._decref_socketios() + + def _wrap_ssl_read(self, len, buffer=None): + try: + return self._ssl_io_loop(self.sslobj.read, len, buffer) + except ssl.SSLError as e: + if e.errno == ssl.SSL_ERROR_EOF and self.suppress_ragged_eofs: + return 0 # eof, return 0. + else: + raise + + def _ssl_io_loop(self, func, *args): + """Performs an I/O loop between incoming/outgoing and the socket.""" + should_loop = True + ret = None + + while should_loop: + errno = None + try: + ret = func(*args) + except ssl.SSLError as e: + if e.errno not in (ssl.SSL_ERROR_WANT_READ, ssl.SSL_ERROR_WANT_WRITE): + # WANT_READ, and WANT_WRITE are expected, others are not. + raise e + errno = e.errno + + buf = self.outgoing.read() + self.socket.sendall(buf) + + if errno is None: + should_loop = False + elif errno == ssl.SSL_ERROR_WANT_READ: + buf = self.socket.recv(SSL_BLOCKSIZE) + if buf: + self.incoming.write(buf) + else: + self.incoming.write_eof() + return ret diff --git a/venv/Lib/site-packages/pip/py.typed b/venv/Lib/site-packages/pip/py.typed new file mode 100644 index 0000000..493b53e --- /dev/null +++ b/venv/Lib/site-packages/pip/py.typed @@ -0,0 +1,4 @@ +pip is a command line program. While it is implemented in Python, and so is +available for import, you must not use pip's internal APIs in this way. Typing +information is provided as a convenience only and is not a guarantee. Expect +unannounced changes to the API and types in releases. diff --git a/venv/Lib/site-packages/pkg_resources/_vendor/packaging/_manylinux.py b/venv/Lib/site-packages/pkg_resources/_vendor/packaging/_manylinux.py new file mode 100644 index 0000000..4c379aa --- /dev/null +++ b/venv/Lib/site-packages/pkg_resources/_vendor/packaging/_manylinux.py @@ -0,0 +1,301 @@ +import collections +import functools +import os +import re +import struct +import sys +import warnings +from typing import IO, Dict, Iterator, NamedTuple, Optional, Tuple + + +# Python does not provide platform information at sufficient granularity to +# identify the architecture of the running executable in some cases, so we +# determine it dynamically by reading the information from the running +# process. This only applies on Linux, which uses the ELF format. +class _ELFFileHeader: + # https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header + class _InvalidELFFileHeader(ValueError): + """ + An invalid ELF file header was found. + """ + + ELF_MAGIC_NUMBER = 0x7F454C46 + ELFCLASS32 = 1 + ELFCLASS64 = 2 + ELFDATA2LSB = 1 + ELFDATA2MSB = 2 + EM_386 = 3 + EM_S390 = 22 + EM_ARM = 40 + EM_X86_64 = 62 + EF_ARM_ABIMASK = 0xFF000000 + EF_ARM_ABI_VER5 = 0x05000000 + EF_ARM_ABI_FLOAT_HARD = 0x00000400 + + def __init__(self, file: IO[bytes]) -> None: + def unpack(fmt: str) -> int: + try: + data = file.read(struct.calcsize(fmt)) + result: Tuple[int, ...] = struct.unpack(fmt, data) + except struct.error: + raise _ELFFileHeader._InvalidELFFileHeader() + return result[0] + + self.e_ident_magic = unpack(">I") + if self.e_ident_magic != self.ELF_MAGIC_NUMBER: + raise _ELFFileHeader._InvalidELFFileHeader() + self.e_ident_class = unpack("B") + if self.e_ident_class not in {self.ELFCLASS32, self.ELFCLASS64}: + raise _ELFFileHeader._InvalidELFFileHeader() + self.e_ident_data = unpack("B") + if self.e_ident_data not in {self.ELFDATA2LSB, self.ELFDATA2MSB}: + raise _ELFFileHeader._InvalidELFFileHeader() + self.e_ident_version = unpack("B") + self.e_ident_osabi = unpack("B") + self.e_ident_abiversion = unpack("B") + self.e_ident_pad = file.read(7) + format_h = "H" + format_i = "I" + format_q = "Q" + format_p = format_i if self.e_ident_class == self.ELFCLASS32 else format_q + self.e_type = unpack(format_h) + self.e_machine = unpack(format_h) + self.e_version = unpack(format_i) + self.e_entry = unpack(format_p) + self.e_phoff = unpack(format_p) + self.e_shoff = unpack(format_p) + self.e_flags = unpack(format_i) + self.e_ehsize = unpack(format_h) + self.e_phentsize = unpack(format_h) + self.e_phnum = unpack(format_h) + self.e_shentsize = unpack(format_h) + self.e_shnum = unpack(format_h) + self.e_shstrndx = unpack(format_h) + + +def _get_elf_header() -> Optional[_ELFFileHeader]: + try: + with open(sys.executable, "rb") as f: + elf_header = _ELFFileHeader(f) + except (OSError, TypeError, _ELFFileHeader._InvalidELFFileHeader): + return None + return elf_header + + +def _is_linux_armhf() -> bool: + # hard-float ABI can be detected from the ELF header of the running + # process + # https://static.docs.arm.com/ihi0044/g/aaelf32.pdf + elf_header = _get_elf_header() + if elf_header is None: + return False + result = elf_header.e_ident_class == elf_header.ELFCLASS32 + result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB + result &= elf_header.e_machine == elf_header.EM_ARM + result &= ( + elf_header.e_flags & elf_header.EF_ARM_ABIMASK + ) == elf_header.EF_ARM_ABI_VER5 + result &= ( + elf_header.e_flags & elf_header.EF_ARM_ABI_FLOAT_HARD + ) == elf_header.EF_ARM_ABI_FLOAT_HARD + return result + + +def _is_linux_i686() -> bool: + elf_header = _get_elf_header() + if elf_header is None: + return False + result = elf_header.e_ident_class == elf_header.ELFCLASS32 + result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB + result &= elf_header.e_machine == elf_header.EM_386 + return result + + +def _have_compatible_abi(arch: str) -> bool: + if arch == "armv7l": + return _is_linux_armhf() + if arch == "i686": + return _is_linux_i686() + return arch in {"x86_64", "aarch64", "ppc64", "ppc64le", "s390x"} + + +# If glibc ever changes its major version, we need to know what the last +# minor version was, so we can build the complete list of all versions. +# For now, guess what the highest minor version might be, assume it will +# be 50 for testing. Once this actually happens, update the dictionary +# with the actual value. +_LAST_GLIBC_MINOR: Dict[int, int] = collections.defaultdict(lambda: 50) + + +class _GLibCVersion(NamedTuple): + major: int + minor: int + + +def _glibc_version_string_confstr() -> Optional[str]: + """ + Primary implementation of glibc_version_string using os.confstr. + """ + # os.confstr is quite a bit faster than ctypes.DLL. It's also less likely + # to be broken or missing. This strategy is used in the standard library + # platform module. + # https://github.com/python/cpython/blob/fcf1d003bf4f0100c/Lib/platform.py#L175-L183 + try: + # os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17". + version_string = os.confstr("CS_GNU_LIBC_VERSION") + assert version_string is not None + _, version = version_string.split() + except (AssertionError, AttributeError, OSError, ValueError): + # os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)... + return None + return version + + +def _glibc_version_string_ctypes() -> Optional[str]: + """ + Fallback implementation of glibc_version_string using ctypes. + """ + try: + import ctypes + except ImportError: + return None + + # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen + # manpage says, "If filename is NULL, then the returned handle is for the + # main program". This way we can let the linker do the work to figure out + # which libc our process is actually using. + # + # We must also handle the special case where the executable is not a + # dynamically linked executable. This can occur when using musl libc, + # for example. In this situation, dlopen() will error, leading to an + # OSError. Interestingly, at least in the case of musl, there is no + # errno set on the OSError. The single string argument used to construct + # OSError comes from libc itself and is therefore not portable to + # hard code here. In any case, failure to call dlopen() means we + # can proceed, so we bail on our attempt. + try: + process_namespace = ctypes.CDLL(None) + except OSError: + return None + + try: + gnu_get_libc_version = process_namespace.gnu_get_libc_version + except AttributeError: + # Symbol doesn't exist -> therefore, we are not linked to + # glibc. + return None + + # Call gnu_get_libc_version, which returns a string like "2.5" + gnu_get_libc_version.restype = ctypes.c_char_p + version_str: str = gnu_get_libc_version() + # py2 / py3 compatibility: + if not isinstance(version_str, str): + version_str = version_str.decode("ascii") + + return version_str + + +def _glibc_version_string() -> Optional[str]: + """Returns glibc version string, or None if not using glibc.""" + return _glibc_version_string_confstr() or _glibc_version_string_ctypes() + + +def _parse_glibc_version(version_str: str) -> Tuple[int, int]: + """Parse glibc version. + + We use a regexp instead of str.split because we want to discard any + random junk that might come after the minor version -- this might happen + in patched/forked versions of glibc (e.g. Linaro's version of glibc + uses version strings like "2.20-2014.11"). See gh-3588. + """ + m = re.match(r"(?P[0-9]+)\.(?P[0-9]+)", version_str) + if not m: + warnings.warn( + "Expected glibc version with 2 components major.minor," + " got: %s" % version_str, + RuntimeWarning, + ) + return -1, -1 + return int(m.group("major")), int(m.group("minor")) + + +@functools.lru_cache() +def _get_glibc_version() -> Tuple[int, int]: + version_str = _glibc_version_string() + if version_str is None: + return (-1, -1) + return _parse_glibc_version(version_str) + + +# From PEP 513, PEP 600 +def _is_compatible(name: str, arch: str, version: _GLibCVersion) -> bool: + sys_glibc = _get_glibc_version() + if sys_glibc < version: + return False + # Check for presence of _manylinux module. + try: + import _manylinux # noqa + except ImportError: + return True + if hasattr(_manylinux, "manylinux_compatible"): + result = _manylinux.manylinux_compatible(version[0], version[1], arch) + if result is not None: + return bool(result) + return True + if version == _GLibCVersion(2, 5): + if hasattr(_manylinux, "manylinux1_compatible"): + return bool(_manylinux.manylinux1_compatible) + if version == _GLibCVersion(2, 12): + if hasattr(_manylinux, "manylinux2010_compatible"): + return bool(_manylinux.manylinux2010_compatible) + if version == _GLibCVersion(2, 17): + if hasattr(_manylinux, "manylinux2014_compatible"): + return bool(_manylinux.manylinux2014_compatible) + return True + + +_LEGACY_MANYLINUX_MAP = { + # CentOS 7 w/ glibc 2.17 (PEP 599) + (2, 17): "manylinux2014", + # CentOS 6 w/ glibc 2.12 (PEP 571) + (2, 12): "manylinux2010", + # CentOS 5 w/ glibc 2.5 (PEP 513) + (2, 5): "manylinux1", +} + + +def platform_tags(linux: str, arch: str) -> Iterator[str]: + if not _have_compatible_abi(arch): + return + # Oldest glibc to be supported regardless of architecture is (2, 17). + too_old_glibc2 = _GLibCVersion(2, 16) + if arch in {"x86_64", "i686"}: + # On x86/i686 also oldest glibc to be supported is (2, 5). + too_old_glibc2 = _GLibCVersion(2, 4) + current_glibc = _GLibCVersion(*_get_glibc_version()) + glibc_max_list = [current_glibc] + # We can assume compatibility across glibc major versions. + # https://sourceware.org/bugzilla/show_bug.cgi?id=24636 + # + # Build a list of maximum glibc versions so that we can + # output the canonical list of all glibc from current_glibc + # down to too_old_glibc2, including all intermediary versions. + for glibc_major in range(current_glibc.major - 1, 1, -1): + glibc_minor = _LAST_GLIBC_MINOR[glibc_major] + glibc_max_list.append(_GLibCVersion(glibc_major, glibc_minor)) + for glibc_max in glibc_max_list: + if glibc_max.major == too_old_glibc2.major: + min_minor = too_old_glibc2.minor + else: + # For other glibc major versions oldest supported is (x, 0). + min_minor = -1 + for glibc_minor in range(glibc_max.minor, min_minor, -1): + glibc_version = _GLibCVersion(glibc_max.major, glibc_minor) + tag = "manylinux_{}_{}".format(*glibc_version) + if _is_compatible(tag, arch, glibc_version): + yield linux.replace("linux", tag) + # Handle the legacy manylinux1, manylinux2010, manylinux2014 tags. + if glibc_version in _LEGACY_MANYLINUX_MAP: + legacy_tag = _LEGACY_MANYLINUX_MAP[glibc_version] + if _is_compatible(legacy_tag, arch, glibc_version): + yield linux.replace("linux", legacy_tag) diff --git a/venv/Lib/site-packages/pkg_resources/_vendor/packaging/_musllinux.py b/venv/Lib/site-packages/pkg_resources/_vendor/packaging/_musllinux.py new file mode 100644 index 0000000..8ac3059 --- /dev/null +++ b/venv/Lib/site-packages/pkg_resources/_vendor/packaging/_musllinux.py @@ -0,0 +1,136 @@ +"""PEP 656 support. + +This module implements logic to detect if the currently running Python is +linked against musl, and what musl version is used. +""" + +import contextlib +import functools +import operator +import os +import re +import struct +import subprocess +import sys +from typing import IO, Iterator, NamedTuple, Optional, Tuple + + +def _read_unpacked(f: IO[bytes], fmt: str) -> Tuple[int, ...]: + return struct.unpack(fmt, f.read(struct.calcsize(fmt))) + + +def _parse_ld_musl_from_elf(f: IO[bytes]) -> Optional[str]: + """Detect musl libc location by parsing the Python executable. + + Based on: https://gist.github.com/lyssdod/f51579ae8d93c8657a5564aefc2ffbca + ELF header: https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html + """ + f.seek(0) + try: + ident = _read_unpacked(f, "16B") + except struct.error: + return None + if ident[:4] != tuple(b"\x7fELF"): # Invalid magic, not ELF. + return None + f.seek(struct.calcsize("HHI"), 1) # Skip file type, machine, and version. + + try: + # e_fmt: Format for program header. + # p_fmt: Format for section header. + # p_idx: Indexes to find p_type, p_offset, and p_filesz. + e_fmt, p_fmt, p_idx = { + 1: ("IIIIHHH", "IIIIIIII", (0, 1, 4)), # 32-bit. + 2: ("QQQIHHH", "IIQQQQQQ", (0, 2, 5)), # 64-bit. + }[ident[4]] + except KeyError: + return None + else: + p_get = operator.itemgetter(*p_idx) + + # Find the interpreter section and return its content. + try: + _, e_phoff, _, _, _, e_phentsize, e_phnum = _read_unpacked(f, e_fmt) + except struct.error: + return None + for i in range(e_phnum + 1): + f.seek(e_phoff + e_phentsize * i) + try: + p_type, p_offset, p_filesz = p_get(_read_unpacked(f, p_fmt)) + except struct.error: + return None + if p_type != 3: # Not PT_INTERP. + continue + f.seek(p_offset) + interpreter = os.fsdecode(f.read(p_filesz)).strip("\0") + if "musl" not in interpreter: + return None + return interpreter + return None + + +class _MuslVersion(NamedTuple): + major: int + minor: int + + +def _parse_musl_version(output: str) -> Optional[_MuslVersion]: + lines = [n for n in (n.strip() for n in output.splitlines()) if n] + if len(lines) < 2 or lines[0][:4] != "musl": + return None + m = re.match(r"Version (\d+)\.(\d+)", lines[1]) + if not m: + return None + return _MuslVersion(major=int(m.group(1)), minor=int(m.group(2))) + + +@functools.lru_cache() +def _get_musl_version(executable: str) -> Optional[_MuslVersion]: + """Detect currently-running musl runtime version. + + This is done by checking the specified executable's dynamic linking + information, and invoking the loader to parse its output for a version + string. If the loader is musl, the output would be something like:: + + musl libc (x86_64) + Version 1.2.2 + Dynamic Program Loader + """ + with contextlib.ExitStack() as stack: + try: + f = stack.enter_context(open(executable, "rb")) + except OSError: + return None + ld = _parse_ld_musl_from_elf(f) + if not ld: + return None + proc = subprocess.run([ld], stderr=subprocess.PIPE, universal_newlines=True) + return _parse_musl_version(proc.stderr) + + +def platform_tags(arch: str) -> Iterator[str]: + """Generate musllinux tags compatible to the current platform. + + :param arch: Should be the part of platform tag after the ``linux_`` + prefix, e.g. ``x86_64``. The ``linux_`` prefix is assumed as a + prerequisite for the current platform to be musllinux-compatible. + + :returns: An iterator of compatible musllinux tags. + """ + sys_musl = _get_musl_version(sys.executable) + if sys_musl is None: # Python not dynamically linked against musl. + return + for minor in range(sys_musl.minor, -1, -1): + yield f"musllinux_{sys_musl.major}_{minor}_{arch}" + + +if __name__ == "__main__": # pragma: no cover + import sysconfig + + plat = sysconfig.get_platform() + assert plat.startswith("linux-"), "not linux" + + print("plat:", plat) + print("musl:", _get_musl_version(sys.executable)) + print("tags:", end=" ") + for t in platform_tags(re.sub(r"[.-]", "_", plat.split("-", 1)[-1])): + print(t, end="\n ") diff --git a/venv/Lib/site-packages/pkg_resources/_vendor/typing_extensions.py b/venv/Lib/site-packages/pkg_resources/_vendor/typing_extensions.py new file mode 100644 index 0000000..ef42417 --- /dev/null +++ b/venv/Lib/site-packages/pkg_resources/_vendor/typing_extensions.py @@ -0,0 +1,2209 @@ +import abc +import collections +import collections.abc +import functools +import operator +import sys +import types as _types +import typing + + +__all__ = [ + # Super-special typing primitives. + 'Any', + 'ClassVar', + 'Concatenate', + 'Final', + 'LiteralString', + 'ParamSpec', + 'ParamSpecArgs', + 'ParamSpecKwargs', + 'Self', + 'Type', + 'TypeVar', + 'TypeVarTuple', + 'Unpack', + + # ABCs (from collections.abc). + 'Awaitable', + 'AsyncIterator', + 'AsyncIterable', + 'Coroutine', + 'AsyncGenerator', + 'AsyncContextManager', + 'ChainMap', + + # Concrete collection types. + 'ContextManager', + 'Counter', + 'Deque', + 'DefaultDict', + 'NamedTuple', + 'OrderedDict', + 'TypedDict', + + # Structural checks, a.k.a. protocols. + 'SupportsIndex', + + # One-off things. + 'Annotated', + 'assert_never', + 'assert_type', + 'clear_overloads', + 'dataclass_transform', + 'get_overloads', + 'final', + 'get_args', + 'get_origin', + 'get_type_hints', + 'IntVar', + 'is_typeddict', + 'Literal', + 'NewType', + 'overload', + 'override', + 'Protocol', + 'reveal_type', + 'runtime', + 'runtime_checkable', + 'Text', + 'TypeAlias', + 'TypeGuard', + 'TYPE_CHECKING', + 'Never', + 'NoReturn', + 'Required', + 'NotRequired', +] + +# for backward compatibility +PEP_560 = True +GenericMeta = type + +# The functions below are modified copies of typing internal helpers. +# They are needed by _ProtocolMeta and they provide support for PEP 646. + +_marker = object() + + +def _check_generic(cls, parameters, elen=_marker): + """Check correct count for parameters of a generic cls (internal helper). + This gives a nice error message in case of count mismatch. + """ + if not elen: + raise TypeError(f"{cls} is not a generic class") + if elen is _marker: + if not hasattr(cls, "__parameters__") or not cls.__parameters__: + raise TypeError(f"{cls} is not a generic class") + elen = len(cls.__parameters__) + alen = len(parameters) + if alen != elen: + if hasattr(cls, "__parameters__"): + parameters = [p for p in cls.__parameters__ if not _is_unpack(p)] + num_tv_tuples = sum(isinstance(p, TypeVarTuple) for p in parameters) + if (num_tv_tuples > 0) and (alen >= elen - num_tv_tuples): + return + raise TypeError(f"Too {'many' if alen > elen else 'few'} parameters for {cls};" + f" actual {alen}, expected {elen}") + + +if sys.version_info >= (3, 10): + def _should_collect_from_parameters(t): + return isinstance( + t, (typing._GenericAlias, _types.GenericAlias, _types.UnionType) + ) +elif sys.version_info >= (3, 9): + def _should_collect_from_parameters(t): + return isinstance(t, (typing._GenericAlias, _types.GenericAlias)) +else: + def _should_collect_from_parameters(t): + return isinstance(t, typing._GenericAlias) and not t._special + + +def _collect_type_vars(types, typevar_types=None): + """Collect all type variable contained in types in order of + first appearance (lexicographic order). For example:: + + _collect_type_vars((T, List[S, T])) == (T, S) + """ + if typevar_types is None: + typevar_types = typing.TypeVar + tvars = [] + for t in types: + if ( + isinstance(t, typevar_types) and + t not in tvars and + not _is_unpack(t) + ): + tvars.append(t) + if _should_collect_from_parameters(t): + tvars.extend([t for t in t.__parameters__ if t not in tvars]) + return tuple(tvars) + + +NoReturn = typing.NoReturn + +# Some unconstrained type variables. These are used by the container types. +# (These are not for export.) +T = typing.TypeVar('T') # Any type. +KT = typing.TypeVar('KT') # Key type. +VT = typing.TypeVar('VT') # Value type. +T_co = typing.TypeVar('T_co', covariant=True) # Any type covariant containers. +T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant. + + +if sys.version_info >= (3, 11): + from typing import Any +else: + + class _AnyMeta(type): + def __instancecheck__(self, obj): + if self is Any: + raise TypeError("typing_extensions.Any cannot be used with isinstance()") + return super().__instancecheck__(obj) + + def __repr__(self): + if self is Any: + return "typing_extensions.Any" + return super().__repr__() + + class Any(metaclass=_AnyMeta): + """Special type indicating an unconstrained type. + - Any is compatible with every type. + - Any assumed to have all methods. + - All values assumed to be instances of Any. + Note that all the above statements are true from the point of view of + static type checkers. At runtime, Any should not be used with instance + checks. + """ + def __new__(cls, *args, **kwargs): + if cls is Any: + raise TypeError("Any cannot be instantiated") + return super().__new__(cls, *args, **kwargs) + + +ClassVar = typing.ClassVar + +# On older versions of typing there is an internal class named "Final". +# 3.8+ +if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7): + Final = typing.Final +# 3.7 +else: + class _FinalForm(typing._SpecialForm, _root=True): + + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + Final = _FinalForm('Final', + doc="""A special typing construct to indicate that a name + cannot be re-assigned or overridden in a subclass. + For example: + + MAX_SIZE: Final = 9000 + MAX_SIZE += 1 # Error reported by type checker + + class Connection: + TIMEOUT: Final[int] = 10 + class FastConnector(Connection): + TIMEOUT = 1 # Error reported by type checker + + There is no runtime checking of these properties.""") + +if sys.version_info >= (3, 11): + final = typing.final +else: + # @final exists in 3.8+, but we backport it for all versions + # before 3.11 to keep support for the __final__ attribute. + # See https://bugs.python.org/issue46342 + def final(f): + """This decorator can be used to indicate to type checkers that + the decorated method cannot be overridden, and decorated class + cannot be subclassed. For example: + + class Base: + @final + def done(self) -> None: + ... + class Sub(Base): + def done(self) -> None: # Error reported by type checker + ... + @final + class Leaf: + ... + class Other(Leaf): # Error reported by type checker + ... + + There is no runtime checking of these properties. The decorator + sets the ``__final__`` attribute to ``True`` on the decorated object + to allow runtime introspection. + """ + try: + f.__final__ = True + except (AttributeError, TypeError): + # Skip the attribute silently if it is not writable. + # AttributeError happens if the object has __slots__ or a + # read-only property, TypeError if it's a builtin class. + pass + return f + + +def IntVar(name): + return typing.TypeVar(name) + + +# 3.8+: +if hasattr(typing, 'Literal'): + Literal = typing.Literal +# 3.7: +else: + class _LiteralForm(typing._SpecialForm, _root=True): + + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + return typing._GenericAlias(self, parameters) + + Literal = _LiteralForm('Literal', + doc="""A type that can be used to indicate to type checkers + that the corresponding value has a value literally equivalent + to the provided parameter. For example: + + var: Literal[4] = 4 + + The type checker understands that 'var' is literally equal to + the value 4 and no other value. + + Literal[...] cannot be subclassed. There is no runtime + checking verifying that the parameter is actually a value + instead of a type.""") + + +_overload_dummy = typing._overload_dummy # noqa + + +if hasattr(typing, "get_overloads"): # 3.11+ + overload = typing.overload + get_overloads = typing.get_overloads + clear_overloads = typing.clear_overloads +else: + # {module: {qualname: {firstlineno: func}}} + _overload_registry = collections.defaultdict( + functools.partial(collections.defaultdict, dict) + ) + + def overload(func): + """Decorator for overloaded functions/methods. + + In a stub file, place two or more stub definitions for the same + function in a row, each decorated with @overload. For example: + + @overload + def utf8(value: None) -> None: ... + @overload + def utf8(value: bytes) -> bytes: ... + @overload + def utf8(value: str) -> bytes: ... + + In a non-stub file (i.e. a regular .py file), do the same but + follow it with an implementation. The implementation should *not* + be decorated with @overload. For example: + + @overload + def utf8(value: None) -> None: ... + @overload + def utf8(value: bytes) -> bytes: ... + @overload + def utf8(value: str) -> bytes: ... + def utf8(value): + # implementation goes here + + The overloads for a function can be retrieved at runtime using the + get_overloads() function. + """ + # classmethod and staticmethod + f = getattr(func, "__func__", func) + try: + _overload_registry[f.__module__][f.__qualname__][ + f.__code__.co_firstlineno + ] = func + except AttributeError: + # Not a normal function; ignore. + pass + return _overload_dummy + + def get_overloads(func): + """Return all defined overloads for *func* as a sequence.""" + # classmethod and staticmethod + f = getattr(func, "__func__", func) + if f.__module__ not in _overload_registry: + return [] + mod_dict = _overload_registry[f.__module__] + if f.__qualname__ not in mod_dict: + return [] + return list(mod_dict[f.__qualname__].values()) + + def clear_overloads(): + """Clear all overloads in the registry.""" + _overload_registry.clear() + + +# This is not a real generic class. Don't use outside annotations. +Type = typing.Type + +# Various ABCs mimicking those in collections.abc. +# A few are simply re-exported for completeness. + + +Awaitable = typing.Awaitable +Coroutine = typing.Coroutine +AsyncIterable = typing.AsyncIterable +AsyncIterator = typing.AsyncIterator +Deque = typing.Deque +ContextManager = typing.ContextManager +AsyncContextManager = typing.AsyncContextManager +DefaultDict = typing.DefaultDict + +# 3.7.2+ +if hasattr(typing, 'OrderedDict'): + OrderedDict = typing.OrderedDict +# 3.7.0-3.7.2 +else: + OrderedDict = typing._alias(collections.OrderedDict, (KT, VT)) + +Counter = typing.Counter +ChainMap = typing.ChainMap +AsyncGenerator = typing.AsyncGenerator +NewType = typing.NewType +Text = typing.Text +TYPE_CHECKING = typing.TYPE_CHECKING + + +_PROTO_WHITELIST = ['Callable', 'Awaitable', + 'Iterable', 'Iterator', 'AsyncIterable', 'AsyncIterator', + 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', + 'ContextManager', 'AsyncContextManager'] + + +def _get_protocol_attrs(cls): + attrs = set() + for base in cls.__mro__[:-1]: # without object + if base.__name__ in ('Protocol', 'Generic'): + continue + annotations = getattr(base, '__annotations__', {}) + for attr in list(base.__dict__.keys()) + list(annotations.keys()): + if (not attr.startswith('_abc_') and attr not in ( + '__abstractmethods__', '__annotations__', '__weakref__', + '_is_protocol', '_is_runtime_protocol', '__dict__', + '__args__', '__slots__', + '__next_in_mro__', '__parameters__', '__origin__', + '__orig_bases__', '__extra__', '__tree_hash__', + '__doc__', '__subclasshook__', '__init__', '__new__', + '__module__', '_MutableMapping__marker', '_gorg')): + attrs.add(attr) + return attrs + + +def _is_callable_members_only(cls): + return all(callable(getattr(cls, attr, None)) for attr in _get_protocol_attrs(cls)) + + +def _maybe_adjust_parameters(cls): + """Helper function used in Protocol.__init_subclass__ and _TypedDictMeta.__new__. + + The contents of this function are very similar + to logic found in typing.Generic.__init_subclass__ + on the CPython main branch. + """ + tvars = [] + if '__orig_bases__' in cls.__dict__: + tvars = typing._collect_type_vars(cls.__orig_bases__) + # Look for Generic[T1, ..., Tn] or Protocol[T1, ..., Tn]. + # If found, tvars must be a subset of it. + # If not found, tvars is it. + # Also check for and reject plain Generic, + # and reject multiple Generic[...] and/or Protocol[...]. + gvars = None + for base in cls.__orig_bases__: + if (isinstance(base, typing._GenericAlias) and + base.__origin__ in (typing.Generic, Protocol)): + # for error messages + the_base = base.__origin__.__name__ + if gvars is not None: + raise TypeError( + "Cannot inherit from Generic[...]" + " and/or Protocol[...] multiple types.") + gvars = base.__parameters__ + if gvars is None: + gvars = tvars + else: + tvarset = set(tvars) + gvarset = set(gvars) + if not tvarset <= gvarset: + s_vars = ', '.join(str(t) for t in tvars if t not in gvarset) + s_args = ', '.join(str(g) for g in gvars) + raise TypeError(f"Some type variables ({s_vars}) are" + f" not listed in {the_base}[{s_args}]") + tvars = gvars + cls.__parameters__ = tuple(tvars) + + +# 3.8+ +if hasattr(typing, 'Protocol'): + Protocol = typing.Protocol +# 3.7 +else: + + def _no_init(self, *args, **kwargs): + if type(self)._is_protocol: + raise TypeError('Protocols cannot be instantiated') + + class _ProtocolMeta(abc.ABCMeta): # noqa: B024 + # This metaclass is a bit unfortunate and exists only because of the lack + # of __instancehook__. + def __instancecheck__(cls, instance): + # We need this method for situations where attributes are + # assigned in __init__. + if ((not getattr(cls, '_is_protocol', False) or + _is_callable_members_only(cls)) and + issubclass(instance.__class__, cls)): + return True + if cls._is_protocol: + if all(hasattr(instance, attr) and + (not callable(getattr(cls, attr, None)) or + getattr(instance, attr) is not None) + for attr in _get_protocol_attrs(cls)): + return True + return super().__instancecheck__(instance) + + class Protocol(metaclass=_ProtocolMeta): + # There is quite a lot of overlapping code with typing.Generic. + # Unfortunately it is hard to avoid this while these live in two different + # modules. The duplicated code will be removed when Protocol is moved to typing. + """Base class for protocol classes. Protocol classes are defined as:: + + class Proto(Protocol): + def meth(self) -> int: + ... + + Such classes are primarily used with static type checkers that recognize + structural subtyping (static duck-typing), for example:: + + class C: + def meth(self) -> int: + return 0 + + def func(x: Proto) -> int: + return x.meth() + + func(C()) # Passes static type check + + See PEP 544 for details. Protocol classes decorated with + @typing_extensions.runtime act as simple-minded runtime protocol that checks + only the presence of given attributes, ignoring their type signatures. + + Protocol classes can be generic, they are defined as:: + + class GenProto(Protocol[T]): + def meth(self) -> T: + ... + """ + __slots__ = () + _is_protocol = True + + def __new__(cls, *args, **kwds): + if cls is Protocol: + raise TypeError("Type Protocol cannot be instantiated; " + "it can only be used as a base class") + return super().__new__(cls) + + @typing._tp_cache + def __class_getitem__(cls, params): + if not isinstance(params, tuple): + params = (params,) + if not params and cls is not typing.Tuple: + raise TypeError( + f"Parameter list to {cls.__qualname__}[...] cannot be empty") + msg = "Parameters to generic types must be types." + params = tuple(typing._type_check(p, msg) for p in params) # noqa + if cls is Protocol: + # Generic can only be subscripted with unique type variables. + if not all(isinstance(p, typing.TypeVar) for p in params): + i = 0 + while isinstance(params[i], typing.TypeVar): + i += 1 + raise TypeError( + "Parameters to Protocol[...] must all be type variables." + f" Parameter {i + 1} is {params[i]}") + if len(set(params)) != len(params): + raise TypeError( + "Parameters to Protocol[...] must all be unique") + else: + # Subscripting a regular Generic subclass. + _check_generic(cls, params, len(cls.__parameters__)) + return typing._GenericAlias(cls, params) + + def __init_subclass__(cls, *args, **kwargs): + if '__orig_bases__' in cls.__dict__: + error = typing.Generic in cls.__orig_bases__ + else: + error = typing.Generic in cls.__bases__ + if error: + raise TypeError("Cannot inherit from plain Generic") + _maybe_adjust_parameters(cls) + + # Determine if this is a protocol or a concrete subclass. + if not cls.__dict__.get('_is_protocol', None): + cls._is_protocol = any(b is Protocol for b in cls.__bases__) + + # Set (or override) the protocol subclass hook. + def _proto_hook(other): + if not cls.__dict__.get('_is_protocol', None): + return NotImplemented + if not getattr(cls, '_is_runtime_protocol', False): + if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']: + return NotImplemented + raise TypeError("Instance and class checks can only be used with" + " @runtime protocols") + if not _is_callable_members_only(cls): + if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']: + return NotImplemented + raise TypeError("Protocols with non-method members" + " don't support issubclass()") + if not isinstance(other, type): + # Same error as for issubclass(1, int) + raise TypeError('issubclass() arg 1 must be a class') + for attr in _get_protocol_attrs(cls): + for base in other.__mro__: + if attr in base.__dict__: + if base.__dict__[attr] is None: + return NotImplemented + break + annotations = getattr(base, '__annotations__', {}) + if (isinstance(annotations, typing.Mapping) and + attr in annotations and + isinstance(other, _ProtocolMeta) and + other._is_protocol): + break + else: + return NotImplemented + return True + if '__subclasshook__' not in cls.__dict__: + cls.__subclasshook__ = _proto_hook + + # We have nothing more to do for non-protocols. + if not cls._is_protocol: + return + + # Check consistency of bases. + for base in cls.__bases__: + if not (base in (object, typing.Generic) or + base.__module__ == 'collections.abc' and + base.__name__ in _PROTO_WHITELIST or + isinstance(base, _ProtocolMeta) and base._is_protocol): + raise TypeError('Protocols can only inherit from other' + f' protocols, got {repr(base)}') + cls.__init__ = _no_init + + +# 3.8+ +if hasattr(typing, 'runtime_checkable'): + runtime_checkable = typing.runtime_checkable +# 3.7 +else: + def runtime_checkable(cls): + """Mark a protocol class as a runtime protocol, so that it + can be used with isinstance() and issubclass(). Raise TypeError + if applied to a non-protocol class. + + This allows a simple-minded structural check very similar to the + one-offs in collections.abc such as Hashable. + """ + if not isinstance(cls, _ProtocolMeta) or not cls._is_protocol: + raise TypeError('@runtime_checkable can be only applied to protocol classes,' + f' got {cls!r}') + cls._is_runtime_protocol = True + return cls + + +# Exists for backwards compatibility. +runtime = runtime_checkable + + +# 3.8+ +if hasattr(typing, 'SupportsIndex'): + SupportsIndex = typing.SupportsIndex +# 3.7 +else: + @runtime_checkable + class SupportsIndex(Protocol): + __slots__ = () + + @abc.abstractmethod + def __index__(self) -> int: + pass + + +if hasattr(typing, "Required"): + # The standard library TypedDict in Python 3.8 does not store runtime information + # about which (if any) keys are optional. See https://bugs.python.org/issue38834 + # The standard library TypedDict in Python 3.9.0/1 does not honour the "total" + # keyword with old-style TypedDict(). See https://bugs.python.org/issue42059 + # The standard library TypedDict below Python 3.11 does not store runtime + # information about optional and required keys when using Required or NotRequired. + # Generic TypedDicts are also impossible using typing.TypedDict on Python <3.11. + TypedDict = typing.TypedDict + _TypedDictMeta = typing._TypedDictMeta + is_typeddict = typing.is_typeddict +else: + def _check_fails(cls, other): + try: + if sys._getframe(1).f_globals['__name__'] not in ['abc', + 'functools', + 'typing']: + # Typed dicts are only for static structural subtyping. + raise TypeError('TypedDict does not support instance and class checks') + except (AttributeError, ValueError): + pass + return False + + def _dict_new(*args, **kwargs): + if not args: + raise TypeError('TypedDict.__new__(): not enough arguments') + _, args = args[0], args[1:] # allow the "cls" keyword be passed + return dict(*args, **kwargs) + + _dict_new.__text_signature__ = '($cls, _typename, _fields=None, /, **kwargs)' + + def _typeddict_new(*args, total=True, **kwargs): + if not args: + raise TypeError('TypedDict.__new__(): not enough arguments') + _, args = args[0], args[1:] # allow the "cls" keyword be passed + if args: + typename, args = args[0], args[1:] # allow the "_typename" keyword be passed + elif '_typename' in kwargs: + typename = kwargs.pop('_typename') + import warnings + warnings.warn("Passing '_typename' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + raise TypeError("TypedDict.__new__() missing 1 required positional " + "argument: '_typename'") + if args: + try: + fields, = args # allow the "_fields" keyword be passed + except ValueError: + raise TypeError('TypedDict.__new__() takes from 2 to 3 ' + f'positional arguments but {len(args) + 2} ' + 'were given') + elif '_fields' in kwargs and len(kwargs) == 1: + fields = kwargs.pop('_fields') + import warnings + warnings.warn("Passing '_fields' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + fields = None + + if fields is None: + fields = kwargs + elif kwargs: + raise TypeError("TypedDict takes either a dict or keyword arguments," + " but not both") + + ns = {'__annotations__': dict(fields)} + try: + # Setting correct module is necessary to make typed dict classes pickleable. + ns['__module__'] = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + pass + + return _TypedDictMeta(typename, (), ns, total=total) + + _typeddict_new.__text_signature__ = ('($cls, _typename, _fields=None,' + ' /, *, total=True, **kwargs)') + + class _TypedDictMeta(type): + def __init__(cls, name, bases, ns, total=True): + super().__init__(name, bases, ns) + + def __new__(cls, name, bases, ns, total=True): + # Create new typed dict class object. + # This method is called directly when TypedDict is subclassed, + # or via _typeddict_new when TypedDict is instantiated. This way + # TypedDict supports all three syntaxes described in its docstring. + # Subclasses and instances of TypedDict return actual dictionaries + # via _dict_new. + ns['__new__'] = _typeddict_new if name == 'TypedDict' else _dict_new + # Don't insert typing.Generic into __bases__ here, + # or Generic.__init_subclass__ will raise TypeError + # in the super().__new__() call. + # Instead, monkey-patch __bases__ onto the class after it's been created. + tp_dict = super().__new__(cls, name, (dict,), ns) + + if any(issubclass(base, typing.Generic) for base in bases): + tp_dict.__bases__ = (typing.Generic, dict) + _maybe_adjust_parameters(tp_dict) + + annotations = {} + own_annotations = ns.get('__annotations__', {}) + msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" + own_annotations = { + n: typing._type_check(tp, msg) for n, tp in own_annotations.items() + } + required_keys = set() + optional_keys = set() + + for base in bases: + annotations.update(base.__dict__.get('__annotations__', {})) + required_keys.update(base.__dict__.get('__required_keys__', ())) + optional_keys.update(base.__dict__.get('__optional_keys__', ())) + + annotations.update(own_annotations) + for annotation_key, annotation_type in own_annotations.items(): + annotation_origin = get_origin(annotation_type) + if annotation_origin is Annotated: + annotation_args = get_args(annotation_type) + if annotation_args: + annotation_type = annotation_args[0] + annotation_origin = get_origin(annotation_type) + + if annotation_origin is Required: + required_keys.add(annotation_key) + elif annotation_origin is NotRequired: + optional_keys.add(annotation_key) + elif total: + required_keys.add(annotation_key) + else: + optional_keys.add(annotation_key) + + tp_dict.__annotations__ = annotations + tp_dict.__required_keys__ = frozenset(required_keys) + tp_dict.__optional_keys__ = frozenset(optional_keys) + if not hasattr(tp_dict, '__total__'): + tp_dict.__total__ = total + return tp_dict + + __instancecheck__ = __subclasscheck__ = _check_fails + + TypedDict = _TypedDictMeta('TypedDict', (dict,), {}) + TypedDict.__module__ = __name__ + TypedDict.__doc__ = \ + """A simple typed name space. At runtime it is equivalent to a plain dict. + + TypedDict creates a dictionary type that expects all of its + instances to have a certain set of keys, with each key + associated with a value of a consistent type. This expectation + is not checked at runtime but is only enforced by type checkers. + Usage:: + + class Point2D(TypedDict): + x: int + y: int + label: str + + a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK + b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check + + assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first') + + The type info can be accessed via the Point2D.__annotations__ dict, and + the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets. + TypedDict supports two additional equivalent forms:: + + Point2D = TypedDict('Point2D', x=int, y=int, label=str) + Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str}) + + The class syntax is only supported in Python 3.6+, while two other + syntax forms work for Python 2.7 and 3.2+ + """ + + if hasattr(typing, "_TypedDictMeta"): + _TYPEDDICT_TYPES = (typing._TypedDictMeta, _TypedDictMeta) + else: + _TYPEDDICT_TYPES = (_TypedDictMeta,) + + def is_typeddict(tp): + """Check if an annotation is a TypedDict class + + For example:: + class Film(TypedDict): + title: str + year: int + + is_typeddict(Film) # => True + is_typeddict(Union[list, str]) # => False + """ + return isinstance(tp, tuple(_TYPEDDICT_TYPES)) + + +if hasattr(typing, "assert_type"): + assert_type = typing.assert_type + +else: + def assert_type(__val, __typ): + """Assert (to the type checker) that the value is of the given type. + + When the type checker encounters a call to assert_type(), it + emits an error if the value is not of the specified type:: + + def greet(name: str) -> None: + assert_type(name, str) # ok + assert_type(name, int) # type checker error + + At runtime this returns the first argument unchanged and otherwise + does nothing. + """ + return __val + + +if hasattr(typing, "Required"): + get_type_hints = typing.get_type_hints +else: + import functools + import types + + # replaces _strip_annotations() + def _strip_extras(t): + """Strips Annotated, Required and NotRequired from a given type.""" + if isinstance(t, _AnnotatedAlias): + return _strip_extras(t.__origin__) + if hasattr(t, "__origin__") and t.__origin__ in (Required, NotRequired): + return _strip_extras(t.__args__[0]) + if isinstance(t, typing._GenericAlias): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return t.copy_with(stripped_args) + if hasattr(types, "GenericAlias") and isinstance(t, types.GenericAlias): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return types.GenericAlias(t.__origin__, stripped_args) + if hasattr(types, "UnionType") and isinstance(t, types.UnionType): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return functools.reduce(operator.or_, stripped_args) + + return t + + def get_type_hints(obj, globalns=None, localns=None, include_extras=False): + """Return type hints for an object. + + This is often the same as obj.__annotations__, but it handles + forward references encoded as string literals, adds Optional[t] if a + default value equal to None is set and recursively replaces all + 'Annotated[T, ...]', 'Required[T]' or 'NotRequired[T]' with 'T' + (unless 'include_extras=True'). + + The argument may be a module, class, method, or function. The annotations + are returned as a dictionary. For classes, annotations include also + inherited members. + + TypeError is raised if the argument is not of a type that can contain + annotations, and an empty dictionary is returned if no annotations are + present. + + BEWARE -- the behavior of globalns and localns is counterintuitive + (unless you are familiar with how eval() and exec() work). The + search order is locals first, then globals. + + - If no dict arguments are passed, an attempt is made to use the + globals from obj (or the respective module's globals for classes), + and these are also used as the locals. If the object does not appear + to have globals, an empty dictionary is used. + + - If one dict argument is passed, it is used for both globals and + locals. + + - If two dict arguments are passed, they specify globals and + locals, respectively. + """ + if hasattr(typing, "Annotated"): + hint = typing.get_type_hints( + obj, globalns=globalns, localns=localns, include_extras=True + ) + else: + hint = typing.get_type_hints(obj, globalns=globalns, localns=localns) + if include_extras: + return hint + return {k: _strip_extras(t) for k, t in hint.items()} + + +# Python 3.9+ has PEP 593 (Annotated) +if hasattr(typing, 'Annotated'): + Annotated = typing.Annotated + # Not exported and not a public API, but needed for get_origin() and get_args() + # to work. + _AnnotatedAlias = typing._AnnotatedAlias +# 3.7-3.8 +else: + class _AnnotatedAlias(typing._GenericAlias, _root=True): + """Runtime representation of an annotated type. + + At its core 'Annotated[t, dec1, dec2, ...]' is an alias for the type 't' + with extra annotations. The alias behaves like a normal typing alias, + instantiating is the same as instantiating the underlying type, binding + it to types is also the same. + """ + def __init__(self, origin, metadata): + if isinstance(origin, _AnnotatedAlias): + metadata = origin.__metadata__ + metadata + origin = origin.__origin__ + super().__init__(origin, origin) + self.__metadata__ = metadata + + def copy_with(self, params): + assert len(params) == 1 + new_type = params[0] + return _AnnotatedAlias(new_type, self.__metadata__) + + def __repr__(self): + return (f"typing_extensions.Annotated[{typing._type_repr(self.__origin__)}, " + f"{', '.join(repr(a) for a in self.__metadata__)}]") + + def __reduce__(self): + return operator.getitem, ( + Annotated, (self.__origin__,) + self.__metadata__ + ) + + def __eq__(self, other): + if not isinstance(other, _AnnotatedAlias): + return NotImplemented + if self.__origin__ != other.__origin__: + return False + return self.__metadata__ == other.__metadata__ + + def __hash__(self): + return hash((self.__origin__, self.__metadata__)) + + class Annotated: + """Add context specific metadata to a type. + + Example: Annotated[int, runtime_check.Unsigned] indicates to the + hypothetical runtime_check module that this type is an unsigned int. + Every other consumer of this type can ignore this metadata and treat + this type as int. + + The first argument to Annotated must be a valid type (and will be in + the __origin__ field), the remaining arguments are kept as a tuple in + the __extra__ field. + + Details: + + - It's an error to call `Annotated` with less than two arguments. + - Nested Annotated are flattened:: + + Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] + + - Instantiating an annotated type is equivalent to instantiating the + underlying type:: + + Annotated[C, Ann1](5) == C(5) + + - Annotated can be used as a generic type alias:: + + Optimized = Annotated[T, runtime.Optimize()] + Optimized[int] == Annotated[int, runtime.Optimize()] + + OptimizedList = Annotated[List[T], runtime.Optimize()] + OptimizedList[int] == Annotated[List[int], runtime.Optimize()] + """ + + __slots__ = () + + def __new__(cls, *args, **kwargs): + raise TypeError("Type Annotated cannot be instantiated.") + + @typing._tp_cache + def __class_getitem__(cls, params): + if not isinstance(params, tuple) or len(params) < 2: + raise TypeError("Annotated[...] should be used " + "with at least two arguments (a type and an " + "annotation).") + allowed_special_forms = (ClassVar, Final) + if get_origin(params[0]) in allowed_special_forms: + origin = params[0] + else: + msg = "Annotated[t, ...]: t must be a type." + origin = typing._type_check(params[0], msg) + metadata = tuple(params[1:]) + return _AnnotatedAlias(origin, metadata) + + def __init_subclass__(cls, *args, **kwargs): + raise TypeError( + f"Cannot subclass {cls.__module__}.Annotated" + ) + +# Python 3.8 has get_origin() and get_args() but those implementations aren't +# Annotated-aware, so we can't use those. Python 3.9's versions don't support +# ParamSpecArgs and ParamSpecKwargs, so only Python 3.10's versions will do. +if sys.version_info[:2] >= (3, 10): + get_origin = typing.get_origin + get_args = typing.get_args +# 3.7-3.9 +else: + try: + # 3.9+ + from typing import _BaseGenericAlias + except ImportError: + _BaseGenericAlias = typing._GenericAlias + try: + # 3.9+ + from typing import GenericAlias as _typing_GenericAlias + except ImportError: + _typing_GenericAlias = typing._GenericAlias + + def get_origin(tp): + """Get the unsubscripted version of a type. + + This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar + and Annotated. Return None for unsupported types. Examples:: + + get_origin(Literal[42]) is Literal + get_origin(int) is None + get_origin(ClassVar[int]) is ClassVar + get_origin(Generic) is Generic + get_origin(Generic[T]) is Generic + get_origin(Union[T, int]) is Union + get_origin(List[Tuple[T, T]][int]) == list + get_origin(P.args) is P + """ + if isinstance(tp, _AnnotatedAlias): + return Annotated + if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias, _BaseGenericAlias, + ParamSpecArgs, ParamSpecKwargs)): + return tp.__origin__ + if tp is typing.Generic: + return typing.Generic + return None + + def get_args(tp): + """Get type arguments with all substitutions performed. + + For unions, basic simplifications used by Union constructor are performed. + Examples:: + get_args(Dict[str, int]) == (str, int) + get_args(int) == () + get_args(Union[int, Union[T, int], str][int]) == (int, str) + get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) + get_args(Callable[[], T][int]) == ([], int) + """ + if isinstance(tp, _AnnotatedAlias): + return (tp.__origin__,) + tp.__metadata__ + if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias)): + if getattr(tp, "_special", False): + return () + res = tp.__args__ + if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis: + res = (list(res[:-1]), res[-1]) + return res + return () + + +# 3.10+ +if hasattr(typing, 'TypeAlias'): + TypeAlias = typing.TypeAlias +# 3.9 +elif sys.version_info[:2] >= (3, 9): + class _TypeAliasForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + @_TypeAliasForm + def TypeAlias(self, parameters): + """Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example above. + """ + raise TypeError(f"{self} is not subscriptable") +# 3.7-3.8 +else: + class _TypeAliasForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + TypeAlias = _TypeAliasForm('TypeAlias', + doc="""Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example + above.""") + + +class _DefaultMixin: + """Mixin for TypeVarLike defaults.""" + + __slots__ = () + + def __init__(self, default): + if isinstance(default, (tuple, list)): + self.__default__ = tuple((typing._type_check(d, "Default must be a type") + for d in default)) + elif default: + self.__default__ = typing._type_check(default, "Default must be a type") + else: + self.__default__ = None + + +# Add default and infer_variance parameters from PEP 696 and 695 +class TypeVar(typing.TypeVar, _DefaultMixin, _root=True): + """Type variable.""" + + __module__ = 'typing' + + def __init__(self, name, *constraints, bound=None, + covariant=False, contravariant=False, + default=None, infer_variance=False): + super().__init__(name, *constraints, bound=bound, covariant=covariant, + contravariant=contravariant) + _DefaultMixin.__init__(self, default) + self.__infer_variance__ = infer_variance + + # for pickling: + try: + def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + def_mod = None + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + +# Python 3.10+ has PEP 612 +if hasattr(typing, 'ParamSpecArgs'): + ParamSpecArgs = typing.ParamSpecArgs + ParamSpecKwargs = typing.ParamSpecKwargs +# 3.7-3.9 +else: + class _Immutable: + """Mixin to indicate that object should not be copied.""" + __slots__ = () + + def __copy__(self): + return self + + def __deepcopy__(self, memo): + return self + + class ParamSpecArgs(_Immutable): + """The args for a ParamSpec object. + + Given a ParamSpec object P, P.args is an instance of ParamSpecArgs. + + ParamSpecArgs objects have a reference back to their ParamSpec: + + P.args.__origin__ is P + + This type is meant for runtime introspection and has no special meaning to + static type checkers. + """ + def __init__(self, origin): + self.__origin__ = origin + + def __repr__(self): + return f"{self.__origin__.__name__}.args" + + def __eq__(self, other): + if not isinstance(other, ParamSpecArgs): + return NotImplemented + return self.__origin__ == other.__origin__ + + class ParamSpecKwargs(_Immutable): + """The kwargs for a ParamSpec object. + + Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs. + + ParamSpecKwargs objects have a reference back to their ParamSpec: + + P.kwargs.__origin__ is P + + This type is meant for runtime introspection and has no special meaning to + static type checkers. + """ + def __init__(self, origin): + self.__origin__ = origin + + def __repr__(self): + return f"{self.__origin__.__name__}.kwargs" + + def __eq__(self, other): + if not isinstance(other, ParamSpecKwargs): + return NotImplemented + return self.__origin__ == other.__origin__ + +# 3.10+ +if hasattr(typing, 'ParamSpec'): + + # Add default Parameter - PEP 696 + class ParamSpec(typing.ParamSpec, _DefaultMixin, _root=True): + """Parameter specification variable.""" + + __module__ = 'typing' + + def __init__(self, name, *, bound=None, covariant=False, contravariant=False, + default=None): + super().__init__(name, bound=bound, covariant=covariant, + contravariant=contravariant) + _DefaultMixin.__init__(self, default) + + # for pickling: + try: + def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + def_mod = None + if def_mod != 'typing_extensions': + self.__module__ = def_mod + +# 3.7-3.9 +else: + + # Inherits from list as a workaround for Callable checks in Python < 3.9.2. + class ParamSpec(list, _DefaultMixin): + """Parameter specification variable. + + Usage:: + + P = ParamSpec('P') + + Parameter specification variables exist primarily for the benefit of static + type checkers. They are used to forward the parameter types of one + callable to another callable, a pattern commonly found in higher order + functions and decorators. They are only valid when used in ``Concatenate``, + or s the first argument to ``Callable``. In Python 3.10 and higher, + they are also supported in user-defined Generics at runtime. + See class Generic for more information on generic types. An + example for annotating a decorator:: + + T = TypeVar('T') + P = ParamSpec('P') + + def add_logging(f: Callable[P, T]) -> Callable[P, T]: + '''A type-safe decorator to add logging to a function.''' + def inner(*args: P.args, **kwargs: P.kwargs) -> T: + logging.info(f'{f.__name__} was called') + return f(*args, **kwargs) + return inner + + @add_logging + def add_two(x: float, y: float) -> float: + '''Add two numbers together.''' + return x + y + + Parameter specification variables defined with covariant=True or + contravariant=True can be used to declare covariant or contravariant + generic types. These keyword arguments are valid, but their actual semantics + are yet to be decided. See PEP 612 for details. + + Parameter specification variables can be introspected. e.g.: + + P.__name__ == 'T' + P.__bound__ == None + P.__covariant__ == False + P.__contravariant__ == False + + Note that only parameter specification variables defined in global scope can + be pickled. + """ + + # Trick Generic __parameters__. + __class__ = typing.TypeVar + + @property + def args(self): + return ParamSpecArgs(self) + + @property + def kwargs(self): + return ParamSpecKwargs(self) + + def __init__(self, name, *, bound=None, covariant=False, contravariant=False, + default=None): + super().__init__([self]) + self.__name__ = name + self.__covariant__ = bool(covariant) + self.__contravariant__ = bool(contravariant) + if bound: + self.__bound__ = typing._type_check(bound, 'Bound must be a type.') + else: + self.__bound__ = None + _DefaultMixin.__init__(self, default) + + # for pickling: + try: + def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + def_mod = None + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + def __repr__(self): + if self.__covariant__: + prefix = '+' + elif self.__contravariant__: + prefix = '-' + else: + prefix = '~' + return prefix + self.__name__ + + def __hash__(self): + return object.__hash__(self) + + def __eq__(self, other): + return self is other + + def __reduce__(self): + return self.__name__ + + # Hack to get typing._type_check to pass. + def __call__(self, *args, **kwargs): + pass + + +# 3.7-3.9 +if not hasattr(typing, 'Concatenate'): + # Inherits from list as a workaround for Callable checks in Python < 3.9.2. + class _ConcatenateGenericAlias(list): + + # Trick Generic into looking into this for __parameters__. + __class__ = typing._GenericAlias + + # Flag in 3.8. + _special = False + + def __init__(self, origin, args): + super().__init__(args) + self.__origin__ = origin + self.__args__ = args + + def __repr__(self): + _type_repr = typing._type_repr + return (f'{_type_repr(self.__origin__)}' + f'[{", ".join(_type_repr(arg) for arg in self.__args__)}]') + + def __hash__(self): + return hash((self.__origin__, self.__args__)) + + # Hack to get typing._type_check to pass in Generic. + def __call__(self, *args, **kwargs): + pass + + @property + def __parameters__(self): + return tuple( + tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec)) + ) + + +# 3.7-3.9 +@typing._tp_cache +def _concatenate_getitem(self, parameters): + if parameters == (): + raise TypeError("Cannot take a Concatenate of no types.") + if not isinstance(parameters, tuple): + parameters = (parameters,) + if not isinstance(parameters[-1], ParamSpec): + raise TypeError("The last parameter to Concatenate should be a " + "ParamSpec variable.") + msg = "Concatenate[arg, ...]: each arg must be a type." + parameters = tuple(typing._type_check(p, msg) for p in parameters) + return _ConcatenateGenericAlias(self, parameters) + + +# 3.10+ +if hasattr(typing, 'Concatenate'): + Concatenate = typing.Concatenate + _ConcatenateGenericAlias = typing._ConcatenateGenericAlias # noqa +# 3.9 +elif sys.version_info[:2] >= (3, 9): + @_TypeAliasForm + def Concatenate(self, parameters): + """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a + higher order function which adds, removes or transforms parameters of a + callable. + + For example:: + + Callable[Concatenate[int, P], int] + + See PEP 612 for detailed information. + """ + return _concatenate_getitem(self, parameters) +# 3.7-8 +else: + class _ConcatenateForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + return _concatenate_getitem(self, parameters) + + Concatenate = _ConcatenateForm( + 'Concatenate', + doc="""Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a + higher order function which adds, removes or transforms parameters of a + callable. + + For example:: + + Callable[Concatenate[int, P], int] + + See PEP 612 for detailed information. + """) + +# 3.10+ +if hasattr(typing, 'TypeGuard'): + TypeGuard = typing.TypeGuard +# 3.9 +elif sys.version_info[:2] >= (3, 9): + class _TypeGuardForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + @_TypeGuardForm + def TypeGuard(self, parameters): + """Special typing form used to annotate the return type of a user-defined + type guard function. ``TypeGuard`` only accepts a single type argument. + At runtime, functions marked this way should return a boolean. + + ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static + type checkers to determine a more precise type of an expression within a + program's code flow. Usually type narrowing is done by analyzing + conditional code flow and applying the narrowing to a block of code. The + conditional expression here is sometimes referred to as a "type guard". + + Sometimes it would be convenient to use a user-defined boolean function + as a type guard. Such a function should use ``TypeGuard[...]`` as its + return type to alert static type checkers to this intention. + + Using ``-> TypeGuard`` tells the static type checker that for a given + function: + + 1. The return value is a boolean. + 2. If the return value is ``True``, the type of its argument + is the type inside ``TypeGuard``. + + For example:: + + def is_str(val: Union[str, float]): + # "isinstance" type guard + if isinstance(val, str): + # Type of ``val`` is narrowed to ``str`` + ... + else: + # Else, type of ``val`` is narrowed to ``float``. + ... + + Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower + form of ``TypeA`` (it can even be a wider form) and this may lead to + type-unsafe results. The main reason is to allow for things like + narrowing ``List[object]`` to ``List[str]`` even though the latter is not + a subtype of the former, since ``List`` is invariant. The responsibility of + writing type-safe type guards is left to the user. + + ``TypeGuard`` also works with type variables. For more information, see + PEP 647 (User-Defined Type Guards). + """ + item = typing._type_check(parameters, f'{self} accepts only a single type.') + return typing._GenericAlias(self, (item,)) +# 3.7-3.8 +else: + class _TypeGuardForm(typing._SpecialForm, _root=True): + + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type') + return typing._GenericAlias(self, (item,)) + + TypeGuard = _TypeGuardForm( + 'TypeGuard', + doc="""Special typing form used to annotate the return type of a user-defined + type guard function. ``TypeGuard`` only accepts a single type argument. + At runtime, functions marked this way should return a boolean. + + ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static + type checkers to determine a more precise type of an expression within a + program's code flow. Usually type narrowing is done by analyzing + conditional code flow and applying the narrowing to a block of code. The + conditional expression here is sometimes referred to as a "type guard". + + Sometimes it would be convenient to use a user-defined boolean function + as a type guard. Such a function should use ``TypeGuard[...]`` as its + return type to alert static type checkers to this intention. + + Using ``-> TypeGuard`` tells the static type checker that for a given + function: + + 1. The return value is a boolean. + 2. If the return value is ``True``, the type of its argument + is the type inside ``TypeGuard``. + + For example:: + + def is_str(val: Union[str, float]): + # "isinstance" type guard + if isinstance(val, str): + # Type of ``val`` is narrowed to ``str`` + ... + else: + # Else, type of ``val`` is narrowed to ``float``. + ... + + Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower + form of ``TypeA`` (it can even be a wider form) and this may lead to + type-unsafe results. The main reason is to allow for things like + narrowing ``List[object]`` to ``List[str]`` even though the latter is not + a subtype of the former, since ``List`` is invariant. The responsibility of + writing type-safe type guards is left to the user. + + ``TypeGuard`` also works with type variables. For more information, see + PEP 647 (User-Defined Type Guards). + """) + + +# Vendored from cpython typing._SpecialFrom +class _SpecialForm(typing._Final, _root=True): + __slots__ = ('_name', '__doc__', '_getitem') + + def __init__(self, getitem): + self._getitem = getitem + self._name = getitem.__name__ + self.__doc__ = getitem.__doc__ + + def __getattr__(self, item): + if item in {'__name__', '__qualname__'}: + return self._name + + raise AttributeError(item) + + def __mro_entries__(self, bases): + raise TypeError(f"Cannot subclass {self!r}") + + def __repr__(self): + return f'typing_extensions.{self._name}' + + def __reduce__(self): + return self._name + + def __call__(self, *args, **kwds): + raise TypeError(f"Cannot instantiate {self!r}") + + def __or__(self, other): + return typing.Union[self, other] + + def __ror__(self, other): + return typing.Union[other, self] + + def __instancecheck__(self, obj): + raise TypeError(f"{self} cannot be used with isinstance()") + + def __subclasscheck__(self, cls): + raise TypeError(f"{self} cannot be used with issubclass()") + + @typing._tp_cache + def __getitem__(self, parameters): + return self._getitem(self, parameters) + + +if hasattr(typing, "LiteralString"): + LiteralString = typing.LiteralString +else: + @_SpecialForm + def LiteralString(self, params): + """Represents an arbitrary literal string. + + Example:: + + from typing_extensions import LiteralString + + def query(sql: LiteralString) -> ...: + ... + + query("SELECT * FROM table") # ok + query(f"SELECT * FROM {input()}") # not ok + + See PEP 675 for details. + + """ + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, "Self"): + Self = typing.Self +else: + @_SpecialForm + def Self(self, params): + """Used to spell the type of "self" in classes. + + Example:: + + from typing import Self + + class ReturnsSelf: + def parse(self, data: bytes) -> Self: + ... + return self + + """ + + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, "Never"): + Never = typing.Never +else: + @_SpecialForm + def Never(self, params): + """The bottom type, a type that has no members. + + This can be used to define a function that should never be + called, or a function that never returns:: + + from typing_extensions import Never + + def never_call_me(arg: Never) -> None: + pass + + def int_or_str(arg: int | str) -> None: + never_call_me(arg) # type checker error + match arg: + case int(): + print("It's an int") + case str(): + print("It's a str") + case _: + never_call_me(arg) # ok, arg is of type Never + + """ + + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, 'Required'): + Required = typing.Required + NotRequired = typing.NotRequired +elif sys.version_info[:2] >= (3, 9): + class _ExtensionsSpecialForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + @_ExtensionsSpecialForm + def Required(self, parameters): + """A special typing construct to mark a key of a total=False TypedDict + as required. For example: + + class Movie(TypedDict, total=False): + title: Required[str] + year: int + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + + There is no runtime checking that a required key is actually provided + when instantiating a related TypedDict. + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + @_ExtensionsSpecialForm + def NotRequired(self, parameters): + """A special typing construct to mark a key of a TypedDict as + potentially missing. For example: + + class Movie(TypedDict): + title: str + year: NotRequired[int] + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + +else: + class _RequiredForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + Required = _RequiredForm( + 'Required', + doc="""A special typing construct to mark a key of a total=False TypedDict + as required. For example: + + class Movie(TypedDict, total=False): + title: Required[str] + year: int + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + + There is no runtime checking that a required key is actually provided + when instantiating a related TypedDict. + """) + NotRequired = _RequiredForm( + 'NotRequired', + doc="""A special typing construct to mark a key of a TypedDict as + potentially missing. For example: + + class Movie(TypedDict): + title: str + year: NotRequired[int] + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + """) + + +if hasattr(typing, "Unpack"): # 3.11+ + Unpack = typing.Unpack +elif sys.version_info[:2] >= (3, 9): + class _UnpackSpecialForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + class _UnpackAlias(typing._GenericAlias, _root=True): + __class__ = typing.TypeVar + + @_UnpackSpecialForm + def Unpack(self, parameters): + """A special typing construct to unpack a variadic type. For example: + + Shape = TypeVarTuple('Shape') + Batch = NewType('Batch', int) + + def add_batch_axis( + x: Array[Unpack[Shape]] + ) -> Array[Batch, Unpack[Shape]]: ... + + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return _UnpackAlias(self, (item,)) + + def _is_unpack(obj): + return isinstance(obj, _UnpackAlias) + +else: + class _UnpackAlias(typing._GenericAlias, _root=True): + __class__ = typing.TypeVar + + class _UnpackForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type.') + return _UnpackAlias(self, (item,)) + + Unpack = _UnpackForm( + 'Unpack', + doc="""A special typing construct to unpack a variadic type. For example: + + Shape = TypeVarTuple('Shape') + Batch = NewType('Batch', int) + + def add_batch_axis( + x: Array[Unpack[Shape]] + ) -> Array[Batch, Unpack[Shape]]: ... + + """) + + def _is_unpack(obj): + return isinstance(obj, _UnpackAlias) + + +if hasattr(typing, "TypeVarTuple"): # 3.11+ + + # Add default Parameter - PEP 696 + class TypeVarTuple(typing.TypeVarTuple, _DefaultMixin, _root=True): + """Type variable tuple.""" + + def __init__(self, name, *, default=None): + super().__init__(name) + _DefaultMixin.__init__(self, default) + + # for pickling: + try: + def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + def_mod = None + if def_mod != 'typing_extensions': + self.__module__ = def_mod + +else: + class TypeVarTuple(_DefaultMixin): + """Type variable tuple. + + Usage:: + + Ts = TypeVarTuple('Ts') + + In the same way that a normal type variable is a stand-in for a single + type such as ``int``, a type variable *tuple* is a stand-in for a *tuple* + type such as ``Tuple[int, str]``. + + Type variable tuples can be used in ``Generic`` declarations. + Consider the following example:: + + class Array(Generic[*Ts]): ... + + The ``Ts`` type variable tuple here behaves like ``tuple[T1, T2]``, + where ``T1`` and ``T2`` are type variables. To use these type variables + as type parameters of ``Array``, we must *unpack* the type variable tuple using + the star operator: ``*Ts``. The signature of ``Array`` then behaves + as if we had simply written ``class Array(Generic[T1, T2]): ...``. + In contrast to ``Generic[T1, T2]``, however, ``Generic[*Shape]`` allows + us to parameterise the class with an *arbitrary* number of type parameters. + + Type variable tuples can be used anywhere a normal ``TypeVar`` can. + This includes class definitions, as shown above, as well as function + signatures and variable annotations:: + + class Array(Generic[*Ts]): + + def __init__(self, shape: Tuple[*Ts]): + self._shape: Tuple[*Ts] = shape + + def get_shape(self) -> Tuple[*Ts]: + return self._shape + + shape = (Height(480), Width(640)) + x: Array[Height, Width] = Array(shape) + y = abs(x) # Inferred type is Array[Height, Width] + z = x + x # ... is Array[Height, Width] + x.get_shape() # ... is tuple[Height, Width] + + """ + + # Trick Generic __parameters__. + __class__ = typing.TypeVar + + def __iter__(self): + yield self.__unpacked__ + + def __init__(self, name, *, default=None): + self.__name__ = name + _DefaultMixin.__init__(self, default) + + # for pickling: + try: + def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + def_mod = None + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + self.__unpacked__ = Unpack[self] + + def __repr__(self): + return self.__name__ + + def __hash__(self): + return object.__hash__(self) + + def __eq__(self, other): + return self is other + + def __reduce__(self): + return self.__name__ + + def __init_subclass__(self, *args, **kwds): + if '_root' not in kwds: + raise TypeError("Cannot subclass special typing classes") + + +if hasattr(typing, "reveal_type"): + reveal_type = typing.reveal_type +else: + def reveal_type(__obj: T) -> T: + """Reveal the inferred type of a variable. + + When a static type checker encounters a call to ``reveal_type()``, + it will emit the inferred type of the argument:: + + x: int = 1 + reveal_type(x) + + Running a static type checker (e.g., ``mypy``) on this example + will produce output similar to 'Revealed type is "builtins.int"'. + + At runtime, the function prints the runtime type of the + argument and returns it unchanged. + + """ + print(f"Runtime type is {type(__obj).__name__!r}", file=sys.stderr) + return __obj + + +if hasattr(typing, "assert_never"): + assert_never = typing.assert_never +else: + def assert_never(__arg: Never) -> Never: + """Assert to the type checker that a line of code is unreachable. + + Example:: + + def int_or_str(arg: int | str) -> None: + match arg: + case int(): + print("It's an int") + case str(): + print("It's a str") + case _: + assert_never(arg) + + If a type checker finds that a call to assert_never() is + reachable, it will emit an error. + + At runtime, this throws an exception when called. + + """ + raise AssertionError("Expected code to be unreachable") + + +if hasattr(typing, 'dataclass_transform'): + dataclass_transform = typing.dataclass_transform +else: + def dataclass_transform( + *, + eq_default: bool = True, + order_default: bool = False, + kw_only_default: bool = False, + field_specifiers: typing.Tuple[ + typing.Union[typing.Type[typing.Any], typing.Callable[..., typing.Any]], + ... + ] = (), + **kwargs: typing.Any, + ) -> typing.Callable[[T], T]: + """Decorator that marks a function, class, or metaclass as providing + dataclass-like behavior. + + Example: + + from typing_extensions import dataclass_transform + + _T = TypeVar("_T") + + # Used on a decorator function + @dataclass_transform() + def create_model(cls: type[_T]) -> type[_T]: + ... + return cls + + @create_model + class CustomerModel: + id: int + name: str + + # Used on a base class + @dataclass_transform() + class ModelBase: ... + + class CustomerModel(ModelBase): + id: int + name: str + + # Used on a metaclass + @dataclass_transform() + class ModelMeta(type): ... + + class ModelBase(metaclass=ModelMeta): ... + + class CustomerModel(ModelBase): + id: int + name: str + + Each of the ``CustomerModel`` classes defined in this example will now + behave similarly to a dataclass created with the ``@dataclasses.dataclass`` + decorator. For example, the type checker will synthesize an ``__init__`` + method. + + The arguments to this decorator can be used to customize this behavior: + - ``eq_default`` indicates whether the ``eq`` parameter is assumed to be + True or False if it is omitted by the caller. + - ``order_default`` indicates whether the ``order`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``kw_only_default`` indicates whether the ``kw_only`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``field_specifiers`` specifies a static list of supported classes + or functions that describe fields, similar to ``dataclasses.field()``. + + At runtime, this decorator records its arguments in the + ``__dataclass_transform__`` attribute on the decorated object. + + See PEP 681 for details. + + """ + def decorator(cls_or_fn): + cls_or_fn.__dataclass_transform__ = { + "eq_default": eq_default, + "order_default": order_default, + "kw_only_default": kw_only_default, + "field_specifiers": field_specifiers, + "kwargs": kwargs, + } + return cls_or_fn + return decorator + + +if hasattr(typing, "override"): + override = typing.override +else: + _F = typing.TypeVar("_F", bound=typing.Callable[..., typing.Any]) + + def override(__arg: _F) -> _F: + """Indicate that a method is intended to override a method in a base class. + + Usage: + + class Base: + def method(self) -> None: ... + pass + + class Child(Base): + @override + def method(self) -> None: + super().method() + + When this decorator is applied to a method, the type checker will + validate that it overrides a method with the same name on a base class. + This helps prevent bugs that may occur when a base class is changed + without an equivalent change to a child class. + + See PEP 698 for details. + + """ + return __arg + + +# We have to do some monkey patching to deal with the dual nature of +# Unpack/TypeVarTuple: +# - We want Unpack to be a kind of TypeVar so it gets accepted in +# Generic[Unpack[Ts]] +# - We want it to *not* be treated as a TypeVar for the purposes of +# counting generic parameters, so that when we subscript a generic, +# the runtime doesn't try to substitute the Unpack with the subscripted type. +if not hasattr(typing, "TypeVarTuple"): + typing._collect_type_vars = _collect_type_vars + typing._check_generic = _check_generic + + +# Backport typing.NamedTuple as it exists in Python 3.11. +# In 3.11, the ability to define generic `NamedTuple`s was supported. +# This was explicitly disallowed in 3.9-3.10, and only half-worked in <=3.8. +if sys.version_info >= (3, 11): + NamedTuple = typing.NamedTuple +else: + def _caller(): + try: + return sys._getframe(2).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): # For platforms without _getframe() + return None + + def _make_nmtuple(name, types, module, defaults=()): + fields = [n for n, t in types] + annotations = {n: typing._type_check(t, f"field {n} annotation must be a type") + for n, t in types} + nm_tpl = collections.namedtuple(name, fields, + defaults=defaults, module=module) + nm_tpl.__annotations__ = nm_tpl.__new__.__annotations__ = annotations + # The `_field_types` attribute was removed in 3.9; + # in earlier versions, it is the same as the `__annotations__` attribute + if sys.version_info < (3, 9): + nm_tpl._field_types = annotations + return nm_tpl + + _prohibited_namedtuple_fields = typing._prohibited + _special_namedtuple_fields = frozenset({'__module__', '__name__', '__annotations__'}) + + class _NamedTupleMeta(type): + def __new__(cls, typename, bases, ns): + assert _NamedTuple in bases + for base in bases: + if base is not _NamedTuple and base is not typing.Generic: + raise TypeError( + 'can only inherit from a NamedTuple type and Generic') + bases = tuple(tuple if base is _NamedTuple else base for base in bases) + types = ns.get('__annotations__', {}) + default_names = [] + for field_name in types: + if field_name in ns: + default_names.append(field_name) + elif default_names: + raise TypeError(f"Non-default namedtuple field {field_name} " + f"cannot follow default field" + f"{'s' if len(default_names) > 1 else ''} " + f"{', '.join(default_names)}") + nm_tpl = _make_nmtuple( + typename, types.items(), + defaults=[ns[n] for n in default_names], + module=ns['__module__'] + ) + nm_tpl.__bases__ = bases + if typing.Generic in bases: + class_getitem = typing.Generic.__class_getitem__.__func__ + nm_tpl.__class_getitem__ = classmethod(class_getitem) + # update from user namespace without overriding special namedtuple attributes + for key in ns: + if key in _prohibited_namedtuple_fields: + raise AttributeError("Cannot overwrite NamedTuple attribute " + key) + elif key not in _special_namedtuple_fields and key not in nm_tpl._fields: + setattr(nm_tpl, key, ns[key]) + if typing.Generic in bases: + nm_tpl.__init_subclass__() + return nm_tpl + + def NamedTuple(__typename, __fields=None, **kwargs): + if __fields is None: + __fields = kwargs.items() + elif kwargs: + raise TypeError("Either list of fields or keywords" + " can be provided to NamedTuple, not both") + return _make_nmtuple(__typename, __fields, module=_caller()) + + NamedTuple.__doc__ = typing.NamedTuple.__doc__ + _NamedTuple = type.__new__(_NamedTupleMeta, 'NamedTuple', (), {}) + + # On 3.8+, alter the signature so that it matches typing.NamedTuple. + # The signature of typing.NamedTuple on >=3.8 is invalid syntax in Python 3.7, + # so just leave the signature as it is on 3.7. + if sys.version_info >= (3, 8): + NamedTuple.__text_signature__ = '(typename, fields=None, /, **kwargs)' + + def _namedtuple_mro_entries(bases): + assert NamedTuple in bases + return (_NamedTuple,) + + NamedTuple.__mro_entries__ = _namedtuple_mro_entries diff --git a/venv/Lib/site-packages/pkg_resources/_vendor/zipp.py b/venv/Lib/site-packages/pkg_resources/_vendor/zipp.py new file mode 100644 index 0000000..26b723c --- /dev/null +++ b/venv/Lib/site-packages/pkg_resources/_vendor/zipp.py @@ -0,0 +1,329 @@ +import io +import posixpath +import zipfile +import itertools +import contextlib +import sys +import pathlib + +if sys.version_info < (3, 7): + from collections import OrderedDict +else: + OrderedDict = dict + + +__all__ = ['Path'] + + +def _parents(path): + """ + Given a path with elements separated by + posixpath.sep, generate all parents of that path. + + >>> list(_parents('b/d')) + ['b'] + >>> list(_parents('/b/d/')) + ['/b'] + >>> list(_parents('b/d/f/')) + ['b/d', 'b'] + >>> list(_parents('b')) + [] + >>> list(_parents('')) + [] + """ + return itertools.islice(_ancestry(path), 1, None) + + +def _ancestry(path): + """ + Given a path with elements separated by + posixpath.sep, generate all elements of that path + + >>> list(_ancestry('b/d')) + ['b/d', 'b'] + >>> list(_ancestry('/b/d/')) + ['/b/d', '/b'] + >>> list(_ancestry('b/d/f/')) + ['b/d/f', 'b/d', 'b'] + >>> list(_ancestry('b')) + ['b'] + >>> list(_ancestry('')) + [] + """ + path = path.rstrip(posixpath.sep) + while path and path != posixpath.sep: + yield path + path, tail = posixpath.split(path) + + +_dedupe = OrderedDict.fromkeys +"""Deduplicate an iterable in original order""" + + +def _difference(minuend, subtrahend): + """ + Return items in minuend not in subtrahend, retaining order + with O(1) lookup. + """ + return itertools.filterfalse(set(subtrahend).__contains__, minuend) + + +class CompleteDirs(zipfile.ZipFile): + """ + A ZipFile subclass that ensures that implied directories + are always included in the namelist. + """ + + @staticmethod + def _implied_dirs(names): + parents = itertools.chain.from_iterable(map(_parents, names)) + as_dirs = (p + posixpath.sep for p in parents) + return _dedupe(_difference(as_dirs, names)) + + def namelist(self): + names = super(CompleteDirs, self).namelist() + return names + list(self._implied_dirs(names)) + + def _name_set(self): + return set(self.namelist()) + + def resolve_dir(self, name): + """ + If the name represents a directory, return that name + as a directory (with the trailing slash). + """ + names = self._name_set() + dirname = name + '/' + dir_match = name not in names and dirname in names + return dirname if dir_match else name + + @classmethod + def make(cls, source): + """ + Given a source (filename or zipfile), return an + appropriate CompleteDirs subclass. + """ + if isinstance(source, CompleteDirs): + return source + + if not isinstance(source, zipfile.ZipFile): + return cls(_pathlib_compat(source)) + + # Only allow for FastLookup when supplied zipfile is read-only + if 'r' not in source.mode: + cls = CompleteDirs + + source.__class__ = cls + return source + + +class FastLookup(CompleteDirs): + """ + ZipFile subclass to ensure implicit + dirs exist and are resolved rapidly. + """ + + def namelist(self): + with contextlib.suppress(AttributeError): + return self.__names + self.__names = super(FastLookup, self).namelist() + return self.__names + + def _name_set(self): + with contextlib.suppress(AttributeError): + return self.__lookup + self.__lookup = super(FastLookup, self)._name_set() + return self.__lookup + + +def _pathlib_compat(path): + """ + For path-like objects, convert to a filename for compatibility + on Python 3.6.1 and earlier. + """ + try: + return path.__fspath__() + except AttributeError: + return str(path) + + +class Path: + """ + A pathlib-compatible interface for zip files. + + Consider a zip file with this structure:: + + . + ├── a.txt + └── b + ├── c.txt + └── d + └── e.txt + + >>> data = io.BytesIO() + >>> zf = zipfile.ZipFile(data, 'w') + >>> zf.writestr('a.txt', 'content of a') + >>> zf.writestr('b/c.txt', 'content of c') + >>> zf.writestr('b/d/e.txt', 'content of e') + >>> zf.filename = 'mem/abcde.zip' + + Path accepts the zipfile object itself or a filename + + >>> root = Path(zf) + + From there, several path operations are available. + + Directory iteration (including the zip file itself): + + >>> a, b = root.iterdir() + >>> a + Path('mem/abcde.zip', 'a.txt') + >>> b + Path('mem/abcde.zip', 'b/') + + name property: + + >>> b.name + 'b' + + join with divide operator: + + >>> c = b / 'c.txt' + >>> c + Path('mem/abcde.zip', 'b/c.txt') + >>> c.name + 'c.txt' + + Read text: + + >>> c.read_text() + 'content of c' + + existence: + + >>> c.exists() + True + >>> (b / 'missing.txt').exists() + False + + Coercion to string: + + >>> import os + >>> str(c).replace(os.sep, posixpath.sep) + 'mem/abcde.zip/b/c.txt' + + At the root, ``name``, ``filename``, and ``parent`` + resolve to the zipfile. Note these attributes are not + valid and will raise a ``ValueError`` if the zipfile + has no filename. + + >>> root.name + 'abcde.zip' + >>> str(root.filename).replace(os.sep, posixpath.sep) + 'mem/abcde.zip' + >>> str(root.parent) + 'mem' + """ + + __repr = "{self.__class__.__name__}({self.root.filename!r}, {self.at!r})" + + def __init__(self, root, at=""): + """ + Construct a Path from a ZipFile or filename. + + Note: When the source is an existing ZipFile object, + its type (__class__) will be mutated to a + specialized type. If the caller wishes to retain the + original type, the caller should either create a + separate ZipFile object or pass a filename. + """ + self.root = FastLookup.make(root) + self.at = at + + def open(self, mode='r', *args, pwd=None, **kwargs): + """ + Open this entry as text or binary following the semantics + of ``pathlib.Path.open()`` by passing arguments through + to io.TextIOWrapper(). + """ + if self.is_dir(): + raise IsADirectoryError(self) + zip_mode = mode[0] + if not self.exists() and zip_mode == 'r': + raise FileNotFoundError(self) + stream = self.root.open(self.at, zip_mode, pwd=pwd) + if 'b' in mode: + if args or kwargs: + raise ValueError("encoding args invalid for binary operation") + return stream + return io.TextIOWrapper(stream, *args, **kwargs) + + @property + def name(self): + return pathlib.Path(self.at).name or self.filename.name + + @property + def suffix(self): + return pathlib.Path(self.at).suffix or self.filename.suffix + + @property + def suffixes(self): + return pathlib.Path(self.at).suffixes or self.filename.suffixes + + @property + def stem(self): + return pathlib.Path(self.at).stem or self.filename.stem + + @property + def filename(self): + return pathlib.Path(self.root.filename).joinpath(self.at) + + def read_text(self, *args, **kwargs): + with self.open('r', *args, **kwargs) as strm: + return strm.read() + + def read_bytes(self): + with self.open('rb') as strm: + return strm.read() + + def _is_child(self, path): + return posixpath.dirname(path.at.rstrip("/")) == self.at.rstrip("/") + + def _next(self, at): + return self.__class__(self.root, at) + + def is_dir(self): + return not self.at or self.at.endswith("/") + + def is_file(self): + return self.exists() and not self.is_dir() + + def exists(self): + return self.at in self.root._name_set() + + def iterdir(self): + if not self.is_dir(): + raise ValueError("Can't listdir a file") + subs = map(self._next, self.root.namelist()) + return filter(self._is_child, subs) + + def __str__(self): + return posixpath.join(self.root.filename, self.at) + + def __repr__(self): + return self.__repr.format(self=self) + + def joinpath(self, *other): + next = posixpath.join(self.at, *map(_pathlib_compat, other)) + return self._next(self.root.resolve_dir(next)) + + __truediv__ = joinpath + + @property + def parent(self): + if not self.at: + return self.filename.parent + parent_at = posixpath.dirname(self.at.rstrip('/')) + if parent_at: + parent_at += '/' + return self._next(parent_at) diff --git a/venv/Lib/site-packages/pluggy-0.13.1.dist-info/INSTALLER b/venv/Lib/site-packages/pluggy-0.13.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/pluggy-0.13.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/pluggy-0.13.1.dist-info/LICENSE b/venv/Lib/site-packages/pluggy-0.13.1.dist-info/LICENSE new file mode 100644 index 0000000..85f4dd6 --- /dev/null +++ b/venv/Lib/site-packages/pluggy-0.13.1.dist-info/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 holger krekel (rather uses bitbucket/hpk42) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/venv/Lib/site-packages/pluggy-0.13.1.dist-info/METADATA b/venv/Lib/site-packages/pluggy-0.13.1.dist-info/METADATA new file mode 100644 index 0000000..cc993ee --- /dev/null +++ b/venv/Lib/site-packages/pluggy-0.13.1.dist-info/METADATA @@ -0,0 +1,482 @@ +Metadata-Version: 2.1 +Name: pluggy +Version: 0.13.1 +Summary: plugin and hook calling mechanisms for python +Home-page: https://github.com/pytest-dev/pluggy +Author: Holger Krekel +Author-email: holger@merlinux.eu +License: MIT license +Platform: unix +Platform: linux +Platform: osx +Platform: win32 +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: POSIX +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Topic :: Software Development :: Testing +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Utilities +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* +Requires-Dist: importlib-metadata (>=0.12) ; python_version < "3.8" +Provides-Extra: dev +Requires-Dist: pre-commit ; extra == 'dev' +Requires-Dist: tox ; extra == 'dev' + +==================================================== +pluggy - A minimalist production ready plugin system +==================================================== + +|pypi| |conda-forge| |versions| |travis| |appveyor| |gitter| |black| |codecov| + +This is the core framework used by the `pytest`_, `tox`_, and `devpi`_ projects. + +Please `read the docs`_ to learn more! + +A definitive example +==================== +.. code-block:: python + + import pluggy + + hookspec = pluggy.HookspecMarker("myproject") + hookimpl = pluggy.HookimplMarker("myproject") + + + class MySpec(object): + """A hook specification namespace. + """ + + @hookspec + def myhook(self, arg1, arg2): + """My special little hook that you can customize. + """ + + + class Plugin_1(object): + """A hook implementation namespace. + """ + + @hookimpl + def myhook(self, arg1, arg2): + print("inside Plugin_1.myhook()") + return arg1 + arg2 + + + class Plugin_2(object): + """A 2nd hook implementation namespace. + """ + + @hookimpl + def myhook(self, arg1, arg2): + print("inside Plugin_2.myhook()") + return arg1 - arg2 + + + # create a manager and add the spec + pm = pluggy.PluginManager("myproject") + pm.add_hookspecs(MySpec) + + # register plugins + pm.register(Plugin_1()) + pm.register(Plugin_2()) + + # call our ``myhook`` hook + results = pm.hook.myhook(arg1=1, arg2=2) + print(results) + + +Running this directly gets us:: + + $ python docs/examples/toy-example.py + inside Plugin_2.myhook() + inside Plugin_1.myhook() + [-1, 3] + + +.. badges + +.. |pypi| image:: https://img.shields.io/pypi/v/pluggy.svg + :target: https://pypi.org/pypi/pluggy + +.. |versions| image:: https://img.shields.io/pypi/pyversions/pluggy.svg + :target: https://pypi.org/pypi/pluggy + +.. |travis| image:: https://img.shields.io/travis/pytest-dev/pluggy/master.svg + :target: https://travis-ci.org/pytest-dev/pluggy + +.. |appveyor| image:: https://img.shields.io/appveyor/ci/pytestbot/pluggy/master.svg + :target: https://ci.appveyor.com/project/pytestbot/pluggy + +.. |conda-forge| image:: https://img.shields.io/conda/vn/conda-forge/pluggy.svg + :target: https://anaconda.org/conda-forge/pytest + +.. |gitter| image:: https://badges.gitter.im/pytest-dev/pluggy.svg + :alt: Join the chat at https://gitter.im/pytest-dev/pluggy + :target: https://gitter.im/pytest-dev/pluggy?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge + +.. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/ambv/black + +.. |codecov| image:: https://codecov.io/gh/pytest-dev/pluggy/branch/master/graph/badge.svg + :target: https://codecov.io/gh/pytest-dev/pluggy + :alt: Code coverage Status + +.. links +.. _pytest: + http://pytest.org +.. _tox: + https://tox.readthedocs.org +.. _devpi: + http://doc.devpi.net +.. _read the docs: + https://pluggy.readthedocs.io/en/latest/ + + +========= +Changelog +========= + +.. towncrier release notes start + +pluggy 0.13.1 (2019-11-21) +========================== + +Trivial/Internal Changes +------------------------ + +- `#236 `_: Improved documentation, especially with regard to references. + + +pluggy 0.13.0 (2019-09-10) +========================== + +Trivial/Internal Changes +------------------------ + +- `#222 `_: Replace ``importlib_metadata`` backport with ``importlib.metadata`` from the + standard library on Python 3.8+. + + +pluggy 0.12.0 (2019-05-27) +========================== + +Features +-------- + +- `#215 `_: Switch from ``pkg_resources`` to ``importlib-metadata`` for entrypoint detection for improved performance and import time. This time with ``.egg`` support. + + +pluggy 0.11.0 (2019-05-07) +========================== + +Bug Fixes +--------- + +- `#205 `_: Revert changes made in 0.10.0 release breaking ``.egg`` installs. + + +pluggy 0.10.0 (2019-05-07) +========================== + +Features +-------- + +- `#199 `_: Switch from ``pkg_resources`` to ``importlib-metadata`` for entrypoint detection for improved performance and import time. + + +pluggy 0.9.0 (2019-02-21) +========================= + +Features +-------- + +- `#189 `_: ``PluginManager.load_setuptools_entrypoints`` now accepts a ``name`` parameter that when given will + load only entry points with that name. + + ``PluginManager.load_setuptools_entrypoints`` also now returns the number of plugins loaded by the + call, as opposed to the number of all plugins loaded by all calls to this method. + + + +Bug Fixes +--------- + +- `#187 `_: Fix internal ``varnames`` function for PyPy3. + + +pluggy 0.8.1 (2018-11-09) +========================= + +Trivial/Internal Changes +------------------------ + +- `#166 `_: Add ``stacklevel=2`` to implprefix warning so that the reported location of warning is the caller of PluginManager. + + +pluggy 0.8.0 (2018-10-15) +========================= + +Features +-------- + +- `#177 `_: Add ``get_hookimpls()`` method to hook callers. + + + +Trivial/Internal Changes +------------------------ + +- `#165 `_: Add changelog in long package description and documentation. + + +- `#172 `_: Add a test exemplifying the opt-in nature of spec defined args. + + +- `#57 `_: Encapsulate hook specifications in a type for easier introspection. + + +pluggy 0.7.1 (2018-07-28) +========================= + +Deprecations and Removals +------------------------- + +- `#116 `_: Deprecate the ``implprefix`` kwarg to ``PluginManager`` and instead + expect users to start using explicit ``HookimplMarker`` everywhere. + + + +Features +-------- + +- `#122 `_: Add ``.plugin`` member to ``PluginValidationError`` to access failing plugin during post-mortem. + + +- `#138 `_: Add per implementation warnings support for hookspecs allowing for both + deprecation and future warnings of legacy and (future) experimental hooks + respectively. + + + +Bug Fixes +--------- + +- `#110 `_: Fix a bug where ``_HookCaller.call_historic()`` would call the ``proc`` + arg even when the default is ``None`` resulting in a ``TypeError``. + +- `#160 `_: Fix problem when handling ``VersionConflict`` errors when loading setuptools plugins. + + + +Improved Documentation +---------------------- + +- `#123 `_: Document how exceptions are handled and how the hook call loop + terminates immediately on the first error which is then delivered + to any surrounding wrappers. + + +- `#136 `_: Docs rework including a much better introduction and comprehensive example + set for new users. A big thanks goes out to @obestwalter for the great work! + + + +Trivial/Internal Changes +------------------------ + +- `#117 `_: Break up the main monolithic package modules into separate modules by concern + + +- `#131 `_: Automate ``setuptools`` wheels building and PyPi upload using TravisCI. + + +- `#153 `_: Reorganize tests more appropriately by modules relating to each + internal component/feature. This is in an effort to avoid (future) + duplication and better separation of concerns in the test set. + + +- `#156 `_: Add ``HookImpl.__repr__()`` for better debugging. + + +- `#66 `_: Start using ``towncrier`` and a custom ``tox`` environment to prepare releases! + + +pluggy 0.7.0 (Unreleased) +========================= + +* `#160 `_: We discovered a deployment issue so this version was never released to PyPI, only the tag exists. + +pluggy 0.6.0 (2017-11-24) +========================= + +- Add CI testing for the features, release, and master + branches of ``pytest`` (PR `#79`_). +- Document public API for ``_Result`` objects passed to wrappers + (PR `#85`_). +- Document and test hook LIFO ordering (PR `#85`_). +- Turn warnings into errors in test suite (PR `#89`_). +- Deprecate ``_Result.result`` (PR `#88`_). +- Convert ``_Multicall`` to a simple function distinguishing it from + the legacy version (PR `#90`_). +- Resolve E741 errors (PR `#96`_). +- Test and bug fix for unmarked hook collection (PRs `#97`_ and + `#102`_). +- Drop support for EOL Python 2.6 and 3.3 (PR `#103`_). +- Fix ``inspect`` based arg introspection on py3.6 (PR `#94`_). + +.. _#79: https://github.com/pytest-dev/pluggy/pull/79 +.. _#85: https://github.com/pytest-dev/pluggy/pull/85 +.. _#88: https://github.com/pytest-dev/pluggy/pull/88 +.. _#89: https://github.com/pytest-dev/pluggy/pull/89 +.. _#90: https://github.com/pytest-dev/pluggy/pull/90 +.. _#94: https://github.com/pytest-dev/pluggy/pull/94 +.. _#96: https://github.com/pytest-dev/pluggy/pull/96 +.. _#97: https://github.com/pytest-dev/pluggy/pull/97 +.. _#102: https://github.com/pytest-dev/pluggy/pull/102 +.. _#103: https://github.com/pytest-dev/pluggy/pull/103 + + +pluggy 0.5.2 (2017-09-06) +========================= + +- fix bug where ``firstresult`` wrappers were being sent an incorrectly configured + ``_Result`` (a list was set instead of a single value). Add tests to check for + this as well as ``_Result.force_result()`` behaviour. Thanks to `@tgoodlet`_ + for the PR `#72`_. + +- fix incorrect ``getattr`` of ``DeprecationWarning`` from the ``warnings`` + module. Thanks to `@nicoddemus`_ for the PR `#77`_. + +- hide ``pytest`` tracebacks in certain core routines. Thanks to + `@nicoddemus`_ for the PR `#80`_. + +.. _#72: https://github.com/pytest-dev/pluggy/pull/72 +.. _#77: https://github.com/pytest-dev/pluggy/pull/77 +.. _#80: https://github.com/pytest-dev/pluggy/pull/80 + + +pluggy 0.5.1 (2017-08-29) +========================= + +- fix a bug and add tests for case where ``firstresult`` hooks return + ``None`` results. Thanks to `@RonnyPfannschmidt`_ and `@tgoodlet`_ + for the issue (`#68`_) and PR (`#69`_) respectively. + +.. _#69: https://github.com/pytest-dev/pluggy/pull/69 +.. _#68: https://github.com/pytest-dev/pluggy/issues/68 + + +pluggy 0.5.0 (2017-08-28) +========================= + +- fix bug where callbacks for historic hooks would not be called for + already registered plugins. Thanks `@vodik`_ for the PR + and `@hpk42`_ for further fixes. + +- fix `#17`_ by considering only actual functions for hooks + this removes the ability to register arbitrary callable objects + which at first glance is a reasonable simplification, + thanks `@RonnyPfannschmidt`_ for report and pr. + +- fix `#19`_: allow registering hookspecs from instances. The PR from + `@tgoodlet`_ also modernized the varnames implementation. + +- resolve `#32`_: split up the test set into multiple modules. + Thanks to `@RonnyPfannschmidt`_ for the PR and `@tgoodlet`_ for + the initial request. + +- resolve `#14`_: add full sphinx docs. Thanks to `@tgoodlet`_ for + PR `#39`_. + +- add hook call mismatch warnings. Thanks to `@tgoodlet`_ for the + PR `#42`_. + +- resolve `#44`_: move to new-style classes. Thanks to `@MichalTHEDUDE`_ + for PR `#46`_. + +- add baseline benchmarking/speed tests using ``pytest-benchmark`` + in PR `#54`_. Thanks to `@tgoodlet`_. + +- update the README to showcase the API. Thanks to `@tgoodlet`_ for the + issue and PR `#55`_. + +- deprecate ``__multicall__`` and add a faster call loop implementation. + Thanks to `@tgoodlet`_ for PR `#58`_. + +- raise a comprehensible error when a ``hookimpl`` is called with positional + args. Thanks to `@RonnyPfannschmidt`_ for the issue and `@tgoodlet`_ for + PR `#60`_. + +- fix the ``firstresult`` test making it more complete + and remove a duplicate of that test. Thanks to `@tgoodlet`_ + for PR `#62`_. + +.. _#62: https://github.com/pytest-dev/pluggy/pull/62 +.. _#60: https://github.com/pytest-dev/pluggy/pull/60 +.. _#58: https://github.com/pytest-dev/pluggy/pull/58 +.. _#55: https://github.com/pytest-dev/pluggy/pull/55 +.. _#54: https://github.com/pytest-dev/pluggy/pull/54 +.. _#46: https://github.com/pytest-dev/pluggy/pull/46 +.. _#44: https://github.com/pytest-dev/pluggy/issues/44 +.. _#42: https://github.com/pytest-dev/pluggy/pull/42 +.. _#39: https://github.com/pytest-dev/pluggy/pull/39 +.. _#32: https://github.com/pytest-dev/pluggy/pull/32 +.. _#19: https://github.com/pytest-dev/pluggy/issues/19 +.. _#17: https://github.com/pytest-dev/pluggy/issues/17 +.. _#14: https://github.com/pytest-dev/pluggy/issues/14 + + +pluggy 0.4.0 (2016-09-25) +========================= + +- add ``has_plugin(name)`` method to pluginmanager. thanks `@nicoddemus`_. + +- fix `#11`_: make plugin parsing more resilient against exceptions + from ``__getattr__`` functions. Thanks `@nicoddemus`_. + +- fix issue `#4`_: specific ``HookCallError`` exception for when a hook call + provides not enough arguments. + +- better error message when loading setuptools entrypoints fails + due to a ``VersionConflict``. Thanks `@blueyed`_. + +.. _#11: https://github.com/pytest-dev/pluggy/issues/11 +.. _#4: https://github.com/pytest-dev/pluggy/issues/4 + + +pluggy 0.3.1 (2015-09-17) +========================= + +- avoid using deprecated-in-python3.5 getargspec method. Thanks + `@mdboom`_. + + +pluggy 0.3.0 (2015-05-07) +========================= + +initial release + +.. contributors +.. _@hpk42: https://github.com/hpk42 +.. _@tgoodlet: https://github.com/goodboy +.. _@MichalTHEDUDE: https://github.com/MichalTHEDUDE +.. _@vodik: https://github.com/vodik +.. _@RonnyPfannschmidt: https://github.com/RonnyPfannschmidt +.. _@blueyed: https://github.com/blueyed +.. _@nicoddemus: https://github.com/nicoddemus +.. _@mdboom: https://github.com/mdboom + + diff --git a/venv/Lib/site-packages/pluggy-0.13.1.dist-info/RECORD b/venv/Lib/site-packages/pluggy-0.13.1.dist-info/RECORD new file mode 100644 index 0000000..c37a099 --- /dev/null +++ b/venv/Lib/site-packages/pluggy-0.13.1.dist-info/RECORD @@ -0,0 +1,18 @@ +pluggy-0.13.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pluggy-0.13.1.dist-info/LICENSE,sha256=1rZebCE6XQtXeRHTTW5ZSbn1nXbCOMUHGi8_wWz7JgY,1110 +pluggy-0.13.1.dist-info/METADATA,sha256=6xIuxFdAfUN0R1pfQKrnSjocoIoKoPBFZpmaC0wBus0,15789 +pluggy-0.13.1.dist-info/RECORD,, +pluggy-0.13.1.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110 +pluggy-0.13.1.dist-info/top_level.txt,sha256=xKSCRhai-v9MckvMuWqNz16c1tbsmOggoMSwTgcpYHE,7 +pluggy/__init__.py,sha256=FlQ2T7ewtZu6euZ0pG_1YANZ_lXzV9LDdLSgKutQmEg,486 +pluggy/__pycache__/__init__.cpython-39.pyc,, +pluggy/__pycache__/_tracing.cpython-39.pyc,, +pluggy/__pycache__/_version.cpython-39.pyc,, +pluggy/__pycache__/callers.cpython-39.pyc,, +pluggy/__pycache__/hooks.cpython-39.pyc,, +pluggy/__pycache__/manager.cpython-39.pyc,, +pluggy/_tracing.py,sha256=alc0j9EAgwavq43Tu0D4vuXmwn6ypzyXx9v6ouCwVaQ,1561 +pluggy/_version.py,sha256=qgt73isSUreytNwWnjCB0NjJve7NfJIyilQugyH2dY8,117 +pluggy/callers.py,sha256=ftcvH6AX7p9cK58916KxxLtsFEhOr2OR69LMAVqxrFk,6820 +pluggy/hooks.py,sha256=kyzHy7LNqCyZ70hpE3EOxxZ1jgI5Z3eS4yf9EDQH4bw,12289 +pluggy/manager.py,sha256=hL3cHd9-cXgM9PN5tKjTwFkYNWHLbFGBUju94NkM1sk,15513 diff --git a/venv/Lib/site-packages/pluggy-0.13.1.dist-info/WHEEL b/venv/Lib/site-packages/pluggy-0.13.1.dist-info/WHEEL new file mode 100644 index 0000000..8b701e9 --- /dev/null +++ b/venv/Lib/site-packages/pluggy-0.13.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.33.6) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/pluggy-0.13.1.dist-info/top_level.txt b/venv/Lib/site-packages/pluggy-0.13.1.dist-info/top_level.txt new file mode 100644 index 0000000..11bdb5c --- /dev/null +++ b/venv/Lib/site-packages/pluggy-0.13.1.dist-info/top_level.txt @@ -0,0 +1 @@ +pluggy diff --git a/venv/Lib/site-packages/py-1.11.0.dist-info/INSTALLER b/venv/Lib/site-packages/py-1.11.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/py-1.11.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/py-1.11.0.dist-info/LICENSE b/venv/Lib/site-packages/py-1.11.0.dist-info/LICENSE new file mode 100644 index 0000000..31ecdfb --- /dev/null +++ b/venv/Lib/site-packages/py-1.11.0.dist-info/LICENSE @@ -0,0 +1,19 @@ + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + diff --git a/venv/Lib/site-packages/py-1.11.0.dist-info/METADATA b/venv/Lib/site-packages/py-1.11.0.dist-info/METADATA new file mode 100644 index 0000000..a14febe --- /dev/null +++ b/venv/Lib/site-packages/py-1.11.0.dist-info/METADATA @@ -0,0 +1,69 @@ +Metadata-Version: 2.1 +Name: py +Version: 1.11.0 +Summary: library with cross-python path, ini-parsing, io, code, log facilities +Home-page: https://py.readthedocs.io/ +Author: holger krekel, Ronny Pfannschmidt, Benjamin Peterson and others +Author-email: pytest-dev@python.org +License: MIT license +Platform: unix +Platform: linux +Platform: osx +Platform: cygwin +Platform: win32 +Classifier: Development Status :: 6 - Mature +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: POSIX +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Topic :: Software Development :: Testing +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Utilities +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* + +.. image:: https://img.shields.io/pypi/v/py.svg + :target: https://pypi.org/project/py + +.. image:: https://img.shields.io/conda/vn/conda-forge/py.svg + :target: https://anaconda.org/conda-forge/py + +.. image:: https://img.shields.io/pypi/pyversions/py.svg + :target: https://pypi.org/project/py + +.. image:: https://github.com/pytest-dev/py/workflows/build/badge.svg + :target: https://github.com/pytest-dev/py/actions + + +**NOTE**: this library is in **maintenance mode** and should not be used in new code. + +The py lib is a Python development support library featuring +the following tools and modules: + +* ``py.path``: uniform local and svn path objects -> please use pathlib/pathlib2 instead +* ``py.apipkg``: explicit API control and lazy-importing -> please use the standalone package instead +* ``py.iniconfig``: easy parsing of .ini files -> please use the standalone package instead +* ``py.code``: dynamic code generation and introspection (deprecated, moved to ``pytest`` as a implementation detail). + +**NOTE**: prior to the 1.4 release this distribution used to +contain py.test which is now its own package, see https://docs.pytest.org + +For questions and more information please visit https://py.readthedocs.io + +Bugs and issues: https://github.com/pytest-dev/py + +Authors: Holger Krekel and others, 2004-2017 + + diff --git a/venv/Lib/site-packages/py-1.11.0.dist-info/RECORD b/venv/Lib/site-packages/py-1.11.0.dist-info/RECORD new file mode 100644 index 0000000..f28e197 --- /dev/null +++ b/venv/Lib/site-packages/py-1.11.0.dist-info/RECORD @@ -0,0 +1,101 @@ +py-1.11.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +py-1.11.0.dist-info/LICENSE,sha256=KvaAw570k_uCgwNW0dPfGstaBgM8ui3sehniHKp3qGY,1061 +py-1.11.0.dist-info/METADATA,sha256=j1AvLZH7HqTO06dYJbYYGypPxkhP9IZjlTPSOY82ehM,2811 +py-1.11.0.dist-info/RECORD,, +py-1.11.0.dist-info/WHEEL,sha256=WzZ8cwjh8l0jtULNjYq1Hpr-WCqCRgPr--TX4P5I1Wo,110 +py-1.11.0.dist-info/top_level.txt,sha256=rwh8_ukTaGscjyhGkBVcsGOMdc-Cfdz2QH7BKGENv-4,3 +py/__init__.py,sha256=56vBwkYKqNTj2StRTFjqa-p51_y6qVkvoyj10NyThtY,6022 +py/__init__.pyi,sha256=J0oNF3G0rcZL521oXyfWg7T053Spb2DmB5eDe40LcpY,341 +py/__metainfo.py,sha256=-APUcNtmuKgbYF8JfzlEyULMfp67uDDnRFKiu9nmxD0,55 +py/__pycache__/__init__.cpython-39.pyc,, +py/__pycache__/__metainfo.cpython-39.pyc,, +py/__pycache__/_builtin.cpython-39.pyc,, +py/__pycache__/_error.cpython-39.pyc,, +py/__pycache__/_std.cpython-39.pyc,, +py/__pycache__/_version.cpython-39.pyc,, +py/__pycache__/_xmlgen.cpython-39.pyc,, +py/__pycache__/test.cpython-39.pyc,, +py/_builtin.py,sha256=c9wCmZ0nsZtFARJoZ5Ia7RxJuBo1Bp7IHjLC5uQvIug,4021 +py/_code/__init__.py,sha256=PsNXpJtPfle_IbAgLXQTO5YJyHi8N1xR8YtetmLs1Ac,46 +py/_code/__pycache__/__init__.cpython-39.pyc,, +py/_code/__pycache__/_assertionnew.cpython-39.pyc,, +py/_code/__pycache__/_assertionold.cpython-39.pyc,, +py/_code/__pycache__/_py2traceback.cpython-39.pyc,, +py/_code/__pycache__/assertion.cpython-39.pyc,, +py/_code/__pycache__/code.cpython-39.pyc,, +py/_code/__pycache__/source.cpython-39.pyc,, +py/_code/_assertionnew.py,sha256=52ADFyZkW2aks5iFFKStINwz_2fFTomBBz40AplZ4vI,11450 +py/_code/_assertionold.py,sha256=HaDKP9esnh95ZUTZRH2gUcjGFHK4MAHi8Bk18rFBycA,17869 +py/_code/_py2traceback.py,sha256=QdRC-rUpHkhtfRq5EuBub-y6Tna_Z5BlXqBYtvf0-hE,2765 +py/_code/assertion.py,sha256=UgPH8qihF0qOIWGK-DR-usrJZztz-Njj-0cBuuqwjug,3174 +py/_code/code.py,sha256=5fTjcWOdqd8Xm37g82knNL2uK4ymp9yLpnmQrc9uWzI,27492 +py/_code/source.py,sha256=hZIzxUbKhgOElxeaiYlxEisxOevfg_OgxugXxpbMmGA,14050 +py/_error.py,sha256=59i7uYaoQlEB1QyRakvuIHh09fKGAOC521R4Rb1KVcI,2917 +py/_io/__init__.py,sha256=mroFkl-vhr0GhoOU33DR8CW5a23AmWEMkYd0Xkrn9gQ,29 +py/_io/__pycache__/__init__.cpython-39.pyc,, +py/_io/__pycache__/capture.cpython-39.pyc,, +py/_io/__pycache__/saferepr.cpython-39.pyc,, +py/_io/__pycache__/terminalwriter.cpython-39.pyc,, +py/_io/capture.py,sha256=UD23HRIjE9sZs70RaPJj5Zk8XlKSqJpqMR8-AqlOv80,11652 +py/_io/saferepr.py,sha256=vPzOq5XoGYzdTf5-zn3_2ib6w4IdPP2URwenkDkMO8s,2483 +py/_io/terminalwriter.py,sha256=bKN8Gnd5gKZeXALbCLZkfzkjF-jGbXPyID_lxCGezX4,14714 +py/_log/__init__.py,sha256=2GE1ao7mud57-K6VXgmItZJsMDJBR500Xj7_-ou_jY4,74 +py/_log/__pycache__/__init__.cpython-39.pyc,, +py/_log/__pycache__/log.cpython-39.pyc,, +py/_log/__pycache__/warning.cpython-39.pyc,, +py/_log/log.py,sha256=arQ8lvZUIPlwDo6ffg6lNvAQ0x8U1yPRhkMLtHUQKx8,6003 +py/_log/warning.py,sha256=wufxpNU8YBXKNNcCZsZnaJaaNuKEjuvsIa1V-HE6YIk,2565 +py/_path/__init__.py,sha256=uBkaNhYAPiTOe8cj8WWD7rpM06XR6H0E3KghK6MgBpA,32 +py/_path/__pycache__/__init__.cpython-39.pyc,, +py/_path/__pycache__/cacheutil.cpython-39.pyc,, +py/_path/__pycache__/common.cpython-39.pyc,, +py/_path/__pycache__/local.cpython-39.pyc,, +py/_path/__pycache__/svnurl.cpython-39.pyc,, +py/_path/__pycache__/svnwc.cpython-39.pyc,, +py/_path/cacheutil.py,sha256=jQ0wk4Goqr_bIE8wGdr-CTiMD6dpcgdqyngGmMO48pY,3333 +py/_path/common.py,sha256=EC18Pl6zYGGMzHkDgGNbLC2W23ajtDwHMJOm3jNMdOA,14818 +py/_path/local.py,sha256=-QdTI95H2gtAPAfE4WhvRQq_2qMjlNBVRSp6_reg7kE,36759 +py/_path/svnurl.py,sha256=OC0w9p_pNpSncwgvD61Pcr4r2NrFztYb-OngD8RzNi8,14715 +py/_path/svnwc.py,sha256=IKJkzNwevB7zxxW9OIhH5n4wesAnJQcJTgxjxdgcqUk,43825 +py/_process/__init__.py,sha256=e7LQPDo7Q-LR9VjcRithvT4UoszeZ80NEeUvc9j4H-o,40 +py/_process/__pycache__/__init__.cpython-39.pyc,, +py/_process/__pycache__/cmdexec.cpython-39.pyc,, +py/_process/__pycache__/forkedfunc.cpython-39.pyc,, +py/_process/__pycache__/killproc.cpython-39.pyc,, +py/_process/cmdexec.py,sha256=bTtnRydYMvW5w-K_qzRRRgycU8p4IfWQB5ymzLXMdkU,1814 +py/_process/forkedfunc.py,sha256=ZTGHp8kp5Z1icj0TonoPRmpcm64pyaVVfiRC9c5TnGU,3692 +py/_process/killproc.py,sha256=0fj_w_A8Mi_ZBJd9Koy_NnmMNoNYttb713943WxTVxw,648 +py/_std.py,sha256=JnzTePDF0TNzPKjYHIRMKwuwzE6bvLOV8q9r7FlLZZ8,668 +py/_vendored_packages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +py/_vendored_packages/__pycache__/__init__.cpython-39.pyc,, +py/_vendored_packages/apipkg-2.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +py/_vendored_packages/apipkg-2.0.0.dist-info/LICENSE,sha256=6J7tEHTTqUMZi6E5uAhE9bRFuGC7p0qK6twGEFZhZOo,1054 +py/_vendored_packages/apipkg-2.0.0.dist-info/METADATA,sha256=GqNwkxraK5UTxObLVXTLc2UqktOPwZnKqdk2ThzHX0A,4292 +py/_vendored_packages/apipkg-2.0.0.dist-info/RECORD,sha256=VqARwZMQSTLsSY4QcLChtdNYtH1_llKRb1sGiK7wRm4,801 +py/_vendored_packages/apipkg-2.0.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +py/_vendored_packages/apipkg-2.0.0.dist-info/WHEEL,sha256=WzZ8cwjh8l0jtULNjYq1Hpr-WCqCRgPr--TX4P5I1Wo,110 +py/_vendored_packages/apipkg-2.0.0.dist-info/top_level.txt,sha256=3TGS6nmN7kjxhUK4LpPCB3QkQI34QYGrT0ZQGWajoZ8,7 +py/_vendored_packages/apipkg/__init__.py,sha256=gpbD3O57S9f-LsO2e-XwI6IGISayicfnCq3B5y_8frg,6978 +py/_vendored_packages/apipkg/__pycache__/__init__.cpython-39.pyc,, +py/_vendored_packages/apipkg/__pycache__/version.cpython-39.pyc,, +py/_vendored_packages/apipkg/version.py,sha256=bgZFg-f3UKhgE-z2w8RoFrwqRBzJBZkM4_jKFiYB9eU,142 +py/_vendored_packages/iniconfig-1.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +py/_vendored_packages/iniconfig-1.1.1.dist-info/LICENSE,sha256=KvaAw570k_uCgwNW0dPfGstaBgM8ui3sehniHKp3qGY,1061 +py/_vendored_packages/iniconfig-1.1.1.dist-info/METADATA,sha256=_4-oFKpRXuZv5rzepScpXRwhq6DzqsgbnA5ZpgMUMcs,2405 +py/_vendored_packages/iniconfig-1.1.1.dist-info/RECORD,sha256=13Pl7e4y-9Te0285E_6IMvnDQzT4NawZCXhkodtXlk4,863 +py/_vendored_packages/iniconfig-1.1.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +py/_vendored_packages/iniconfig-1.1.1.dist-info/WHEEL,sha256=ADKeyaGyKF5DwBNE0sRE5pvW-bSkFMJfBuhzZ3rceP4,110 +py/_vendored_packages/iniconfig-1.1.1.dist-info/top_level.txt,sha256=7KfM0fugdlToj9UW7enKXk2HYALQD8qHiyKtjhSzgN8,10 +py/_vendored_packages/iniconfig/__init__.py,sha256=-pBe5AF_6aAwo1CxJQ8i_zJq6ejc6IxHta7qk2tNJhY,5208 +py/_vendored_packages/iniconfig/__init__.pyi,sha256=-4KOctzq28ohRmTZsqlH6aylyFqsNKxYqtk1dteypi4,1205 +py/_vendored_packages/iniconfig/__pycache__/__init__.cpython-39.pyc,, +py/_vendored_packages/iniconfig/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +py/_version.py,sha256=Xs0eR54RO9PHie_bsnHE9MaEmKMBiyxDAkf-poAVEX0,144 +py/_xmlgen.py,sha256=y-PCg1hZpIozJi7GXSRZv6saT_0nnNZ2D-6ue_A2xww,8364 +py/error.pyi,sha256=fQOaF1TOx_pK1StqWC_6d6DAGzSuPJ6vR6Fd_5lRol0,3409 +py/iniconfig.pyi,sha256=-4KOctzq28ohRmTZsqlH6aylyFqsNKxYqtk1dteypi4,1205 +py/io.pyi,sha256=nuC3RIVMXOp-xsaXBbPYNZHxzcCEHgDdIpS9yRmJR-g,5277 +py/path.pyi,sha256=OmDEqkp756dcWHq10Gwaw8pXtIABAdbg9mSAUCQPPyk,7168 +py/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +py/test.py,sha256=1VLPdbBKEOai2WAKABJAbVdRfcJxtff2x2mXNmQgDL8,222 +py/xml.pyi,sha256=SBnALd6w7VwqrGYtEm4ESJ_u9iD7LVH7LWFZ3Y7xAoo,787 diff --git a/venv/Lib/site-packages/py-1.11.0.dist-info/WHEEL b/venv/Lib/site-packages/py-1.11.0.dist-info/WHEEL new file mode 100644 index 0000000..b733a60 --- /dev/null +++ b/venv/Lib/site-packages/py-1.11.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/py-1.11.0.dist-info/top_level.txt b/venv/Lib/site-packages/py-1.11.0.dist-info/top_level.txt new file mode 100644 index 0000000..edfce78 --- /dev/null +++ b/venv/Lib/site-packages/py-1.11.0.dist-info/top_level.txt @@ -0,0 +1 @@ +py diff --git a/venv/Lib/site-packages/pygame-2.1.2.dist-info/INSTALLER b/venv/Lib/site-packages/pygame-2.1.2.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/pygame-2.1.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/pygame-2.1.2.dist-info/METADATA b/venv/Lib/site-packages/pygame-2.1.2.dist-info/METADATA new file mode 100644 index 0000000..5675b46 --- /dev/null +++ b/venv/Lib/site-packages/pygame-2.1.2.dist-info/METADATA @@ -0,0 +1,228 @@ +Metadata-Version: 2.1 +Name: pygame +Version: 2.1.2 +Summary: Python Game Development +Home-page: https://www.pygame.org +Author: A community project. +Author-email: pygame@pygame.org +License: LGPL +Project-URL: Documentation, https://pygame.org/docs +Project-URL: Bug Tracker, https://github.com/pygame/pygame/issues +Project-URL: Source, https://github.com/pygame/pygame +Project-URL: Twitter, https://twitter.com/pygame_org +Platform: UNKNOWN +Classifier: Development Status :: 6 - Mature +Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) +Classifier: Programming Language :: Assembly +Classifier: Programming Language :: C +Classifier: Programming Language :: Cython +Classifier: Programming Language :: Objective C +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Games/Entertainment +Classifier: Topic :: Multimedia :: Sound/Audio +Classifier: Topic :: Multimedia :: Sound/Audio :: MIDI +Classifier: Topic :: Multimedia :: Sound/Audio :: Players +Classifier: Topic :: Multimedia :: Graphics +Classifier: Topic :: Multimedia :: Graphics :: Capture :: Digital Camera +Classifier: Topic :: Multimedia :: Graphics :: Capture :: Screen Capture +Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion +Classifier: Topic :: Multimedia :: Graphics :: Viewers +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: POSIX +Classifier: Operating System :: Unix +Classifier: Operating System :: MacOS +Requires-Python: >=3.6 +Description-Content-Type: text/x-rst + +.. image:: https://raw.githubusercontent.com/pygame/pygame/main/docs/pygame_logo.svg + :alt: pygame + :target: https://www.pygame.org/ + + +|AppVeyorBuild| |PyPiVersion| |PyPiLicense| +|Python3| |GithubCommits| |LGTMAlerts| |LGTMGradePython| |LGTMGradeC| + +pygame_ is a free and open-source cross-platform library +for the development of multimedia applications like video games using Python. +It uses the `Simple DirectMedia Layer library`_ and several other +popular libraries to abstract the most common functions, making writing +these programs a more intuitive task. + +`We need your help`_ to make pygame the best it can be! +New contributors are welcome. + + +Installation +------------ + +:: + + pip install pygame + + +Help +---- + +If you are just getting started with pygame, you should be able to +get started fairly quickly. Pygame comes with many tutorials and +introductions. There is also full reference documentation for the +entire library. Browse the documentation on the `docs page`_. + +The online documentation stays up to date with the development version +of pygame on github. This may be a bit newer than the version of pygame +you are using. To upgrade to the latest full release, run +``pip install pygame --upgrade`` in your terminal. + +Best of all, the examples directory has many playable small programs +which can get you started playing with the code right away. + + +Building From Source +-------------------- + +If you want to use features that are currently in development, +or you want to contribute to pygame, you will need to build pygame +locally from its source code, rather than pip installing it. + +Installing from source is fairly automated. The most work will +involve compiling and installing all the pygame dependencies. Once +that is done, run the ``setup.py`` script which will attempt to +auto-configure, build, and install pygame. + +Much more information about installing and compiling is available +on the `Compilation wiki page`_. + + +Credits +------- + +Thanks to everyone who has helped contribute to this library. +Special thanks are also in order. + +* Marcus Von Appen: many changes, and fixes, 1.7.1+ freebsd maintainer +* Lenard Lindstrom: the 1.8+ windows maintainer, many changes, and fixes +* Brian Fisher for svn auto builder, bug tracker and many contributions +* Rene Dudfield: many changes, and fixes, 1.7+ release manager/maintainer +* Phil Hassey for his work on the pygame.org website +* DR0ID for his work on the sprite module +* Richard Goedeken for his smoothscale function +* Ulf Ekström for his pixel perfect collision detection code +* Pete Shinners: original author +* David Clark for filling the right-hand-man position +* Ed Boraas and Francis Irving: Debian packages +* Maxim Sobolev: FreeBSD packaging +* Bob Ippolito: MacOS and OS X porting (much work!) +* Jan Ekhol, Ray Kelm, and Peter Nicolai: putting up with early design ideas +* Nat Pryce for starting our unit tests +* Dan Richter for documentation work +* TheCorruptor for his incredible logos and graphics +* Nicholas Dudfield: many test improvements +* Alex Folkner for pygame-ctypes + +Thanks to those sending in patches and fixes: Niki Spahiev, Gordon +Tyler, Nathaniel Pryce, Dave Wallace, John Popplewell, Michael Urman, +Andrew Straw, Michael Hudson, Ole Martin Bjoerndalen, Herve Cauwelier, +James Mazer, Lalo Martins, Timothy Stranex, Chad Lester, Matthias +Spiller, Bo Jangeborg, Dmitry Borisov, Campbell Barton, Diego Essaya, +Eyal Lotem, Regis Desgroppes, Emmanuel Hainry, Randy Kaelber +Matthew L Daniel, Nirav Patel, Forrest Voight, Charlie Nolan, +Frankie Robertson, John Krukoff, Lorenz Quack, Nick Irvine, +Michael George, Saul Spatz, Thomas Ibbotson, Tom Rothamel, Evan Kroske, +Cambell Barton. + +And our bug hunters above and beyond: Angus, Guillaume Proux, Frank +Raiser, Austin Henry, Kaweh Kazemi, Arturo Aldama, Mike Mulcheck, +Michael Benfield, David Lau + +There's many more folks out there who've submitted helpful ideas, kept +this project going, and basically made our life easier. Thanks! + +Many thank you's for people making documentation comments, and adding to the +pygame.org wiki. + +Also many thanks for people creating games and putting them on the +pygame.org website for others to learn from and enjoy. + +Lots of thanks to James Paige for hosting the pygame bugzilla. + +Also a big thanks to Roger Dingledine and the crew at SEUL.ORG for our +excellent hosting. + +Dependencies +------------ + +Pygame is obviously strongly dependent on SDL and Python. It also +links to and embeds several other smaller libraries. The font +module relies on SDL_ttf, which is dependent on freetype. The mixer +(and mixer.music) modules depend on SDL_mixer. The image module +depends on SDL_image, which also can use libjpeg and libpng. The +transform module has an embedded version of SDL_rotozoom for its +own rotozoom function. The surfarray module requires the Python +NumPy package for its multidimensional numeric arrays. +Dependency versions: + +* CPython >= 3.6 or PyPy3 +* SDL >= 2.0.0 +* SDL_mixer >= 2.0.0 +* SDL_image >= 2.0.0 +* SDL_ttf >= 2.0.11 +* SDL_gfx (optional, vendored in) +* NumPy >= 1.6.2 (optional) + + +License +------- + +This library is distributed under `GNU LGPL version 2.1`_, which can +be found in the file ``docs/LGPL.txt``. We reserve the right to place +future versions of this library under a different license. + +This basically means you can use pygame in any project you want, +but if you make any changes or additions to pygame itself, those +must be released with a compatible license (preferably submitted +back to the pygame project). Closed source and commercial games are fine. + +The programs in the ``examples`` subdirectory are in the public domain. + +See docs/licenses for licenses of dependencies. + + +.. |AppVeyorBuild| image:: https://ci.appveyor.com/api/projects/status/x4074ybuobsh4myx?svg=true + :target: https://ci.appveyor.com/project/pygame/pygame + +.. |PyPiVersion| image:: https://img.shields.io/pypi/v/pygame.svg?v=1 + :target: https://pypi.python.org/pypi/pygame + +.. |PyPiLicense| image:: https://img.shields.io/pypi/l/pygame.svg?v=1 + :target: https://pypi.python.org/pypi/pygame + +.. |Python3| image:: https://img.shields.io/badge/python-3-blue.svg?v=1 + +.. |GithubCommits| image:: https://img.shields.io/github/commits-since/pygame/pygame/2.1.2.svg + :target: https://github.com/pygame/pygame/compare/2.1.2...main + +.. |LGTMAlerts| image:: https://img.shields.io/lgtm/alerts/g/pygame/pygame.svg?logo=lgtm&logoWidth=18 + :target: https://lgtm.com/projects/g/pygame/pygame/alerts/ + +.. |LGTMGradePython| image:: https://img.shields.io/lgtm/grade/python/g/pygame/pygame.svg?logo=lgtm&logoWidth=18 + :target: https://lgtm.com/projects/g/pygame/pygame/context:python + +.. |LGTMGradeC| image:: https://img.shields.io/lgtm/grade/cpp/g/pygame/pygame.svg?logo=lgtm&logoWidth=18 + :target: https://lgtm.com/projects/g/pygame/pygame/context:cpp + +.. _pygame: https://www.pygame.org +.. _Simple DirectMedia Layer library: https://www.libsdl.org +.. _We need your help: https://www.pygame.org/contribute.html +.. _Compilation wiki page: https://www.pygame.org/wiki/Compilation +.. _docs page: https://www.pygame.org/docs/ +.. _GNU LGPL version 2.1: https://www.gnu.org/copyleft/lesser.html + + diff --git a/venv/Lib/site-packages/pygame-2.1.2.dist-info/RECORD b/venv/Lib/site-packages/pygame-2.1.2.dist-info/RECORD new file mode 100644 index 0000000..8780b6b --- /dev/null +++ b/venv/Lib/site-packages/pygame-2.1.2.dist-info/RECORD @@ -0,0 +1,747 @@ +../../include/site/python3.9/pygame/_camera.h,sha256=T0VYAfQxm0c4zww_BZaJGz4exa4z0FdEf3RSN_W2E-E,839 +../../include/site/python3.9/pygame/_pygame.h,sha256=CikuDYKerHeppUL-DykqiRwxdLBATvWbUWYL0hfV30o,9562 +../../include/site/python3.9/pygame/_surface.h,sha256=Bbi9rW0SqwGs6THID0l6eB5d-5h-kxW7517TdqoxEZM,957 +../../include/site/python3.9/pygame/camera.h,sha256=M4aRsLhiFgaEeGEWGltpkFtMAfgMS51tJ43yu46wcw0,6548 +../../include/site/python3.9/pygame/font.h,sha256=VHcKhYtIHduegTXEf1hbmbxCwN5IrqsJch2HaxEtB6I,348 +../../include/site/python3.9/pygame/freetype.h,sha256=LbGY6saj9oakyoeGSlWlirSHySOpeoTKKOF-DO4zLRs,3245 +../../include/site/python3.9/pygame/include/_pygame.h,sha256=_12ZQTJT7buO_nJkvP1wd7_WXunpJ8_mJimyvWoLHNQ,15800 +../../include/site/python3.9/pygame/include/bitmask.h,sha256=tGzYwZ407sMIHDQG7xeXBQCRmhZZ4wp-yTerhUmIlCU,4952 +../../include/site/python3.9/pygame/include/pgcompat.h,sha256=Yi3MQsneRDFCdjDxhRn2XmergYYaT-oTFRfsVJG-IX4,2019 +../../include/site/python3.9/pygame/include/pgimport.h,sha256=p3W2we9tyxK3VhBxn3_BjUVUdBeo_EReehUMPgtYdj4,2927 +../../include/site/python3.9/pygame/include/pgplatform.h,sha256=VkD2qNRPrDibskbApL_W2xa_YJFXDiE4TIfu9_MgN1Y,2478 +../../include/site/python3.9/pygame/include/pygame.h,sha256=OsEc_zNPFlXo4owOhGRqH4cbuYMtNJ_7K9d_Te--OEU,1245 +../../include/site/python3.9/pygame/include/pygame_bufferproxy.h,sha256=Poh7HsIjugo3NFeKjItZe40_BavF5V7re8bVFjkpmfU,1834 +../../include/site/python3.9/pygame/include/pygame_font.h,sha256=JKPbDFQdh_BAuz5F9S37iBSZbfjnL2scUlkS1geLd4s,1501 +../../include/site/python3.9/pygame/include/pygame_freetype.h,sha256=VNyvy7xukNOXymg3IMZne9-iVu3sI5LvKLagfkWpKAk,1346 +../../include/site/python3.9/pygame/include/pygame_mask.h,sha256=ONXIz3M3MPF4BlPSS2xRquysEYjZZf7AP2JRro8j4I0,1303 +../../include/site/python3.9/pygame/include/pygame_mixer.h,sha256=HthA7STa9TLomwQQswroyAmAd72pywDu_UCLfIV71is,2021 +../../include/site/python3.9/pygame/include/sse2neon.h,sha256=DcazZmLfny6MVJFIUlWbsdI39ZWQWGwmCJDuFEVZsw0,237885 +../../include/site/python3.9/pygame/mask.h,sha256=Y7OqzNUqQQHchUsSlvd-ja5d9IgAfSV2uFlaa8_5Lys,153 +../../include/site/python3.9/pygame/mixer.h,sha256=HJMd0Ho0DrdGBdPMDo_egSqkVxZnUZPMEQyPJMIw6_M,348 +../../include/site/python3.9/pygame/palette.h,sha256=dzARYIsQdHAaV8ypCrQbYRWFisXYXABD4ToMlzYKojg,7057 +../../include/site/python3.9/pygame/pgarrinter.h,sha256=alsw7p6X7ukOB1o3curyrjWOcGHgVCQgCvS1D9FtiRc,1060 +../../include/site/python3.9/pygame/pgbufferproxy.h,sha256=tqMDkdkH40QoYJ3NtTjiknAnSMh0i1sfNMaow3npvKI,179 +../../include/site/python3.9/pygame/pgcompat.h,sha256=4bEjh9FGMhxpEEq6KMO-nKXEzyEH6z6QjqA3lVXoMx0,1597 +../../include/site/python3.9/pygame/pgopengl.h,sha256=bbIysbLph5paPfeE2nnrQBIrq8iZz4T4pGfz2mYPuRw,606 +../../include/site/python3.9/pygame/pgplatform.h,sha256=K25oz-likyqlYgKmlqtVVW-wOb8Pqsd8yu4xXFDBHUA,956 +../../include/site/python3.9/pygame/pygame.h,sha256=AQcZWIoAWGmN9fYBynCXxc81hd9lcwxBwWeq8WZjTKE,1083 +../../include/site/python3.9/pygame/scrap.h,sha256=dfD-C8y2VbdoW-iJhWDMATBakwA3p0KFffXQXDtSJ28,4704 +../../include/site/python3.9/pygame/surface.h,sha256=3uku5zs5pTotf5dydrtMu1Vot1F_W9LXMp_gsLcxb4Q,14452 +pygame-2.1.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pygame-2.1.2.dist-info/METADATA,sha256=k79RWBp5mg3gPKwQR2XnkNx4H1loAbcqiRgvEZBsMlE,9144 +pygame-2.1.2.dist-info/RECORD,, +pygame-2.1.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pygame-2.1.2.dist-info/WHEEL,sha256=fVcVlLzi8CGi_Ul8vjMdn8gER25dn5GBg9E6k9z41-Y,100 +pygame-2.1.2.dist-info/entry_points.txt,sha256=ecT3iHcE_RL35uzQ2sXUdmOZbqq1XtPQNmbotP1FOQY,64 +pygame-2.1.2.dist-info/top_level.txt,sha256=ABXdFGIAE2g9m2VOzQPaLa917r6XEu6d96RqIzvAWCs,7 +pygame/SDL2.dll,sha256=80zZCxMc60W38y1BaAoT_UsT5fSPDRZJy_RBgzEFMQw,2227712 +pygame/SDL2_image.dll,sha256=HjZK91_uDINQb739TVsOOGxOnGoz3b3axh3bEx42AZQ,125440 +pygame/SDL2_mixer.dll,sha256=kA7rabZyZpRvVBvG2lRg5sue1PkoFqFxCoRiWtEjgIw,123904 +pygame/SDL2_ttf.dll,sha256=UH3IqXfVQ7Pga9P85B9XWdZLKyGugpzS70G3e_ZpaMQ,33792 +pygame/__init__.py,sha256=1fYUjwATVywvryFZrU4tcWOIMWPlEf7at3ax87U1AUQ,10287 +pygame/__init__.pyi,sha256=OnbBT0SMG4QZJDkzBHqgdDEIaIGvMi3GHX3AQj6eqK0,2390 +pygame/__pycache__/__init__.cpython-39.pyc,, +pygame/__pycache__/_camera_opencv.cpython-39.pyc,, +pygame/__pycache__/_camera_vidcapture.cpython-39.pyc,, +pygame/__pycache__/camera.cpython-39.pyc,, +pygame/__pycache__/colordict.cpython-39.pyc,, +pygame/__pycache__/cursors.cpython-39.pyc,, +pygame/__pycache__/draw_py.cpython-39.pyc,, +pygame/__pycache__/fastevent.cpython-39.pyc,, +pygame/__pycache__/freetype.cpython-39.pyc,, +pygame/__pycache__/ftfont.cpython-39.pyc,, +pygame/__pycache__/locals.cpython-39.pyc,, +pygame/__pycache__/macosx.cpython-39.pyc,, +pygame/__pycache__/midi.cpython-39.pyc,, +pygame/__pycache__/pkgdata.cpython-39.pyc,, +pygame/__pycache__/sndarray.cpython-39.pyc,, +pygame/__pycache__/sprite.cpython-39.pyc,, +pygame/__pycache__/surfarray.cpython-39.pyc,, +pygame/__pycache__/sysfont.cpython-39.pyc,, +pygame/__pycache__/version.cpython-39.pyc,, +pygame/__pyinstaller/__init__.py,sha256=-c4Zo8nQGKAm8wc_LDscxMtK7zr_YhZwRnC9CMruUBE,72 +pygame/__pyinstaller/__pycache__/__init__.cpython-39.pyc,, +pygame/__pyinstaller/__pycache__/hook-pygame.cpython-39.pyc,, +pygame/__pyinstaller/hook-pygame.py,sha256=2aLZ6jkeJe_bNqFAU98vgNc2xeJl4X_anExEn7rp_xo,1367 +pygame/_camera.cp39-win_amd64.pyd,sha256=JeBNO3GghLCsoFeYdiK3A3zz7AabHLPh8ELO9aBIsgc,31232 +pygame/_camera_opencv.py,sha256=oUb_Rf3PKDJpcryavpOAB1__6ZGE5XrqkVqo4cc_vOU,4386 +pygame/_camera_vidcapture.py,sha256=MJih74Ya6djH-mZZj4OYfRKJOH-SD0VUHNaUcxwX7N8,3402 +pygame/_common.pyi,sha256=EQ6zBPsEITU8rgzSW9PFJAzlaOQusBBYySDXFSAzVLs,956 +pygame/_freetype.cp39-win_amd64.pyd,sha256=5ejPr4_L1vFfk7ja3MZj-L2ViWr4PG8oj94Xzw9zlj4,78336 +pygame/_sdl2/__init__.py,sha256=gmSh3cXyxHqEXwbck_mNOmoW--itmGMwonEHQnY49Zo,248 +pygame/_sdl2/__init__.pyi,sha256=YGq944qutqf59Mv4nSzlRI2CfpbfBTiPPkd7bEw-PZ8,33 +pygame/_sdl2/__pycache__/__init__.cpython-39.pyc,, +pygame/_sdl2/audio.cp39-win_amd64.pyd,sha256=5r5Qm7QH0uKB17BOrtXjgQj9-NGl7Z2vUF3Lz0nosuE,139776 +pygame/_sdl2/controller.cp39-win_amd64.pyd,sha256=hdXxT1q1_qB13gpACFD0fqa9l3IB4JXPCL9od0PW6as,71680 +pygame/_sdl2/controller.pyi,sha256=-GgY9eKV3vuuJlTd2Vor9Wt8v0hN1UPmBjTr6W8aplU,1039 +pygame/_sdl2/mixer.cp39-win_amd64.pyd,sha256=WnucSy-IReWD8BNot55OSKgEwJ6nAny3txIypPgdvfw,121344 +pygame/_sdl2/sdl2.cp39-win_amd64.pyd,sha256=h43bkh8ZkFWkq0e4b1s4B71R4bDs3j_DKDTfZ-Tn6X8,36864 +pygame/_sdl2/touch.cp39-win_amd64.pyd,sha256=AxMtDH4GtycpbDGO9zxUsXzWxQu30OgDoAv1wdp4WwI,13824 +pygame/_sdl2/touch.pyi,sha256=-vYGJsSC18E2gitH10HIv_V_DUc6DIeCb55zuQp3jPc,231 +pygame/_sdl2/video.cp39-win_amd64.pyd,sha256=wTKdVV65VEKIvj-K65B_azFxN31bbeMhps6Jsesk4qQ,184320 +pygame/_sdl2/video.pyi,sha256=Rs6qO6xdcRHGY85eKzaQbT6GlTTRE53zIj1fFtfsNvY,4443 +pygame/_sprite.cp39-win_amd64.pyd,sha256=Pwx9-CBzerxe34bObILLnbp12rmPeXdlsEKuOFumNks,251904 +pygame/base.cp39-win_amd64.pyd,sha256=WOQA21Km-Jc3EHc-BHXan2ZFHHiB1SU8D1Ge_K4vbQk,30720 +pygame/bufferproxy.cp39-win_amd64.pyd,sha256=btTZTqctU_B2uf04c_YMabQf3UZen97icJsVbHJ0PSM,18432 +pygame/bufferproxy.pyi,sha256=aES-Sa035yvUZRj4dc7Y0Y5XFpyazzlBO7xkBfQKs-w,271 +pygame/camera.py,sha256=t3-tRPygmpezwOCTwp8wcqqlqD99tHI_3ZPXOjOjuFI,4496 +pygame/camera.pyi,sha256=1-83dS-kpbPnt_7uSLQlaXblf31kWDE9IPbRZ0XEPXA,885 +pygame/color.cp39-win_amd64.pyd,sha256=N3pTiWHYUtMu8rrhTzNPQhdt5FbF8IzMW7w5MSqcayw,35328 +pygame/color.pyi,sha256=7tbA3I5P0AAXgccUhXbBeYA6GrZI17jLjq40SPP2P58,1476 +pygame/colordict.py,sha256=xS-mwTxatoVa3Howpp53otRNZ3p-b1MzZChlvy0cuic,25773 +pygame/constants.cp39-win_amd64.pyd,sha256=sR_pbGcM6iZI5D68vQ_nlCreq3pmWap5Qy3jPI0TJhg,49152 +pygame/constants.pyi,sha256=JXis8T-vJqjvJVmI1skNg0Ofmq1EUfpE4DXwwoEMfm4,9852 +pygame/cursors.py,sha256=Tg7Qo2LkmH6miYCNmlq1kHrF99r3CTgOBlVsRD56-O4,18203 +pygame/cursors.pyi,sha256=LrV2FL07nz-URidMq_ME1QN-LO01LcNYO3tT2cYZ21o,1829 +pygame/display.cp39-win_amd64.pyd,sha256=g-kOurtXheSljS6Mz15AXwJ9_sQAnnhWcpmRzzS1Xac,44032 +pygame/display.pyi,sha256=McfbuPD2mfnGyDqRd5WFYETxiAWSZvfeZ2C8qd3Cy24,2025 +pygame/docs/__main__.py,sha256=hDDCEJ6Jhts8k7dKgdAPTTx91X4COGtKCPiac1H-5q0,1020 +pygame/docs/__pycache__/__main__.cpython-39.pyc,, +pygame/docs/generated/_images/AdvancedInputOutput1.gif,sha256=uSCxW5dFtO7PYQyoJglWJTe_aRYFfOav5DjnPkKBzKg,5649 +pygame/docs/generated/_images/AdvancedInputOutput11.gif,sha256=uSCxW5dFtO7PYQyoJglWJTe_aRYFfOav5DjnPkKBzKg,5649 +pygame/docs/generated/_images/AdvancedInputOutput2.gif,sha256=2UMDweIgRefzHFTJcJgbDsWgy-SlyOYaw2AKD6NKwmM,72233 +pygame/docs/generated/_images/AdvancedInputOutput21.gif,sha256=2UMDweIgRefzHFTJcJgbDsWgy-SlyOYaw2AKD6NKwmM,72233 +pygame/docs/generated/_images/AdvancedInputOutput3.gif,sha256=ez4Y7Yy0LsNH6UPYybfGckLmzutcLh7VIisajgFa4O8,6294 +pygame/docs/generated/_images/AdvancedInputOutput31.gif,sha256=ez4Y7Yy0LsNH6UPYybfGckLmzutcLh7VIisajgFa4O8,6294 +pygame/docs/generated/_images/AdvancedInputOutput4.gif,sha256=2-rK9cGngrgpJLW404oI3lG4NQnoT-UNwzA3Up48YIc,29185 +pygame/docs/generated/_images/AdvancedInputOutput41.gif,sha256=2-rK9cGngrgpJLW404oI3lG4NQnoT-UNwzA3Up48YIc,29185 +pygame/docs/generated/_images/AdvancedInputOutput5.gif,sha256=C6N4d_JD4QNMjLwPdINCOFWufyD4vM7b5LpR2GaHMcY,37349 +pygame/docs/generated/_images/AdvancedInputOutput51.gif,sha256=C6N4d_JD4QNMjLwPdINCOFWufyD4vM7b5LpR2GaHMcY,37349 +pygame/docs/generated/_images/AdvancedOutputAlpha1.gif,sha256=MH3CmK658WpN_u56GL9CV4YMFky9GLaKh0CAcixkMrA,14915 +pygame/docs/generated/_images/AdvancedOutputAlpha11.gif,sha256=MH3CmK658WpN_u56GL9CV4YMFky9GLaKh0CAcixkMrA,14915 +pygame/docs/generated/_images/AdvancedOutputAlpha2.gif,sha256=9E2YAIULWHZsAELfqLf5gdqL7-uE-Ebg4uqKgbSyVYk,71819 +pygame/docs/generated/_images/AdvancedOutputAlpha21.gif,sha256=9E2YAIULWHZsAELfqLf5gdqL7-uE-Ebg4uqKgbSyVYk,71819 +pygame/docs/generated/_images/AdvancedOutputAlpha3.gif,sha256=7gHdbhSKaUpyXgOC7GSusTdN7oJQvjGFY_o8DQNZ2Fc,30380 +pygame/docs/generated/_images/AdvancedOutputAlpha31.gif,sha256=7gHdbhSKaUpyXgOC7GSusTdN7oJQvjGFY_o8DQNZ2Fc,30380 +pygame/docs/generated/_images/AdvancedOutputProcess1.gif,sha256=QihTI3ThxtEnPjQ0qZaYF4rKj5GxSwDfFgfUmFjvcOw,15951 +pygame/docs/generated/_images/AdvancedOutputProcess11.gif,sha256=QihTI3ThxtEnPjQ0qZaYF4rKj5GxSwDfFgfUmFjvcOw,15951 +pygame/docs/generated/_images/AdvancedOutputProcess2.gif,sha256=qP09Je0xWwST1CoAs9BCy7_vq6OB69opna8kejTln50,1868 +pygame/docs/generated/_images/AdvancedOutputProcess21.gif,sha256=qP09Je0xWwST1CoAs9BCy7_vq6OB69opna8kejTln50,1868 +pygame/docs/generated/_images/AdvancedOutputProcess3.gif,sha256=4WhoBbEheizUdZfs_pFEBGGAm9aoetw3tJhgcNgVIyY,1912 +pygame/docs/generated/_images/AdvancedOutputProcess31.gif,sha256=4WhoBbEheizUdZfs_pFEBGGAm9aoetw3tJhgcNgVIyY,1912 +pygame/docs/generated/_images/AdvancedOutputProcess4.gif,sha256=m-gUJNOn6AuXT7FpKF6HRR8A6ytWorY9Y07N2uZaSIQ,14500 +pygame/docs/generated/_images/AdvancedOutputProcess41.gif,sha256=m-gUJNOn6AuXT7FpKF6HRR8A6ytWorY9Y07N2uZaSIQ,14500 +pygame/docs/generated/_images/AdvancedOutputProcess5.gif,sha256=GCi9KGUIhQTFg-HLEnp2GEgrnQl8_2KftS3N_UkuEH8,16896 +pygame/docs/generated/_images/AdvancedOutputProcess51.gif,sha256=GCi9KGUIhQTFg-HLEnp2GEgrnQl8_2KftS3N_UkuEH8,16896 +pygame/docs/generated/_images/AdvancedOutputProcess6.gif,sha256=nzV_M0JoA4aDyGwpe8lWoUFd5c1PK-WxUI-lF8WzfQQ,34058 +pygame/docs/generated/_images/AdvancedOutputProcess61.gif,sha256=nzV_M0JoA4aDyGwpe8lWoUFd5c1PK-WxUI-lF8WzfQQ,34058 +pygame/docs/generated/_images/Bagic-INPUT-resultscreen.png,sha256=RDZbxtVyFMJXdZA8wouSyJJjXf2MQ2WYTBzVotsDH88,5973 +pygame/docs/generated/_images/Bagic-INPUT-resultscreen1.png,sha256=RDZbxtVyFMJXdZA8wouSyJJjXf2MQ2WYTBzVotsDH88,5973 +pygame/docs/generated/_images/Bagic-INPUT-sourcecode.png,sha256=3F2c3AnravGgsRMxaNXlaekyqrhMl2cwYySJxhj7L0A,77061 +pygame/docs/generated/_images/Bagic-INPUT-sourcecode1.png,sha256=3F2c3AnravGgsRMxaNXlaekyqrhMl2cwYySJxhj7L0A,77061 +pygame/docs/generated/_images/Bagic-PROCESS-resultscreen.png,sha256=hQ1m6S1xhXpcaf0g50VRoOagmsiZZpUeOBx7QgG7Lqs,5348 +pygame/docs/generated/_images/Bagic-PROCESS-resultscreen1.png,sha256=hQ1m6S1xhXpcaf0g50VRoOagmsiZZpUeOBx7QgG7Lqs,5348 +pygame/docs/generated/_images/Bagic-PROCESS-sourcecode.png,sha256=vj0D6wrXFNjIHKmRFZrltZH4nH51zG6YSy94ID2fWos,66070 +pygame/docs/generated/_images/Bagic-PROCESS-sourcecode1.png,sha256=vj0D6wrXFNjIHKmRFZrltZH4nH51zG6YSy94ID2fWos,66070 +pygame/docs/generated/_images/Bagic-ouput-result-screen.png,sha256=Ig1vKczM-l0ebtdjYEHdwcJuqt8IoyUiK-RANEC065k,4819 +pygame/docs/generated/_images/Bagic-ouput-result-screen1.png,sha256=Ig1vKczM-l0ebtdjYEHdwcJuqt8IoyUiK-RANEC065k,4819 +pygame/docs/generated/_images/Basic-ouput-sourcecode.png,sha256=B6OVjvOtA2ZwiEwJyYkK1-tsGyN13y8O9kls1OYvzTo,57466 +pygame/docs/generated/_images/Basic-ouput-sourcecode1.png,sha256=B6OVjvOtA2ZwiEwJyYkK1-tsGyN13y8O9kls1OYvzTo,57466 +pygame/docs/generated/_images/camera_average.jpg,sha256=dkXZ7NdHmM69rbcYCpu0vKtqmHF3qh9nPUgZX3wlWDc,20881 +pygame/docs/generated/_images/camera_background.jpg,sha256=exoGN5fT9IKQyMJK_3VrEjfKTvr5yMeoSLCQplD0hes,7493 +pygame/docs/generated/_images/camera_green.jpg,sha256=NpIuT5qRzN5I7TFLva8m_kCAo1cwOuR5R5-Du9kaEo0,10219 +pygame/docs/generated/_images/camera_hsv.jpg,sha256=tfL0KJyxSk5A_KjVZR7MdV-qegBhej5HlXXw2CnoZR8,36673 +pygame/docs/generated/_images/camera_mask.jpg,sha256=0u0yMCldZMvSW1vyO2KK32D-fVYuYpXlNzmWwbdZ__s,18779 +pygame/docs/generated/_images/camera_rgb.jpg,sha256=GN_1jI8mnDJm1bRbjNBmpJETDSAKcVAS9BxmycYMMv0,32488 +pygame/docs/generated/_images/camera_thresh.jpg,sha256=WBYm8M-TxnuKCYEBvmu68iO_r9EYucnENZ5Ew8i6tqk,4346 +pygame/docs/generated/_images/camera_thresholded.jpg,sha256=OMh-3zXV2a-aahnMQlE7ihvxwXy1UADb15c3LzIWgh0,23678 +pygame/docs/generated/_images/camera_yuv.jpg,sha256=Gp0omp1py-_j6Qpv95VIo6EmDO2u5VY83fPWA2Rd6Bk,20105 +pygame/docs/generated/_images/chimpshot.gif,sha256=Yc_ufSFTkZ5NA1IogV2juH5Cr4_ykoI7QcXQvfGYBfc,46010 +pygame/docs/generated/_images/draw_module_example.png,sha256=fshvuNXWzZt3XL5FEmYilZ8F5xl-3CSy5lxQ-eqEhl8,7727 +pygame/docs/generated/_images/intro_ball.gif,sha256=vEs0-OG_j55JZJML48IXhHsN4ZMIWrqlS7dfxd9-hxc,5015 +pygame/docs/generated/_images/intro_blade.jpg,sha256=Aj59Tt9z1mdJeDK89HbWaQ7DVTDKbzoUDT-vNcJnYQo,2631 +pygame/docs/generated/_images/intro_freedom.jpg,sha256=RL-jChKVMdqoS7BN5NGV7hjlxSgU4qaKrj4ZXH2zsI8,7050 +pygame/docs/generated/_images/introduction-Battleship.png,sha256=6iHEhqo_HnXRfmQv9yriYMc3dX8Q2TwGbSGDQREFkN4,165586 +pygame/docs/generated/_images/introduction-Battleship1.png,sha256=6iHEhqo_HnXRfmQv9yriYMc3dX8Q2TwGbSGDQREFkN4,165586 +pygame/docs/generated/_images/introduction-PuyoPuyo.png,sha256=OEMjFSzQc8vJLQryUdkp7lJ3DhIw_yEo5-5nm2vBfrs,31388 +pygame/docs/generated/_images/introduction-PuyoPuyo1.png,sha256=OEMjFSzQc8vJLQryUdkp7lJ3DhIw_yEo5-5nm2vBfrs,31388 +pygame/docs/generated/_images/introduction-TPS.png,sha256=M4ioZMyjR2n7pQIp8UhGRV4m2V_rcXJCuo5lU3V7yGw,136031 +pygame/docs/generated/_images/introduction-TPS1.png,sha256=M4ioZMyjR2n7pQIp8UhGRV4m2V_rcXJCuo5lU3V7yGw,136031 +pygame/docs/generated/_images/joystick_calls.png,sha256=AWSPPJNhXafqoaGxi3evBCQFEcbvbS-EiqcQJqF__k4,23524 +pygame/docs/generated/_images/surfarray_allblack.png,sha256=XEUO2hKFfTfZMyaqbPvM0u3zmETfl___AANBkHn6y-w,125 +pygame/docs/generated/_images/surfarray_flipped.png,sha256=UZ1FpljGrdAnB1UCUTuAfeJJxyqI-_0duSCKqy9UN3w,50835 +pygame/docs/generated/_images/surfarray_redimg.png,sha256=6tlO_tZokQTsfgvD3yNW21nHA5uA9hDWoaL7POrr_qE,23443 +pygame/docs/generated/_images/surfarray_rgbarray.png,sha256=8US5r3GcG_jZBncK-47HG2JLB2ZwQjaSBWhb3ynNs9w,50897 +pygame/docs/generated/_images/surfarray_scaledown.png,sha256=Z68XSoPUvV5bYIhJdkmhZYr42JpQKnC8g9hmN18iaWI,15109 +pygame/docs/generated/_images/surfarray_scaleup.png,sha256=sdxQlmVoRhlF_ocD2ecre0q51Q2LLoCxNsJaI8O1NYI,67759 +pygame/docs/generated/_images/surfarray_soften.png,sha256=XNzAZzfLUqn-QIQ25TxB2ujoDZkPEIRI6QSDnjJMIk0,47540 +pygame/docs/generated/_images/surfarray_striped.png,sha256=iH7gLZhBu5aATV-vfrsQmW30KdsMQoYB_LD-efRzl_Y,392 +pygame/docs/generated/_images/surfarray_xfade.png,sha256=uD8g8Ueqc3IMZaOqiD4n4sZmg5I4j798oIzl1pWDM70,41834 +pygame/docs/generated/_images/tom_basic.png,sha256=RzKBFmep1ksfD5QrJVW7JzdHvDN1_4ayUfGyVN-8Wms,5139 +pygame/docs/generated/_images/tom_event-flowchart.png,sha256=sG8YOH8YX2yTtx4-agBUWIcT8-jj1m6uKCF98QxmbKQ,5528 +pygame/docs/generated/_images/tom_formulae.png,sha256=6k8VDsueGVOh01ZrAVLE5miliOWKhQJqIrlPW_JEmXk,6763 +pygame/docs/generated/_images/tom_radians.png,sha256=BkBTx4OoiSXO5d6sMG01MyYBtO7EmDvgJixbTRKMm9Q,17409 +pygame/docs/generated/_sources/c_api.rst.txt,sha256=42nhfRAilcsq1ezpGMlfdHLVLOy6GszORZzNplGrPSM,492 +pygame/docs/generated/_sources/filepaths.rst.txt,sha256=sou-1N5amW1JXHqwKUU0BqYQmm2c5qDjjFKVIKIppfo,899 +pygame/docs/generated/_sources/index.rst.txt,sha256=e8kO6-BbS8hlDqzthROoGHaGMIvDkycoN9Gc1OF3lvM,5190 +pygame/docs/generated/_sources/ref/bufferproxy.rst.txt,sha256=V5gSzq__85alqL5Is05MTmpDv5NUHbLuuW4PYH98MzI,4708 +pygame/docs/generated/_sources/ref/camera.rst.txt,sha256=jGe1yh6URcyLvMq4n52_IetG4hRWQxJPAHJXtQAMR3M,9563 +pygame/docs/generated/_sources/ref/cdrom.rst.txt,sha256=0FlYODuxoQOsTYpZ9EiDYmUD9PIQrAeAlsXE8I67RQk,9068 +pygame/docs/generated/_sources/ref/color.rst.txt,sha256=5fld0cemR82HhYYdSWOckR_-x58XYc_hYS35bHMS6-Q,10222 +pygame/docs/generated/_sources/ref/color_list.rst.txt,sha256=XLIKLmTx_liiWk0gdKlrElBlCNZD0_sIvAg_El6tgfE,96353 +pygame/docs/generated/_sources/ref/cursors.rst.txt,sha256=I34-Lsy054BfoHels8rEsvDPeQ4LrKRPG6cMt_v2kcA,9414 +pygame/docs/generated/_sources/ref/display.rst.txt,sha256=s_rmPPKV3ZRZKqcMDWAqgNeeBkdc9agVnCP9S8C-ZSc,28538 +pygame/docs/generated/_sources/ref/draw.rst.txt,sha256=CEFZSKX_KEAtsom-I1nafw0EEK-PlxzratVOhoIs0BA,24806 +pygame/docs/generated/_sources/ref/event.rst.txt,sha256=_9GUThqJVfqIwDnY8WoOR3Eu490DWjitTFXZMXd75NM,17626 +pygame/docs/generated/_sources/ref/examples.rst.txt,sha256=044bT9v4pQYRZqmaAwrdAI_GV3HLiwRlWHKYturVbN4,14095 +pygame/docs/generated/_sources/ref/fastevent.rst.txt,sha256=6gyem0cRZ-syKMDcQ6qexC83dJMro1O9-XHY_k2_HNg,3545 +pygame/docs/generated/_sources/ref/font.rst.txt,sha256=NuF6G-sjVET0h2oWnFTT2Mc2D1tGVCtQG6LNv1Z4RvE,14703 +pygame/docs/generated/_sources/ref/freetype.rst.txt,sha256=YPU6Ag9224LZMTpGOyeEjHcTeZb2eJJZvebNbRiOFLg,31070 +pygame/docs/generated/_sources/ref/gfxdraw.rst.txt,sha256=bQYID2bOb6xETZoDKM0mRtaCU_QD48MjQmCV8lvEErE,21842 +pygame/docs/generated/_sources/ref/image.rst.txt,sha256=Emy-SkCQClMxR3vHKyvipTgWH-cKLHMDiaCj6392--c,9544 +pygame/docs/generated/_sources/ref/joystick.rst.txt,sha256=L94TFACz01-OaO-qQrAGEAKa41g4Ql6jxzxhPRIaOuA,15523 +pygame/docs/generated/_sources/ref/key.rst.txt,sha256=DHgxo8qWMOhcQ7cPNSFlxWJmBN1pToqC2AqCz1gcX6M,14822 +pygame/docs/generated/_sources/ref/locals.rst.txt,sha256=VZi8cE2ZlPei4WdzSsok0fU_BOgPhlOmjfTCTSvl0N8,1022 +pygame/docs/generated/_sources/ref/mask.rst.txt,sha256=RAVpZZNK2i-ltHlCbNZgFa80x2RAXc_4lYkPgAVoyjs,24220 +pygame/docs/generated/_sources/ref/math.rst.txt,sha256=OVUUPjA_yd-24tDz1B_Wopn7v9XeF4IQOYHgzmToQnI,27250 +pygame/docs/generated/_sources/ref/midi.rst.txt,sha256=jIJ5qOZNvlMtBH0TA2icWTSB4_7CcUmU6_y9uVhGiak,14358 +pygame/docs/generated/_sources/ref/mixer.rst.txt,sha256=xIef_nLJUcN4jggYtRTd91iZo_oVYVDDHo-vVg5HNis,22346 +pygame/docs/generated/_sources/ref/mouse.rst.txt,sha256=VmAjwqKkTwm3RM96WW9O6xnVUJ1ZnVuS59OOQhe8Hv8,8129 +pygame/docs/generated/_sources/ref/music.rst.txt,sha256=TRWBNIajSaZWCdj82yMna5vQCFafiaju0KvKClN8Q7s,9531 +pygame/docs/generated/_sources/ref/overlay.rst.txt,sha256=loD8HVw0KQnsaPPisw_Xe8yms59CEAbdsboXwhS7zqk,2659 +pygame/docs/generated/_sources/ref/pixelarray.rst.txt,sha256=I5BlUFayOaB4wS1j8uSYAHJKRL_ErHi_CgEACnZOx_Q,10207 +pygame/docs/generated/_sources/ref/pixelcopy.rst.txt,sha256=SMb-VGMZSxBBWgAjsFg2ucaQp80KglnIo56AkS7O-vE,4531 +pygame/docs/generated/_sources/ref/pygame.rst.txt,sha256=BOv-OScRXp9bMGBCn2KnAeTFXbNE9QUfj_kZ0nd233I,14445 +pygame/docs/generated/_sources/ref/rect.rst.txt,sha256=ddBCeV756daL6s5nVyX8HOfbGTv0OlSNB9E7sBQ6iTs,13019 +pygame/docs/generated/_sources/ref/scrap.rst.txt,sha256=At1I3Htg5K0y61krT4hHiW2bOYimeOcqJs5BsLO28eI,7990 +pygame/docs/generated/_sources/ref/sdl2_controller.rst.txt,sha256=1fJFma_4t39mGIbYIyenuM8Q2XdWCAA-rPBJNsU62iU,9324 +pygame/docs/generated/_sources/ref/sdl2_video.rst.txt,sha256=3YrzdapWvu7Jy4rwvwPy0rPTdXQP4Lz44MgAtvV7hgw,9115 +pygame/docs/generated/_sources/ref/sndarray.rst.txt,sha256=9N1u6w7AxTr943nJiSUoDyNi-8qE_tWJeVU0rVEQYi0,3260 +pygame/docs/generated/_sources/ref/sprite.rst.txt,sha256=DfJlI4xKt3iuWQ_XTc727G4IHRQb6ohKxSMRo9SqVYQ,29584 +pygame/docs/generated/_sources/ref/surface.rst.txt,sha256=Z8_rxC2kannzcGdCZlvENgj_-bSTUSFdGsx2ExnuaB0,34198 +pygame/docs/generated/_sources/ref/surfarray.rst.txt,sha256=rBeiZncxG9HIetGkZS0IcwxIlHqQgCxpiZxO6bSvY8s,12251 +pygame/docs/generated/_sources/ref/tests.rst.txt,sha256=yBiMVm8xKcDfnFq1rrxQRDx-N0Zf12XmnjsapTBrsO0,4571 +pygame/docs/generated/_sources/ref/time.rst.txt,sha256=YL2ZqmQh9pIOULLhQDwAOOImjiFgU2RPXAiSX4PSLho,5624 +pygame/docs/generated/_sources/ref/touch.rst.txt,sha256=v7V0P85KlxiQIBLjaVyhTtH1fmDmqif-kDLhV0O6x4s,1957 +pygame/docs/generated/_sources/ref/transform.rst.txt,sha256=7xIt7WJtx4CgbK0vDXIXDty97Qq8uX92NeFY5MOOpIg,10639 +pygame/docs/generated/_static/basic.css,sha256=X8WBnnfAUhUYizTi0hhgc5By5vvQYXwOi9SpeCTY19s,15571 +pygame/docs/generated/_static/doctools.js,sha256=WgAZNIhr3ty6v4n2qB6CU8DBu0esGOnHuFnw_LHZJAY,9630 +pygame/docs/generated/_static/documentation_options.js,sha256=V2WEUwCNbTl9qPOsPPP1dt33ELjzRizQcYtnG7sqrrM,366 +pygame/docs/generated/_static/file.png,sha256=XEvJoWrr84xLlQ9ZuOUByjZJUyjLnrYiIYvOkGSjXj4,286 +pygame/docs/generated/_static/jquery-3.5.1.js,sha256=QWo7LDvxbWT2tbbQ97B53yJnYU3WhH_C8ycbRAkjPDc,287630 +pygame/docs/generated/_static/jquery.js,sha256=9_aliU8dGd2tb6OSsuzixeV4y_faTqgFtohetphbbj0,89476 +pygame/docs/generated/_static/language_data.js,sha256=xi5x8BZFGUKL0gawJ14ChNvuoB9X8NjyGp4aO0Oth50,11151 +pygame/docs/generated/_static/minus.png,sha256=R-f8UNs2mfHKQc6aL_ogLADF0dUYDFX2K6hZsb1swAg,90 +pygame/docs/generated/_static/plus.png,sha256=VBFRmblqEwy6AhR8R8DetD3Mm58ItRYruoZCs0mArGM,90 +pygame/docs/generated/_static/pygame.css,sha256=5oEbWVD4pENgtvEh4j8F_UEB4gNaPj-GdPIThrUkXhw,12133 +pygame/docs/generated/_static/pygame.ico,sha256=YeIWletq938Rg_G11m_1iGL_zw9T_U1QXZhjnbHjJSU,1078 +pygame/docs/generated/_static/pygame_tiny.png,sha256=BXPk3OkSWdSkqjMkCQ1Dt5WjxZfb4zj4c2ir9U9_Y7Q,15310 +pygame/docs/generated/_static/pygments.css,sha256=85BWybvZ71cAlI5uqwNERzofjlACIqPlYvQDmkKVM2o,4919 +pygame/docs/generated/_static/reset.css,sha256=wqvSs8L_cB2K6bR903cOJkEtfJi0LpNQFl3nC_kZQr4,1083 +pygame/docs/generated/_static/searchtools.js,sha256=Owa-DGWcGVZoE91fdbc1m9h_5qVc4e_gXsMS6EoXi8w,16793 +pygame/docs/generated/_static/tooltip.css,sha256=UkuHG9X2M7DaTSMJX3-mW-4LV8wBtFxfG5k_pr7xrc4,798 +pygame/docs/generated/_static/underscore-1.13.1.js,sha256=zBD3mc0Pa2X5XEASRFSX5bo8ufUZZKlGiUCye96YtIc,68420 +pygame/docs/generated/_static/underscore.js,sha256=IY-xwfxy6a9rhm9DC-Kmf6N2OStNsvTb8ydyZxtq5Vw,19530 +pygame/docs/generated/c_api.html,sha256=r3HLkhmSRwz_Iw9q8HBdAGb6mFHYoFfcSItYt6hDvJU,7566 +pygame/docs/generated/c_api/base.html,sha256=C1AdEbfKM9RGrJY7duAV3B-ycqdp_feQMGgNk8MZqlI,32530 +pygame/docs/generated/c_api/bufferproxy.html,sha256=tj34IHxfIABtHtsAU7OfBkaHpW1k292-ET0wM_qLDBY,11945 +pygame/docs/generated/c_api/cdrom.html,sha256=xP6_kPg7MvalMPZvu-z48qiPVJCtaPqr4ueO_CXNjrk,10824 +pygame/docs/generated/c_api/color.html,sha256=QniDzyEEO9-XuU2P7QFpNDkjgjcGAJu8uyUlusnSA7Q,10360 +pygame/docs/generated/c_api/display.html,sha256=puyFk2-NyOe9QQap3n8O0sHjUdcDnFE25NjLE_hjXjg,10788 +pygame/docs/generated/c_api/event.html,sha256=KYqCj9Vjq9OxuYPdJ-oMmP3jVXXElRB8GM2AfSe5DZU,12101 +pygame/docs/generated/c_api/freetype.html,sha256=svIwbMC9jPavxTLNE9wlBGDpU-QyLIAaLcVZ9gWO1vI,11343 +pygame/docs/generated/c_api/mixer.html,sha256=ME8z6tK5583Xf7q3gP7RqIrtww79HimHeWbOchzH3JI,15347 +pygame/docs/generated/c_api/rect.html,sha256=W5KQmPgweCH2Z_Uzl6pK_iJfm1d0odtw86vnd1VDla4,12973 +pygame/docs/generated/c_api/rwobject.html,sha256=F7lnZXLJgxwY6QuUUTzvx294iYq47Yza9ayPphDr0OY,15502 +pygame/docs/generated/c_api/slots.html,sha256=-F2PHuoqlP0AwEyP6Us-kgyrJ1O0iRJtTv7lwKYbBRs,6786 +pygame/docs/generated/c_api/surface.html,sha256=OdUcYeP7AdS_UpSr3Qj48XjDaFmE7nMamHuPSdViPcg,13707 +pygame/docs/generated/c_api/surflock.html,sha256=X_4HIVweM89CHzeg7aBCblpjbCZK5tOTAqFau5HTNWo,16779 +pygame/docs/generated/c_api/version.html,sha256=74oy9aD4EZkvfWgZwYM8D5P70bufE_cFNNIzOC77T50,8192 +pygame/docs/generated/filepaths.html,sha256=xZtp1myeDqFtw_gDksSjLwTkPZjuUpaxxO06Z97yRxw,6253 +pygame/docs/generated/genindex.html,sha256=0stxbNS3tECzLEzIlbjfDyI5EXNa3beBao4UCe4btuI,120659 +pygame/docs/generated/index.html,sha256=XWdapSU8INt2OHRac9wPoXZDumsLpUnVrCWK0PL0TdA,14818 +pygame/docs/generated/py-modindex.html,sha256=UPC2SSs_sCLJsE2unwvplKAU0nTICTrONh0Rbb4jv-M,11495 +pygame/docs/generated/ref/bufferproxy.html,sha256=xJWEZ5X89W27jGZ3G0EBWplq_3qND7slrlqruwc3HOE,17734 +pygame/docs/generated/ref/camera.html,sha256=mOtE4zdwTjoOP2Qtl4CKdwgN0xe_jt3tHKCkJvKkSuM,27219 +pygame/docs/generated/ref/cdrom.html,sha256=Yvg778apmy2iS0ukSZ2C9uPyXSTD05qOzPEQuOxjvkg,33373 +pygame/docs/generated/ref/color.html,sha256=CiNOwpJgkY2zK6a0qZCICfaeoTlfmB_r8KAPyXt9WA8,35001 +pygame/docs/generated/ref/color_list.html,sha256=x5QEKcFxbevIOc-rbIPu31WKDUx8bLVmPoxgSI0_bsk,177058 +pygame/docs/generated/ref/cursors.html,sha256=shw4NFuvDw_VqUrJdRoUgYaRnBOEEjprDtpjaBY4rS4,35776 +pygame/docs/generated/ref/display.html,sha256=Nvn5pxSTs6jKgcmURVr7IsV6u4iykvHjNuj5WzlAONw,76291 +pygame/docs/generated/ref/draw.html,sha256=fA8dpdUGt64gAcukEIL5hdxIhvtg0iChl164aIKrR1w,85124 +pygame/docs/generated/ref/event.html,sha256=46W4hzNsUK2hJtXtJ-G2VWL2HJah-P9qIlsyfez8JiI,57841 +pygame/docs/generated/ref/examples.html,sha256=3RrX6NufDNIfwajfC2tlIqTEgVIOf9haItUXvqI1H04,48536 +pygame/docs/generated/ref/fastevent.html,sha256=utrseqHf_qZ0VU6EN2jCH3qe6bt9XF29kaIV8tSXLZk,15077 +pygame/docs/generated/ref/font.html,sha256=oAWOZRtxpWWDd0oWjrjarzTlF5csLKx4P5PAOKzwD7I,41462 +pygame/docs/generated/ref/freetype.html,sha256=g_kVak-7t8-qTPZevzUaiUEp4WxDVhWapx3QelbW2eE,100099 +pygame/docs/generated/ref/gfxdraw.html,sha256=7FBifkrsIHnU99eouwv2Evw1M-tT9DdG5vaVUulz9Q8,79785 +pygame/docs/generated/ref/image.html,sha256=o6pySSnriEiMu5JAH-2y5m9qz4L3nGWLYLwgm5KXTBQ,29518 +pygame/docs/generated/ref/joystick.html,sha256=j_JcNTMZ2EwpsUOr5V59sKRdDacigdV3MsNA3Z4Pc3A,78288 +pygame/docs/generated/ref/key.html,sha256=X5ekJN1SJAhIeknXTp-8q7e36-YQy8xcKwXVlA0xrYU,40159 +pygame/docs/generated/ref/locals.html,sha256=zP697nb7avI0uifoKszgKr6QxQLrM2FxU5adckcX4Yg,8596 +pygame/docs/generated/ref/mask.html,sha256=7PK7H6-Z8t-v0hYxFDHOIfY0Hg9Wlysf3STLoqbP3-8,80462 +pygame/docs/generated/ref/math.html,sha256=Zf4kdgbf1mtohQfsQcbxabZxurX99FYmn6fsFXMhI5g,94354 +pygame/docs/generated/ref/midi.html,sha256=T1c__e17qLRqyxhBw2l0pTdimZj4hPzK2QUHXsSWWx4,52574 +pygame/docs/generated/ref/mixer.html,sha256=g_WXIeC_VPt4_jhY46RzUBgyPyvcfR8Di6oQLFW3ev8,64002 +pygame/docs/generated/ref/mouse.html,sha256=gsmQgha3E_TS54cCMr5aWy39YwAqneHOwT8Y0r_s3G0,27469 +pygame/docs/generated/ref/music.html,sha256=E2GNUUCUhDLWCvHcEa9t3XrU4FubkVvDtj36qHUdV08,33614 +pygame/docs/generated/ref/overlay.html,sha256=8ZBQMFfMxYIFRXXunmhY96s4CfFP4dKpaSg8InfyNiY,10990 +pygame/docs/generated/ref/pixelarray.html,sha256=DfDVy-7lD7JoFY7Qhk_Fe-8rGRE2cxov8mqCi7Jlwec,31456 +pygame/docs/generated/ref/pixelcopy.html,sha256=ffw0UCRZzXA52bm-9Qejm-dm-zlzbN0PGDB187qAebo,15097 +pygame/docs/generated/ref/pygame.html,sha256=JPVdZtpAoMfw90VEonVnhkaEALltnT9WCiHyts8CH_k,48034 +pygame/docs/generated/ref/rect.html,sha256=zlm3onMcRGMR4lJvBxTZVdRGq160R9RNagES-0CM0JM,39749 +pygame/docs/generated/ref/scrap.html,sha256=_Dovf_e9gG1nzx0rGt2FH_lb4DGbZZxB4Qg3f244_Hs,30547 +pygame/docs/generated/ref/sdl2_controller.html,sha256=Or9oCyVV2hTXP6N607BPsElarhu_GZCCqW3rj1Pjvg8,36688 +pygame/docs/generated/ref/sdl2_video.html,sha256=8Ifl3JNwurEMWFBGj0aAWPQwOZ_tu4uorgy2gPN-Ylo,61815 +pygame/docs/generated/ref/sndarray.html,sha256=Pn0NpyLTy2E53tyxsRIHf2nDhiaQeyUEjbyKm4K8tl4,14698 +pygame/docs/generated/ref/sprite.html,sha256=_s4XRxJKE2EiEc8a4iRYRgUyKpNlUpa5ehiAPLvpefc,92722 +pygame/docs/generated/ref/surface.html,sha256=aEWvdWizgJbIwUat7wSPA52yfJ71XbqILtCU4AwarKM,86275 +pygame/docs/generated/ref/surfarray.html,sha256=iVNHWmNYewzejN3Oj6m_kJboYzwqlgO_40aYwYty6aI,38299 +pygame/docs/generated/ref/tests.html,sha256=lbY4Mu8DpIH4gmZ6HcVNdb0GCdPJ_HV4QK1NQrllOu8,18478 +pygame/docs/generated/ref/time.html,sha256=fM5gFknXfbzxB2mXl7ZyhyQnLMjRt7znUii9iLlLigU,20023 +pygame/docs/generated/ref/touch.html,sha256=HSiWbsfqfDjEybzWQkHB-dMz1JOiL5ABMKc9-OmeDJk,12976 +pygame/docs/generated/ref/transform.html,sha256=2YSMlxTCQbuunRKSIh63sJGLgvjKbyRDTog2mJtvgz0,36989 +pygame/docs/generated/search.html,sha256=njM7cM6bbRh3LOPoyHaBf68K_cUdT30ZlW9mwEGV90U,3238 +pygame/docs/generated/searchindex.js,sha256=AH1X3yCCAKnAk5IWHmANoMHyUkiP3sV1e741kQv66hQ,199705 +pygame/docs/generated/tut/CameraIntro.html,sha256=uFSju0hAdBpwSmwtckKVKJvAdxHaZuTRkt5gqNIru3Q,38483 +pygame/docs/generated/tut/ChimpLineByLine.html,sha256=2m-xShhIT6okIMonp3hN6VNfPX_6_cdcjBcdnRxRvZo,58710 +pygame/docs/generated/tut/DisplayModes.html,sha256=HfoU9w36TkiIPYFfQzqCCGGZadPxjfKYhLDFuYkXQEg,22291 +pygame/docs/generated/tut/ImportInit.html,sha256=7Ub1FOkuX-QLG3oEZE6MMqCXnWMtp9MMRilR61HxWlY,9729 +pygame/docs/generated/tut/MakeGames.html,sha256=ohFMNLQ0DRi2MHg9Y4Y04yHh54fkLpntMCKCO_YRMBw,14922 +pygame/docs/generated/tut/MoveIt.html,sha256=Is5DsNxIFBI4ECHSW6sKbBihYgzPViaGQqGxvSVU9IQ,47543 +pygame/docs/generated/tut/PygameIntro.html,sha256=gMl0I27yw8Gbw6Jhpz1NXDt34S_zrCrTYrf2oKzx8J4,29776 +pygame/docs/generated/tut/SpriteIntro.html,sha256=JQpbBISsCIxmCucgJ-fuevXynl7Wc7xM837tqUb-thA,44388 +pygame/docs/generated/tut/SurfarrayIntro.html,sha256=5F5SAeYtk42lOp9D4YYWCkVVloWVrya7qQEEsZ_aS88,51225 +pygame/docs/generated/tut/chimp.py.html,sha256=AA33V1Xr3hGOdc2HcAwW0FIrLd3dOINjx9YG_jRQwko,36223 +pygame/docs/generated/tut/newbieguide.html,sha256=tzuWa-PUs-3DKhBCCIxv_KokCskgBdw9vC8jSEq4LDA,37720 +pygame/docs/generated/tut/tom_games2.html,sha256=dzzaNqFS_dNzQzOw1xKWAnoWfPi2xJRvojIt3ibhy_0,17758 +pygame/docs/generated/tut/tom_games3.html,sha256=MvrhVwtkqhLnfbZB42fLEtZPB1U7TFuX5_t_CK09dcA,15366 +pygame/docs/generated/tut/tom_games4.html,sha256=z_vy8OTUHJaDcG20crNNdFCSuAXvMWtwlimTzSZ4IpI,19241 +pygame/docs/generated/tut/tom_games5.html,sha256=XoiS0YtWXk9uqN9nrNLXnvCaXauIBCiK22GyFNiNXfg,21505 +pygame/docs/generated/tut/tom_games6.html,sha256=ceZbz3HuEgvqcvP5nFN2w92R2n6VatTVJpgzs_sKIhA,53261 +pygame/draw.cp39-win_amd64.pyd,sha256=6d_tNeVDVb-jOoUdNpRqkVVzRkWm3lrkkrruYIaq5_Y,48128 +pygame/draw.pyi,sha256=fY1s2gCQgqXZ_o2uANCdyI41lf3M599qblgFn1r2-rA,1753 +pygame/draw_py.py,sha256=jFIaxRR9jqvfHqy5xuaugK398H2KKF9IPubE3TTLkAo,18687 +pygame/event.cp39-win_amd64.pyd,sha256=nXaDsi7jTv4OGe1vGOWQXtjOLT_yAO-HVoV4egXw3Ew,40448 +pygame/event.pyi,sha256=mtDr6zuXbg5Scdm5P5ICFniTNJi6-KWjiHoqoCpJ4Yg,1193 +pygame/examples/README.rst,sha256=EByCXjSksQjKrdwut3-4LbS-u69zb1vJOXpExxRScek,4360 +pygame/examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pygame/examples/__pycache__/__init__.cpython-39.pyc,, +pygame/examples/__pycache__/aacircle.cpython-39.pyc,, +pygame/examples/__pycache__/aliens.cpython-39.pyc,, +pygame/examples/__pycache__/arraydemo.cpython-39.pyc,, +pygame/examples/__pycache__/audiocapture.cpython-39.pyc,, +pygame/examples/__pycache__/blend_fill.cpython-39.pyc,, +pygame/examples/__pycache__/blit_blends.cpython-39.pyc,, +pygame/examples/__pycache__/camera.cpython-39.pyc,, +pygame/examples/__pycache__/chimp.cpython-39.pyc,, +pygame/examples/__pycache__/cursors.cpython-39.pyc,, +pygame/examples/__pycache__/dropevent.cpython-39.pyc,, +pygame/examples/__pycache__/eventlist.cpython-39.pyc,, +pygame/examples/__pycache__/font_viewer.cpython-39.pyc,, +pygame/examples/__pycache__/fonty.cpython-39.pyc,, +pygame/examples/__pycache__/freetype_misc.cpython-39.pyc,, +pygame/examples/__pycache__/glcube.cpython-39.pyc,, +pygame/examples/__pycache__/headless_no_windows_needed.cpython-39.pyc,, +pygame/examples/__pycache__/joystick.cpython-39.pyc,, +pygame/examples/__pycache__/liquid.cpython-39.pyc,, +pygame/examples/__pycache__/mask.cpython-39.pyc,, +pygame/examples/__pycache__/midi.cpython-39.pyc,, +pygame/examples/__pycache__/moveit.cpython-39.pyc,, +pygame/examples/__pycache__/music_drop_fade.cpython-39.pyc,, +pygame/examples/__pycache__/pixelarray.cpython-39.pyc,, +pygame/examples/__pycache__/playmus.cpython-39.pyc,, +pygame/examples/__pycache__/prevent_display_stretching.cpython-39.pyc,, +pygame/examples/__pycache__/resizing_new.cpython-39.pyc,, +pygame/examples/__pycache__/scaletest.cpython-39.pyc,, +pygame/examples/__pycache__/scrap_clipboard.cpython-39.pyc,, +pygame/examples/__pycache__/scroll.cpython-39.pyc,, +pygame/examples/__pycache__/setmodescale.cpython-39.pyc,, +pygame/examples/__pycache__/sound.cpython-39.pyc,, +pygame/examples/__pycache__/sound_array_demos.cpython-39.pyc,, +pygame/examples/__pycache__/sprite_texture.cpython-39.pyc,, +pygame/examples/__pycache__/stars.cpython-39.pyc,, +pygame/examples/__pycache__/testsprite.cpython-39.pyc,, +pygame/examples/__pycache__/textinput.cpython-39.pyc,, +pygame/examples/__pycache__/vgrade.cpython-39.pyc,, +pygame/examples/__pycache__/video.cpython-39.pyc,, +pygame/examples/aacircle.py,sha256=pX1LpRdF_w_tvkCX9ngs7T1lyM5JpG8mwcB7P2k4_10,1034 +pygame/examples/aliens.py,sha256=BiT_DsYpTnWCZu4Ozl2YcopkIqcYAsv5GLaFrpvJUcI,12055 +pygame/examples/arraydemo.py,sha256=IdAvdvTIVSx9jEZjcgc1CrZy2dghKsxCQlxtnXSE_Tg,3633 +pygame/examples/audiocapture.py,sha256=4RQdjYlRMM_iAAwuccV0kT_SuNhQw2KibDeLOhgy6ow,1563 +pygame/examples/blend_fill.py,sha256=LZ1u3axCmw7uunMFJkoyF2Wir74uIIOxDU1i2HFO-eg,3425 +pygame/examples/blit_blends.py,sha256=P_BgoD_GnDtGkltRs5p5nIFOljhYWjl1Yocw8zEzqWQ,6345 +pygame/examples/camera.py,sha256=YmSUf-E3UD34uianEMIfIhyKblTGakn7pt3QvPUOBKc,3028 +pygame/examples/chimp.py,sha256=htSz24LiUgGgrkGdnd0bj0fKEj6BYyFf8WA1Y8EyQT8,5910 +pygame/examples/cursors.py,sha256=b-IapWngIiv_nCm89Ctb4cXRMt_wFGrK4EnEqF-CV1g,2873 +pygame/examples/data/BGR.png,sha256=DvOrlW5BJdat94nNV8XEETBLRrSWRV7byQsMPsA69uw,244 +pygame/examples/data/alien1.gif,sha256=8Wveo1zpLVaFCtYITm_SoYqjy8L-TDuaZOcNa8Osqsw,3826 +pygame/examples/data/alien1.jpg,sha256=HOjXjmW4Ofsu_en9WNrkuIp_DCwupXcFB0Yt_cqV9rA,3103 +pygame/examples/data/alien1.png,sha256=femzLssV7oGvT3S2tyviyq7qO32QfhBDtMOR3ENBCLs,3522 +pygame/examples/data/alien2.gif,sha256=0MPpVYzvjAECy0pd7YRFKCEzzIYDKEJt70rbjlLbTZM,3834 +pygame/examples/data/alien2.png,sha256=FKGYDI2FBBR1Z56BLn357PNfh3-M38gAJpSQL8BpKYY,3526 +pygame/examples/data/alien3.gif,sha256=bFCRGZOQPaadCKIc-tlqoUjHdsi5IzR0E-2SjpPEvmA,3829 +pygame/examples/data/alien3.png,sha256=a51Tb9E4IvoICGzQChHq51RKVQJLf1GOCEeqA5yYfnk,3518 +pygame/examples/data/arraydemo.bmp,sha256=xM4-n_hRCQFZlfwwdTK6eaBweycUc863TgSFbWp3dbA,76854 +pygame/examples/data/asprite.bmp,sha256=97XMpKq9lLpMuv8UveCf8UJEAxheBhPUjHfMRQBkUx4,578 +pygame/examples/data/background.gif,sha256=-3kZwt99MFUBbBo-kHvPZXVlFrSB34XVNQWWxfHb970,9133 +pygame/examples/data/black.ppm,sha256=Yu8BwDOeFwOnVYjdWTMo7Tl1xcx2a7J38zZP-JllcMQ,6203 +pygame/examples/data/blue.gif,sha256=hqbgDzCeUz0NHjAQHYURIxSOpRbpHf6QeFch8ux_dAE,84 +pygame/examples/data/blue.mpg,sha256=XDj1CRPt1MWxspCfA3oqb822nlZgQ7CyyEuVJwlgmpg,6144 +pygame/examples/data/bomb.gif,sha256=TZ60QP1S2QBN6QPNSqBwS5VyebZA93iu8ZMUXzEg2QA,1170 +pygame/examples/data/boom.wav,sha256=kfoWs0VVDGHv0JSa46nXZBGyw70-jpfPq_B31qNA_F8,12562 +pygame/examples/data/brick.png,sha256=K_mshK0aL81nzOjAorTXyPps6n9mvofLeOWFXFpVjYA,170 +pygame/examples/data/car_door.wav,sha256=TwYWVqme5NqVVID1N4es92RSKEdTYkxbNx6dNamK-_4,3910 +pygame/examples/data/chimp.png,sha256=gFY5lDOflZ5fCMXpL9_HmipP4-3ALn_r6cCB9yTZKBk,826 +pygame/examples/data/city.png,sha256=c0Nu2o7x7QmvGMDmDCaPnhvJ8tPNuguKKpI_Z-NfQ40,143 +pygame/examples/data/crimson.pnm,sha256=o9ziiY4ox_cCmEo07w08SQckCQTRttxtLgKBE0VmZY8,3124 +pygame/examples/data/danger.gif,sha256=m0CBKalFbkqlohgOmrwkwVOfqBhRWonb7xm1pzbDy2Q,2761 +pygame/examples/data/explosion1.gif,sha256=WYcdwbZqmYdaaaPYFiR5vka0Anp4F4nnNlpSSx_1xug,6513 +pygame/examples/data/fist.png,sha256=X0VOsy6fP0UGqBjy7baoBX8XAXyp_1_s2tOItbtA7EI,86196 +pygame/examples/data/green.pcx,sha256=si9WT7dyn3nsXoh34UBW0yOCKWbC-Rz0fKkc_7TDRbY,320 +pygame/examples/data/grey.pgm,sha256=uWTtnBH-Fv605OtEJzS9fG5ns9XaeUHq2YeAC_cdkKU,4155 +pygame/examples/data/house_lo.mp3,sha256=R0nZUXymMp_XLPU8S1yvsiVeWT6MKLt5Rjp-WSnVrLQ,116320 +pygame/examples/data/house_lo.ogg,sha256=64FiQ1Zjq-cOj6Bmya_v3ZjEWmBaGZlTl19udKaz6sU,31334 +pygame/examples/data/house_lo.wav,sha256=B1BwfFaPIsSxaash-igVI_YE9SQd1BCXRTnSAKsNunY,78464 +pygame/examples/data/laplacian.png,sha256=uWI8dPstqMEPVuFPGtm-guu48T2-L3kn99rWA3ZhZ-Q,253 +pygame/examples/data/liquid.bmp,sha256=qtzPXhq0dr2ORNCCZ6gY2loT2Tsu0Dx5YvXB548I1Xg,11734 +pygame/examples/data/midikeys.png,sha256=9HCCmMHvlubR6G9a0jMv1C-AKeBzYfb5jjNhol2Mdqw,19666 +pygame/examples/data/player1.gif,sha256=3ZTVWGxnedKqtf3R-X1omPC0Y8jUSPGgHBAzeGhnV4c,3470 +pygame/examples/data/punch.wav,sha256=A0F1xT8aIZ6aNI_5McMqLygb1EfmdIzPi4kWkU4EwQc,4176 +pygame/examples/data/purple.xpm,sha256=3r6_3v6tob2qy-1hrQ3ujYHpuFb9UQ7LuNsHWq9mj5A,1249 +pygame/examples/data/red.jpg,sha256=mgaTBGP_k55FcqJIL7eV4jYll80zaZHPHfFtXAOLnF8,1251 +pygame/examples/data/sans.ttf,sha256=nrZ6FRet4dwlvA7xOReYCP2QwyGebk0iVJaSFbtpOhM,133088 +pygame/examples/data/scarlet.webp,sha256=iLN1RrY8LCSUnDrwYvWC99v_pLGy0iN8winH7VAyVL0,82 +pygame/examples/data/secosmic_lo.wav,sha256=-EIFkzj7k5qEqG04n7mnUGUp1SsyCJ4n08TzPT600DY,18700 +pygame/examples/data/shot.gif,sha256=bF2eY629zQzvDu83AKpveSFhJq5G4QpOE98A0tvbPFI,129 +pygame/examples/data/static.png,sha256=Xe4wN80awt7nTNiLemoSNTEKlAbGFW7djNETP8IleNs,1202 +pygame/examples/data/teal.svg,sha256=nkksR3fo0NPwC9sVXQPrPR_QrvqRiUB1vC4I-K83dho,313 +pygame/examples/data/turquoise.tif,sha256=4OkIy6CDPMv77tRR_wA9ZHA6qZzG3pjZ-1m1mNB7bcI,1186 +pygame/examples/data/whiff.wav,sha256=FMWM3XnYtce6mHFXQCYPgzT-xu-Q4DJybZfpPjG8cpE,5850 +pygame/examples/data/yellow.tga,sha256=EhxUG3SMO6bbHxr4yFggnKrsC1mYZVq-L6znAsR3z8I,3116 +pygame/examples/dropevent.py,sha256=BvidStsTzZoC4CURTc0muK6ErDd4Q3FJt6MDsNgMGcA,2240 +pygame/examples/eventlist.py,sha256=1PhPxMies_2rZtxVSg4nnVw7S3bDEYXw7p4yJS-n0ic,5938 +pygame/examples/font_viewer.py,sha256=53EE0szoIMxZFk7I44hD7kZg--zlC7kQg-AcqnZu0TU,9841 +pygame/examples/fonty.py,sha256=Fm3POU3D82ypRTYEl7NIdeFcpcCPL6h3TC2tfkp_DDw,2080 +pygame/examples/freetype_misc.py,sha256=Zq2hF3j0MaleVkELLz1vn0wgc5k5yuwoHPt8Mjz0XVQ,3656 +pygame/examples/glcube.py,sha256=UONh_9RvLhCG8qLQUys4sE2xXY8ukf2zs0KXr_IRE5k,16860 +pygame/examples/headless_no_windows_needed.py,sha256=DYSKwYk4EWjNtujuv2SAyQ_-8eKhVqiHGKdI67fBjd0,1301 +pygame/examples/joystick.py,sha256=Yb9KMRvaFEK_0f1peZVo089qxZgM1WKBIasm-RH9EiU,5333 +pygame/examples/liquid.py,sha256=Y9pOpubVrb4pwd8F8qoC2aiueyWi4h_Xmq58g8jn-is,2541 +pygame/examples/mask.py,sha256=RsJFbWGJWNyLkKDxz-Oa8uqFS4eNZZUBdIUCDS4TxRM,5811 +pygame/examples/midi.py,sha256=aIF0N5c12-SMqAhEfncWeC2mlpokgIUF6jyRNdl4PpU,29414 +pygame/examples/moveit.py,sha256=swUcvxdNi0zx50i-sT2IW9UtBegWEepZFTGL2KhPTgQ,1824 +pygame/examples/music_drop_fade.py,sha256=Kn8r4u1zGAovWhUHIotjia1Ex-XhpiDvWU-TpND0vR0,8999 +pygame/examples/pixelarray.py,sha256=G2QLM6ooZKN0y3ULndWcZap5R8FBXQl3FwUcDeNAq9M,3450 +pygame/examples/playmus.py,sha256=jTFOwnRpA701s6HbFxzD9bKY039foXJcr2LRBjYrusg,5223 +pygame/examples/prevent_display_stretching.py,sha256=QK0eUSE7Am0gJ5H7C9XPeBIoURcEUzyX8o2XK3oKv3A,2492 +pygame/examples/resizing_new.py,sha256=8p6Sy8s74A49OXeboxmWnKGQJVO99ATE4nm7A_ADTxY,1046 +pygame/examples/scaletest.py,sha256=tP6-18mhlRa4ffsECE3LoID0w0RRwCgC4Eqkp4NTsD4,4866 +pygame/examples/scrap_clipboard.py,sha256=QERCic7zIHipQjp7eUxmzNU7kQ_N-sYdejsoA87tX2I,3056 +pygame/examples/scroll.py,sha256=KZZVc-TZhYRIZCBChDq6OmA5kM_CBrUlwe9g7J6AqI4,6578 +pygame/examples/setmodescale.py,sha256=6GCUOLrGp7KITI1qoGj1hJqNxkouUqmdfYgXlD7IYns,1801 +pygame/examples/sound.py,sha256=CwQ3hSKjD_sHmXEBLfimdbt18cQcXwk5QQ7jfnOuSS0,1172 +pygame/examples/sound_array_demos.py,sha256=WscuFblSjp8K9G1rtBbnDr7B0B12haYo4Ma7j41FmzQ,5797 +pygame/examples/sprite_texture.py,sha256=zq5ry_333hIOYevVmoOrkTJauWIoPvIqeF7CrIPerXM,2516 +pygame/examples/stars.py,sha256=nLDKyCQ4xor98M_z62uMWEojAkC9eWlFbDk_r7eCQTE,2762 +pygame/examples/testsprite.py,sha256=ibKDhB0LEXGmcVNOa7fcuCW7VGMFUoZPYZEpG_9iOKw,7001 +pygame/examples/textinput.py,sha256=r6rsAZDb-4L_BIFwYPvhrw0CJnC0yD94thfLNXUfz2w,5394 +pygame/examples/vgrade.py,sha256=_t_10Y7vQoFQjyeUlxQJgcbLkT1r3jCKLeOrWek7ofY,3277 +pygame/examples/video.py,sha256=RMnMLIY_AHaItROsYK2XKKqofIdebwYwU4PkeGJ4cWo,4452 +pygame/fastevent.py,sha256=NOVGX3eAvQGCSHDOZZJ_VuWSyekqdPO1Wrr2MvCEQeU,1694 +pygame/fastevent.pyi,sha256=qZgTFBKUESMcDySpT0uIGjH1fkov9CO2VvazYoWQFxI,249 +pygame/font.cp39-win_amd64.pyd,sha256=QgDnGxO_PVb4DOcapNvERsNos-fs7gpM0qA7YiN5zoQ,24064 +pygame/font.pyi,sha256=622c9NX1dIFIFNQX28xp5MnPBEn602QE_PK20UfW3cI,1528 +pygame/freesansbold.ttf,sha256=v5JRJp8R5LNVgqmTdglt7uPQxJc6RZy9l7C-vAH0QK0,98600 +pygame/freetype.py,sha256=fuFG_GnP5IpwyDbu0tpgcFLqLBL24MM1oh76AzqXJVQ,2216 +pygame/freetype.pyi,sha256=TfhgKrq9pnw9O3oMxH0UxbZC1tG4zClHztk0NHkXvEI,3269 +pygame/ftfont.py,sha256=i_YMSrD-fqL7vDhaNJTF-S9fZ2-cEyHWe22W7eNb4-Y,6145 +pygame/gfxdraw.cp39-win_amd64.pyd,sha256=EdnNtyHtZYUoZLJBPsEBQ-pZXImRflQD3AvKVCIB0zk,57856 +pygame/gfxdraw.pyi,sha256=L3J_XWYdwJdfXojW3fZRNNnNULH6jDOGGz8XXw15s9M,2531 +pygame/image.cp39-win_amd64.pyd,sha256=riPfqR8doKuyypAWT_wnngCUn7RKCLx3f_0FPfWwi8A,28160 +pygame/image.pyi,sha256=nXtOIFYkslgBLnka3vZyRx-z59aM5FYr5dWGrHTUWrM,1317 +pygame/imageext.cp39-win_amd64.pyd,sha256=o0pr7YqaICqHfJGzLsnxAna3v45cVVJGou2HIqX99m8,19456 +pygame/joystick.cp39-win_amd64.pyd,sha256=XYMJs3i4uS4tykD_3rkcqO6QfFw5Wu-u-LqzwjeXBVk,20480 +pygame/joystick.pyi,sha256=OSudzqdY_e9yfsddxK5F6A7n0mMoYXO3a6WuYxtzapc,1032 +pygame/key.cp39-win_amd64.pyd,sha256=bgtFNIGVqyEo-1qdun1D52eEwMjr7Jlfbgjp7yz1uAI,26624 +pygame/key.pyi,sha256=axWlbWi-noOlfXKx8gO3w9ZTlY6BghTSjTxfdTA_4yk,502 +pygame/libFLAC-8.dll,sha256=0HM78uCYCQTn2A-rp5DLOmG19AMrTU7cCSgJJTTFdkE,441344 +pygame/libfreetype-6.dll,sha256=jiY_2SV-joO6_aDJQxhKSYwHQkxNVYMh_bSMmhl-WKQ,586240 +pygame/libjpeg-9.dll,sha256=OiJK9UDJZXSAD16az2SyzfuQYOcnkZ7BT70Yeptb_mk,244224 +pygame/libmodplug-1.dll,sha256=ZAvEx0T7awNnKptjjcm9xoUS71UjG-h5PTyTjuhFKCE,252928 +pygame/libmpg123-0.dll,sha256=8ONr-AsVKwPM_5cJ4qG2NMcO77NThXUij4DNvrBQSoE,337408 +pygame/libogg-0.dll,sha256=6ksaxXVOzfe33CxevSJFYmNxLMWVJuKHRr9dTU-YemA,52224 +pygame/libopus-0.dll,sha256=9okXbB9HJTq1P9EKyzbfjINC2Xgp_LF9J4JHO_1fr4Y,124928 +pygame/libopusfile-0.dll,sha256=QMBYXUwLimj0WBr0jijgXek1ZS1FnM4N0eNFlxBeNCU,46592 +pygame/libpng16-16.dll,sha256=5oi0pNGPS2zMmcbKSYD1EhjLglYQd1GS2bYLLwXv8tU,210944 +pygame/libtiff-5.dll,sha256=6_6XrF7ya5SUWvPbX_0RCkuOktwCVZv4HMsz8NXrzpU,432640 +pygame/libvorbis-0.dll,sha256=an11kXbLm064p0gcVTOG3CmBSIcpUxLUr2RB6rbWLac,251904 +pygame/libvorbisfile-3.dll,sha256=DXhfgoLmwDifxr8R0YwXZTUvYlETRrL0auEbdBN5tu0,69632 +pygame/libwebp-7.dll,sha256=mlNWO2BY9w8nJQKbfdL-lvhpwg6AkAMc0wPplN_ge1A,447488 +pygame/locals.py,sha256=20tMfZH9ByKbxjHd3WIrF98FH2ZH6WMv8DetCxXZNR0,11638 +pygame/macosx.py,sha256=sZuU-urA2snMkjlody2cl2dkEGudSCoJfen2YenBRPs,399 +pygame/mask.cp39-win_amd64.pyd,sha256=KPAaH2Csm61fRsN9fTbgwafVRXZb-rtDy-HMJGCf6LY,56832 +pygame/mask.pyi,sha256=MFj5YpcgBE5PyPbsOaxBG1vhhKaCY1iUlLDp_0l6l80,2328 +pygame/math.cp39-win_amd64.pyd,sha256=Rz7HzmK0LYZToZAxj87tZHzs9UTCvkg3RvuBvs5rwvA,67584 +pygame/math.pyi,sha256=2k_qesYS32Iu3QEuV216XUMc4nIheXk5cNJQo-4WL8w,10394 +pygame/midi.py,sha256=iZIlXZrPMPXUrwVU1dpbq8gH0-9BMH1DBt8WPQmytRM,24398 +pygame/midi.pyi,sha256=SR2ye2EixdqdKGdSuoWLoSZbvuxsOLrkvpzS1nfvLDQ,1780 +pygame/mixer.cp39-win_amd64.pyd,sha256=KxGQSHRYsCSCtWDld8zTWp-cQ5A9SDuEti7MGIjWigk,37376 +pygame/mixer.pyi,sha256=4686BQHhEqmPwEiybnMd0Aa003SSuZrG3jpP-skbea8,2522 +pygame/mixer_music.cp39-win_amd64.pyd,sha256=Ft0ZANne2RrL0173Oj1LY9mcefMBrAEr7IL-peY3GxM,20992 +pygame/mouse.cp39-win_amd64.pyd,sha256=XWAAmp5Tmv2PEXKg-x3G8AE8XOOyjrEFkG8gdhhfkbg,19456 +pygame/mouse.pyi,sha256=0qUx45nLXk7k_kTLwHYWht7JrN7KF4ZXoO3YsMEmQTQ,1050 +pygame/music.pyi,sha256=WFKWboTgVmNsI-4j2dj9Z3OsyHrVoKMtu5IMfonQcvg,694 +pygame/newbuffer.cp39-win_amd64.pyd,sha256=8JmQP4U3iW6A-gvLosgag1bRJxjStOc9xkzIkLNJ7pY,22016 +pygame/pixelarray.cp39-win_amd64.pyd,sha256=x-PlrXsfs2b6hiBuhOj7mCtPwNiwY_Wehktqkcaz2i8,44544 +pygame/pixelarray.pyi,sha256=YrDhSQfAVlBq3a9gVRLsPnKhKym640mH1Amtc2phHts,949 +pygame/pixelcopy.cp39-win_amd64.pyd,sha256=xOT5aDeIf5VT_ofmdeZlJ9w75ehfjhnd-6GaDnyfU-w,26112 +pygame/pixelcopy.pyi,sha256=ihu_zbReupXhpCRVcrkz13FEzLOwkPfwVs7ko6zBxr8,545 +pygame/pkgdata.py,sha256=0soLxo1AmhV06EZ8k72T0tirZQIsX_54hLGD7OAPr5k,2445 +pygame/portmidi.dll,sha256=yfjZBDrBVwsQ8QTy0ArseR9WJhyE7kB3O-c9Cjgi4BM,41984 +pygame/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pygame/pygame.ico,sha256=PBF9cw0Ca9Rw2pNmDD3iXvcYYQeI9ZzZ9vxtRLQRoJc,145516 +pygame/pygame_icon.bmp,sha256=Twnby8nv4HMhGka49n-47CPseDvwrSLZ0l1o9U2Bb5s,630 +pygame/pygame_icon.icns,sha256=4jwAo9VtMhTK9hq9ibt6MZ4_sd2VsZueWZ3YAMuTPgw,264148 +pygame/pygame_icon_mac.bmp,sha256=QrAs3kEF6v7wVMlIJgktI90aUdTg9RdTmp16d2HZhNg,262282 +pygame/pypm.cp39-win_amd64.pyd,sha256=8D8G2cyr9uONXQ3-UV-_-kMEhbiHbh_ump8vjqPnGA8,71680 +pygame/rect.cp39-win_amd64.pyd,sha256=hR1yUuNgIWfjLntNdgIGEhaTzgo34aI1sHAGrO06sLw,36864 +pygame/rect.pyi,sha256=B6MtasUsjTQCmijkaZa1CBFdZBgCFE8H6bCBBegco2g,7989 +pygame/rwobject.cp39-win_amd64.pyd,sha256=GuLH7_YIdeyXEhSRFMAB8CYyJxAvnr1iKR5gR8stExk,19456 +pygame/scrap.cp39-win_amd64.pyd,sha256=imNhVNmhqWZASoXKtOAPl3IzbWreCFKR6friwTwWRfo,18944 +pygame/scrap.pyi,sha256=iBei8wQYnp2UcZ01YyOblEKzkhpWyKr1--NkrTb5vZk,312 +pygame/sndarray.py,sha256=hJMTnQBEbOBYzeBRdCiGHCr3S20NqpHVevX2WFxw51I,4083 +pygame/sndarray.pyi,sha256=-kUmCShhKSazBRhHberq4kDhQau0I-02LZHvfIVYi7A,337 +pygame/sprite.py,sha256=SrMpwUJ9wpXYupD1vrWx7qrGXNw49gZw2L7JSkJ2dEo,61450 +pygame/sprite.pyi,sha256=a_7QqTKtfrcN5iIKzIK2bbvG1vohzhGVp00xVw5JHJI,5259 +pygame/surface.cp39-win_amd64.pyd,sha256=M55iNVXBogmL0327RtZ4Z3EaHSGjXCwtsU5JQWRjpNw,220672 +pygame/surface.pyi,sha256=2Yaz8WLA1HSO3Exu1jfn3cy0gehzsUzhfbgZjxoN1P0,4540 +pygame/surfarray.py,sha256=4Beyg1cQUaFmvf7VgddTsUOr-nT89YvZ6Dwv_oer9yU,14424 +pygame/surfarray.pyi,sha256=9mkysuFQ3set-H6Fwc2lurpEfUcjpStn7DbaiuJfZ-4,1111 +pygame/surflock.cp39-win_amd64.pyd,sha256=1ebsHFwRmvxgdm84j7JXuUaG0X3wSCnin2UNHOiRxlk,13824 +pygame/sysfont.py,sha256=VCQ1YR-wUC0RylnRIw7vPojp_QI7X7btBV2bRUfUcn4,16053 +pygame/tests/__init__.py,sha256=wfUhz-LZF-OXZNT81UfGdofNYPCUMJoF3nwgXpzg4sE,1251 +pygame/tests/__main__.py,sha256=B9PuRd67whv9v1qnCzeIlFzc4R-_9kGj6xwKAS3F8_w,3826 +pygame/tests/__pycache__/__init__.cpython-39.pyc,, +pygame/tests/__pycache__/__main__.cpython-39.pyc,, +pygame/tests/__pycache__/base_test.cpython-39.pyc,, +pygame/tests/__pycache__/blit_test.cpython-39.pyc,, +pygame/tests/__pycache__/bufferproxy_test.cpython-39.pyc,, +pygame/tests/__pycache__/camera_test.cpython-39.pyc,, +pygame/tests/__pycache__/color_test.cpython-39.pyc,, +pygame/tests/__pycache__/constants_test.cpython-39.pyc,, +pygame/tests/__pycache__/controller_test.cpython-39.pyc,, +pygame/tests/__pycache__/cursors_test.cpython-39.pyc,, +pygame/tests/__pycache__/display_test.cpython-39.pyc,, +pygame/tests/__pycache__/docs_test.cpython-39.pyc,, +pygame/tests/__pycache__/draw_test.cpython-39.pyc,, +pygame/tests/__pycache__/event_test.cpython-39.pyc,, +pygame/tests/__pycache__/font_test.cpython-39.pyc,, +pygame/tests/__pycache__/freetype_tags.cpython-39.pyc,, +pygame/tests/__pycache__/freetype_test.cpython-39.pyc,, +pygame/tests/__pycache__/ftfont_tags.cpython-39.pyc,, +pygame/tests/__pycache__/ftfont_test.cpython-39.pyc,, +pygame/tests/__pycache__/gfxdraw_test.cpython-39.pyc,, +pygame/tests/__pycache__/image__save_gl_surface_test.cpython-39.pyc,, +pygame/tests/__pycache__/image_tags.cpython-39.pyc,, +pygame/tests/__pycache__/image_test.cpython-39.pyc,, +pygame/tests/__pycache__/imageext_tags.cpython-39.pyc,, +pygame/tests/__pycache__/imageext_test.cpython-39.pyc,, +pygame/tests/__pycache__/joystick_test.cpython-39.pyc,, +pygame/tests/__pycache__/key_test.cpython-39.pyc,, +pygame/tests/__pycache__/mask_test.cpython-39.pyc,, +pygame/tests/__pycache__/math_test.cpython-39.pyc,, +pygame/tests/__pycache__/midi_test.cpython-39.pyc,, +pygame/tests/__pycache__/mixer_music_tags.cpython-39.pyc,, +pygame/tests/__pycache__/mixer_music_test.cpython-39.pyc,, +pygame/tests/__pycache__/mixer_tags.cpython-39.pyc,, +pygame/tests/__pycache__/mixer_test.cpython-39.pyc,, +pygame/tests/__pycache__/mouse_test.cpython-39.pyc,, +pygame/tests/__pycache__/pixelarray_test.cpython-39.pyc,, +pygame/tests/__pycache__/pixelcopy_test.cpython-39.pyc,, +pygame/tests/__pycache__/rect_test.cpython-39.pyc,, +pygame/tests/__pycache__/rwobject_test.cpython-39.pyc,, +pygame/tests/__pycache__/scrap_tags.cpython-39.pyc,, +pygame/tests/__pycache__/scrap_test.cpython-39.pyc,, +pygame/tests/__pycache__/sndarray_tags.cpython-39.pyc,, +pygame/tests/__pycache__/sndarray_test.cpython-39.pyc,, +pygame/tests/__pycache__/sprite_test.cpython-39.pyc,, +pygame/tests/__pycache__/surface_test.cpython-39.pyc,, +pygame/tests/__pycache__/surfarray_tags.cpython-39.pyc,, +pygame/tests/__pycache__/surfarray_test.cpython-39.pyc,, +pygame/tests/__pycache__/surflock_test.cpython-39.pyc,, +pygame/tests/__pycache__/sysfont_test.cpython-39.pyc,, +pygame/tests/__pycache__/test_test_.cpython-39.pyc,, +pygame/tests/__pycache__/threads_test.cpython-39.pyc,, +pygame/tests/__pycache__/time_test.cpython-39.pyc,, +pygame/tests/__pycache__/touch_test.cpython-39.pyc,, +pygame/tests/__pycache__/transform_test.cpython-39.pyc,, +pygame/tests/__pycache__/version_test.cpython-39.pyc,, +pygame/tests/__pycache__/video_test.cpython-39.pyc,, +pygame/tests/base_test.py,sha256=gIAQG4pAY5RbpVq6tpeQMg1Jc3ewL133SIYtgh5hhkY,22634 +pygame/tests/blit_test.py,sha256=YmrU8GAJEuMFCPpDZ7jRjP7ArUCaz1_TiPmjjoA40OE,4740 +pygame/tests/bufferproxy_test.py,sha256=EroM5MVP_mKxC64fFJjPc5WPrmQYx8CA5v48DbD4zPY,16511 +pygame/tests/camera_test.py,sha256=KdGG1pLTe8Eh2SHiEsH7DuLqwn-OsaLCHm4MGCKPAvg,70 +pygame/tests/color_test.py,sha256=avlBC0X2KM2uFiyv_ZBM-3Hh4b5AL0xbBh6Bz9n_s2Y,47441 +pygame/tests/constants_test.py,sha256=t3xGL86Lt5YvYxx7ooH_taZfQBvC5UL4bBp_KdXuu4Q,9516 +pygame/tests/controller_test.py,sha256=a6NSWn1k1Rpt4HTYeOAbF-cDx0KfnKsrG6DwA0vk_0k,10834 +pygame/tests/cursors_test.py,sha256=NyQ2B9I5VJXwPS-VZfd2HNPJKHUhIZDxGw6GRtuHWWA,7700 +pygame/tests/display_test.py,sha256=_9t187FcrghjskhLLWWWi3rzcMm-DxMWxSxthAvLEOQ,29009 +pygame/tests/docs_test.py,sha256=r2qa_ox8eg2_Y5Pb9-XzZExAhqJrdVMO30guO1o7PPM,1091 +pygame/tests/draw_test.py,sha256=sS3dxb_Z0n-EAeFEZlRUO2Mhl3ppQmByzBvnjk46SYc,237007 +pygame/tests/event_test.py,sha256=5KRBJQXlrkEO7NlIMVlMIeYRpIGYRRyi_rDmyETWpAM,28625 +pygame/tests/fixtures/fonts/A_PyGameMono-8.png,sha256=QmhReADwKrzW5RWnG1KHEtZIqpVtwWzhXmydX1su10c,92 +pygame/tests/fixtures/fonts/PyGameMono-18-100dpi.bdf,sha256=nm3okxnfAFtADlp7s2AY43zS49NYg9jq7GVzG2lPhOQ,1947 +pygame/tests/fixtures/fonts/PyGameMono-18-75dpi.bdf,sha256=4kB0uYeEpa3W-ZAomFMpc0hD-h6FnOh2m5IPi6xzfds,1648 +pygame/tests/fixtures/fonts/PyGameMono-8.bdf,sha256=aK0KV-_osDPTPiA1BUCgZHOmufy6J9Vh5pf1IAi0_yg,1365 +pygame/tests/fixtures/fonts/PyGameMono.otf,sha256=_Af4LyMEgKKGa8jDlfik89axhLc3HoS8aG5JHWN5sZw,3128 +pygame/tests/fixtures/fonts/test_fixed.otf,sha256=FWHmFsQUobgtbm370Y5XJv1lAokTreGR5fo4tuw3Who,58464 +pygame/tests/fixtures/fonts/test_sans.ttf,sha256=nrZ6FRet4dwlvA7xOReYCP2QwyGebk0iVJaSFbtpOhM,133088 +pygame/tests/fixtures/fonts/u13079_PyGameMono-8.png,sha256=x_D28PW8aKed8ZHBK6AISEZ9vlEV76Whi770ItTuFVU,89 +pygame/tests/fixtures/xbm_cursors/white_sizing.xbm,sha256=VLAS1A417T-Vg6GMsmicUCYpOhvGsrgJJYUvdFYYteY,366 +pygame/tests/fixtures/xbm_cursors/white_sizing_mask.xbm,sha256=CKQeiOtlFoJdAts83UmTEeVk-3pxgJ9Wu2QJaCjzAQM,391 +pygame/tests/font_test.py,sha256=pD2uulSNvBMejK_gpqbdVz-zDXWQWJr8BUAw4W_l0sQ,22605 +pygame/tests/freetype_tags.py,sha256=NdjMDSYHfrhopKR0JuTeUfFX-AbcCu4fsXnS1a46iVM,182 +pygame/tests/freetype_test.py,sha256=z3un9cZ53PedVy5NUIWoduudXlNUxuslHL8lxxvTuK4,64428 +pygame/tests/ftfont_tags.py,sha256=IvteBUDEp4rv9q6FwlTpQ9X2px-XUromSMQ921VrhCU,180 +pygame/tests/ftfont_test.py,sha256=-VB-0kdWCDTWVvIf4bRTjrvjvTBZDbfgYZyl20pd2SI,523 +pygame/tests/gfxdraw_test.py,sha256=HI3NMPdA2qhKmva0CzL0ORveInHEvgemjZ7evvRLGFY,32375 +pygame/tests/image__save_gl_surface_test.py,sha256=5H8TeGZNRZzu5kJInWPe8AuuKqHv-utunadoBmn--CI,1198 +pygame/tests/image_tags.py,sha256=_WJGXgTOaUn4IG7fIk1sDKfDDZP3W8N6PkrrOpPT-U8,132 +pygame/tests/image_test.py,sha256=cpWnFpqn5-IitDfNaJunHWgd64Mxcxnt-51LTnXkoJY,37989 +pygame/tests/imageext_tags.py,sha256=-vnXr7O5F1NVrEDrOHBEYdaD-JiuBT9NI-lxGps-K1U,135 +pygame/tests/imageext_test.py,sha256=6HYyo1dBkOhfJgo8I_YkKxmeHYHHoYO8WF-2aVUL3uw,2889 +pygame/tests/joystick_test.py,sha256=yH8HxUvnZwq3lEnxBDJ7ObDbdDlB8ph5DqO-mqj19Sg,6168 +pygame/tests/key_test.py,sha256=Jrza338ku2Wr3nyYm_IM-fF9JGeMSsNXsXB0844CbVI,4171 +pygame/tests/mask_test.py,sha256=VqBVCT-h3HSo-szDIUrtLhswIYyqToGoi5mNB-bij-g,246451 +pygame/tests/math_test.py,sha256=lEEQkuM15kgYD3RspkGFAZFj1FSrIjskuUp2JAlV_hQ,87928 +pygame/tests/midi_test.py,sha256=4AX1VUn0JsamgQrH2c11H44qucayulbcwNUuOxNZkOU,16914 +pygame/tests/mixer_music_tags.py,sha256=o0gsQDjuICFYw8j3WOlIluwk9fdA42ledU1U6DIJzNU,138 +pygame/tests/mixer_music_test.py,sha256=rc7L55A8851lZOaAv6Dht_XNHyq1F3hVdAoJoLcJKeY,13312 +pygame/tests/mixer_tags.py,sha256=qKcn8AD46H3V87xONG0iXlGH_FveeGBgf2gE1MMh2s0,132 +pygame/tests/mixer_test.py,sha256=9pKcARpHFF3PrW8aaaTGBHk1sKk-XqX7xxAm-SRnlg8,43923 +pygame/tests/mouse_test.py,sha256=AcMoPwO4O56_UQcioyaKS43kX3p4_e2addYXskqsvzY,13149 +pygame/tests/pixelarray_test.py,sha256=UEgev8LnH4x-JMFwtC3v5-6hYfmevUb4QfDKPUfz7AE,62428 +pygame/tests/pixelcopy_test.py,sha256=9HwB0wcSBEzjlBh8-xLSemlomn6CrhXOPTOZyk0egSo,25561 +pygame/tests/rect_test.py,sha256=oHS1V9MNV2IiNXS8evZ0ul68Qqo8SB8ju20RSANqjQM,75529 +pygame/tests/run_tests__tests/__init__.py,sha256=9_8wL9Scv8_Cs8HJyJHGvx1vwXErsuvlsAqNZLcJQR0,8 +pygame/tests/run_tests__tests/__pycache__/__init__.cpython-39.pyc,, +pygame/tests/run_tests__tests/__pycache__/run_tests__test.cpython-39.pyc,, +pygame/tests/run_tests__tests/all_ok/__init__.py,sha256=9_8wL9Scv8_Cs8HJyJHGvx1vwXErsuvlsAqNZLcJQR0,8 +pygame/tests/run_tests__tests/all_ok/__pycache__/__init__.cpython-39.pyc,, +pygame/tests/run_tests__tests/all_ok/__pycache__/fake_2_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/all_ok/__pycache__/fake_3_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/all_ok/__pycache__/fake_4_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/all_ok/__pycache__/fake_5_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/all_ok/__pycache__/fake_6_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/all_ok/__pycache__/no_assertions__ret_code_of_1__test.cpython-39.pyc,, +pygame/tests/run_tests__tests/all_ok/__pycache__/zero_tests_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/all_ok/fake_2_test.py,sha256=zFUNsDLmH9Pvpo-YEpvfW2raQyA6EL_BW3CuP10YIKU,899 +pygame/tests/run_tests__tests/all_ok/fake_3_test.py,sha256=zFUNsDLmH9Pvpo-YEpvfW2raQyA6EL_BW3CuP10YIKU,899 +pygame/tests/run_tests__tests/all_ok/fake_4_test.py,sha256=zFUNsDLmH9Pvpo-YEpvfW2raQyA6EL_BW3CuP10YIKU,899 +pygame/tests/run_tests__tests/all_ok/fake_5_test.py,sha256=zFUNsDLmH9Pvpo-YEpvfW2raQyA6EL_BW3CuP10YIKU,899 +pygame/tests/run_tests__tests/all_ok/fake_6_test.py,sha256=zFUNsDLmH9Pvpo-YEpvfW2raQyA6EL_BW3CuP10YIKU,899 +pygame/tests/run_tests__tests/all_ok/no_assertions__ret_code_of_1__test.py,sha256=PNrfACCpcPnO964Oxv2-9l4ciuJ-Iqw3x8HDs-kebVg,797 +pygame/tests/run_tests__tests/all_ok/zero_tests_test.py,sha256=XzLaMjkygsvNkFEqnRU9y2Ijm6bfds9n5Z6mg_LOMJQ,545 +pygame/tests/run_tests__tests/everything/__init__.py,sha256=9_8wL9Scv8_Cs8HJyJHGvx1vwXErsuvlsAqNZLcJQR0,8 +pygame/tests/run_tests__tests/everything/__pycache__/__init__.cpython-39.pyc,, +pygame/tests/run_tests__tests/everything/__pycache__/fake_2_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/everything/__pycache__/incomplete_todo_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/everything/__pycache__/magic_tag_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/everything/__pycache__/sleep_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/everything/fake_2_test.py,sha256=zFUNsDLmH9Pvpo-YEpvfW2raQyA6EL_BW3CuP10YIKU,899 +pygame/tests/run_tests__tests/everything/incomplete_todo_test.py,sha256=71myeZtFerYY2rB-j60l5Ltz3FiRCuOR4evFXtJHC34,909 +pygame/tests/run_tests__tests/everything/magic_tag_test.py,sha256=SjIKB_7aLfGdih8cotQ34m1KbSEII_1wGQUBwrWeIyY,859 +pygame/tests/run_tests__tests/everything/sleep_test.py,sha256=AyGwZk5fQAkfeCr9VewdsuD_z5BzlVfkmbZD-XetB50,715 +pygame/tests/run_tests__tests/exclude/__init__.py,sha256=9_8wL9Scv8_Cs8HJyJHGvx1vwXErsuvlsAqNZLcJQR0,8 +pygame/tests/run_tests__tests/exclude/__pycache__/__init__.cpython-39.pyc,, +pygame/tests/run_tests__tests/exclude/__pycache__/fake_2_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/exclude/__pycache__/invisible_tag_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/exclude/__pycache__/magic_tag_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/exclude/fake_2_test.py,sha256=zFUNsDLmH9Pvpo-YEpvfW2raQyA6EL_BW3CuP10YIKU,899 +pygame/tests/run_tests__tests/exclude/invisible_tag_test.py,sha256=AdHFvOK-kCRi2iUs68So6Ngef6C_LEdx3QpMLjhKtmM,925 +pygame/tests/run_tests__tests/exclude/magic_tag_test.py,sha256=SjIKB_7aLfGdih8cotQ34m1KbSEII_1wGQUBwrWeIyY,859 +pygame/tests/run_tests__tests/failures1/__init__.py,sha256=9_8wL9Scv8_Cs8HJyJHGvx1vwXErsuvlsAqNZLcJQR0,8 +pygame/tests/run_tests__tests/failures1/__pycache__/__init__.cpython-39.pyc,, +pygame/tests/run_tests__tests/failures1/__pycache__/fake_2_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/failures1/__pycache__/fake_3_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/failures1/__pycache__/fake_4_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/failures1/fake_2_test.py,sha256=zFUNsDLmH9Pvpo-YEpvfW2raQyA6EL_BW3CuP10YIKU,899 +pygame/tests/run_tests__tests/failures1/fake_3_test.py,sha256=zFUNsDLmH9Pvpo-YEpvfW2raQyA6EL_BW3CuP10YIKU,899 +pygame/tests/run_tests__tests/failures1/fake_4_test.py,sha256=xWpIVUpzevSs4bVeze48Q9jkZzss4szdw6eMOrJnZV8,949 +pygame/tests/run_tests__tests/incomplete/__init__.py,sha256=9_8wL9Scv8_Cs8HJyJHGvx1vwXErsuvlsAqNZLcJQR0,8 +pygame/tests/run_tests__tests/incomplete/__pycache__/__init__.cpython-39.pyc,, +pygame/tests/run_tests__tests/incomplete/__pycache__/fake_2_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/incomplete/__pycache__/fake_3_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/incomplete/fake_2_test.py,sha256=RVUuQZxqYScIUAflNIsXd7UE6Rxm6HHFZSi8cpz5m-k,889 +pygame/tests/run_tests__tests/incomplete/fake_3_test.py,sha256=zFUNsDLmH9Pvpo-YEpvfW2raQyA6EL_BW3CuP10YIKU,899 +pygame/tests/run_tests__tests/incomplete_todo/__init__.py,sha256=9_8wL9Scv8_Cs8HJyJHGvx1vwXErsuvlsAqNZLcJQR0,8 +pygame/tests/run_tests__tests/incomplete_todo/__pycache__/__init__.cpython-39.pyc,, +pygame/tests/run_tests__tests/incomplete_todo/__pycache__/fake_2_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/incomplete_todo/__pycache__/fake_3_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/incomplete_todo/fake_2_test.py,sha256=71myeZtFerYY2rB-j60l5Ltz3FiRCuOR4evFXtJHC34,909 +pygame/tests/run_tests__tests/incomplete_todo/fake_3_test.py,sha256=zFUNsDLmH9Pvpo-YEpvfW2raQyA6EL_BW3CuP10YIKU,899 +pygame/tests/run_tests__tests/infinite_loop/__init__.py,sha256=9_8wL9Scv8_Cs8HJyJHGvx1vwXErsuvlsAqNZLcJQR0,8 +pygame/tests/run_tests__tests/infinite_loop/__pycache__/__init__.cpython-39.pyc,, +pygame/tests/run_tests__tests/infinite_loop/__pycache__/fake_1_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/infinite_loop/__pycache__/fake_2_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/infinite_loop/fake_1_test.py,sha256=rNt-VaNziz7OmfbDXcbXbDIbwC_6ScFJ-MtenMjR68Y,906 +pygame/tests/run_tests__tests/infinite_loop/fake_2_test.py,sha256=zFUNsDLmH9Pvpo-YEpvfW2raQyA6EL_BW3CuP10YIKU,899 +pygame/tests/run_tests__tests/print_stderr/__init__.py,sha256=9_8wL9Scv8_Cs8HJyJHGvx1vwXErsuvlsAqNZLcJQR0,8 +pygame/tests/run_tests__tests/print_stderr/__pycache__/__init__.cpython-39.pyc,, +pygame/tests/run_tests__tests/print_stderr/__pycache__/fake_2_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/print_stderr/__pycache__/fake_3_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/print_stderr/__pycache__/fake_4_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/print_stderr/fake_2_test.py,sha256=zFUNsDLmH9Pvpo-YEpvfW2raQyA6EL_BW3CuP10YIKU,899 +pygame/tests/run_tests__tests/print_stderr/fake_3_test.py,sha256=6AGEff135DU_spRhZ09oDGXE4lZC3dlHU_phnfOyWYY,954 +pygame/tests/run_tests__tests/print_stderr/fake_4_test.py,sha256=xWpIVUpzevSs4bVeze48Q9jkZzss4szdw6eMOrJnZV8,949 +pygame/tests/run_tests__tests/print_stdout/__init__.py,sha256=9_8wL9Scv8_Cs8HJyJHGvx1vwXErsuvlsAqNZLcJQR0,8 +pygame/tests/run_tests__tests/print_stdout/__pycache__/__init__.cpython-39.pyc,, +pygame/tests/run_tests__tests/print_stdout/__pycache__/fake_2_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/print_stdout/__pycache__/fake_3_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/print_stdout/__pycache__/fake_4_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/print_stdout/fake_2_test.py,sha256=zFUNsDLmH9Pvpo-YEpvfW2raQyA6EL_BW3CuP10YIKU,899 +pygame/tests/run_tests__tests/print_stdout/fake_3_test.py,sha256=cruYqrh3O3MQ8fczEFloLpsrQrYmMOd6jgxMU6e5H8w,1012 +pygame/tests/run_tests__tests/print_stdout/fake_4_test.py,sha256=xWpIVUpzevSs4bVeze48Q9jkZzss4szdw6eMOrJnZV8,949 +pygame/tests/run_tests__tests/run_tests__test.py,sha256=oM-sBRUtv5QkCJ49H-LtuSLIWsX_u0_f8LeVDczZqN8,4342 +pygame/tests/run_tests__tests/timeout/__init__.py,sha256=9_8wL9Scv8_Cs8HJyJHGvx1vwXErsuvlsAqNZLcJQR0,8 +pygame/tests/run_tests__tests/timeout/__pycache__/__init__.cpython-39.pyc,, +pygame/tests/run_tests__tests/timeout/__pycache__/fake_2_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/timeout/__pycache__/sleep_test.cpython-39.pyc,, +pygame/tests/run_tests__tests/timeout/fake_2_test.py,sha256=zFUNsDLmH9Pvpo-YEpvfW2raQyA6EL_BW3CuP10YIKU,899 +pygame/tests/run_tests__tests/timeout/sleep_test.py,sha256=5EDW4U6kYN4QIid0IgHBypJ3T3a78pILILF41DPpujk,716 +pygame/tests/rwobject_test.py,sha256=LAJun6obwHADEiONe6F68WNM9qAuL7i4hqbPErjmox4,4323 +pygame/tests/scrap_tags.py,sha256=zHyLWy2JRyfw0DamlH9dz-MZq2R2uOryjH9JRu-RCkw,671 +pygame/tests/scrap_test.py,sha256=qt47IQLTs3jqf8FEP1mBC8gX6SzbeLsjJnIdszMhbYU,9160 +pygame/tests/sndarray_tags.py,sha256=ThDQxqGFaAembuWgdYGsFSWEppVezgXJ2htYRvvDaXE,190 +pygame/tests/sndarray_test.py,sha256=TGqnR0acDPEIEsKZv9nSDRxCNFDpx3RZix-GSth13J4,6297 +pygame/tests/sprite_test.py,sha256=cpH70OV5xVzaqexIl03RFJGLSdzzZiSTEM-EJoPOWM4,46638 +pygame/tests/surface_test.py,sha256=mhZm0WwNu4jxXuMD-ientJiX50ysPjd_fwkCYKvxj8g,163734 +pygame/tests/surfarray_tags.py,sha256=AwlglKM7DrjHvvcSMm-yXb-PSxsVhJkS6VE7Z8wOhes,260 +pygame/tests/surfarray_test.py,sha256=p7cV1-ND6aO47T9917QckFQ7yuXBd1-GdPHYsDDPg0U,25768 +pygame/tests/surflock_test.py,sha256=dMZkzND7-R_z-GaxN4ZIcpNtW3PsK1i7kdnizpU21UY,4728 +pygame/tests/sysfont_test.py,sha256=uf7ISqCvoiegyUvYTqOT1-kYQi_POeejL1TqXXeYF9Q,1463 +pygame/tests/test_test_.py,sha256=2LXEtnUdSV5f_vU-SvIYka21ANoN8o3BlyfKDNohPYs,21 +pygame/tests/test_utils/__init__.py,sha256=NOlEmfNGF1o7X0vZ_oUvVvV7twigUP-m4gWYOvEytyA,5371 +pygame/tests/test_utils/__pycache__/__init__.cpython-39.pyc,, +pygame/tests/test_utils/__pycache__/arrinter.cpython-39.pyc,, +pygame/tests/test_utils/__pycache__/async_sub.cpython-39.pyc,, +pygame/tests/test_utils/__pycache__/buftools.cpython-39.pyc,, +pygame/tests/test_utils/__pycache__/endian.cpython-39.pyc,, +pygame/tests/test_utils/__pycache__/png.cpython-39.pyc,, +pygame/tests/test_utils/__pycache__/run_tests.cpython-39.pyc,, +pygame/tests/test_utils/__pycache__/test_machinery.cpython-39.pyc,, +pygame/tests/test_utils/__pycache__/test_runner.cpython-39.pyc,, +pygame/tests/test_utils/arrinter.py,sha256=pIG0XmkGBzkXGeZxuNuBrn0AzgH7zG3FLbkK8ITLKIc,14843 +pygame/tests/test_utils/async_sub.py,sha256=3uoy70d7BBH27Jq3QZr3WrYoMoXSHh4hnQiKfBQiFL0,9128 +pygame/tests/test_utils/buftools.py,sha256=4jm6Cm4M0KNgdunooqvXfLQrdWbnPdglJUs_IA97-4A,23706 +pygame/tests/test_utils/endian.py,sha256=Rc7rl38YamHgi8EzB92Muu8C4XH6yltH9f5On7qfMpY,495 +pygame/tests/test_utils/png.py,sha256=zyc67s1HBUgeiuf3UUKhXmZWrEFXIAKuWs2FJjrjEgg,152382 +pygame/tests/test_utils/run_tests.py,sha256=vzxjrZZ3E_jCBjhrUDeLrR3inXYRjmYIf7gVwS0oGqA,12049 +pygame/tests/test_utils/test_machinery.py,sha256=WcbORRvQPnKXvNWq10tqD92xjVoSIUhdieEh2ozTQ1c,2483 +pygame/tests/test_utils/test_runner.py,sha256=-hrK4ZI2EXx7dMKjW3ZNDXOXiLcWPoicS-Hd0NBqY1U,9434 +pygame/tests/threads_test.py,sha256=nAu5n4xHfIG2DRAFKV8ZttQLu1akW8kqo1avoUXqlUI,7842 +pygame/tests/time_test.py,sha256=iyBWHYLbFvO3Lo12xVRspcs_9zhzNDmFG7dO50Q79nE,15336 +pygame/tests/touch_test.py,sha256=7XiB-3ywji23u8tqjDMrZ4QFNGdfmCjVN3buiDTkXic,3223 +pygame/tests/transform_test.py,sha256=-07Y0v6kEEwbtwQzmiV8vaUJPfoaszWkB7TcR1AmnfI,49044 +pygame/tests/version_test.py,sha256=dvNIneFf1c4PAKa4xo1YLAlYRDFYL8_ZeUwI1FS55Is,1536 +pygame/tests/video_test.py,sha256=TvH2fuzpNkSkhuOsB7k_jqfDlA-DGqRc9fM4k_IEcBs,696 +pygame/threads/__init__.py,sha256=KW19d_4mfBXMZuf1s2o9J6O2rdvEP1QjlgU5QkRUfW8,8074 +pygame/threads/__pycache__/__init__.cpython-39.pyc,, +pygame/time.cp39-win_amd64.pyd,sha256=6V4-hSMVq3OdUZGUVMQdmgU_utoT0Hot_caY4VFW3dc,18944 +pygame/time.pyi,sha256=BnGVQeO1cedoAucxR-HIkCwf9abC6HPlNOaVi2K8YVc,484 +pygame/transform.cp39-win_amd64.pyd,sha256=5UOO1DBoBX6BLExA9o-IItrwtSKXH8q2hlKfxE6BgXU,52224 +pygame/transform.pyi,sha256=_ALjGSYNIIaR4BUKfrHhBkQ-jZPEVwPAVjTF_v0IJ7Q,1551 +pygame/version.py,sha256=z5SbkdkakwGW2e_DocoF9xhm87ng2Fnfx0trQltTmfc,2526 +pygame/version.pyi,sha256=kHMtNQTsvLjrGnbCum1RPdNJgJ66DaN7e8n-phr7LQE,403 +pygame/zlib1.dll,sha256=sfWKF_O_1VUj5772haz1sy0cKm8lq9zUQmgSZv0mqwg,108544 diff --git a/venv/Lib/site-packages/pygame-2.1.2.dist-info/REQUESTED b/venv/Lib/site-packages/pygame-2.1.2.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/pygame-2.1.2.dist-info/WHEEL b/venv/Lib/site-packages/pygame-2.1.2.dist-info/WHEEL new file mode 100644 index 0000000..d5a9837 --- /dev/null +++ b/venv/Lib/site-packages/pygame-2.1.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: false +Tag: cp39-cp39-win_amd64 + diff --git a/venv/Lib/site-packages/pygame-2.1.2.dist-info/entry_points.txt b/venv/Lib/site-packages/pygame-2.1.2.dist-info/entry_points.txt new file mode 100644 index 0000000..e5a477e --- /dev/null +++ b/venv/Lib/site-packages/pygame-2.1.2.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[pyinstaller40] +hook-dirs = pygame.__pyinstaller:get_hook_dirs + diff --git a/venv/Lib/site-packages/pygame-2.1.2.dist-info/top_level.txt b/venv/Lib/site-packages/pygame-2.1.2.dist-info/top_level.txt new file mode 100644 index 0000000..0cb7ff1 --- /dev/null +++ b/venv/Lib/site-packages/pygame-2.1.2.dist-info/top_level.txt @@ -0,0 +1 @@ +pygame diff --git a/venv/Lib/site-packages/pygame/SDL2.dll b/venv/Lib/site-packages/pygame/SDL2.dll new file mode 100644 index 0000000..7f2b9fd Binary files /dev/null and b/venv/Lib/site-packages/pygame/SDL2.dll differ diff --git a/venv/Lib/site-packages/pygame/SDL2_image.dll b/venv/Lib/site-packages/pygame/SDL2_image.dll new file mode 100644 index 0000000..d701655 Binary files /dev/null and b/venv/Lib/site-packages/pygame/SDL2_image.dll differ diff --git a/venv/Lib/site-packages/pygame/SDL2_mixer.dll b/venv/Lib/site-packages/pygame/SDL2_mixer.dll new file mode 100644 index 0000000..40bb1c1 Binary files /dev/null and b/venv/Lib/site-packages/pygame/SDL2_mixer.dll differ diff --git a/venv/Lib/site-packages/pygame/SDL2_ttf.dll b/venv/Lib/site-packages/pygame/SDL2_ttf.dll new file mode 100644 index 0000000..575636a Binary files /dev/null and b/venv/Lib/site-packages/pygame/SDL2_ttf.dll differ diff --git a/venv/Lib/site-packages/pygame/__init__.py b/venv/Lib/site-packages/pygame/__init__.py new file mode 100644 index 0000000..d488d67 --- /dev/null +++ b/venv/Lib/site-packages/pygame/__init__.py @@ -0,0 +1,371 @@ +# coding: ascii +# pygame - Python Game Library +# Copyright (C) 2000-2001 Pete Shinners +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Pete Shinners +# pete@shinners.org +"""Pygame is a set of Python modules designed for writing games. +It is written on top of the excellent SDL library. This allows you +to create fully featured games and multimedia programs in the python +language. The package is highly portable, with games running on +Windows, MacOS, OS X, BeOS, FreeBSD, IRIX, and Linux.""" + +import sys +import os + +# Choose Windows display driver +if os.name == "nt": + # pypy does not find the dlls, so we add package folder to PATH. + pygame_dir = os.path.split(__file__)[0] + os.environ["PATH"] = os.environ["PATH"] + ";" + pygame_dir + +# when running under X11, always set the SDL window WM_CLASS to make the +# window managers correctly match the pygame window. +elif "DISPLAY" in os.environ and "SDL_VIDEO_X11_WMCLASS" not in os.environ: + os.environ["SDL_VIDEO_X11_WMCLASS"] = os.path.basename(sys.argv[0]) + + +class MissingModule: + _NOT_IMPLEMENTED_ = True + + def __init__(self, name, urgent=0): + self.name = name + exc_type, exc_msg = sys.exc_info()[:2] + self.info = str(exc_msg) + self.reason = f"{exc_type.__name__}: {self.info}" + self.urgent = urgent + if urgent: + self.warn() + + def __getattr__(self, var): + if not self.urgent: + self.warn() + self.urgent = 1 + missing_msg = f"{self.name} module not available ({self.reason})" + raise NotImplementedError(missing_msg) + + def __nonzero__(self): + return False + + __bool__ = __nonzero__ + + def warn(self): + msg_type = "import" if self.urgent else "use" + message = f"{msg_type} {self.name}: {self.info}\n({self.reason})" + try: + import warnings + + level = 4 if self.urgent else 3 + warnings.warn(message, RuntimeWarning, level) + except ImportError: + print(message) + + +# we need to import like this, each at a time. the cleanest way to import +# our modules is with the import command (not the __import__ function) +# isort: skip_file + +# first, the "required" modules +from pygame.base import * # pylint: disable=wildcard-import; lgtm[py/polluting-import] +from pygame.constants import * # now has __all__ pylint: disable=wildcard-import; lgtm[py/polluting-import] +from pygame.version import * # pylint: disable=wildcard-import; lgtm[py/polluting-import] +from pygame.rect import Rect +from pygame.rwobject import encode_string, encode_file_path +import pygame.surflock +import pygame.color + +Color = pygame.color.Color +import pygame.bufferproxy + +BufferProxy = pygame.bufferproxy.BufferProxy +import pygame.math + +Vector2 = pygame.math.Vector2 +Vector3 = pygame.math.Vector3 + +__version__ = ver + +# next, the "standard" modules +# we still allow them to be missing for stripped down pygame distributions +if get_sdl_version() < (2, 0, 0): + # cdrom only available for SDL 1.2.X + try: + import pygame.cdrom + except (ImportError, IOError): + cdrom = MissingModule("cdrom", urgent=1) + +try: + import pygame.display +except (ImportError, IOError): + display = MissingModule("display", urgent=1) + +try: + import pygame.draw +except (ImportError, IOError): + draw = MissingModule("draw", urgent=1) + +try: + import pygame.event +except (ImportError, IOError): + event = MissingModule("event", urgent=1) + +try: + import pygame.image +except (ImportError, IOError): + image = MissingModule("image", urgent=1) + +try: + import pygame.joystick +except (ImportError, IOError): + joystick = MissingModule("joystick", urgent=1) + +try: + import pygame.key +except (ImportError, IOError): + key = MissingModule("key", urgent=1) + +try: + import pygame.mouse +except (ImportError, IOError): + mouse = MissingModule("mouse", urgent=1) + +try: + import pygame.cursors + from pygame.cursors import Cursor +except (ImportError, IOError): + cursors = MissingModule("cursors", urgent=1) + Cursor = lambda: Missing_Function + +try: + import pygame.sprite +except (ImportError, IOError): + sprite = MissingModule("sprite", urgent=1) + +try: + import pygame.threads +except (ImportError, IOError): + threads = MissingModule("threads", urgent=1) + +try: + import pygame.pixelcopy +except (ImportError, IOError): + pixelcopy = MissingModule("pixelcopy", urgent=1) + + +def warn_unwanted_files(): + """warn about unneeded old files""" + + # a temporary hack to warn about camera.so and camera.pyd. + install_path = os.path.split(pygame.base.__file__)[0] + extension_ext = os.path.splitext(pygame.base.__file__)[1] + + # here are the .so/.pyd files we need to ask to remove. + ext_to_remove = ["camera"] + + # here are the .py/.pyo/.pyc files we need to ask to remove. + py_to_remove = ["color"] + + # Don't warn on Symbian. The color.py is used as a wrapper. + if os.name == "e32": + py_to_remove = [] + + # See if any of the files are there. + extension_files = [f"{x}{extension_ext}" for x in ext_to_remove] + + py_files = [ + f"{x}{py_ext}" for py_ext in [".py", ".pyc", ".pyo"] for x in py_to_remove + ] + + files = py_files + extension_files + + unwanted_files = [] + for f in files: + unwanted_files.append(os.path.join(install_path, f)) + + ask_remove = [] + for f in unwanted_files: + if os.path.exists(f): + ask_remove.append(f) + + if ask_remove: + message = "Detected old file(s). Please remove the old files:\n" + message += " ".join(ask_remove) + message += "\nLeaving them there might break pygame. Cheers!\n\n" + + try: + import warnings + + level = 4 + warnings.warn(message, RuntimeWarning, level) + except ImportError: + print(message) + + +# disable, because we hopefully don't need it. +# warn_unwanted_files() + + +try: + from pygame.surface import Surface, SurfaceType +except (ImportError, IOError): + Surface = lambda: Missing_Function + +try: + import pygame.mask + from pygame.mask import Mask +except (ImportError, IOError): + mask = MissingModule("mask", urgent=0) + Mask = lambda: Missing_Function + +try: + from pygame.pixelarray import PixelArray +except (ImportError, IOError): + PixelArray = lambda: Missing_Function + +try: + from pygame.overlay import Overlay +except (ImportError, IOError): + Overlay = lambda: Missing_Function + +try: + import pygame.time +except (ImportError, IOError): + time = MissingModule("time", urgent=1) + +try: + import pygame.transform +except (ImportError, IOError): + transform = MissingModule("transform", urgent=1) + +# lastly, the "optional" pygame modules +if "PYGAME_FREETYPE" in os.environ: + try: + import pygame.ftfont as font + + sys.modules["pygame.font"] = font + except (ImportError, IOError): + pass +try: + import pygame.font + import pygame.sysfont + + pygame.font.SysFont = pygame.sysfont.SysFont + pygame.font.get_fonts = pygame.sysfont.get_fonts + pygame.font.match_font = pygame.sysfont.match_font +except (ImportError, IOError): + font = MissingModule("font", urgent=0) + +# try and load pygame.mixer_music before mixer, for py2app... +try: + import pygame.mixer_music + + # del pygame.mixer_music + # print ("NOTE2: failed importing pygame.mixer_music in lib/__init__.py") +except (ImportError, IOError): + pass + +try: + import pygame.mixer +except (ImportError, IOError): + mixer = MissingModule("mixer", urgent=0) + +# always fails, but MissingModule needs an exception to process +try: + import pygame.movie +except (ImportError, IOError): + movie = MissingModule("movie", urgent=0) + +try: + import pygame.scrap +except (ImportError, IOError): + scrap = MissingModule("scrap", urgent=0) + +try: + import pygame.surfarray +except (ImportError, IOError): + surfarray = MissingModule("surfarray", urgent=0) + +try: + import pygame.sndarray +except (ImportError, IOError): + sndarray = MissingModule("sndarray", urgent=0) + +try: + import pygame.fastevent +except (ImportError, IOError): + fastevent = MissingModule("fastevent", urgent=0) + +# there's also a couple "internal" modules not needed +# by users, but putting them here helps "dependency finder" +# programs get everything they need (like py2exe) +try: + import pygame.imageext + + del pygame.imageext +except (ImportError, IOError): + pass + + +def packager_imports(): + """some additional imports that py2app/py2exe will want to see""" + import atexit + import numpy + import OpenGL.GL + import pygame.macosx + import pygame.colordict + + +# make Rects pickleable + +import copyreg + + +def __rect_constructor(x, y, w, h): + return Rect(x, y, w, h) + + +def __rect_reduce(r): + assert isinstance(r, Rect) + return __rect_constructor, (r.x, r.y, r.w, r.h) + + +copyreg.pickle(Rect, __rect_reduce, __rect_constructor) + + +# make Colors pickleable +def __color_constructor(r, g, b, a): + return Color(r, g, b, a) + + +def __color_reduce(c): + assert isinstance(c, Color) + return __color_constructor, (c.r, c.g, c.b, c.a) + + +copyreg.pickle(Color, __color_reduce, __color_constructor) + +# Thanks for supporting pygame. Without support now, there won't be pygame later. +if "PYGAME_HIDE_SUPPORT_PROMPT" not in os.environ: + print( + "pygame {} (SDL {}.{}.{}, Python {}.{}.{})".format( # pylint: disable=consider-using-f-string + ver, *get_sdl_version() + sys.version_info[0:3] + ) + ) + print("Hello from the pygame community. https://www.pygame.org/contribute.html") + +# cleanup namespace +del pygame, os, sys, MissingModule, copyreg diff --git a/venv/Lib/site-packages/pygame/__init__.pyi b/venv/Lib/site-packages/pygame/__init__.pyi new file mode 100644 index 0000000..9c1bc7f --- /dev/null +++ b/venv/Lib/site-packages/pygame/__init__.pyi @@ -0,0 +1,74 @@ +from typing import Any, Tuple, Callable, Optional, overload, Type + +# Re-export modules as members; see PEP 484 for stub export rules. + +# Most useful stuff +from pygame.constants import * +from pygame import surface as surface +from pygame import rect as rect +from pygame import color as color +from pygame import event as event +from pygame import draw as draw +from pygame import display as display +from pygame import font as font +from pygame import image as image +from pygame import key as key +from pygame import mixer as mixer +from pygame import mouse as mouse +from pygame import time as time +from pygame import version as version + +# Advanced stuff +from pygame import cursors as cursors +from pygame import joystick as joystick +from pygame import mask as mask +from pygame import sprite as sprite +from pygame import transform as transform +from pygame import bufferproxy as bufferproxy +from pygame import pixelarray as pixelarray +from pygame import pixelcopy as pixelcopy +from pygame import sndarray as sndarray +from pygame import surfarray as surfarray +from pygame import math as math +from pygame import fastevent as fastevent + +# Other +from pygame import scrap as scrap + +from ._common import _AnyPath + +# These classes are auto imported with pygame, so I put their declaration here +class Rect(rect.Rect): ... +class Surface(surface.Surface): ... +class Color(color.Color): ... +class PixelArray(pixelarray.PixelArray): ... +class Vector2(math.Vector2): ... +class Vector3(math.Vector3): ... +class Cursor(cursors.Cursor): ... + +def init() -> Tuple[int, int]: ... +def quit() -> None: ... +def get_init() -> bool: ... + +class error(RuntimeError): ... + +def get_error() -> str: ... +def set_error(error_msg: str) -> None: ... +def get_sdl_version() -> Tuple[int, int, int]: ... +def get_sdl_byteorder() -> int: ... +def encode_string( + obj: Optional[_AnyPath], + encoding: Optional[str] = "unicode_escape", + errors: Optional[str] = "backslashreplace", + etype: Optional[Type[Exception]] = UnicodeEncodeError, +) -> bytes: ... +@overload +def encode_file_path( + obj: Optional[_AnyPath], etype: Optional[Type[Exception]] = UnicodeEncodeError +) -> bytes: ... +@overload +def encode_file_path( + obj: Any, etype: Optional[Type[Exception]] = UnicodeEncodeError +) -> bytes: ... +def register_quit(callable: Callable[[], Any]) -> None: ... +def __getattr__(name: str) -> Any: ... # don't error on missing stubs diff --git a/venv/Lib/site-packages/pygame/__pyinstaller/__init__.py b/venv/Lib/site-packages/pygame/__pyinstaller/__init__.py new file mode 100644 index 0000000..1c52aad --- /dev/null +++ b/venv/Lib/site-packages/pygame/__pyinstaller/__init__.py @@ -0,0 +1,5 @@ +import os + + +def get_hook_dirs(): + return [os.path.dirname(__file__)] diff --git a/venv/Lib/site-packages/pygame/__pyinstaller/hook-pygame.py b/venv/Lib/site-packages/pygame/__pyinstaller/hook-pygame.py new file mode 100644 index 0000000..64ba71b --- /dev/null +++ b/venv/Lib/site-packages/pygame/__pyinstaller/hook-pygame.py @@ -0,0 +1,44 @@ +""" +binaries hook for pygame seems to be required for pygame 2.0 Windows. +Otherwise some essential DLLs will not be transfered to the exe. + +And also put hooks for datas, resources that pygame uses, to work +correctly with pyinstaller +""" + +import os +import platform + +from pygame import __file__ as pygame_main_file + +# Get pygame's folder +pygame_folder = os.path.dirname(os.path.abspath(pygame_main_file)) + +# datas is the variable that pyinstaller looks for while processing hooks +datas = [] + +# A helper to append the relative path of a resource to hook variable - datas +def _append_to_datas(file_path): + res_path = os.path.join(pygame_folder, file_path) + if os.path.exists(res_path): + datas.append((res_path, "pygame")) + + +# First append the font file, then based on the OS, append pygame icon file +_append_to_datas("freesansbold.ttf") +if platform.system() == "Darwin": + _append_to_datas("pygame_icon_mac.bmp") +else: + _append_to_datas("pygame_icon.bmp") + +if platform.system() == "Windows": + from PyInstaller.utils.hooks import collect_dynamic_libs + + pre_binaries = collect_dynamic_libs("pygame") + binaries = [] + + for b in pre_binaries: + binary, location = b + # settles all the DLLs into the top level folder, which prevents duplication + # with the DLLs already being put there. + binaries.append((binary, ".")) diff --git a/venv/Lib/site-packages/pygame/_camera_opencv.py b/venv/Lib/site-packages/pygame/_camera_opencv.py new file mode 100644 index 0000000..a16a086 --- /dev/null +++ b/venv/Lib/site-packages/pygame/_camera_opencv.py @@ -0,0 +1,174 @@ +import numpy +import cv2 +import time + +import pygame + + +def list_cameras(): + return [0] + + +def list_cameras_darwin(): + import subprocess + from xml.etree import ElementTree + + # pylint: disable=consider-using-with + flout, _ = subprocess.Popen( + "system_profiler -xml SPCameraDataType", + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ).communicate() + + last_text = None + cameras = [] + + for node in ElementTree.fromstring(flout).iterfind("./array/dict/array/dict/*"): + if last_text == "_name": + cameras.append(node.text) + last_text = node.text + + return cameras + + +class Camera(object): + def __init__(self, device=0, size=(640, 480), mode="RGB"): + self._device_index = device + self._size = size + + if mode == "RGB": + self._fmt = cv2.COLOR_BGR2RGB + elif mode == "YUV": + self._fmt = cv2.COLOR_BGR2YUV + elif mode == "HSV": + self._fmt = cv2.COLOR_BGR2HSV + else: + raise ValueError("Not a supported mode") + + self._open = False + + # all of this could have been done in the constructor, but creating + # the VideoCapture is very time consuming, so it makes more sense in the + # actual start() method + def start(self): + if self._open: + return + + self._cam = cv2.VideoCapture(self._device_index) + + if not self._cam.isOpened(): + raise ValueError("Could not open camera.") + + self._cam.set(cv2.CAP_PROP_FRAME_WIDTH, self._size[0]) + self._cam.set(cv2.CAP_PROP_FRAME_HEIGHT, self._size[1]) + + w = self._cam.get(cv2.CAP_PROP_FRAME_WIDTH) + h = self._cam.get(cv2.CAP_PROP_FRAME_HEIGHT) + self._size = (int(w), int(h)) + + self._flipx = False + self._flipy = False + self._brightness = 1 + + self._frametime = 1 / self._cam.get(cv2.CAP_PROP_FPS) + self._last_frame_time = 0 + + self._open = True + + def stop(self): + if self._open: + self._cam.release() + self._cam = None + self._open = False + + def _check_open(self): + if not self._open: + raise pygame.error("Camera must be started") + + def get_size(self): + self._check_open() + + return self._size + + def set_controls(self, hflip=None, vflip=None, brightness=None): + self._check_open() + + if hflip is not None: + self._flipx = bool(hflip) + if vflip is not None: + self._flipy = bool(vflip) + if brightness is not None: + self._cam.set(cv2.CAP_PROP_BRIGHTNESS, brightness) + + return self.get_controls() + + def get_controls(self): + self._check_open() + + return (self._flipx, self._flipy, self._cam.get(cv2.CAP_PROP_BRIGHTNESS)) + + def query_image(self): + self._check_open() + + current_time = time.time() + if current_time - self._last_frame_time > self._frametime: + return True + return False + + def get_image(self, dest_surf=None): + self._check_open() + + self._last_frame_time = time.time() + + _, image = self._cam.read() + + image = cv2.cvtColor(image, self._fmt) + + flip_code = None + if self._flipx: + if self._flipy: + flip_code = -1 + else: + flip_code = 1 + elif self._flipy: + flip_code = 0 + + if flip_code is not None: + image = cv2.flip(image, flip_code) + + image = numpy.fliplr(image) + image = numpy.rot90(image) + + surf = pygame.surfarray.make_surface(image) + + if dest_surf: + dest_surf.blit(surf, (0, 0)) + return dest_surf + + return surf + + def get_raw(self): + self._check_open() + + self._last_frame_time = time.time() + + _, image = self._cam.read() + + return image.tobytes() + + +class CameraMac(Camera): + def __init__(self, device=0, size=(640, 480), mode="RGB"): + + if isinstance(device, int): + _dev = device + elif isinstance(device, str): + _dev = list_cameras_darwin().index(device) + else: + raise TypeError( + "OpenCV-Mac backend can take device indices or names, ints or strings, not ", + str(type(device)), + ) + + super().__init__(_dev, size, mode) diff --git a/venv/Lib/site-packages/pygame/_camera_vidcapture.py b/venv/Lib/site-packages/pygame/_camera_vidcapture.py new file mode 100644 index 0000000..56df43d --- /dev/null +++ b/venv/Lib/site-packages/pygame/_camera_vidcapture.py @@ -0,0 +1,117 @@ +"""pygame.camera.Camera implementation using the videocapture module for windows. + +http://videocapture.sourceforge.net/ + +Binary windows wheels: + https://www.lfd.uci.edu/~gohlke/pythonlibs/#videocapture +""" +import pygame + + +def list_cameras(): + """Always only lists one camera. + + Functionality not supported in videocapture module. + """ + return [0] + + # this just cycles through all the cameras trying to open them + # cameras = [] + # for x in range(256): + # try: + # c = Camera(x) + # except: + # break + # cameras.append(x) + # return cameras + + +def init(): + global vidcap + try: + import vidcap as vc + except ImportError: + from VideoCapture import vidcap as vc + vidcap = vc + + +def quit(): + global vidcap + vidcap = None + + +class Camera: + # pylint: disable=unused-argument + def __init__(self, device=0, size=(640, 480), mode="RGB", show_video_window=0): + """device: VideoCapture enumerates the available video capture devices + on your system. If you have more than one device, specify + the desired one here. The device number starts from 0. + + show_video_window: 0 ... do not display a video window (the default) + 1 ... display a video window + + Mainly used for debugging, since the video window + can not be closed or moved around. + """ + self.dev = vidcap.new_Dev(device, show_video_window) + width, height = size + self.dev.setresolution(width, height) + + def display_capture_filter_properties(self): + """Displays a dialog containing the property page of the capture filter. + + For VfW drivers you may find the option to select the resolution most + likely here. + """ + self.dev.displaycapturefilterproperties() + + def display_capture_pin_properties(self): + """Displays a dialog containing the property page of the capture pin. + + For WDM drivers you may find the option to select the resolution most + likely here. + """ + self.dev.displaycapturepinproperties() + + def set_resolution(self, width, height): + """Sets the capture resolution. (without dialog)""" + self.dev.setresolution(width, height) + + def get_buffer(self): + """Returns a string containing the raw pixel data.""" + return self.dev.getbuffer() + + def start(self): + """Not implemented.""" + + def set_controls(self, **kwargs): + """Not implemented.""" + + def stop(self): + """Not implemented.""" + + def get_image(self, dest_surf=None): + """ """ + return self.get_surface(dest_surf) + + def get_surface(self, dest_surf=None): + """Returns a pygame Surface.""" + abuffer, width, height = self.get_buffer() + if not abuffer: + return None + surf = pygame.image.frombuffer(abuffer, (width, height), "BGR") + surf = pygame.transform.flip(surf, 0, 1) + # if there is a destination surface given, we blit onto that. + if dest_surf: + dest_surf.blit(surf, (0, 0)) + else: + dest_surf = surf + return dest_surf + + +if __name__ == "__main__": + import pygame.examples.camera + + pygame.camera.Camera = Camera + pygame.camera.list_cameras = list_cameras + pygame.examples.camera.main() diff --git a/venv/Lib/site-packages/pygame/_common.pyi b/venv/Lib/site-packages/pygame/_common.pyi new file mode 100644 index 0000000..f4084ba --- /dev/null +++ b/venv/Lib/site-packages/pygame/_common.pyi @@ -0,0 +1,34 @@ +from os import PathLike +from typing import IO, List, Sequence, Tuple, Union + +from typing_extensions import Protocol + +from pygame.color import Color +from pygame.math import Vector2 +from pygame.rect import Rect + +# For functions that take a file name +_AnyPath = Union[str, bytes, PathLike[str], PathLike[bytes]] + +# Most pygame functions that take a file argument should be able to handle +# a _FileArg type +_FileArg = Union[_AnyPath, IO[bytes], IO[str]] + +_Coordinate = Union[Tuple[float, float], Sequence[float], Vector2] + +# This typehint is used when a function would return an RGBA tuble +_RgbaOutput = Tuple[int, int, int, int] +_ColorValue = Union[Color, int, str, Tuple[int, int, int], List[int], _RgbaOutput] + +_CanBeRect = Union[ + Rect, + Tuple[int, int, int, int], + List[int], + Tuple[_Coordinate, _Coordinate], + List[_Coordinate], +] + +class _HasRectAttribute(Protocol): + rect: _CanBeRect + +_RectValue = Union[_CanBeRect, _HasRectAttribute] diff --git a/venv/Lib/site-packages/pygame/_sdl2/__init__.py b/venv/Lib/site-packages/pygame/_sdl2/__init__.py new file mode 100644 index 0000000..b08b716 --- /dev/null +++ b/venv/Lib/site-packages/pygame/_sdl2/__init__.py @@ -0,0 +1,3 @@ +from .sdl2 import * # pylint: disable=wildcard-import; lgtm[py/polluting-import] +from .audio import * # pylint: disable=wildcard-import; lgtm[py/polluting-import] +from .video import * # pylint: disable=wildcard-import; lgtm[py/polluting-import] diff --git a/venv/Lib/site-packages/pygame/_sdl2/__init__.pyi b/venv/Lib/site-packages/pygame/_sdl2/__init__.pyi new file mode 100644 index 0000000..0106556 --- /dev/null +++ b/venv/Lib/site-packages/pygame/_sdl2/__init__.pyi @@ -0,0 +1 @@ +from pygame._sdl2.video import * diff --git a/venv/Lib/site-packages/pygame/_sdl2/controller.pyi b/venv/Lib/site-packages/pygame/_sdl2/controller.pyi new file mode 100644 index 0000000..5437b6b --- /dev/null +++ b/venv/Lib/site-packages/pygame/_sdl2/controller.pyi @@ -0,0 +1,30 @@ +from typing import Dict, Mapping, Optional + +from pygame.joystick import Joystick + +def init() -> None: ... +def get_init() -> bool: ... +def quit() -> None: ... +def set_eventstate(state: bool) -> None: ... +def get_eventstate() -> bool: ... +def get_count() -> int: ... +def is_controller(index: int) -> bool: ... +def name_forindex(index: int) -> Optional[str]: ... + +class Controller: + def __init__(self, index: int) -> None: ... + def init(self) -> None: ... + def get_init(self) -> bool: ... + def quit(self) -> None: ... + @staticmethod + def from_joystick(joy: Joystick) -> Controller: ... + def attached(self) -> bool: ... + def as_joystick(self) -> Joystick: ... + def get_axis(self, axis: int) -> int: ... + def get_button(self, button: int) -> bool: ... + def get_mapping(self) -> Dict[str, str]: ... + def set_mapping(self, mapping: Mapping[str, str]) -> int: ... + def rumble( + self, low_frequency: float, high_frequency: float, duration: int + ) -> bool: ... + def stop_rumble(self) -> None: ... diff --git a/venv/Lib/site-packages/pygame/_sdl2/touch.pyi b/venv/Lib/site-packages/pygame/_sdl2/touch.pyi new file mode 100644 index 0000000..93e2745 --- /dev/null +++ b/venv/Lib/site-packages/pygame/_sdl2/touch.pyi @@ -0,0 +1,6 @@ +from typing import Dict, Union + +def get_num_devices() -> int: ... +def get_device(index: int) -> int: ... +def get_num_fingers(device_id: int) -> int: ... +def get_finger(touchid: int, index: int) -> Dict[str, Union[int, float]]: ... diff --git a/venv/Lib/site-packages/pygame/_sdl2/video.pyi b/venv/Lib/site-packages/pygame/_sdl2/video.pyi new file mode 100644 index 0000000..706dd42 --- /dev/null +++ b/venv/Lib/site-packages/pygame/_sdl2/video.pyi @@ -0,0 +1,154 @@ +from typing import Any, Generator, Iterable, Optional, Tuple, Union + +from pygame.color import Color +from pygame.rect import Rect +from pygame.surface import Surface + +from .._common import _CanBeRect + +WINDOWPOS_UNDEFINED: int +WINDOWPOS_CENTERED: int + +MESSAGEBOX_ERROR: int +MESSAGEBOX_WARNING: int +MESSAGEBOX_INFORMATION: int + +class RendererDriverInfo: + name: str + flags: int + num_texture_formats: int + max_texture_width: int + max_texture_height: int + +def get_drivers() -> Generator[RendererDriverInfo, None, None]: ... +def get_grabbed_window() -> Optional[Window]: ... +def messagebox( + title: str, + message: str, + window: Optional[Window] = None, + info: bool = False, + warn: bool = False, + error: bool = False, + buttons: Tuple[str, ...] = ("OK",), + return_button: int = 0, + escape_button: int = 0, +) -> int: ... + +class Window: + def __init__( + self, + title: str = "pygame", + size: Iterable[int] = (640, 480), + position: Optional[Iterable[int]] = None, + fullscreen: bool = False, + fullscreen_desktop: bool = False, + **kwargs: bool + ) -> None: ... + @staticmethod + def from_display_module() -> Window: ... + grab: bool + relative_mouse: bool + def set_windowed(self) -> None: ... + def set_fullscreen(self, desktop: bool = False) -> None: ... + title: str + def destroy(self) -> None: ... + def hide(self) -> None: ... + def show(self) -> None: ... + def focus(self, input_only: bool = False) -> None: ... + def restore(self) -> None: ... + def maximize(self) -> None: ... + def minimize(self) -> None: ... + resizable: bool + borderless: bool + def set_icon(self, surface: Surface) -> None: ... + id: int + size: Iterable[int] + position: Union[int, Iterable[int]] + opacity: float + brightness: float + display_index: int + def set_modal_for(self, Window) -> None: ... + +class Texture: + def __init__( + self, + renderer: Renderer, + size: Iterable[int], + static: bool = False, + streaming: bool = False, + target: bool = False, + ) -> None: ... + @staticmethod + def from_surface(renderer: Renderer, surface: Surface) -> Texture: ... + renderer: Renderer + width: int + height: int + alpha: int + blend_mode: int + color: Color + def get_rect(self, **kwargs: Any) -> Rect: ... + def draw( + self, + srcrect: Optional[_CanBeRect] = None, + dstrect: Optional[Union[_CanBeRect, Iterable[int]]] = None, + angle: int = 0, + origin: Optional[Iterable[int]] = None, + flipX: bool = False, + flipY: bool = False, + ) -> None: ... + def update(self, surface: Surface, area: Optional[_CanBeRect] = None) -> None: ... + +class Image: + def __init__( + self, + textureOrImage: Union[Texture, Image], + srcrect: Optional[_CanBeRect] = None, + ) -> None: ... + def get_rect(self, **kwargs: Any) -> Rect: ... + def draw( + self, srcrect: Optional[_CanBeRect] = None, dstrect: Optional[_CanBeRect] = None + ) -> None: ... + angle: float + origin: Optional[Iterable[float]] + flipX: bool + flipY: bool + color: Color + alpha: float + blend_mode: int + texture: Texture + srcrect: Rect + +class Renderer: + def __init__( + self, + window: Window, + index: int = -1, + accelerated: int = -1, + vsync: bool = False, + target_texture: bool = False, + ) -> None: ... + @staticmethod + def from_window(window: Window) -> Renderer: ... + draw_blend_mode: int + draw_color: Color + def clear(self) -> None: ... + def present(self) -> None: ... + def get_viewport(self) -> Rect: ... + def set_viewport(self, area: Optional[_CanBeRect]) -> None: ... + logical_size: Iterable[int] + scale: Iterable[float] + target: Union[Texture, None] + def blit( + self, + source: Union[Texture, Image], + dest: Optional[_CanBeRect] = None, + area: Optional[_CanBeRect] = None, + special_flags: int = 0, + ) -> Rect: ... + def draw_line(self, p1: Iterable[int], p2: Iterable[int]) -> None: ... + def draw_point(self, point: Iterable[int]) -> None: ... + def draw_rect(self, rect: _CanBeRect) -> None: ... + def fill_rect(self, rect: _CanBeRect) -> None: ... + def to_surface( + self, surface: Optional[Surface] = None, area: Optional[_CanBeRect] = None + ) -> Surface: ... diff --git a/venv/Lib/site-packages/pygame/bufferproxy.pyi b/venv/Lib/site-packages/pygame/bufferproxy.pyi new file mode 100644 index 0000000..44e7b47 --- /dev/null +++ b/venv/Lib/site-packages/pygame/bufferproxy.pyi @@ -0,0 +1,10 @@ +from typing import Any, overload + +class BufferProxy(object): + parent: Any + length: int + @overload + def __init__(self) -> None: ... + @overload + def __init__(self, parent: Any) -> None: ... + def write(self, buffer: bytes, offset: int = 0) -> None: ... diff --git a/venv/Lib/site-packages/pygame/camera.py b/venv/Lib/site-packages/pygame/camera.py new file mode 100644 index 0000000..f4174a5 --- /dev/null +++ b/venv/Lib/site-packages/pygame/camera.py @@ -0,0 +1,194 @@ +import os +import sys +import platform +import warnings +from abc import ABC, abstractmethod + +_is_init = 0 + + +def _setup_opencv_mac(): + global list_cameras, Camera, colorspace + + from pygame import _camera_opencv + + try: + from pygame import _camera + except ImportError: + _camera = None + + list_cameras = _camera_opencv.list_cameras_darwin + Camera = _camera_opencv.CameraMac + if _camera: + colorspace = _camera.colorspace + + +def _setup_opencv(): + global list_cameras, Camera, colorspace + + from pygame import _camera_opencv + + try: + from pygame import _camera + except ImportError: + _camera = None + + list_cameras = _camera_opencv.list_cameras + Camera = _camera_opencv.Camera + if _camera: + colorspace = _camera.colorspace + + +def _setup__camera(): + global list_cameras, Camera, colorspace + + from pygame import _camera + + list_cameras = _camera.list_cameras + Camera = _camera.Camera + colorspace = _camera.colorspace + + +def _setup_vidcapture(): + global list_cameras, Camera, colorspace + + from pygame import _camera_vidcapture + + try: + from pygame import _camera + except ImportError: + _camera = None + + warnings.warn( + "The VideoCapture backend is not recommended and may be removed." + "For Python3 and Windows 8+, there is now a native Windows backend built into pygame.", + DeprecationWarning, + stacklevel=2, + ) + + _camera_vidcapture.init() + list_cameras = _camera_vidcapture.list_cameras + Camera = _camera_vidcapture.Camera + if _camera: + colorspace = _camera.colorspace + + +def get_backends(): + possible_backends = [] + + if sys.platform == "win32" and int(platform.win32_ver()[0]) > 8: + possible_backends.append("_camera (MSMF)") + + if "linux" in sys.platform: + possible_backends.append("_camera (V4L2)") + + if "darwin" in sys.platform: + possible_backends.append("OpenCV-Mac") + + possible_backends.append("OpenCV") + + if sys.platform == "win32": + possible_backends.append("VidCapture") + + # see if we have any user specified defaults in environments. + camera_env = os.environ.get("PYGAME_CAMERA", "") + if camera_env == "opencv": # prioritize opencv + if "OpenCV" in possible_backends: + possible_backends.remove("OpenCV") + possible_backends = ["OpenCV"] + possible_backends + if camera_env == "vidcapture": # prioritize vidcapture + if "VideoCapture" in possible_backends: + possible_backends.remove("VideoCapture") + possible_backends = ["VideoCapture"] + possible_backends + + return possible_backends + + +backend_table = { + "opencv-mac": _setup_opencv_mac, + "opencv": _setup_opencv, + "_camera (msmf)": _setup__camera, + "_camera (v4l2)": _setup__camera, + "videocapture": _setup_vidcapture, +} + + +def init(backend=None): + global _is_init + # select the camera module to import here. + + backends = get_backends() + + if not backends: + _is_init = 1 + return + + backends = [b.lower() for b in backends] + + if not backend: + backend = backends[0] + else: + backend = backend.lower() + + if backend not in backend_table: + raise ValueError("unrecognized backend name") + + if backend not in backends: + warnings.warn( + "We don't think this is a supported backend on this system, but we'll try it...", + Warning, + stacklevel=2, + ) + + backend_table[backend]() + + _is_init = 1 + + +def quit(): + global _is_init + _is_init = 0 + + +class AbstractCamera(ABC): + @abstractmethod + def __init__(self, device=0, size=(320, 200), mode="RGB"): + """ """ + + @abstractmethod + def set_resolution(self, width, height): + """Sets the capture resolution. (without dialog)""" + + @abstractmethod + def start(self): + """ """ + + @abstractmethod + def stop(self): + """ """ + + @abstractmethod + def get_buffer(self): + """ """ + + @abstractmethod + def set_controls(self, **kwargs): + """ """ + + @abstractmethod + def get_image(self, dest_surf=None): + """ """ + + @abstractmethod + def get_surface(self, dest_surf=None): + """ """ + + +if __name__ == "__main__": + + # try and use this camera stuff with the pygame camera example. + import pygame.examples.camera + + # pygame.camera.Camera = Camera + # pygame.camera.list_cameras = list_cameras + pygame.examples.camera.main() diff --git a/venv/Lib/site-packages/pygame/camera.pyi b/venv/Lib/site-packages/pygame/camera.pyi new file mode 100644 index 0000000..ba9a051 --- /dev/null +++ b/venv/Lib/site-packages/pygame/camera.pyi @@ -0,0 +1,29 @@ +from typing import List, Optional, Tuple, Union + +from pygame.surface import Surface + +def get_backends() -> List[str]: ... +def init(backend: Optional[str]) -> None: ... +def quit() -> None: ... +def list_cameras() -> List[str]: ... + +class Camera: + def __init__( + self, + device: str, + size: Union[Tuple[int, int], List[int]] = (640, 480), + format: str = "RGB", + ) -> None: ... + def start(self) -> None: ... + def stop(self) -> None: ... + def get_controls(self) -> Tuple[bool, bool, int]: ... + def set_controls( + self, + hflip: bool = ..., + vflip: bool = ..., + brightness: int = ..., + ) -> Tuple[bool, bool, int]: ... + def get_size(self) -> Tuple[int, int]: ... + def query_image(self) -> bool: ... + def get_image(self, surface: Optional[Surface] = None) -> Surface: ... + def get_raw(self) -> bytes: ... diff --git a/venv/Lib/site-packages/pygame/color.pyi b/venv/Lib/site-packages/pygame/color.pyi new file mode 100644 index 0000000..8af8f3f --- /dev/null +++ b/venv/Lib/site-packages/pygame/color.pyi @@ -0,0 +1,40 @@ +from typing import Tuple, overload + +from ._common import _ColorValue + +class Color: + r: int + g: int + b: int + a: int + cmy: Tuple[float, float, float] + hsva: Tuple[float, float, float, float] + hsla: Tuple[float, float, float, float] + i1i2i3: Tuple[float, float, float] + __hash__: None # type: ignore + @overload + def __init__(self, r: int, g: int, b: int, a: int = 255) -> None: ... + @overload + def __init__(self, rgbvalue: _ColorValue) -> None: ... + @overload + def __getitem__(self, i: int) -> int: ... + @overload + def __getitem__(self, s: slice) -> Tuple[int]: ... + def __setitem__(self, key: int, value: int) -> None: ... + def __add__(self, other: Color) -> Color: ... + def __sub__(self, other: Color) -> Color: ... + def __mul__(self, other: Color) -> Color: ... + def __floordiv__(self, other: Color) -> Color: ... + def __mod__(self, other: Color) -> Color: ... + def __int__(self) -> int: ... + def __float__(self) -> float: ... + def __len__(self) -> int: ... + def normalize(self) -> Tuple[float, float, float, float]: ... + def correct_gamma(self, gamma: float) -> Color: ... + def set_length(self, length: int) -> None: ... + def lerp(self, color: _ColorValue, amount: float) -> Color: ... + def premul_alpha(self) -> Color: ... + @overload + def update(self, r: int, g: int, b: int, a: int = 255) -> None: ... + @overload + def update(self, rgbvalue: _ColorValue) -> None: ... diff --git a/venv/Lib/site-packages/pygame/colordict.py b/venv/Lib/site-packages/pygame/colordict.py new file mode 100644 index 0000000..0bd7256 --- /dev/null +++ b/venv/Lib/site-packages/pygame/colordict.py @@ -0,0 +1,692 @@ +# pygame - Python Game Library +# Copyright (C) 2000-2003 Pete Shinners +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Pete Shinners +# pete@shinners.org + +""" A dictionary of RGBA tuples indexed by color names. + +See https://www.pygame.org/docs/ref/color_list.html for sample swatches. +""" + +THECOLORS = { + "aliceblue": (240, 248, 255, 255), + "antiquewhite": (250, 235, 215, 255), + "antiquewhite1": (255, 239, 219, 255), + "antiquewhite2": (238, 223, 204, 255), + "antiquewhite3": (205, 192, 176, 255), + "antiquewhite4": (139, 131, 120, 255), + "aqua": (0, 255, 255, 255), + "aquamarine": (127, 255, 212, 255), + "aquamarine1": (127, 255, 212, 255), + "aquamarine2": (118, 238, 198, 255), + "aquamarine3": (102, 205, 170, 255), + "aquamarine4": (69, 139, 116, 255), + "azure": (240, 255, 255, 255), + "azure1": (240, 255, 255, 255), + "azure3": (193, 205, 205, 255), + "azure2": (224, 238, 238, 255), + "azure4": (131, 139, 139, 255), + "beige": (245, 245, 220, 255), + "bisque": (255, 228, 196, 255), + "bisque1": (255, 228, 196, 255), + "bisque2": (238, 213, 183, 255), + "bisque3": (205, 183, 158, 255), + "bisque4": (139, 125, 107, 255), + "black": (0, 0, 0, 255), + "blanchedalmond": (255, 235, 205, 255), + "blue": (0, 0, 255, 255), + "blue1": (0, 0, 255, 255), + "blue2": (0, 0, 238, 255), + "blue3": (0, 0, 205, 255), + "blue4": (0, 0, 139, 255), + "blueviolet": (138, 43, 226, 255), + "brown": (165, 42, 42, 255), + "brown1": (255, 64, 64, 255), + "brown2": (238, 59, 59, 255), + "brown3": (205, 51, 51, 255), + "brown4": (139, 35, 35, 255), + "burlywood": (222, 184, 135, 255), + "burlywood1": (255, 211, 155, 255), + "burlywood2": (238, 197, 145, 255), + "burlywood3": (205, 170, 125, 255), + "burlywood4": (139, 115, 85, 255), + "cadetblue": (95, 158, 160, 255), + "cadetblue1": (152, 245, 255, 255), + "cadetblue2": (142, 229, 238, 255), + "cadetblue3": (122, 197, 205, 255), + "cadetblue4": (83, 134, 139, 255), + "chartreuse": (127, 255, 0, 255), + "chartreuse1": (127, 255, 0, 255), + "chartreuse2": (118, 238, 0, 255), + "chartreuse3": (102, 205, 0, 255), + "chartreuse4": (69, 139, 0, 255), + "chocolate": (210, 105, 30, 255), + "chocolate1": (255, 127, 36, 255), + "chocolate2": (238, 118, 33, 255), + "chocolate3": (205, 102, 29, 255), + "chocolate4": (139, 69, 19, 255), + "coral": (255, 127, 80, 255), + "coral1": (255, 114, 86, 255), + "coral2": (238, 106, 80, 255), + "coral3": (205, 91, 69, 255), + "coral4": (139, 62, 47, 255), + "cornflowerblue": (100, 149, 237, 255), + "cornsilk": (255, 248, 220, 255), + "cornsilk1": (255, 248, 220, 255), + "cornsilk2": (238, 232, 205, 255), + "cornsilk3": (205, 200, 177, 255), + "cornsilk4": (139, 136, 120, 255), + "crimson": (220, 20, 60, 255), + "cyan": (0, 255, 255, 255), + "cyan1": (0, 255, 255, 255), + "cyan2": (0, 238, 238, 255), + "cyan3": (0, 205, 205, 255), + "cyan4": (0, 139, 139, 255), + "darkblue": (0, 0, 139, 255), + "darkcyan": (0, 139, 139, 255), + "darkgoldenrod": (184, 134, 11, 255), + "darkgoldenrod1": (255, 185, 15, 255), + "darkgoldenrod2": (238, 173, 14, 255), + "darkgoldenrod3": (205, 149, 12, 255), + "darkgoldenrod4": (139, 101, 8, 255), + "darkgray": (169, 169, 169, 255), + "darkgreen": (0, 100, 0, 255), + "darkgrey": (169, 169, 169, 255), + "darkkhaki": (189, 183, 107, 255), + "darkmagenta": (139, 0, 139, 255), + "darkolivegreen": (85, 107, 47, 255), + "darkolivegreen1": (202, 255, 112, 255), + "darkolivegreen2": (188, 238, 104, 255), + "darkolivegreen3": (162, 205, 90, 255), + "darkolivegreen4": (110, 139, 61, 255), + "darkorange": (255, 140, 0, 255), + "darkorange1": (255, 127, 0, 255), + "darkorange2": (238, 118, 0, 255), + "darkorange3": (205, 102, 0, 255), + "darkorange4": (139, 69, 0, 255), + "darkorchid": (153, 50, 204, 255), + "darkorchid1": (191, 62, 255, 255), + "darkorchid2": (178, 58, 238, 255), + "darkorchid3": (154, 50, 205, 255), + "darkorchid4": (104, 34, 139, 255), + "darkred": (139, 0, 0, 255), + "darksalmon": (233, 150, 122, 255), + "darkseagreen": (143, 188, 143, 255), + "darkseagreen1": (193, 255, 193, 255), + "darkseagreen2": (180, 238, 180, 255), + "darkseagreen3": (155, 205, 155, 255), + "darkseagreen4": (105, 139, 105, 255), + "darkslateblue": (72, 61, 139, 255), + "darkslategray": (47, 79, 79, 255), + "darkslategray1": (151, 255, 255, 255), + "darkslategray2": (141, 238, 238, 255), + "darkslategray3": (121, 205, 205, 255), + "darkslategray4": (82, 139, 139, 255), + "darkslategrey": (47, 79, 79, 255), + "darkturquoise": (0, 206, 209, 255), + "darkviolet": (148, 0, 211, 255), + "deeppink": (255, 20, 147, 255), + "deeppink1": (255, 20, 147, 255), + "deeppink2": (238, 18, 137, 255), + "deeppink3": (205, 16, 118, 255), + "deeppink4": (139, 10, 80, 255), + "deepskyblue": (0, 191, 255, 255), + "deepskyblue1": (0, 191, 255, 255), + "deepskyblue2": (0, 178, 238, 255), + "deepskyblue3": (0, 154, 205, 255), + "deepskyblue4": (0, 104, 139, 255), + "dimgray": (105, 105, 105, 255), + "dimgrey": (105, 105, 105, 255), + "dodgerblue": (30, 144, 255, 255), + "dodgerblue1": (30, 144, 255, 255), + "dodgerblue2": (28, 134, 238, 255), + "dodgerblue3": (24, 116, 205, 255), + "dodgerblue4": (16, 78, 139, 255), + "firebrick": (178, 34, 34, 255), + "firebrick1": (255, 48, 48, 255), + "firebrick2": (238, 44, 44, 255), + "firebrick3": (205, 38, 38, 255), + "firebrick4": (139, 26, 26, 255), + "floralwhite": (255, 250, 240, 255), + "forestgreen": (34, 139, 34, 255), + "fuchsia": (255, 0, 255, 255), + "gainsboro": (220, 220, 220, 255), + "ghostwhite": (248, 248, 255, 255), + "gold": (255, 215, 0, 255), + "gold1": (255, 215, 0, 255), + "gold2": (238, 201, 0, 255), + "gold3": (205, 173, 0, 255), + "gold4": (139, 117, 0, 255), + "goldenrod": (218, 165, 32, 255), + "goldenrod1": (255, 193, 37, 255), + "goldenrod2": (238, 180, 34, 255), + "goldenrod3": (205, 155, 29, 255), + "goldenrod4": (139, 105, 20, 255), + "gray": (190, 190, 190, 255), + "gray0": (0, 0, 0, 255), + "gray1": (3, 3, 3, 255), + "gray2": (5, 5, 5, 255), + "gray3": (8, 8, 8, 255), + "gray4": (10, 10, 10, 255), + "gray5": (13, 13, 13, 255), + "gray6": (15, 15, 15, 255), + "gray7": (18, 18, 18, 255), + "gray8": (20, 20, 20, 255), + "gray9": (23, 23, 23, 255), + "gray10": (26, 26, 26, 255), + "gray11": (28, 28, 28, 255), + "gray12": (31, 31, 31, 255), + "gray13": (33, 33, 33, 255), + "gray14": (36, 36, 36, 255), + "gray15": (38, 38, 38, 255), + "gray16": (41, 41, 41, 255), + "gray17": (43, 43, 43, 255), + "gray18": (46, 46, 46, 255), + "gray19": (48, 48, 48, 255), + "gray20": (51, 51, 51, 255), + "gray21": (54, 54, 54, 255), + "gray22": (56, 56, 56, 255), + "gray23": (59, 59, 59, 255), + "gray24": (61, 61, 61, 255), + "gray25": (64, 64, 64, 255), + "gray26": (66, 66, 66, 255), + "gray27": (69, 69, 69, 255), + "gray28": (71, 71, 71, 255), + "gray29": (74, 74, 74, 255), + "gray30": (77, 77, 77, 255), + "gray31": (79, 79, 79, 255), + "gray32": (82, 82, 82, 255), + "gray33": (84, 84, 84, 255), + "gray34": (87, 87, 87, 255), + "gray35": (89, 89, 89, 255), + "gray36": (92, 92, 92, 255), + "gray37": (94, 94, 94, 255), + "gray38": (97, 97, 97, 255), + "gray39": (99, 99, 99, 255), + "gray40": (102, 102, 102, 255), + "gray41": (105, 105, 105, 255), + "gray42": (107, 107, 107, 255), + "gray43": (110, 110, 110, 255), + "gray44": (112, 112, 112, 255), + "gray45": (115, 115, 115, 255), + "gray46": (117, 117, 117, 255), + "gray47": (120, 120, 120, 255), + "gray48": (122, 122, 122, 255), + "gray49": (125, 125, 125, 255), + "gray50": (127, 127, 127, 255), + "gray51": (130, 130, 130, 255), + "gray52": (133, 133, 133, 255), + "gray53": (135, 135, 135, 255), + "gray54": (138, 138, 138, 255), + "gray55": (140, 140, 140, 255), + "gray56": (143, 143, 143, 255), + "gray57": (145, 145, 145, 255), + "gray58": (148, 148, 148, 255), + "gray59": (150, 150, 150, 255), + "gray60": (153, 153, 153, 255), + "gray61": (156, 156, 156, 255), + "gray62": (158, 158, 158, 255), + "gray63": (161, 161, 161, 255), + "gray64": (163, 163, 163, 255), + "gray65": (166, 166, 166, 255), + "gray66": (168, 168, 168, 255), + "gray67": (171, 171, 171, 255), + "gray68": (173, 173, 173, 255), + "gray69": (176, 176, 176, 255), + "gray70": (179, 179, 179, 255), + "gray71": (181, 181, 181, 255), + "gray72": (184, 184, 184, 255), + "gray73": (186, 186, 186, 255), + "gray74": (189, 189, 189, 255), + "gray75": (191, 191, 191, 255), + "gray76": (194, 194, 194, 255), + "gray77": (196, 196, 196, 255), + "gray78": (199, 199, 199, 255), + "gray79": (201, 201, 201, 255), + "gray80": (204, 204, 204, 255), + "gray81": (207, 207, 207, 255), + "gray82": (209, 209, 209, 255), + "gray83": (212, 212, 212, 255), + "gray84": (214, 214, 214, 255), + "gray85": (217, 217, 217, 255), + "gray86": (219, 219, 219, 255), + "gray87": (222, 222, 222, 255), + "gray88": (224, 224, 224, 255), + "gray89": (227, 227, 227, 255), + "gray90": (229, 229, 229, 255), + "gray91": (232, 232, 232, 255), + "gray92": (235, 235, 235, 255), + "gray93": (237, 237, 237, 255), + "gray94": (240, 240, 240, 255), + "gray95": (242, 242, 242, 255), + "gray96": (245, 245, 245, 255), + "gray97": (247, 247, 247, 255), + "gray98": (250, 250, 250, 255), + "gray99": (252, 252, 252, 255), + "gray100": (255, 255, 255, 255), + "green": (0, 255, 0, 255), + "green1": (0, 255, 0, 255), + "green2": (0, 238, 0, 255), + "green3": (0, 205, 0, 255), + "green4": (0, 139, 0, 255), + "greenyellow": (173, 255, 47, 255), + "grey": (190, 190, 190, 255), + "grey0": (0, 0, 0, 255), + "grey1": (3, 3, 3, 255), + "grey2": (5, 5, 5, 255), + "grey3": (8, 8, 8, 255), + "grey4": (10, 10, 10, 255), + "grey5": (13, 13, 13, 255), + "grey6": (15, 15, 15, 255), + "grey7": (18, 18, 18, 255), + "grey8": (20, 20, 20, 255), + "grey9": (23, 23, 23, 255), + "grey10": (26, 26, 26, 255), + "grey11": (28, 28, 28, 255), + "grey12": (31, 31, 31, 255), + "grey13": (33, 33, 33, 255), + "grey14": (36, 36, 36, 255), + "grey15": (38, 38, 38, 255), + "grey16": (41, 41, 41, 255), + "grey17": (43, 43, 43, 255), + "grey18": (46, 46, 46, 255), + "grey19": (48, 48, 48, 255), + "grey20": (51, 51, 51, 255), + "grey21": (54, 54, 54, 255), + "grey22": (56, 56, 56, 255), + "grey23": (59, 59, 59, 255), + "grey24": (61, 61, 61, 255), + "grey25": (64, 64, 64, 255), + "grey26": (66, 66, 66, 255), + "grey27": (69, 69, 69, 255), + "grey28": (71, 71, 71, 255), + "grey29": (74, 74, 74, 255), + "grey30": (77, 77, 77, 255), + "grey31": (79, 79, 79, 255), + "grey32": (82, 82, 82, 255), + "grey33": (84, 84, 84, 255), + "grey34": (87, 87, 87, 255), + "grey35": (89, 89, 89, 255), + "grey36": (92, 92, 92, 255), + "grey37": (94, 94, 94, 255), + "grey38": (97, 97, 97, 255), + "grey39": (99, 99, 99, 255), + "grey40": (102, 102, 102, 255), + "grey41": (105, 105, 105, 255), + "grey42": (107, 107, 107, 255), + "grey43": (110, 110, 110, 255), + "grey44": (112, 112, 112, 255), + "grey45": (115, 115, 115, 255), + "grey46": (117, 117, 117, 255), + "grey47": (120, 120, 120, 255), + "grey48": (122, 122, 122, 255), + "grey49": (125, 125, 125, 255), + "grey50": (127, 127, 127, 255), + "grey51": (130, 130, 130, 255), + "grey52": (133, 133, 133, 255), + "grey53": (135, 135, 135, 255), + "grey54": (138, 138, 138, 255), + "grey55": (140, 140, 140, 255), + "grey56": (143, 143, 143, 255), + "grey57": (145, 145, 145, 255), + "grey58": (148, 148, 148, 255), + "grey59": (150, 150, 150, 255), + "grey60": (153, 153, 153, 255), + "grey61": (156, 156, 156, 255), + "grey62": (158, 158, 158, 255), + "grey63": (161, 161, 161, 255), + "grey64": (163, 163, 163, 255), + "grey65": (166, 166, 166, 255), + "grey66": (168, 168, 168, 255), + "grey67": (171, 171, 171, 255), + "grey68": (173, 173, 173, 255), + "grey69": (176, 176, 176, 255), + "grey70": (179, 179, 179, 255), + "grey71": (181, 181, 181, 255), + "grey72": (184, 184, 184, 255), + "grey73": (186, 186, 186, 255), + "grey74": (189, 189, 189, 255), + "grey75": (191, 191, 191, 255), + "grey76": (194, 194, 194, 255), + "grey77": (196, 196, 196, 255), + "grey78": (199, 199, 199, 255), + "grey79": (201, 201, 201, 255), + "grey80": (204, 204, 204, 255), + "grey81": (207, 207, 207, 255), + "grey82": (209, 209, 209, 255), + "grey83": (212, 212, 212, 255), + "grey84": (214, 214, 214, 255), + "grey85": (217, 217, 217, 255), + "grey86": (219, 219, 219, 255), + "grey87": (222, 222, 222, 255), + "grey88": (224, 224, 224, 255), + "grey89": (227, 227, 227, 255), + "grey90": (229, 229, 229, 255), + "grey91": (232, 232, 232, 255), + "grey92": (235, 235, 235, 255), + "grey93": (237, 237, 237, 255), + "grey94": (240, 240, 240, 255), + "grey95": (242, 242, 242, 255), + "grey96": (245, 245, 245, 255), + "grey97": (247, 247, 247, 255), + "grey98": (250, 250, 250, 255), + "grey99": (252, 252, 252, 255), + "grey100": (255, 255, 255, 255), + "honeydew": (240, 255, 240, 255), + "honeydew1": (240, 255, 240, 255), + "honeydew2": (224, 238, 224, 255), + "honeydew3": (193, 205, 193, 255), + "honeydew4": (131, 139, 131, 255), + "hotpink": (255, 105, 180, 255), + "hotpink1": (255, 110, 180, 255), + "hotpink2": (238, 106, 167, 255), + "hotpink3": (205, 96, 144, 255), + "hotpink4": (139, 58, 98, 255), + "indianred": (205, 92, 92, 255), + "indianred1": (255, 106, 106, 255), + "indianred2": (238, 99, 99, 255), + "indianred3": (205, 85, 85, 255), + "indianred4": (139, 58, 58, 255), + "indigo": (75, 0, 130, 255), + "ivory": (255, 255, 240, 255), + "ivory1": (255, 255, 240, 255), + "ivory2": (238, 238, 224, 255), + "ivory3": (205, 205, 193, 255), + "ivory4": (139, 139, 131, 255), + "khaki": (240, 230, 140, 255), + "khaki1": (255, 246, 143, 255), + "khaki2": (238, 230, 133, 255), + "khaki3": (205, 198, 115, 255), + "khaki4": (139, 134, 78, 255), + "lavender": (230, 230, 250, 255), + "lavenderblush": (255, 240, 245, 255), + "lavenderblush1": (255, 240, 245, 255), + "lavenderblush2": (238, 224, 229, 255), + "lavenderblush3": (205, 193, 197, 255), + "lavenderblush4": (139, 131, 134, 255), + "lawngreen": (124, 252, 0, 255), + "lemonchiffon": (255, 250, 205, 255), + "lemonchiffon1": (255, 250, 205, 255), + "lemonchiffon2": (238, 233, 191, 255), + "lemonchiffon3": (205, 201, 165, 255), + "lemonchiffon4": (139, 137, 112, 255), + "lightblue": (173, 216, 230, 255), + "lightblue1": (191, 239, 255, 255), + "lightblue2": (178, 223, 238, 255), + "lightblue3": (154, 192, 205, 255), + "lightblue4": (104, 131, 139, 255), + "lightcoral": (240, 128, 128, 255), + "lightcyan": (224, 255, 255, 255), + "lightcyan1": (224, 255, 255, 255), + "lightcyan2": (209, 238, 238, 255), + "lightcyan3": (180, 205, 205, 255), + "lightcyan4": (122, 139, 139, 255), + "lightgoldenrod": (238, 221, 130, 255), + "lightgoldenrod1": (255, 236, 139, 255), + "lightgoldenrod2": (238, 220, 130, 255), + "lightgoldenrod3": (205, 190, 112, 255), + "lightgoldenrod4": (139, 129, 76, 255), + "lightgoldenrodyellow": (250, 250, 210, 255), + "lightgray": (211, 211, 211, 255), + "lightgreen": (144, 238, 144, 255), + "lightgrey": (211, 211, 211, 255), + "lightpink": (255, 182, 193, 255), + "lightpink1": (255, 174, 185, 255), + "lightpink2": (238, 162, 173, 255), + "lightpink3": (205, 140, 149, 255), + "lightpink4": (139, 95, 101, 255), + "lightsalmon": (255, 160, 122, 255), + "lightsalmon1": (255, 160, 122, 255), + "lightsalmon2": (238, 149, 114, 255), + "lightsalmon3": (205, 129, 98, 255), + "lightsalmon4": (139, 87, 66, 255), + "lightseagreen": (32, 178, 170, 255), + "lightskyblue": (135, 206, 250, 255), + "lightskyblue1": (176, 226, 255, 255), + "lightskyblue2": (164, 211, 238, 255), + "lightskyblue3": (141, 182, 205, 255), + "lightskyblue4": (96, 123, 139, 255), + "lightslateblue": (132, 112, 255, 255), + "lightslategray": (119, 136, 153, 255), + "lightslategrey": (119, 136, 153, 255), + "lightsteelblue": (176, 196, 222, 255), + "lightsteelblue1": (202, 225, 255, 255), + "lightsteelblue2": (188, 210, 238, 255), + "lightsteelblue3": (162, 181, 205, 255), + "lightsteelblue4": (110, 123, 139, 255), + "lightyellow": (255, 255, 224, 255), + "lightyellow1": (255, 255, 224, 255), + "lightyellow2": (238, 238, 209, 255), + "lightyellow3": (205, 205, 180, 255), + "lightyellow4": (139, 139, 122, 255), + "linen": (250, 240, 230, 255), + "lime": (0, 255, 0, 255), + "limegreen": (50, 205, 50, 255), + "magenta": (255, 0, 255, 255), + "magenta1": (255, 0, 255, 255), + "magenta2": (238, 0, 238, 255), + "magenta3": (205, 0, 205, 255), + "magenta4": (139, 0, 139, 255), + "maroon": (176, 48, 96, 255), + "maroon1": (255, 52, 179, 255), + "maroon2": (238, 48, 167, 255), + "maroon3": (205, 41, 144, 255), + "maroon4": (139, 28, 98, 255), + "mediumaquamarine": (102, 205, 170, 255), + "mediumblue": (0, 0, 205, 255), + "mediumorchid": (186, 85, 211, 255), + "mediumorchid1": (224, 102, 255, 255), + "mediumorchid2": (209, 95, 238, 255), + "mediumorchid3": (180, 82, 205, 255), + "mediumorchid4": (122, 55, 139, 255), + "mediumpurple": (147, 112, 219, 255), + "mediumpurple1": (171, 130, 255, 255), + "mediumpurple2": (159, 121, 238, 255), + "mediumpurple3": (137, 104, 205, 255), + "mediumpurple4": (93, 71, 139, 255), + "mediumseagreen": (60, 179, 113, 255), + "mediumslateblue": (123, 104, 238, 255), + "mediumspringgreen": (0, 250, 154, 255), + "mediumturquoise": (72, 209, 204, 255), + "mediumvioletred": (199, 21, 133, 255), + "midnightblue": (25, 25, 112, 255), + "mintcream": (245, 255, 250, 255), + "mistyrose": (255, 228, 225, 255), + "mistyrose1": (255, 228, 225, 255), + "mistyrose2": (238, 213, 210, 255), + "mistyrose3": (205, 183, 181, 255), + "mistyrose4": (139, 125, 123, 255), + "moccasin": (255, 228, 181, 255), + "navajowhite": (255, 222, 173, 255), + "navajowhite1": (255, 222, 173, 255), + "navajowhite2": (238, 207, 161, 255), + "navajowhite3": (205, 179, 139, 255), + "navajowhite4": (139, 121, 94, 255), + "navy": (0, 0, 128, 255), + "navyblue": (0, 0, 128, 255), + "oldlace": (253, 245, 230, 255), + "olive": (128, 128, 0, 255), + "olivedrab": (107, 142, 35, 255), + "olivedrab1": (192, 255, 62, 255), + "olivedrab2": (179, 238, 58, 255), + "olivedrab3": (154, 205, 50, 255), + "olivedrab4": (105, 139, 34, 255), + "orange": (255, 165, 0, 255), + "orange1": (255, 165, 0, 255), + "orange2": (238, 154, 0, 255), + "orange3": (205, 133, 0, 255), + "orange4": (139, 90, 0, 255), + "orangered": (255, 69, 0, 255), + "orangered1": (255, 69, 0, 255), + "orangered2": (238, 64, 0, 255), + "orangered3": (205, 55, 0, 255), + "orangered4": (139, 37, 0, 255), + "orchid": (218, 112, 214, 255), + "orchid1": (255, 131, 250, 255), + "orchid2": (238, 122, 233, 255), + "orchid3": (205, 105, 201, 255), + "orchid4": (139, 71, 137, 255), + "palegreen": (152, 251, 152, 255), + "palegreen1": (154, 255, 154, 255), + "palegreen2": (144, 238, 144, 255), + "palegreen3": (124, 205, 124, 255), + "palegreen4": (84, 139, 84, 255), + "palegoldenrod": (238, 232, 170, 255), + "paleturquoise": (175, 238, 238, 255), + "paleturquoise1": (187, 255, 255, 255), + "paleturquoise2": (174, 238, 238, 255), + "paleturquoise3": (150, 205, 205, 255), + "paleturquoise4": (102, 139, 139, 255), + "palevioletred": (219, 112, 147, 255), + "palevioletred1": (255, 130, 171, 255), + "palevioletred2": (238, 121, 159, 255), + "palevioletred3": (205, 104, 137, 255), + "palevioletred4": (139, 71, 93, 255), + "papayawhip": (255, 239, 213, 255), + "peachpuff": (255, 218, 185, 255), + "peachpuff1": (255, 218, 185, 255), + "peachpuff2": (238, 203, 173, 255), + "peachpuff3": (205, 175, 149, 255), + "peachpuff4": (139, 119, 101, 255), + "peru": (205, 133, 63, 255), + "pink": (255, 192, 203, 255), + "pink1": (255, 181, 197, 255), + "pink2": (238, 169, 184, 255), + "pink3": (205, 145, 158, 255), + "pink4": (139, 99, 108, 255), + "plum": (221, 160, 221, 255), + "plum1": (255, 187, 255, 255), + "plum2": (238, 174, 238, 255), + "plum3": (205, 150, 205, 255), + "plum4": (139, 102, 139, 255), + "powderblue": (176, 224, 230, 255), + "purple": (160, 32, 240, 255), + "purple1": (155, 48, 255, 255), + "purple2": (145, 44, 238, 255), + "purple3": (125, 38, 205, 255), + "purple4": (85, 26, 139, 255), + "red": (255, 0, 0, 255), + "red1": (255, 0, 0, 255), + "red2": (238, 0, 0, 255), + "red3": (205, 0, 0, 255), + "red4": (139, 0, 0, 255), + "rosybrown": (188, 143, 143, 255), + "rosybrown1": (255, 193, 193, 255), + "rosybrown2": (238, 180, 180, 255), + "rosybrown3": (205, 155, 155, 255), + "rosybrown4": (139, 105, 105, 255), + "royalblue": (65, 105, 225, 255), + "royalblue1": (72, 118, 255, 255), + "royalblue2": (67, 110, 238, 255), + "royalblue3": (58, 95, 205, 255), + "royalblue4": (39, 64, 139, 255), + "salmon": (250, 128, 114, 255), + "salmon1": (255, 140, 105, 255), + "salmon2": (238, 130, 98, 255), + "salmon3": (205, 112, 84, 255), + "salmon4": (139, 76, 57, 255), + "saddlebrown": (139, 69, 19, 255), + "sandybrown": (244, 164, 96, 255), + "seagreen": (46, 139, 87, 255), + "seagreen1": (84, 255, 159, 255), + "seagreen2": (78, 238, 148, 255), + "seagreen3": (67, 205, 128, 255), + "seagreen4": (46, 139, 87, 255), + "seashell": (255, 245, 238, 255), + "seashell1": (255, 245, 238, 255), + "seashell2": (238, 229, 222, 255), + "seashell3": (205, 197, 191, 255), + "seashell4": (139, 134, 130, 255), + "sienna": (160, 82, 45, 255), + "sienna1": (255, 130, 71, 255), + "sienna2": (238, 121, 66, 255), + "sienna3": (205, 104, 57, 255), + "sienna4": (139, 71, 38, 255), + "silver": (192, 192, 192, 255), + "skyblue": (135, 206, 235, 255), + "skyblue1": (135, 206, 255, 255), + "skyblue2": (126, 192, 238, 255), + "skyblue3": (108, 166, 205, 255), + "skyblue4": (74, 112, 139, 255), + "slateblue": (106, 90, 205, 255), + "slateblue1": (131, 111, 255, 255), + "slateblue2": (122, 103, 238, 255), + "slateblue3": (105, 89, 205, 255), + "slateblue4": (71, 60, 139, 255), + "slategray": (112, 128, 144, 255), + "slategray1": (198, 226, 255, 255), + "slategray2": (185, 211, 238, 255), + "slategray3": (159, 182, 205, 255), + "slategray4": (108, 123, 139, 255), + "slategrey": (112, 128, 144, 255), + "snow": (255, 250, 250, 255), + "snow1": (255, 250, 250, 255), + "snow2": (238, 233, 233, 255), + "snow3": (205, 201, 201, 255), + "snow4": (139, 137, 137, 255), + "springgreen": (0, 255, 127, 255), + "springgreen1": (0, 255, 127, 255), + "springgreen2": (0, 238, 118, 255), + "springgreen3": (0, 205, 102, 255), + "springgreen4": (0, 139, 69, 255), + "steelblue": (70, 130, 180, 255), + "steelblue1": (99, 184, 255, 255), + "steelblue2": (92, 172, 238, 255), + "steelblue3": (79, 148, 205, 255), + "steelblue4": (54, 100, 139, 255), + "tan": (210, 180, 140, 255), + "tan1": (255, 165, 79, 255), + "tan2": (238, 154, 73, 255), + "tan3": (205, 133, 63, 255), + "tan4": (139, 90, 43, 255), + "teal": (0, 128, 128, 255), + "thistle": (216, 191, 216, 255), + "thistle1": (255, 225, 255, 255), + "thistle2": (238, 210, 238, 255), + "thistle3": (205, 181, 205, 255), + "thistle4": (139, 123, 139, 255), + "tomato": (255, 99, 71, 255), + "tomato1": (255, 99, 71, 255), + "tomato2": (238, 92, 66, 255), + "tomato3": (205, 79, 57, 255), + "tomato4": (139, 54, 38, 255), + "turquoise": (64, 224, 208, 255), + "turquoise1": (0, 245, 255, 255), + "turquoise2": (0, 229, 238, 255), + "turquoise3": (0, 197, 205, 255), + "turquoise4": (0, 134, 139, 255), + "violet": (238, 130, 238, 255), + "violetred": (208, 32, 144, 255), + "violetred1": (255, 62, 150, 255), + "violetred2": (238, 58, 140, 255), + "violetred3": (205, 50, 120, 255), + "violetred4": (139, 34, 82, 255), + "wheat": (245, 222, 179, 255), + "wheat1": (255, 231, 186, 255), + "wheat2": (238, 216, 174, 255), + "wheat3": (205, 186, 150, 255), + "wheat4": (139, 126, 102, 255), + "white": (255, 255, 255, 255), + "whitesmoke": (245, 245, 245, 255), + "yellow": (255, 255, 0, 255), + "yellow1": (255, 255, 0, 255), + "yellow2": (238, 238, 0, 255), + "yellow3": (205, 205, 0, 255), + "yellow4": (139, 139, 0, 255), + "yellowgreen": (154, 205, 50, 255), +} diff --git a/venv/Lib/site-packages/pygame/constants.pyi b/venv/Lib/site-packages/pygame/constants.pyi new file mode 100644 index 0000000..171a0c7 --- /dev/null +++ b/venv/Lib/site-packages/pygame/constants.pyi @@ -0,0 +1,557 @@ +""" +Script used to generate this file (if we change something in the constants in the future): +import pygame.constants +const = [] +for element in dir(pygame.constants): + constant_type = getattr(pygame.constants, element) + if not element.startswith("_"): + const.append("{}: {}\n".format(element, constant_type.__class__.__name__)) +with open("constants.pyi", "w") as f: + f.write("from typing import List\n\n\n") + for line in const: + f.write(str(line)) + f.write("__all__: List[str]\n") +""" + +from typing import List + +ACTIVEEVENT: int +ANYFORMAT: int +APPACTIVE: int +APPFOCUSMOUSE: int +APPINPUTFOCUS: int +ASYNCBLIT: int +AUDIODEVICEADDED: int +AUDIODEVICEREMOVED: int +AUDIO_ALLOW_ANY_CHANGE: int +AUDIO_ALLOW_CHANNELS_CHANGE: int +AUDIO_ALLOW_FORMAT_CHANGE: int +AUDIO_ALLOW_FREQUENCY_CHANGE: int +AUDIO_S16: int +AUDIO_S16LSB: int +AUDIO_S16MSB: int +AUDIO_S16SYS: int +AUDIO_S8: int +AUDIO_U16: int +AUDIO_U16LSB: int +AUDIO_U16MSB: int +AUDIO_U16SYS: int +AUDIO_U8: int +BIG_ENDIAN: int +BLENDMODE_ADD: int +BLENDMODE_BLEND: int +BLENDMODE_MOD: int +BLENDMODE_NONE: int +BLEND_ADD: int +BLEND_ALPHA_SDL2: int +BLEND_MAX: int +BLEND_MIN: int +BLEND_MULT: int +BLEND_PREMULTIPLIED: int +BLEND_RGBA_ADD: int +BLEND_RGBA_MAX: int +BLEND_RGBA_MIN: int +BLEND_RGBA_MULT: int +BLEND_RGBA_SUB: int +BLEND_RGB_ADD: int +BLEND_RGB_MAX: int +BLEND_RGB_MIN: int +BLEND_RGB_MULT: int +BLEND_RGB_SUB: int +BLEND_SUB: int +BUTTON_LEFT: int +BUTTON_MIDDLE: int +BUTTON_RIGHT: int +BUTTON_WHEELDOWN: int +BUTTON_WHEELUP: int +BUTTON_X1: int +BUTTON_X2: int +CONTROLLERAXISMOTION: int +CONTROLLERBUTTONDOWN: int +CONTROLLERBUTTONUP: int +CONTROLLERDEVICEADDED: int +CONTROLLERDEVICEREMAPPED: int +CONTROLLERDEVICEREMOVED: int +CONTROLLER_AXIS_INVALID: int +CONTROLLER_AXIS_LEFTX: int +CONTROLLER_AXIS_LEFTY: int +CONTROLLER_AXIS_MAX: int +CONTROLLER_AXIS_RIGHTX: int +CONTROLLER_AXIS_RIGHTY: int +CONTROLLER_AXIS_TRIGGERLEFT: int +CONTROLLER_AXIS_TRIGGERRIGHT: int +CONTROLLER_BUTTON_A: int +CONTROLLER_BUTTON_B: int +CONTROLLER_BUTTON_BACK: int +CONTROLLER_BUTTON_DPAD_DOWN: int +CONTROLLER_BUTTON_DPAD_LEFT: int +CONTROLLER_BUTTON_DPAD_RIGHT: int +CONTROLLER_BUTTON_DPAD_UP: int +CONTROLLER_BUTTON_GUIDE: int +CONTROLLER_BUTTON_INVALID: int +CONTROLLER_BUTTON_LEFTSHOULDER: int +CONTROLLER_BUTTON_LEFTSTICK: int +CONTROLLER_BUTTON_MAX: int +CONTROLLER_BUTTON_RIGHTSHOULDER: int +CONTROLLER_BUTTON_RIGHTSTICK: int +CONTROLLER_BUTTON_START: int +CONTROLLER_BUTTON_X: int +CONTROLLER_BUTTON_Y: int +DOUBLEBUF: int +DROPBEGIN: int +DROPCOMPLETE: int +DROPFILE: int +DROPTEXT: int +FINGERDOWN: int +FINGERMOTION: int +FINGERUP: int +FULLSCREEN: int +GL_ACCELERATED_VISUAL: int +GL_ACCUM_ALPHA_SIZE: int +GL_ACCUM_BLUE_SIZE: int +GL_ACCUM_GREEN_SIZE: int +GL_ACCUM_RED_SIZE: int +GL_ALPHA_SIZE: int +GL_BLUE_SIZE: int +GL_BUFFER_SIZE: int +GL_CONTEXT_DEBUG_FLAG: int +GL_CONTEXT_FLAGS: int +GL_CONTEXT_FORWARD_COMPATIBLE_FLAG: int +GL_CONTEXT_MAJOR_VERSION: int +GL_CONTEXT_MINOR_VERSION: int +GL_CONTEXT_PROFILE_COMPATIBILITY: int +GL_CONTEXT_PROFILE_CORE: int +GL_CONTEXT_PROFILE_ES: int +GL_CONTEXT_PROFILE_MASK: int +GL_CONTEXT_RELEASE_BEHAVIOR: int +GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH: int +GL_CONTEXT_RELEASE_BEHAVIOR_NONE: int +GL_CONTEXT_RESET_ISOLATION_FLAG: int +GL_CONTEXT_ROBUST_ACCESS_FLAG: int +GL_DEPTH_SIZE: int +GL_DOUBLEBUFFER: int +GL_FRAMEBUFFER_SRGB_CAPABLE: int +GL_GREEN_SIZE: int +GL_MULTISAMPLEBUFFERS: int +GL_MULTISAMPLESAMPLES: int +GL_RED_SIZE: int +GL_SHARE_WITH_CURRENT_CONTEXT: int +GL_STENCIL_SIZE: int +GL_STEREO: int +GL_SWAP_CONTROL: int +HAT_CENTERED: int +HAT_DOWN: int +HAT_LEFT: int +HAT_LEFTDOWN: int +HAT_LEFTUP: int +HAT_RIGHT: int +HAT_RIGHTDOWN: int +HAT_RIGHTUP: int +HAT_UP: int +HIDDEN: int +HWACCEL: int +HWPALETTE: int +HWSURFACE: int +JOYAXISMOTION: int +JOYBALLMOTION: int +JOYBUTTONDOWN: int +JOYBUTTONUP: int +JOYDEVICEADDED: int +JOYDEVICEREMOVED: int +JOYHATMOTION: int +KEYDOWN: int +KEYUP: int +KMOD_ALT: int +KMOD_CAPS: int +KMOD_CTRL: int +KMOD_GUI: int +KMOD_LALT: int +KMOD_LCTRL: int +KMOD_LGUI: int +KMOD_LMETA: int +KMOD_LSHIFT: int +KMOD_META: int +KMOD_MODE: int +KMOD_NONE: int +KMOD_NUM: int +KMOD_RALT: int +KMOD_RCTRL: int +KMOD_RGUI: int +KMOD_RMETA: int +KMOD_RSHIFT: int +KMOD_SHIFT: int +KSCAN_0: int +KSCAN_1: int +KSCAN_2: int +KSCAN_3: int +KSCAN_4: int +KSCAN_5: int +KSCAN_6: int +KSCAN_7: int +KSCAN_8: int +KSCAN_9: int +KSCAN_A: int +KSCAN_APOSTROPHE: int +KSCAN_B: int +KSCAN_BACKSLASH: int +KSCAN_BACKSPACE: int +KSCAN_BREAK: int +KSCAN_C: int +KSCAN_CAPSLOCK: int +KSCAN_CLEAR: int +KSCAN_COMMA: int +KSCAN_CURRENCYSUBUNIT: int +KSCAN_CURRENCYUNIT: int +KSCAN_D: int +KSCAN_DELETE: int +KSCAN_DOWN: int +KSCAN_E: int +KSCAN_END: int +KSCAN_EQUALS: int +KSCAN_ESCAPE: int +KSCAN_EURO: int +KSCAN_F: int +KSCAN_F1: int +KSCAN_F10: int +KSCAN_F11: int +KSCAN_F12: int +KSCAN_F13: int +KSCAN_F14: int +KSCAN_F15: int +KSCAN_F2: int +KSCAN_F3: int +KSCAN_F4: int +KSCAN_F5: int +KSCAN_F6: int +KSCAN_F7: int +KSCAN_F8: int +KSCAN_F9: int +KSCAN_G: int +KSCAN_GRAVE: int +KSCAN_H: int +KSCAN_HELP: int +KSCAN_HOME: int +KSCAN_I: int +KSCAN_INSERT: int +KSCAN_INTERNATIONAL1: int +KSCAN_INTERNATIONAL2: int +KSCAN_INTERNATIONAL3: int +KSCAN_INTERNATIONAL4: int +KSCAN_INTERNATIONAL5: int +KSCAN_INTERNATIONAL6: int +KSCAN_INTERNATIONAL7: int +KSCAN_INTERNATIONAL8: int +KSCAN_INTERNATIONAL9: int +KSCAN_J: int +KSCAN_K: int +KSCAN_KP0: int +KSCAN_KP1: int +KSCAN_KP2: int +KSCAN_KP3: int +KSCAN_KP4: int +KSCAN_KP5: int +KSCAN_KP6: int +KSCAN_KP7: int +KSCAN_KP8: int +KSCAN_KP9: int +KSCAN_KP_0: int +KSCAN_KP_1: int +KSCAN_KP_2: int +KSCAN_KP_3: int +KSCAN_KP_4: int +KSCAN_KP_5: int +KSCAN_KP_6: int +KSCAN_KP_7: int +KSCAN_KP_8: int +KSCAN_KP_9: int +KSCAN_KP_DIVIDE: int +KSCAN_KP_ENTER: int +KSCAN_KP_EQUALS: int +KSCAN_KP_MINUS: int +KSCAN_KP_MULTIPLY: int +KSCAN_KP_PERIOD: int +KSCAN_KP_PLUS: int +KSCAN_L: int +KSCAN_LALT: int +KSCAN_LANG1: int +KSCAN_LANG2: int +KSCAN_LANG3: int +KSCAN_LANG4: int +KSCAN_LANG5: int +KSCAN_LANG6: int +KSCAN_LANG7: int +KSCAN_LANG8: int +KSCAN_LANG9: int +KSCAN_LCTRL: int +KSCAN_LEFT: int +KSCAN_LEFTBRACKET: int +KSCAN_LGUI: int +KSCAN_LMETA: int +KSCAN_LSHIFT: int +KSCAN_LSUPER: int +KSCAN_M: int +KSCAN_MENU: int +KSCAN_MINUS: int +KSCAN_MODE: int +KSCAN_N: int +KSCAN_NONUSBACKSLASH: int +KSCAN_NONUSHASH: int +KSCAN_NUMLOCK: int +KSCAN_NUMLOCKCLEAR: int +KSCAN_O: int +KSCAN_P: int +KSCAN_PAGEDOWN: int +KSCAN_PAGEUP: int +KSCAN_PAUSE: int +KSCAN_PERIOD: int +KSCAN_POWER: int +KSCAN_PRINT: int +KSCAN_PRINTSCREEN: int +KSCAN_Q: int +KSCAN_R: int +KSCAN_RALT: int +KSCAN_RCTRL: int +KSCAN_RETURN: int +KSCAN_RGUI: int +KSCAN_RIGHT: int +KSCAN_RIGHTBRACKET: int +KSCAN_RMETA: int +KSCAN_RSHIFT: int +KSCAN_RSUPER: int +KSCAN_S: int +KSCAN_SCROLLLOCK: int +KSCAN_SCROLLOCK: int +KSCAN_SEMICOLON: int +KSCAN_SLASH: int +KSCAN_SPACE: int +KSCAN_SYSREQ: int +KSCAN_T: int +KSCAN_TAB: int +KSCAN_U: int +KSCAN_UNKNOWN: int +KSCAN_UP: int +KSCAN_V: int +KSCAN_W: int +KSCAN_X: int +KSCAN_Y: int +KSCAN_Z: int +K_0: int +K_1: int +K_2: int +K_3: int +K_4: int +K_5: int +K_6: int +K_7: int +K_8: int +K_9: int +K_AC_BACK: int +K_AMPERSAND: int +K_ASTERISK: int +K_AT: int +K_BACKQUOTE: int +K_BACKSLASH: int +K_BACKSPACE: int +K_BREAK: int +K_CAPSLOCK: int +K_CARET: int +K_CLEAR: int +K_COLON: int +K_COMMA: int +K_CURRENCYSUBUNIT: int +K_CURRENCYUNIT: int +K_DELETE: int +K_DOLLAR: int +K_DOWN: int +K_END: int +K_EQUALS: int +K_ESCAPE: int +K_EURO: int +K_EXCLAIM: int +K_F1: int +K_F10: int +K_F11: int +K_F12: int +K_F13: int +K_F14: int +K_F15: int +K_F2: int +K_F3: int +K_F4: int +K_F5: int +K_F6: int +K_F7: int +K_F8: int +K_F9: int +K_GREATER: int +K_HASH: int +K_HELP: int +K_HOME: int +K_INSERT: int +K_KP0: int +K_KP1: int +K_KP2: int +K_KP3: int +K_KP4: int +K_KP5: int +K_KP6: int +K_KP7: int +K_KP8: int +K_KP9: int +K_KP_0: int +K_KP_1: int +K_KP_2: int +K_KP_3: int +K_KP_4: int +K_KP_5: int +K_KP_6: int +K_KP_7: int +K_KP_8: int +K_KP_9: int +K_KP_DIVIDE: int +K_KP_ENTER: int +K_KP_EQUALS: int +K_KP_MINUS: int +K_KP_MULTIPLY: int +K_KP_PERIOD: int +K_KP_PLUS: int +K_LALT: int +K_LCTRL: int +K_LEFT: int +K_LEFTBRACKET: int +K_LEFTPAREN: int +K_LESS: int +K_LGUI: int +K_LMETA: int +K_LSHIFT: int +K_LSUPER: int +K_MENU: int +K_MINUS: int +K_MODE: int +K_NUMLOCK: int +K_NUMLOCKCLEAR: int +K_PAGEDOWN: int +K_PAGEUP: int +K_PAUSE: int +K_PERCENT: int +K_PERIOD: int +K_PLUS: int +K_POWER: int +K_PRINT: int +K_PRINTSCREEN: int +K_QUESTION: int +K_QUOTE: int +K_QUOTEDBL: int +K_RALT: int +K_RCTRL: int +K_RETURN: int +K_RGUI: int +K_RIGHT: int +K_RIGHTBRACKET: int +K_RIGHTPAREN: int +K_RMETA: int +K_RSHIFT: int +K_RSUPER: int +K_SCROLLLOCK: int +K_SCROLLOCK: int +K_SEMICOLON: int +K_SLASH: int +K_SPACE: int +K_SYSREQ: int +K_TAB: int +K_UNDERSCORE: int +K_UNKNOWN: int +K_UP: int +K_a: int +K_b: int +K_c: int +K_d: int +K_e: int +K_f: int +K_g: int +K_h: int +K_i: int +K_j: int +K_k: int +K_l: int +K_m: int +K_n: int +K_o: int +K_p: int +K_q: int +K_r: int +K_s: int +K_t: int +K_u: int +K_v: int +K_w: int +K_x: int +K_y: int +K_z: int +LIL_ENDIAN: int +MIDIIN: int +MIDIOUT: int +MOUSEBUTTONDOWN: int +MOUSEBUTTONUP: int +MOUSEMOTION: int +MOUSEWHEEL: int +MULTIGESTURE: int +NOEVENT: int +NOFRAME: int +NUMEVENTS: int +OPENGL: int +OPENGLBLIT: int +PREALLOC: int +QUIT: int +RESIZABLE: int +RLEACCEL: int +RLEACCELOK: int +SCALED: int +SCRAP_BMP: str +SCRAP_CLIPBOARD: int +SCRAP_PBM: str +SCRAP_PPM: str +SCRAP_SELECTION: int +SCRAP_TEXT: str +SHOWN: int +SRCALPHA: int +SRCCOLORKEY: int +SWSURFACE: int +SYSTEM_CURSOR_ARROW: int +SYSTEM_CURSOR_CROSSHAIR: int +SYSTEM_CURSOR_HAND: int +SYSTEM_CURSOR_IBEAM: int +SYSTEM_CURSOR_NO: int +SYSTEM_CURSOR_SIZEALL: int +SYSTEM_CURSOR_SIZENESW: int +SYSTEM_CURSOR_SIZENS: int +SYSTEM_CURSOR_SIZENWSE: int +SYSTEM_CURSOR_SIZEWE: int +SYSTEM_CURSOR_WAIT: int +SYSTEM_CURSOR_WAITARROW: int +SYSWMEVENT: int +TEXTEDITING: int +TEXTINPUT: int +TIMER_RESOLUTION: int +USEREVENT: int +USEREVENT_DROPFILE: int +VIDEOEXPOSE: int +VIDEORESIZE: int +WINDOWCLOSE: int +WINDOWENTER: int +WINDOWEXPOSED: int +WINDOWFOCUSGAINED: int +WINDOWFOCUSLOST: int +WINDOWHIDDEN: int +WINDOWHITTEST: int +WINDOWLEAVE: int +WINDOWMAXIMIZED: int +WINDOWMINIMIZED: int +WINDOWMOVED: int +WINDOWRESIZED: int +WINDOWRESTORED: int +WINDOWSHOWN: int +WINDOWSIZECHANGED: int +WINDOWTAKEFOCUS: int + +__all__: List[str] diff --git a/venv/Lib/site-packages/pygame/cursors.py b/venv/Lib/site-packages/pygame/cursors.py new file mode 100644 index 0000000..d7f71b5 --- /dev/null +++ b/venv/Lib/site-packages/pygame/cursors.py @@ -0,0 +1,840 @@ +# pygame - Python Game Library +# Copyright (C) 2000-2003 Pete Shinners +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Pete Shinners +# pete@shinners.org + +"""Set of cursor resources available for use. These cursors come +in a sequence of values that are needed as the arguments for +pygame.mouse.set_cursor(). To dereference the sequence in place +and create the cursor in one step, call like this: + pygame.mouse.set_cursor(*pygame.cursors.arrow). + +Here is a list of available cursors: + arrow, diamond, ball, broken_x, tri_left, tri_right + +There is also a sample string cursor named 'thickarrow_strings'. +The compile() function can convert these string cursors into cursor byte data that can be used to +create Cursor objects. + +Alternately, you can also create Cursor objects using surfaces or cursors constants, +such as pygame.SYSTEM_CURSOR_ARROW. +""" + +import pygame + +_cursor_id_table = { + pygame.SYSTEM_CURSOR_ARROW: "SYSTEM_CURSOR_ARROW", + pygame.SYSTEM_CURSOR_IBEAM: "SYSTEM_CURSOR_IBEAM", + pygame.SYSTEM_CURSOR_WAIT: "SYSTEM_CURSOR_WAIT", + pygame.SYSTEM_CURSOR_CROSSHAIR: "SYSTEM_CURSOR_CROSSHAIR", + pygame.SYSTEM_CURSOR_WAITARROW: "SYSTEM_CURSOR_WAITARROW", + pygame.SYSTEM_CURSOR_SIZENWSE: "SYSTEM_CURSOR_SIZENWSE", + pygame.SYSTEM_CURSOR_SIZENESW: "SYSTEM_CURSOR_SIZENESW", + pygame.SYSTEM_CURSOR_SIZEWE: "SYSTEM_CURSOR_SIZEWE", + pygame.SYSTEM_CURSOR_SIZENS: "SYSTEM_CURSOR_SIZENS", + pygame.SYSTEM_CURSOR_SIZEALL: "SYSTEM_CURSOR_SIZEALL", + pygame.SYSTEM_CURSOR_NO: "SYSTEM_CURSOR_NO", + pygame.SYSTEM_CURSOR_HAND: "SYSTEM_CURSOR_HAND", +} + + +class Cursor(object): + def __init__(self, *args): + """Cursor(size, hotspot, xormasks, andmasks) -> Cursor + Cursor(hotspot, Surface) -> Cursor + Cursor(constant) -> Cursor + Cursor(Cursor) -> copies the Cursor object passed as an argument + Cursor() -> Cursor + + pygame object for representing cursors + + You can initialize a cursor from a system cursor or use the + constructor on an existing Cursor object, which will copy it. + Providing a Surface instance will render the cursor displayed + as that Surface when used. + + These Surfaces may use other colors than black and white.""" + if len(args) == 0: + self.type = "system" + self.data = (pygame.SYSTEM_CURSOR_ARROW,) + elif len(args) == 1 and args[0] in _cursor_id_table: + self.type = "system" + self.data = (args[0],) + elif len(args) == 1 and isinstance(args[0], Cursor): + self.type = args[0].type + self.data = args[0].data + elif ( + len(args) == 2 and len(args[0]) == 2 and isinstance(args[1], pygame.Surface) + ): + self.type = "color" + self.data = tuple(args) + elif len(args) == 4 and len(args[0]) == 2 and len(args[1]) == 2: + self.type = "bitmap" + # pylint: disable=consider-using-generator + # See https://github.com/pygame/pygame/pull/2509 for analysis + self.data = tuple([tuple(arg) for arg in args]) + else: + raise TypeError("Arguments must match a cursor specification") + + def __len__(self): + return len(self.data) + + def __getitem__(self, index): + return self.data[index] + + def __eq__(self, other): + return isinstance(other, Cursor) and self.data == other.data + + def __ne__(self, other): + return not self.__eq__(other) + + def __copy__(self): + """Clone the current Cursor object. + You can do the same thing by doing Cursor(Cursor).""" + return self.__class__(self) + + copy = __copy__ + + def __hash__(self): + return hash(tuple([self.type] + list(self.data))) + + def __repr__(self): + if self.type == "system": + id_string = _cursor_id_table.get(self.data[0], "constant lookup error") + return "" + if self.type == "bitmap": + size = "size: " + str(self.data[0]) + hotspot = "hotspot: " + str(self.data[1]) + return "" + if self.type == "color": + hotspot = "hotspot: " + str(self.data[0]) + surf = repr(self.data[1]) + return "" + raise TypeError("Invalid Cursor") + + +# Python side of the set_cursor function: C side in mouse.c +def set_cursor(*args): + """set_cursor(pygame.cursors.Cursor OR args for a pygame.cursors.Cursor) -> None + set the mouse cursor to a new cursor""" + cursor = Cursor(*args) + pygame.mouse._set_cursor(**{cursor.type: cursor.data}) + + +pygame.mouse.set_cursor = set_cursor +del set_cursor # cleanup namespace + +# Python side of the get_cursor function: C side in mouse.c +def get_cursor(): + """get_cursor() -> pygame.cursors.Cursor + get the current mouse cursor""" + return Cursor(*pygame.mouse._get_cursor()) + + +pygame.mouse.get_cursor = get_cursor +del get_cursor # cleanup namespace + +arrow = Cursor( + (16, 16), + (0, 0), + ( + 0x00, + 0x00, + 0x40, + 0x00, + 0x60, + 0x00, + 0x70, + 0x00, + 0x78, + 0x00, + 0x7C, + 0x00, + 0x7E, + 0x00, + 0x7F, + 0x00, + 0x7F, + 0x80, + 0x7C, + 0x00, + 0x6C, + 0x00, + 0x46, + 0x00, + 0x06, + 0x00, + 0x03, + 0x00, + 0x03, + 0x00, + 0x00, + 0x00, + ), + ( + 0x40, + 0x00, + 0xE0, + 0x00, + 0xF0, + 0x00, + 0xF8, + 0x00, + 0xFC, + 0x00, + 0xFE, + 0x00, + 0xFF, + 0x00, + 0xFF, + 0x80, + 0xFF, + 0xC0, + 0xFF, + 0x80, + 0xFE, + 0x00, + 0xEF, + 0x00, + 0x4F, + 0x00, + 0x07, + 0x80, + 0x07, + 0x80, + 0x03, + 0x00, + ), +) + +diamond = Cursor( + (16, 16), + (7, 7), + ( + 0, + 0, + 1, + 0, + 3, + 128, + 7, + 192, + 14, + 224, + 28, + 112, + 56, + 56, + 112, + 28, + 56, + 56, + 28, + 112, + 14, + 224, + 7, + 192, + 3, + 128, + 1, + 0, + 0, + 0, + 0, + 0, + ), + ( + 1, + 0, + 3, + 128, + 7, + 192, + 15, + 224, + 31, + 240, + 62, + 248, + 124, + 124, + 248, + 62, + 124, + 124, + 62, + 248, + 31, + 240, + 15, + 224, + 7, + 192, + 3, + 128, + 1, + 0, + 0, + 0, + ), +) + +ball = Cursor( + (16, 16), + (7, 7), + ( + 0, + 0, + 3, + 192, + 15, + 240, + 24, + 248, + 51, + 252, + 55, + 252, + 127, + 254, + 127, + 254, + 127, + 254, + 127, + 254, + 63, + 252, + 63, + 252, + 31, + 248, + 15, + 240, + 3, + 192, + 0, + 0, + ), + ( + 3, + 192, + 15, + 240, + 31, + 248, + 63, + 252, + 127, + 254, + 127, + 254, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 127, + 254, + 127, + 254, + 63, + 252, + 31, + 248, + 15, + 240, + 3, + 192, + ), +) + +broken_x = Cursor( + (16, 16), + (7, 7), + ( + 0, + 0, + 96, + 6, + 112, + 14, + 56, + 28, + 28, + 56, + 12, + 48, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 12, + 48, + 28, + 56, + 56, + 28, + 112, + 14, + 96, + 6, + 0, + 0, + ), + ( + 224, + 7, + 240, + 15, + 248, + 31, + 124, + 62, + 62, + 124, + 30, + 120, + 14, + 112, + 0, + 0, + 0, + 0, + 14, + 112, + 30, + 120, + 62, + 124, + 124, + 62, + 248, + 31, + 240, + 15, + 224, + 7, + ), +) + +tri_left = Cursor( + (16, 16), + (1, 1), + ( + 0, + 0, + 96, + 0, + 120, + 0, + 62, + 0, + 63, + 128, + 31, + 224, + 31, + 248, + 15, + 254, + 15, + 254, + 7, + 128, + 7, + 128, + 3, + 128, + 3, + 128, + 1, + 128, + 1, + 128, + 0, + 0, + ), + ( + 224, + 0, + 248, + 0, + 254, + 0, + 127, + 128, + 127, + 224, + 63, + 248, + 63, + 254, + 31, + 255, + 31, + 255, + 15, + 254, + 15, + 192, + 7, + 192, + 7, + 192, + 3, + 192, + 3, + 192, + 1, + 128, + ), +) + +tri_right = Cursor( + (16, 16), + (14, 1), + ( + 0, + 0, + 0, + 6, + 0, + 30, + 0, + 124, + 1, + 252, + 7, + 248, + 31, + 248, + 127, + 240, + 127, + 240, + 1, + 224, + 1, + 224, + 1, + 192, + 1, + 192, + 1, + 128, + 1, + 128, + 0, + 0, + ), + ( + 0, + 7, + 0, + 31, + 0, + 127, + 1, + 254, + 7, + 254, + 31, + 252, + 127, + 252, + 255, + 248, + 255, + 248, + 127, + 240, + 3, + 240, + 3, + 224, + 3, + 224, + 3, + 192, + 3, + 192, + 1, + 128, + ), +) + + +# Here is an example string resource cursor. To use this: +# curs, mask = pygame.cursors.compile_cursor(pygame.cursors.thickarrow_strings, 'X', '.') +# pygame.mouse.set_cursor((24, 24), (0, 0), curs, mask) +# Be warned, though, that cursors created from compiled strings do not support colors. + +# sized 24x24 +thickarrow_strings = ( + "XX ", + "XXX ", + "XXXX ", + "XX.XX ", + "XX..XX ", + "XX...XX ", + "XX....XX ", + "XX.....XX ", + "XX......XX ", + "XX.......XX ", + "XX........XX ", + "XX........XXX ", + "XX......XXXXX ", + "XX.XXX..XX ", + "XXXX XX..XX ", + "XX XX..XX ", + " XX..XX ", + " XX..XX ", + " XX..XX ", + " XXXX ", + " XX ", + " ", + " ", + " ", +) + +# sized 24x16 +sizer_x_strings = ( + " X X ", + " XX XX ", + " X.X X.X ", + " X..X X..X ", + " X...XXXXXXXX...X ", + "X................X ", + " X...XXXXXXXX...X ", + " X..X X..X ", + " X.X X.X ", + " XX XX ", + " X X ", + " ", + " ", + " ", + " ", + " ", +) + +# sized 16x24 +sizer_y_strings = ( + " X ", + " X.X ", + " X...X ", + " X.....X ", + " X.......X ", + "XXXXX.XXXXX ", + " X.X ", + " X.X ", + " X.X ", + " X.X ", + " X.X ", + " X.X ", + " X.X ", + "XXXXX.XXXXX ", + " X.......X ", + " X.....X ", + " X...X ", + " X.X ", + " X ", + " ", + " ", + " ", + " ", + " ", +) + +# sized 24x16 +sizer_xy_strings = ( + "XXXXXXXX ", + "X.....X ", + "X....X ", + "X...X ", + "X..X.X ", + "X.X X.X ", + "XX X.X X ", + "X X.X XX ", + " X.XX.X ", + " X...X ", + " X...X ", + " X....X ", + " X.....X ", + " XXXXXXXX ", + " ", + " ", +) + +# sized 8x16 +textmarker_strings = ( + "ooo ooo ", + " o ", + " o ", + " o ", + " o ", + " o ", + " o ", + " o ", + " o ", + " o ", + " o ", + "ooo ooo ", + " ", + " ", + " ", + " ", +) + + +def compile(strings, black="X", white=".", xor="o"): + """pygame.cursors.compile(strings, black, white, xor) -> data, mask + compile cursor strings into cursor data + + This takes a set of strings with equal length and computes + the binary data for that cursor. The string widths must be + divisible by 8. + + The black and white arguments are single letter strings that + tells which characters will represent black pixels, and which + characters represent white pixels. All other characters are + considered clear. + + Some systems allow you to set a special toggle color for the + system color, this is also called the xor color. If the system + does not support xor cursors, that color will simply be black. + + This returns a tuple containing the cursor data and cursor mask + data. Both these arguments are used when setting a cursor with + pygame.mouse.set_cursor(). + """ + # first check for consistent lengths + size = len(strings[0]), len(strings) + if size[0] % 8 or size[1] % 8: + raise ValueError(f"cursor string sizes must be divisible by 8 {size}") + + for s in strings[1:]: + if len(s) != size[0]: + raise ValueError("Cursor strings are inconsistent lengths") + + # create the data arrays. + # this could stand a little optimizing + maskdata = [] + filldata = [] + maskitem = fillitem = 0 + step = 8 + for s in strings: + for c in s: + maskitem = maskitem << 1 + fillitem = fillitem << 1 + step = step - 1 + if c == black: + maskitem = maskitem | 1 + fillitem = fillitem | 1 + elif c == white: + maskitem = maskitem | 1 + elif c == xor: + fillitem = fillitem | 1 + + if not step: + maskdata.append(maskitem) + filldata.append(fillitem) + maskitem = fillitem = 0 + step = 8 + + return tuple(filldata), tuple(maskdata) + + +def load_xbm(curs, mask): + """pygame.cursors.load_xbm(cursorfile, maskfile) -> cursor_args + reads a pair of XBM files into set_cursor arguments + + Arguments can either be filenames or filelike objects + with the readlines method. Not largely tested, but + should work with typical XBM files. + """ + + def bitswap(num): + val = 0 + for x in range(8): + b = num & (1 << x) != 0 + val = val << 1 | b + return val + + if hasattr(curs, "readlines"): + curs = curs.readlines() + else: + with open(curs, encoding="ascii") as cursor_f: + curs = cursor_f.readlines() + + if hasattr(mask, "readlines"): + mask = mask.readlines() + else: + with open(mask, encoding="ascii") as mask_f: + mask = mask_f.readlines() + + # avoid comments + for i, line in enumerate(curs): + if line.startswith("#define"): + curs = curs[i:] + break + + for i, line in enumerate(mask): + if line.startswith("#define"): + mask = mask[i:] + break + + # load width,height + width = int(curs[0].split()[-1]) + height = int(curs[1].split()[-1]) + # load hotspot position + if curs[2].startswith("#define"): + hotx = int(curs[2].split()[-1]) + hoty = int(curs[3].split()[-1]) + else: + hotx = hoty = 0 + + info = width, height, hotx, hoty + + possible_starts = ("static char", "static unsigned char") + for i, line in enumerate(curs): + if line.startswith(possible_starts): + break + data = " ".join(curs[i + 1 :]).replace("};", "").replace(",", " ") + cursdata = [] + for x in data.split(): + cursdata.append(bitswap(int(x, 16))) + cursdata = tuple(cursdata) + for i, line in enumerate(mask): + if line.startswith(possible_starts): + break + data = " ".join(mask[i + 1 :]).replace("};", "").replace(",", " ") + maskdata = [] + for x in data.split(): + maskdata.append(bitswap(int(x, 16))) + + maskdata = tuple(maskdata) + return info[:2], info[2:], cursdata, maskdata diff --git a/venv/Lib/site-packages/pygame/cursors.pyi b/venv/Lib/site-packages/pygame/cursors.pyi new file mode 100644 index 0000000..834b457 --- /dev/null +++ b/venv/Lib/site-packages/pygame/cursors.pyi @@ -0,0 +1,86 @@ +from typing import Iterator, List, Tuple, Sequence, Iterable, Union, overload + +from pygame.surface import Surface + +_Small_string = Tuple[ + str, str, str, str, str, str, str, str, str, str, str, str, str, str, str, str +] +_Big_string = Tuple[ + str, + str, + str, + str, + str, + str, + str, + str, + str, + str, + str, + str, + str, + str, + str, + str, + str, + str, + str, + str, + str, + str, + str, + str, +] + +arrow: Cursor +diamond: Cursor +broken_x: Cursor +tri_left: Cursor +tri_right: Cursor +thickarrow_strings: _Big_string +sizer_x_strings: _Small_string +sizer_y_strings: _Big_string +sizer_xy_strings: _Small_string + +def compile( + strings: Sequence[str], + black: str = "X", + white: str = ".", + xor: str = "o", +) -> Tuple[Sequence[int], Sequence[int]]: ... +def load_xbm( + cursorfile: str, maskfile: str +) -> Tuple[List[int], List[int], Tuple[int, ...], Tuple[int, ...]]: ... + +class Cursor(Iterable[object]): + @overload + def __init__(self, constant: int = ...) -> None: ... + @overload + def __init__(self, cursor: Cursor) -> None: ... + @overload + def __init__( + self, + size: Union[Tuple[int, int], List[int]], + hotspot: Union[Tuple[int, int], List[int]], + xormasks: Sequence[int], + andmasks: Sequence[int], + ) -> None: ... + @overload + def __init__( + self, + hotspot: Union[Tuple[int, int], List[int]], + surface: Surface, + ) -> None: ... + def __iter__(self) -> Iterator[object]: ... + def __len__(self) -> int: ... + type: str + data: Union[ + Tuple[int], + Tuple[ + Union[Tuple[int, int], List[int]], + Union[Tuple[int, int], List[int]], + Sequence[int], + Sequence[int], + ], + Tuple[int, Surface], + ] diff --git a/venv/Lib/site-packages/pygame/display.pyi b/venv/Lib/site-packages/pygame/display.pyi new file mode 100644 index 0000000..bfcf865 --- /dev/null +++ b/venv/Lib/site-packages/pygame/display.pyi @@ -0,0 +1,68 @@ +from typing import Union, Tuple, List, Optional, Dict, Sequence + +from pygame.surface import Surface +from pygame.constants import FULLSCREEN +from ._common import _Coordinate, _RectValue, _ColorValue, _RgbaOutput + +class _VidInfo: + hw: int + wm: int + video_mem: int + bitsize: int + bytesize: int + masks: _RgbaOutput + shifts: _RgbaOutput + losses: _RgbaOutput + blit_hw: int + blit_hw_CC: int + blit_hw_A: int + blit_sw: int + blit_sw_CC: int + blit_sw_A: int + current_h: int + current_w: int + +def init() -> None: ... +def quit() -> None: ... +def get_init() -> bool: ... +def set_mode( + size: _Coordinate = (0, 0), + flags: int = 0, + depth: int = 0, + display: int = 0, + vsync: int = 0, +) -> Surface: ... +def get_surface() -> Surface: ... +def flip() -> None: ... +def update(rectangle: Optional[Union[_RectValue, List[_RectValue]]] = None) -> None: ... +def get_driver() -> str: ... +def Info() -> _VidInfo: ... +def get_wm_info() -> Dict[str, int]: ... +def list_modes( + depth: int = 0, + flags: int = FULLSCREEN, + display: int = 0, +) -> List[Tuple[int, int]]: ... +def mode_ok( + size: Union[Sequence[int], Tuple[int, int]], + flags: int = 0, + depth: int = 0, + display: int = 0, +) -> int: ... +def gl_get_attribute(flag: int) -> int: ... +def gl_set_attribute(flag: int, value: int) -> None: ... +def get_active() -> bool: ... +def iconify() -> bool: ... +def toggle_fullscreen() -> int: ... +def set_gamma(red: float, green: float = ..., blue: float = ...) -> int: ... +def set_gamma_ramp( + red: Sequence[int], green: Sequence[int], blue: Sequence[int] +) -> int: ... +def set_icon(surface: Surface) -> None: ... +def set_caption(title: str, icontitle: Optional[str] = None) -> None: ... +def get_caption() -> Tuple[str, str]: ... +def set_palette(palette: Sequence[_ColorValue]) -> None: ... +def get_num_displays() -> int: ... +def get_window_size() -> Tuple[int, int]: ... +def get_allow_screensaver() -> bool: ... +def set_allow_screensaver(value: bool = True) -> None: ... diff --git a/venv/Lib/site-packages/pygame/docs/__main__.py b/venv/Lib/site-packages/pygame/docs/__main__.py new file mode 100644 index 0000000..28b95bb --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/__main__.py @@ -0,0 +1,38 @@ +# python -m pygame.docs + +import os +import webbrowser +from urllib.parse import quote, urlunparse + + +def _iterpath(path): + path, last = os.path.split(path) + if last: + for p in _iterpath(path): + yield p + yield last + + +# for test suite to confirm pygame built with local docs +def has_local_docs(): + pkg_dir = os.path.dirname(os.path.abspath(__file__)) + main_page = os.path.join(pkg_dir, "generated", "index.html") + return os.path.exists(main_page) + + +def open_docs(): + pkg_dir = os.path.dirname(os.path.abspath(__file__)) + main_page = os.path.join(pkg_dir, "generated", "index.html") + if os.path.exists(main_page): + url_path = quote("/".join(_iterpath(main_page))) + drive, rest = os.path.splitdrive(__file__) + if drive: + url_path = "%s/%s" % (drive, url_path) + url = urlunparse(("file", "", url_path, "", "", "")) + else: + url = "https://www.pygame.org/docs/" + webbrowser.open(url) + + +if __name__ == "__main__": + open_docs() diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput1.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput1.gif new file mode 100644 index 0000000..8c7f7ea Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput1.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput11.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput11.gif new file mode 100644 index 0000000..8c7f7ea Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput11.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput2.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput2.gif new file mode 100644 index 0000000..2094e3a Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput2.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput21.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput21.gif new file mode 100644 index 0000000..2094e3a Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput21.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput3.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput3.gif new file mode 100644 index 0000000..3a0d748 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput3.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput31.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput31.gif new file mode 100644 index 0000000..3a0d748 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput31.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput4.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput4.gif new file mode 100644 index 0000000..415644e Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput4.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput41.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput41.gif new file mode 100644 index 0000000..415644e Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput41.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput5.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput5.gif new file mode 100644 index 0000000..5796b4e Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput5.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput51.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput51.gif new file mode 100644 index 0000000..5796b4e Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedInputOutput51.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputAlpha1.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputAlpha1.gif new file mode 100644 index 0000000..c0d4124 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputAlpha1.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputAlpha11.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputAlpha11.gif new file mode 100644 index 0000000..c0d4124 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputAlpha11.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputAlpha2.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputAlpha2.gif new file mode 100644 index 0000000..00b443d Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputAlpha2.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputAlpha21.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputAlpha21.gif new file mode 100644 index 0000000..00b443d Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputAlpha21.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputAlpha3.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputAlpha3.gif new file mode 100644 index 0000000..be1204d Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputAlpha3.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputAlpha31.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputAlpha31.gif new file mode 100644 index 0000000..be1204d Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputAlpha31.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess1.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess1.gif new file mode 100644 index 0000000..20edf21 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess1.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess11.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess11.gif new file mode 100644 index 0000000..20edf21 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess11.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess2.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess2.gif new file mode 100644 index 0000000..5445c0e Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess2.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess21.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess21.gif new file mode 100644 index 0000000..5445c0e Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess21.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess3.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess3.gif new file mode 100644 index 0000000..0da81f1 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess3.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess31.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess31.gif new file mode 100644 index 0000000..0da81f1 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess31.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess4.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess4.gif new file mode 100644 index 0000000..18506fa Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess4.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess41.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess41.gif new file mode 100644 index 0000000..18506fa Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess41.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess5.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess5.gif new file mode 100644 index 0000000..def0e06 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess5.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess51.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess51.gif new file mode 100644 index 0000000..def0e06 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess51.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess6.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess6.gif new file mode 100644 index 0000000..127cc1e Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess6.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess61.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess61.gif new file mode 100644 index 0000000..127cc1e Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/AdvancedOutputProcess61.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-INPUT-resultscreen.png b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-INPUT-resultscreen.png new file mode 100644 index 0000000..9280cbe Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-INPUT-resultscreen.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-INPUT-resultscreen1.png b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-INPUT-resultscreen1.png new file mode 100644 index 0000000..9280cbe Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-INPUT-resultscreen1.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-INPUT-sourcecode.png b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-INPUT-sourcecode.png new file mode 100644 index 0000000..d378854 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-INPUT-sourcecode.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-INPUT-sourcecode1.png b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-INPUT-sourcecode1.png new file mode 100644 index 0000000..d378854 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-INPUT-sourcecode1.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-PROCESS-resultscreen.png b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-PROCESS-resultscreen.png new file mode 100644 index 0000000..f4e8322 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-PROCESS-resultscreen.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-PROCESS-resultscreen1.png b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-PROCESS-resultscreen1.png new file mode 100644 index 0000000..f4e8322 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-PROCESS-resultscreen1.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-PROCESS-sourcecode.png b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-PROCESS-sourcecode.png new file mode 100644 index 0000000..b20873a Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-PROCESS-sourcecode.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-PROCESS-sourcecode1.png b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-PROCESS-sourcecode1.png new file mode 100644 index 0000000..b20873a Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-PROCESS-sourcecode1.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-ouput-result-screen.png b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-ouput-result-screen.png new file mode 100644 index 0000000..d8628e1 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-ouput-result-screen.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-ouput-result-screen1.png b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-ouput-result-screen1.png new file mode 100644 index 0000000..d8628e1 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/Bagic-ouput-result-screen1.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/Basic-ouput-sourcecode.png b/venv/Lib/site-packages/pygame/docs/generated/_images/Basic-ouput-sourcecode.png new file mode 100644 index 0000000..659c981 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/Basic-ouput-sourcecode.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/Basic-ouput-sourcecode1.png b/venv/Lib/site-packages/pygame/docs/generated/_images/Basic-ouput-sourcecode1.png new file mode 100644 index 0000000..659c981 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/Basic-ouput-sourcecode1.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/camera_average.jpg b/venv/Lib/site-packages/pygame/docs/generated/_images/camera_average.jpg new file mode 100644 index 0000000..043e485 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/camera_average.jpg differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/camera_background.jpg b/venv/Lib/site-packages/pygame/docs/generated/_images/camera_background.jpg new file mode 100644 index 0000000..cfcbd02 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/camera_background.jpg differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/camera_green.jpg b/venv/Lib/site-packages/pygame/docs/generated/_images/camera_green.jpg new file mode 100644 index 0000000..24c4b09 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/camera_green.jpg differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/camera_hsv.jpg b/venv/Lib/site-packages/pygame/docs/generated/_images/camera_hsv.jpg new file mode 100644 index 0000000..afe9559 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/camera_hsv.jpg differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/camera_mask.jpg b/venv/Lib/site-packages/pygame/docs/generated/_images/camera_mask.jpg new file mode 100644 index 0000000..cd8ed1d Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/camera_mask.jpg differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/camera_rgb.jpg b/venv/Lib/site-packages/pygame/docs/generated/_images/camera_rgb.jpg new file mode 100644 index 0000000..3401421 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/camera_rgb.jpg differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/camera_thresh.jpg b/venv/Lib/site-packages/pygame/docs/generated/_images/camera_thresh.jpg new file mode 100644 index 0000000..cb2426f Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/camera_thresh.jpg differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/camera_thresholded.jpg b/venv/Lib/site-packages/pygame/docs/generated/_images/camera_thresholded.jpg new file mode 100644 index 0000000..c4ee891 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/camera_thresholded.jpg differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/camera_yuv.jpg b/venv/Lib/site-packages/pygame/docs/generated/_images/camera_yuv.jpg new file mode 100644 index 0000000..1cda596 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/camera_yuv.jpg differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/chimpshot.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/chimpshot.gif new file mode 100644 index 0000000..c27191d Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/chimpshot.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/draw_module_example.png b/venv/Lib/site-packages/pygame/docs/generated/_images/draw_module_example.png new file mode 100644 index 0000000..c6c832d Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/draw_module_example.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/intro_ball.gif b/venv/Lib/site-packages/pygame/docs/generated/_images/intro_ball.gif new file mode 100644 index 0000000..bbc4a95 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/intro_ball.gif differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/intro_blade.jpg b/venv/Lib/site-packages/pygame/docs/generated/_images/intro_blade.jpg new file mode 100644 index 0000000..2ed490c Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/intro_blade.jpg differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/intro_freedom.jpg b/venv/Lib/site-packages/pygame/docs/generated/_images/intro_freedom.jpg new file mode 100644 index 0000000..9ed473d Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/intro_freedom.jpg differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/introduction-Battleship.png b/venv/Lib/site-packages/pygame/docs/generated/_images/introduction-Battleship.png new file mode 100644 index 0000000..35674f6 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/introduction-Battleship.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/introduction-Battleship1.png b/venv/Lib/site-packages/pygame/docs/generated/_images/introduction-Battleship1.png new file mode 100644 index 0000000..35674f6 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/introduction-Battleship1.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/introduction-PuyoPuyo.png b/venv/Lib/site-packages/pygame/docs/generated/_images/introduction-PuyoPuyo.png new file mode 100644 index 0000000..dc104ea Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/introduction-PuyoPuyo.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/introduction-PuyoPuyo1.png b/venv/Lib/site-packages/pygame/docs/generated/_images/introduction-PuyoPuyo1.png new file mode 100644 index 0000000..dc104ea Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/introduction-PuyoPuyo1.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/introduction-TPS.png b/venv/Lib/site-packages/pygame/docs/generated/_images/introduction-TPS.png new file mode 100644 index 0000000..9c8cb0c Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/introduction-TPS.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/introduction-TPS1.png b/venv/Lib/site-packages/pygame/docs/generated/_images/introduction-TPS1.png new file mode 100644 index 0000000..9c8cb0c Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/introduction-TPS1.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/joystick_calls.png b/venv/Lib/site-packages/pygame/docs/generated/_images/joystick_calls.png new file mode 100644 index 0000000..93b80eb Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/joystick_calls.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_allblack.png b/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_allblack.png new file mode 100644 index 0000000..80cbc35 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_allblack.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_flipped.png b/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_flipped.png new file mode 100644 index 0000000..742f4f3 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_flipped.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_redimg.png b/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_redimg.png new file mode 100644 index 0000000..58e9c3f Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_redimg.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_rgbarray.png b/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_rgbarray.png new file mode 100644 index 0000000..8513ef7 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_rgbarray.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_scaledown.png b/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_scaledown.png new file mode 100644 index 0000000..0be3541 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_scaledown.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_scaleup.png b/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_scaleup.png new file mode 100644 index 0000000..ff1f15e Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_scaleup.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_soften.png b/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_soften.png new file mode 100644 index 0000000..c1d4ce4 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_soften.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_striped.png b/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_striped.png new file mode 100644 index 0000000..2ca4a79 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_striped.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_xfade.png b/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_xfade.png new file mode 100644 index 0000000..8b90706 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/surfarray_xfade.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/tom_basic.png b/venv/Lib/site-packages/pygame/docs/generated/_images/tom_basic.png new file mode 100644 index 0000000..849adb5 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/tom_basic.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/tom_event-flowchart.png b/venv/Lib/site-packages/pygame/docs/generated/_images/tom_event-flowchart.png new file mode 100644 index 0000000..6a33613 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/tom_event-flowchart.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/tom_formulae.png b/venv/Lib/site-packages/pygame/docs/generated/_images/tom_formulae.png new file mode 100644 index 0000000..f04b482 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/tom_formulae.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_images/tom_radians.png b/venv/Lib/site-packages/pygame/docs/generated/_images/tom_radians.png new file mode 100644 index 0000000..4569df1 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_images/tom_radians.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/c_api.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/c_api.rst.txt new file mode 100644 index 0000000..66d878f --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/c_api.rst.txt @@ -0,0 +1,26 @@ +pygame C API +============ + +.. toctree:: + :maxdepth: 1 + :glob: + + c_api/slots.rst + c_api/base.rst + c_api/bufferproxy.rst + c_api/cdrom.rst + c_api/color.rst + c_api/display.rst + c_api/event.rst + c_api/freetype.rst + c_api/mixer.rst + c_api/rect.rst + c_api/rwobject.rst + c_api/surface.rst + c_api/surflock.rst + c_api/version.rst + + +src_c/include/ contains header files for applications +that use the pygame C API, while src_c/ contains +headers used by pygame internally. diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/filepaths.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/filepaths.rst.txt new file mode 100644 index 0000000..e17f687 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/filepaths.rst.txt @@ -0,0 +1,17 @@ +File Path Function Arguments +============================ + +A pygame function or method which takes a file path argument will accept +either a Unicode or a byte (8-bit or ASCII character) string. +Unicode strings are translated to Python's default filesystem encoding, +as returned by sys.getfilesystemencoding(). A Unicode code point +above U+FFFF (``\uFFFF``) can be coded directly with a 32-bit escape sequences +(``\Uxxxxxxxx``), even for Python interpreters built with an UCS-2 +(16-bit character) Unicode type. Byte strings are passed +to the operating system unchanged. + +Null characters (``\x00``) are not permitted in the path, raising an exception. +An exception is also raised if an Unicode file path cannot be encoded. +How UTF-16 surrogate codes are handled is Python-interpreter-dependent. +Use UTF-32 code points and 32-bit escape sequences instead. +The exception types are function-dependent. diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/index.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/index.rst.txt new file mode 100644 index 0000000..f1a700c --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/index.rst.txt @@ -0,0 +1,190 @@ +.. Pygame documentation master file, created by + sphinx-quickstart on Sat Mar 5 11:56:39 2011. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Pygame Front Page +================= + +.. toctree:: + :maxdepth: 2 + :glob: + :hidden: + + ref/* + tut/* + tut/en/**/* + tut/ko/**/* + c_api + filepaths + +Documents +--------- + +`Readme`_ + Basic information about pygame: what it is, who is involved, and where to find it. + +`Install`_ + Steps needed to compile pygame on several platforms. + Also help on finding and installing prebuilt binaries for your system. + +`File Path Function Arguments`_ + How pygame handles file system paths. + +`LGPL License`_ + This is the license pygame is distributed under. + It provides for pygame to be distributed with open source and commercial software. + Generally, if pygame is not changed, it can be used with any type of program. + +Tutorials +--------- + +:doc:`Introduction to Pygame ` + An introduction to the basics of pygame. + This is written for users of Python and appeared in volume two of the Py magazine. + +:doc:`Import and Initialize ` + The beginning steps on importing and initializing pygame. + The pygame package is made of several modules. + Some modules are not included on all platforms. + +:doc:`How do I move an Image? ` + A basic tutorial that covers the concepts behind 2D computer animation. + Information about drawing and clearing objects to make them appear animated. + +:doc:`Chimp Tutorial, Line by Line ` + The pygame examples include a simple program with an interactive fist and a chimpanzee. + This was inspired by the annoying flash banner of the early 2000s. + This tutorial examines every line of code used in the example. + +:doc:`Sprite Module Introduction ` + Pygame includes a higher level sprite module to help organize games. + The sprite module includes several classes that help manage details found in almost all games types. + The Sprite classes are a bit more advanced than the regular pygame modules, + and need more understanding to be properly used. + +:doc:`Surfarray Introduction ` + Pygame used the NumPy python module to allow efficient per pixel effects on images. + Using the surface arrays is an advanced feature that allows custom effects and filters. + This also examines some of the simple effects from the pygame example, arraydemo.py. + +:doc:`Camera Module Introduction ` + Pygame, as of 1.9, has a camera module that allows you to capture images, + watch live streams, and do some basic computer vision. + This tutorial covers those use cases. + +:doc:`Newbie Guide ` + A list of thirteen helpful tips for people to get comfortable using pygame. + +:doc:`Making Games Tutorial ` + A large tutorial that covers the bigger topics needed to create an entire game. + +:doc:`Display Modes ` + Getting a display surface for the screen. + +:doc:`한국어 튜토리얼 (Korean Tutorial) ` + 빨간블록 검은블록 + +Reference +--------- + +:ref:`genindex` + A list of all functions, classes, and methods in the pygame package. + +:doc:`ref/bufferproxy` + An array protocol view of surface pixels + +:doc:`ref/color` + Color representation. + +:doc:`ref/cursors` + Loading and compiling cursor images. + +:doc:`ref/display` + Configure the display surface. + +:doc:`ref/draw` + Drawing simple shapes like lines and ellipses to surfaces. + +:doc:`ref/event` + Manage the incoming events from various input devices and the windowing platform. + +:doc:`ref/examples` + Various programs demonstrating the use of individual pygame modules. + +:doc:`ref/font` + Loading and rendering TrueType fonts. + +:doc:`ref/freetype` + Enhanced pygame module for loading and rendering font faces. + +:doc:`ref/gfxdraw` + Anti-aliasing draw functions. + +:doc:`ref/image` + Loading, saving, and transferring of surfaces. + +:doc:`ref/joystick` + Manage the joystick devices. + +:doc:`ref/key` + Manage the keyboard device. + +:doc:`ref/locals` + Pygame constants. + +:doc:`ref/mixer` + Load and play sounds + +:doc:`ref/mouse` + Manage the mouse device and display. + +:doc:`ref/music` + Play streaming music tracks. + +:doc:`ref/pygame` + Top level functions to manage pygame. + +:doc:`ref/pixelarray` + Manipulate image pixel data. + +:doc:`ref/rect` + Flexible container for a rectangle. + +:doc:`ref/scrap` + Native clipboard access. + +:doc:`ref/sndarray` + Manipulate sound sample data. + +:doc:`ref/sprite` + Higher level objects to represent game images. + +:doc:`ref/surface` + Objects for images and the screen. + +:doc:`ref/surfarray` + Manipulate image pixel data. + +:doc:`ref/tests` + Test pygame. + +:doc:`ref/time` + Manage timing and framerate. + +:doc:`ref/transform` + Resize and move images. + +:doc:`pygame C API ` + The C api shared amongst pygame extension modules. + +:ref:`search` + Search pygame documents by keyword. + +.. _Readme: ../wiki/about + +.. _Install: ../wiki/GettingStarted#Pygame%20Installation + +.. _File Path Function Arguments: filepaths.html + +.. _LGPL License: LGPL.txt diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/bufferproxy.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/bufferproxy.rst.txt new file mode 100644 index 0000000..bb4e693 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/bufferproxy.rst.txt @@ -0,0 +1,113 @@ +.. include:: common.txt + +.. default-domain:: py + +:class:`pygame.BufferProxy` +=========================== + +.. currentmodule:: pygame + +.. class:: BufferProxy + + | :sl:`pygame object to export a surface buffer through an array protocol` + | :sg:`BufferProxy() -> BufferProxy` + + :class:`BufferProxy` is a pygame support type, designed as the return value + of the :meth:`Surface.get_buffer` and :meth:`Surface.get_view` methods. + For all Python versions a :class:`BufferProxy` object exports a C struct + and Python level array interface on behalf of its parent object's buffer. + A new buffer interface is also exported. + In pygame, :class:`BufferProxy` is key to implementing the + :mod:`pygame.surfarray` module. + + :class:`BufferProxy` instances can be created directly from Python code, + either for a parent that exports an interface, or from a Python ``dict`` + describing an object's buffer layout. The dict entries are based on the + Python level array interface mapping. The following keys are recognized: + + ``"shape"`` : tuple + The length of each array dimension as a tuple of integers. The + length of the tuple is the number of dimensions in the array. + + ``"typestr"`` : string + The array element type as a length 3 string. The first character + gives byteorder, '<' for little-endian, '>' for big-endian, and + '\|' for not applicable. The second character is the element type, + 'i' for signed integer, 'u' for unsigned integer, 'f' for floating + point, and 'V' for an chunk of bytes. The third character gives the + bytesize of the element, from '1' to '9' bytes. So, for example, + " Surface` + | :sg:`parent -> ` + + The :class:`Surface` which returned the :class:`BufferProxy` object or + the object passed to a :class:`BufferProxy` call. + + .. attribute:: length + + | :sl:`The size, in bytes, of the exported buffer.` + | :sg:`length -> int` + + The number of valid bytes of data exported. For discontinuous data, + that is data which is not a single block of memory, the bytes within + the gaps are excluded from the count. This property is equivalent to + the ``Py_buffer`` C struct ``len`` field. + + .. attribute:: raw + + | :sl:`A copy of the exported buffer as a single block of bytes.` + | :sg:`raw -> bytes` + + The buffer data as a ``str``/``bytes`` object. + Any gaps in the exported data are removed. + + .. method:: write + + | :sl:`Write raw bytes to object buffer.` + | :sg:`write(buffer, offset=0)` + + Overwrite bytes in the parent object's data. The data must be C or F + contiguous, otherwise a ValueError is raised. Argument `buffer` is a + ``str``/``bytes`` object. An optional offset gives a + start position, in bytes, within the buffer where overwriting begins. + If the offset is negative or greater that or equal to the buffer proxy's + :attr:`length` value, an ``IndexException`` is raised. + If ``len(buffer) > proxy.length + offset``, a ``ValueError`` is raised. diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/camera.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/camera.rst.txt new file mode 100644 index 0000000..b9377df --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/camera.rst.txt @@ -0,0 +1,247 @@ +.. include:: common.txt + +:mod:`pygame.camera` +==================== + +.. module:: pygame.camera + :synopsis: pygame module for camera use + +| :sl:`pygame module for camera use` + +Pygame currently supports Linux (V4L2) and Windows (MSMF) cameras natively, +with wider platform support available via an integrated OpenCV backend. + +.. versionadded:: 2.0.2 Windows native camera support +.. versionadded:: 2.0.3 New OpenCV backends + +EXPERIMENTAL!: This API may change or disappear in later pygame releases. If +you use this, your code will very likely break with the next pygame release. + +The Bayer to ``RGB`` function is based on: + +:: + + Sonix SN9C101 based webcam basic I/F routines + Copyright (C) 2004 Takafumi Mizuno + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +New in pygame 1.9.0. + +.. function:: init + + | :sl:`Module init` + | :sg:`init(backend = None) -> None` + + This function starts up the camera module, choosing the best webcam backend + it can find for your system. This is not guaranteed to succeed, and may even + attempt to import third party modules, like `OpenCV`. If you want to + override its backend choice, you can call pass the name of the backend you + want into this function. More about backends in + :func:`get_backends()`. + + .. versionchanged:: 2.0.3 Option to explicitly select backend + + .. ## pygame.camera.init ## + +.. function:: get_backends + + | :sl:`Get the backends supported on this system` + | :sg:`get_backends() -> [str]` + + This function returns every backend it thinks has a possibility of working + on your system, in order of priority. + + pygame.camera Backends: + :: + + Backend OS Description + --------------------------------------------------------------------------------- + _camera (MSMF) Windows Builtin, works on Windows 8+ Python3 + _camera (V4L2) Linux Builtin + OpenCV Any Uses `opencv-python` module, can't enumerate cameras + OpenCV-Mac Mac Same as OpenCV, but has camera enumeration + VideoCapture Windows Uses abandoned `VideoCapture` module, can't enumerate + cameras, may be removed in the future + + There are two main differences among backends. + + The _camera backends are built in to pygame itself, and require no third + party imports. All the other backends do. For the OpenCV and VideoCapture + backends, those modules need to be installed on your system. + + The other big difference is "camera enumeration." Some backends don't have + a way to list out camera names, or even the number of cameras on the + system. In these cases, :func:`list_cameras()` will return + something like ``[0]``. If you know you have multiple cameras on the + system, these backend ports will pass through a "camera index number" + through if you use that as the ``device`` parameter. + + .. versionadded:: 2.0.3 + + .. ## pygame.camera.get_backends ## + +.. function:: colorspace + + | :sl:`Surface colorspace conversion` + | :sg:`colorspace(Surface, format, DestSurface = None) -> Surface` + + Allows for conversion from "RGB" to a destination colorspace of "HSV" or + "YUV". The source and destination surfaces must be the same size and pixel + depth. This is useful for computer vision on devices with limited processing + power. Capture as small of an image as possible, ``transform.scale()`` it + even smaller, and then convert the colorspace to ``YUV`` or ``HSV`` before + doing any processing on it. + + .. ## pygame.camera.colorspace ## + +.. function:: list_cameras + + | :sl:`returns a list of available cameras` + | :sg:`list_cameras() -> [cameras]` + + Checks the computer for available cameras and returns a list of strings of + camera names, ready to be fed into :class:`pygame.camera.Camera`. + + If the camera backend doesn't support webcam enumeration, this will return + something like ``[0]``. See :func:`get_backends()` for much more + information. + + .. ## pygame.camera.list_cameras ## + +.. class:: Camera + + | :sl:`load a camera` + | :sg:`Camera(device, (width, height), format) -> Camera` + + Loads a camera. On Linux, the device is typically something like + "/dev/video0". Default width and height are 640 by 480. + Format is the desired colorspace of the output. + This is useful for computer vision purposes. The default is + ``RGB``. The following are supported: + + * ``RGB`` - Red, Green, Blue + + * ``YUV`` - Luma, Blue Chrominance, Red Chrominance + + * ``HSV`` - Hue, Saturation, Value + + .. method:: start + + | :sl:`opens, initializes, and starts capturing` + | :sg:`start() -> None` + + Opens the camera device, attempts to initialize it, and begins recording + images to a buffer. The camera must be started before any of the below + functions can be used. + + .. ## Camera.start ## + + .. method:: stop + + | :sl:`stops, uninitializes, and closes the camera` + | :sg:`stop() -> None` + + Stops recording, uninitializes the camera, and closes it. Once a camera + is stopped, the below functions cannot be used until it is started again. + + .. ## Camera.stop ## + + .. method:: get_controls + + | :sl:`gets current values of user controls` + | :sg:`get_controls() -> (hflip = bool, vflip = bool, brightness)` + + If the camera supports it, get_controls will return the current settings + for horizontal and vertical image flip as bools and brightness as an int. + If unsupported, it will return the default values of (0, 0, 0). Note that + the return values here may be different than those returned by + set_controls, though these are more likely to be correct. + + .. ## Camera.get_controls ## + + .. method:: set_controls + + | :sl:`changes camera settings if supported by the camera` + | :sg:`set_controls(hflip = bool, vflip = bool, brightness) -> (hflip = bool, vflip = bool, brightness)` + + Allows you to change camera settings if the camera supports it. The + return values will be the input values if the camera claims it succeeded + or the values previously in use if not. Each argument is optional, and + the desired one can be chosen by supplying the keyword, like hflip. Note + that the actual settings being used by the camera may not be the same as + those returned by set_controls. On Windows, :code:`hflip` and :code:`vflip` are + implemented by pygame, not by the Camera, so they should always work, but + :code:`brightness` is unsupported. + + .. ## Camera.set_controls ## + + .. method:: get_size + + | :sl:`returns the dimensions of the images being recorded` + | :sg:`get_size() -> (width, height)` + + Returns the current dimensions of the images being captured by the + camera. This will return the actual size, which may be different than the + one specified during initialization if the camera did not support that + size. + + .. ## Camera.get_size ## + + .. method:: query_image + + | :sl:`checks if a frame is ready` + | :sg:`query_image() -> bool` + + If an image is ready to get, it returns true. Otherwise it returns false. + Note that some webcams will always return False and will only queue a + frame when called with a blocking function like :func:`get_image()`. + On Windows (MSMF), and the OpenCV backends, :func:`query_image()` + should be reliable, though. This is useful to separate the framerate of + the game from that of the camera without having to use threading. + + .. ## Camera.query_image ## + + .. method:: get_image + + | :sl:`captures an image as a Surface` + | :sg:`get_image(Surface = None) -> Surface` + + Pulls an image off of the buffer as an ``RGB`` Surface. It can optionally + reuse an existing Surface to save time. The bit-depth of the surface is + 24 bits on Linux, 32 bits on Windows, or the same as the optionally + supplied Surface. + + .. ## Camera.get_image ## + + .. method:: get_raw + + | :sl:`returns an unmodified image as bytes` + | :sg:`get_raw() -> bytes` + + Gets an image from a camera as a string in the native pixelformat of the + camera. Useful for integration with other libraries. This returns a + bytes object + + .. ## Camera.get_raw ## + + .. ## pygame.camera.Camera ## + +.. ## pygame.camera ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/cdrom.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/cdrom.rst.txt new file mode 100644 index 0000000..62688c9 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/cdrom.rst.txt @@ -0,0 +1,310 @@ +.. include:: common.txt + +:mod:`pygame.cdrom` +=================== + +.. module:: pygame.cdrom + :synopsis: pygame module for audio cdrom control + +| :sl:`pygame module for audio cdrom control` + +.. warning:: + This module is non functional in pygame 2.0 and above, unless you have manually compiled pygame with SDL1. + This module will not be supported in the future. + One alternative for python cdrom functionality is `pycdio `_. + +The cdrom module manages the ``CD`` and ``DVD`` drives on a computer. It can +also control the playback of audio CDs. This module needs to be initialized +before it can do anything. Each ``CD`` object you create represents a cdrom +drive and must also be initialized individually before it can do most things. + +.. function:: init + + | :sl:`initialize the cdrom module` + | :sg:`init() -> None` + + Initialize the cdrom module. This will scan the system for all ``CD`` + devices. The module must be initialized before any other functions will + work. This automatically happens when you call ``pygame.init()``. + + It is safe to call this function more than once. + + .. ## pygame.cdrom.init ## + +.. function:: quit + + | :sl:`uninitialize the cdrom module` + | :sg:`quit() -> None` + + Uninitialize the cdrom module. After you call this any existing ``CD`` + objects will no longer work. + + It is safe to call this function more than once. + + .. ## pygame.cdrom.quit ## + +.. function:: get_init + + | :sl:`true if the cdrom module is initialized` + | :sg:`get_init() -> bool` + + Test if the cdrom module is initialized or not. This is different than the + ``CD.init()`` since each drive must also be initialized individually. + + .. ## pygame.cdrom.get_init ## + +.. function:: get_count + + | :sl:`number of cd drives on the system` + | :sg:`get_count() -> count` + + Return the number of cd drives on the system. When you create ``CD`` objects + you need to pass an integer id that must be lower than this count. The count + will be 0 if there are no drives on the system. + + .. ## pygame.cdrom.get_count ## + +.. class:: CD + + | :sl:`class to manage a cdrom drive` + | :sg:`CD(id) -> CD` + + You can create a ``CD`` object for each cdrom on the system. Use + ``pygame.cdrom.get_count()`` to determine how many drives actually exist. + The id argument is an integer of the drive, starting at zero. + + The ``CD`` object is not initialized, you can only call ``CD.get_id()`` and + ``CD.get_name()`` on an uninitialized drive. + + It is safe to create multiple ``CD`` objects for the same drive, they will + all cooperate normally. + + .. method:: init + + | :sl:`initialize a cdrom drive for use` + | :sg:`init() -> None` + + Initialize the cdrom drive for use. The drive must be initialized for + most ``CD`` methods to work. Even if the rest of pygame has been + initialized. + + There may be a brief pause while the drive is initialized. Avoid + ``CD.init()`` if the program should not stop for a second or two. + + .. ## CD.init ## + + .. method:: quit + + | :sl:`uninitialize a cdrom drive for use` + | :sg:`quit() -> None` + + Uninitialize a drive for use. Call this when your program will not be + accessing the drive for awhile. + + .. ## CD.quit ## + + .. method:: get_init + + | :sl:`true if this cd device initialized` + | :sg:`get_init() -> bool` + + Test if this ``CDROM`` device is initialized. This is different than the + ``pygame.cdrom.init()`` since each drive must also be initialized + individually. + + .. ## CD.get_init ## + + .. method:: play + + | :sl:`start playing audio` + | :sg:`play(track, start=None, end=None) -> None` + + Playback audio from an audio cdrom in the drive. Besides the track number + argument, you can also pass a starting and ending time for playback. The + start and end time are in seconds, and can limit the section of an audio + track played. + + If you pass a start time but no end, the audio will play to the end of + the track. If you pass a start time and 'None' for the end time, the + audio will play to the end of the entire disc. + + See the ``CD.get_numtracks()`` and ``CD.get_track_audio()`` to find + tracks to playback. + + Note, track 0 is the first track on the ``CD``. Track numbers start at + zero. + + .. ## CD.play ## + + .. method:: stop + + | :sl:`stop audio playback` + | :sg:`stop() -> None` + + Stops playback of audio from the cdrom. This will also lose the current + playback position. This method does nothing if the drive isn't already + playing audio. + + .. ## CD.stop ## + + .. method:: pause + + | :sl:`temporarily stop audio playback` + | :sg:`pause() -> None` + + Temporarily stop audio playback on the ``CD``. The playback can be + resumed at the same point with the ``CD.resume()`` method. If the ``CD`` + is not playing this method does nothing. + + Note, track 0 is the first track on the ``CD``. Track numbers start at + zero. + + .. ## CD.pause ## + + .. method:: resume + + | :sl:`unpause audio playback` + | :sg:`resume() -> None` + + Unpause a paused ``CD``. If the ``CD`` is not paused or already playing, + this method does nothing. + + .. ## CD.resume ## + + .. method:: eject + + | :sl:`eject or open the cdrom drive` + | :sg:`eject() -> None` + + This will open the cdrom drive and eject the cdrom. If the drive is + playing or paused it will be stopped. + + .. ## CD.eject ## + + .. method:: get_id + + | :sl:`the index of the cdrom drive` + | :sg:`get_id() -> id` + + Returns the integer id that was used to create the ``CD`` instance. This + method can work on an uninitialized ``CD``. + + .. ## CD.get_id ## + + .. method:: get_name + + | :sl:`the system name of the cdrom drive` + | :sg:`get_name() -> name` + + Return the string name of the drive. This is the system name used to + represent the drive. It is often the drive letter or device name. This + method can work on an uninitialized ``CD``. + + .. ## CD.get_name ## + + .. method:: get_busy + + | :sl:`true if the drive is playing audio` + | :sg:`get_busy() -> bool` + + Returns True if the drive busy playing back audio. + + .. ## CD.get_busy ## + + .. method:: get_paused + + | :sl:`true if the drive is paused` + | :sg:`get_paused() -> bool` + + Returns True if the drive is currently paused. + + .. ## CD.get_paused ## + + .. method:: get_current + + | :sl:`the current audio playback position` + | :sg:`get_current() -> track, seconds` + + Returns both the current track and time of that track. This method works + when the drive is either playing or paused. + + Note, track 0 is the first track on the ``CD``. Track numbers start at + zero. + + .. ## CD.get_current ## + + .. method:: get_empty + + | :sl:`False if a cdrom is in the drive` + | :sg:`get_empty() -> bool` + + Return False if there is a cdrom currently in the drive. If the drive is + empty this will return True. + + .. ## CD.get_empty ## + + .. method:: get_numtracks + + | :sl:`the number of tracks on the cdrom` + | :sg:`get_numtracks() -> count` + + Return the number of tracks on the cdrom in the drive. This will return + zero of the drive is empty or has no tracks. + + .. ## CD.get_numtracks ## + + .. method:: get_track_audio + + | :sl:`true if the cdrom track has audio data` + | :sg:`get_track_audio(track) -> bool` + + Determine if a track on a cdrom contains audio data. You can also call + ``CD.num_tracks()`` and ``CD.get_all()`` to determine more information + about the cdrom. + + Note, track 0 is the first track on the ``CD``. Track numbers start at + zero. + + .. ## CD.get_track_audio ## + + .. method:: get_all + + | :sl:`get all track information` + | :sg:`get_all() -> [(audio, start, end, length), ...]` + + Return a list with information for every track on the cdrom. The + information consists of a tuple with four values. The audio value is True + if the track contains audio data. The start, end, and length values are + floating point numbers in seconds. Start and end represent absolute times + on the entire disc. + + .. ## CD.get_all ## + + .. method:: get_track_start + + | :sl:`start time of a cdrom track` + | :sg:`get_track_start(track) -> seconds` + + Return the absolute time in seconds where at start of the cdrom track. + + Note, track 0 is the first track on the ``CD``. Track numbers start at + zero. + + .. ## CD.get_track_start ## + + .. method:: get_track_length + + | :sl:`length of a cdrom track` + | :sg:`get_track_length(track) -> seconds` + + Return a floating point value in seconds of the length of the cdrom + track. + + Note, track 0 is the first track on the ``CD``. Track numbers start at + zero. + + .. ## CD.get_track_length ## + + .. ## pygame.cdrom.CD ## + +.. ## pygame.cdrom ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/color.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/color.rst.txt new file mode 100644 index 0000000..1841137 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/color.rst.txt @@ -0,0 +1,266 @@ +.. include:: common.txt + +:mod:`pygame.Color` +=================== + +.. currentmodule:: pygame + +.. class:: Color + + | :sl:`pygame object for color representations` + | :sg:`Color(r, g, b) -> Color` + | :sg:`Color(r, g, b, a=255) -> Color` + | :sg:`Color(color_value) -> Color` + + The ``Color`` class represents ``RGBA`` color values using a value range of + 0 to 255 inclusive. It allows basic arithmetic operations — binary + operations ``+``, ``-``, ``*``, ``//``, ``%``, and unary operation ``~`` — to + create new colors, supports conversions to other color spaces such as ``HSV`` + or ``HSL`` and lets you adjust single color channels. + Alpha defaults to 255 (fully opaque) when not given. + The arithmetic operations and ``correct_gamma()`` method preserve subclasses. + For the binary operators, the class of the returned color is that of the + left hand color object of the operator. + + Color objects support equality comparison with other color objects and 3 or + 4 element tuples of integers. There was a bug in pygame 1.8.1 + where the default alpha was 0, not 255 like previously. + + Color objects export the C level array interface. The interface exports a + read-only one dimensional unsigned byte array of the same assigned length + as the color. The new buffer interface is also exported, with the same + characteristics as the array interface. + + The floor division, ``//``, and modulus, ``%``, operators do not raise + an exception for division by zero. Instead, if a color, or alpha, channel + in the right hand color is 0, then the result is 0. For example: :: + + # These expressions are True + Color(255, 255, 255, 255) // Color(0, 64, 64, 64) == Color(0, 3, 3, 3) + Color(255, 255, 255, 255) % Color(64, 64, 64, 0) == Color(63, 63, 63, 0) + + Use ``int(color)`` to return the immutable integer value of the color, + usable as a ``dict`` key. This integer value differs from the mapped + pixel values of :meth:`pygame.Surface.get_at_mapped`, + :meth:`pygame.Surface.map_rgb` and :meth:`pygame.Surface.unmap_rgb`. + It can be passed as a ``color_value`` argument to :class:`Color` + (useful with sets). + + See :doc:`color_list` for samples of the available named colors. + + :param int r: red value in the range of 0 to 255 inclusive + :param int g: green value in the range of 0 to 255 inclusive + :param int b: blue value in the range of 0 to 255 inclusive + :param int a: (optional) alpha value in the range of 0 to 255 inclusive, + default is 255 + :param color_value: color value (see note below for the supported formats) + + .. note:: + Supported ``color_value`` formats: + | - **Color object:** clones the given :class:`Color` object + | - **Color name: str:** name of the color to use, e.g. ``'red'`` + (all the supported name strings can be found in the + :doc:`color_list`, with sample swatches) + | - **HTML color format str:** ``'#rrggbbaa'`` or ``'#rrggbb'``, + where rr, gg, bb, and aa are 2-digit hex numbers in the range + of 0 to 0xFF inclusive, the aa (alpha) value defaults to 0xFF + if not provided + | - **hex number str:** ``'0xrrggbbaa'`` or ``'0xrrggbb'``, where + rr, gg, bb, and aa are 2-digit hex numbers in the range of 0x00 + to 0xFF inclusive, the aa (alpha) value defaults to 0xFF if not + provided + | - **int:** int value of the color to use, using hex numbers can + make this parameter more readable, e.g. ``0xrrggbbaa``, where rr, + gg, bb, and aa are 2-digit hex numbers in the range of 0x00 to + 0xFF inclusive, note that the aa (alpha) value is not optional for + the int format and must be provided + | - **tuple/list of int color values:** ``(R, G, B, A)`` or + ``(R, G, B)``, where R, G, B, and A are int values in the range of + 0 to 255 inclusive, the A (alpha) value defaults to 255 if not + provided + + :type color_value: Color or str or int or tuple(int, int, int, [int]) or + list(int, int, int, [int]) + + :returns: a newly created :class:`Color` object + :rtype: Color + + .. versionchanged:: 2.0.0 + Support for tuples, lists, and :class:`Color` objects when creating + :class:`Color` objects. + .. versionchanged:: 1.9.2 Color objects export the C level array interface. + .. versionchanged:: 1.9.0 Color objects support 4-element tuples of integers. + .. versionchanged:: 1.8.1 New implementation of the class. + + .. attribute:: r + + | :sl:`Gets or sets the red value of the Color.` + | :sg:`r -> int` + + The red value of the Color. + + .. ## Color.r ## + + .. attribute:: g + + | :sl:`Gets or sets the green value of the Color.` + | :sg:`g -> int` + + The green value of the Color. + + .. ## Color.g ## + + .. attribute:: b + + | :sl:`Gets or sets the blue value of the Color.` + | :sg:`b -> int` + + The blue value of the Color. + + .. ## Color.b ## + + .. attribute:: a + + | :sl:`Gets or sets the alpha value of the Color.` + | :sg:`a -> int` + + The alpha value of the Color. + + .. ## Color.a ## + + .. attribute:: cmy + + | :sl:`Gets or sets the CMY representation of the Color.` + | :sg:`cmy -> tuple` + + The ``CMY`` representation of the Color. The ``CMY`` components are in + the ranges ``C`` = [0, 1], ``M`` = [0, 1], ``Y`` = [0, 1]. Note that this + will not return the absolutely exact ``CMY`` values for the set ``RGB`` + values in all cases. Due to the ``RGB`` mapping from 0-255 and the + ``CMY`` mapping from 0-1 rounding errors may cause the ``CMY`` values to + differ slightly from what you might expect. + + .. ## Color.cmy ## + + .. attribute:: hsva + + | :sl:`Gets or sets the HSVA representation of the Color.` + | :sg:`hsva -> tuple` + + The ``HSVA`` representation of the Color. The ``HSVA`` components are in + the ranges ``H`` = [0, 360], ``S`` = [0, 100], ``V`` = [0, 100], A = [0, + 100]. Note that this will not return the absolutely exact ``HSV`` values + for the set ``RGB`` values in all cases. Due to the ``RGB`` mapping from + 0-255 and the ``HSV`` mapping from 0-100 and 0-360 rounding errors may + cause the ``HSV`` values to differ slightly from what you might expect. + + .. ## Color.hsva ## + + .. attribute:: hsla + + | :sl:`Gets or sets the HSLA representation of the Color.` + | :sg:`hsla -> tuple` + + The ``HSLA`` representation of the Color. The ``HSLA`` components are in + the ranges ``H`` = [0, 360], ``S`` = [0, 100], ``V`` = [0, 100], A = [0, + 100]. Note that this will not return the absolutely exact ``HSL`` values + for the set ``RGB`` values in all cases. Due to the ``RGB`` mapping from + 0-255 and the ``HSL`` mapping from 0-100 and 0-360 rounding errors may + cause the ``HSL`` values to differ slightly from what you might expect. + + .. ## Color.hsla ## + + .. attribute:: i1i2i3 + + | :sl:`Gets or sets the I1I2I3 representation of the Color.` + | :sg:`i1i2i3 -> tuple` + + The ``I1I2I3`` representation of the Color. The ``I1I2I3`` components are + in the ranges ``I1`` = [0, 1], ``I2`` = [-0.5, 0.5], ``I3`` = [-0.5, + 0.5]. Note that this will not return the absolutely exact ``I1I2I3`` + values for the set ``RGB`` values in all cases. Due to the ``RGB`` + mapping from 0-255 and the ``I1I2I3`` mapping from 0-1 rounding errors + may cause the ``I1I2I3`` values to differ slightly from what you might + expect. + + .. ## Color.i1i2i3 ## + + .. method:: normalize + + | :sl:`Returns the normalized RGBA values of the Color.` + | :sg:`normalize() -> tuple` + + Returns the normalized ``RGBA`` values of the Color as floating point + values. + + .. ## Color.normalize ## + + .. method:: correct_gamma + + | :sl:`Applies a certain gamma value to the Color.` + | :sg:`correct_gamma (gamma) -> Color` + + Applies a certain gamma value to the Color and returns a new Color with + the adjusted ``RGBA`` values. + + .. ## Color.correct_gamma ## + + .. method:: set_length + + | :sl:`Set the number of elements in the Color to 1,2,3, or 4.` + | :sg:`set_length(len) -> None` + + The default Color length is 4. Colors can have lengths 1,2,3 or 4. This + is useful if you want to unpack to r,g,b and not r,g,b,a. If you want to + get the length of a Color do ``len(acolor)``. + + .. versionadded:: 1.9.0 + + .. ## Color.set_length ## + + .. method:: lerp + + | :sl:`returns a linear interpolation to the given Color.` + | :sg:`lerp(Color, float) -> Color` + + Returns a Color which is a linear interpolation between self and the + given Color in RGBA space. The second parameter determines how far + between self and other the result is going to be. + It must be a value between 0 and 1 where 0 means self and 1 means + other will be returned. + + .. versionadded:: 2.0.1 + + .. ## Color.lerp ## + + .. method:: premul_alpha + + | :sl:`returns a Color where the r,g,b components have been multiplied by the alpha.` + | :sg:`premul_alpha() -> Color` + + Returns a new Color where each of the red, green and blue colour + channels have been multiplied by the alpha channel of the original + color. The alpha channel remains unchanged. + + This is useful when working with the ``BLEND_PREMULTIPLIED`` blending mode + flag for :meth:`pygame.Surface.blit()`, which assumes that all surfaces using + it are using pre-multiplied alpha colors. + + .. versionadded:: 2.0.0 + + .. ## Color.premul_alpha ## + + .. method:: update + + | :sl:`Sets the elements of the color` + | :sg:`update(r, g, b) -> None` + | :sg:`update(r, g, b, a=255) -> None` + | :sg:`update(color_value) -> None` + + Sets the elements of the color. See parameters for :meth:`pygame.Color` for the + parameters of this function. If the alpha value was not set it will not change. + + .. versionadded:: 2.0.1 + + .. ## Color.update ## + .. ## pygame.Color ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/color_list.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/color_list.rst.txt new file mode 100644 index 0000000..b6cf289 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/color_list.rst.txt @@ -0,0 +1,2014 @@ +.. include:: common.txt + +Named Colors +============ + +.. raw:: html + + + +:doc:`color` lets you specify any of these named colors when creating a new +``pygame.Color`` (taken from the +`colordict module `_). + +.. role:: aliceblue +.. role:: antiquewhite +.. role:: antiquewhite1 +.. role:: antiquewhite2 +.. role:: antiquewhite3 +.. role:: antiquewhite4 +.. role:: aqua +.. role:: aquamarine +.. role:: aquamarine1 +.. role:: aquamarine2 +.. role:: aquamarine3 +.. role:: aquamarine4 +.. role:: azure +.. role:: azure1 +.. role:: azure2 +.. role:: azure3 +.. role:: azure4 +.. role:: beige +.. role:: bisque +.. role:: bisque1 +.. role:: bisque2 +.. role:: bisque3 +.. role:: bisque4 +.. role:: black +.. role:: blanchedalmond +.. role:: blue +.. role:: blue1 +.. role:: blue2 +.. role:: blue3 +.. role:: blue4 +.. role:: blueviolet +.. role:: brown +.. role:: brown1 +.. role:: brown2 +.. role:: brown3 +.. role:: brown4 +.. role:: burlywood +.. role:: burlywood1 +.. role:: burlywood2 +.. role:: burlywood3 +.. role:: burlywood4 +.. role:: cadetblue +.. role:: cadetblue1 +.. role:: cadetblue2 +.. role:: cadetblue3 +.. role:: cadetblue4 +.. role:: chartreuse +.. role:: chartreuse1 +.. role:: chartreuse2 +.. role:: chartreuse3 +.. role:: chartreuse4 +.. role:: chocolate +.. role:: chocolate1 +.. role:: chocolate2 +.. role:: chocolate3 +.. role:: chocolate4 +.. role:: coral +.. role:: coral1 +.. role:: coral2 +.. role:: coral3 +.. role:: coral4 +.. role:: cornflowerblue +.. role:: cornsilk +.. role:: cornsilk1 +.. role:: cornsilk2 +.. role:: cornsilk3 +.. role:: cornsilk4 +.. role:: crimson +.. role:: cyan +.. role:: cyan1 +.. role:: cyan2 +.. role:: cyan3 +.. role:: cyan4 +.. role:: darkblue +.. role:: darkcyan +.. role:: darkgoldenrod +.. role:: darkgoldenrod1 +.. role:: darkgoldenrod2 +.. role:: darkgoldenrod3 +.. role:: darkgoldenrod4 +.. role:: darkgray +.. role:: darkgreen +.. role:: darkgrey +.. role:: darkkhaki +.. role:: darkmagenta +.. role:: darkolivegreen +.. role:: darkolivegreen1 +.. role:: darkolivegreen2 +.. role:: darkolivegreen3 +.. role:: darkolivegreen4 +.. role:: darkorange +.. role:: darkorange1 +.. role:: darkorange2 +.. role:: darkorange3 +.. role:: darkorange4 +.. role:: darkorchid +.. role:: darkorchid1 +.. role:: darkorchid2 +.. role:: darkorchid3 +.. role:: darkorchid4 +.. role:: darkred +.. role:: darksalmon +.. role:: darkseagreen +.. role:: darkseagreen1 +.. role:: darkseagreen2 +.. role:: darkseagreen3 +.. role:: darkseagreen4 +.. role:: darkslateblue +.. role:: darkslategray +.. role:: darkslategray1 +.. role:: darkslategray2 +.. role:: darkslategray3 +.. role:: darkslategray4 +.. role:: darkslategrey +.. role:: darkturquoise +.. role:: darkviolet +.. role:: deeppink +.. role:: deeppink1 +.. role:: deeppink2 +.. role:: deeppink3 +.. role:: deeppink4 +.. role:: deepskyblue +.. role:: deepskyblue1 +.. role:: deepskyblue2 +.. role:: deepskyblue3 +.. role:: deepskyblue4 +.. role:: dimgray +.. role:: dimgrey +.. role:: dodgerblue +.. role:: dodgerblue1 +.. role:: dodgerblue2 +.. role:: dodgerblue3 +.. role:: dodgerblue4 +.. role:: firebrick +.. role:: firebrick1 +.. role:: firebrick2 +.. role:: firebrick3 +.. role:: firebrick4 +.. role:: floralwhite +.. role:: forestgreen +.. role:: fuchsia +.. role:: gainsboro +.. role:: ghostwhite +.. role:: gold +.. role:: gold1 +.. role:: gold2 +.. role:: gold3 +.. role:: gold4 +.. role:: goldenrod +.. role:: goldenrod1 +.. role:: goldenrod2 +.. role:: goldenrod3 +.. role:: goldenrod4 +.. role:: gray +.. role:: gray0 +.. role:: gray1 +.. role:: gray2 +.. role:: gray3 +.. role:: gray4 +.. role:: gray5 +.. role:: gray6 +.. role:: gray7 +.. role:: gray8 +.. role:: gray9 +.. role:: gray10 +.. role:: gray11 +.. role:: gray12 +.. role:: gray13 +.. role:: gray14 +.. role:: gray15 +.. role:: gray16 +.. role:: gray17 +.. role:: gray18 +.. role:: gray19 +.. role:: gray20 +.. role:: gray21 +.. role:: gray22 +.. role:: gray23 +.. role:: gray24 +.. role:: gray25 +.. role:: gray26 +.. role:: gray27 +.. role:: gray28 +.. role:: gray29 +.. role:: gray30 +.. role:: gray31 +.. role:: gray32 +.. role:: gray33 +.. role:: gray34 +.. role:: gray35 +.. role:: gray36 +.. role:: gray37 +.. role:: gray38 +.. role:: gray39 +.. role:: gray40 +.. role:: gray41 +.. role:: gray42 +.. role:: gray43 +.. role:: gray44 +.. role:: gray45 +.. role:: gray46 +.. role:: gray47 +.. role:: gray48 +.. role:: gray49 +.. role:: gray50 +.. role:: gray51 +.. role:: gray52 +.. role:: gray53 +.. role:: gray54 +.. role:: gray55 +.. role:: gray56 +.. role:: gray57 +.. role:: gray58 +.. role:: gray59 +.. role:: gray60 +.. role:: gray61 +.. role:: gray62 +.. role:: gray63 +.. role:: gray64 +.. role:: gray65 +.. role:: gray66 +.. role:: gray67 +.. role:: gray68 +.. role:: gray69 +.. role:: gray70 +.. role:: gray71 +.. role:: gray72 +.. role:: gray73 +.. role:: gray74 +.. role:: gray75 +.. role:: gray76 +.. role:: gray77 +.. role:: gray78 +.. role:: gray79 +.. role:: gray80 +.. role:: gray81 +.. role:: gray82 +.. role:: gray83 +.. role:: gray84 +.. role:: gray85 +.. role:: gray86 +.. role:: gray87 +.. role:: gray88 +.. role:: gray89 +.. role:: gray90 +.. role:: gray91 +.. role:: gray92 +.. role:: gray93 +.. role:: gray94 +.. role:: gray95 +.. role:: gray96 +.. role:: gray97 +.. role:: gray98 +.. role:: gray99 +.. role:: gray100 +.. role:: green +.. role:: green1 +.. role:: green2 +.. role:: green3 +.. role:: green4 +.. role:: greenyellow +.. role:: grey +.. role:: grey0 +.. role:: grey1 +.. role:: grey2 +.. role:: grey3 +.. role:: grey4 +.. role:: grey5 +.. role:: grey6 +.. role:: grey7 +.. role:: grey8 +.. role:: grey9 +.. role:: grey10 +.. role:: grey11 +.. role:: grey12 +.. role:: grey13 +.. role:: grey14 +.. role:: grey15 +.. role:: grey16 +.. role:: grey17 +.. role:: grey18 +.. role:: grey19 +.. role:: grey20 +.. role:: grey21 +.. role:: grey22 +.. role:: grey23 +.. role:: grey24 +.. role:: grey25 +.. role:: grey26 +.. role:: grey27 +.. role:: grey28 +.. role:: grey29 +.. role:: grey30 +.. role:: grey31 +.. role:: grey32 +.. role:: grey33 +.. role:: grey34 +.. role:: grey35 +.. role:: grey36 +.. role:: grey37 +.. role:: grey38 +.. role:: grey39 +.. role:: grey40 +.. role:: grey41 +.. role:: grey42 +.. role:: grey43 +.. role:: grey44 +.. role:: grey45 +.. role:: grey46 +.. role:: grey47 +.. role:: grey48 +.. role:: grey49 +.. role:: grey50 +.. role:: grey51 +.. role:: grey52 +.. role:: grey53 +.. role:: grey54 +.. role:: grey55 +.. role:: grey56 +.. role:: grey57 +.. role:: grey58 +.. role:: grey59 +.. role:: grey60 +.. role:: grey61 +.. role:: grey62 +.. role:: grey63 +.. role:: grey64 +.. role:: grey65 +.. role:: grey66 +.. role:: grey67 +.. role:: grey68 +.. role:: grey69 +.. role:: grey70 +.. role:: grey71 +.. role:: grey72 +.. role:: grey73 +.. role:: grey74 +.. role:: grey75 +.. role:: grey76 +.. role:: grey77 +.. role:: grey78 +.. role:: grey79 +.. role:: grey80 +.. role:: grey81 +.. role:: grey82 +.. role:: grey83 +.. role:: grey84 +.. role:: grey85 +.. role:: grey86 +.. role:: grey87 +.. role:: grey88 +.. role:: grey89 +.. role:: grey90 +.. role:: grey91 +.. role:: grey92 +.. role:: grey93 +.. role:: grey94 +.. role:: grey95 +.. role:: grey96 +.. role:: grey97 +.. role:: grey98 +.. role:: grey99 +.. role:: grey100 +.. role:: honeydew +.. role:: honeydew1 +.. role:: honeydew2 +.. role:: honeydew3 +.. role:: honeydew4 +.. role:: hotpink +.. role:: hotpink1 +.. role:: hotpink2 +.. role:: hotpink3 +.. role:: hotpink4 +.. role:: indianred +.. role:: indianred1 +.. role:: indianred2 +.. role:: indianred3 +.. role:: indianred4 +.. role:: indigo +.. role:: ivory +.. role:: ivory1 +.. role:: ivory2 +.. role:: ivory3 +.. role:: ivory4 +.. role:: khaki +.. role:: khaki1 +.. role:: khaki2 +.. role:: khaki3 +.. role:: khaki4 +.. role:: lavender +.. role:: lavenderblush +.. role:: lavenderblush1 +.. role:: lavenderblush2 +.. role:: lavenderblush3 +.. role:: lavenderblush4 +.. role:: lawngreen +.. role:: lemonchiffon +.. role:: lemonchiffon1 +.. role:: lemonchiffon2 +.. role:: lemonchiffon3 +.. role:: lemonchiffon4 +.. role:: lightblue +.. role:: lightblue1 +.. role:: lightblue2 +.. role:: lightblue3 +.. role:: lightblue4 +.. role:: lightcoral +.. role:: lightcyan +.. role:: lightcyan1 +.. role:: lightcyan2 +.. role:: lightcyan3 +.. role:: lightcyan4 +.. role:: lightgoldenrod +.. role:: lightgoldenrod1 +.. role:: lightgoldenrod2 +.. role:: lightgoldenrod3 +.. role:: lightgoldenrod4 +.. role:: lightgoldenrodyellow +.. role:: lightgray +.. role:: lightgreen +.. role:: lightgrey +.. role:: lightpink +.. role:: lightpink1 +.. role:: lightpink2 +.. role:: lightpink3 +.. role:: lightpink4 +.. role:: lightsalmon +.. role:: lightsalmon1 +.. role:: lightsalmon2 +.. role:: lightsalmon3 +.. role:: lightsalmon4 +.. role:: lightseagreen +.. role:: lightskyblue +.. role:: lightskyblue1 +.. role:: lightskyblue2 +.. role:: lightskyblue3 +.. role:: lightskyblue4 +.. role:: lightslateblue +.. role:: lightslategray +.. role:: lightslategrey +.. role:: lightsteelblue +.. role:: lightsteelblue1 +.. role:: lightsteelblue2 +.. role:: lightsteelblue3 +.. role:: lightsteelblue4 +.. role:: lightyellow +.. role:: lightyellow1 +.. role:: lightyellow2 +.. role:: lightyellow3 +.. role:: lightyellow4 +.. role:: limegreen +.. role:: lime +.. role:: linen +.. role:: magenta +.. role:: magenta1 +.. role:: magenta2 +.. role:: magenta3 +.. role:: magenta4 +.. role:: maroon +.. role:: maroon1 +.. role:: maroon2 +.. role:: maroon3 +.. role:: maroon4 +.. role:: mediumaquamarine +.. role:: mediumblue +.. role:: mediumorchid +.. role:: mediumorchid1 +.. role:: mediumorchid2 +.. role:: mediumorchid3 +.. role:: mediumorchid4 +.. role:: mediumpurple +.. role:: mediumpurple1 +.. role:: mediumpurple2 +.. role:: mediumpurple3 +.. role:: mediumpurple4 +.. role:: mediumseagreen +.. role:: mediumslateblue +.. role:: mediumspringgreen +.. role:: mediumturquoise +.. role:: mediumvioletred +.. role:: midnightblue +.. role:: mintcream +.. role:: mistyrose +.. role:: mistyrose1 +.. role:: mistyrose2 +.. role:: mistyrose3 +.. role:: mistyrose4 +.. role:: moccasin +.. role:: navajowhite +.. role:: navajowhite1 +.. role:: navajowhite2 +.. role:: navajowhite3 +.. role:: navajowhite4 +.. role:: navy +.. role:: navyblue +.. role:: oldlace +.. role:: olive +.. role:: olivedrab +.. role:: olivedrab1 +.. role:: olivedrab2 +.. role:: olivedrab3 +.. role:: olivedrab4 +.. role:: orange +.. role:: orange1 +.. role:: orange2 +.. role:: orange3 +.. role:: orange4 +.. role:: orangered +.. role:: orangered1 +.. role:: orangered2 +.. role:: orangered3 +.. role:: orangered4 +.. role:: orchid +.. role:: orchid1 +.. role:: orchid2 +.. role:: orchid3 +.. role:: orchid4 +.. role:: palegoldenrod +.. role:: palegreen +.. role:: palegreen1 +.. role:: palegreen2 +.. role:: palegreen3 +.. role:: palegreen4 +.. role:: paleturquoise +.. role:: paleturquoise1 +.. role:: paleturquoise2 +.. role:: paleturquoise3 +.. role:: paleturquoise4 +.. role:: palevioletred +.. role:: palevioletred1 +.. role:: palevioletred2 +.. role:: palevioletred3 +.. role:: palevioletred4 +.. role:: papayawhip +.. role:: peachpuff +.. role:: peachpuff1 +.. role:: peachpuff2 +.. role:: peachpuff3 +.. role:: peachpuff4 +.. role:: peru +.. role:: pink +.. role:: pink1 +.. role:: pink2 +.. role:: pink3 +.. role:: pink4 +.. role:: plum +.. role:: plum1 +.. role:: plum2 +.. role:: plum3 +.. role:: plum4 +.. role:: powderblue +.. role:: purple +.. role:: purple1 +.. role:: purple2 +.. role:: purple3 +.. role:: purple4 +.. role:: red +.. role:: red1 +.. role:: red2 +.. role:: red3 +.. role:: red4 +.. role:: rosybrown +.. role:: rosybrown1 +.. role:: rosybrown2 +.. role:: rosybrown3 +.. role:: rosybrown4 +.. role:: royalblue +.. role:: royalblue1 +.. role:: royalblue2 +.. role:: royalblue3 +.. role:: royalblue4 +.. role:: saddlebrown +.. role:: salmon +.. role:: salmon1 +.. role:: salmon2 +.. role:: salmon3 +.. role:: salmon4 +.. role:: sandybrown +.. role:: seagreen +.. role:: seagreen1 +.. role:: seagreen2 +.. role:: seagreen3 +.. role:: seagreen4 +.. role:: seashell +.. role:: seashell1 +.. role:: seashell2 +.. role:: seashell3 +.. role:: seashell4 +.. role:: sienna +.. role:: sienna1 +.. role:: sienna2 +.. role:: sienna3 +.. role:: sienna4 +.. role:: silver +.. role:: skyblue +.. role:: skyblue1 +.. role:: skyblue2 +.. role:: skyblue3 +.. role:: skyblue4 +.. role:: slateblue +.. role:: slateblue1 +.. role:: slateblue2 +.. role:: slateblue3 +.. role:: slateblue4 +.. role:: slategray +.. role:: slategray1 +.. role:: slategray2 +.. role:: slategray3 +.. role:: slategray4 +.. role:: slategrey +.. role:: snow +.. role:: snow1 +.. role:: snow2 +.. role:: snow3 +.. role:: snow4 +.. role:: springgreen +.. role:: springgreen1 +.. role:: springgreen2 +.. role:: springgreen3 +.. role:: springgreen4 +.. role:: steelblue +.. role:: steelblue1 +.. role:: steelblue2 +.. role:: steelblue3 +.. role:: steelblue4 +.. role:: tan +.. role:: tan1 +.. role:: tan2 +.. role:: tan3 +.. role:: tan4 +.. role:: teal +.. role:: thistle +.. role:: thistle1 +.. role:: thistle2 +.. role:: thistle3 +.. role:: thistle4 +.. role:: tomato +.. role:: tomato1 +.. role:: tomato2 +.. role:: tomato3 +.. role:: tomato4 +.. role:: turquoise +.. role:: turquoise1 +.. role:: turquoise2 +.. role:: turquoise3 +.. role:: turquoise4 +.. role:: violet +.. role:: violetred +.. role:: violetred1 +.. role:: violetred2 +.. role:: violetred3 +.. role:: violetred4 +.. role:: wheat +.. role:: wheat1 +.. role:: wheat2 +.. role:: wheat3 +.. role:: wheat4 +.. role:: white +.. role:: whitesmoke +.. role:: yellow +.. role:: yellow1 +.. role:: yellow2 +.. role:: yellow3 +.. role:: yellow4 +.. role:: yellowgreen + +========================== ====================================================================================================== +Name Color +========================== ====================================================================================================== +``aliceblue`` :aliceblue:`████████` +``antiquewhite`` :antiquewhite:`████████` +``antiquewhite1`` :antiquewhite1:`████████` +``antiquewhite2`` :antiquewhite2:`████████` +``antiquewhite3`` :antiquewhite3:`████████` +``antiquewhite4`` :antiquewhite4:`████████` +``aqua`` :aqua:`████████` +``aquamarine`` :aquamarine:`████████` +``aquamarine1`` :aquamarine1:`████████` +``aquamarine2`` :aquamarine2:`████████` +``aquamarine3`` :aquamarine3:`████████` +``aquamarine4`` :aquamarine4:`████████` +``azure`` :azure:`████████` +``azure1`` :azure1:`████████` +``azure2`` :azure2:`████████` +``azure3`` :azure3:`████████` +``azure4`` :azure4:`████████` +``beige`` :beige:`████████` +``bisque`` :bisque:`████████` +``bisque1`` :bisque1:`████████` +``bisque2`` :bisque2:`████████` +``bisque3`` :bisque3:`████████` +``bisque4`` :bisque4:`████████` +``black`` :black:`████████` +``blanchedalmond`` :blanchedalmond:`████████` +``blue`` :blue:`████████` +``blue1`` :blue1:`████████` +``blue2`` :blue2:`████████` +``blue3`` :blue3:`████████` +``blue4`` :blue4:`████████` +``blueviolet`` :blueviolet:`████████` +``brown`` :brown:`████████` +``brown1`` :brown1:`████████` +``brown2`` :brown2:`████████` +``brown3`` :brown3:`████████` +``brown4`` :brown4:`████████` +``burlywood`` :burlywood:`████████` +``burlywood1`` :burlywood1:`████████` +``burlywood2`` :burlywood2:`████████` +``burlywood3`` :burlywood3:`████████` +``burlywood4`` :burlywood4:`████████` +``cadetblue`` :cadetblue:`████████` +``cadetblue1`` :cadetblue1:`████████` +``cadetblue2`` :cadetblue2:`████████` +``cadetblue3`` :cadetblue3:`████████` +``cadetblue4`` :cadetblue4:`████████` +``chartreuse`` :chartreuse:`████████` +``chartreuse1`` :chartreuse1:`████████` +``chartreuse2`` :chartreuse2:`████████` +``chartreuse3`` :chartreuse3:`████████` +``chartreuse4`` :chartreuse4:`████████` +``chocolate`` :chocolate:`████████` +``chocolate1`` :chocolate1:`████████` +``chocolate2`` :chocolate2:`████████` +``chocolate3`` :chocolate3:`████████` +``chocolate4`` :chocolate4:`████████` +``coral`` :coral:`████████` +``coral1`` :coral1:`████████` +``coral2`` :coral2:`████████` +``coral3`` :coral3:`████████` +``coral4`` :coral4:`████████` +``cornflowerblue`` :cornflowerblue:`████████` +``cornsilk`` :cornsilk:`████████` +``cornsilk1`` :cornsilk1:`████████` +``cornsilk2`` :cornsilk2:`████████` +``cornsilk3`` :cornsilk3:`████████` +``cornsilk4`` :cornsilk4:`████████` +``crimson`` :crimson:`████████` +``cyan`` :cyan:`████████` +``cyan1`` :cyan1:`████████` +``cyan2`` :cyan2:`████████` +``cyan3`` :cyan3:`████████` +``cyan4`` :cyan4:`████████` +``darkblue`` :darkblue:`████████` +``darkcyan`` :darkcyan:`████████` +``darkgoldenrod`` :darkgoldenrod:`████████` +``darkgoldenrod1`` :darkgoldenrod1:`████████` +``darkgoldenrod2`` :darkgoldenrod2:`████████` +``darkgoldenrod3`` :darkgoldenrod3:`████████` +``darkgoldenrod4`` :darkgoldenrod4:`████████` +``darkgray`` :darkgray:`████████` +``darkgreen`` :darkgreen:`████████` +``darkgrey`` :darkgrey:`████████` +``darkkhaki`` :darkkhaki:`████████` +``darkmagenta`` :darkmagenta:`████████` +``darkolivegreen`` :darkolivegreen:`████████` +``darkolivegreen1`` :darkolivegreen1:`████████` +``darkolivegreen2`` :darkolivegreen2:`████████` +``darkolivegreen3`` :darkolivegreen3:`████████` +``darkolivegreen4`` :darkolivegreen4:`████████` +``darkorange`` :darkorange:`████████` +``darkorange1`` :darkorange1:`████████` +``darkorange2`` :darkorange2:`████████` +``darkorange3`` :darkorange3:`████████` +``darkorange4`` :darkorange4:`████████` +``darkorchid`` :darkorchid:`████████` +``darkorchid1`` :darkorchid1:`████████` +``darkorchid2`` :darkorchid2:`████████` +``darkorchid3`` :darkorchid3:`████████` +``darkorchid4`` :darkorchid4:`████████` +``darkred`` :darkred:`████████` +``darksalmon`` :darksalmon:`████████` +``darkseagreen`` :darkseagreen:`████████` +``darkseagreen1`` :darkseagreen1:`████████` +``darkseagreen2`` :darkseagreen2:`████████` +``darkseagreen3`` :darkseagreen3:`████████` +``darkseagreen4`` :darkseagreen4:`████████` +``darkslateblue`` :darkslateblue:`████████` +``darkslategray`` :darkslategray:`████████` +``darkslategray1`` :darkslategray1:`████████` +``darkslategray2`` :darkslategray2:`████████` +``darkslategray3`` :darkslategray3:`████████` +``darkslategray4`` :darkslategray4:`████████` +``darkslategrey`` :darkslategrey:`████████` +``darkturquoise`` :darkturquoise:`████████` +``darkviolet`` :darkviolet:`████████` +``deeppink`` :deeppink:`████████` +``deeppink1`` :deeppink1:`████████` +``deeppink2`` :deeppink2:`████████` +``deeppink3`` :deeppink3:`████████` +``deeppink4`` :deeppink4:`████████` +``deepskyblue`` :deepskyblue:`████████` +``deepskyblue1`` :deepskyblue1:`████████` +``deepskyblue2`` :deepskyblue2:`████████` +``deepskyblue3`` :deepskyblue3:`████████` +``deepskyblue4`` :deepskyblue4:`████████` +``dimgray`` :dimgray:`████████` +``dimgrey`` :dimgrey:`████████` +``dodgerblue`` :dodgerblue:`████████` +``dodgerblue1`` :dodgerblue1:`████████` +``dodgerblue2`` :dodgerblue2:`████████` +``dodgerblue3`` :dodgerblue3:`████████` +``dodgerblue4`` :dodgerblue4:`████████` +``firebrick`` :firebrick:`████████` +``firebrick1`` :firebrick1:`████████` +``firebrick2`` :firebrick2:`████████` +``firebrick3`` :firebrick3:`████████` +``firebrick4`` :firebrick4:`████████` +``floralwhite`` :floralwhite:`████████` +``forestgreen`` :forestgreen:`████████` +``fuchsia`` :fuchsia:`████████` +``gainsboro`` :gainsboro:`████████` +``ghostwhite`` :ghostwhite:`████████` +``gold`` :gold:`████████` +``gold1`` :gold1:`████████` +``gold2`` :gold2:`████████` +``gold3`` :gold3:`████████` +``gold4`` :gold4:`████████` +``goldenrod`` :goldenrod:`████████` +``goldenrod1`` :goldenrod1:`████████` +``goldenrod2`` :goldenrod2:`████████` +``goldenrod3`` :goldenrod3:`████████` +``goldenrod4`` :goldenrod4:`████████` +``gray`` :gray:`████████` +``gray0`` :gray0:`████████` +``gray1`` :gray1:`████████` +``gray2`` :gray2:`████████` +``gray3`` :gray3:`████████` +``gray4`` :gray4:`████████` +``gray5`` :gray5:`████████` +``gray6`` :gray6:`████████` +``gray7`` :gray7:`████████` +``gray8`` :gray8:`████████` +``gray9`` :gray9:`████████` +``gray10`` :gray10:`████████` +``gray11`` :gray11:`████████` +``gray12`` :gray12:`████████` +``gray13`` :gray13:`████████` +``gray14`` :gray14:`████████` +``gray15`` :gray15:`████████` +``gray16`` :gray16:`████████` +``gray17`` :gray17:`████████` +``gray18`` :gray18:`████████` +``gray19`` :gray19:`████████` +``gray20`` :gray20:`████████` +``gray21`` :gray21:`████████` +``gray22`` :gray22:`████████` +``gray23`` :gray23:`████████` +``gray24`` :gray24:`████████` +``gray25`` :gray25:`████████` +``gray26`` :gray26:`████████` +``gray27`` :gray27:`████████` +``gray28`` :gray28:`████████` +``gray29`` :gray29:`████████` +``gray30`` :gray30:`████████` +``gray31`` :gray31:`████████` +``gray32`` :gray32:`████████` +``gray33`` :gray33:`████████` +``gray34`` :gray34:`████████` +``gray35`` :gray35:`████████` +``gray36`` :gray36:`████████` +``gray37`` :gray37:`████████` +``gray38`` :gray38:`████████` +``gray39`` :gray39:`████████` +``gray40`` :gray40:`████████` +``gray41`` :gray41:`████████` +``gray42`` :gray42:`████████` +``gray43`` :gray43:`████████` +``gray44`` :gray44:`████████` +``gray45`` :gray45:`████████` +``gray46`` :gray46:`████████` +``gray47`` :gray47:`████████` +``gray48`` :gray48:`████████` +``gray49`` :gray49:`████████` +``gray50`` :gray50:`████████` +``gray51`` :gray51:`████████` +``gray52`` :gray52:`████████` +``gray53`` :gray53:`████████` +``gray54`` :gray54:`████████` +``gray55`` :gray55:`████████` +``gray56`` :gray56:`████████` +``gray57`` :gray57:`████████` +``gray58`` :gray58:`████████` +``gray59`` :gray59:`████████` +``gray60`` :gray60:`████████` +``gray61`` :gray61:`████████` +``gray62`` :gray62:`████████` +``gray63`` :gray63:`████████` +``gray64`` :gray64:`████████` +``gray65`` :gray65:`████████` +``gray66`` :gray66:`████████` +``gray67`` :gray67:`████████` +``gray68`` :gray68:`████████` +``gray69`` :gray69:`████████` +``gray70`` :gray70:`████████` +``gray71`` :gray71:`████████` +``gray72`` :gray72:`████████` +``gray73`` :gray73:`████████` +``gray74`` :gray74:`████████` +``gray75`` :gray75:`████████` +``gray76`` :gray76:`████████` +``gray77`` :gray77:`████████` +``gray78`` :gray78:`████████` +``gray79`` :gray79:`████████` +``gray80`` :gray80:`████████` +``gray81`` :gray81:`████████` +``gray82`` :gray82:`████████` +``gray83`` :gray83:`████████` +``gray84`` :gray84:`████████` +``gray85`` :gray85:`████████` +``gray86`` :gray86:`████████` +``gray87`` :gray87:`████████` +``gray88`` :gray88:`████████` +``gray89`` :gray89:`████████` +``gray90`` :gray90:`████████` +``gray91`` :gray91:`████████` +``gray92`` :gray92:`████████` +``gray93`` :gray93:`████████` +``gray94`` :gray94:`████████` +``gray95`` :gray95:`████████` +``gray96`` :gray96:`████████` +``gray97`` :gray97:`████████` +``gray98`` :gray98:`████████` +``gray99`` :gray99:`████████` +``gray100`` :gray100:`████████` +``green`` :green:`████████` +``green1`` :green1:`████████` +``green2`` :green2:`████████` +``green3`` :green3:`████████` +``green4`` :green4:`████████` +``greenyellow`` :greenyellow:`████████` +``grey`` :grey:`████████` +``grey0`` :grey0:`████████` +``grey1`` :grey1:`████████` +``grey2`` :grey2:`████████` +``grey3`` :grey3:`████████` +``grey4`` :grey4:`████████` +``grey5`` :grey5:`████████` +``grey6`` :grey6:`████████` +``grey7`` :grey7:`████████` +``grey8`` :grey8:`████████` +``grey9`` :grey9:`████████` +``grey10`` :grey10:`████████` +``grey11`` :grey11:`████████` +``grey12`` :grey12:`████████` +``grey13`` :grey13:`████████` +``grey14`` :grey14:`████████` +``grey15`` :grey15:`████████` +``grey16`` :grey16:`████████` +``grey17`` :grey17:`████████` +``grey18`` :grey18:`████████` +``grey19`` :grey19:`████████` +``grey20`` :grey20:`████████` +``grey21`` :grey21:`████████` +``grey22`` :grey22:`████████` +``grey23`` :grey23:`████████` +``grey24`` :grey24:`████████` +``grey25`` :grey25:`████████` +``grey26`` :grey26:`████████` +``grey27`` :grey27:`████████` +``grey28`` :grey28:`████████` +``grey29`` :grey29:`████████` +``grey30`` :grey30:`████████` +``grey31`` :grey31:`████████` +``grey32`` :grey32:`████████` +``grey33`` :grey33:`████████` +``grey34`` :grey34:`████████` +``grey35`` :grey35:`████████` +``grey36`` :grey36:`████████` +``grey37`` :grey37:`████████` +``grey38`` :grey38:`████████` +``grey39`` :grey39:`████████` +``grey40`` :grey40:`████████` +``grey41`` :grey41:`████████` +``grey42`` :grey42:`████████` +``grey43`` :grey43:`████████` +``grey44`` :grey44:`████████` +``grey45`` :grey45:`████████` +``grey46`` :grey46:`████████` +``grey47`` :grey47:`████████` +``grey48`` :grey48:`████████` +``grey49`` :grey49:`████████` +``grey50`` :grey50:`████████` +``grey51`` :grey51:`████████` +``grey52`` :grey52:`████████` +``grey53`` :grey53:`████████` +``grey54`` :grey54:`████████` +``grey55`` :grey55:`████████` +``grey56`` :grey56:`████████` +``grey57`` :grey57:`████████` +``grey58`` :grey58:`████████` +``grey59`` :grey59:`████████` +``grey60`` :grey60:`████████` +``grey61`` :grey61:`████████` +``grey62`` :grey62:`████████` +``grey63`` :grey63:`████████` +``grey64`` :grey64:`████████` +``grey65`` :grey65:`████████` +``grey66`` :grey66:`████████` +``grey67`` :grey67:`████████` +``grey68`` :grey68:`████████` +``grey69`` :grey69:`████████` +``grey70`` :grey70:`████████` +``grey71`` :grey71:`████████` +``grey72`` :grey72:`████████` +``grey73`` :grey73:`████████` +``grey74`` :grey74:`████████` +``grey75`` :grey75:`████████` +``grey76`` :grey76:`████████` +``grey77`` :grey77:`████████` +``grey78`` :grey78:`████████` +``grey79`` :grey79:`████████` +``grey80`` :grey80:`████████` +``grey81`` :grey81:`████████` +``grey82`` :grey82:`████████` +``grey83`` :grey83:`████████` +``grey84`` :grey84:`████████` +``grey85`` :grey85:`████████` +``grey86`` :grey86:`████████` +``grey87`` :grey87:`████████` +``grey88`` :grey88:`████████` +``grey89`` :grey89:`████████` +``grey90`` :grey90:`████████` +``grey91`` :grey91:`████████` +``grey92`` :grey92:`████████` +``grey93`` :grey93:`████████` +``grey94`` :grey94:`████████` +``grey95`` :grey95:`████████` +``grey96`` :grey96:`████████` +``grey97`` :grey97:`████████` +``grey98`` :grey98:`████████` +``grey99`` :grey99:`████████` +``grey100`` :grey100:`████████` +``honeydew`` :honeydew:`████████` +``honeydew1`` :honeydew1:`████████` +``honeydew2`` :honeydew2:`████████` +``honeydew3`` :honeydew3:`████████` +``honeydew4`` :honeydew4:`████████` +``hotpink`` :hotpink:`████████` +``hotpink1`` :hotpink1:`████████` +``hotpink2`` :hotpink2:`████████` +``hotpink3`` :hotpink3:`████████` +``hotpink4`` :hotpink4:`████████` +``indianred`` :indianred:`████████` +``indianred1`` :indianred1:`████████` +``indianred2`` :indianred2:`████████` +``indianred3`` :indianred3:`████████` +``indianred4`` :indianred4:`████████` +``indigo`` :indigo:`████████` +``ivory`` :ivory:`████████` +``ivory1`` :ivory1:`████████` +``ivory2`` :ivory2:`████████` +``ivory3`` :ivory3:`████████` +``ivory4`` :ivory4:`████████` +``khaki`` :khaki:`████████` +``khaki1`` :khaki1:`████████` +``khaki2`` :khaki2:`████████` +``khaki3`` :khaki3:`████████` +``khaki4`` :khaki4:`████████` +``lavender`` :lavender:`████████` +``lavenderblush`` :lavenderblush:`████████` +``lavenderblush1`` :lavenderblush1:`████████` +``lavenderblush2`` :lavenderblush2:`████████` +``lavenderblush3`` :lavenderblush3:`████████` +``lavenderblush4`` :lavenderblush4:`████████` +``lawngreen`` :lawngreen:`████████` +``lemonchiffon`` :lemonchiffon:`████████` +``lemonchiffon1`` :lemonchiffon1:`████████` +``lemonchiffon2`` :lemonchiffon2:`████████` +``lemonchiffon3`` :lemonchiffon3:`████████` +``lemonchiffon4`` :lemonchiffon4:`████████` +``lightblue`` :lightblue:`████████` +``lightblue1`` :lightblue1:`████████` +``lightblue2`` :lightblue2:`████████` +``lightblue3`` :lightblue3:`████████` +``lightblue4`` :lightblue4:`████████` +``lightcoral`` :lightcoral:`████████` +``lightcyan`` :lightcyan:`████████` +``lightcyan1`` :lightcyan1:`████████` +``lightcyan2`` :lightcyan2:`████████` +``lightcyan3`` :lightcyan3:`████████` +``lightcyan4`` :lightcyan4:`████████` +``lightgoldenrod`` :lightgoldenrod:`████████` +``lightgoldenrod1`` :lightgoldenrod1:`████████` +``lightgoldenrod2`` :lightgoldenrod2:`████████` +``lightgoldenrod3`` :lightgoldenrod3:`████████` +``lightgoldenrod4`` :lightgoldenrod4:`████████` +``lightgoldenrodyellow`` :lightgoldenrodyellow:`████████` +``lightgray`` :lightgray:`████████` +``lightgreen`` :lightgreen:`████████` +``lightgrey`` :lightgrey:`████████` +``lightpink`` :lightpink:`████████` +``lightpink1`` :lightpink1:`████████` +``lightpink2`` :lightpink2:`████████` +``lightpink3`` :lightpink3:`████████` +``lightpink4`` :lightpink4:`████████` +``lightsalmon`` :lightsalmon:`████████` +``lightsalmon1`` :lightsalmon1:`████████` +``lightsalmon2`` :lightsalmon2:`████████` +``lightsalmon3`` :lightsalmon3:`████████` +``lightsalmon4`` :lightsalmon4:`████████` +``lightseagreen`` :lightseagreen:`████████` +``lightskyblue`` :lightskyblue:`████████` +``lightskyblue1`` :lightskyblue1:`████████` +``lightskyblue2`` :lightskyblue2:`████████` +``lightskyblue3`` :lightskyblue3:`████████` +``lightskyblue4`` :lightskyblue4:`████████` +``lightslateblue`` :lightslateblue:`████████` +``lightslategray`` :lightslategray:`████████` +``lightslategrey`` :lightslategrey:`████████` +``lightsteelblue`` :lightsteelblue:`████████` +``lightsteelblue1`` :lightsteelblue1:`████████` +``lightsteelblue2`` :lightsteelblue2:`████████` +``lightsteelblue3`` :lightsteelblue3:`████████` +``lightsteelblue4`` :lightsteelblue4:`████████` +``lightyellow`` :lightyellow:`████████` +``lightyellow1`` :lightyellow1:`████████` +``lightyellow2`` :lightyellow2:`████████` +``lightyellow3`` :lightyellow3:`████████` +``lightyellow4`` :lightyellow4:`████████` +``lime`` :lime:`████████` +``limegreen`` :limegreen:`████████` +``linen`` :linen:`████████` +``magenta`` :magenta:`████████` +``magenta1`` :magenta1:`████████` +``magenta2`` :magenta2:`████████` +``magenta3`` :magenta3:`████████` +``magenta4`` :magenta4:`████████` +``maroon`` :maroon:`████████` +``maroon1`` :maroon1:`████████` +``maroon2`` :maroon2:`████████` +``maroon3`` :maroon3:`████████` +``maroon4`` :maroon4:`████████` +``mediumaquamarine`` :mediumaquamarine:`████████` +``mediumblue`` :mediumblue:`████████` +``mediumorchid`` :mediumorchid:`████████` +``mediumorchid1`` :mediumorchid1:`████████` +``mediumorchid2`` :mediumorchid2:`████████` +``mediumorchid3`` :mediumorchid3:`████████` +``mediumorchid4`` :mediumorchid4:`████████` +``mediumpurple`` :mediumpurple:`████████` +``mediumpurple1`` :mediumpurple1:`████████` +``mediumpurple2`` :mediumpurple2:`████████` +``mediumpurple3`` :mediumpurple3:`████████` +``mediumpurple4`` :mediumpurple4:`████████` +``mediumseagreen`` :mediumseagreen:`████████` +``mediumslateblue`` :mediumslateblue:`████████` +``mediumspringgreen`` :mediumspringgreen:`████████` +``mediumturquoise`` :mediumturquoise:`████████` +``mediumvioletred`` :mediumvioletred:`████████` +``midnightblue`` :midnightblue:`████████` +``mintcream`` :mintcream:`████████` +``mistyrose`` :mistyrose:`████████` +``mistyrose1`` :mistyrose1:`████████` +``mistyrose2`` :mistyrose2:`████████` +``mistyrose3`` :mistyrose3:`████████` +``mistyrose4`` :mistyrose4:`████████` +``moccasin`` :moccasin:`████████` +``navajowhite`` :navajowhite:`████████` +``navajowhite1`` :navajowhite1:`████████` +``navajowhite2`` :navajowhite2:`████████` +``navajowhite3`` :navajowhite3:`████████` +``navajowhite4`` :navajowhite4:`████████` +``navy`` :navy:`████████` +``navyblue`` :navyblue:`████████` +``oldlace`` :oldlace:`████████` +``olive`` :olive:`████████` +``olivedrab`` :olivedrab:`████████` +``olivedrab1`` :olivedrab1:`████████` +``olivedrab2`` :olivedrab2:`████████` +``olivedrab3`` :olivedrab3:`████████` +``olivedrab4`` :olivedrab4:`████████` +``orange`` :orange:`████████` +``orange1`` :orange1:`████████` +``orange2`` :orange2:`████████` +``orange3`` :orange3:`████████` +``orange4`` :orange4:`████████` +``orangered`` :orangered:`████████` +``orangered1`` :orangered1:`████████` +``orangered2`` :orangered2:`████████` +``orangered3`` :orangered3:`████████` +``orangered4`` :orangered4:`████████` +``orchid`` :orchid:`████████` +``orchid1`` :orchid1:`████████` +``orchid2`` :orchid2:`████████` +``orchid3`` :orchid3:`████████` +``orchid4`` :orchid4:`████████` +``palegoldenrod`` :palegoldenrod:`████████` +``palegreen`` :palegreen:`████████` +``palegreen1`` :palegreen1:`████████` +``palegreen2`` :palegreen2:`████████` +``palegreen3`` :palegreen3:`████████` +``palegreen4`` :palegreen4:`████████` +``paleturquoise`` :paleturquoise:`████████` +``paleturquoise1`` :paleturquoise1:`████████` +``paleturquoise2`` :paleturquoise2:`████████` +``paleturquoise3`` :paleturquoise3:`████████` +``paleturquoise4`` :paleturquoise4:`████████` +``palevioletred`` :palevioletred:`████████` +``palevioletred1`` :palevioletred1:`████████` +``palevioletred2`` :palevioletred2:`████████` +``palevioletred3`` :palevioletred3:`████████` +``palevioletred4`` :palevioletred4:`████████` +``papayawhip`` :papayawhip:`████████` +``peachpuff`` :peachpuff:`████████` +``peachpuff1`` :peachpuff1:`████████` +``peachpuff2`` :peachpuff2:`████████` +``peachpuff3`` :peachpuff3:`████████` +``peachpuff4`` :peachpuff4:`████████` +``peru`` :peru:`████████` +``pink`` :pink:`████████` +``pink1`` :pink1:`████████` +``pink2`` :pink2:`████████` +``pink3`` :pink3:`████████` +``pink4`` :pink4:`████████` +``plum`` :plum:`████████` +``plum1`` :plum1:`████████` +``plum2`` :plum2:`████████` +``plum3`` :plum3:`████████` +``plum4`` :plum4:`████████` +``powderblue`` :powderblue:`████████` +``purple`` :purple:`████████` +``purple1`` :purple1:`████████` +``purple2`` :purple2:`████████` +``purple3`` :purple3:`████████` +``purple4`` :purple4:`████████` +``red`` :red:`████████` +``red1`` :red1:`████████` +``red2`` :red2:`████████` +``red3`` :red3:`████████` +``red4`` :red4:`████████` +``rosybrown`` :rosybrown:`████████` +``rosybrown1`` :rosybrown1:`████████` +``rosybrown2`` :rosybrown2:`████████` +``rosybrown3`` :rosybrown3:`████████` +``rosybrown4`` :rosybrown4:`████████` +``royalblue`` :royalblue:`████████` +``royalblue1`` :royalblue1:`████████` +``royalblue2`` :royalblue2:`████████` +``royalblue3`` :royalblue3:`████████` +``royalblue4`` :royalblue4:`████████` +``saddlebrown`` :saddlebrown:`████████` +``salmon`` :salmon:`████████` +``salmon1`` :salmon1:`████████` +``salmon2`` :salmon2:`████████` +``salmon3`` :salmon3:`████████` +``salmon4`` :salmon4:`████████` +``sandybrown`` :sandybrown:`████████` +``seagreen`` :seagreen:`████████` +``seagreen1`` :seagreen1:`████████` +``seagreen2`` :seagreen2:`████████` +``seagreen3`` :seagreen3:`████████` +``seagreen4`` :seagreen4:`████████` +``seashell`` :seashell:`████████` +``seashell1`` :seashell1:`████████` +``seashell2`` :seashell2:`████████` +``seashell3`` :seashell3:`████████` +``seashell4`` :seashell4:`████████` +``sienna`` :sienna:`████████` +``sienna1`` :sienna1:`████████` +``sienna2`` :sienna2:`████████` +``sienna3`` :sienna3:`████████` +``sienna4`` :sienna4:`████████` +``silver`` :silver:`████████` +``skyblue`` :skyblue:`████████` +``skyblue1`` :skyblue1:`████████` +``skyblue2`` :skyblue2:`████████` +``skyblue3`` :skyblue3:`████████` +``skyblue4`` :skyblue4:`████████` +``slateblue`` :slateblue:`████████` +``slateblue1`` :slateblue1:`████████` +``slateblue2`` :slateblue2:`████████` +``slateblue3`` :slateblue3:`████████` +``slateblue4`` :slateblue4:`████████` +``slategray`` :slategray:`████████` +``slategray1`` :slategray1:`████████` +``slategray2`` :slategray2:`████████` +``slategray3`` :slategray3:`████████` +``slategray4`` :slategray4:`████████` +``slategrey`` :slategrey:`████████` +``snow`` :snow:`████████` +``snow1`` :snow1:`████████` +``snow2`` :snow2:`████████` +``snow3`` :snow3:`████████` +``snow4`` :snow4:`████████` +``springgreen`` :springgreen:`████████` +``springgreen1`` :springgreen1:`████████` +``springgreen2`` :springgreen2:`████████` +``springgreen3`` :springgreen3:`████████` +``springgreen4`` :springgreen4:`████████` +``steelblue`` :steelblue:`████████` +``steelblue1`` :steelblue1:`████████` +``steelblue2`` :steelblue2:`████████` +``steelblue3`` :steelblue3:`████████` +``steelblue4`` :steelblue4:`████████` +``tan`` :tan:`████████` +``tan1`` :tan1:`████████` +``tan2`` :tan2:`████████` +``tan3`` :tan3:`████████` +``tan4`` :tan4:`████████` +``teal`` :teal:`████████` +``thistle`` :thistle:`████████` +``thistle1`` :thistle1:`████████` +``thistle2`` :thistle2:`████████` +``thistle3`` :thistle3:`████████` +``thistle4`` :thistle4:`████████` +``tomato`` :tomato:`████████` +``tomato1`` :tomato1:`████████` +``tomato2`` :tomato2:`████████` +``tomato3`` :tomato3:`████████` +``tomato4`` :tomato4:`████████` +``turquoise`` :turquoise:`████████` +``turquoise1`` :turquoise1:`████████` +``turquoise2`` :turquoise2:`████████` +``turquoise3`` :turquoise3:`████████` +``turquoise4`` :turquoise4:`████████` +``violet`` :violet:`████████` +``violetred`` :violetred:`████████` +``violetred1`` :violetred1:`████████` +``violetred2`` :violetred2:`████████` +``violetred3`` :violetred3:`████████` +``violetred4`` :violetred4:`████████` +``wheat`` :wheat:`████████` +``wheat1`` :wheat1:`████████` +``wheat2`` :wheat2:`████████` +``wheat3`` :wheat3:`████████` +``wheat4`` :wheat4:`████████` +``white`` :white:`████████` +``whitesmoke`` :whitesmoke:`████████` +``yellow`` :yellow:`████████` +``yellow1`` :yellow1:`████████` +``yellow2`` :yellow2:`████████` +``yellow3`` :yellow3:`████████` +``yellow4`` :yellow4:`████████` +``yellowgreen`` :yellowgreen:`████████` +========================== ====================================================================================================== diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/cursors.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/cursors.rst.txt new file mode 100644 index 0000000..b0dc73e --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/cursors.rst.txt @@ -0,0 +1,250 @@ +.. include:: common.txt + +:mod:`pygame.cursors` +===================== + +.. module:: pygame.cursors + :synopsis: pygame module for cursor resources + +| :sl:`pygame module for cursor resources` + +Pygame offers control over the system hardware cursor. Pygame supports +black and white cursors (bitmap cursors), as well as system variant cursors and color cursors. +You control the cursor with functions inside :mod:`pygame.mouse`. + +This cursors module contains functions for loading and decoding various +cursor formats. These allow you to easily store your cursors in external files +or directly as encoded python strings. + +The module includes several standard cursors. The :func:`pygame.mouse.set_cursor()` +function takes several arguments. All those arguments have been stored in a +single tuple you can call like this: + +:: + + >>> pygame.mouse.set_cursor(*pygame.cursors.arrow) + +The following variables can be passed to ``pygame.mouse.set_cursor`` function: + + * ``pygame.cursors.arrow`` + + * ``pygame.cursors.diamond`` + + * ``pygame.cursors.broken_x`` + + * ``pygame.cursors.tri_left`` + + * ``pygame.cursors.tri_right`` + +This module also contains a few cursors as formatted strings. You'll need to +pass these to ``pygame.cursors.compile()`` function before you can use them. +The example call would look like this: + +:: + + >>> cursor = pygame.cursors.compile(pygame.cursors.textmarker_strings) + >>> pygame.mouse.set_cursor((8, 16), (0, 0), *cursor) + +The following strings can be converted into cursor bitmaps with +``pygame.cursors.compile()`` : + + * ``pygame.cursors.thickarrow_strings`` + + * ``pygame.cursors.sizer_x_strings`` + + * ``pygame.cursors.sizer_y_strings`` + + * ``pygame.cursors.sizer_xy_strings`` + + * ``pygame.cursor.textmarker_strings`` + +.. function:: compile + + | :sl:`create binary cursor data from simple strings` + | :sg:`compile(strings, black='X', white='.', xor='o') -> data, mask` + + A sequence of strings can be used to create binary cursor data for the + system cursor. This returns the binary data in the form of two tuples. + Those can be passed as the third and fourth arguments respectively of the + :func:`pygame.mouse.set_cursor()` function. + + If you are creating your own cursor strings, you can use any value represent + the black and white pixels. Some system allow you to set a special toggle + color for the system color, this is also called the xor color. If the system + does not support xor cursors, that color will simply be black. + + The height must be divisible by 8. The width of the strings must all be equal + and be divisible by 8. If these two conditions are not met, ``ValueError`` is + raised. + An example set of cursor strings looks like this + + :: + + thickarrow_strings = ( #sized 24x24 + "XX ", + "XXX ", + "XXXX ", + "XX.XX ", + "XX..XX ", + "XX...XX ", + "XX....XX ", + "XX.....XX ", + "XX......XX ", + "XX.......XX ", + "XX........XX ", + "XX........XXX ", + "XX......XXXXX ", + "XX.XXX..XX ", + "XXXX XX..XX ", + "XX XX..XX ", + " XX..XX ", + " XX..XX ", + " XX..XX ", + " XXXX ", + " XX ", + " ", + " ", + " ") + + .. ## pygame.cursors.compile ## + +.. function:: load_xbm + + | :sl:`load cursor data from an XBM file` + | :sg:`load_xbm(cursorfile) -> cursor_args` + | :sg:`load_xbm(cursorfile, maskfile) -> cursor_args` + + This loads cursors for a simple subset of ``XBM`` files. ``XBM`` files are + traditionally used to store cursors on UNIX systems, they are an ASCII + format used to represent simple images. + + Sometimes the black and white color values will be split into two separate + ``XBM`` files. You can pass a second maskfile argument to load the two + images into a single cursor. + + The cursorfile and maskfile arguments can either be filenames or file-like + object with the readlines method. + + The return value cursor_args can be passed directly to the + ``pygame.mouse.set_cursor()`` function. + + .. ## pygame.cursors.load_xbm ## + + + +.. class:: Cursor + + | :sl:`pygame object representing a cursor` + | :sg:`Cursor(size, hotspot, xormasks, andmasks) -> Cursor` + | :sg:`Cursor(hotspot, surface) -> Cursor` + | :sg:`Cursor(constant) -> Cursor` + | :sg:`Cursor(Cursor) -> Cursor` + | :sg:`Cursor() -> Cursor` + + In pygame 2, there are 3 types of cursors you can create to give your + game that little bit of extra polish. There's **bitmap** type cursors, + which existed in pygame 1.x, and are compiled from a string or load from an xbm file. + Then there are **system** type cursors, where you choose a preset that will + convey the same meaning but look native across different operating systems. + Finally you can create a **color** cursor, which displays a pygame surface as the cursor. + + **Creating a system cursor** + + Choose a constant from this list, pass it into ``pygame.cursors.Cursor(constant)``, + and you're good to go. Be advised that not all systems support every system + cursor, and you may get a substitution instead. For example, on MacOS, + WAIT/WAITARROW should show up as an arrow, and SIZENWSE/SIZENESW/SIZEALL + should show up as a closed hand. And on Wayland, every SIZE cursor should + show up as a hand. + + :: + + Pygame Cursor Constant Description + -------------------------------------------- + pygame.SYSTEM_CURSOR_ARROW arrow + pygame.SYSTEM_CURSOR_IBEAM i-beam + pygame.SYSTEM_CURSOR_WAIT wait + pygame.SYSTEM_CURSOR_CROSSHAIR crosshair + pygame.SYSTEM_CURSOR_WAITARROW small wait cursor + (or wait if not available) + pygame.SYSTEM_CURSOR_SIZENWSE double arrow pointing + northwest and southeast + pygame.SYSTEM_CURSOR_SIZENESW double arrow pointing + northeast and southwest + pygame.SYSTEM_CURSOR_SIZEWE double arrow pointing + west and east + pygame.SYSTEM_CURSOR_SIZENS double arrow pointing + north and south + pygame.SYSTEM_CURSOR_SIZEALL four pointed arrow pointing + north, south, east, and west + pygame.SYSTEM_CURSOR_NO slashed circle or crossbones + pygame.SYSTEM_CURSOR_HAND hand + + **Creating a cursor without passing arguments** + + In addition to the cursor constants available and described above, + you can also call ``pygame.cursors.Cursor()``, and your cursor is ready (doing that is the same as + calling ``pygame.cursors.Cursor(pygame.SYSTEM_CURSOR_ARROW)``. + Doing one of those calls actually creates a system cursor using the default native image. + + **Creating a color cursor** + + To create a color cursor, create a ``Cursor`` from a ``hotspot`` and a ``surface``. + ``hotspot`` is an (x,y) coordinate that determines where in the cursor the exact point is. + The hotspot position must be within the bounds of the ``surface``. + + **Creating a bitmap cursor** + + When the mouse cursor is visible, it will be displayed as a black and white + bitmap using the given bitmask arrays. The ``size`` is a sequence containing + the cursor width and height. ``hotspot`` is a sequence containing the cursor + hotspot position. + + A cursor has a width and height, but a mouse position is represented by a + set of point coordinates. So the value passed into the cursor ``hotspot`` + variable helps pygame to actually determine at what exact point the cursor + is at. + + ``xormasks`` is a sequence of bytes containing the cursor xor data masks. + Lastly ``andmasks``, a sequence of bytes containing the cursor bitmask data. + To create these variables, we can make use of the + :func:`pygame.cursors.compile()` function. + + Width and height must be a multiple of 8, and the mask arrays must be the + correct size for the given width and height. Otherwise an exception is raised. + + .. method:: copy + | :sl:`copy the current cursor` + | :sg:`copy() -> Cursor` + + Returns a new Cursor object with the same data and hotspot as the original. + .. ## pygame.cursors.Cursor.copy ## + + + .. attribute:: type + + | :sl:`Gets the cursor type` + | :sg:`type -> string` + + The type will be ``"system"``, ``"bitmap"``, or ``"color"``. + + .. ## pygame.cursors.Cursor.type ## + + .. attribute:: data + + | :sl:`Gets the cursor data` + | :sg:`data -> tuple` + + Returns the data that was used to create this cursor object, wrapped up in a tuple. + + .. ## pygame.cursors.Cursor.data ## + + .. versionadded:: 2.0.1 + + .. ## pygame.cursors.Cursor ## + +.. ## pygame.cursors ## + +Example code for creating and settings cursors. (Click the mouse to switch cursor) + +.. literalinclude:: code_examples/cursors_module_example.py diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/display.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/display.rst.txt new file mode 100644 index 0000000..95a7ed6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/display.rst.txt @@ -0,0 +1,716 @@ +.. include:: common.txt + +:mod:`pygame.display` +===================== + +.. module:: pygame.display + :synopsis: pygame module to control the display window and screen + +| :sl:`pygame module to control the display window and screen` + +This module offers control over the pygame display. Pygame has a single display +Surface that is either contained in a window or runs full screen. Once you +create the display you treat it as a regular Surface. Changes are not +immediately visible onscreen; you must choose one of the two flipping functions +to update the actual display. + +The origin of the display, where x = 0 and y = 0, is the top left of the +screen. Both axes increase positively towards the bottom right of the screen. + +The pygame display can actually be initialized in one of several modes. By +default, the display is a basic software driven framebuffer. You can request +special modules like automatic scaling or OpenGL support. These are +controlled by flags passed to ``pygame.display.set_mode()``. + +Pygame can only have a single display active at any time. Creating a new one +with ``pygame.display.set_mode()`` will close the previous display. To detect +the number and size of attached screens, you can use +``pygame.display.get_desktop_sizes`` and then select appropriate window size +and display index to pass to ``pygame.display.set_mode()``. + +For backward compatibility ``pygame.display`` allows precise control over +the pixel format or display resolutions. This used to be necessary with old +grahics cards and CRT screens, but is usually not needed any more. Use the +functions ``pygame.display.mode_ok()``, ``pygame.display.list_modes()``, and +``pygame.display.Info()`` to query detailed information about the display. + +Once the display Surface is created, the functions from this module affect the +single existing display. The Surface becomes invalid if the module is +uninitialized. If a new display mode is set, the existing Surface will +automatically switch to operate on the new display. + +When the display mode is set, several events are placed on the pygame event +queue. ``pygame.QUIT`` is sent when the user has requested the program to +shut down. The window will receive ``pygame.ACTIVEEVENT`` events as the display +gains and loses input focus. If the display is set with the +``pygame.RESIZABLE`` flag, ``pygame.VIDEORESIZE`` events will be sent when the +user adjusts the window dimensions. Hardware displays that draw direct to the +screen will get ``pygame.VIDEOEXPOSE`` events when portions of the window must +be redrawn. + +A new windowevent API was introduced in pygame 2.0.1. Check event module docs +for more information on that + +Some display environments have an option for automatically stretching all +windows. When this option is enabled, this automatic stretching distorts the +appearance of the pygame window. In the pygame examples directory, there is +example code (prevent_display_stretching.py) which shows how to disable this +automatic stretching of the pygame display on Microsoft Windows (Vista or newer +required). + +.. function:: init + + | :sl:`Initialize the display module` + | :sg:`init() -> None` + + Initializes the pygame display module. The display module cannot do anything + until it is initialized. This is usually handled for you automatically when + you call the higher level ``pygame.init()``. + + Pygame will select from one of several internal display backends when it is + initialized. The display mode will be chosen depending on the platform and + permissions of current user. Before the display module is initialized the + environment variable ``SDL_VIDEODRIVER`` can be set to control which backend + is used. The systems with multiple choices are listed here. + + :: + + Windows : windib, directx + Unix : x11, dga, fbcon, directfb, ggi, vgl, svgalib, aalib + + On some platforms it is possible to embed the pygame display into an already + existing window. To do this, the environment variable ``SDL_WINDOWID`` must + be set to a string containing the window id or handle. The environment + variable is checked when the pygame display is initialized. Be aware that + there can be many strange side effects when running in an embedded display. + + It is harmless to call this more than once, repeated calls have no effect. + + .. ## pygame.display.init ## + +.. function:: quit + + | :sl:`Uninitialize the display module` + | :sg:`quit() -> None` + + This will shut down the entire display module. This means any active + displays will be closed. This will also be handled automatically when the + program exits. + + It is harmless to call this more than once, repeated calls have no effect. + + .. ## pygame.display.quit ## + +.. function:: get_init + + | :sl:`Returns True if the display module has been initialized` + | :sg:`get_init() -> bool` + + Returns True if the :mod:`pygame.display` module is currently initialized. + + .. ## pygame.display.get_init ## + +.. function:: set_mode + + | :sl:`Initialize a window or screen for display` + | :sg:`set_mode(size=(0, 0), flags=0, depth=0, display=0, vsync=0) -> Surface` + + This function will create a display Surface. The arguments passed in are + requests for a display type. The actual created display will be the best + possible match supported by the system. + + Note that calling this function implicitly initializes ``pygame.display``, if + it was not initialized before. + + The size argument is a pair of numbers representing the width and + height. The flags argument is a collection of additional options. The depth + argument represents the number of bits to use for color. + + The Surface that gets returned can be drawn to like a regular Surface but + changes will eventually be seen on the monitor. + + If no size is passed or is set to ``(0, 0)`` and pygame uses ``SDL`` + version 1.2.10 or above, the created Surface will have the same size as the + current screen resolution. If only the width or height are set to ``0``, the + Surface will have the same width or height as the screen resolution. Using a + ``SDL`` version prior to 1.2.10 will raise an exception. + + It is usually best to not pass the depth argument. It will default to the + best and fastest color depth for the system. If your game requires a + specific color format you can control the depth with this argument. Pygame + will emulate an unavailable color depth which can be slow. + + When requesting fullscreen display modes, sometimes an exact match for the + requested size cannot be made. In these situations pygame will select + the closest compatible match. The returned surface will still always match + the requested size. + + On high resolution displays(4k, 1080p) and tiny graphics games (640x480) + show up very small so that they are unplayable. SCALED scales up the window + for you. The game thinks it's a 640x480 window, but really it can be bigger. + Mouse events are scaled for you, so your game doesn't need to do it. Note + that SCALED is considered an experimental API and may change in future + releases. + + The flags argument controls which type of display you want. There are + several to choose from, and you can even combine multiple types using the + bitwise or operator, (the pipe "|" character). Here are the display + flags you will want to choose from: + + :: + + pygame.FULLSCREEN create a fullscreen display + pygame.DOUBLEBUF (obsolete in pygame 2) recommended for HWSURFACE or OPENGL + pygame.HWSURFACE (obsolete in pygame 2) hardware accelerated, only in FULLSCREEN + pygame.OPENGL create an OpenGL-renderable display + pygame.RESIZABLE display window should be sizeable + pygame.NOFRAME display window will have no border or controls + pygame.SCALED resolution depends on desktop size and scale graphics + pygame.SHOWN window is opened in visible mode (default) + pygame.HIDDEN window is opened in hidden mode + + + .. versionadded:: 2.0.0 ``SCALED``, ``SHOWN`` and ``HIDDEN`` + + By setting the ``vsync`` parameter to ``1``, it is possible to get a display + with vertical sync, but you are not guaranteed to get one. The request only + works at all for calls to ``set_mode()`` with the ``pygame.OPENGL`` or + ``pygame.SCALED`` flags set, and is still not guaranteed even with one of + those set. What you get depends on the hardware and driver configuration + of the system pygame is running on. Here is an example usage of a call + to ``set_mode()`` that may give you a display with vsync: + + :: + + flags = pygame.OPENGL | pygame.FULLSCREEN + window_surface = pygame.display.set_mode((1920, 1080), flags, vsync=1) + + Vsync behaviour is considered experimental, and may change in future releases. + + .. versionadded:: 2.0.0 ``vsync`` + + Basic example: + + :: + + # Open a window on the screen + screen_width=700 + screen_height=400 + screen=pygame.display.set_mode([screen_width, screen_height]) + + The display index ``0`` means the default display is used. If no display + index argument is provided, the default display can be overridden with an + environment variable. + + + .. versionchanged:: 1.9.5 ``display`` argument added + + .. ## pygame.display.set_mode ## + +.. function:: get_surface + + | :sl:`Get a reference to the currently set display surface` + | :sg:`get_surface() -> Surface` + + Return a reference to the currently set display Surface. If no display mode + has been set this will return None. + + .. ## pygame.display.get_surface ## + +.. function:: flip + + | :sl:`Update the full display Surface to the screen` + | :sg:`flip() -> None` + + This will update the contents of the entire display. If your display mode is + using the flags ``pygame.HWSURFACE`` and ``pygame.DOUBLEBUF`` on pygame 1, + this will wait for a vertical retrace and swap the surfaces. + + When using an ``pygame.OPENGL`` display mode this will perform a gl buffer + swap. + + .. ## pygame.display.flip ## + +.. function:: update + + | :sl:`Update portions of the screen for software displays` + | :sg:`update(rectangle=None) -> None` + | :sg:`update(rectangle_list) -> None` + + This function is like an optimized version of ``pygame.display.flip()`` for + software displays. It allows only a portion of the screen to updated, + instead of the entire area. If no argument is passed it updates the entire + Surface area like ``pygame.display.flip()``. + + Note that calling ``display.update(None)`` means no part of the window is + updated. Whereas ``display.update()`` means the whole window is updated. + + You can pass the function a single rectangle, or a sequence of rectangles. + It is more efficient to pass many rectangles at once than to call update + multiple times with single or a partial list of rectangles. If passing a + sequence of rectangles it is safe to include None values in the list, which + will be skipped. + + This call cannot be used on ``pygame.OPENGL`` displays and will generate an + exception. + + .. ## pygame.display.update ## + +.. function:: get_driver + + | :sl:`Get the name of the pygame display backend` + | :sg:`get_driver() -> name` + + Pygame chooses one of many available display backends when it is + initialized. This returns the internal name used for the display backend. + This can be used to provide limited information about what display + capabilities might be accelerated. See the ``SDL_VIDEODRIVER`` flags in + ``pygame.display.set_mode()`` to see some of the common options. + + .. ## pygame.display.get_driver ## + +.. function:: Info + + | :sl:`Create a video display information object` + | :sg:`Info() -> VideoInfo` + + Creates a simple object containing several attributes to describe the + current graphics environment. If this is called before + ``pygame.display.set_mode()`` some platforms can provide information about + the default display mode. This can also be called after setting the display + mode to verify specific display options were satisfied. The VidInfo object + has several attributes: + + :: + + hw: 1 if the display is hardware accelerated + wm: 1 if windowed display modes can be used + video_mem: The megabytes of video memory on the display. This is 0 if + unknown + bitsize: Number of bits used to store each pixel + bytesize: Number of bytes used to store each pixel + masks: Four values used to pack RGBA values into pixels + shifts: Four values used to pack RGBA values into pixels + losses: Four values used to pack RGBA values into pixels + blit_hw: 1 if hardware Surface blitting is accelerated + blit_hw_CC: 1 if hardware Surface colorkey blitting is accelerated + blit_hw_A: 1 if hardware Surface pixel alpha blitting is accelerated + blit_sw: 1 if software Surface blitting is accelerated + blit_sw_CC: 1 if software Surface colorkey blitting is accelerated + blit_sw_A: 1 if software Surface pixel alpha blitting is accelerated + current_h, current_w: Height and width of the current video mode, or + of the desktop mode if called before the display.set_mode + is called. (current_h, current_w are available since + SDL 1.2.10, and pygame 1.8.0). They are -1 on error, or if + an old SDL is being used. + + .. ## pygame.display.Info ## + +.. function:: get_wm_info + + | :sl:`Get information about the current windowing system` + | :sg:`get_wm_info() -> dict` + + Creates a dictionary filled with string keys. The strings and values are + arbitrarily created by the system. Some systems may have no information and + an empty dictionary will be returned. Most platforms will return a "window" + key with the value set to the system id for the current display. + + .. versionadded:: 1.7.1 + + .. ## pygame.display.get_wm_info ## + +.. function:: get_desktop_sizes + + | :sl:`Get sizes of active desktops` + | :sg:`get_desktop_sizes() -> list` + + This function returns the sizes of the currrently configured + virtual desktops as a list of (x, y) tuples of integers. + + The length of the list is not the same as the number of attached monitors, + as a desktop can be mirrored across multiple monitors. The desktop sizes + do not indicate the maximum monitor resolutions supported by the hardware, + but the desktop size configured in the operating system. + + In order to fit windows into the desktop as it is currently configured, and + to respect the resolution configured by the operating system in fullscreen + mode, this function *should* be used to replace many use cases of + ``pygame.display.list_modes()`` whenever applicable. + + .. versionadded:: 2.0.0 + +.. function:: list_modes + + | :sl:`Get list of available fullscreen modes` + | :sg:`list_modes(depth=0, flags=pygame.FULLSCREEN, display=0) -> list` + + This function returns a list of possible sizes for a specified color + depth. The return value will be an empty list if no display modes are + available with the given arguments. A return value of ``-1`` means that + any requested size should work (this is likely the case for windowed + modes). Mode sizes are sorted from biggest to smallest. + + If depth is ``0``, the current/best color depth for the display is used. + The flags defaults to ``pygame.FULLSCREEN``, but you may need to add + additional flags for specific fullscreen modes. + + The display index ``0`` means the default display is used. + + Since pygame 2.0, ``pygame.display.get_desktop_sizes()`` has taken over + some use cases from ``pygame.display.list_modes()``: + + To find a suitable size for non-fullscreen windows, it is preferable to + use ``pygame.display.get_desktop_sizes()`` to get the size of the *current* + desktop, and to then choose a smaller window size. This way, the window is + guaranteed to fit, even when the monitor is configured to a lower resolution + than the maximum supported by the hardware. + + To avoid changing the physical monitor resolution, it is also preferable to + use ``pygame.display.get_desktop_sizes()`` to determine the fullscreen + resolution. Developers are strongly advised to default to the current + physical monitor resolution unless the user explicitly requests a different + one (e.g. in an options menu or configuration file). + + .. versionchanged:: 1.9.5 ``display`` argument added + + .. ## pygame.display.list_modes ## + +.. function:: mode_ok + + | :sl:`Pick the best color depth for a display mode` + | :sg:`mode_ok(size, flags=0, depth=0, display=0) -> depth` + + This function uses the same arguments as ``pygame.display.set_mode()``. It + is used to determine if a requested display mode is available. It will + return ``0`` if the display mode cannot be set. Otherwise it will return a + pixel depth that best matches the display asked for. + + Usually the depth argument is not passed, but some platforms can support + multiple display depths. If passed it will hint to which depth is a better + match. + + The function will return ``0`` if the passed display flags cannot be set. + + The display index ``0`` means the default display is used. + + .. versionchanged:: 1.9.5 ``display`` argument added + + .. ## pygame.display.mode_ok ## + +.. function:: gl_get_attribute + + | :sl:`Get the value for an OpenGL flag for the current display` + | :sg:`gl_get_attribute(flag) -> value` + + After calling ``pygame.display.set_mode()`` with the ``pygame.OPENGL`` flag, + it is a good idea to check the value of any requested OpenGL attributes. See + ``pygame.display.gl_set_attribute()`` for a list of valid flags. + + .. ## pygame.display.gl_get_attribute ## + +.. function:: gl_set_attribute + + | :sl:`Request an OpenGL display attribute for the display mode` + | :sg:`gl_set_attribute(flag, value) -> None` + + When calling ``pygame.display.set_mode()`` with the ``pygame.OPENGL`` flag, + Pygame automatically handles setting the OpenGL attributes like color and + double-buffering. OpenGL offers several other attributes you may want control + over. Pass one of these attributes as the flag, and its appropriate value. + This must be called before ``pygame.display.set_mode()``. + + Many settings are the requested minimum. Creating a window with an OpenGL context + will fail if OpenGL cannot provide the requested attribute, but it may for example + give you a stencil buffer even if you request none, or it may give you a larger + one than requested. + + The ``OPENGL`` flags are: + + :: + + GL_ALPHA_SIZE, GL_DEPTH_SIZE, GL_STENCIL_SIZE, GL_ACCUM_RED_SIZE, + GL_ACCUM_GREEN_SIZE, GL_ACCUM_BLUE_SIZE, GL_ACCUM_ALPHA_SIZE, + GL_MULTISAMPLEBUFFERS, GL_MULTISAMPLESAMPLES, GL_STEREO + + :const:`GL_MULTISAMPLEBUFFERS` + + Whether to enable multisampling anti-aliasing. + Defaults to 0 (disabled). + + Set ``GL_MULTISAMPLESAMPLES`` to a value + above 0 to control the amount of anti-aliasing. + A typical value is 2 or 3. + + :const:`GL_STENCIL_SIZE` + + Minimum bit size of the stencil buffer. Defaults to 0. + + :const:`GL_DEPTH_SIZE` + + Minimum bit size of the depth buffer. Defaults to 16. + + :const:`GL_STEREO` + + 1 enables stereo 3D. Defaults to 0. + + :const:`GL_BUFFER_SIZE` + + Minimum bit size of the frame buffer. Defaults to 0. + + .. versionadded:: 2.0.0 Additional attributes: + + :: + + GL_ACCELERATED_VISUAL, + GL_CONTEXT_MAJOR_VERSION, GL_CONTEXT_MINOR_VERSION, + GL_CONTEXT_FLAGS, GL_CONTEXT_PROFILE_MASK, + GL_SHARE_WITH_CURRENT_CONTEXT, + GL_CONTEXT_RELEASE_BEHAVIOR, + GL_FRAMEBUFFER_SRGB_CAPABLE + + :const:`GL_CONTEXT_PROFILE_MASK` + + Sets the OpenGL profile to one of these values: + + :: + + GL_CONTEXT_PROFILE_CORE disable deprecated features + GL_CONTEXT_PROFILE_COMPATIBILITY allow deprecated features + GL_CONTEXT_PROFILE_ES allow only the ES feature + subset of OpenGL + + :const:`GL_ACCELERATED_VISUAL` + + Set to 1 to require hardware acceleration, or 0 to force software render. + By default, both are allowed. + + .. ## pygame.display.gl_set_attribute ## + +.. function:: get_active + + | :sl:`Returns True when the display is active on the screen` + | :sg:`get_active() -> bool` + + Returns True when the display Surface is considered actively + renderable on the screen and may be visible to the user. This is + the default state immediately after ``pygame.display.set_mode()``. + This method may return True even if the application is fully hidden + behind another application window. + + This will return False if the display Surface has been iconified or + minimized (either via ``pygame.display.iconify()`` or via an OS + specific method such as the minimize-icon available on most + desktops). + + The method can also return False for other reasons without the + application being explicitly iconified or minimized by the user. A + notable example being if the user has multiple virtual desktops and + the display Surface is not on the active virtual desktop. + + .. note:: This function returning True is unrelated to whether the + application has input focus. Please see + ``pygame.key.get_focused()`` and ``pygame.mouse.get_focused()`` + for APIs related to input focus. + + .. ## pygame.display.get_active ## + +.. function:: iconify + + | :sl:`Iconify the display surface` + | :sg:`iconify() -> bool` + + Request the window for the display surface be iconified or hidden. Not all + systems and displays support an iconified display. The function will return + True if successful. + + When the display is iconified ``pygame.display.get_active()`` will return + ``False``. The event queue should receive an ``ACTIVEEVENT`` event when the + window has been iconified. Additionally, the event queue also recieves a + ``WINDOWEVENT_MINIMIZED`` event when the window has been iconified on pygame 2. + + .. ## pygame.display.iconify ## + +.. function:: toggle_fullscreen + + | :sl:`Switch between fullscreen and windowed displays` + | :sg:`toggle_fullscreen() -> int` + + Switches the display window between windowed and fullscreen modes. + Display driver support is not great when using pygame 1, but with + pygame 2 it is the most reliable method to switch to and from fullscreen. + + Supported display drivers in pygame 1: + + * x11 (Linux/Unix) + * wayland (Linux/Unix) + + Supported display drivers in pygame 2: + + * windows (Windows) + * x11 (Linux/Unix) + * wayland (Linux/Unix) + * cocoa (OSX/Mac) + + .. Note:: :func:`toggle_fullscreen` doesn't work on Windows + unless the window size is in :func:`pygame.display.list_modes()` or + the window is created with the flag ``pygame.SCALED``. + See `issue #2380 `_. + + .. ## pygame.display.toggle_fullscreen ## + +.. function:: set_gamma + + | :sl:`Change the hardware gamma ramps` + | :sg:`set_gamma(red, green=None, blue=None) -> bool` + + Set the red, green, and blue gamma values on the display hardware. If the + green and blue arguments are not passed, they will both be the same as red. + Not all systems and hardware support gamma ramps, if the function succeeds + it will return ``True``. + + A gamma value of ``1.0`` creates a linear color table. Lower values will + darken the display and higher values will brighten. + + .. ## pygame.display.set_gamma ## + +.. function:: set_gamma_ramp + + | :sl:`Change the hardware gamma ramps with a custom lookup` + | :sg:`set_gamma_ramp(red, green, blue) -> bool` + + Set the red, green, and blue gamma ramps with an explicit lookup table. Each + argument should be sequence of 256 integers. The integers should range + between ``0`` and ``0xffff``. Not all systems and hardware support gamma + ramps, if the function succeeds it will return ``True``. + + .. ## pygame.display.set_gamma_ramp ## + +.. function:: set_icon + + | :sl:`Change the system image for the display window` + | :sg:`set_icon(Surface) -> None` + + Sets the runtime icon the system will use to represent the display window. + All windows default to a simple pygame logo for the window icon. + + Note that calling this function implicitly initializes ``pygame.display``, if + it was not initialized before. + + You can pass any surface, but most systems want a smaller image around + 32x32. The image can have colorkey transparency which will be passed to the + system. + + Some systems do not allow the window icon to change after it has been shown. + This function can be called before ``pygame.display.set_mode()`` to create + the icon before the display mode is set. + + .. ## pygame.display.set_icon ## + +.. function:: set_caption + + | :sl:`Set the current window caption` + | :sg:`set_caption(title, icontitle=None) -> None` + + If the display has a window title, this function will change the name on the + window. In pygame 1.x, some systems supported an alternate shorter title to + be used for minimized displays, but in pygame 2 ``icontitle`` does nothing. + + .. ## pygame.display.set_caption ## + +.. function:: get_caption + + | :sl:`Get the current window caption` + | :sg:`get_caption() -> (title, icontitle)` + + Returns the title and icontitle for the display window. In pygame 2.x + these will always be the same value. + + .. ## pygame.display.get_caption ## + +.. function:: set_palette + + | :sl:`Set the display color palette for indexed displays` + | :sg:`set_palette(palette=None) -> None` + + This will change the video display color palette for 8-bit displays. This + does not change the palette for the actual display Surface, only the palette + that is used to display the Surface. If no palette argument is passed, the + system default palette will be restored. The palette is a sequence of + ``RGB`` triplets. + + .. ## pygame.display.set_palette ## + +.. function:: get_num_displays + + | :sl:`Return the number of displays` + | :sg:`get_num_displays() -> int` + + Returns the number of available displays. This is always 1 if + :func:`pygame.get_sdl_version()` returns a major version number below 2. + + .. versionadded:: 1.9.5 + + .. ## pygame.display.get_num_displays ## + +.. function:: get_window_size + + | :sl:`Return the size of the window or screen` + | :sg:`get_window_size() -> tuple` + + Returns the size of the window initialized with :func:`pygame.display.set_mode()`. + This may differ from the size of the display surface if ``SCALED`` is used. + + .. versionadded:: 2.0.0 + + .. ## pygame.display.get_window_size ## + +.. function:: get_allow_screensaver + + | :sl:`Return whether the screensaver is allowed to run.` + | :sg:`get_allow_screensaver() -> bool` + + Return whether screensaver is allowed to run whilst the app is running. + Default is ``False``. + By default pygame does not allow the screensaver during game play. + + .. note:: Some platforms do not have a screensaver or support + disabling the screensaver. Please see + :func:`pygame.display.set_allow_screensaver()` for + caveats with screensaver support. + + .. versionadded:: 2.0.0 + + .. ## pygame.display.get_allow_screensaver ## + +.. function:: set_allow_screensaver + + | :sl:`Set whether the screensaver may run` + | :sg:`set_allow_screensaver(bool) -> None` + + Change whether screensavers should be allowed whilst the app is running. + The default value of the argument to the function is True. + By default pygame does not allow the screensaver during game play. + + If the screensaver has been disallowed due to this function, it will automatically + be allowed to run when :func:`pygame.quit()` is called. + + It is possible to influence the default value via the environment variable + ``SDL_HINT_VIDEO_ALLOW_SCREENSAVER``, which can be set to either ``0`` (disable) + or ``1`` (enable). + + .. note:: Disabling screensaver is subject to platform support. + When platform support is absent, this function will + silently appear to work even though the screensaver state + is unchanged. The lack of feedback is due to SDL not + providing any supported method for determining whether + it supports changing the screensaver state. + ``SDL_HINT_VIDEO_ALLOW_SCREENSAVER`` is available in SDL 2.0.2 or later. + SDL1.2 does not implement this. + + .. versionadded:: 2.0.0 + + + .. ## pygame.display.set_allow_screensaver ## + +.. ## pygame.display ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/draw.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/draw.rst.txt new file mode 100644 index 0000000..c82d021 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/draw.rst.txt @@ -0,0 +1,559 @@ +.. include:: common.txt + +:mod:`pygame.draw` +================== + +.. module:: pygame.draw + :synopsis: pygame module for drawing shapes + +| :sl:`pygame module for drawing shapes` + +Draw several simple shapes to a surface. These functions will work for +rendering to any format of surface. Rendering to hardware surfaces will be +slower than regular software surfaces. + +Most of the functions take a width argument to represent the size of stroke +(thickness) around the edge of the shape. If a width of 0 is passed the shape +will be filled (solid). + +All the drawing functions respect the clip area for the surface and will be +constrained to that area. The functions return a rectangle representing the +bounding area of changed pixels. This bounding rectangle is the 'minimum' +bounding box that encloses the affected area. + +All the drawing functions accept a color argument that can be one of the +following formats: + + - a :mod:`pygame.Color` object + - an ``(RGB)`` triplet (tuple/list) + - an ``(RGBA)`` quadruplet (tuple/list) + - an integer value that has been mapped to the surface's pixel format + (see :func:`pygame.Surface.map_rgb` and :func:`pygame.Surface.unmap_rgb`) + +A color's alpha value will be written directly into the surface (if the +surface contains pixel alphas), but the draw function will not draw +transparently. + +These functions temporarily lock the surface they are operating on. Many +sequential drawing calls can be sped up by locking and unlocking the surface +object around the draw calls (see :func:`pygame.Surface.lock` and +:func:`pygame.Surface.unlock`). + +.. note :: + See the :mod:`pygame.gfxdraw` module for alternative draw methods. + + +.. function:: rect + + | :sl:`draw a rectangle` + | :sg:`rect(surface, color, rect) -> Rect` + | :sg:`rect(surface, color, rect, width=0, border_radius=0, border_top_left_radius=-1, border_top_right_radius=-1, border_bottom_left_radius=-1, border_bottom_right_radius=-1) -> Rect` + + Draws a rectangle on the given surface. + + :param Surface surface: surface to draw on + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or int or tuple(int, int, int, [int]) + :param Rect rect: rectangle to draw, position and dimensions + :param int width: (optional) used for line thickness or to indicate that + the rectangle is to be filled (not to be confused with the width value + of the ``rect`` parameter) + + | if ``width == 0``, (default) fill the rectangle + | if ``width > 0``, used for line thickness + | if ``width < 0``, nothing will be drawn + | + + .. note:: + When using ``width`` values ``> 1``, the edge lines will grow + outside the original boundary of the rect. For more details on + how the thickness for edge lines grow, refer to the ``width`` notes + of the :func:`pygame.draw.line` function. + :param int border_radius: (optional) used for drawing rectangle with rounded corners. + The supported range is [0, min(height, width) / 2], with 0 representing a rectangle + without rounded corners. + :param int border_top_left_radius: (optional) used for setting the value of top left + border. If you don't set this value, it will use the border_radius value. + :param int border_top_right_radius: (optional) used for setting the value of top right + border. If you don't set this value, it will use the border_radius value. + :param int border_bottom_left_radius: (optional) used for setting the value of bottom left + border. If you don't set this value, it will use the border_radius value. + :param int border_bottom_right_radius: (optional) used for setting the value of bottom right + border. If you don't set this value, it will use the border_radius value. + + | if ``border_radius < 1`` it will draw rectangle without rounded corners + | if any of border radii has the value ``< 0`` it will use value of the border_radius + | If sum of radii on the same side of the rectangle is greater than the rect size the radii + | will get scaled + + :returns: a rect bounding the changed pixels, if nothing is drawn the + bounding rect's position will be the position of the given ``rect`` + parameter and its width and height will be 0 + :rtype: Rect + + .. note:: + The :func:`pygame.Surface.fill()` method works just as well for drawing + filled rectangles and can be hardware accelerated on some platforms with + both software and hardware display modes. + + .. versionchanged:: 2.0.0 Added support for keyword arguments. + .. versionchanged:: 2.0.0.dev8 Added support for border radius. + + .. ## pygame.draw.rect ## + +.. function:: polygon + + | :sl:`draw a polygon` + | :sg:`polygon(surface, color, points) -> Rect` + | :sg:`polygon(surface, color, points, width=0) -> Rect` + + Draws a polygon on the given surface. + + :param Surface surface: surface to draw on + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or int or tuple(int, int, int, [int]) + :param points: a sequence of 3 or more (x, y) coordinates that make up the + vertices of the polygon, each *coordinate* in the sequence must be a + tuple/list/:class:`pygame.math.Vector2` of 2 ints/floats, + e.g. ``[(x1, y1), (x2, y2), (x3, y3)]`` + :type points: tuple(coordinate) or list(coordinate) + :param int width: (optional) used for line thickness or to indicate that + the polygon is to be filled + + | if width == 0, (default) fill the polygon + | if width > 0, used for line thickness + | if width < 0, nothing will be drawn + | + + .. note:: + When using ``width`` values ``> 1``, the edge lines will grow + outside the original boundary of the polygon. For more details on + how the thickness for edge lines grow, refer to the ``width`` notes + of the :func:`pygame.draw.line` function. + + :returns: a rect bounding the changed pixels, if nothing is drawn the + bounding rect's position will be the position of the first point in the + ``points`` parameter (float values will be truncated) and its width and + height will be 0 + :rtype: Rect + + :raises ValueError: if ``len(points) < 3`` (must have at least 3 points) + :raises TypeError: if ``points`` is not a sequence or ``points`` does not + contain number pairs + + .. note:: + For an aapolygon, use :func:`aalines()` with ``closed=True``. + + .. versionchanged:: 2.0.0 Added support for keyword arguments. + + .. ## pygame.draw.polygon ## + +.. function:: circle + + | :sl:`draw a circle` + | :sg:`circle(surface, color, center, radius) -> Rect` + | :sg:`circle(surface, color, center, radius, width=0, draw_top_right=None, draw_top_left=None, draw_bottom_left=None, draw_bottom_right=None) -> Rect` + + Draws a circle on the given surface. + + :param Surface surface: surface to draw on + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or int or tuple(int, int, int, [int]) + :param center: center point of the circle as a sequence of 2 ints/floats, + e.g. ``(x, y)`` + :type center: tuple(int or float, int or float) or + list(int or float, int or float) or Vector2(int or float, int or float) + :param radius: radius of the circle, measured from the ``center`` parameter, + nothing will be drawn if the ``radius`` is less than 1 + :type radius: int or float + :param int width: (optional) used for line thickness or to indicate that + the circle is to be filled + + | if ``width == 0``, (default) fill the circle + | if ``width > 0``, used for line thickness + | if ``width < 0``, nothing will be drawn + | + + .. note:: + When using ``width`` values ``> 1``, the edge lines will only grow + inward. + :param bool draw_top_right: (optional) if this is set to True then the top right corner + of the circle will be drawn + :param bool draw_top_left: (optional) if this is set to True then the top left corner + of the circle will be drawn + :param bool draw_bottom_left: (optional) if this is set to True then the bottom left corner + of the circle will be drawn + :param bool draw_bottom_right: (optional) if this is set to True then the bottom right corner + of the circle will be drawn + + | if any of the draw_circle_part is True then it will draw all circle parts that have the True + | value, otherwise it will draw the entire circle. + + :returns: a rect bounding the changed pixels, if nothing is drawn the + bounding rect's position will be the ``center`` parameter value (float + values will be truncated) and its width and height will be 0 + :rtype: Rect + + :raises TypeError: if ``center`` is not a sequence of two numbers + :raises TypeError: if ``radius`` is not a number + + .. versionchanged:: 2.0.0 Added support for keyword arguments. + Nothing is drawn when the radius is 0 (a pixel at the ``center`` coordinates + used to be drawn when the radius equaled 0). + Floats, and Vector2 are accepted for the ``center`` param. + The drawing algorithm was improved to look more like a circle. + .. versionchanged:: 2.0.0.dev8 Added support for drawing circle quadrants. + + .. ## pygame.draw.circle ## + +.. function:: ellipse + + | :sl:`draw an ellipse` + | :sg:`ellipse(surface, color, rect) -> Rect` + | :sg:`ellipse(surface, color, rect, width=0) -> Rect` + + Draws an ellipse on the given surface. + + :param Surface surface: surface to draw on + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or int or tuple(int, int, int, [int]) + :param Rect rect: rectangle to indicate the position and dimensions of the + ellipse, the ellipse will be centered inside the rectangle and bounded + by it + :param int width: (optional) used for line thickness or to indicate that + the ellipse is to be filled (not to be confused with the width value + of the ``rect`` parameter) + + | if ``width == 0``, (default) fill the ellipse + | if ``width > 0``, used for line thickness + | if ``width < 0``, nothing will be drawn + | + + .. note:: + When using ``width`` values ``> 1``, the edge lines will only grow + inward from the original boundary of the ``rect`` parameter. + + :returns: a rect bounding the changed pixels, if nothing is drawn the + bounding rect's position will be the position of the given ``rect`` + parameter and its width and height will be 0 + :rtype: Rect + + .. versionchanged:: 2.0.0 Added support for keyword arguments. + + .. ## pygame.draw.ellipse ## + +.. function:: arc + + | :sl:`draw an elliptical arc` + | :sg:`arc(surface, color, rect, start_angle, stop_angle) -> Rect` + | :sg:`arc(surface, color, rect, start_angle, stop_angle, width=1) -> Rect` + + Draws an elliptical arc on the given surface. + + The two angle arguments are given in radians and indicate the start and stop + positions of the arc. The arc is drawn in a counterclockwise direction from + the ``start_angle`` to the ``stop_angle``. + + :param Surface surface: surface to draw on + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or int or tuple(int, int, int, [int]) + :param Rect rect: rectangle to indicate the position and dimensions of the + ellipse which the arc will be based on, the ellipse will be centered + inside the rectangle + :param float start_angle: start angle of the arc in radians + :param float stop_angle: stop angle of the arc in + radians + + | if ``start_angle < stop_angle``, the arc is drawn in a + counterclockwise direction from the ``start_angle`` to the + ``stop_angle`` + | if ``start_angle > stop_angle``, tau (tau == 2 * pi) will be added + to the ``stop_angle``, if the resulting stop angle value is greater + than the ``start_angle`` the above ``start_angle < stop_angle`` case + applies, otherwise nothing will be drawn + | if ``start_angle == stop_angle``, nothing will be drawn + | + + :param int width: (optional) used for line thickness (not to be confused + with the width value of the ``rect`` parameter) + + | if ``width == 0``, nothing will be drawn + | if ``width > 0``, (default is 1) used for line thickness + | if ``width < 0``, same as ``width == 0`` + + .. note:: + When using ``width`` values ``> 1``, the edge lines will only grow + inward from the original boundary of the ``rect`` parameter. + + :returns: a rect bounding the changed pixels, if nothing is drawn the + bounding rect's position will be the position of the given ``rect`` + parameter and its width and height will be 0 + :rtype: Rect + + .. versionchanged:: 2.0.0 Added support for keyword arguments. + + .. ## pygame.draw.arc ## + +.. function:: line + + | :sl:`draw a straight line` + | :sg:`line(surface, color, start_pos, end_pos) -> Rect` + | :sg:`line(surface, color, start_pos, end_pos, width=1) -> Rect` + + Draws a straight line on the given surface. There are no endcaps. For thick + lines the ends are squared off. + + :param Surface surface: surface to draw on + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or int or tuple(int, int, int, [int]) + :param start_pos: start position of the line, (x, y) + :type start_pos: tuple(int or float, int or float) or + list(int or float, int or float) or Vector2(int or float, int or float) + :param end_pos: end position of the line, (x, y) + :type end_pos: tuple(int or float, int or float) or + list(int or float, int or float) or Vector2(int or float, int or float) + :param int width: (optional) used for line thickness + + | if width >= 1, used for line thickness (default is 1) + | if width < 1, nothing will be drawn + | + + .. note:: + When using ``width`` values ``> 1``, lines will grow as follows. + + For odd ``width`` values, the thickness of each line grows with the + original line being in the center. + + For even ``width`` values, the thickness of each line grows with the + original line being offset from the center (as there is no exact + center line drawn). As a result, lines with a slope < 1 + (horizontal-ish) will have 1 more pixel of thickness below the + original line (in the y direction). Lines with a slope >= 1 + (vertical-ish) will have 1 more pixel of thickness to the right of + the original line (in the x direction). + + :returns: a rect bounding the changed pixels, if nothing is drawn the + bounding rect's position will be the ``start_pos`` parameter value (float + values will be truncated) and its width and height will be 0 + :rtype: Rect + + :raises TypeError: if ``start_pos`` or ``end_pos`` is not a sequence of + two numbers + + .. versionchanged:: 2.0.0 Added support for keyword arguments. + + .. ## pygame.draw.line ## + +.. function:: lines + + | :sl:`draw multiple contiguous straight line segments` + | :sg:`lines(surface, color, closed, points) -> Rect` + | :sg:`lines(surface, color, closed, points, width=1) -> Rect` + + Draws a sequence of contiguous straight lines on the given surface. There are + no endcaps or miter joints. For thick lines the ends are squared off. + Drawing thick lines with sharp corners can have undesired looking results. + + :param Surface surface: surface to draw on + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or int or tuple(int, int, int, [int]) + :param bool closed: if ``True`` an additional line segment is drawn between + the first and last points in the ``points`` sequence + :param points: a sequence of 2 or more (x, y) coordinates, where each + *coordinate* in the sequence must be a + tuple/list/:class:`pygame.math.Vector2` of 2 ints/floats and adjacent + coordinates will be connected by a line segment, e.g. for the + points ``[(x1, y1), (x2, y2), (x3, y3)]`` a line segment will be drawn + from ``(x1, y1)`` to ``(x2, y2)`` and from ``(x2, y2)`` to ``(x3, y3)``, + additionally if the ``closed`` parameter is ``True`` another line segment + will be drawn from ``(x3, y3)`` to ``(x1, y1)`` + :type points: tuple(coordinate) or list(coordinate) + :param int width: (optional) used for line thickness + + | if width >= 1, used for line thickness (default is 1) + | if width < 1, nothing will be drawn + | + + .. note:: + When using ``width`` values ``> 1`` refer to the ``width`` notes + of :func:`line` for details on how thick lines grow. + + :returns: a rect bounding the changed pixels, if nothing is drawn the + bounding rect's position will be the position of the first point in the + ``points`` parameter (float values will be truncated) and its width and + height will be 0 + :rtype: Rect + + :raises ValueError: if ``len(points) < 2`` (must have at least 2 points) + :raises TypeError: if ``points`` is not a sequence or ``points`` does not + contain number pairs + + .. versionchanged:: 2.0.0 Added support for keyword arguments. + + .. ## pygame.draw.lines ## + +.. function:: aaline + + | :sl:`draw a straight antialiased line` + | :sg:`aaline(surface, color, start_pos, end_pos) -> Rect` + | :sg:`aaline(surface, color, start_pos, end_pos, blend=1) -> Rect` + + Draws a straight antialiased line on the given surface. + + The line has a thickness of one pixel and the endpoints have a height and + width of one pixel each. + + The way a line and its endpoints are drawn: + If both endpoints are equal, only a single pixel is drawn (after + rounding floats to nearest integer). + + Otherwise if the line is not steep (i.e. if the length along the x-axis + is greater than the height along the y-axis): + + For each endpoint: + + If ``x``, the endpoint's x-coordinate, is a whole number find + which pixels would be covered by it and draw them. + + Otherwise: + + Calculate the position of the nearest point with a whole number + for its x-coordinate, when extending the line past the + endpoint. + + Find which pixels would be covered and how much by that point. + + If the endpoint is the left one, multiply the coverage by (1 - + the decimal part of ``x``). + + Otherwise multiply the coverage by the decimal part of ``x``. + + Then draw those pixels. + + *e.g.:* + | The left endpoint of the line ``((1, 1.3), (5, 3))`` would + cover 70% of the pixel ``(1, 1)`` and 30% of the pixel + ``(1, 2)`` while the right one would cover 100% of the + pixel ``(5, 3)``. + | The left endpoint of the line ``((1.2, 1.4), (4.6, 3.1))`` + would cover 56% *(i.e. 0.8 * 70%)* of the pixel ``(1, 1)`` + and 24% *(i.e. 0.8 * 30%)* of the pixel ``(1, 2)`` while + the right one would cover 42% *(i.e. 0.6 * 70%)* of the + pixel ``(5, 3)`` and 18% *(i.e. 0.6 * 30%)* of the pixel + ``(5, 4)`` while the right + + Then for each point between the endpoints, along the line, whose + x-coordinate is a whole number: + + Find which pixels would be covered and how much by that point and + draw them. + + *e.g.:* + | The points along the line ``((1, 1), (4, 2.5))`` would be + ``(2, 1.5)`` and ``(3, 2)`` and would cover 50% of the pixel + ``(2, 1)``, 50% of the pixel ``(2, 2)`` and 100% of the pixel + ``(3, 2)``. + | The points along the line ``((1.2, 1.4), (4.6, 3.1))`` would + be ``(2, 1.8)`` (covering 20% of the pixel ``(2, 1)`` and 80% + of the pixel ``(2, 2)``), ``(3, 2.3)`` (covering 70% of the + pixel ``(3, 2)`` and 30% of the pixel ``(3, 3)``) and ``(4, + 2.8)`` (covering 20% of the pixel ``(2, 1)`` and 80% of the + pixel ``(2, 2)``) + + Otherwise do the same for steep lines as for non-steep lines except + along the y-axis instead of the x-axis (using ``y`` instead of ``x``, + top instead of left and bottom instead of right). + + .. note:: + Regarding float values for coordinates, a point with coordinate + consisting of two whole numbers is considered being right in the center + of said pixel (and having a height and width of 1 pixel would therefore + completely cover it), while a point with coordinate where one (or both) + of the numbers have non-zero decimal parts would be partially covering + two (or four if both numbers have decimal parts) adjacent pixels, *e.g.* + the point ``(1.4, 2)`` covers 60% of the pixel ``(1, 2)`` and 40% of the + pixel ``(2,2)``. + + :param Surface surface: surface to draw on + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or int or tuple(int, int, int, [int]) + :param start_pos: start position of the line, (x, y) + :type start_pos: tuple(int or float, int or float) or + list(int or float, int or float) or Vector2(int or float, int or float) + :param end_pos: end position of the line, (x, y) + :type end_pos: tuple(int or float, int or float) or + list(int or float, int or float) or Vector2(int or float, int or float) + :param int blend: (optional) if non-zero (default) the line will be blended + with the surface's existing pixel shades, otherwise it will overwrite them + + :returns: a rect bounding the changed pixels, if nothing is drawn the + bounding rect's position will be the ``start_pos`` parameter value (float + values will be truncated) and its width and height will be 0 + :rtype: Rect + + :raises TypeError: if ``start_pos`` or ``end_pos`` is not a sequence of + two numbers + + .. versionchanged:: 2.0.0 Added support for keyword arguments. + + .. ## pygame.draw.aaline ## + +.. function:: aalines + + | :sl:`draw multiple contiguous straight antialiased line segments` + | :sg:`aalines(surface, color, closed, points) -> Rect` + | :sg:`aalines(surface, color, closed, points, blend=1) -> Rect` + + Draws a sequence of contiguous straight antialiased lines on the given + surface. + + :param Surface surface: surface to draw on + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or int or tuple(int, int, int, [int]) + :param bool closed: if ``True`` an additional line segment is drawn between + the first and last points in the ``points`` sequence + :param points: a sequence of 2 or more (x, y) coordinates, where each + *coordinate* in the sequence must be a + tuple/list/:class:`pygame.math.Vector2` of 2 ints/floats and adjacent + coordinates will be connected by a line segment, e.g. for the + points ``[(x1, y1), (x2, y2), (x3, y3)]`` a line segment will be drawn + from ``(x1, y1)`` to ``(x2, y2)`` and from ``(x2, y2)`` to ``(x3, y3)``, + additionally if the ``closed`` parameter is ``True`` another line segment + will be drawn from ``(x3, y3)`` to ``(x1, y1)`` + :type points: tuple(coordinate) or list(coordinate) + :param int blend: (optional) if non-zero (default) each line will be blended + with the surface's existing pixel shades, otherwise the pixels will be + overwritten + + :returns: a rect bounding the changed pixels, if nothing is drawn the + bounding rect's position will be the position of the first point in the + ``points`` parameter (float values will be truncated) and its width and + height will be 0 + :rtype: Rect + + :raises ValueError: if ``len(points) < 2`` (must have at least 2 points) + :raises TypeError: if ``points`` is not a sequence or ``points`` does not + contain number pairs + + .. versionchanged:: 2.0.0 Added support for keyword arguments. + + .. ## pygame.draw.aalines ## + +.. ## pygame.draw ## + +.. figure:: code_examples/draw_module_example.png + :alt: draw module example + + Example code for draw module. + +.. literalinclude:: code_examples/draw_module_example.py + diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/event.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/event.rst.txt new file mode 100644 index 0000000..5b4a6d2 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/event.rst.txt @@ -0,0 +1,476 @@ +.. include:: common.txt + +:mod:`pygame.event` +=================== + +.. module:: pygame.event + :synopsis: pygame module for interacting with events and queues + +| :sl:`pygame module for interacting with events and queues` + +Pygame handles all its event messaging through an event queue. The routines in +this module help you manage that event queue. The input queue is heavily +dependent on the :mod:`pygame.display` module. If the display has not been +initialized and a video mode not set, the event queue may not work properly. + +The event queue has an upper limit on the number of events it can hold. When +the queue becomes full new events are quietly dropped. To prevent lost events, +especially input events which signal a quit command, your program must handle +events every frame (with ``pygame.event.get()``, ``pygame.event.pump()``, +``pygame.event.wait()``, ``pygame.event.peek()`` or ``pygame.event.clear()``) +and process them. Not handling events may cause your system to decide your +program has locked up. To speed up queue processing use +:func:`pygame.event.set_blocked()` to limit which events get queued. + +To get the state of various input devices, you can forego the event queue and +access the input devices directly with their appropriate modules: +:mod:`pygame.mouse`, :mod:`pygame.key`, and :mod:`pygame.joystick`. If you use +this method, remember that pygame requires some form of communication with the +system window manager and other parts of the platform. To keep pygame in sync +with the system, you will need to call :func:`pygame.event.pump()` to keep +everything current. Usually, this should be called once per game loop. +Note: Joysticks will not send any events until the device has been initialized. + +The event queue contains :class:`pygame.event.EventType` event objects. +There are a variety of ways to access the queued events, from simply +checking for the existence of events, to grabbing them directly off the stack. +The event queue also offers some simple filtering which can slightly help +performance by blocking certain event types from the queue. Use +:func:`pygame.event.set_allowed()` and :func:`pygame.event.set_blocked()` to +change this filtering. By default, all event types can be placed on the queue. + +All :class:`pygame.event.EventType` instances contain an event type identifier +and attributes specific to that event type. The event type identifier is +accessible as the :attr:`pygame.event.EventType.type` property. Any of the +event specific attributes can be accessed through the +:attr:`pygame.event.EventType.__dict__` attribute or directly as an attribute +of the event object (as member lookups are passed through to the object's +dictionary values). The event object has no method functions. Users can create +their own new events with the :func:`pygame.event.Event()` function. + +The event type identifier is in between the values of ``NOEVENT`` and +``NUMEVENTS``. User defined events should have a value in the inclusive range +of ``USEREVENT`` to ``NUMEVENTS - 1``. User defined events can get a custom +event number with :func:`pygame.event.custom_type()`. +It is recommended all user events follow this system. + +Events support equality and inequality comparisons. Two events are equal if +they are the same type and have identical attribute values. + +While debugging and experimenting, you can print an event object for a quick +display of its type and members. The function :func:`pygame.event.event_name()` +can be used to get a string representing the name of the event type. + +Events that come from the system will have a guaranteed set of member +attributes based on the type. The following is a list event types with their +specific attributes. + +:: + + QUIT none + ACTIVEEVENT gain, state + KEYDOWN key, mod, unicode, scancode + KEYUP key, mod, unicode, scancode + MOUSEMOTION pos, rel, buttons, touch + MOUSEBUTTONUP pos, button, touch + MOUSEBUTTONDOWN pos, button, touch + JOYAXISMOTION joy (deprecated), instance_id, axis, value + JOYBALLMOTION joy (deprecated), instance_id, ball, rel + JOYHATMOTION joy (deprecated), instance_id, hat, value + JOYBUTTONUP joy (deprecated), instance_id, button + JOYBUTTONDOWN joy (deprecated), instance_id, button + VIDEORESIZE size, w, h + VIDEOEXPOSE none + USEREVENT code + +.. versionchanged:: 2.0.0 The ``joy`` attribute was deprecated, ``instance_id`` was added. + +.. versionchanged:: 2.0.1 The ``unicode`` attribute was added to ``KEYUP`` event. + +You can also find a list of constants for keyboard keys +:ref:`here `. + +| + +On MacOSX when a file is opened using a pygame application, a ``USEREVENT`` +with its ``code`` attribute set to ``pygame.USEREVENT_DROPFILE`` is generated. +There is an additional attribute called ``filename`` where the name of the file +being accessed is stored. + +:: + + USEREVENT code=pygame.USEREVENT_DROPFILE, filename + +.. versionadded:: 1.9.2 + +| + +When compiled with SDL2, pygame has these additional events and their +attributes. + +:: + + AUDIODEVICEADDED which, iscapture + AUDIODEVICEREMOVED which, iscapture + FINGERMOTION touch_id, finger_id, x, y, dx, dy + FINGERDOWN touch_id, finger_id, x, y, dx, dy + FINGERUP touch_id, finger_id, x, y, dx, dy + MOUSEWHEEL which, flipped, x, y, touch + MULTIGESTURE touch_id, x, y, pinched, rotated, num_fingers + TEXTEDITING text, start, length + TEXTINPUT text + +.. versionadded:: 1.9.5 + +.. versionchanged:: 2.0.2 Fixed amount horizontal scroll (x, positive to the right and negative to the left). + +.. versionchanged:: 2.0.2 The ``touch`` attribute was added to all the ``MOUSE`` events. + +The ``touch`` attribute of ``MOUSE`` events indicates whether or not the events were generated +by a touch input device, and not a real mouse. You might want to ignore such events, if your application +already handles ``FINGERMOTION``, ``FINGERDOWN`` and ``FINGERUP`` events. + +| + +Many new events were introduced in pygame 2. + +pygame can recognize text or files dropped in its window. If a file +is dropped, ``DROPFILE`` event will be sent, ``file`` will be its path. +The ``DROPTEXT`` event is only supported on X11. + +``MIDIIN`` and ``MIDIOUT`` are events reserved for :mod:`pygame.midi` use. + +pygame 2 also supports controller hot-plugging + +:: + + DROPBEGIN + DROPCOMPLETE + DROPFILE file + DROPTEXT text + MIDIIN + MIDIOUT + CONTROLLERDEVICEADDED device_index + JOYDEVICEADDED device_index + CONTROLLERDEVICEREMOVED instance_id + JOYDEVICEREMOVED instance_id + CONTROLLERDEVICEREMAPPED instance_id + +Also in this version, ``instance_id`` attributes were added to joystick events, +and the ``joy`` attribute was deprecated. + +.. versionadded:: 2.0.0 + +Since pygame 2.0.1, there are a new set of events, called window events. +Here is a list of all window events, along with a short description + +:: + + Event type Short description + + WINDOWSHOWN Window became shown + WINDOWHIDDEN Window became hidden + WINDOWEXPOSED Window got updated by some external event + WINDOWMOVED Window got moved + WINDOWRESIZED Window got resized + WINDOWSIZECHANGED Window changed its size + WINDOWMINIMIZED Window was minimized + WINDOWMAXIMIZED Window was maximized + WINDOWRESTORED Window was restored + WINDOWENTER Mouse entered the window + WINDOWLEAVE Mouse left the window + WINDOWFOCUSGAINED Window gained focus + WINDOWFOCUSLOST Window lost focus + WINDOWCLOSE Window was closed + WINDOWTAKEFOCUS Window was offered focus + WINDOWHITTEST Window has a special hit test + + +If SDL version used is less than 2.0.5, the last two events ``WINDOWTAKEFOCUS`` +and ``WINDOWHITTEST`` will not work. + +Most these window events do not have any attributes, except ``WINDOWMOVED``, +``WINDOWRESIZED`` and ``WINDOWSIZECHANGED``, these have ``x`` and ``y`` attributes + +| + +.. function:: pump + + | :sl:`internally process pygame event handlers` + | :sg:`pump() -> None` + + For each frame of your game, you will need to make some sort of call to the + event queue. This ensures your program can internally interact with the rest + of the operating system. If you are not using other event functions in your + game, you should call ``pygame.event.pump()`` to allow pygame to handle + internal actions. + + This function is not necessary if your program is consistently processing + events on the queue through the other :mod:`pygame.event` functions. + + There are important things that must be dealt with internally in the event + queue. The main window may need to be repainted or respond to the system. If + you fail to make a call to the event queue for too long, the system may + decide your program has locked up. + + .. caution:: + This function should only be called in the thread that initialized :mod:`pygame.display`. + + .. ## pygame.event.pump ## + +.. function:: get + + | :sl:`get events from the queue` + | :sg:`get(eventtype=None) -> Eventlist` + | :sg:`get(eventtype=None, pump=True) -> Eventlist` + | :sg:`get(eventtype=None, pump=True, exclude=None) -> Eventlist` + + This will get all the messages and remove them from the queue. If a type or + sequence of types is given only those messages will be removed from the + queue and returned. + + If a type or sequence of types is passed in the ``exclude`` argument + instead, then all only *other* messages will be removed from the queue. If + an ``exclude`` parameter is passed, the ``eventtype`` parameter *must* be + None. + + If you are only taking specific events from the queue, be aware that the + queue could eventually fill up with the events you are not interested. + + If ``pump`` is ``True`` (the default), then :func:`pygame.event.pump()` will be called. + + .. versionchanged:: 1.9.5 Added ``pump`` argument + .. versionchanged:: 2.0.2 Added ``exclude`` argument + + .. ## pygame.event.get ## + +.. function:: poll + + | :sl:`get a single event from the queue` + | :sg:`poll() -> EventType instance` + + Returns a single event from the queue. If the event queue is empty an event + of type ``pygame.NOEVENT`` will be returned immediately. The returned event + is removed from the queue. + + .. caution:: + This function should only be called in the thread that initialized :mod:`pygame.display`. + + .. ## pygame.event.poll ## + +.. function:: wait + + | :sl:`wait for a single event from the queue` + | :sg:`wait() -> EventType instance` + | :sg:`wait(timeout) -> EventType instance` + + Returns a single event from the queue. If the queue is empty this function + will wait until one is created. From pygame 2.0.0, if a ``timeout`` argument + is given, the function will return an event of type ``pygame.NOEVENT`` + if no events enter the queue in ``timeout`` milliseconds. The event is removed + from the queue once it has been returned. While the program is waiting it will + sleep in an idle state. This is important for programs that want to share the + system with other applications. + + .. versionchanged:: 2.0.0.dev13 Added ``timeout`` argument + + .. caution:: + This function should only be called in the thread that initialized :mod:`pygame.display`. + + .. ## pygame.event.wait ## + +.. function:: peek + + | :sl:`test if event types are waiting on the queue` + | :sg:`peek(eventtype=None) -> bool` + | :sg:`peek(eventtype=None, pump=True) -> bool` + + Returns ``True`` if there are any events of the given type waiting on the + queue. If a sequence of event types is passed, this will return ``True`` if + any of those events are on the queue. + + If ``pump`` is ``True`` (the default), then :func:`pygame.event.pump()` will be called. + + .. versionchanged:: 1.9.5 Added ``pump`` argument + + .. ## pygame.event.peek ## + +.. function:: clear + + | :sl:`remove all events from the queue` + | :sg:`clear(eventtype=None) -> None` + | :sg:`clear(eventtype=None, pump=True) -> None` + + Removes all events from the queue. If ``eventtype`` is given, removes the given event + or sequence of events. This has the same effect as :func:`pygame.event.get()` except ``None`` + is returned. It can be slightly more efficient when clearing a full event queue. + + If ``pump`` is ``True`` (the default), then :func:`pygame.event.pump()` will be called. + + .. versionchanged:: 1.9.5 Added ``pump`` argument + + .. ## pygame.event.clear ## + +.. function:: event_name + + | :sl:`get the string name from an event id` + | :sg:`event_name(type) -> string` + + Returns a string representing the name (in CapWords style) of the given + event type. + + "UserEvent" is returned for all values in the user event id range. + "Unknown" is returned when the event type does not exist. + + .. ## pygame.event.event_name ## + +.. function:: set_blocked + + | :sl:`control which events are allowed on the queue` + | :sg:`set_blocked(type) -> None` + | :sg:`set_blocked(typelist) -> None` + | :sg:`set_blocked(None) -> None` + + The given event types are not allowed to appear on the event queue. By + default all events can be placed on the queue. It is safe to disable an + event type multiple times. + + If ``None`` is passed as the argument, ALL of the event types are blocked + from being placed on the queue. + + .. ## pygame.event.set_blocked ## + +.. function:: set_allowed + + | :sl:`control which events are allowed on the queue` + | :sg:`set_allowed(type) -> None` + | :sg:`set_allowed(typelist) -> None` + | :sg:`set_allowed(None) -> None` + + The given event types are allowed to appear on the event queue. By default, + all event types can be placed on the queue. It is safe to enable an event + type multiple times. + + If ``None`` is passed as the argument, ALL of the event types are allowed + to be placed on the queue. + + .. ## pygame.event.set_allowed ## + +.. function:: get_blocked + + | :sl:`test if a type of event is blocked from the queue` + | :sg:`get_blocked(type) -> bool` + | :sg:`get_blocked(typelist) -> bool` + + Returns ``True`` if the given event type is blocked from the queue. If a + sequence of event types is passed, this will return ``True`` if any of those + event types are blocked. + + .. ## pygame.event.get_blocked ## + +.. function:: set_grab + + | :sl:`control the sharing of input devices with other applications` + | :sg:`set_grab(bool) -> None` + + When your program runs in a windowed environment, it will share the mouse + and keyboard devices with other applications that have focus. If your + program sets the event grab to ``True``, it will lock all input into your + program. + + It is best to not always grab the input, since it prevents the user from + doing other things on their system. + + .. ## pygame.event.set_grab ## + +.. function:: get_grab + + | :sl:`test if the program is sharing input devices` + | :sg:`get_grab() -> bool` + + Returns ``True`` when the input events are grabbed for this application. + + .. ## pygame.event.get_grab ## + +.. function:: post + + | :sl:`place a new event on the queue` + | :sg:`post(Event) -> bool` + + Places the given event at the end of the event queue. + + This is usually used for placing custom events on the event queue. + Any type of event can be posted, and the events posted can have any attributes. + + This returns a boolean on whether the event was posted or not. Blocked events + cannot be posted, and this function returns ``False`` if you try to post them. + + .. versionchanged:: 2.0.1 returns a boolean, previously returned ``None`` + + .. ## pygame.event.post ## + +.. function:: custom_type + + | :sl:`make custom user event type` + | :sg:`custom_type() -> int` + + Reserves a ``pygame.USEREVENT`` for a custom use. + + If too many events are made a :exc:`pygame.error` is raised. + + .. versionadded:: 2.0.0.dev3 + + .. ## pygame.event.custom_type ## + +.. function:: Event + + | :sl:`create a new event object` + | :sg:`Event(type, dict) -> EventType instance` + | :sg:`Event(type, \**attributes) -> EventType instance` + + Creates a new event with the given type and attributes. The attributes can + come from a dictionary argument with string keys or from keyword arguments. + + .. ## pygame.event.Event ## + +.. class:: EventType + + | :sl:`pygame object for representing events` + + A pygame object that represents an event. User event instances are created + with an :func:`pygame.event.Event()` function call. The ``EventType`` type + is not directly callable. ``EventType`` instances support attribute + assignment and deletion. + + .. attribute:: type + + | :sl:`event type identifier.` + | :sg:`type -> int` + + Read-only. The event type identifier. For user created event + objects, this is the ``type`` argument passed to + :func:`pygame.event.Event()`. + + For example, some predefined event identifiers are ``QUIT`` and + ``MOUSEMOTION``. + + .. ## pygame.event.EventType.type ## + + .. attribute:: __dict__ + + | :sl:`event attribute dictionary` + | :sg:`__dict__ -> dict` + + Read-only. The event type specific attributes of an event. The + ``dict`` attribute is a synonym for backward compatibility. + + For example, the attributes of a ``KEYDOWN`` event would be ``unicode``, + ``key``, and ``mod`` + + .. ## pygame.event.EventType.__dict__ ## + + .. versionadded:: 1.9.2 Mutable attributes. + + .. ## pygame.event.EventType ## + +.. ## pygame.event ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/examples.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/examples.rst.txt new file mode 100644 index 0000000..000ea76 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/examples.rst.txt @@ -0,0 +1,451 @@ +.. include:: common.txt + +:mod:`pygame.examples` +====================== + +.. module:: pygame.examples + :synopsis: module of example programs + +| :sl:`module of example programs` + +These examples should help get you started with pygame. Here is a brief rundown +of what you get. The source code for these examples is in the public domain. +Feel free to use for your own projects. + +There are several ways to run the examples. First they can be run as +stand-alone programs. Second they can be imported and their ``main()`` methods +called (see below). Finally, the easiest way is to use the python -m option: + +:: + + python -m pygame.examples. + +eg: + +:: + + python -m pygame.examples.scaletest someimage.png + +Resources such as images and sounds for the examples are found in the +pygame/examples/data subdirectory. + +You can find where the example files are installed by using the following +commands inside the python interpreter. + +:: + + >>> import pygame.examples.scaletest + >>> pygame.examples.scaletest.__file__ + '/usr/lib/python2.6/site-packages/pygame/examples/scaletest.py' + +On each OS and version of Python the location will be slightly different. +For example on Windows it might be in 'C:/Python26/Lib/site-packages/pygame/examples/' +On Mac OS X it might be in '/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/pygame/examples/' + + +You can also run the examples in the python interpreter by calling each modules main() function. + +:: + + >>> import pygame.examples.scaletest + >>> pygame.examples.scaletest.main() + + +We're always on the lookout for more examples and/or example requests. Code +like this is probably the best way to start getting involved with python +gaming. + +examples as a package is new to pygame 1.9.0. But most of the examples came with +pygame much earlier. + +.. function:: aliens.main + + | :sl:`play the full aliens example` + | :sg:`aliens.main() -> None` + + This started off as a port of the ``SDL`` demonstration, Aliens. Now it has + evolved into something sort of resembling fun. This demonstrates a lot of + different uses of sprites and optimized blitting. Also transparency, + colorkeys, fonts, sound, music, joystick, and more. (PS, my high score is + 117! goodluck) + + .. ## pygame.examples.aliens.main ## + +.. function:: stars.main + + | :sl:`run a simple starfield example` + | :sg:`stars.main() -> None` + + A simple starfield example. You can change the center of perspective by + leftclicking the mouse on the screen. + + .. ## pygame.examples.stars.main ## + +.. function:: chimp.main + + | :sl:`hit the moving chimp` + | :sg:`chimp.main() -> None` + + This simple example is derived from the line-by-line tutorial that comes + with pygame. It is based on a 'popular' web banner. Note there are comments + here, but for the full explanation, follow along in the tutorial. + + .. ## pygame.examples.chimp.main ## + +.. function:: moveit.main + + | :sl:`display animated objects on the screen` + | :sg:`moveit.main() -> None` + + This is the full and final example from the Pygame Tutorial, "How Do I Make + It Move". It creates 10 objects and animates them on the screen. + + Note it's a bit scant on error checking, but it's easy to read. :] + Fortunately, this is python, and we needn't wrestle with a pile of error + codes. + + .. ## pygame.examples.moveit.main ## + +.. function:: fonty.main + + | :sl:`run a font rendering example` + | :sg:`fonty.main() -> None` + + Super quick, super simple application demonstrating the different ways to + render fonts with the font module + + .. ## pygame.examples.fonty.main ## + +.. function:: freetype_misc.main + + | :sl:`run a FreeType rendering example` + | :sg:`freetype_misc.main() -> None` + + A showcase of rendering features the :class:`pygame.freetype.Font` + class provides in addition to those available with :class:`pygame.font.Font`. + It is a demonstration of direct to surface rendering, with vertical text + and rotated text, opaque text and semi transparent text, horizontally + stretched text and vertically stretched text. + + .. ## pygame.examples.fonty.main ## + +.. function:: vgrade.main + + | :sl:`display a vertical gradient` + | :sg:`vgrade.main() -> None` + + Demonstrates creating a vertical gradient with pixelcopy and NumPy python. + The app will create a new gradient every half second and report the time + needed to create and display the image. If you're not prepared to start + working with the NumPy arrays, don't worry about the source for this one :] + + .. ## pygame.examples.vgrade.main ## + +.. function:: eventlist.main + + | :sl:`display pygame events` + | :sg:`eventlist.main() -> None` + + Eventlist is a sloppy style of pygame, but is a handy tool for learning + about pygame events and input. At the top of the screen are the state of + several device values, and a scrolling list of events are displayed on the + bottom. + + This is not quality 'ui' code at all, but you can see how to implement very + non-interactive status displays, or even a crude text output control. + + .. ## pygame.examples.eventlist.main ## + +.. function:: arraydemo.main + + | :sl:`show various surfarray effects` + | :sg:`arraydemo.main(arraytype=None) -> None` + + Another example filled with various surfarray effects. It requires the + surfarray and image modules to be installed. This little demo can also make + a good starting point for any of your own tests with surfarray + + The ``arraytype`` parameter is deprecated; passing any value besides 'numpy' + will raise ValueError. + + .. ## pygame.examples.arraydemo.main ## + +.. function:: sound.main + + | :sl:`load and play a sound` + | :sg:`sound.main(file_path=None) -> None` + + Extremely basic testing of the mixer module. Load a sound and play it. All + from the command shell, no graphics. + + If provided, use the audio file 'file_path', otherwise use a default file. + + ``sound.py`` optional command line argument: an audio file + + .. ## pygame.examples.sound.main ## + +.. function:: sound_array_demos.main + + | :sl:`play various sndarray effects` + | :sg:`sound_array_demos.main(arraytype=None) -> None` + + + Uses sndarray and NumPy to create offset faded copies of the + original sound. Currently it just uses hardcoded values for the number of + echoes and the delay. Easy for you to recreate as needed. + + The ``arraytype`` parameter is deprecated; passing any value besides 'numpy' + will raise ValueError. + + .. ## pygame.examples.sound_array_demos.main ## + +.. function:: liquid.main + + | :sl:`display an animated liquid effect` + | :sg:`liquid.main() -> None` + + This example was created in a quick comparison with the BlitzBasic gaming + language. Nonetheless, it demonstrates a quick 8-bit setup (with colormap). + + .. ## pygame.examples.liquid.main ## + +.. function:: glcube.main + + | :sl:`display an animated 3D cube using OpenGL` + | :sg:`glcube.main() -> None` + + Using PyOpenGL and pygame, this creates a spinning 3D multicolored cube. + + .. ## pygame.examples.glcube.main ## + +.. function:: scrap_clipboard.main + + | :sl:`access the clipboard` + | :sg:`scrap_clipboard.main() -> None` + + A simple demonstration example for the clipboard support. + + .. ## pygame.examples.scrap_clipboard.main ## + +.. function:: mask.main + + | :sl:`display multiple images bounce off each other using collision detection` + | :sg:`mask.main(*args) -> None` + + Positional arguments: + + :: + + one or more image file names. + + This ``pygame.masks`` demo will display multiple moving sprites bouncing off + each other. More than one sprite image can be provided. + + If run as a program then ``mask.py`` takes one or more image files as + command line arguments. + + .. ## pygame.examples.mask.main ## + +.. function:: testsprite.main + + | :sl:`show lots of sprites moving around` + | :sg:`testsprite.main(update_rects = True, use_static = False, use_FastRenderGroup = False, screen_dims = [640, 480], use_alpha = False, flags = 0) -> None` + + Optional keyword arguments: + + :: + + update_rects - use the RenderUpdate sprite group class + use_static - include non-moving images + use_FastRenderGroup - Use the FastRenderGroup sprite group + screen_dims - pygame window dimensions + use_alpha - use alpha blending + flags - additional display mode flags + + Like the ``testsprite.c`` that comes with SDL, this pygame version shows + lots of sprites moving around. + + If run as a stand-alone program then no command line arguments are taken. + + .. ## pygame.examples.testsprite.main ## + +.. function:: headless_no_windows_needed.main + + | :sl:`write an image file that is smoothscaled copy of an input file` + | :sg:`headless_no_windows_needed.main(fin, fout, w, h) -> None` + + arguments: + + :: + + fin - name of an input image file + fout - name of the output file to create/overwrite + w, h - size of the rescaled image, as integer width and height + + How to use pygame with no windowing system, like on headless servers. + + Thumbnail generation with scaling is an example of what you can do with + pygame. + + ``NOTE``: the pygame scale function uses MMX/SSE if available, and can be + run in multiple threads. + + If ``headless_no_windows_needed.py`` is run as a program it takes the + following command line arguments: + + :: + + -scale inputimage outputimage new_width new_height + eg. -scale in.png outpng 50 50 + + .. ## pygame.examples.headless_no_windows_needed.main ## + +.. function:: joystick.main + + | :sl:`demonstrate joystick functionality` + | :sg:`joystick.main() -> None` + + A demo showing full joystick support. + + .. versionadded:: 2.0.2 + + .. ## pygame.examples.joystick.main ## + +.. function:: blend_fill.main + + | :sl:`demonstrate the various surface.fill method blend options` + | :sg:`blend_fill.main() -> None` + + A interactive demo that lets one choose which BLEND_xxx option to apply to a + surface. + + .. ## pygame.examples.blend_fill.main ## + +.. function:: blit_blends.main + + | :sl:`uses alternative additive fill to that of surface.fill` + | :sg:`blit_blends.main() -> None` + + Fake additive blending. Using NumPy. it doesn't clamp. Press r,g,b Somewhat + like blend_fill. + + .. ## pygame.examples.blit_blends.main ## + +.. function:: cursors.main + + | :sl:`display two different custom cursors` + | :sg:`cursors.main() -> None` + + Display an arrow or circle with crossbar cursor. + + .. ## pygame.examples.cursors.main ## + +.. function:: pixelarray.main + + | :sl:`display various pixelarray generated effects` + | :sg:`pixelarray.main() -> None` + + Display various pixelarray generated effects. + + .. ## pygame.examples.pixelarray.main ## + +.. function:: scaletest.main + + | :sl:`interactively scale an image using smoothscale` + | :sg:`scaletest.main(imagefile, convert_alpha=False, run_speed_test=True) -> None` + + arguments: + + :: + + imagefile - file name of source image (required) + convert_alpha - use convert_alpha() on the surf (default False) + run_speed_test - (default False) + + A smoothscale example that resized an image on the screen. Vertical and + horizontal arrow keys are used to change the width and height of the + displayed image. If the convert_alpha option is True then the source image + is forced to have source alpha, whether or not the original images does. If + run_speed_test is True then a background timing test is performed instead of + the interactive scaler. + + If ``scaletest.py`` is run as a program then the command line options are: + + :: + + ImageFile [-t] [-convert_alpha] + [-t] = Run Speed Test + [-convert_alpha] = Use convert_alpha() on the surf. + + .. ## pygame.examples.scaletest.main ## + +.. function:: midi.main + + | :sl:`run a midi example` + | :sg:`midi.main(mode='output', device_id=None) -> None` + + Arguments: + + :: + + mode - if 'output' run a midi keyboard output example + 'input' run a midi event logger input example + 'list' list available midi devices + (default 'output') + device_id - midi device number; if None then use the default midi input or + output device for the system + + The output example shows how to translate mouse clicks or computer keyboard + events into midi notes. It implements a rudimentary button widget and state + machine. + + The input example shows how to translate midi input to pygame events. + + With the use of a virtual midi patch cord the output and input examples can + be run as separate processes and connected so the keyboard output is + displayed on a console. + + new to pygame 1.9.0 + + .. ## pygame.examples.midi.main ## + +.. function:: scroll.main + + | :sl:`run a Surface.scroll example that shows a magnified image` + | :sg:`scroll.main(image_file=None) -> None` + + This example shows a scrollable image that has a zoom factor of eight. It + uses the :meth:`Surface.scroll() ` + function to shift the image on the display surface. + A clip rectangle protects a margin area. If called as a function, + the example accepts an optional image file path. If run as a program it + takes an optional file path command line argument. If no file is provided a + default image file is used. + + When running click on a black triangle to move one pixel in the direction + the triangle points. Or use the arrow keys. Close the window or press + ``ESC`` to quit. + + .. ## pygame.examples.scroll.main ## + +.. function:: camera.main + + | :sl:`display video captured live from an attached camera` + | :sg:`camera.main() -> None` + + A simple live video player, it uses the first available camera it finds on + the system. + + .. ## pygame.examples.camera.main ## + +.. function:: playmus.main + + | :sl:`play an audio file` + | :sg:`playmus.main(file_path) -> None` + + A simple music player with window and keyboard playback control. Playback can + be paused and rewound to the beginning. + + .. ## pygame.examples.playmus.main ## + +.. ## pygame.examples ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/fastevent.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/fastevent.rst.txt new file mode 100644 index 0000000..a2efe5f --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/fastevent.rst.txt @@ -0,0 +1,109 @@ +.. include:: common.txt + +:mod:`pygame.fastevent` +======================= + +.. module:: pygame.fastevent + :synopsis: pygame module for interacting with events and queues from multiple + threads. + +| :sl:`pygame module for interacting with events and queues` + +IMPORTANT NOTE: THIS MODULE IS DEPRECATED IN PYGAME 2.2 + +In older pygame versions before pygame 2, :mod:`pygame.event` was not well +suited for posting events from different threads. This module served as a +replacement (with less features) for multithreaded use. Now, the usage of this +module is highly discouraged in favour of use of the main :mod:`pygame.event` +module. This module will be removed in a future pygame version. + +Below, the legacy docs of the module is provided + +.. function:: init + + | :sl:`initialize pygame.fastevent` + | :sg:`init() -> None` + + Initialize the pygame.fastevent module. + + .. ## pygame.fastevent.init ## + +.. function:: get_init + + | :sl:`returns True if the fastevent module is currently initialized` + | :sg:`get_init() -> bool` + + Returns True if the pygame.fastevent module is currently initialized. + + .. ## pygame.fastevent.get_init ## + +.. function:: pump + + | :sl:`internally process pygame event handlers` + | :sg:`pump() -> None` + + For each frame of your game, you will need to make some sort of call to the + event queue. This ensures your program can internally interact with the rest + of the operating system. + + This function is not necessary if your program is consistently processing + events on the queue through the other :mod:`pygame.fastevent` functions. + + There are important things that must be dealt with internally in the event + queue. The main window may need to be repainted or respond to the system. If + you fail to make a call to the event queue for too long, the system may + decide your program has locked up. + + .. ## pygame.fastevent.pump ## + +.. function:: wait + + | :sl:`wait for an event` + | :sg:`wait() -> Event` + + Returns the current event on the queue. If there are no messages + waiting on the queue, this will not return until one is available. + Sometimes it is important to use this wait to get events from the queue, + it will allow your application to idle when the user isn't doing anything + with it. + + .. ## pygame.fastevent.wait ## + +.. function:: poll + + | :sl:`get an available event` + | :sg:`poll() -> Event` + + Returns next event on queue. If there is no event waiting on the queue, + this will return an event with type NOEVENT. + + .. ## pygame.fastevent.poll ## + +.. function:: get + + | :sl:`get all events from the queue` + | :sg:`get() -> list of Events` + + This will get all the messages and remove them from the queue. + + .. ## pygame.fastevent.get ## + +.. function:: post + + | :sl:`place an event on the queue` + | :sg:`post(Event) -> None` + + This will post your own event objects onto the event queue. You can post + any event type you want, but some care must be taken. For example, if you + post a MOUSEBUTTONDOWN event to the queue, it is likely any code receiving + the event will expect the standard MOUSEBUTTONDOWN attributes to be + available, like 'pos' and 'button'. + + Because pygame.fastevent.post() may have to wait for the queue to empty, + you can get into a dead lock if you try to append an event on to a full + queue from the thread that processes events. For that reason I do not + recommend using this function in the main thread of an SDL program. + + .. ## pygame.fastevent.post ## + +.. ## pygame.fastevent ## \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/font.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/font.rst.txt new file mode 100644 index 0000000..4d6cd05 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/font.rst.txt @@ -0,0 +1,405 @@ +.. include:: common.txt + +:mod:`pygame.font` +================== + +.. module:: pygame.font + :synopsis: pygame module for loading and rendering fonts + +| :sl:`pygame module for loading and rendering fonts` + +The font module allows for rendering TrueType fonts into a new Surface object. +It accepts any UCS-2 character ('\u0001' to '\uFFFF'). This module is optional +and requires SDL_ttf as a dependency. You should test that :mod:`pygame.font` +is available and initialized before attempting to use the module. + +Most of the work done with fonts are done by using the actual Font objects. The +module by itself only has routines to initialize the module and create Font +objects with ``pygame.font.Font()``. + +You can load fonts from the system by using the ``pygame.font.SysFont()`` +function. There are a few other functions to help lookup the system fonts. + +Pygame comes with a builtin default font. This can always be accessed by +passing None as the font name. + +To use the :mod:`pygame.freetype` based ``pygame.ftfont`` as +:mod:`pygame.font` define the environment variable PYGAME_FREETYPE before the +first import of :mod:`pygame`. Module ``pygame.ftfont`` is a :mod:`pygame.font` +compatible module that passes all but one of the font module unit tests: +it does not have the UCS-2 limitation of the SDL_ttf based font module, so +fails to raise an exception for a code point greater than '\uFFFF'. If +:mod:`pygame.freetype` is unavailable then the SDL_ttf font module will be +loaded instead. + +.. function:: init + + | :sl:`initialize the font module` + | :sg:`init() -> None` + + This method is called automatically by ``pygame.init()``. It initializes the + font module. The module must be initialized before any other functions will + work. + + It is safe to call this function more than once. + + .. ## pygame.font.init ## + +.. function:: quit + + | :sl:`uninitialize the font module` + | :sg:`quit() -> None` + + Manually uninitialize SDL_ttf's font system. This is called automatically by + ``pygame.quit()``. + + It is safe to call this function even if font is currently not initialized. + + .. ## pygame.font.quit ## + +.. function:: get_init + + | :sl:`true if the font module is initialized` + | :sg:`get_init() -> bool` + + Test if the font module is initialized or not. + + .. ## pygame.font.get_init ## + +.. function:: get_default_font + + | :sl:`get the filename of the default font` + | :sg:`get_default_font() -> string` + + Return the filename of the system font. This is not the full path to the + file. This file can usually be found in the same directory as the font + module, but it can also be bundled in separate archives. + + .. ## pygame.font.get_default_font ## + +.. function:: get_fonts + + | :sl:`get all available fonts` + | :sg:`get_fonts() -> list of strings` + + Returns a list of all the fonts available on the system. The names of the + fonts will be set to lowercase with all spaces and punctuation removed. This + works on most systems, but some will return an empty list if they cannot + find fonts. + + .. ## pygame.font.get_fonts ## + +.. function:: match_font + + | :sl:`find a specific font on the system` + | :sg:`match_font(name, bold=False, italic=False) -> path` + + Returns the full path to a font file on the system. If bold or italic are + set to true, this will attempt to find the correct family of font. + + The font name can also be an iterable of font names, a string of + comma-separated font names, or a bytes of comma-separated font names, in + which case the set of names will be searched in order. + If none of the given names are found, None is returned. + + .. versionadded:: 2.0.1 Accept an iterable of font names. + + Example: + + :: + + print pygame.font.match_font('bitstreamverasans') + # output is: /usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf + # (but only if you have Vera on your system) + + .. ## pygame.font.match_font ## + +.. function:: SysFont + + | :sl:`create a Font object from the system fonts` + | :sg:`SysFont(name, size, bold=False, italic=False) -> Font` + + Return a new Font object that is loaded from the system fonts. The font will + match the requested bold and italic flags. Pygame uses a small set of common + font aliases. If the specific font you ask for is not available, a reasonable + alternative may be used. If a suitable system font is not found this will + fall back on loading the default pygame font. + + The font name can also be an iterable of font names, a string of + comma-separated font names, or a bytes of comma-separated font names, in + which case the set of names will be searched in order. + + .. versionadded:: 2.0.1 Accept an iterable of font names. + + .. ## pygame.font.SysFont ## + +.. class:: Font + + | :sl:`create a new Font object from a file` + | :sg:`Font(filename, size) -> Font` + | :sg:`Font(pathlib.Path, size) -> Font` + | :sg:`Font(object, size) -> Font` + + Load a new font from a given filename or a python file object. The size is + the height of the font in pixels. If the filename is None the pygame default + font will be loaded. If a font cannot be loaded from the arguments given an + exception will be raised. Once the font is created the size cannot be + changed. + + Font objects are mainly used to render text into new Surface objects. The + render can emulate bold or italic features, but it is better to load from a + font with actual italic or bold glyphs. The rendered text can be regular + strings or unicode. + + .. attribute:: bold + + | :sl:`Gets or sets whether the font should be rendered in (faked) bold.` + | :sg:`bold -> bool` + + Whether the font should be rendered in bold. + + When set to True, this enables the bold rendering of text. This + is a fake stretching of the font that doesn't look good on many + font types. If possible load the font from a real bold font + file. While bold, the font will have a different width than when + normal. This can be mixed with the italic and underline modes. + + .. versionadded:: 2.0.0 + + .. ## Font.bold ## + + .. attribute:: italic + + | :sl:`Gets or sets whether the font should be rendered in (faked) italics.` + | :sg:`italic -> bool` + + Whether the font should be rendered in italic. + + When set to True, this enables fake rendering of italic + text. This is a fake skewing of the font that doesn't look good + on many font types. If possible load the font from a real italic + font file. While italic the font will have a different width + than when normal. This can be mixed with the bold and underline + modes. + + .. versionadded:: 2.0.0 + + .. ## Font.italic ## + + .. attribute:: underline + + | :sl:`Gets or sets whether the font should be rendered with an underline.` + | :sg:`underline -> bool` + + Whether the font should be rendered in underline. + + When set to True, all rendered fonts will include an + underline. The underline is always one pixel thick, regardless + of font size. This can be mixed with the bold and italic modes. + + .. versionadded:: 2.0.0 + + .. ## Font.underline ## + + .. method:: render + + | :sl:`draw text on a new Surface` + | :sg:`render(text, antialias, color, background=None) -> Surface` + + This creates a new Surface with the specified text rendered on it. pygame + provides no way to directly draw text on an existing Surface: instead you + must use ``Font.render()`` to create an image (Surface) of the text, then + blit this image onto another Surface. + + The text can only be a single line: newline characters are not rendered. + Null characters ('\x00') raise a TypeError. Both Unicode and char (byte) + strings are accepted. For Unicode strings only UCS-2 characters + ('\u0001' to '\uFFFF') were previously supported and any greater unicode + codepoint would raise a UnicodeError. Now, characters in the UCS-4 range + are supported. For char strings a ``LATIN1`` encoding is assumed. The + antialias argument is a boolean: if true the characters will have smooth + edges. The color argument is the color of the text + [e.g.: (0,0,255) for blue]. The optional background argument is a color + to use for the text background. If no background is passed the area + outside the text will be transparent. + + The Surface returned will be of the dimensions required to hold the text. + (the same as those returned by Font.size()). If an empty string is passed + for the text, a blank surface will be returned that is zero pixel wide and + the height of the font. + + Depending on the type of background and antialiasing used, this returns + different types of Surfaces. For performance reasons, it is good to know + what type of image will be used. If antialiasing is not used, the return + image will always be an 8-bit image with a two-color palette. If the + background is transparent a colorkey will be set. Antialiased images are + rendered to 24-bit ``RGB`` images. If the background is transparent a + pixel alpha will be included. + + Optimization: if you know that the final destination for the text (on the + screen) will always have a solid background, and the text is antialiased, + you can improve performance by specifying the background color. This will + cause the resulting image to maintain transparency information by + colorkey rather than (much less efficient) alpha values. + + If you render '\\n' an unknown char will be rendered. Usually a + rectangle. Instead you need to handle new lines yourself. + + Font rendering is not thread safe: only a single thread can render text + at any time. + + .. versionchanged:: 2.0.3 Rendering UCS_4 unicode works and does not + raise an exception. Use `if hasattr(pygame.font, 'UCS_4'):` to see if + pygame supports rendering UCS_4 unicode including more languages and + emoji. + + .. ## Font.render ## + + .. method:: size + + | :sl:`determine the amount of space needed to render text` + | :sg:`size(text) -> (width, height)` + + Returns the dimensions needed to render the text. This can be used to + help determine the positioning needed for text before it is rendered. It + can also be used for wordwrapping and other layout effects. + + Be aware that most fonts use kerning which adjusts the widths for + specific letter pairs. For example, the width for "ae" will not always + match the width for "a" + "e". + + .. ## Font.size ## + + .. method:: set_underline + + | :sl:`control if text is rendered with an underline` + | :sg:`set_underline(bool) -> None` + + When enabled, all rendered fonts will include an underline. The underline + is always one pixel thick, regardless of font size. This can be mixed + with the bold and italic modes. + + .. note:: This is the same as the :attr:`underline` attribute. + + .. ## Font.set_underline ## + + .. method:: get_underline + + | :sl:`check if text will be rendered with an underline` + | :sg:`get_underline() -> bool` + + Return True when the font underline is enabled. + + .. note:: This is the same as the :attr:`underline` attribute. + + .. ## Font.get_underline ## + + .. method:: set_bold + + | :sl:`enable fake rendering of bold text` + | :sg:`set_bold(bool) -> None` + + Enables the bold rendering of text. This is a fake stretching of the font + that doesn't look good on many font types. If possible load the font from + a real bold font file. While bold, the font will have a different width + than when normal. This can be mixed with the italic and underline modes. + + .. note:: This is the same as the :attr:`bold` attribute. + + .. ## Font.set_bold ## + + .. method:: get_bold + + | :sl:`check if text will be rendered bold` + | :sg:`get_bold() -> bool` + + Return True when the font bold rendering mode is enabled. + + .. note:: This is the same as the :attr:`bold` attribute. + + .. ## Font.get_bold ## + + .. method:: set_italic + + | :sl:`enable fake rendering of italic text` + | :sg:`set_italic(bool) -> None` + + Enables fake rendering of italic text. This is a fake skewing of the font + that doesn't look good on many font types. If possible load the font from + a real italic font file. While italic the font will have a different + width than when normal. This can be mixed with the bold and underline + modes. + + .. note:: This is the same as the :attr:`italic` attribute. + + .. ## Font.set_italic ## + + .. method:: metrics + + | :sl:`gets the metrics for each character in the passed string` + | :sg:`metrics(text) -> list` + + The list contains tuples for each character, which contain the minimum + ``X`` offset, the maximum ``X`` offset, the minimum ``Y`` offset, the + maximum ``Y`` offset and the advance offset (bearing plus width) of the + character. [(minx, maxx, miny, maxy, advance), (minx, maxx, miny, maxy, + advance), ...]. None is entered in the list for each unrecognized + character. + + .. ## Font.metrics ## + + .. method:: get_italic + + | :sl:`check if the text will be rendered italic` + | :sg:`get_italic() -> bool` + + Return True when the font italic rendering mode is enabled. + + .. note:: This is the same as the :attr:`italic` attribute. + + .. ## Font.get_italic ## + + .. method:: get_linesize + + | :sl:`get the line space of the font text` + | :sg:`get_linesize() -> int` + + Return the height in pixels for a line of text with the font. When + rendering multiple lines of text this is the recommended amount of space + between lines. + + .. ## Font.get_linesize ## + + .. method:: get_height + + | :sl:`get the height of the font` + | :sg:`get_height() -> int` + + Return the height in pixels of the actual rendered text. This is the + average size for each glyph in the font. + + .. ## Font.get_height ## + + .. method:: get_ascent + + | :sl:`get the ascent of the font` + | :sg:`get_ascent() -> int` + + Return the height in pixels for the font ascent. The ascent is the number + of pixels from the font baseline to the top of the font. + + .. ## Font.get_ascent ## + + .. method:: get_descent + + | :sl:`get the descent of the font` + | :sg:`get_descent() -> int` + + Return the height in pixels for the font descent. The descent is the + number of pixels from the font baseline to the bottom of the font. + + .. ## Font.get_descent ## + + .. ## pygame.font.Font ## + +.. ## pygame.font ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/freetype.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/freetype.rst.txt new file mode 100644 index 0000000..6e10461 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/freetype.rst.txt @@ -0,0 +1,766 @@ +.. include:: common.txt + +:mod:`pygame.freetype` +====================== + +.. module:: pygame.freetype + :synopsis: Enhanced pygame module for loading and rendering computer fonts + +| :sl:`Enhanced pygame module for loading and rendering computer fonts` + +The ``pygame.freetype`` module is a replacement for :mod:`pygame.font`. +It has all of the functionality of the original, plus many new features. +Yet is has absolutely no dependencies on the SDL_ttf library. +It is implemented directly on the FreeType 2 library. +The ``pygame.freetype`` module is not itself backward compatible with +:mod:`pygame.font`. +Instead, use the ``pygame.ftfont`` module as a drop-in replacement +for :mod:`pygame.font`. + +All font file formats supported by FreeType can be rendered by +``pygame.freetype``, namely ``TTF``, Type1, ``CFF``, OpenType, +``SFNT``, ``PCF``, ``FNT``, ``BDF``, ``PFR`` and Type42 fonts. +All glyphs having UTF-32 code points are accessible +(see :attr:`Font.ucs4`). + +Most work on fonts is done using :class:`Font` instances. +The module itself only has routines for initialization and creation +of :class:`Font` objects. +You can load fonts from the system using the :func:`SysFont` function. + +Extra support of bitmap fonts is available. Available bitmap sizes can +be listed (see :meth:`Font.get_sizes`). For bitmap only fonts :class:`Font` +can set the size for you (see the :attr:`Font.size` property). + +For now undefined character codes are replaced with the ``.notdef`` +(not defined) character. +How undefined codes are handled may become configurable in a future release. + +Pygame comes with a built-in default font. This can always be accessed by +passing None as the font name to the :class:`Font` constructor. + +Extra rendering features available to :class:`pygame.freetype.Font` +are direct to surface rendering (see :meth:`Font.render_to`), character kerning +(see :attr:`Font.kerning`), vertical layout (see :attr:`Font.vertical`), +rotation of rendered text (see :attr:`Font.rotation`), +and the strong style (see :attr:`Font.strong`). +Some properties are configurable, such as +strong style strength (see :attr:`Font.strength`) and underline positioning +(see :attr:`Font.underline_adjustment`). Text can be positioned by the upper +right corner of the text box or by the text baseline (see :attr:`Font.origin`). +Finally, a font's vertical and horizontal size can be adjusted separately +(see :attr:`Font.size`). +The :any:`pygame.examples.freetype_misc ` +example shows these features in use. + +The pygame package does not import ``freetype`` automatically when +loaded. This module must be imported explicitly to be used. :: + + import pygame + import pygame.freetype + +.. versionadded:: 1.9.2 :mod:`freetype` + + +.. function:: get_error + + | :sl:`Return the latest FreeType error` + | :sg:`get_error() -> str` + | :sg:`get_error() -> None` + + Return a description of the last error which occurred in the FreeType2 + library, or ``None`` if no errors have occurred. + +.. function:: get_version + + | :sl:`Return the FreeType version` + | :sg:`get_version() -> (int, int, int)` + + Returns the version of the FreeType library in use by this module. + + Note that the ``freetype`` module depends on the FreeType 2 library. + It will not compile with the original FreeType 1.0. Hence, the first element + of the tuple will always be "2". + +.. function:: init + + | :sl:`Initialize the underlying FreeType library.` + | :sg:`init(cache_size=64, resolution=72) -> None` + + This function initializes the underlying FreeType library and must be + called before trying to use any of the functionality of the ``freetype`` + module. + + However, :func:`pygame.init()` will automatically call this function + if the ``freetype`` module is already imported. It is safe to call this + function more than once. + + Optionally, you may specify a default *cache_size* for the Glyph cache: the + maximum number of glyphs that will be cached at any given time by the + module. Exceedingly small values will be automatically tuned for + performance. Also a default pixel *resolution*, in dots per inch, can + be given to adjust font scaling. + +.. function:: quit + + | :sl:`Shut down the underlying FreeType library.` + | :sg:`quit() -> None` + + This function closes the ``freetype`` module. After calling this + function, you should not invoke any class, method or function related to the + ``freetype`` module as they are likely to fail or might give unpredictable + results. It is safe to call this function even if the module hasn't been + initialized yet. + +.. function:: get_init + + | :sl:`Returns True if the FreeType module is currently initialized.` + | :sg:`get_init() -> bool` + + Returns ``True`` if the ``pygame.freetype`` module is currently initialized. + + .. versionadded:: 1.9.5 + +.. function:: was_init + + | :sl:`DEPRECATED: Use get_init() instead.` + | :sg:`was_init() -> bool` + + DEPRECATED: Returns ``True`` if the ``pygame.freetype`` module is currently + initialized. Use ``get_init()`` instead. + +.. function:: get_cache_size + + | :sl:`Return the glyph case size` + | :sg:`get_cache_size() -> long` + + See :func:`pygame.freetype.init()`. + +.. function:: get_default_resolution + + | :sl:`Return the default pixel size in dots per inch` + | :sg:`get_default_resolution() -> long` + + Returns the default pixel size, in dots per inch, for the module. + The default is 72 DPI. + +.. function:: set_default_resolution + + | :sl:`Set the default pixel size in dots per inch for the module` + | :sg:`set_default_resolution([resolution])` + + Set the default pixel size, in dots per inch, for the module. If the + optional argument is omitted or zero the resolution is reset to 72 DPI. + +.. function:: SysFont + + | :sl:`create a Font object from the system fonts` + | :sg:`SysFont(name, size, bold=False, italic=False) -> Font` + + Return a new Font object that is loaded from the system fonts. The font will + match the requested *bold* and *italic* flags. Pygame uses a small set of + common font aliases. If the specific font you ask for is not available, a + reasonable alternative may be used. If a suitable system font is not found + this will fall back on loading the default pygame font. + + The font *name* can also be an iterable of font names, a string of + comma-separated font names, or a bytes of comma-separated font names, in + which case the set of names will be searched in order. + + .. versionadded:: 2.0.1 Accept an iterable of font names. + +.. function:: get_default_font + + | :sl:`Get the filename of the default font` + | :sg:`get_default_font() -> string` + + Return the filename of the default pygame font. This is not the full path + to the file. The file is usually in the same directory as the font module, + but can also be bundled in a separate archive. + +.. class:: Font + + | :sl:`Create a new Font instance from a supported font file.` + | :sg:`Font(file, size=0, font_index=0, resolution=0, ucs4=False) -> Font` + | :sg:`Font(pathlib.Path) -> Font` + + Argument *file* can be either a string representing the font's filename, a + file-like object containing the font, or None; if None, a default, + Pygame, font is used. + + .. _freetype-font-size-argument: + + Optionally, a *size* argument may be specified to set the default size in + points, which determines the size of the rendered characters. + The size can also be passed explicitly to each method call. + Because of the way the caching system works, specifying a default size on + the constructor doesn't imply a performance gain over manually passing + the size on each function call. If the font is bitmap and no *size* + is given, the default size is set to the first available size for the font. + + If the font file has more than one font, the font to load can be chosen with + the *index* argument. An exception is raised for an out-of-range font index + value. + + The optional *resolution* argument sets the pixel size, in dots per inch, + for use in scaling glyphs for this Font instance. If 0 then the default + module value, set by :func:`init`, is used. The Font object's + resolution can only be changed by re-initializing the Font instance. + + The optional *ucs4* argument, an integer, sets the default text translation + mode: 0 (False) recognize UTF-16 surrogate pairs, any other value (True), + to treat Unicode text as UCS-4, with no surrogate pairs. See + :attr:`Font.ucs4`. + + .. attribute:: name + + | :sl:`Proper font name.` + | :sg:`name -> string` + + Read only. Returns the real (long) name of the font, as + recorded in the font file. + + .. attribute:: path + + | :sl:`Font file path` + | :sg:`path -> unicode` + + Read only. Returns the path of the loaded font file + + .. attribute:: size + + | :sl:`The default point size used in rendering` + | :sg:`size -> float` + | :sg:`size -> (float, float)` + + Get or set the default size for text metrics and rendering. It can be + a single point size, given as a Python ``int`` or ``float``, or a + font ppem (width, height) ``tuple``. Size values are non-negative. + A zero size or width represents an undefined size. In this case + the size must be given as a method argument, or an exception is + raised. A zero width but non-zero height is a ValueError. + + For a scalable font, a single number value is equivalent to a tuple + with width equal height. A font can be stretched vertically with + height set greater than width, or horizontally with width set + greater than height. For embedded bitmaps, as listed by :meth:`get_sizes`, + use the nominal width and height to select an available size. + + Font size differs for a non-scalable, bitmap, font. During a + method call it must match one of the available sizes returned by + method :meth:`get_sizes`. If not, an exception is raised. + If the size is a single number, the size is first matched against the + point size value. If no match, then the available size with the + same nominal width and height is chosen. + + .. method:: get_rect + + | :sl:`Return the size and offset of rendered text` + | :sg:`get_rect(text, style=STYLE_DEFAULT, rotation=0, size=0) -> rect` + + Gets the final dimensions and origin, in pixels, of *text* using the + optional *size* in points, *style*, and *rotation*. For other + relevant render properties, and for any optional argument not given, + the default values set for the :class:`Font` instance are used. + + Returns a :class:`Rect ` instance containing the + width and height of the text's bounding box and the position of the + text's origin. + The origin is useful in aligning separately rendered pieces of text. + It gives the baseline position and bearing at the start of the text. + See the :meth:`render_to` method for an example. + + If *text* is a char (byte) string, its encoding is assumed to be + ``LATIN1``. + + Optionally, *text* can be ``None``, which will return the bounding + rectangle for the text passed to a previous :meth:`get_rect`, + :meth:`render`, :meth:`render_to`, :meth:`render_raw`, or + :meth:`render_raw_to` call. See :meth:`render_to` for more + details. + + .. method:: get_metrics + + | :sl:`Return the glyph metrics for the given text` + | :sg:`get_metrics(text, size=0) -> [(...), ...]` + + Returns the glyph metrics for each character in *text*. + + The glyph metrics are returned as a list of tuples. Each tuple gives + metrics of a single character glyph. The glyph metrics are: + + :: + + (min_x, max_x, min_y, max_y, horizontal_advance_x, horizontal_advance_y) + + The bounding box min_x, max_x, min_y, and max_y values are returned as + grid-fitted pixel coordinates of type int. The advance values are + float values. + + The calculations are done using the font's default size in points. + Optionally you may specify another point size with the *size* argument. + + The metrics are adjusted for the current rotation, strong, and oblique + settings. + + If text is a char (byte) string, then its encoding is assumed to be + ``LATIN1``. + + .. attribute:: height + + | :sl:`The unscaled height of the font in font units` + | :sg:`height -> int` + + Read only. Gets the height of the font. This is the average value of all + glyphs in the font. + + .. attribute:: ascender + + | :sl:`The unscaled ascent of the font in font units` + | :sg:`ascender -> int` + + Read only. Return the number of units from the font's baseline to + the top of the bounding box. + + .. attribute:: descender + + | :sl:`The unscaled descent of the font in font units` + | :sg:`descender -> int` + + Read only. Return the height in font units for the font descent. + The descent is the number of units from the font's baseline to the + bottom of the bounding box. + + .. method:: get_sized_ascender + + | :sl:`The scaled ascent of the font in pixels` + | :sg:`get_sized_ascender(=0) -> int` + + Return the number of units from the font's baseline to the top of the + bounding box. It is not adjusted for strong or rotation. + + .. method:: get_sized_descender + + | :sl:`The scaled descent of the font in pixels` + | :sg:`get_sized_descender(=0) -> int` + + Return the number of pixels from the font's baseline to the top of the + bounding box. It is not adjusted for strong or rotation. + + .. method:: get_sized_height + + | :sl:`The scaled height of the font in pixels` + | :sg:`get_sized_height(=0) -> int` + + Returns the height of the font. This is the average value of all + glyphs in the font. It is not adjusted for strong or rotation. + + .. method:: get_sized_glyph_height + + | :sl:`The scaled bounding box height of the font in pixels` + | :sg:`get_sized_glyph_height(=0) -> int` + + Return the glyph bounding box height of the font in pixels. + This is the average value of all glyphs in the font. + It is not adjusted for strong or rotation. + + .. method:: get_sizes + + | :sl:`return the available sizes of embedded bitmaps` + | :sg:`get_sizes() -> [(int, int, int, float, float), ...]` + | :sg:`get_sizes() -> []` + + Returns a list of tuple records, one for each point size + supported. Each tuple containing the point size, the height in pixels, + width in pixels, horizontal ppem (nominal width) in fractional pixels, + and vertical ppem (nominal height) in fractional pixels. + + .. method:: render + + | :sl:`Return rendered text as a surface` + | :sg:`render(text, fgcolor=None, bgcolor=None, style=STYLE_DEFAULT, rotation=0, size=0) -> (Surface, Rect)` + + Returns a new :class:`Surface `, + with the text rendered to it + in the color given by 'fgcolor'. If no foreground color is given, + the default foreground color, :attr:`fgcolor ` is used. + If ``bgcolor`` is given, the surface + will be filled with this color. When no background color is given, + the surface background is transparent, zero alpha. Normally the returned + surface has a 32 bit pixel size. However, if ``bgcolor`` is ``None`` + and anti-aliasing is disabled a monochrome 8 bit colorkey surface, + with colorkey set for the background color, is returned. + + The return value is a tuple: the new surface and the bounding + rectangle giving the size and origin of the rendered text. + + If an empty string is passed for text then the returned Rect is zero + width and the height of the font. + + Optional *fgcolor*, *style*, *rotation*, and *size* arguments override + the default values set for the :class:`Font` instance. + + If *text* is a char (byte) string, then its encoding is assumed to be + ``LATIN1``. + + Optionally, *text* can be ``None``, which will render the text + passed to a previous :meth:`get_rect`, :meth:`render`, :meth:`render_to`, + :meth:`render_raw`, or :meth:`render_raw_to` call. + See :meth:`render_to` for details. + + .. method:: render_to + + | :sl:`Render text onto an existing surface` + | :sg:`render_to(surf, dest, text, fgcolor=None, bgcolor=None, style=STYLE_DEFAULT, rotation=0, size=0) -> Rect` + + Renders the string *text* to the :mod:`pygame.Surface` *surf*, + at position *dest*, a (x, y) surface coordinate pair. + If either x or y is not an integer it is converted to one if possible. + Any sequence where the first two items are x and y positional elements + is accepted, including a :class:`Rect ` instance. + As with :meth:`render`, + optional *fgcolor*, *style*, *rotation*, and *size* argument are + available. + + If a background color *bgcolor* is given, the text bounding box is + first filled with that color. The text is blitted next. + Both the background fill and text rendering involve full alpha blits. + That is, the alpha values of the foreground, background, and destination + target surface all affect the blit. + + The return value is a rectangle giving the size and position of the + rendered text within the surface. + + If an empty string is passed for text then the returned + :class:`Rect ` is zero width and the height of the font. + The rect will test False. + + Optionally, *text* can be set ``None``, which will re-render text + passed to a previous :meth:`render_to`, :meth:`get_rect`, :meth:`render`, + :meth:`render_raw`, or :meth:`render_raw_to` call. Primarily, this + feature is an aid to using :meth:`render_to` in combination with + :meth:`get_rect`. An example: :: + + def word_wrap(surf, text, font, color=(0, 0, 0)): + font.origin = True + words = text.split(' ') + width, height = surf.get_size() + line_spacing = font.get_sized_height() + 2 + x, y = 0, line_spacing + space = font.get_rect(' ') + for word in words: + bounds = font.get_rect(word) + if x + bounds.width + bounds.x >= width: + x, y = 0, y + line_spacing + if x + bounds.width + bounds.x >= width: + raise ValueError("word too wide for the surface") + if y + bounds.height - bounds.y >= height: + raise ValueError("text to long for the surface") + font.render_to(surf, (x, y), None, color) + x += bounds.width + space.width + return x, y + + When :meth:`render_to` is called with the same + font properties ― :attr:`size`, :attr:`style`, :attr:`strength`, + :attr:`wide`, :attr:`antialiased`, :attr:`vertical`, :attr:`rotation`, + :attr:`kerning`, and :attr:`use_bitmap_strikes` ― as :meth:`get_rect`, + :meth:`render_to` will use the layout calculated by :meth:`get_rect`. + Otherwise, :meth:`render_to` will recalculate the layout if called + with a text string or one of the above properties has changed + after the :meth:`get_rect` call. + + If *text* is a char (byte) string, then its encoding is assumed to be + ``LATIN1``. + + .. method:: render_raw + + | :sl:`Return rendered text as a string of bytes` + | :sg:`render_raw(text, style=STYLE_DEFAULT, rotation=0, size=0, invert=False) -> (bytes, (int, int))` + + Like :meth:`render` but with the pixels returned as a byte string + of 8-bit gray-scale values. The foreground color is 255, the + background 0, useful as an alpha mask for a foreground pattern. + + .. method:: render_raw_to + + | :sl:`Render text into an array of ints` + | :sg:`render_raw_to(array, text, dest=None, style=STYLE_DEFAULT, rotation=0, size=0, invert=False) -> Rect` + + Render to an array object exposing an array struct interface. The array + must be two dimensional with integer items. The default *dest* value, + ``None``, is equivalent to position (0, 0). See :meth:`render_to`. + As with the other render methods, *text* can be ``None`` to + render a text string passed previously to another method. + + The return value is a :func:`pygame.Rect` giving the size and position of + the rendered text. + + .. attribute:: style + + | :sl:`The font's style flags` + | :sg:`style -> int` + + Gets or sets the default style of the Font. This default style will be + used for all text rendering and size calculations unless overridden + specifically a render or :meth:`get_rect` call. + The style value may be a bit-wise OR of one or more of the following + constants: + + :: + + STYLE_NORMAL + STYLE_UNDERLINE + STYLE_OBLIQUE + STYLE_STRONG + STYLE_WIDE + STYLE_DEFAULT + + These constants may be found on the FreeType constants module. + Optionally, the default style can be modified or obtained accessing the + individual style attributes (underline, oblique, strong). + + The ``STYLE_OBLIQUE`` and ``STYLE_STRONG`` styles are for + scalable fonts only. An attempt to set either for a bitmap font raises + an AttributeError. An attempt to set either for an inactive font, + as returned by ``Font.__new__()``, raises a RuntimeError. + + Assigning ``STYLE_DEFAULT`` to the :attr:`style` property leaves + the property unchanged, as this property defines the default. + The :attr:`style` property will never return ``STYLE_DEFAULT``. + + .. attribute:: underline + + | :sl:`The state of the font's underline style flag` + | :sg:`underline -> bool` + + Gets or sets whether the font will be underlined when drawing text. This + default style value will be used for all text rendering and size + calculations unless overridden specifically in a render or + :meth:`get_rect` call, via the 'style' parameter. + + .. attribute:: strong + + | :sl:`The state of the font's strong style flag` + | :sg:`strong -> bool` + + Gets or sets whether the font will be bold when drawing text. This + default style value will be used for all text rendering and size + calculations unless overridden specifically in a render or + :meth:`get_rect` call, via the 'style' parameter. + + .. attribute:: oblique + + | :sl:`The state of the font's oblique style flag` + | :sg:`oblique -> bool` + + Gets or sets whether the font will be rendered as oblique. This + default style value will be used for all text rendering and size + calculations unless overridden specifically in a render or + :meth:`get_rect` call, via the *style* parameter. + + The oblique style is only supported for scalable (outline) fonts. + An attempt to set this style on a bitmap font will raise an + AttributeError. If the font object is inactive, as returned by + ``Font.__new__()``, setting this property raises a RuntimeError. + + .. attribute:: wide + + | :sl:`The state of the font's wide style flag` + | :sg:`wide -> bool` + + Gets or sets whether the font will be stretched horizontally + when drawing text. It produces a result similar to + :class:`pygame.font.Font`'s bold. This style not available for + rotated text. + + .. attribute:: strength + + | :sl:`The strength associated with the strong or wide font styles` + | :sg:`strength -> float` + + The amount by which a font glyph's size is enlarged for the + strong or wide transformations, as a fraction of the untransformed + size. For the wide style only the horizontal dimension is + increased. For strong text both the horizontal and vertical + dimensions are enlarged. A wide style of strength 0.08333 ( 1/12 ) is + equivalent to the :class:`pygame.font.Font` bold style. + The default is 0.02778 ( 1/36 ). + + The strength style is only supported for scalable (outline) fonts. + An attempt to set this property on a bitmap font will raise an + AttributeError. If the font object is inactive, as returned by + ``Font.__new__()``, assignment to this property raises a RuntimeError. + + .. attribute:: underline_adjustment + + | :sl:`Adjustment factor for the underline position` + | :sg:`underline_adjustment -> float` + + Gets or sets a factor which, when positive, is multiplied with the + font's underline offset to adjust the underline position. A negative + value turns an underline into a strike-through or overline. It is + multiplied with the ascender. Accepted values range between -2.0 and 2.0 + inclusive. A value of 0.5 closely matches Tango underlining. A value of + 1.0 mimics :class:`pygame.font.Font` underlining. + + .. attribute:: fixed_width + + | :sl:`Gets whether the font is fixed-width` + | :sg:`fixed_width -> bool` + + Read only. Returns ``True`` if the font contains fixed-width + characters (for example Courier, Bitstream Vera Sans Mono, Andale Mono). + + .. attribute:: fixed_sizes + + | :sl:`the number of available bitmap sizes for the font` + | :sg:`fixed_sizes -> int` + + Read only. Returns the number of point sizes for which the font contains + bitmap character images. If zero then the font is not a bitmap font. + A scalable font may contain pre-rendered point sizes as strikes. + + .. attribute:: scalable + + | :sl:`Gets whether the font is scalable` + | :sg:`scalable -> bool` + + Read only. Returns ``True`` if the font contains outline glyphs. + If so, the point size is not limited to available bitmap sizes. + + .. attribute:: use_bitmap_strikes + + | :sl:`allow the use of embedded bitmaps in an outline font file` + | :sg:`use_bitmap_strikes -> bool` + + Some scalable fonts include embedded bitmaps for particular point + sizes. This property controls whether or not those bitmap strikes + are used. Set it ``False`` to disable the loading of any bitmap + strike. Set it ``True``, the default, to permit bitmap strikes + for a non-rotated render with no style other than :attr:`wide` or + :attr:`underline`. This property is ignored for bitmap fonts. + + See also :attr:`fixed_sizes` and :meth:`get_sizes`. + + .. attribute:: antialiased + + | :sl:`Font anti-aliasing mode` + | :sg:`antialiased -> bool` + + Gets or sets the font's anti-aliasing mode. This defaults to + ``True`` on all fonts, which are rendered with full 8 bit blending. + + Set to ``False`` to do monochrome rendering. This should + provide a small speed gain and reduce cache memory size. + + .. attribute:: kerning + + | :sl:`Character kerning mode` + | :sg:`kerning -> bool` + + Gets or sets the font's kerning mode. This defaults to ``False`` + on all fonts, which will be rendered without kerning. + + Set to ``True`` to add kerning between character pairs, if supported + by the font, when positioning glyphs. + + .. attribute:: vertical + + | :sl:`Font vertical mode` + | :sg:`vertical -> bool` + + Gets or sets whether the characters are laid out vertically rather + than horizontally. May be useful when rendering Kanji or some other + vertical script. + + Set to ``True`` to switch to a vertical text layout. The default + is ``False``, place horizontally. + + Note that the :class:`Font` class does not automatically determine + script orientation. Vertical layout must be selected explicitly. + + Also note that several font formats (especially bitmap based ones) don't + contain the necessary metrics to draw glyphs vertically, so drawing in + those cases will give unspecified results. + + .. attribute:: rotation + + | :sl:`text rotation in degrees counterclockwise` + | :sg:`rotation -> int` + + Gets or sets the baseline angle of the rendered text. The angle is + represented as integer degrees. The default angle is 0, with horizontal + text rendered along the X-axis, and vertical text along the Y-axis. + A positive value rotates these axes counterclockwise that many degrees. + A negative angle corresponds to a clockwise rotation. The rotation + value is normalized to a value within the range 0 to 359 inclusive + (eg. 390 -> 390 - 360 -> 30, -45 -> 360 + -45 -> 315, + 720 -> 720 - (2 * 360) -> 0). + + Only scalable (outline) fonts can be rotated. An attempt to change + the rotation of a bitmap font raises an AttributeError. + An attempt to change the rotation of an inactive font instance, as + returned by ``Font.__new__()``, raises a RuntimeError. + + .. attribute:: fgcolor + + | :sl:`default foreground color` + | :sg:`fgcolor -> Color` + + Gets or sets the default glyph rendering color. It is initially opaque + black ― (0, 0, 0, 255). Applies to :meth:`render` and :meth:`render_to`. + + .. attribute:: bgcolor + + | :sl:`default background color` + | :sg:`bgcolor -> Color` + + Gets or sets the default background rendering color. Initially it is + unset and text will render with a transparent background by default. + Applies to :meth:`render` and :meth:`render_to`. + + .. versionadded:: 2.0.0 + + .. attribute:: origin + + | :sl:`Font render to text origin mode` + | :sg:`origin -> bool` + + If set ``True``, :meth:`render_to` and :meth:`render_raw_to` will + take the *dest* position to be that of the text origin, as opposed to + the top-left corner of the bounding box. See :meth:`get_rect` for + details. + + .. attribute:: pad + + | :sl:`padded boundary mode` + | :sg:`pad -> bool` + + If set ``True``, then the text boundary rectangle will be inflated + to match that of :class:`font.Font `. + Otherwise, the boundary rectangle is just large enough for the text. + + .. attribute:: ucs4 + + | :sl:`Enable UCS-4 mode` + | :sg:`ucs4 -> bool` + + Gets or sets the decoding of Unicode text. By default, the + freetype module performs UTF-16 surrogate pair decoding on Unicode text. + This allows 32-bit escape sequences ('\Uxxxxxxxx') between 0x10000 and + 0x10FFFF to represent their corresponding UTF-32 code points on Python + interpreters built with a UCS-2 Unicode type (on Windows, for instance). + It also means character values within the UTF-16 surrogate area (0xD800 + to 0xDFFF) are considered part of a surrogate pair. A malformed surrogate + pair will raise a UnicodeEncodeError. Setting ucs4 ``True`` turns + surrogate pair decoding off, allowing access the full UCS-4 character + range to a Python interpreter built with four-byte Unicode character + support. + + .. attribute:: resolution + + | :sl:`Pixel resolution in dots per inch` + | :sg:`resolution -> int` + + Read only. Gets pixel size used in scaling font glyphs for this + :class:`Font` instance. diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/gfxdraw.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/gfxdraw.rst.txt new file mode 100644 index 0000000..28153a3 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/gfxdraw.rst.txt @@ -0,0 +1,628 @@ +.. include:: common.txt + +:mod:`pygame.gfxdraw` +===================== + +.. module:: pygame.gfxdraw + :synopsis: pygame module for drawing shapes + +| :sl:`pygame module for drawing shapes` + +**EXPERIMENTAL!**: This API may change or disappear in later pygame releases. If +you use this, your code may break with the next pygame release. + +The pygame package does not import gfxdraw automatically when loaded, so it +must imported explicitly to be used. + +:: + + import pygame + import pygame.gfxdraw + +For all functions the arguments are strictly positional and integers are +accepted for coordinates and radii. The ``color`` argument can be one of the +following formats: + + - a :mod:`pygame.Color` object + - an ``(RGB)`` triplet (tuple/list) + - an ``(RGBA)`` quadruplet (tuple/list) + +The functions :meth:`rectangle` and :meth:`box` will accept any ``(x, y, w, h)`` +sequence for their ``rect`` argument, though :mod:`pygame.Rect` instances are +preferred. + +To draw a filled antialiased shape, first use the antialiased (aa*) version +of the function, and then use the filled (filled_*) version. +For example: + +:: + + col = (255, 0, 0) + surf.fill((255, 255, 255)) + pygame.gfxdraw.aacircle(surf, x, y, 30, col) + pygame.gfxdraw.filled_circle(surf, x, y, 30, col) + + +.. note:: + For threading, each of the functions releases the GIL during the C part of + the call. + +.. note:: + See the :mod:`pygame.draw` module for alternative draw methods. + The ``pygame.gfxdraw`` module differs from the :mod:`pygame.draw` module in + the API it uses and the different draw functions available. + ``pygame.gfxdraw`` wraps the primitives from the library called SDL_gfx, + rather than using modified versions. + +.. versionadded:: 1.9.0 + + +.. function:: pixel + + | :sl:`draw a pixel` + | :sg:`pixel(surface, x, y, color) -> None` + + Draws a single pixel, at position (x ,y), on the given surface. + + :param Surface surface: surface to draw on + :param int x: x coordinate of the pixel + :param int y: y coordinate of the pixel + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.pixel ## + +.. function:: hline + + | :sl:`draw a horizontal line` + | :sg:`hline(surface, x1, x2, y, color) -> None` + + Draws a straight horizontal line (``(x1, y)`` to ``(x2, y)``) on the given + surface. There are no endcaps. + + :param Surface surface: surface to draw on + :param int x1: x coordinate of one end of the line + :param int x2: x coordinate of the other end of the line + :param int y: y coordinate of the line + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.hline ## + +.. function:: vline + + | :sl:`draw a vertical line` + | :sg:`vline(surface, x, y1, y2, color) -> None` + + Draws a straight vertical line (``(x, y1)`` to ``(x, y2)``) on the given + surface. There are no endcaps. + + :param Surface surface: surface to draw on + :param int x: x coordinate of the line + :param int y1: y coordinate of one end of the line + :param int y2: y coordinate of the other end of the line + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.vline ## + +.. function:: line + + | :sl:`draw a line` + | :sg:`line(surface, x1, y1, x2, y2, color) -> None` + + Draws a straight line (``(x1, y1)`` to ``(x2, y2)``) on the given surface. + There are no endcaps. + + :param Surface surface: surface to draw on + :param int x1: x coordinate of one end of the line + :param int y1: y coordinate of one end of the line + :param int x2: x coordinate of the other end of the line + :param int y2: y coordinate of the other end of the line + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.line ## + +.. function:: rectangle + + | :sl:`draw a rectangle` + | :sg:`rectangle(surface, rect, color) -> None` + + Draws an unfilled rectangle on the given surface. For a filled rectangle use + :meth:`box`. + + :param Surface surface: surface to draw on + :param Rect rect: rectangle to draw, position and dimensions + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. note:: + The ``rect.bottom`` and ``rect.right`` attributes of a :mod:`pygame.Rect` + always lie one pixel outside of its actual border. Therefore, these + values will not be included as part of the drawing. + + .. ## pygame.gfxdraw.rectangle ## + +.. function:: box + + | :sl:`draw a filled rectangle` + | :sg:`box(surface, rect, color) -> None` + + Draws a filled rectangle on the given surface. For an unfilled rectangle use + :meth:`rectangle`. + + :param Surface surface: surface to draw on + :param Rect rect: rectangle to draw, position and dimensions + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. note:: + The ``rect.bottom`` and ``rect.right`` attributes of a :mod:`pygame.Rect` + always lie one pixel outside of its actual border. Therefore, these + values will not be included as part of the drawing. + + .. note:: + The :func:`pygame.Surface.fill` method works just as well for drawing + filled rectangles. In fact :func:`pygame.Surface.fill` can be hardware + accelerated on some platforms with both software and hardware display + modes. + + .. ## pygame.gfxdraw.box ## + +.. function:: circle + + | :sl:`draw a circle` + | :sg:`circle(surface, x, y, r, color) -> None` + + Draws an unfilled circle on the given surface. For a filled circle use + :meth:`filled_circle`. + + :param Surface surface: surface to draw on + :param int x: x coordinate of the center of the circle + :param int y: y coordinate of the center of the circle + :param int r: radius of the circle + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.circle ## + +.. function:: aacircle + + | :sl:`draw an antialiased circle` + | :sg:`aacircle(surface, x, y, r, color) -> None` + + Draws an unfilled antialiased circle on the given surface. + + :param Surface surface: surface to draw on + :param int x: x coordinate of the center of the circle + :param int y: y coordinate of the center of the circle + :param int r: radius of the circle + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.aacircle ## + +.. function:: filled_circle + + | :sl:`draw a filled circle` + | :sg:`filled_circle(surface, x, y, r, color) -> None` + + Draws a filled circle on the given surface. For an unfilled circle use + :meth:`circle`. + + :param Surface surface: surface to draw on + :param int x: x coordinate of the center of the circle + :param int y: y coordinate of the center of the circle + :param int r: radius of the circle + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.filled_circle ## + +.. function:: ellipse + + | :sl:`draw an ellipse` + | :sg:`ellipse(surface, x, y, rx, ry, color) -> None` + + Draws an unfilled ellipse on the given surface. For a filled ellipse use + :meth:`filled_ellipse`. + + :param Surface surface: surface to draw on + :param int x: x coordinate of the center of the ellipse + :param int y: y coordinate of the center of the ellipse + :param int rx: horizontal radius of the ellipse + :param int ry: vertical radius of the ellipse + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.ellipse ## + +.. function:: aaellipse + + | :sl:`draw an antialiased ellipse` + | :sg:`aaellipse(surface, x, y, rx, ry, color) -> None` + + Draws an unfilled antialiased ellipse on the given surface. + + :param Surface surface: surface to draw on + :param int x: x coordinate of the center of the ellipse + :param int y: y coordinate of the center of the ellipse + :param int rx: horizontal radius of the ellipse + :param int ry: vertical radius of the ellipse + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.aaellipse ## + +.. function:: filled_ellipse + + | :sl:`draw a filled ellipse` + | :sg:`filled_ellipse(surface, x, y, rx, ry, color) -> None` + + Draws a filled ellipse on the given surface. For an unfilled ellipse use + :meth:`ellipse`. + + :param Surface surface: surface to draw on + :param int x: x coordinate of the center of the ellipse + :param int y: y coordinate of the center of the ellipse + :param int rx: horizontal radius of the ellipse + :param int ry: vertical radius of the ellipse + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.filled_ellipse ## + +.. function:: arc + + | :sl:`draw an arc` + | :sg:`arc(surface, x, y, r, start_angle, stop_angle, color) -> None` + + Draws an arc on the given surface. For an arc with its endpoints connected + to its center use :meth:`pie`. + + The two angle arguments are given in degrees and indicate the start and stop + positions of the arc. The arc is drawn in a clockwise direction from the + ``start_angle`` to the ``stop_angle``. If ``start_angle == stop_angle``, + nothing will be drawn + + :param Surface surface: surface to draw on + :param int x: x coordinate of the center of the arc + :param int y: y coordinate of the center of the arc + :param int r: radius of the arc + :param int start_angle: start angle in degrees + :param int stop_angle: stop angle in degrees + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. note:: + This function uses *degrees* while the :func:`pygame.draw.arc` function + uses *radians*. + + .. ## pygame.gfxdraw.arc ## + +.. function:: pie + + | :sl:`draw a pie` + | :sg:`pie(surface, x, y, r, start_angle, stop_angle, color) -> None` + + Draws an unfilled pie on the given surface. A pie is an :meth:`arc` with its + endpoints connected to its center. + + The two angle arguments are given in degrees and indicate the start and stop + positions of the pie. The pie is drawn in a clockwise direction from the + ``start_angle`` to the ``stop_angle``. If ``start_angle == stop_angle``, + a straight line will be drawn from the center position at the given angle, + to a length of the radius. + + :param Surface surface: surface to draw on + :param int x: x coordinate of the center of the pie + :param int y: y coordinate of the center of the pie + :param int r: radius of the pie + :param int start_angle: start angle in degrees + :param int stop_angle: stop angle in degrees + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.pie ## + +.. function:: trigon + + | :sl:`draw a trigon/triangle` + | :sg:`trigon(surface, x1, y1, x2, y2, x3, y3, color) -> None` + + Draws an unfilled trigon (triangle) on the given surface. For a filled + trigon use :meth:`filled_trigon`. + + A trigon can also be drawn using :meth:`polygon` e.g. + ``polygon(surface, ((x1, y1), (x2, y2), (x3, y3)), color)`` + + :param Surface surface: surface to draw on + :param int x1: x coordinate of the first corner of the trigon + :param int y1: y coordinate of the first corner of the trigon + :param int x2: x coordinate of the second corner of the trigon + :param int y2: y coordinate of the second corner of the trigon + :param int x3: x coordinate of the third corner of the trigon + :param int y3: y coordinate of the third corner of the trigon + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.trigon ## + +.. function:: aatrigon + + | :sl:`draw an antialiased trigon/triangle` + | :sg:`aatrigon(surface, x1, y1, x2, y2, x3, y3, color) -> None` + + Draws an unfilled antialiased trigon (triangle) on the given surface. + + An aatrigon can also be drawn using :meth:`aapolygon` e.g. + ``aapolygon(surface, ((x1, y1), (x2, y2), (x3, y3)), color)`` + + :param Surface surface: surface to draw on + :param int x1: x coordinate of the first corner of the trigon + :param int y1: y coordinate of the first corner of the trigon + :param int x2: x coordinate of the second corner of the trigon + :param int y2: y coordinate of the second corner of the trigon + :param int x3: x coordinate of the third corner of the trigon + :param int y3: y coordinate of the third corner of the trigon + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.aatrigon ## + +.. function:: filled_trigon + + | :sl:`draw a filled trigon/triangle` + | :sg:`filled_trigon(surface, x1, y1, x2, y2, x3, y3, color) -> None` + + Draws a filled trigon (triangle) on the given surface. For an unfilled + trigon use :meth:`trigon`. + + A filled_trigon can also be drawn using :meth:`filled_polygon` e.g. + ``filled_polygon(surface, ((x1, y1), (x2, y2), (x3, y3)), color)`` + + :param Surface surface: surface to draw on + :param int x1: x coordinate of the first corner of the trigon + :param int y1: y coordinate of the first corner of the trigon + :param int x2: x coordinate of the second corner of the trigon + :param int y2: y coordinate of the second corner of the trigon + :param int x3: x coordinate of the third corner of the trigon + :param int y3: y coordinate of the third corner of the trigon + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + .. ## pygame.gfxdraw.filled_trigon ## + +.. function:: polygon + + | :sl:`draw a polygon` + | :sg:`polygon(surface, points, color) -> None` + + Draws an unfilled polygon on the given surface. For a filled polygon use + :meth:`filled_polygon`. + + The adjacent coordinates in the ``points`` argument, as well as the first + and last points, will be connected by line segments. + e.g. For the points ``[(x1, y1), (x2, y2), (x3, y3)]`` a line segment will + be drawn from ``(x1, y1)`` to ``(x2, y2)``, from ``(x2, y2)`` to + ``(x3, y3)``, and from ``(x3, y3)`` to ``(x1, y1)``. + + :param Surface surface: surface to draw on + :param points: a sequence of 3 or more (x, y) coordinates, where each + *coordinate* in the sequence must be a + tuple/list/:class:`pygame.math.Vector2` of 2 ints/floats (float values + will be truncated) + :type points: tuple(coordinate) or list(coordinate) + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + :raises ValueError: if ``len(points) < 3`` (must have at least 3 points) + :raises IndexError: if ``len(coordinate) < 2`` (each coordinate must have + at least 2 items) + + .. ## pygame.gfxdraw.polygon ## + +.. function:: aapolygon + + | :sl:`draw an antialiased polygon` + | :sg:`aapolygon(surface, points, color) -> None` + + Draws an unfilled antialiased polygon on the given surface. + + The adjacent coordinates in the ``points`` argument, as well as the first + and last points, will be connected by line segments. + e.g. For the points ``[(x1, y1), (x2, y2), (x3, y3)]`` a line segment will + be drawn from ``(x1, y1)`` to ``(x2, y2)``, from ``(x2, y2)`` to + ``(x3, y3)``, and from ``(x3, y3)`` to ``(x1, y1)``. + + :param Surface surface: surface to draw on + :param points: a sequence of 3 or more (x, y) coordinates, where each + *coordinate* in the sequence must be a + tuple/list/:class:`pygame.math.Vector2` of 2 ints/floats (float values + will be truncated) + :type points: tuple(coordinate) or list(coordinate) + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + :raises ValueError: if ``len(points) < 3`` (must have at least 3 points) + :raises IndexError: if ``len(coordinate) < 2`` (each coordinate must have + at least 2 items) + + .. ## pygame.gfxdraw.aapolygon ## + +.. function:: filled_polygon + + | :sl:`draw a filled polygon` + | :sg:`filled_polygon(surface, points, color) -> None` + + Draws a filled polygon on the given surface. For an unfilled polygon use + :meth:`polygon`. + + The adjacent coordinates in the ``points`` argument, as well as the first + and last points, will be connected by line segments. + e.g. For the points ``[(x1, y1), (x2, y2), (x3, y3)]`` a line segment will + be drawn from ``(x1, y1)`` to ``(x2, y2)``, from ``(x2, y2)`` to + ``(x3, y3)``, and from ``(x3, y3)`` to ``(x1, y1)``. + + :param Surface surface: surface to draw on + :param points: a sequence of 3 or more (x, y) coordinates, where each + *coordinate* in the sequence must be a + tuple/list/:class:`pygame.math.Vector2` of 2 ints/floats (float values + will be truncated)` + :type points: tuple(coordinate) or list(coordinate) + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + :raises ValueError: if ``len(points) < 3`` (must have at least 3 points) + :raises IndexError: if ``len(coordinate) < 2`` (each coordinate must have + at least 2 items) + + .. ## pygame.gfxdraw.filled_polygon ## + +.. function:: textured_polygon + + | :sl:`draw a textured polygon` + | :sg:`textured_polygon(surface, points, texture, tx, ty) -> None` + + Draws a textured polygon on the given surface. For better performance, the + surface and the texture should have the same format. + + A per-pixel alpha texture blit to a per-pixel alpha surface will differ from + a :func:`pygame.Surface.blit` blit. Also, a per-pixel alpha texture cannot be + used with an 8-bit per pixel destination. + + The adjacent coordinates in the ``points`` argument, as well as the first + and last points, will be connected by line segments. + e.g. For the points ``[(x1, y1), (x2, y2), (x3, y3)]`` a line segment will + be drawn from ``(x1, y1)`` to ``(x2, y2)``, from ``(x2, y2)`` to + ``(x3, y3)``, and from ``(x3, y3)`` to ``(x1, y1)``. + + :param Surface surface: surface to draw on + :param points: a sequence of 3 or more (x, y) coordinates, where each + *coordinate* in the sequence must be a + tuple/list/:class:`pygame.math.Vector2` of 2 ints/floats (float values + will be truncated) + :type points: tuple(coordinate) or list(coordinate) + :param Surface texture: texture to draw on the polygon + :param int tx: x offset of the texture + :param int ty: y offset of the texture + + :returns: ``None`` + :rtype: NoneType + + :raises ValueError: if ``len(points) < 3`` (must have at least 3 points) + :raises IndexError: if ``len(coordinate) < 2`` (each coordinate must have + at least 2 items) + + .. ## pygame.gfxdraw.textured_polygon ## + +.. function:: bezier + + | :sl:`draw a Bezier curve` + | :sg:`bezier(surface, points, steps, color) -> None` + + Draws a Bézier curve on the given surface. + + :param Surface surface: surface to draw on + :param points: a sequence of 3 or more (x, y) coordinates used to form a + curve, where each *coordinate* in the sequence must be a + tuple/list/:class:`pygame.math.Vector2` of 2 ints/floats (float values + will be truncated) + :type points: tuple(coordinate) or list(coordinate) + :param int steps: number of steps for the interpolation, the minimum is 2 + :param color: color to draw with, the alpha value is optional if using a + tuple ``(RGB[A])`` + :type color: Color or tuple(int, int, int, [int]) + + :returns: ``None`` + :rtype: NoneType + + :raises ValueError: if ``steps < 2`` + :raises ValueError: if ``len(points) < 3`` (must have at least 3 points) + :raises IndexError: if ``len(coordinate) < 2`` (each coordinate must have + at least 2 items) + + .. ## pygame.gfxdraw.bezier ## + +.. ## pygame.gfxdraw ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/image.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/image.rst.txt new file mode 100644 index 0000000..ee4d238 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/image.rst.txt @@ -0,0 +1,284 @@ +.. include:: common.txt + +:mod:`pygame.image` +=================== + +.. module:: pygame.image + :synopsis: pygame module for image transfer + +| :sl:`pygame module for image transfer` + +The image module contains functions for loading and saving pictures, as well as +transferring Surfaces to formats usable by other packages. + +Note that there is no Image class; an image is loaded as a Surface object. The +Surface class allows manipulation (drawing lines, setting pixels, capturing +regions, etc.). + +The image module is a required dependency of pygame, but it only optionally +supports any extended file formats. By default it can only load uncompressed +``BMP`` images. When built with full image support, the ``pygame.image.load()`` +function can support the following formats. + + * ``BMP`` + + * ``GIF`` (non-animated) + + * ``JPEG`` + + * ``LBM`` (and ``PBM``, ``PGM``, ``PPM``) + + * ``PCX`` + + * ``PNG`` + + * ``PNM`` + + * ``SVG`` (limited support, using Nano SVG) + + * ``TGA`` (uncompressed) + + * ``TIFF`` + + * ``WEBP`` + + * ``XPM`` + + +.. versionadded:: 2.0 Loading SVG, WebP, PNM + +Saving images only supports a limited set of formats. You can save to the +following formats. + + * ``BMP`` + + * ``JPEG`` + + * ``PNG`` + + * ``TGA`` + + +``JPEG`` and ``JPG``, as well as ``TIF`` and ``TIFF`` refer to the same file format + +.. versionadded:: 1.8 Saving PNG and JPEG files. + + +.. function:: load + + | :sl:`load new image from a file (or file-like object)` + | :sg:`load(filename) -> Surface` + | :sg:`load(fileobj, namehint="") -> Surface` + + Load an image from a file source. You can pass either a filename, a Python + file-like object, or a pathlib.Path. + + Pygame will automatically determine the image type (e.g., ``GIF`` or bitmap) + and create a new Surface object from the data. In some cases it will need to + know the file extension (e.g., ``GIF`` images should end in ".gif"). If you + pass a raw file-like object, you may also want to pass the original filename + as the namehint argument. + + The returned Surface will contain the same color format, colorkey and alpha + transparency as the file it came from. You will often want to call + ``Surface.convert()`` with no arguments, to create a copy that will draw + more quickly on the screen. + + For alpha transparency, like in .png images, use the ``convert_alpha()`` + method after loading so that the image has per pixel transparency. + + pygame may not always be built to support all image formats. At minimum it + will support uncompressed ``BMP``. If ``pygame.image.get_extended()`` + returns 'True', you should be able to load most images (including PNG, JPG + and GIF). + + You should use ``os.path.join()`` for compatibility. + + :: + + eg. asurf = pygame.image.load(os.path.join('data', 'bla.png')) + + .. ## pygame.image.load ## + +.. function:: save + + | :sl:`save an image to file (or file-like object)` + | :sg:`save(Surface, filename) -> None` + | :sg:`save(Surface, fileobj, namehint="") -> None` + + This will save your Surface as either a ``BMP``, ``TGA``, ``PNG``, or + ``JPEG`` image. If the filename extension is unrecognized it will default to + ``TGA``. Both ``TGA``, and ``BMP`` file formats create uncompressed files. + You can pass a filename, a pathlib.Path or a Python file-like object. + For file-like object, the image is saved to ``TGA`` format unless + a namehint with a recognizable extension is passed in. + + .. note:: When saving to a file-like object, it seems that for most formats, + the object needs to be flushed after saving to it to make loading + from it possible. + + .. versionchanged:: 1.8 Saving PNG and JPEG files. + .. versionchanged:: 2.0.0 + The ``namehint`` parameter was added to make it possible + to save other formats than ``TGA`` to a file-like object. + Saving to a file-like object with JPEG is possible. + + .. ## pygame.image.save ## + +.. function:: get_sdl_image_version + + | :sl:`get version number of the SDL_Image library being used` + | :sg:`get_sdl_image_version() -> None` + | :sg:`get_sdl_image_version() -> (major, minor, patch)` + + If pygame is built with extended image formats, then this function will + return the SDL_Image library's version number as a tuple of 3 integers + ``(major, minor, patch)``. If not, then it will return ``None``. + + .. versionadded:: 2.0.0 + + .. ## pygame.image.get_sdl_image_version ## + +.. function:: get_extended + + | :sl:`test if extended image formats can be loaded` + | :sg:`get_extended() -> bool` + + If pygame is built with extended image formats this function will return + True. It is still not possible to determine which formats will be available, + but generally you will be able to load them all. + + .. ## pygame.image.get_extended ## + +.. function:: tostring + + | :sl:`transfer image to string buffer` + | :sg:`tostring(Surface, format, flipped=False) -> string` + + Creates a string that can be transferred with the 'fromstring' method in + other Python imaging packages. Some Python image packages prefer their + images in bottom-to-top format (PyOpenGL for example). If you pass True for + the flipped argument, the string buffer will be vertically flipped. + + The format argument is a string of one of the following values. Note that + only 8-bit Surfaces can use the "P" format. The other formats will work for + any Surface. Also note that other Python image packages support more formats + than pygame. + + * ``P``, 8-bit palettized Surfaces + + * ``RGB``, 24-bit image + + * ``RGBX``, 32-bit image with unused space + + * ``RGBA``, 32-bit image with an alpha channel + + * ``ARGB``, 32-bit image with alpha channel first + + * ``RGBA_PREMULT``, 32-bit image with colors scaled by alpha channel + + * ``ARGB_PREMULT``, 32-bit image with colors scaled by alpha channel, alpha channel first + + .. ## pygame.image.tostring ## + +.. function:: fromstring + + | :sl:`create new Surface from a string buffer` + | :sg:`fromstring(string, size, format, flipped=False) -> Surface` + + This function takes arguments similar to ``pygame.image.tostring()``. The + size argument is a pair of numbers representing the width and height. Once + the new Surface is created you can destroy the string buffer. + + The size and format image must compute the exact same size as the passed + string buffer. Otherwise an exception will be raised. + + See the ``pygame.image.frombuffer()`` method for a potentially faster way to + transfer images into pygame. + + .. ## pygame.image.fromstring ## + +.. function:: frombuffer + + | :sl:`create a new Surface that shares data inside a bytes buffer` + | :sg:`frombuffer(bytes, size, format) -> Surface` + + Create a new Surface that shares pixel data directly from a bytes buffer. + This method takes similar arguments to ``pygame.image.fromstring()``, but + is unable to vertically flip the source data. + + This will run much faster than :func:`pygame.image.fromstring`, since no + pixel data must be allocated and copied. + + It accepts the following 'format' arguments: + + * ``P``, 8-bit palettized Surfaces + + * ``RGB``, 24-bit image + + * ``BGR``, 24-bit image, red and blue channels swapped. + + * ``RGBX``, 32-bit image with unused space + + * ``RGBA``, 32-bit image with an alpha channel + + * ``ARGB``, 32-bit image with alpha channel first + + .. ## pygame.image.frombuffer ## + +.. function:: load_basic + + | :sl:`load new BMP image from a file (or file-like object)` + | :sg:`load_basic(file) -> Surface` + + Load an image from a file source. You can pass either a filename or a Python + file-like object, or a pathlib.Path. + + This function only supports loading "basic" image format, ie ``BMP`` + format. + This function is always available, no matter how pygame was built. + + .. ## pygame.image.load_basic ## + +.. function:: load_extended + + | :sl:`load an image from a file (or file-like object)` + | :sg:`load_extended(filename) -> Surface` + | :sg:`load_extended(fileobj, namehint="") -> Surface` + + This function is similar to ``pygame.image.load()``, except that this + function can only be used if pygame was built with extended image format + support. + + From version 2.0.1, this function is always available, but raises an + error if extended image formats are not supported. Previously, this + function may or may not be available, depending on the state of + extended image format support. + + .. versionchanged:: 2.0.1 + + .. ## pygame.image.load_extended ## + +.. function:: save_extended + + | :sl:`save a png/jpg image to file (or file-like object)` + | :sg:`save_extended(Surface, filename) -> None` + | :sg:`save_extended(Surface, fileobj, namehint="") -> None` + + This will save your Surface as either a ``PNG`` or ``JPEG`` image. + + Incase the image is being saved to a file-like object, this function + uses the namehint argument to determine the format of the file being + saved. Saves to ``JPEG`` incase the namehint was not specified while + saving to file-like object. + + .. versionchanged:: 2.0.1 + This function is always available, but raises an + error if extended image formats are not supported. + Previously, this function may or may not be + available, depending on the state of extended image + format support. + + .. ## pygame.image.save_extended ## + +.. ## pygame.image ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/joystick.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/joystick.rst.txt new file mode 100644 index 0000000..9b72b71 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/joystick.rst.txt @@ -0,0 +1,545 @@ +.. include:: common.txt + +:mod:`pygame.joystick` +====================== + +.. module:: pygame.joystick + :synopsis: Pygame module for interacting with joysticks, gamepads, and trackballs. + +| :sl:`Pygame module for interacting with joysticks, gamepads, and trackballs.` + +The joystick module manages the joystick devices on a computer. +Joystick devices include trackballs and video-game-style +gamepads, and the module allows the use of multiple buttons and "hats". +Computers may manage multiple joysticks at a time. + +Each instance of the Joystick class represents one gaming device plugged +into the computer. If a gaming pad has multiple joysticks on it, then the +joystick object can actually represent multiple joysticks on that single +game device. + +For a quick way to initialise the joystick module and get a list of Joystick instances +use the following code:: + + pygame.joystick.init() + joysticks = [pygame.joystick.Joystick(x) for x in range(pygame.joystick.get_count())] + +The following event types will be generated by the joysticks :: + + JOYAXISMOTION JOYBALLMOTION JOYBUTTONDOWN JOYBUTTONUP JOYHATMOTION + +And in pygame 2, which supports hotplugging:: + + JOYDEVICEADDED JOYDEVICEREMOVED + +Note that in pygame 2, joysticks events use a unique "instance ID". The device index +passed in the constructor to a Joystick object is not unique after devices have +been added and removed. You must call :meth:`Joystick.get_instance_id()` to find +the instance ID that was assigned to a Joystick on opening. + +The event queue needs to be pumped frequently for some of the methods to work. +So call one of pygame.event.get, pygame.event.wait, or pygame.event.pump regularly. + + +.. function:: init + + | :sl:`Initialize the joystick module.` + | :sg:`init() -> None` + + This function is called automatically by ``pygame.init()``. + + It initializes the joystick module. The module must be initialized before any + other functions will work. + + It is safe to call this function more than once. + + .. ## pygame.joystick.init ## + +.. function:: quit + + | :sl:`Uninitialize the joystick module.` + | :sg:`quit() -> None` + + Uninitialize the joystick module. After you call this any existing joystick + objects will no longer work. + + It is safe to call this function more than once. + + .. ## pygame.joystick.quit ## + +.. function:: get_init + + | :sl:`Returns True if the joystick module is initialized.` + | :sg:`get_init() -> bool` + + Test if the ``pygame.joystick.init()`` function has been called. + + .. ## pygame.joystick.get_init ## + +.. function:: get_count + + | :sl:`Returns the number of joysticks.` + | :sg:`get_count() -> count` + + Return the number of joystick devices on the system. The count will be ``0`` + if there are no joysticks on the system. + + When you create Joystick objects using ``Joystick(id)``, you pass an integer + that must be lower than this count. + + .. ## pygame.joystick.get_count ## + +.. class:: Joystick + + | :sl:`Create a new Joystick object.` + | :sg:`Joystick(id) -> Joystick` + + Create a new joystick to access a physical device. The id argument must be a + value from ``0`` to ``pygame.joystick.get_count() - 1``. + + Joysticks are initialised on creation and are shut down when deallocated. + Once the device is initialized the pygame event queue will start receiving + events about its input. + + .. versionchanged:: 2.0.0 Joystick objects are now opened immediately on creation. + + .. method:: init + + | :sl:`initialize the Joystick` + | :sg:`init() -> None` + + Initialize the joystick, if it has been closed. It is safe to call this + even if the joystick is already initialized. + + .. deprecated:: 2.0.0 + + In future it will not be possible to reinitialise a closed Joystick + object. Will be removed in Pygame 2.1. + + .. ## Joystick.init ## + + .. method:: quit + + | :sl:`uninitialize the Joystick` + | :sg:`quit() -> None` + + Close a Joystick object. After this the pygame event queue will no longer + receive events from the device. + + It is safe to call this more than once. + + .. ## Joystick.quit ## + + .. method:: get_init + + | :sl:`check if the Joystick is initialized` + | :sg:`get_init() -> bool` + + Return True if the Joystick object is currently initialised. + + .. ## Joystick.get_init ## + + .. method:: get_id + + | :sl:`get the device index (deprecated)` + | :sg:`get_id() -> int` + + Returns the original device index for this device. This is the same + value that was passed to the ``Joystick()`` constructor. This method can + safely be called while the Joystick is not initialized. + + .. deprecated:: 2.0.0 + + The original device index is not useful in pygame 2. Use + :meth:`.get_instance_id` instead. Will be removed in Pygame 2.1. + + .. method:: get_instance_id() -> int + + | :sl:`get the joystick instance id` + | :sg:`get_instance_id() -> int` + + Get the joystick instance ID. This matches the ``instance_id`` field + that is given in joystick events. + + .. versionadded:: 2.0.0dev11 + + .. method:: get_guid() -> str + + | :sl:`get the joystick GUID` + | :sg:`get_guid() -> str` + + Get the GUID string. This identifies the exact hardware of the joystick + device. + + .. versionadded:: 2.0.0dev11 + + .. method:: get_power_level() -> str + + | :sl:`get the approximate power status of the device` + | :sg:`get_power_level() -> str` + + Get a string giving the power status of the device. + + One of: ``empty``, ``low``, ``medium``, ``full``, ``wired``, ``max``, or + ``unknown``. + + .. versionadded:: 2.0.0dev11 + + .. ## Joystick.get_id ## + + .. method:: get_name + + | :sl:`get the Joystick system name` + | :sg:`get_name() -> string` + + Returns the system name for this joystick device. It is unknown what name + the system will give to the Joystick, but it should be a unique name that + identifies the device. This method can safely be called while the + Joystick is not initialized. + + .. ## Joystick.get_name ## + + .. method:: get_numaxes + + | :sl:`get the number of axes on a Joystick` + | :sg:`get_numaxes() -> int` + + Returns the number of input axes are on a Joystick. There will usually be + two for the position. Controls like rudders and throttles are treated as + additional axes. + + The ``pygame.JOYAXISMOTION`` events will be in the range from ``-1.0`` + to ``1.0``. A value of ``0.0`` means the axis is centered. Gamepad devices + will usually be ``-1``, ``0``, or ``1`` with no values in between. Older + analog joystick axes will not always use the full ``-1`` to ``1`` range, + and the centered value will be some area around ``0``. + + Analog joysticks usually have a bit of noise in their axis, which will + generate a lot of rapid small motion events. + + .. ## Joystick.get_numaxes ## + + .. method:: get_axis + + | :sl:`get the current position of an axis` + | :sg:`get_axis(axis_number) -> float` + + Returns the current position of a joystick axis. The value will range + from ``-1`` to ``1`` with a value of ``0`` being centered. You may want + to take into account some tolerance to handle jitter, and joystick drift + may keep the joystick from centering at ``0`` or using the full range of + position values. + + The axis number must be an integer from ``0`` to ``get_numaxes() - 1``. + + When using gamepads both the control sticks and the analog triggers are + usually reported as axes. + + .. ## Joystick.get_axis ## + + .. method:: get_numballs + + | :sl:`get the number of trackballs on a Joystick` + | :sg:`get_numballs() -> int` + + Returns the number of trackball devices on a Joystick. These devices work + similar to a mouse but they have no absolute position; they only have + relative amounts of movement. + + The ``pygame.JOYBALLMOTION`` event will be sent when the trackball is + rolled. It will report the amount of movement on the trackball. + + .. ## Joystick.get_numballs ## + + .. method:: get_ball + + | :sl:`get the relative position of a trackball` + | :sg:`get_ball(ball_number) -> x, y` + + Returns the relative movement of a joystick button. The value is a ``x, y`` + pair holding the relative movement since the last call to get_ball. + + The ball number must be an integer from ``0`` to ``get_numballs() - 1``. + + .. ## Joystick.get_ball ## + + .. method:: get_numbuttons + + | :sl:`get the number of buttons on a Joystick` + | :sg:`get_numbuttons() -> int` + + Returns the number of pushable buttons on the joystick. These buttons + have a boolean (on or off) state. + + Buttons generate a ``pygame.JOYBUTTONDOWN`` and ``pygame.JOYBUTTONUP`` + event when they are pressed and released. + + .. ## Joystick.get_numbuttons ## + + .. method:: get_button + + | :sl:`get the current button state` + | :sg:`get_button(button) -> bool` + + Returns the current state of a joystick button. + + .. ## Joystick.get_button ## + + .. method:: get_numhats + + | :sl:`get the number of hat controls on a Joystick` + | :sg:`get_numhats() -> int` + + Returns the number of joystick hats on a Joystick. Hat devices are like + miniature digital joysticks on a joystick. Each hat has two axes of + input. + + The ``pygame.JOYHATMOTION`` event is generated when the hat changes + position. The ``position`` attribute for the event contains a pair of + values that are either ``-1``, ``0``, or ``1``. A position of ``(0, 0)`` + means the hat is centered. + + .. ## Joystick.get_numhats ## + + .. method:: get_hat + + | :sl:`get the position of a joystick hat` + | :sg:`get_hat(hat_number) -> x, y` + + Returns the current position of a position hat. The position is given as + two values representing the ``x`` and ``y`` position for the hat. ``(0, 0)`` + means centered. A value of ``-1`` means left/down and a value of ``1`` means + right/up: so ``(-1, 0)`` means left; ``(1, 0)`` means right; ``(0, 1)`` means + up; ``(1, 1)`` means upper-right; etc. + + This value is digital, ``i.e.``, each coordinate can be ``-1``, ``0`` or ``1`` + but never in-between. + + The hat number must be between ``0`` and ``get_numhats() - 1``. + + .. ## Joystick.get_hat ## + + .. method:: rumble + + | :sl:`Start a rumbling effect` + | :sg:`rumble(low_frequency, high_frequency, duration) -> bool` + + Start a rumble effect on the joystick, with the specified strength ranging + from 0 to 1. Duration is length of the effect, in ms. Setting the duration + to 0 will play the effect until another one overwrites it or + :meth:`Joystick.stop_rumble` is called. If an effect is already + playing, then it will be overwritten. + + Returns True if the rumble was played successfully or False if the + joystick does not support it or :meth:`pygame.version.SDL` is below 2.0.9. + + .. versionadded:: 2.0.2 + + .. ## Joystick.rumble ## + + .. method:: stop_rumble + + | :sl:`Stop any rumble effect playing` + | :sg:`stop_rumble() -> None` + + Stops any rumble effect playing on the joystick. See + :meth:`Joystick.rumble` for more information. + + .. versionadded:: 2.0.2 + + .. ## Joystick.stop_rumble ## + + .. ## pygame.joystick.Joystick ## + +.. ## pygame.joystick ## + +.. figure:: code_examples/joystick_calls.png + :scale: 100 % + :alt: joystick module example + + Example code for joystick module. + +.. literalinclude:: code_examples/joystick_calls.py + +.. _controller-mappings: + + +**Common Controller Axis Mappings** + +Controller mappings are drawn from the underlying SDL library which pygame uses and they differ +between pygame 1 and pygame 2. Below are a couple of mappings for two popular game pads. + + +**Pygame 2** + +Axis and hat mappings are listed from -1 to +1. + + +**X-Box 360 Controller (name: "Xbox 360 Controller")** + +In pygame 2 the X360 controller mapping has 6 Axes, 11 buttons and 1 hat. + +* **Left Stick**:: + + Left -> Right - Axis 0 + Up -> Down - Axis 1 + +* **Right Stick**:: + + Left -> Right - Axis 3 + Up -> Down - Axis 4 + +* **Left Trigger**:: + + Out -> In - Axis 2 + +* **Right Trigger**:: + + Out -> In - Axis 5 + +* **Buttons**:: + + A Button - Button 0 + B Button - Button 1 + X Button - Button 2 + Y Button - Button 3 + Left Bumper - Button 4 + Right Bumper - Button 5 + Back Button - Button 6 + Start Button - Button 7 + L. Stick In - Button 8 + R. Stick In - Button 9 + Guide Button - Button 10 + +* **Hat/D-pad**:: + + Down -> Up - Y Axis + Left -> Right - X Axis + + +**Playstation 4 Controller (name: "PS4 Controller")** + +In pygame 2 the PS4 controller mapping has 6 Axes and 16 buttons. + +* **Left Stick**:: + + Left -> Right - Axis 0 + Up -> Down - Axis 1 + +* **Right Stick**:: + + Left -> Right - Axis 2 + Up -> Down - Axis 3 + +* **Left Trigger**:: + + Out -> In - Axis 4 + +* **Right Trigger**:: + + Out -> In - Axis 5 + +* **Buttons**:: + + Cross Button - Button 0 + Circle Button - Button 1 + Square Button - Button 2 + Triangle Button - Button 3 + Share Button - Button 4 + PS Button - Button 5 + Options Button - Button 6 + L. Stick In - Button 7 + R. Stick In - Button 8 + Left Bumper - Button 9 + Right Bumper - Button 10 + D-pad Up - Button 11 + D-pad Down - Button 12 + D-pad Left - Button 13 + D-pad Right - Button 14 + Touch Pad Click - Button 15 + +**Pygame 1** + +Axis and hat mappings are listed from -1 to +1. + + +**X-Box 360 Controller (name: "Controller (XBOX 360 For Windows)")** + +In pygame 1 the X360 controller mapping has 5 Axes, 10 buttons and 1 hat. + +* **Left Stick**:: + + Left -> Right - Axis 0 + Up -> Down - Axis 1 + +* **Right Stick**:: + + Left -> Right - Axis 4 + Up -> Down - Axis 3 + +* **Left Trigger & Right Trigger**:: + + RT -> LT - Axis 2 + +* **Buttons**:: + + A Button - Button 0 + B Button - Button 1 + X Button - Button 2 + Y Button - Button 3 + Left Bumper - Button 4 + Right Bumper - Button 5 + Back Button - Button 6 + Start Button - Button 7 + L. Stick In - Button 8 + R. Stick In - Button 9 + +* **Hat/D-pad**:: + + Down -> Up - Y Axis + Left -> Right - X Axis + + +**Playstation 4 Controller (name: "Wireless Controller")** + +In pygame 1 the PS4 controller mapping has 6 Axes and 14 buttons and 1 hat. + +* **Left Stick**:: + + Left -> Right - Axis 0 + Up -> Down - Axis 1 + +* **Right Stick**:: + + Left -> Right - Axis 2 + Up -> Down - Axis 3 + +* **Left Trigger**:: + + Out -> In - Axis 5 + +* **Right Trigger**:: + + Out -> In - Axis 4 + +* **Buttons**:: + + Cross Button - Button 0 + Circle Button - Button 1 + Square Button - Button 2 + Triangle Button - Button 3 + Left Bumper - Button 4 + Right Bumper - Button 5 + L. Trigger(Full)- Button 6 + R. Trigger(Full)- Button 7 + Share Button - Button 8 + Options Button - Button 9 + L. Stick In - Button 10 + R. Stick In - Button 11 + PS Button - Button 12 + Touch Pad Click - Button 13 + +* **Hat/D-pad**:: + + Down -> Up - Y Axis + Left -> Right - X Axis diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/key.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/key.rst.txt new file mode 100644 index 0000000..695ad0e --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/key.rst.txt @@ -0,0 +1,430 @@ +.. include:: common.txt + +:mod:`pygame.key` +================= + +.. module:: pygame.key + :synopsis: pygame module to work with the keyboard + +| :sl:`pygame module to work with the keyboard` + +This module contains functions for dealing with the keyboard. + +The :mod:`pygame.event` queue gets ``pygame.KEYDOWN`` and ``pygame.KEYUP`` +events when the keyboard buttons are pressed and released. Both events have +``key`` and ``mod`` attributes. + + * ``key``: an :ref:`integer ID ` representing every key + on the keyboard + * ``mod``: a bitmask of all the :ref:`modifier keys ` + that were in a pressed state when the event occurred + +The ``pygame.KEYDOWN`` event has the additional attributes ``unicode`` and +``scancode``. + + * ``unicode``: a single character string that is the fully translated + character entered, this takes into account the shift and composition keys + * ``scancode``: the platform-specific key code, which could be different from + keyboard to keyboard, but is useful for key selection of weird keys like + the multimedia keys + +.. versionadded:: 2.0.0 + The ``pygame.TEXTINPUT`` event is preferred to the ``unicode`` attribute + of ``pygame.KEYDOWN``. The attribute ``text`` contains the input. + + +.. _key-constants-label: + +The following is a list of all the constants (from :mod:`pygame.locals`) used to +represent keyboard keys. + +Portability note: The integers for key constants differ between pygame 1 and 2. +Always use key constants (``K_a``) rather than integers directly (``97``) so +that your key handling code works well on both pygame 1 and pygame 2. + + +:: + + pygame + Constant ASCII Description + --------------------------------- + K_BACKSPACE \b backspace + K_TAB \t tab + K_CLEAR clear + K_RETURN \r return + K_PAUSE pause + K_ESCAPE ^[ escape + K_SPACE space + K_EXCLAIM ! exclaim + K_QUOTEDBL " quotedbl + K_HASH # hash + K_DOLLAR $ dollar + K_AMPERSAND & ampersand + K_QUOTE quote + K_LEFTPAREN ( left parenthesis + K_RIGHTPAREN ) right parenthesis + K_ASTERISK * asterisk + K_PLUS + plus sign + K_COMMA , comma + K_MINUS - minus sign + K_PERIOD . period + K_SLASH / forward slash + K_0 0 0 + K_1 1 1 + K_2 2 2 + K_3 3 3 + K_4 4 4 + K_5 5 5 + K_6 6 6 + K_7 7 7 + K_8 8 8 + K_9 9 9 + K_COLON : colon + K_SEMICOLON ; semicolon + K_LESS < less-than sign + K_EQUALS = equals sign + K_GREATER > greater-than sign + K_QUESTION ? question mark + K_AT @ at + K_LEFTBRACKET [ left bracket + K_BACKSLASH \ backslash + K_RIGHTBRACKET ] right bracket + K_CARET ^ caret + K_UNDERSCORE _ underscore + K_BACKQUOTE ` grave + K_a a a + K_b b b + K_c c c + K_d d d + K_e e e + K_f f f + K_g g g + K_h h h + K_i i i + K_j j j + K_k k k + K_l l l + K_m m m + K_n n n + K_o o o + K_p p p + K_q q q + K_r r r + K_s s s + K_t t t + K_u u u + K_v v v + K_w w w + K_x x x + K_y y y + K_z z z + K_DELETE delete + K_KP0 keypad 0 + K_KP1 keypad 1 + K_KP2 keypad 2 + K_KP3 keypad 3 + K_KP4 keypad 4 + K_KP5 keypad 5 + K_KP6 keypad 6 + K_KP7 keypad 7 + K_KP8 keypad 8 + K_KP9 keypad 9 + K_KP_PERIOD . keypad period + K_KP_DIVIDE / keypad divide + K_KP_MULTIPLY * keypad multiply + K_KP_MINUS - keypad minus + K_KP_PLUS + keypad plus + K_KP_ENTER \r keypad enter + K_KP_EQUALS = keypad equals + K_UP up arrow + K_DOWN down arrow + K_RIGHT right arrow + K_LEFT left arrow + K_INSERT insert + K_HOME home + K_END end + K_PAGEUP page up + K_PAGEDOWN page down + K_F1 F1 + K_F2 F2 + K_F3 F3 + K_F4 F4 + K_F5 F5 + K_F6 F6 + K_F7 F7 + K_F8 F8 + K_F9 F9 + K_F10 F10 + K_F11 F11 + K_F12 F12 + K_F13 F13 + K_F14 F14 + K_F15 F15 + K_NUMLOCK numlock + K_CAPSLOCK capslock + K_SCROLLOCK scrollock + K_RSHIFT right shift + K_LSHIFT left shift + K_RCTRL right control + K_LCTRL left control + K_RALT right alt + K_LALT left alt + K_RMETA right meta + K_LMETA left meta + K_LSUPER left Windows key + K_RSUPER right Windows key + K_MODE mode shift + K_HELP help + K_PRINT print screen + K_SYSREQ sysrq + K_BREAK break + K_MENU menu + K_POWER power + K_EURO Euro + K_AC_BACK Android back button + + +.. _key-modifiers-label: + +The keyboard also has a list of modifier states (from :mod:`pygame.locals`) that +can be assembled by bitwise-ORing them together. + +:: + + pygame + Constant Description + ------------------------- + KMOD_NONE no modifier keys pressed + KMOD_LSHIFT left shift + KMOD_RSHIFT right shift + KMOD_SHIFT left shift or right shift or both + KMOD_LCTRL left control + KMOD_RCTRL right control + KMOD_CTRL left control or right control or both + KMOD_LALT left alt + KMOD_RALT right alt + KMOD_ALT left alt or right alt or both + KMOD_LMETA left meta + KMOD_RMETA right meta + KMOD_META left meta or right meta or both + KMOD_CAPS caps lock + KMOD_NUM num lock + KMOD_MODE AltGr + + +The modifier information is contained in the ``mod`` attribute of the +``pygame.KEYDOWN`` and ``pygame.KEYUP`` events. The ``mod`` attribute is a +bitmask of all the modifier keys that were in a pressed state when the event +occurred. The modifier information can be decoded using a bitwise AND (except +for ``KMOD_NONE``, which should be compared using equals ``==``). For example: + +:: + + for event in pygame.event.get(): + if event.type == pygame.KEYDOWN or event.type == pygame.KEYUP: + if event.mod == pygame.KMOD_NONE: + print('No modifier keys were in a pressed state when this ' + 'event occurred.') + else: + if event.mod & pygame.KMOD_LSHIFT: + print('Left shift was in a pressed state when this event ' + 'occurred.') + if event.mod & pygame.KMOD_RSHIFT: + print('Right shift was in a pressed state when this event ' + 'occurred.') + if event.mod & pygame.KMOD_SHIFT: + print('Left shift or right shift or both were in a ' + 'pressed state when this event occurred.') + + + +.. function:: get_focused + + | :sl:`true if the display is receiving keyboard input from the system` + | :sg:`get_focused() -> bool` + + Returns ``True`` when the display window has keyboard focus from the + system. If the display needs to ensure it does not lose keyboard focus, it + can use :func:`pygame.event.set_grab()` to grab all input. + + .. ## pygame.key.get_focused ## + +.. function:: get_pressed + + | :sl:`get the state of all keyboard buttons` + | :sg:`get_pressed() -> bools` + + Returns a sequence of boolean values representing the state of every key on + the keyboard. Use the key constant values to index the array. A ``True`` + value means that the button is pressed. + + .. note:: + Getting the list of pushed buttons with this function is not the proper + way to handle text entry from the user. There is no way to know the order + of keys pressed, and rapidly pushed keys can be completely unnoticed + between two calls to ``pygame.key.get_pressed()``. There is also no way to + translate these pushed keys into a fully translated character value. See + the ``pygame.KEYDOWN`` events on the :mod:`pygame.event` queue for this + functionality. + + .. ## pygame.key.get_pressed ## + +.. function:: get_mods + + | :sl:`determine which modifier keys are being held` + | :sg:`get_mods() -> int` + + Returns a single integer representing a bitmask of all the modifier keys + being held. Using bitwise operators you can test if specific + :ref:`modifier keys ` are pressed. + + .. ## pygame.key.get_mods ## + +.. function:: set_mods + + | :sl:`temporarily set which modifier keys are pressed` + | :sg:`set_mods(int) -> None` + + Create a bitmask of the :ref:`modifier key constants ` + you want to impose on your program. + + .. ## pygame.key.set_mods ## + +.. function:: set_repeat + + | :sl:`control how held keys are repeated` + | :sg:`set_repeat() -> None` + | :sg:`set_repeat(delay) -> None` + | :sg:`set_repeat(delay, interval) -> None` + + When the keyboard repeat is enabled, keys that are held down will generate + multiple ``pygame.KEYDOWN`` events. The ``delay`` parameter is the number of + milliseconds before the first repeated ``pygame.KEYDOWN`` event will be sent. + After that, another ``pygame.KEYDOWN`` event will be sent every ``interval`` + milliseconds. If a ``delay`` value is provided and an ``interval`` value is + not provided or is 0, then the ``interval`` will be set to the same value as + ``delay``. + + To disable key repeat call this function with no arguments or with ``delay`` + set to 0. + + When pygame is initialized the key repeat is disabled. + + :raises ValueError: if ``delay`` or ``interval`` is < 0 + + .. versionchanged:: 2.0.0 A ``ValueError`` is now raised (instead of a + ``pygame.error``) if ``delay`` or ``interval`` is < 0. + + .. ## pygame.key.set_repeat ## + +.. function:: get_repeat + + | :sl:`see how held keys are repeated` + | :sg:`get_repeat() -> (delay, interval)` + + Get the ``delay`` and ``interval`` keyboard repeat values. Refer to + :func:`pygame.key.set_repeat()` for a description of these values. + + .. versionadded:: 1.8 + + .. ## pygame.key.get_repeat ## + +.. function:: name + + | :sl:`get the name of a key identifier` + | :sg:`name(key) -> string` + + Get the descriptive name of the button from a keyboard button id constant. + + .. ## pygame.key.name ## + +.. function:: key_code + + | :sl:`get the key identifier from a key name` + | :sg:`key_code(name=string) -> int` + + Get the key identifier code from the descriptive name of the key. This + returns an integer matching one of the K_* keycodes. For example: + + :: + + >>> pygame.key.key_code("return") == pygame.K_RETURN + True + >>> pygame.key.key_code("0") == pygame.K_0 + True + >>> pygame.key.key_code("space") == pygame.K_SPACE + True + + :raises ValueError: if the key name is not known. + :raises NotImplementedError: if used with SDL 1. + + .. ## pygame.key.key_code ## + + .. versionadded:: 2.0.0 + + .. ## pygame.key.key_code ## + +.. function:: start_text_input + + | :sl:`start handling Unicode text input events` + | :sg:`start_text_input() -> None` + + Start receiving ``pygame.TEXTEDITING`` and ``pygame.TEXTINPUT`` + events. If applicable, show the on-screen keyboard or IME editor. + + For many languages, key presses will automatically generate a + corresponding ``pygame.TEXTINPUT`` event. Special keys like + escape or function keys, and certain key combinations will not + generate ``pygame.TEXTINPUT`` events. + + In other languages, entering a single symbol may require multiple + key presses, or a language-specific user interface. In this case, + ``pygame.TEXTINPUT`` events are preferable to ``pygame.KEYDOWN`` + events for text input. + + A ``pygame.TEXTEDITING`` event is received when an IME composition + is started or changed. It contains the composition ``text``, ``length``, + and editing ``start`` position within the composition (attributes + ``text``, ``length``, and ``start``, respectively). + When the composition is committed (or non-IME input is received), + a ``pygame.TEXTINPUT`` event is generated. + + Text input events handling is on by default. + + .. versionadded:: 2.0.0 + + .. ## pygame.key.start_text_input ## + +.. function:: stop_text_input + + | :sl:`stop handling Unicode text input events` + | :sg:`stop_text_input() -> None` + + Stop receiving ``pygame.TEXTEDITING`` and ``pygame.TEXTINPUT`` + events. If an on-screen keyboard or IME editor was shown with + ``pygame.key.start_text_input()``, hide it again. + + Text input events handling is on by default. + + To avoid triggering the IME editor or the on-screen keyboard + when the user is holding down a key during gameplay, text input + should be disabled once text entry is finished, or when the user + clicks outside of a text box. + + .. versionadded:: 2.0.0 + + .. ## pygame.key.stop_text_input ## + +.. function:: set_text_input_rect + + | :sl:`controls the position of the candidate list` + | :sg:`set_text_input_rect(Rect) -> None` + + This sets the rectangle used for typing with an IME. + It controls where the candidate list will open, if supported. + + .. versionadded:: 2.0.0 + + .. ## pygame.key.set_text_input_rect ## + +.. ## pygame.key ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/locals.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/locals.rst.txt new file mode 100644 index 0000000..091dbaa --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/locals.rst.txt @@ -0,0 +1,27 @@ +.. include:: common.txt + +:mod:`pygame.locals` +==================== + +.. module:: pygame.locals + :synopsis: pygame constants + +| :sl:`pygame constants` + +This module contains various constants used by pygame. Its contents are +automatically placed in the pygame module namespace. However, an application +can use ``pygame.locals`` to include only the pygame constants with a ``from +pygame.locals import *``. + +Detailed descriptions of the various constants can be found throughout the +pygame documentation. Here are the locations of some of them. + + - The :mod:`pygame.display` module contains flags like ``FULLSCREEN`` used + by :func:`pygame.display.set_mode`. + - The :mod:`pygame.event` module contains the various event types. + - The :mod:`pygame.key` module lists the keyboard constants and modifiers + (``K_``\* and ``MOD_``\*) relating to the ``key`` and ``mod`` attributes of + the ``KEYDOWN`` and ``KEYUP`` events. + - The :mod:`pygame.time` module defines ``TIMER_RESOLUTION``. + +.. ## pygame.locals ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/mask.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/mask.rst.txt new file mode 100644 index 0000000..f4365cf --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/mask.rst.txt @@ -0,0 +1,642 @@ +.. include:: common.txt + +:mod:`pygame.mask` +================== + +.. module:: pygame.mask + :synopsis: pygame module for image masks. + +| :sl:`pygame module for image masks.` + +Useful for fast pixel perfect collision detection. A mask uses 1 bit per-pixel +to store which parts collide. + +.. versionadded:: 1.8 + +.. versionchanged:: 2.0.2 Mask functions now support keyword arguments. + +.. versionchanged:: 2.0.2 Mask functions that take positions or offsets now + support :class:`pygame.math.Vector2` arguments. + + +.. function:: from_surface + + | :sl:`Creates a Mask from the given surface` + | :sg:`from_surface(surface) -> Mask` + | :sg:`from_surface(surface, threshold=127) -> Mask` + + Creates a :class:`Mask` object from the given surface by setting all the + opaque pixels and not setting the transparent pixels. + + If the surface uses a color-key, then it is used to decide which bits in + the resulting mask are set. All the pixels that are **not** equal to the + color-key are **set** and the pixels equal to the color-key are not set. + + If a color-key is not used, then the alpha value of each pixel is used to + decide which bits in the resulting mask are set. All the pixels that have an + alpha value **greater than** the ``threshold`` parameter are **set** and the + pixels with an alpha value less than or equal to the ``threshold`` are + not set. + + :param Surface surface: the surface to create the mask from + :param int threshold: (optional) the alpha threshold (default is 127) to + compare with each surface pixel's alpha value, if the ``surface`` is + color-keyed this parameter is ignored + + :returns: a newly created :class:`Mask` object from the given surface + :rtype: Mask + + .. note:: + This function is used to create the masks for + :func:`pygame.sprite.collide_mask`. + + .. ## pygame.mask.from_surface ## + +.. function:: from_threshold + + | :sl:`Creates a mask by thresholding Surfaces` + | :sg:`from_threshold(surface, color) -> Mask` + | :sg:`from_threshold(surface, color, threshold=(0, 0, 0, 255), othersurface=None, palette_colors=1) -> Mask` + + This is a more featureful method of getting a :class:`Mask` from a surface. + + If the optional ``othersurface`` is not used, all the pixels **within** the + ``threshold`` of the ``color`` parameter are **set** in the resulting mask. + + If the optional ``othersurface`` is used, every pixel in the first surface + that is **within** the ``threshold`` of the corresponding pixel in + ``othersurface`` is **set** in the resulting mask. + + :param Surface surface: the surface to create the mask from + :param color: color used to check if the surface's pixels are within the + given ``threshold`` range, this parameter is ignored if the optional + ``othersurface`` parameter is supplied + :type color: Color or int or tuple(int, int, int, [int]) or list[int, int, int, [int]] + :param threshold: (optional) the threshold range used to check the difference + between two colors (default is ``(0, 0, 0, 255)``) + :type threshold: Color or int or tuple(int, int, int, [int]) or list[int, int, int, [int]] + :param Surface othersurface: (optional) used to check whether the pixels of + the first surface are within the given ``threshold`` range of the pixels + from this surface (default is ``None``) + :param int palette_colors: (optional) indicates whether to use the palette + colors or not, a nonzero value causes the palette colors to be used and a + 0 causes them not to be used (default is 1) + + :returns: a newly created :class:`Mask` object from the given surface + :rtype: Mask + + .. ## pygame.mask.from_threshold ## + +.. class:: Mask + + | :sl:`pygame object for representing 2D bitmasks` + | :sg:`Mask(size=(width, height)) -> Mask` + | :sg:`Mask(size=(width, height), fill=False) -> Mask` + + A ``Mask`` object is used to represent a 2D bitmask. Each bit in + the mask represents a pixel. 1 is used to indicate a set bit and 0 is used + to indicate an unset bit. Set bits in a mask can be used to detect collisions + with other masks and their set bits. + + A filled mask has all of its bits set to 1, conversely an + unfilled/cleared/empty mask has all of its bits set to 0. Masks can be + created unfilled (default) or filled by using the ``fill`` parameter. Masks + can also be cleared or filled using the :func:`pygame.mask.Mask.clear()` and + :func:`pygame.mask.Mask.fill()` methods respectively. + + A mask's coordinates start in the top left corner at ``(0, 0)`` just like + :mod:`pygame.Surface`. Individual bits can be accessed using the + :func:`pygame.mask.Mask.get_at()` and :func:`pygame.mask.Mask.set_at()` + methods. + + .. _mask-offset-label: + + The methods :meth:`overlap`, :meth:`overlap_area`, :meth:`overlap_mask`, + :meth:`draw`, :meth:`erase`, and :meth:`convolve` use an offset parameter + to indicate the offset of another mask's top left corner from the calling + mask's top left corner. The calling mask's top left corner is considered to + be the origin ``(0, 0)``. Offsets are a sequence of two values + ``(x_offset, y_offset)``. Positive and negative offset values are supported. + + :: + + 0 to x (x_offset) + : : + 0 ..... +----:---------+ + to | : | + y .......... +-----------+ + (y_offset) | | othermask | + | +-----------+ + | calling_mask | + +--------------+ + + :param size: the dimensions of the mask (width and height) + :param bool fill: (optional) create an unfilled mask (default: ``False``) or + filled mask (``True``) + + :returns: a newly created :class:`Mask` object + :rtype: Mask + + .. versionchanged:: 2.0.0 + Shallow copy support added. The :class:`Mask` class supports the special + method ``__copy__()`` and shallow copying via ``copy.copy(mask)``. + .. versionchanged:: 2.0.0 Subclassing support added. The :class:`Mask` class + can be used as a base class. + .. versionchanged:: 1.9.5 Added support for keyword arguments. + .. versionchanged:: 1.9.5 Added the optional keyword parameter ``fill``. + .. versionchanged:: 1.9.5 Added support for masks with a width and/or a + height of 0. + + .. method:: copy + + | :sl:`Returns a new copy of the mask` + | :sg:`copy() -> Mask` + + :returns: a new copy of this mask, the new mask will have the same width, + height, and set/unset bits as the original + :rtype: Mask + + .. note:: + If a mask subclass needs to copy any instance specific attributes + then it should override the ``__copy__()`` method. The overridden + ``__copy__()`` method needs to call ``super().__copy__()`` and then + copy the required data as in the following example code. + + :: + + class SubMask(pygame.mask.Mask): + def __copy__(self): + new_mask = super().__copy__() + # Do any SubMask attribute copying here. + return new_mask + + .. versionadded:: 2.0.0 + + .. ## Mask.copy ## + + .. method:: get_size + + | :sl:`Returns the size of the mask` + | :sg:`get_size() -> (width, height)` + + :returns: the size of the mask, (width, height) + :rtype: tuple(int, int) + + .. ## Mask.get_size ## + + .. method:: get_rect + + | :sl:`Returns a Rect based on the size of the mask` + | :sg:`get_rect(\**kwargs) -> Rect` + + Returns a new :func:`pygame.Rect` object based on the size of this mask. + The rect's default position will be ``(0, 0)`` and its default width and + height will be the same as this mask's. The rect's attributes can be + altered via :func:`pygame.Rect` attribute keyword arguments/values passed + into this method. As an example, ``a_mask.get_rect(center=(10, 5))`` would + create a :func:`pygame.Rect` based on the mask's size centered at the + given position. + + :param dict kwargs: :func:`pygame.Rect` attribute keyword arguments/values + that will be applied to the rect + + :returns: a new :func:`pygame.Rect` object based on the size of this mask + with any :func:`pygame.Rect` attribute keyword arguments/values applied + to it + :rtype: Rect + + .. versionadded:: 2.0.0 + + .. ## Mask.get_rect ## + + .. method:: get_at + + | :sl:`Gets the bit at the given position` + | :sg:`get_at(pos) -> int` + + :param pos: the position of the bit to get (x, y) + + :returns: 1 if the bit is set, 0 if the bit is not set + :rtype: int + + :raises IndexError: if the position is outside of the mask's bounds + + .. ## Mask.get_at ## + + .. method:: set_at + + | :sl:`Sets the bit at the given position` + | :sg:`set_at(pos) -> None` + | :sg:`set_at(pos, value=1) -> None` + + :param pos: the position of the bit to set (x, y) + :param int value: any nonzero int will set the bit to 1, 0 will set the + bit to 0 (default is 1) + + :returns: ``None`` + :rtype: NoneType + + :raises IndexError: if the position is outside of the mask's bounds + + .. ## Mask.set_at ## + + .. method:: overlap + + | :sl:`Returns the point of intersection` + | :sg:`overlap(other, offset) -> (x, y)` + | :sg:`overlap(other, offset) -> None` + + Returns the first point of intersection encountered between this mask and + ``other``. A point of intersection is 2 overlapping set bits. + + The current algorithm searches the overlapping area in + ``sizeof(unsigned long int) * CHAR_BIT`` bit wide column blocks (the value + of ``sizeof(unsigned long int) * CHAR_BIT`` is platform dependent, for + clarity it will be referred to as ``W``). Starting at the top left corner + it checks bits 0 to ``W - 1`` of the first row (``(0, 0)`` to + ``(W - 1, 0)``) then continues to the next row (``(0, 1)`` to + ``(W - 1, 1)``). Once this entire column block is checked, it continues to + the next one (``W`` to ``2 * W - 1``). This is repeated until it finds a + point of intersection or the entire overlapping area is checked. + + :param Mask other: the other mask to overlap with this mask + :param offset: the offset of ``other`` from this mask, for more + details refer to the :ref:`Mask offset notes ` + + :returns: point of intersection or ``None`` if no intersection + :rtype: tuple(int, int) or NoneType + + .. ## Mask.overlap ## + + .. method:: overlap_area + + | :sl:`Returns the number of overlapping set bits` + | :sg:`overlap_area(other, offset) -> numbits` + + Returns the number of overlapping set bits between between this mask and + ``other``. + + This can be useful for collision detection. An approximate collision + normal can be found by calculating the gradient of the overlapping area + through the finite difference. + + :: + + dx = mask.overlap_area(other, (x + 1, y)) - mask.overlap_area(other, (x - 1, y)) + dy = mask.overlap_area(other, (x, y + 1)) - mask.overlap_area(other, (x, y - 1)) + + :param Mask other: the other mask to overlap with this mask + :param offset: the offset of ``other`` from this mask, for more + details refer to the :ref:`Mask offset notes ` + + :returns: the number of overlapping set bits + :rtype: int + + .. ## Mask.overlap_area ## + + .. method:: overlap_mask + + | :sl:`Returns a mask of the overlapping set bits` + | :sg:`overlap_mask(other, offset) -> Mask` + + Returns a :class:`Mask`, the same size as this mask, containing the + overlapping set bits between this mask and ``other``. + + :param Mask other: the other mask to overlap with this mask + :param offset: the offset of ``other`` from this mask, for more + details refer to the :ref:`Mask offset notes ` + + :returns: a newly created :class:`Mask` with the overlapping bits set + :rtype: Mask + + .. ## Mask.overlap_mask ## + + .. method:: fill + + | :sl:`Sets all bits to 1` + | :sg:`fill() -> None` + + Sets all bits in the mask to 1. + + :returns: ``None`` + :rtype: NoneType + + .. ## Mask.fill ## + + .. method:: clear + + | :sl:`Sets all bits to 0` + | :sg:`clear() -> None` + + Sets all bits in the mask to 0. + + :returns: ``None`` + :rtype: NoneType + + .. ## Mask.clear ## + + .. method:: invert + + | :sl:`Flips all the bits` + | :sg:`invert() -> None` + + Flips all of the bits in the mask. All the set bits are cleared to 0 and + all the unset bits are set to 1. + + :returns: ``None`` + :rtype: NoneType + + .. ## Mask.invert ## + + .. method:: scale + + | :sl:`Resizes a mask` + | :sg:`scale((width, height)) -> Mask` + + Creates a new :class:`Mask` of the requested size with its bits scaled + from this mask. + + :param size: the width and height (size) of the mask to create + + :returns: a new :class:`Mask` object with its bits scaled from this mask + :rtype: Mask + + :raises ValueError: if ``width < 0`` or ``height < 0`` + + .. ## Mask.scale ## + + .. method:: draw + + | :sl:`Draws a mask onto another` + | :sg:`draw(other, offset) -> None` + + Performs a bitwise OR, drawing ``othermask`` onto this mask. + + :param Mask other: the mask to draw onto this mask + :param offset: the offset of ``other`` from this mask, for more + details refer to the :ref:`Mask offset notes ` + + :returns: ``None`` + :rtype: NoneType + + .. ## Mask.draw ## + + .. method:: erase + + | :sl:`Erases a mask from another` + | :sg:`erase(other, offset) -> None` + + Erases (clears) all bits set in ``other`` from this mask. + + :param Mask other: the mask to erase from this mask + :param offset: the offset of ``other`` from this mask, for more + details refer to the :ref:`Mask offset notes ` + + :returns: ``None`` + :rtype: NoneType + + .. ## Mask.erase ## + + .. method:: count + + | :sl:`Returns the number of set bits` + | :sg:`count() -> bits` + + :returns: the number of set bits in the mask + :rtype: int + + .. ## Mask.count ## + + .. method:: centroid + + | :sl:`Returns the centroid of the set bits` + | :sg:`centroid() -> (x, y)` + + Finds the centroid (the center mass of the set bits) for this mask. + + :returns: a coordinate tuple indicating the centroid of the mask, it will + return ``(0, 0)`` if the mask has no bits set + :rtype: tuple(int, int) + + .. ## Mask.centroid ## + + .. method:: angle + + | :sl:`Returns the orientation of the set bits` + | :sg:`angle() -> theta` + + Finds the approximate orientation (from -90 to 90 degrees) of the set bits + in the mask. This works best if performed on a mask with only one + connected component. + + :returns: the orientation of the set bits in the mask, it will return + ``0.0`` if the mask has no bits set + :rtype: float + + .. note:: + See :meth:`connected_component` for details on how a connected + component is calculated. + + .. ## Mask.angle ## + + .. method:: outline + + | :sl:`Returns a list of points outlining an object` + | :sg:`outline() -> [(x, y), ...]` + | :sg:`outline(every=1) -> [(x, y), ...]` + + Returns a list of points of the outline of the first connected component + encountered in the mask. To find a connected component, the mask is + searched per row (left to right) starting in the top left corner. + + The ``every`` optional parameter skips set bits in the outline. For + example, setting it to 10 would return a list of every 10th set bit in the + outline. + + :param int every: (optional) indicates the number of bits to skip over in + the outline (default is 1) + + :returns: a list of points outlining the first connected component + encountered, an empty list is returned if the mask has no bits set + :rtype: list[tuple(int, int)] + + .. note:: + See :meth:`connected_component` for details on how a connected + component is calculated. + + .. ## Mask.outline ## + + .. method:: convolve + + | :sl:`Returns the convolution of this mask with another mask` + | :sg:`convolve(other) -> Mask` + | :sg:`convolve(other, output=None, offset=(0, 0)) -> Mask` + + Convolve this mask with the given ``other`` Mask. + + :param Mask other: mask to convolve this mask with + :param output: (optional) mask for output (default is ``None``) + :type output: Mask or NoneType + :param offset: the offset of ``other`` from this mask, (default is + ``(0, 0)``) + + :returns: a :class:`Mask` with the ``(i - offset[0], j - offset[1])`` bit + set, if shifting ``other`` (such that its bottom right corner is at + ``(i, j)``) causes it to overlap with this mask + + If an ``output`` Mask is specified, the output is drawn onto it and + it is returned. Otherwise a mask of size ``(MAX(0, width + other mask's + width - 1), MAX(0, height + other mask's height - 1))`` is created and + returned. + :rtype: Mask + + .. ## Mask.convolve ## + + .. method:: connected_component + + | :sl:`Returns a mask containing a connected component` + | :sg:`connected_component() -> Mask` + | :sg:`connected_component(pos) -> Mask` + + A connected component is a group (1 or more) of connected set bits + (orthogonally and diagonally). The SAUF algorithm, which checks 8 point + connectivity, is used to find a connected component in the mask. + + By default this method will return a :class:`Mask` containing the largest + connected component in the mask. Optionally, a bit coordinate can be + specified and the connected component containing it will be returned. If + the bit at the given location is not set, the returned :class:`Mask` will + be empty (no bits set). + + :param pos: (optional) selects the connected component that contains the + bit at this position + + :returns: a :class:`Mask` object (same size as this mask) with the largest + connected component from this mask, if this mask has no bits set then + an empty mask will be returned + + If the ``pos`` parameter is provided then the mask returned will have + the connected component that contains this position. An empty mask will + be returned if the ``pos`` parameter selects an unset bit. + :rtype: Mask + + :raises IndexError: if the optional ``pos`` parameter is outside of the + mask's bounds + + .. ## Mask.connected_component ## + + .. method:: connected_components + + | :sl:`Returns a list of masks of connected components` + | :sg:`connected_components() -> [Mask, ...]` + | :sg:`connected_components(minimum=0) -> [Mask, ...]` + + Provides a list containing a :class:`Mask` object for each connected + component. + + :param int minimum: (optional) indicates the minimum number of bits (to + filter out noise) per connected component (default is 0, which equates + to no minimum and is equivalent to setting it to 1, as a connected + component must have at least 1 bit set) + + :returns: a list containing a :class:`Mask` object for each connected + component, an empty list is returned if the mask has no bits set + :rtype: list[Mask] + + .. note:: + See :meth:`connected_component` for details on how a connected + component is calculated. + + .. ## Mask.connected_components ## + + .. method:: get_bounding_rects + + | :sl:`Returns a list of bounding rects of connected components` + | :sg:`get_bounding_rects() -> [Rect, ...]` + + Provides a list containing a bounding rect for each connected component. + + :returns: a list containing a bounding rect for each connected component, + an empty list is returned if the mask has no bits set + :rtype: list[Rect] + + .. note:: + See :meth:`connected_component` for details on how a connected + component is calculated. + + .. ## Mask.get_bounding_rects ## + + .. method:: to_surface + + | :sl:`Returns a surface with the mask drawn on it` + | :sg:`to_surface() -> Surface` + | :sg:`to_surface(surface=None, setsurface=None, unsetsurface=None, setcolor=(255, 255, 255, 255), unsetcolor=(0, 0, 0, 255), dest=(0, 0)) -> Surface` + + Draws this mask on the given surface. Set bits (bits set to 1) and unset + bits (bits set to 0) can be drawn onto a surface. + + :param surface: (optional) Surface to draw mask onto, if no surface is + provided one will be created (default is ``None``, which will cause a + surface with the parameters + ``Surface(size=mask.get_size(), flags=SRCALPHA, depth=32)`` to be + created, drawn on, and returned) + :type surface: Surface or None + :param setsurface: (optional) use this surface's color values to draw + set bits (default is ``None``), if this surface is smaller than the + mask any bits outside its bounds will use the ``setcolor`` value + :type setsurface: Surface or None + :param unsetsurface: (optional) use this surface's color values to draw + unset bits (default is ``None``), if this surface is smaller than the + mask any bits outside its bounds will use the ``unsetcolor`` value + :type unsetsurface: Surface or None + :param setcolor: (optional) color to draw set bits (default is + ``(255, 255, 255, 255)``, white), use ``None`` to skip drawing the set + bits, the ``setsurface`` parameter (if set) will takes precedence over + this parameter + :type setcolor: Color or str or int or tuple(int, int, int, [int]) or + list(int, int, int, [int]) or None + :param unsetcolor: (optional) color to draw unset bits (default is + ``(0, 0, 0, 255)``, black), use ``None`` to skip drawing the unset + bits, the ``unsetsurface`` parameter (if set) will takes precedence + over this parameter + :type unsetcolor: Color or str or int or tuple(int, int, int, [int]) or + list(int, int, int, [int]) or None + :param dest: (optional) surface destination of where to position the + topleft corner of the mask being drawn (default is ``(0, 0)``), if a + Rect is used as the ``dest`` parameter, its ``x`` and ``y`` attributes + will be used as the destination, **NOTE1:** rects with a negative width + or height value will not be normalized before using their ``x`` and + ``y`` values, **NOTE2:** this destination value is only used to + position the mask on the surface, it does not offset the ``setsurface`` + and ``unsetsurface`` from the mask, they are always aligned with the + mask (i.e. position ``(0, 0)`` on the mask always corresponds to + position ``(0, 0)`` on the ``setsurface`` and ``unsetsurface``) + :type dest: Rect or tuple(int, int) or list(int, int) or Vector2(int, int) + + :returns: the ``surface`` parameter (or a newly created surface if no + ``surface`` parameter was provided) with this mask drawn on it + :rtype: Surface + + :raises ValueError: if the ``setsurface`` parameter or ``unsetsurface`` + parameter does not have the same format (bytesize/bitsize/alpha) as + the ``surface`` parameter + + .. note :: + To skip drawing the set bits, both ``setsurface`` and ``setcolor`` must + be ``None``. The ``setsurface`` parameter defaults to ``None``, but + ``setcolor`` defaults to a color value and therefore must be set to + ``None``. + + .. note :: + To skip drawing the unset bits, both ``unsetsurface`` and + ``unsetcolor`` must be ``None``. The ``unsetsurface`` parameter + defaults to ``None``, but ``unsetcolor`` defaults to a color value and + therefore must be set to ``None``. + + .. versionadded:: 2.0.0 + + .. ## Mask.to_surface ## + + .. ## pygame.mask.Mask ## + +.. ## pygame.mask ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/math.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/math.rst.txt new file mode 100644 index 0000000..865803c --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/math.rst.txt @@ -0,0 +1,880 @@ +.. include:: common.txt + +:mod:`pygame.math` +================== + +.. module:: pygame.math + :synopsis: pygame module for vector classes + +| :sl:`pygame module for vector classes` + +The pygame math module currently provides Vector classes in two and three +dimensions, ``Vector2`` and ``Vector3`` respectively. + +They support the following numerical operations: ``vec+vec``, ``vec-vec``, +``vec*number``, ``number*vec``, ``vec/number``, ``vec//number``, ``vec+=vec``, +``vec-=vec``, ``vec*=number``, ``vec/=number``, ``vec//=number``. + +All these operations will be performed elementwise. +In addition ``vec*vec`` will perform a scalar-product (a.k.a. dot-product). +If you want to multiply every element from vector v with every element from +vector w you can use the elementwise method: ``v.elementwise() * w`` + +The coordinates of a vector can be retrieved or set using attributes or +subscripts + +:: + + v = pygame.Vector3() + + v.x = 5 + v[1] = 2 * v.x + print(v[1]) # 10 + + v.x == v[0] + v.y == v[1] + v.z == v[2] + +Multiple coordinates can be set using slices or swizzling + +:: + + v = pygame.Vector2() + v.xy = 1, 2 + v[:] = 1, 2 + +.. versionadded:: 1.9.2pre +.. versionchanged:: 1.9.4 Removed experimental notice. +.. versionchanged:: 1.9.4 Allow scalar construction like GLSL Vector2(2) == Vector2(2.0, 2.0) +.. versionchanged:: 1.9.4 :mod:`pygame.math` required import. More convenient ``pygame.Vector2`` and ``pygame.Vector3``. + +.. class:: Vector2 + + | :sl:`a 2-Dimensional Vector` + | :sg:`Vector2() -> Vector2` + | :sg:`Vector2(int) -> Vector2` + | :sg:`Vector2(float) -> Vector2` + | :sg:`Vector2(Vector2) -> Vector2` + | :sg:`Vector2(x, y) -> Vector2` + | :sg:`Vector2((x, y)) -> Vector2` + + Some general information about the ``Vector2`` class. + + .. method:: dot + + | :sl:`calculates the dot- or scalar-product with the other vector` + | :sg:`dot(Vector2) -> float` + + .. ## Vector2.dot ## + + .. method:: cross + + | :sl:`calculates the cross- or vector-product` + | :sg:`cross(Vector2) -> Vector2` + + calculates the third component of the cross-product. + + .. ## Vector2.cross ## + + .. method:: magnitude + + | :sl:`returns the Euclidean magnitude of the vector.` + | :sg:`magnitude() -> float` + + calculates the magnitude of the vector which follows from the + theorem: ``vec.magnitude() == math.sqrt(vec.x**2 + vec.y**2)`` + + .. ## Vector2.magnitude ## + + .. method:: magnitude_squared + + | :sl:`returns the squared magnitude of the vector.` + | :sg:`magnitude_squared() -> float` + + calculates the magnitude of the vector which follows from the + theorem: ``vec.magnitude_squared() == vec.x**2 + vec.y**2``. This + is faster than ``vec.magnitude()`` because it avoids the square root. + + .. ## Vector2.magnitude_squared ## + + .. method:: length + + | :sl:`returns the Euclidean length of the vector.` + | :sg:`length() -> float` + + calculates the Euclidean length of the vector which follows from the + Pythagorean theorem: ``vec.length() == math.sqrt(vec.x**2 + vec.y**2)`` + + .. ## Vector2.length ## + + .. method:: length_squared + + | :sl:`returns the squared Euclidean length of the vector.` + | :sg:`length_squared() -> float` + + calculates the Euclidean length of the vector which follows from the + Pythagorean theorem: ``vec.length_squared() == vec.x**2 + vec.y**2``. + This is faster than ``vec.length()`` because it avoids the square root. + + .. ## Vector2.length_squared ## + + .. method:: normalize + + | :sl:`returns a vector with the same direction but length 1.` + | :sg:`normalize() -> Vector2` + + Returns a new vector that has ``length`` equal to ``1`` and the same + direction as self. + + .. ## Vector2.normalize ## + + .. method:: normalize_ip + + | :sl:`normalizes the vector in place so that its length is 1.` + | :sg:`normalize_ip() -> None` + + Normalizes the vector so that it has ``length`` equal to ``1``. + The direction of the vector is not changed. + + .. ## Vector2.normalize_ip ## + + .. method:: is_normalized + + | :sl:`tests if the vector is normalized i.e. has length == 1.` + | :sg:`is_normalized() -> Bool` + + Returns True if the vector has ``length`` equal to ``1``. Otherwise + it returns ``False``. + + .. ## Vector2.is_normalized ## + + .. method:: scale_to_length + + | :sl:`scales the vector to a given length.` + | :sg:`scale_to_length(float) -> None` + + Scales the vector so that it has the given length. The direction of the + vector is not changed. You can also scale to length ``0``. If the vector + is the zero vector (i.e. has length ``0`` thus no direction) a + ``ValueError`` is raised. + + .. ## Vector2.scale_to_length ## + + .. method:: reflect + + | :sl:`returns a vector reflected of a given normal.` + | :sg:`reflect(Vector2) -> Vector2` + + Returns a new vector that points in the direction as if self would bounce + of a surface characterized by the given surface normal. The length of the + new vector is the same as self's. + + .. ## Vector2.reflect ## + + .. method:: reflect_ip + + | :sl:`reflect the vector of a given normal in place.` + | :sg:`reflect_ip(Vector2) -> None` + + Changes the direction of self as if it would have been reflected of a + surface with the given surface normal. + + .. ## Vector2.reflect_ip ## + + .. method:: distance_to + + | :sl:`calculates the Euclidean distance to a given vector.` + | :sg:`distance_to(Vector2) -> float` + + .. ## Vector2.distance_to ## + + .. method:: distance_squared_to + + | :sl:`calculates the squared Euclidean distance to a given vector.` + | :sg:`distance_squared_to(Vector2) -> float` + + .. ## Vector2.distance_squared_to ## + + .. method:: lerp + + | :sl:`returns a linear interpolation to the given vector.` + | :sg:`lerp(Vector2, float) -> Vector2` + + Returns a Vector which is a linear interpolation between self and the + given Vector. The second parameter determines how far between self and + other the result is going to be. It must be a value between ``0`` and ``1`` + where ``0`` means self and ``1`` means other will be returned. + + .. ## Vector2.lerp ## + + .. method:: slerp + + | :sl:`returns a spherical interpolation to the given vector.` + | :sg:`slerp(Vector2, float) -> Vector2` + + Calculates the spherical interpolation from self to the given Vector. The + second argument - often called t - must be in the range ``[-1, 1]``. It + parametrizes where - in between the two vectors - the result should be. + If a negative value is given the interpolation will not take the + complement of the shortest path. + + .. ## Vector2.slerp ## + + .. method:: elementwise + + | :sl:`The next operation will be performed elementwise.` + | :sg:`elementwise() -> VectorElementwiseProxy` + + Applies the following operation to each element of the vector. + + .. ## Vector2.elementwise ## + + .. method:: rotate + + | :sl:`rotates a vector by a given angle in degrees.` + | :sg:`rotate(angle) -> Vector2` + + Returns a vector which has the same length as self but is rotated + counterclockwise by the given angle in degrees. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector2.rotate ## + + .. method:: rotate_rad + + | :sl:`rotates a vector by a given angle in radians.` + | :sg:`rotate_rad(angle) -> Vector2` + + Returns a vector which has the same length as self but is rotated + counterclockwise by the given angle in radians. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.0.0 + + .. ## Vector2.rotate_rad ## + + .. method:: rotate_ip + + | :sl:`rotates the vector by a given angle in degrees in place.` + | :sg:`rotate_ip(angle) -> None` + + Rotates the vector counterclockwise by the given angle in degrees. The + length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector2.rotate_ip ## + + .. method:: rotate_ip_rad + + | :sl:`rotates the vector by a given angle in radians in place.` + | :sg:`rotate_ip_rad(angle) -> None` + + DEPRECATED: Use rotate_rad_ip() instead. + + .. versionadded:: 2.0.0 + .. deprecated:: 2.1.1 + + .. ## Vector2.rotate_rad_ip ## + + .. method:: rotate_rad_ip + + | :sl:`rotates the vector by a given angle in radians in place.` + | :sg:`rotate_rad_ip(angle) -> None` + + Rotates the vector counterclockwise by the given angle in radians. The + length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.1.1 + + .. ## Vector2.rotate_rad_ip ## + + .. method:: angle_to + + | :sl:`calculates the angle to a given vector in degrees.` + | :sg:`angle_to(Vector2) -> float` + + Returns the angle between self and the given vector. + + .. ## Vector2.angle_to ## + + .. method:: as_polar + + | :sl:`returns a tuple with radial distance and azimuthal angle.` + | :sg:`as_polar() -> (r, phi)` + + Returns a tuple ``(r, phi)`` where r is the radial distance, and phi + is the azimuthal angle. + + .. ## Vector2.as_polar ## + + .. method:: from_polar + + | :sl:`Sets x and y from a polar coordinates tuple.` + | :sg:`from_polar((r, phi)) -> None` + + Sets x and y from a tuple (r, phi) where r is the radial distance, and + phi is the azimuthal angle. + + .. ## Vector2.from_polar ## + + .. method:: project + + | :sl:`projects a vector onto another.` + | :sg:`project(Vector2) -> Vector2` + + Returns the projected vector. This is useful for collision detection in finding the components in a certain direction (e.g. in direction of the wall). + For a more detailed explanation see `Wikipedia `_. + + .. versionadded:: 2.0.2 + + .. ## Vector2.project ## + + + .. method :: copy + + | :sl:`Returns a copy of itself.` + | :sg:`copy() -> Vector2` + + Returns a new Vector2 having the same dimensions. + + .. versionadded:: 2.1.1 + + .. ## Vector2.copy ## + + + .. method:: update + + | :sl:`Sets the coordinates of the vector.` + | :sg:`update() -> None` + | :sg:`update(int) -> None` + | :sg:`update(float) -> None` + | :sg:`update(Vector2) -> None` + | :sg:`update(x, y) -> None` + | :sg:`update((x, y)) -> None` + + Sets coordinates x and y in place. + + .. versionadded:: 1.9.5 + + .. ## Vector2.update ## + + .. ## pygame.math.Vector2 ## + +.. class:: Vector3 + + | :sl:`a 3-Dimensional Vector` + | :sg:`Vector3() -> Vector3` + | :sg:`Vector3(int) -> Vector3` + | :sg:`Vector3(float) -> Vector3` + | :sg:`Vector3(Vector3) -> Vector3` + | :sg:`Vector3(x, y, z) -> Vector3` + | :sg:`Vector3((x, y, z)) -> Vector3` + + Some general information about the Vector3 class. + + .. method:: dot + + | :sl:`calculates the dot- or scalar-product with the other vector` + | :sg:`dot(Vector3) -> float` + + .. ## Vector3.dot ## + + .. method:: cross + + | :sl:`calculates the cross- or vector-product` + | :sg:`cross(Vector3) -> Vector3` + + calculates the cross-product. + + .. ## Vector3.cross ## + + .. method:: magnitude + + | :sl:`returns the Euclidean magnitude of the vector.` + | :sg:`magnitude() -> float` + + calculates the magnitude of the vector which follows from the + theorem: ``vec.magnitude() == math.sqrt(vec.x**2 + vec.y**2 + vec.z**2)`` + + .. ## Vector3.magnitude ## + + .. method:: magnitude_squared + + | :sl:`returns the squared Euclidean magnitude of the vector.` + | :sg:`magnitude_squared() -> float` + + calculates the magnitude of the vector which follows from the + theorem: + ``vec.magnitude_squared() == vec.x**2 + vec.y**2 + vec.z**2``. + This is faster than ``vec.magnitude()`` because it avoids the + square root. + + .. ## Vector3.magnitude_squared ## + + .. method:: length + + | :sl:`returns the Euclidean length of the vector.` + | :sg:`length() -> float` + + calculates the Euclidean length of the vector which follows from the + Pythagorean theorem: + ``vec.length() == math.sqrt(vec.x**2 + vec.y**2 + vec.z**2)`` + + .. ## Vector3.length ## + + .. method:: length_squared + + | :sl:`returns the squared Euclidean length of the vector.` + | :sg:`length_squared() -> float` + + calculates the Euclidean length of the vector which follows from the + Pythagorean theorem: + ``vec.length_squared() == vec.x**2 + vec.y**2 + vec.z**2``. + This is faster than ``vec.length()`` because it avoids the square root. + + .. ## Vector3.length_squared ## + + .. method:: normalize + + | :sl:`returns a vector with the same direction but length 1.` + | :sg:`normalize() -> Vector3` + + Returns a new vector that has ``length`` equal to ``1`` and the same + direction as self. + + .. ## Vector3.normalize ## + + .. method:: normalize_ip + + | :sl:`normalizes the vector in place so that its length is 1.` + | :sg:`normalize_ip() -> None` + + Normalizes the vector so that it has ``length`` equal to ``1``. The + direction of the vector is not changed. + + .. ## Vector3.normalize_ip ## + + .. method:: is_normalized + + | :sl:`tests if the vector is normalized i.e. has length == 1.` + | :sg:`is_normalized() -> Bool` + + Returns True if the vector has ``length`` equal to ``1``. Otherwise it + returns ``False``. + + .. ## Vector3.is_normalized ## + + .. method:: scale_to_length + + | :sl:`scales the vector to a given length.` + | :sg:`scale_to_length(float) -> None` + + Scales the vector so that it has the given length. The direction of the + vector is not changed. You can also scale to length ``0``. If the vector + is the zero vector (i.e. has length ``0`` thus no direction) a + ``ValueError`` is raised. + + .. ## Vector3.scale_to_length ## + + .. method:: reflect + + | :sl:`returns a vector reflected of a given normal.` + | :sg:`reflect(Vector3) -> Vector3` + + Returns a new vector that points in the direction as if self would bounce + of a surface characterized by the given surface normal. The length of the + new vector is the same as self's. + + .. ## Vector3.reflect ## + + .. method:: reflect_ip + + | :sl:`reflect the vector of a given normal in place.` + | :sg:`reflect_ip(Vector3) -> None` + + Changes the direction of self as if it would have been reflected of a + surface with the given surface normal. + + .. ## Vector3.reflect_ip ## + + .. method:: distance_to + + | :sl:`calculates the Euclidean distance to a given vector.` + | :sg:`distance_to(Vector3) -> float` + + .. ## Vector3.distance_to ## + + .. method:: distance_squared_to + + | :sl:`calculates the squared Euclidean distance to a given vector.` + | :sg:`distance_squared_to(Vector3) -> float` + + .. ## Vector3.distance_squared_to ## + + .. method:: lerp + + | :sl:`returns a linear interpolation to the given vector.` + | :sg:`lerp(Vector3, float) -> Vector3` + + Returns a Vector which is a linear interpolation between self and the + given Vector. The second parameter determines how far between self an + other the result is going to be. It must be a value between ``0`` and + ``1``, where ``0`` means self and ``1`` means other will be returned. + + .. ## Vector3.lerp ## + + .. method:: slerp + + | :sl:`returns a spherical interpolation to the given vector.` + | :sg:`slerp(Vector3, float) -> Vector3` + + Calculates the spherical interpolation from self to the given Vector. The + second argument - often called t - must be in the range ``[-1, 1]``. It + parametrizes where - in between the two vectors - the result should be. + If a negative value is given the interpolation will not take the + complement of the shortest path. + + .. ## Vector3.slerp ## + + .. method:: elementwise + + | :sl:`The next operation will be performed elementwise.` + | :sg:`elementwise() -> VectorElementwiseProxy` + + Applies the following operation to each element of the vector. + + .. ## Vector3.elementwise ## + + .. method:: rotate + + | :sl:`rotates a vector by a given angle in degrees.` + | :sg:`rotate(angle, Vector3) -> Vector3` + + Returns a vector which has the same length as self but is rotated + counterclockwise by the given angle in degrees around the given axis. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector3.rotate ## + + .. method:: rotate_rad + + | :sl:`rotates a vector by a given angle in radians.` + | :sg:`rotate_rad(angle, Vector3) -> Vector3` + + Returns a vector which has the same length as self but is rotated + counterclockwise by the given angle in radians around the given axis. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.0.0 + + .. ## Vector3.rotate_rad ## + + .. method:: rotate_ip + + | :sl:`rotates the vector by a given angle in degrees in place.` + | :sg:`rotate_ip(angle, Vector3) -> None` + + Rotates the vector counterclockwise around the given axis by the given + angle in degrees. The length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector3.rotate_ip ## + + .. method:: rotate_ip_rad + + | :sl:`rotates the vector by a given angle in radians in place.` + | :sg:`rotate_ip_rad(angle, Vector3) -> None` + + DEPRECATED: Use rotate_rad_ip() instead. + + .. versionadded:: 2.0.0 + .. deprecated:: 2.1.1 + + .. ## Vector3.rotate_ip_rad ## + + .. method:: rotate_rad_ip + + | :sl:`rotates the vector by a given angle in radians in place.` + | :sg:`rotate_rad_ip(angle, Vector3) -> None` + + Rotates the vector counterclockwise around the given axis by the given + angle in radians. The length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.1.1 + + .. ## Vector3.rotate_rad_ip ## + + .. method:: rotate_x + + | :sl:`rotates a vector around the x-axis by the angle in degrees.` + | :sg:`rotate_x(angle) -> Vector3` + + Returns a vector which has the same length as self but is rotated + counterclockwise around the x-axis by the given angle in degrees. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector3.rotate_x ## + + .. method:: rotate_x_rad + + | :sl:`rotates a vector around the x-axis by the angle in radians.` + | :sg:`rotate_x_rad(angle) -> Vector3` + + Returns a vector which has the same length as self but is rotated + counterclockwise around the x-axis by the given angle in radians. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.0.0 + + .. ## Vector3.rotate_x_rad ## + + .. method:: rotate_x_ip + + | :sl:`rotates the vector around the x-axis by the angle in degrees in place.` + | :sg:`rotate_x_ip(angle) -> None` + + Rotates the vector counterclockwise around the x-axis by the given angle + in degrees. The length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector3.rotate_x_ip ## + + .. method:: rotate_x_ip_rad + + | :sl:`rotates the vector around the x-axis by the angle in radians in place.` + | :sg:`rotate_x_ip_rad(angle) -> None` + + DEPRECATED: Use rotate_x_rad_ip() instead. + + .. versionadded:: 2.0.0 + .. deprecated:: 2.1.1 + + .. ## Vector3.rotate_x_ip_rad ## + + .. method:: rotate_x_rad_ip + + | :sl:`rotates the vector around the x-axis by the angle in radians in place.` + | :sg:`rotate_x_rad_ip(angle) -> None` + + Rotates the vector counterclockwise around the x-axis by the given angle + in radians. The length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.1.1 + + .. ## Vector3.rotate_x_rad_ip ## + + .. method:: rotate_y + + | :sl:`rotates a vector around the y-axis by the angle in degrees.` + | :sg:`rotate_y(angle) -> Vector3` + + Returns a vector which has the same length as self but is rotated + counterclockwise around the y-axis by the given angle in degrees. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector3.rotate_y ## + + .. method:: rotate_y_rad + + | :sl:`rotates a vector around the y-axis by the angle in radians.` + | :sg:`rotate_y_rad(angle) -> Vector3` + + Returns a vector which has the same length as self but is rotated + counterclockwise around the y-axis by the given angle in radians. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.0.0 + + .. ## Vector3.rotate_y_rad ## + + .. method:: rotate_y_ip + + | :sl:`rotates the vector around the y-axis by the angle in degrees in place.` + | :sg:`rotate_y_ip(angle) -> None` + + Rotates the vector counterclockwise around the y-axis by the given angle + in degrees. The length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector3.rotate_y_ip ## + + .. method:: rotate_y_ip_rad + + | :sl:`rotates the vector around the y-axis by the angle in radians in place.` + | :sg:`rotate_y_ip_rad(angle) -> None` + + DEPRECATED: Use rotate_y_rad_ip() instead. + + .. versionadded:: 2.0.0 + .. deprecated:: 2.1.1 + + .. ## Vector3.rotate_y_ip_rad ## + + .. method:: rotate_y_rad_ip + + | :sl:`rotates the vector around the y-axis by the angle in radians in place.` + | :sg:`rotate_y_rad_ip(angle) -> None` + + Rotates the vector counterclockwise around the y-axis by the given angle + in radians. The length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.1.1 + + .. ## Vector3.rotate_y_rad_ip ## + + .. method:: rotate_z + + | :sl:`rotates a vector around the z-axis by the angle in degrees.` + | :sg:`rotate_z(angle) -> Vector3` + + Returns a vector which has the same length as self but is rotated + counterclockwise around the z-axis by the given angle in degrees. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector3.rotate_z ## + + .. method:: rotate_z_rad + + | :sl:`rotates a vector around the z-axis by the angle in radians.` + | :sg:`rotate_z_rad(angle) -> Vector3` + + Returns a vector which has the same length as self but is rotated + counterclockwise around the z-axis by the given angle in radians. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.0.0 + + .. ## Vector3.rotate_z_rad ## + + .. method:: rotate_z_ip + + | :sl:`rotates the vector around the z-axis by the angle in degrees in place.` + | :sg:`rotate_z_ip(angle) -> None` + + Rotates the vector counterclockwise around the z-axis by the given angle + in degrees. The length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. ## Vector3.rotate_z_ip ## + + .. method:: rotate_z_ip_rad + + | :sl:`rotates the vector around the z-axis by the angle in radians in place.` + | :sg:`rotate_z_ip_rad(angle) -> None` + + DEPRECATED: Use rotate_z_rad_ip() instead. + + .. deprecated:: 2.1.1 + + .. ## Vector3.rotate_z_ip_rad ## + + .. method:: rotate_z_rad_ip + + | :sl:`rotates the vector around the z-axis by the angle in radians in place.` + | :sg:`rotate_z_rad_ip(angle) -> None` + + Rotates the vector counterclockwise around the z-axis by the given angle + in radians. The length of the vector is not changed. + (Note that due to pygame's inverted y coordinate system, the rotation + will look clockwise if displayed). + + .. versionadded:: 2.1.1 + + .. ## Vector3.rotate_z_rad_ip ## + + .. method:: angle_to + + | :sl:`calculates the angle to a given vector in degrees.` + | :sg:`angle_to(Vector3) -> float` + + Returns the angle between self and the given vector. + + .. ## Vector3.angle_to ## + + .. method:: as_spherical + + | :sl:`returns a tuple with radial distance, inclination and azimuthal angle.` + | :sg:`as_spherical() -> (r, theta, phi)` + + Returns a tuple ``(r, theta, phi)`` where r is the radial distance, theta is + the inclination angle and phi is the azimuthal angle. + + .. ## Vector3.as_spherical ## + + .. method:: from_spherical + + | :sl:`Sets x, y and z from a spherical coordinates 3-tuple.` + | :sg:`from_spherical((r, theta, phi)) -> None` + + Sets x, y and z from a tuple ``(r, theta, phi)`` where r is the radial + distance, theta is the inclination angle and phi is the azimuthal angle. + + .. ## Vector3.from_spherical ## + + .. method:: project + + | :sl:`projects a vector onto another.` + | :sg:`project(Vector3) -> Vector3` + + Returns the projected vector. This is useful for collision detection in finding the components in a certain direction (e.g. in direction of the wall). + For a more detailed explanation see `Wikipedia `_. + + .. versionadded:: 2.0.2 + + .. ## Vector3.project ## + + .. method :: copy + + | :sl:`Returns a copy of itself.` + | :sg:`copy() -> Vector3` + + Returns a new Vector3 having the same dimensions. + + .. versionadded:: 2.1.1 + + .. ## Vector3.copy ## + + .. method:: update + + | :sl:`Sets the coordinates of the vector.` + | :sg:`update() -> None` + | :sg:`update(int) -> None` + | :sg:`update(float) -> None` + | :sg:`update(Vector3) -> None` + | :sg:`update(x, y, z) -> None` + | :sg:`update((x, y, z)) -> None` + + Sets coordinates x, y, and z in place. + + .. versionadded:: 1.9.5 + + .. ## Vector3.update ## + + .. ## ## + + .. ## pygame.math.Vector3 ## + +.. ## pygame.math ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/midi.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/midi.rst.txt new file mode 100644 index 0000000..edc9f25 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/midi.rst.txt @@ -0,0 +1,484 @@ +.. include:: common.txt + +:mod:`pygame.midi` +================== + +.. module:: pygame.midi + :synopsis: pygame module for interacting with midi input and output. + +| :sl:`pygame module for interacting with midi input and output.` + +.. versionadded:: 1.9.0 + +The midi module can send output to midi devices and get input from midi +devices. It can also list midi devices on the system. + +The midi module supports real and virtual midi devices. + +It uses the portmidi library. Is portable to which ever platforms portmidi +supports (currently Windows, Mac OS X, and Linux). + +This uses pyportmidi for now, but may use its own bindings at some point in the +future. The pyportmidi bindings are included with pygame. + +| + +.. versionadded:: 2.0.0 + +These are pygame events (:mod:`pygame.event`) reserved for midi use. The +``MIDIIN`` event is used by :func:`pygame.midi.midis2events` when converting +midi events to pygame events. + +:: + + MIDIIN + MIDIOUT + +| + +.. function:: init + + | :sl:`initialize the midi module` + | :sg:`init() -> None` + + Initializes the :mod:`pygame.midi` module. Must be called before using the + :mod:`pygame.midi` module. + + It is safe to call this more than once. + + .. ## pygame.midi.init ## + +.. function:: quit + + | :sl:`uninitialize the midi module` + | :sg:`quit() -> None` + + Uninitializes the :mod:`pygame.midi` module. If :func:`pygame.midi.init` was + called to initialize the :mod:`pygame.midi` module, then this function will + be called automatically when your program exits. + + It is safe to call this function more than once. + + .. ## pygame.midi.quit ## + +.. function:: get_init + + | :sl:`returns True if the midi module is currently initialized` + | :sg:`get_init() -> bool` + + Gets the initialization state of the :mod:`pygame.midi` module. + + :returns: ``True`` if the :mod:`pygame.midi` module is currently initialized. + :rtype: bool + + .. versionadded:: 1.9.5 + + .. ## pygame.midi.get_init ## + +.. class:: Input + + | :sl:`Input is used to get midi input from midi devices.` + | :sg:`Input(device_id) -> None` + | :sg:`Input(device_id, buffer_size) -> None` + + :param int device_id: midi device id + :param int buffer_size: (optional) the number of input events to be buffered + + .. method:: close + + | :sl:`closes a midi stream, flushing any pending buffers.` + | :sg:`close() -> None` + + PortMidi attempts to close open streams when the application exits. + + .. note:: This is particularly difficult under Windows. + + .. ## Input.close ## + + .. method:: poll + + | :sl:`returns True if there's data, or False if not.` + | :sg:`poll() -> bool` + + Used to indicate if any data exists. + + :returns: ``True`` if there is data, ``False`` otherwise + :rtype: bool + + :raises MidiException: on error + + .. ## Input.poll ## + + .. method:: read + + | :sl:`reads num_events midi events from the buffer.` + | :sg:`read(num_events) -> midi_event_list` + + Reads from the input buffer and gives back midi events. + + :param int num_events: number of input events to read + + :returns: the format for midi_event_list is + ``[[[status, data1, data2, data3], timestamp], ...]`` + :rtype: list + + .. ## Input.read ## + + .. ## pygame.midi.Input ## + +.. class:: Output + + | :sl:`Output is used to send midi to an output device` + | :sg:`Output(device_id) -> None` + | :sg:`Output(device_id, latency=0) -> None` + | :sg:`Output(device_id, buffer_size=256) -> None` + | :sg:`Output(device_id, latency, buffer_size) -> None` + + The ``buffer_size`` specifies the number of output events to be buffered + waiting for output. In some cases (see below) PortMidi does not buffer + output at all and merely passes data to a lower-level API, in which case + buffersize is ignored. + + ``latency`` is the delay in milliseconds applied to timestamps to determine + when the output should actually occur. If ``latency`` is <<0, 0 is assumed. + + If ``latency`` is zero, timestamps are ignored and all output is delivered + immediately. If ``latency`` is greater than zero, output is delayed until the + message timestamp plus the ``latency``. In some cases, PortMidi can obtain + better timing than your application by passing timestamps along to the + device driver or hardware. Latency may also help you to synchronize midi + data to audio data by matching midi latency to the audio buffer latency. + + .. note:: + Time is measured relative to the time source indicated by time_proc. + Timestamps are absolute, not relative delays or offsets. + + .. method:: abort + + | :sl:`terminates outgoing messages immediately` + | :sg:`abort() -> None` + + The caller should immediately close the output port; this call may result + in transmission of a partial midi message. There is no abort for Midi + input because the user can simply ignore messages in the buffer and close + an input device at any time. + + .. ## Output.abort ## + + .. method:: close + + | :sl:`closes a midi stream, flushing any pending buffers.` + | :sg:`close() -> None` + + PortMidi attempts to close open streams when the application exits. + + .. note:: This is particularly difficult under Windows. + + .. ## Output.close ## + + .. method:: note_off + + | :sl:`turns a midi note off (note must be on)` + | :sg:`note_off(note, velocity=None, channel=0) -> None` + + Turn a note off in the output stream. The note must already be on for + this to work correctly. + + .. ## Output.note_off ## + + .. method:: note_on + + | :sl:`turns a midi note on (note must be off)` + | :sg:`note_on(note, velocity=None, channel=0) -> None` + + Turn a note on in the output stream. The note must already be off for + this to work correctly. + + .. ## Output.note_on ## + + .. method:: set_instrument + + | :sl:`select an instrument, with a value between 0 and 127` + | :sg:`set_instrument(instrument_id, channel=0) -> None` + + Select an instrument. + + .. ## Output.set_instrument ## + + .. method:: pitch_bend + + | :sl:`modify the pitch of a channel.` + | :sg:`set_instrument(value=0, channel=0) -> None` + + Adjust the pitch of a channel. The value is a signed integer + from -8192 to +8191. For example, 0 means "no change", +4096 is + typically a semitone higher, and -8192 is 1 whole tone lower (though + the musical range corresponding to the pitch bend range can also be + changed in some synthesizers). + + If no value is given, the pitch bend is returned to "no change". + + .. versionadded:: 1.9.4 + + .. method:: write + + | :sl:`writes a list of midi data to the Output` + | :sg:`write(data) -> None` + + Writes series of MIDI information in the form of a list. + + :param list data: data to write, the expected format is + ``[[[status, data1=0, data2=0, ...], timestamp], ...]`` + with the ``data#`` fields being optional + + :raises IndexError: if more than 1024 elements in the data list + + Example: + :: + + # Program change at time 20000 and 500ms later send note 65 with + # velocity 100. + write([[[0xc0, 0, 0], 20000], [[0x90, 60, 100], 20500]]) + + .. note:: + - Timestamps will be ignored if latency = 0 + - To get a note to play immediately, send MIDI info with timestamp + read from function Time + - Optional data fields: ``write([[[0xc0, 0, 0], 20000]])`` is + equivalent to ``write([[[0xc0], 20000]])`` + + .. ## Output.write ## + + .. method:: write_short + + | :sl:`writes up to 3 bytes of midi data to the Output` + | :sg:`write_short(status) -> None` + | :sg:`write_short(status, data1=0, data2=0) -> None` + + Output MIDI information of 3 bytes or less. The ``data`` fields are + optional and assumed to be 0 if omitted. + + Examples of status byte values: + :: + + 0xc0 # program change + 0x90 # note on + # etc. + + Example: + :: + + # note 65 on with velocity 100 + write_short(0x90, 65, 100) + + .. ## Output.write_short ## + + .. method:: write_sys_ex + + | :sl:`writes a timestamped system-exclusive midi message.` + | :sg:`write_sys_ex(when, msg) -> None` + + Writes a timestamped system-exclusive midi message. + + :param msg: midi message + :type msg: list[int] or str + :param when: timestamp in milliseconds + + Example: + :: + + midi_output.write_sys_ex(0, '\xF0\x7D\x10\x11\x12\x13\xF7') + + # is equivalent to + + midi_output.write_sys_ex(pygame.midi.time(), + [0xF0, 0x7D, 0x10, 0x11, 0x12, 0x13, 0xF7]) + + .. ## Output.write_sys_ex ## + + .. ## pygame.midi.Output ## + +.. function:: get_count + + | :sl:`gets the number of devices.` + | :sg:`get_count() -> num_devices` + + Device ids range from 0 to ``get_count() - 1`` + + .. ## pygame.midi.get_count ## + +.. function:: get_default_input_id + + | :sl:`gets default input device number` + | :sg:`get_default_input_id() -> default_id` + + The following describes the usage details for this function and the + :func:`get_default_output_id` function. + + Return the default device ID or ``-1`` if there are no devices. The result + can be passed to the :class:`Input`/:class:`Output` class. + + On a PC the user can specify a default device by setting an environment + variable. To use device #1, for example: + :: + + set PM_RECOMMENDED_INPUT_DEVICE=1 + or + set PM_RECOMMENDED_OUTPUT_DEVICE=1 + + The user should first determine the available device ID by using the + supplied application "testin" or "testout". + + In general, the registry is a better place for this kind of info. With + USB devices that can come and go, using integers is not very reliable + for device identification. Under Windows, if ``PM_RECOMMENDED_INPUT_DEVICE`` + (or ``PM_RECOMMENDED_OUTPUT_DEVICE``) is NOT found in the environment, + then the default device is obtained by looking for a string in the registry + under: + :: + + HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Input_Device + or + HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Output_Device + + + The number of the first device with a substring that matches the + string exactly is returned. For example, if the string in the registry is + "USB" and device 1 is named "In USB MidiSport 1x1", then that will be + the default input because it contains the string "USB". + + In addition to the name, :func:`get_device_info()` returns "interf", which is + the interface name. The "interface" is the underlying software system or + API used by PortMidi to access devices. Supported interfaces: + :: + + MMSystem # the only Win32 interface currently supported + ALSA # the only Linux interface currently supported + CoreMIDI # the only Mac OS X interface currently supported + # DirectX - not implemented + # OSS - not implemented + + To specify both the interface and the device name in the registry, separate + the two with a comma and a space. The string before the comma must be a + substring of the "interf" string and the string after the space must be a + substring of the "name" name string in order to match the device. e.g.: + :: + + MMSystem, In USB MidiSport 1x1 + + .. note:: + In the current release, the default is simply the first device (the + input or output device with the lowest PmDeviceID). + + .. ## pygame.midi.get_default_input_id ## + +.. function:: get_default_output_id + + | :sl:`gets default output device number` + | :sg:`get_default_output_id() -> default_id` + + See :func:`get_default_input_id` for usage details. + + .. ## pygame.midi.get_default_output_id ## + +.. function:: get_device_info + + | :sl:`returns information about a midi device` + | :sg:`get_device_info(an_id) -> (interf, name, input, output, opened)` + | :sg:`get_device_info(an_id) -> None` + + Gets the device info for a given id. + + :param int an_id: id of the midi device being queried + + :returns: if the id is out of range ``None`` is returned, otherwise + a tuple of (interf, name, input, output, opened) is returned. + + - interf: string describing the device interface (e.g. 'ALSA') + - name: string name of the device (e.g. 'Midi Through Port-0') + - input: 1 if the device is an input device, otherwise 0 + - output: 1 if the device is an output device, otherwise 0 + - opened: 1 if the device is opened, otherwise 0 + :rtype: tuple or None + + .. ## pygame.midi.get_device_info ## + +.. function:: midis2events + + | :sl:`converts midi events to pygame events` + | :sg:`midis2events(midi_events, device_id) -> [Event, ...]` + + Takes a sequence of midi events and returns list of pygame events. + + The ``midi_events`` data is expected to be a sequence of + ``((status, data1, data2, data3), timestamp)`` midi events (all values + required). + + :returns: a list of pygame events of event type ``MIDIIN`` + :rtype: list + + .. ## pygame.midi.midis2events ## + +.. function:: time + + | :sl:`returns the current time in ms of the PortMidi timer` + | :sg:`time() -> time` + + The time is reset to 0 when the :mod:`pygame.midi` module is initialized. + + .. ## pygame.midi.time ## + + +.. function:: frequency_to_midi + + | :sl:`Converts a frequency into a MIDI note. Rounds to the closest midi note.` + | :sg:`frequency_to_midi(midi_note) -> midi_note` + + example: + :: + + frequency_to_midi(27.5) == 21 + + .. versionadded:: 1.9.5 + + .. ## pygame.midi.frequency_to_midi ## + + +.. function:: midi_to_frequency + + | :sl:`Converts a midi note to a frequency.` + | :sg:`midi_to_frequency(midi_note) -> frequency` + + example: + :: + + midi_to_frequency(21) == 27.5 + + .. versionadded:: 1.9.5 + + .. ## pygame.midi.midi_to_frequency ## + + +.. function:: midi_to_ansi_note + + | :sl:`Returns the Ansi Note name for a midi number.` + | :sg:`midi_to_ansi_note(midi_note) -> ansi_note` + + example: + :: + + midi_to_ansi_note(21) == 'A0' + + .. versionadded:: 1.9.5 + + .. ## pygame.midi.midi_to_ansi_note ## + +.. exception:: MidiException + + | :sl:`exception that pygame.midi functions and classes can raise` + | :sg:`MidiException(errno) -> None` + + .. ## pygame.midi.MidiException ## + + +.. ## pygame.midi ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/mixer.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/mixer.rst.txt new file mode 100644 index 0000000..3a0fecc --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/mixer.rst.txt @@ -0,0 +1,604 @@ +.. include:: common.txt + +:mod:`pygame.mixer` +=================== + +.. module:: pygame.mixer + :synopsis: pygame module for loading and playing sounds + +| :sl:`pygame module for loading and playing sounds` + +This module contains classes for loading Sound objects and controlling +playback. The mixer module is optional and depends on SDL_mixer. Your program +should test that :mod:`pygame.mixer` is available and initialized before using +it. + +The mixer module has a limited number of channels for playback of sounds. +Usually programs tell pygame to start playing audio and it selects an available +channel automatically. The default is 8 simultaneous channels, but complex +programs can get more precise control over the number of channels and their +use. + +All sound playback is mixed in background threads. When you begin to play a +Sound object, it will return immediately while the sound continues to play. A +single Sound object can also be actively played back multiple times. + +The mixer also has a special streaming channel. This is for music playback and +is accessed through the :mod:`pygame.mixer.music` module. Consider using this +module for playing long running music. Unlike mixer module, the music module +streams the music from the files without loading music at once into memory. + +The mixer module must be initialized like other pygame modules, but it has some +extra conditions. The ``pygame.mixer.init()`` function takes several optional +arguments to control the playback rate and sample size. Pygame will default to +reasonable values, but pygame cannot perform Sound resampling, so the mixer +should be initialized to match the values of your audio resources. + +``NOTE``: For less laggy sound use a smaller buffer size. The default +is set to reduce the chance of scratchy sounds on some computers. You can +change the default buffer by calling :func:`pygame.mixer.pre_init` before +:func:`pygame.mixer.init` or :func:`pygame.init` is called. For example: +``pygame.mixer.pre_init(44100,-16,2, 1024)`` + + +.. function:: init + + | :sl:`initialize the mixer module` + | :sg:`init(frequency=44100, size=-16, channels=2, buffer=512, devicename=None, allowedchanges=AUDIO_ALLOW_FREQUENCY_CHANGE | AUDIO_ALLOW_CHANNELS_CHANGE) -> None` + + Initialize the mixer module for Sound loading and playback. The default + arguments can be overridden to provide specific audio mixing. Keyword + arguments are accepted. For backwards compatibility, argument values of + 0 are replaced with the startup defaults, except for ``allowedchanges``, + where -1 is used. (startup defaults may be changed by a :func:`pre_init` call). + + The size argument represents how many bits are used for each audio sample. + If the value is negative then signed sample values will be used. Positive + values mean unsigned audio samples will be used. An invalid value raises an + exception. + + The channels argument is used to specify whether to use mono or stereo. 1 + for mono and 2 for stereo. + + The buffer argument controls the number of internal samples used in the + sound mixer. The default value should work for most cases. It can be lowered + to reduce latency, but sound dropout may occur. It can be raised to larger + values to ensure playback never skips, but it will impose latency on sound + playback. The buffer size must be a power of two (if not it is rounded up to + the next nearest power of 2). + + Some platforms require the :mod:`pygame.mixer` module to be initialized + after the display modules have initialized. The top level ``pygame.init()`` + takes care of this automatically, but cannot pass any arguments to the mixer + init. To solve this, mixer has a function ``pygame.mixer.pre_init()`` to set + the proper defaults before the toplevel init is used. + + When using allowedchanges=0 it will convert the samples at runtime to match + what the hardware supports. For example a sound card may not + support 16bit sound samples, so instead it will use 8bit samples internally. + If AUDIO_ALLOW_FORMAT_CHANGE is supplied, then the requested format will + change to the closest that SDL2 supports. + + Apart from 0, allowedchanged accepts the following constants ORed together: + + - AUDIO_ALLOW_FREQUENCY_CHANGE + - AUDIO_ALLOW_FORMAT_CHANGE + - AUDIO_ALLOW_CHANNELS_CHANGE + - AUDIO_ALLOW_ANY_CHANGE + + It is safe to call this more than once, but after the mixer is initialized + you cannot change the playback arguments without first calling + ``pygame.mixer.quit()``. + + .. versionchanged:: 1.8 The default ``buffersize`` changed from 1024 to 3072. + .. versionchanged:: 1.9.1 The default ``buffersize`` changed from 3072 to 4096. + .. versionchanged:: 2.0.0 The default ``buffersize`` changed from 4096 to 512. + .. versionchanged:: 2.0.0 The default ``frequency`` changed from 22050 to 44100. + .. versionchanged:: 2.0.0 ``size`` can be 32 (32-bit floats). + .. versionchanged:: 2.0.0 ``channels`` can also be 4 or 6. + .. versionadded:: 2.0.0 ``allowedchanges``, ``devicename`` arguments added + + .. ## pygame.mixer.init ## + +.. function:: pre_init + + | :sl:`preset the mixer init arguments` + | :sg:`pre_init(frequency=44100, size=-16, channels=2, buffer=512, devicename=None, allowedchanges=AUDIO_ALLOW_FREQUENCY_CHANGE | AUDIO_ALLOW_CHANNELS_CHANGE) -> None` + + Call pre_init to change the defaults used when the real + ``pygame.mixer.init()`` is called. Keyword arguments are accepted. The best + way to set custom mixer playback values is to call + ``pygame.mixer.pre_init()`` before calling the top level ``pygame.init()``. + For backwards compatibility, argument values of 0 are replaced with the + startup defaults, except for ``allowedchanges``, where -1 is used. + + .. versionchanged:: 1.8 The default ``buffersize`` changed from 1024 to 3072. + .. versionchanged:: 1.9.1 The default ``buffersize`` changed from 3072 to 4096. + .. versionchanged:: 2.0.0 The default ``buffersize`` changed from 4096 to 512. + .. versionchanged:: 2.0.0 The default ``frequency`` changed from 22050 to 44100. + .. versionadded:: 2.0.0 ``allowedchanges``, ``devicename`` arguments added + + .. ## pygame.mixer.pre_init ## + +.. function:: quit + + | :sl:`uninitialize the mixer` + | :sg:`quit() -> None` + + This will uninitialize :mod:`pygame.mixer`. All playback will stop and any + loaded Sound objects may not be compatible with the mixer if it is + reinitialized later. + + .. ## pygame.mixer.quit ## + +.. function:: get_init + + | :sl:`test if the mixer is initialized` + | :sg:`get_init() -> (frequency, format, channels)` + + If the mixer is initialized, this returns the playback arguments it is + using. If the mixer has not been initialized this returns ``None``. + + .. ## pygame.mixer.get_init ## + +.. function:: stop + + | :sl:`stop playback of all sound channels` + | :sg:`stop() -> None` + + This will stop all playback of all active mixer channels. + + .. ## pygame.mixer.stop ## + +.. function:: pause + + | :sl:`temporarily stop playback of all sound channels` + | :sg:`pause() -> None` + + This will temporarily stop all playback on the active mixer channels. The + playback can later be resumed with ``pygame.mixer.unpause()`` + + .. ## pygame.mixer.pause ## + +.. function:: unpause + + | :sl:`resume paused playback of sound channels` + | :sg:`unpause() -> None` + + This will resume all active sound channels after they have been paused. + + .. ## pygame.mixer.unpause ## + +.. function:: fadeout + + | :sl:`fade out the volume on all sounds before stopping` + | :sg:`fadeout(time) -> None` + + This will fade out the volume on all active channels over the time argument + in milliseconds. After the sound is muted the playback will stop. + + .. ## pygame.mixer.fadeout ## + +.. function:: set_num_channels + + | :sl:`set the total number of playback channels` + | :sg:`set_num_channels(count) -> None` + + Sets the number of available channels for the mixer. The default value is 8. + The value can be increased or decreased. If the value is decreased, sounds + playing on the truncated channels are stopped. + + .. ## pygame.mixer.set_num_channels ## + +.. function:: get_num_channels + + | :sl:`get the total number of playback channels` + | :sg:`get_num_channels() -> count` + + Returns the number of currently active playback channels. + + .. ## pygame.mixer.get_num_channels ## + +.. function:: set_reserved + + | :sl:`reserve channels from being automatically used` + | :sg:`set_reserved(count) -> count` + + The mixer can reserve any number of channels that will not be automatically + selected for playback by Sounds. If sounds are currently playing on the + reserved channels they will not be stopped. + + This allows the application to reserve a specific number of channels for + important sounds that must not be dropped or have a guaranteed channel to + play on. + + Will return number of channels actually reserved, this may be less than requested + depending on the number of channels previously allocated. + + .. ## pygame.mixer.set_reserved ## + +.. function:: find_channel + + | :sl:`find an unused channel` + | :sg:`find_channel(force=False) -> Channel` + + This will find and return an inactive Channel object. If there are no + inactive Channels this function will return ``None``. If there are no + inactive channels and the force argument is ``True``, this will find the + Channel with the longest running Sound and return it. + + .. ## pygame.mixer.find_channel ## + +.. function:: get_busy + + | :sl:`test if any sound is being mixed` + | :sg:`get_busy() -> bool` + + Returns ``True`` if the mixer is busy mixing any channels. If the mixer is + idle then this return ``False``. + + .. ## pygame.mixer.get_busy ## + +.. function:: get_sdl_mixer_version + + | :sl:`get the mixer's SDL version` + | :sg:`get_sdl_mixer_version() -> (major, minor, patch)` + | :sg:`get_sdl_mixer_version(linked=True) -> (major, minor, patch)` + + :param bool linked: if ``True`` (default) the linked version number is + returned, otherwise the compiled version number is returned + + :returns: the mixer's SDL library version number (linked or compiled + depending on the ``linked`` parameter) as a tuple of 3 integers + ``(major, minor, patch)`` + :rtype: tuple + + .. note:: + The linked and compile version numbers should be the same. + + .. versionadded:: 2.0.0 + + .. ## pygame.mixer.get_sdl_mixer_version ## + +.. class:: Sound + + | :sl:`Create a new Sound object from a file or buffer object` + | :sg:`Sound(filename) -> Sound` + | :sg:`Sound(file=filename) -> Sound` + | :sg:`Sound(file=pathlib_path) -> Sound` + | :sg:`Sound(buffer) -> Sound` + | :sg:`Sound(buffer=buffer) -> Sound` + | :sg:`Sound(object) -> Sound` + | :sg:`Sound(file=object) -> Sound` + | :sg:`Sound(array=object) -> Sound` + + Load a new sound buffer from a filename, a python file object or a readable + buffer object. Limited resampling will be performed to help the sample match + the initialize arguments for the mixer. A Unicode string can only be a file + pathname. A bytes object can be either a pathname or a buffer object. + Use the 'file' or 'buffer' keywords to avoid ambiguity; otherwise Sound may + guess wrong. If the array keyword is used, the object is expected to export + a new buffer interface (The object is checked for a buffer interface first.) + + The Sound object represents actual sound sample data. Methods that change + the state of the Sound object will the all instances of the Sound playback. + A Sound object also exports a new buffer interface. + + The Sound can be loaded from an ``OGG`` audio file or from an uncompressed + ``WAV``. + + Note: The buffer will be copied internally, no data will be shared between + it and the Sound object. + + For now buffer and array support is consistent with ``sndarray.make_sound`` + for Numeric arrays, in that sample sign and byte order are ignored. This + will change, either by correctly handling sign and byte order, or by raising + an exception when different. Also, source samples are truncated to fit the + audio sample size. This will not change. + + .. versionadded:: 1.8 ``pygame.mixer.Sound(buffer)`` + .. versionadded:: 1.9.2 + :class:`pygame.mixer.Sound` keyword arguments and array interface support + .. versionadded:: 2.0.1 pathlib.Path support on Python 3. + + .. method:: play + + | :sl:`begin sound playback` + | :sg:`play(loops=0, maxtime=0, fade_ms=0) -> Channel` + + Begin playback of the Sound (i.e., on the computer's speakers) on an + available Channel. This will forcibly select a Channel, so playback may + cut off a currently playing sound if necessary. + + The loops argument controls how many times the sample will be repeated + after being played the first time. A value of 5 means that the sound will + be played once, then repeated five times, and so is played a total of six + times. The default value (zero) means the Sound is not repeated, and so + is only played once. If loops is set to -1 the Sound will loop + indefinitely (though you can still call ``stop()`` to stop it). + + The maxtime argument can be used to stop playback after a given number of + milliseconds. + + The fade_ms argument will make the sound start playing at 0 volume and + fade up to full volume over the time given. The sample may end before the + fade-in is complete. + + This returns the Channel object for the channel that was selected. + + .. ## Sound.play ## + + .. method:: stop + + | :sl:`stop sound playback` + | :sg:`stop() -> None` + + This will stop the playback of this Sound on any active Channels. + + .. ## Sound.stop ## + + .. method:: fadeout + + | :sl:`stop sound playback after fading out` + | :sg:`fadeout(time) -> None` + + This will stop playback of the sound after fading it out over the time + argument in milliseconds. The Sound will fade and stop on all actively + playing channels. + + .. ## Sound.fadeout ## + + .. method:: set_volume + + | :sl:`set the playback volume for this Sound` + | :sg:`set_volume(value) -> None` + + This will set the playback volume (loudness) for this Sound. This will + immediately affect the Sound if it is playing. It will also affect any + future playback of this Sound. + + :param float value: volume in the range of 0.0 to 1.0 (inclusive) + + | If value < 0.0, the volume will not be changed + | If value > 1.0, the volume will be set to 1.0 + + .. ## Sound.set_volume ## + + .. method:: get_volume + + | :sl:`get the playback volume` + | :sg:`get_volume() -> value` + + Return a value from 0.0 to 1.0 representing the volume for this Sound. + + .. ## Sound.get_volume ## + + .. method:: get_num_channels + + | :sl:`count how many times this Sound is playing` + | :sg:`get_num_channels() -> count` + + Return the number of active channels this sound is playing on. + + .. ## Sound.get_num_channels ## + + .. method:: get_length + + | :sl:`get the length of the Sound` + | :sg:`get_length() -> seconds` + + Return the length of this Sound in seconds. + + .. ## Sound.get_length ## + + .. method:: get_raw + + | :sl:`return a bytestring copy of the Sound samples.` + | :sg:`get_raw() -> bytes` + + Return a copy of the Sound object buffer as a bytes. + + .. versionadded:: 1.9.2 + + .. ## Sound.get_raw ## + + .. ## pygame.mixer.Sound ## + +.. class:: Channel + + | :sl:`Create a Channel object for controlling playback` + | :sg:`Channel(id) -> Channel` + + Return a Channel object for one of the current channels. The id must be a + value from 0 to the value of ``pygame.mixer.get_num_channels()``. + + The Channel object can be used to get fine control over the playback of + Sounds. A channel can only playback a single Sound at time. Using channels + is entirely optional since pygame can manage them by default. + + .. method:: play + + | :sl:`play a Sound on a specific Channel` + | :sg:`play(Sound, loops=0, maxtime=0, fade_ms=0) -> None` + + This will begin playback of a Sound on a specific Channel. If the Channel + is currently playing any other Sound it will be stopped. + + The loops argument has the same meaning as in ``Sound.play()``: it is the + number of times to repeat the sound after the first time. If it is 3, the + sound will be played 4 times (the first time, then three more). If loops + is -1 then the playback will repeat indefinitely. + + As in ``Sound.play()``, the maxtime argument can be used to stop playback + of the Sound after a given number of milliseconds. + + As in ``Sound.play()``, the fade_ms argument can be used fade in the + sound. + + .. ## Channel.play ## + + .. method:: stop + + | :sl:`stop playback on a Channel` + | :sg:`stop() -> None` + + Stop sound playback on a channel. After playback is stopped the channel + becomes available for new Sounds to play on it. + + .. ## Channel.stop ## + + .. method:: pause + + | :sl:`temporarily stop playback of a channel` + | :sg:`pause() -> None` + + Temporarily stop the playback of sound on a channel. It can be resumed at + a later time with ``Channel.unpause()`` + + .. ## Channel.pause ## + + .. method:: unpause + + | :sl:`resume pause playback of a channel` + | :sg:`unpause() -> None` + + Resume the playback on a paused channel. + + .. ## Channel.unpause ## + + .. method:: fadeout + + | :sl:`stop playback after fading channel out` + | :sg:`fadeout(time) -> None` + + Stop playback of a channel after fading out the sound over the given time + argument in milliseconds. + + .. ## Channel.fadeout ## + + .. method:: set_volume + + | :sl:`set the volume of a playing channel` + | :sg:`set_volume(value) -> None` + | :sg:`set_volume(left, right) -> None` + + Set the volume (loudness) of a playing sound. When a channel starts to + play its volume value is reset. This only affects the current sound. The + value argument is between 0.0 and 1.0. + + If one argument is passed, it will be the volume of both speakers. If two + arguments are passed and the mixer is in stereo mode, the first argument + will be the volume of the left speaker and the second will be the volume + of the right speaker. (If the second argument is ``None``, the first + argument will be the volume of both speakers.) + + If the channel is playing a Sound on which ``set_volume()`` has also been + called, both calls are taken into account. For example: + + :: + + sound = pygame.mixer.Sound("s.wav") + channel = s.play() # Sound plays at full volume by default + sound.set_volume(0.9) # Now plays at 90% of full volume. + sound.set_volume(0.6) # Now plays at 60% (previous value replaced). + channel.set_volume(0.5) # Now plays at 30% (0.6 * 0.5). + + .. ## Channel.set_volume ## + + .. method:: get_volume + + | :sl:`get the volume of the playing channel` + | :sg:`get_volume() -> value` + + Return the volume of the channel for the current playing sound. This does + not take into account stereo separation used by + :meth:`Channel.set_volume`. The Sound object also has its own volume + which is mixed with the channel. + + .. ## Channel.get_volume ## + + .. method:: get_busy + + | :sl:`check if the channel is active` + | :sg:`get_busy() -> bool` + + Returns ``True`` if the channel is actively mixing sound. If the channel + is idle this returns ``False``. + + .. ## Channel.get_busy ## + + .. method:: get_sound + + | :sl:`get the currently playing Sound` + | :sg:`get_sound() -> Sound` + + Return the actual Sound object currently playing on this channel. If the + channel is idle ``None`` is returned. + + .. ## Channel.get_sound ## + + .. method:: queue + + | :sl:`queue a Sound object to follow the current` + | :sg:`queue(Sound) -> None` + + When a Sound is queued on a Channel, it will begin playing immediately + after the current Sound is finished. Each channel can only have a single + Sound queued at a time. The queued Sound will only play if the current + playback finished automatically. It is cleared on any other call to + ``Channel.stop()`` or ``Channel.play()``. + + If there is no sound actively playing on the Channel then the Sound will + begin playing immediately. + + .. ## Channel.queue ## + + .. method:: get_queue + + | :sl:`return any Sound that is queued` + | :sg:`get_queue() -> Sound` + + If a Sound is already queued on this channel it will be returned. Once + the queued sound begins playback it will no longer be on the queue. + + .. ## Channel.get_queue ## + + .. method:: set_endevent + + | :sl:`have the channel send an event when playback stops` + | :sg:`set_endevent() -> None` + | :sg:`set_endevent(type) -> None` + + When an endevent is set for a channel, it will send an event to the + pygame queue every time a sound finishes playing on that channel (not + just the first time). Use ``pygame.event.get()`` to retrieve the endevent + once it's sent. + + Note that if you called ``Sound.play(n)`` or ``Channel.play(sound,n)``, + the end event is sent only once: after the sound has been played "n+1" + times (see the documentation of Sound.play). + + If ``Channel.stop()`` or ``Channel.play()`` is called while the sound was + still playing, the event will be posted immediately. + + The type argument will be the event id sent to the queue. This can be any + valid event type, but a good choice would be a value between + ``pygame.locals.USEREVENT`` and ``pygame.locals.NUMEVENTS``. If no type + argument is given then the Channel will stop sending endevents. + + .. ## Channel.set_endevent ## + + .. method:: get_endevent + + | :sl:`get the event a channel sends when playback stops` + | :sg:`get_endevent() -> type` + + Returns the event type to be sent every time the Channel finishes + playback of a Sound. If there is no endevent the function returns + ``pygame.NOEVENT``. + + .. ## Channel.get_endevent ## + + .. ## pygame.mixer.Channel ## + +.. ## pygame.mixer ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/mouse.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/mouse.rst.txt new file mode 100644 index 0000000..84aaded --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/mouse.rst.txt @@ -0,0 +1,219 @@ +.. include:: common.txt + +:mod:`pygame.mouse` +=================== + +.. module:: pygame.mouse + :synopsis: pygame module to work with the mouse + +| :sl:`pygame module to work with the mouse` + +The mouse functions can be used to get the current state of the mouse device. +These functions can also alter the system cursor for the mouse. + +When the display mode is set, the event queue will start receiving mouse +events. The mouse buttons generate ``pygame.MOUSEBUTTONDOWN`` and +``pygame.MOUSEBUTTONUP`` events when they are pressed and released. These +events contain a button attribute representing which button was pressed. The +mouse wheel will generate ``pygame.MOUSEBUTTONDOWN`` and +``pygame.MOUSEBUTTONUP`` events when rolled. The button will be set to 4 +when the wheel is rolled up, and to button 5 when the wheel is rolled down. +Whenever the mouse is moved it generates a ``pygame.MOUSEMOTION`` event. The +mouse movement is broken into small and accurate motion events. As the mouse +is moving many motion events will be placed on the queue. Mouse motion events +that are not properly cleaned from the event queue are the primary reason the +event queue fills up. + +If the mouse cursor is hidden, and input is grabbed to the current display the +mouse will enter a virtual input mode, where the relative movements of the +mouse will never be stopped by the borders of the screen. See the functions +``pygame.mouse.set_visible()`` and ``pygame.event.set_grab()`` to get this +configured. + + +**Mouse Wheel Behavior in pygame 2** + +There is proper functionality for mouse wheel behaviour with pygame 2 supporting +``pygame.MOUSEWHEEL`` events. The new events support horizontal and vertical +scroll movements, with signed integer values representing the amount scrolled +(``x`` and ``y``), as well as ``flipped`` direction (the set positive and +negative values for each axis is flipped). Read more about SDL2 +input-related changes here ``_ + +In pygame 2, the mouse wheel functionality can be used by listening for the +``pygame.MOUSEWHEEL`` type of an event (Bear in mind they still emit +``pygame.MOUSEBUTTONDOWN`` events like in pygame 1.x, as well). +When this event is triggered, a developer can access the appropriate ``Event`` object +with ``pygame.event.get()``. The object can be used to access data about the mouse +scroll, such as ``which`` (it will tell you what exact mouse device trigger the event). + +.. code-block:: python + :caption: Code example of mouse scroll (tested on 2.0.0.dev7) + :name: test.py + + # Taken from husano896's PR thread (slightly modified) + import pygame + from pygame.locals import * + pygame.init() + screen = pygame.display.set_mode((640, 480)) + clock = pygame.time.Clock() + + def main(): + while True: + for event in pygame.event.get(): + if event.type == QUIT: + pygame.quit() + return + elif event.type == MOUSEWHEEL: + print(event) + print(event.x, event.y) + print(event.flipped) + print(event.which) + # can access properties with + # proper notation(ex: event.y) + clock.tick(60) + + # Execute game: + main() + +.. function:: get_pressed + + | :sl:`get the state of the mouse buttons` + | :sg:`get_pressed(num_buttons=3) -> (button1, button2, button3)` + | :sg:`get_pressed(num_buttons=5) -> (button1, button2, button3, button4, button5)` + + Returns a sequence of booleans representing the state of all the mouse + buttons. A true value means the mouse is currently being pressed at the time + of the call. + + Note, to get all of the mouse events it is better to use either + ``pygame.event.wait()`` or ``pygame.event.get()`` and check all of those + events to see if they are ``MOUSEBUTTONDOWN``, ``MOUSEBUTTONUP``, or + ``MOUSEMOTION``. + + Note, that on ``X11`` some X servers use middle button emulation. When you + click both buttons ``1`` and ``3`` at the same time a ``2`` button event + can be emitted. + + Note, remember to call ``pygame.event.get()`` before this function. + Otherwise it will not work as expected. + + To support five button mice, an optional parameter ``num_buttons`` has been + added in pygame 2. When this is set to ``5``, ``button4`` and ``button5`` + are added to the returned tuple. Only ``3`` and ``5`` are valid values + for this parameter. + + .. versionchanged:: 2.0.0 ``num_buttons`` argument added + + .. ## pygame.mouse.get_pressed ## + +.. function:: get_pos + + | :sl:`get the mouse cursor position` + | :sg:`get_pos() -> (x, y)` + + Returns the ``x`` and ``y`` position of the mouse cursor. The position is + relative to the top-left corner of the display. The cursor position can be + located outside of the display window, but is always constrained to the + screen. + + .. ## pygame.mouse.get_pos ## + +.. function:: get_rel + + | :sl:`get the amount of mouse movement` + | :sg:`get_rel() -> (x, y)` + + Returns the amount of movement in ``x`` and ``y`` since the previous call to + this function. The relative movement of the mouse cursor is constrained to + the edges of the screen, but see the virtual input mouse mode for a way + around this. Virtual input mode is described at the top of the page. + + .. ## pygame.mouse.get_rel ## + +.. function:: set_pos + + | :sl:`set the mouse cursor position` + | :sg:`set_pos([x, y]) -> None` + + Set the current mouse position to arguments given. If the mouse cursor is + visible it will jump to the new coordinates. Moving the mouse will generate + a new ``pygame.MOUSEMOTION`` event. + + .. ## pygame.mouse.set_pos ## + +.. function:: set_visible + + | :sl:`hide or show the mouse cursor` + | :sg:`set_visible(bool) -> bool` + + If the bool argument is true, the mouse cursor will be visible. This will + return the previous visible state of the cursor. + + .. ## pygame.mouse.set_visible ## + +.. function:: get_visible + + | :sl:`get the current visibility state of the mouse cursor` + | :sg:`get_visible() -> bool` + + Get the current visibility state of the mouse cursor. ``True`` if the mouse is + visible, ``False`` otherwise. + + .. versionadded:: 2.0.0 + + .. ## pygame.mouse.get_visible ## + +.. function:: get_focused + + | :sl:`check if the display is receiving mouse input` + | :sg:`get_focused() -> bool` + + Returns true when pygame is receiving mouse input events (or, in windowing + terminology, is "active" or has the "focus"). + + This method is most useful when working in a window. By contrast, in + full-screen mode, this method always returns true. + + Note: under ``MS`` Windows, the window that has the mouse focus also has the + keyboard focus. But under X-Windows, one window can receive mouse events and + another receive keyboard events. ``pygame.mouse.get_focused()`` indicates + whether the pygame window receives mouse events. + + .. ## pygame.mouse.get_focused ## + +.. function:: set_cursor + + | :sl:`set the mouse cursor to a new cursor` + | :sg:`set_cursor(pygame.cursors.Cursor) -> None` + | :sg:`set_cursor(size, hotspot, xormasks, andmasks) -> None` + | :sg:`set_cursor(hotspot, surface) -> None` + | :sg:`set_cursor(constant) -> None` + + Set the mouse cursor to something new. This function accepts either an explicit + ``Cursor`` object or arguments to create a ``Cursor`` object. + + See :class:`pygame.cursors.Cursor` for help creating cursors and for examples. + + .. versionchanged:: 2.0.1 + + .. ## pygame.mouse.set_cursor ## + + +.. function:: get_cursor + + | :sl:`get the current mouse cursor` + | :sg:`get_cursor() -> pygame.cursors.Cursor` + + Get the information about the mouse system cursor. The return value contains + the same data as the arguments passed into :func:`pygame.mouse.set_cursor()`. + + .. note:: Code that unpacked a get_cursor() call into + ``size, hotspot, xormasks, andmasks`` will still work, + assuming the call returns an old school type cursor. + + .. versionchanged:: 2.0.1 + + .. ## pygame.mouse.get_cursor ## + +.. ## pygame.mouse ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/music.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/music.rst.txt new file mode 100644 index 0000000..49276b8 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/music.rst.txt @@ -0,0 +1,274 @@ +.. include:: common.txt + +:mod:`pygame.mixer.music` +========================= + +.. module:: pygame.mixer.music + :synopsis: pygame module for controlling streamed audio + +| :sl:`pygame module for controlling streamed audio` + +The music module is closely tied to :mod:`pygame.mixer`. Use the music module +to control the playback of music in the sound mixer. + +The difference between the music playback and regular Sound playback is that +the music is streamed, and never actually loaded all at once. The mixer system +only supports a single music stream at once. + +On older pygame versions, ``MP3`` support was limited under Mac and Linux. This +changed in pygame ``v2.0.2`` which got improved MP3 support. Consider using +``OGG`` file format for music as that can give slightly better compression than +MP3 in most cases. + +.. function:: load + + | :sl:`Load a music file for playback` + | :sg:`load(filename) -> None` + | :sg:`load(fileobj, namehint="") -> None` + + This will load a music filename/file object and prepare it for playback. If + a music stream is already playing it will be stopped. This does not start + the music playing. + + If you are loading from a file object, the namehint parameter can be used to specify + the type of music data in the object. For example: :code:`load(fileobj, "ogg")`. + + .. versionchanged:: 2.0.2 Added optional ``namehint`` argument + + .. ## pygame.mixer.music.load ## + +.. function:: unload + + | :sl:`Unload the currently loaded music to free up resources` + | :sg:`unload() -> None` + + This closes resources like files for any music that may be loaded. + + .. versionadded:: 2.0.0 + + .. ## pygame.mixer.music.load ## + + +.. function:: play + + | :sl:`Start the playback of the music stream` + | :sg:`play(loops=0, start=0.0, fade_ms=0) -> None` + + This will play the loaded music stream. If the music is already playing it + will be restarted. + + ``loops`` is an optional integer argument, which is ``0`` by default, which + indicates how many times to repeat the music. The music repeats indefinitely if + this argument is set to ``-1``. + + ``start`` is an optional float argument, which is ``0.0`` by default, which + denotes the position in time from which the music starts playing. The starting + position depends on the format of the music played. ``MP3`` and ``OGG`` use + the position as time in seconds. For ``MP3`` files the start time position + selected may not be accurate as things like variable bit rate encoding and ID3 + tags can throw off the timing calculations. For ``MOD`` music it is the pattern + order number. Passing a start position will raise a NotImplementedError if + the start position cannot be set. + + ``fade_ms`` is an optional integer argument, which is ``0`` by default, + which denotes the period of time (in milliseconds) over which the music + will fade up from volume level ``0.0`` to full volume (or the volume level + previously set by :func:`set_volume`). The sample may end before the fade-in + is complete. If the music is already streaming ``fade_ms`` is ignored. + + .. versionchanged:: 2.0.0 Added optional ``fade_ms`` argument + + .. ## pygame.mixer.music.play ## + +.. function:: rewind + + | :sl:`restart music` + | :sg:`rewind() -> None` + + Resets playback of the current music to the beginning. If :func:`pause` has + previoulsy been used to pause the music, the music will remain paused. + + .. note:: :func:`rewind` supports a limited number of file types and notably + ``WAV`` files are NOT supported. For unsupported file types use :func:`play` + which will restart the music that's already playing (note that this + will start the music playing again even if previously paused). + + .. ## pygame.mixer.music.rewind ## + +.. function:: stop + + | :sl:`stop the music playback` + | :sg:`stop() -> None` + + Stops the music playback if it is currently playing. + endevent will be triggered, if set. + It won't unload the music. + + .. ## pygame.mixer.music.stop ## + +.. function:: pause + + | :sl:`temporarily stop music playback` + | :sg:`pause() -> None` + + Temporarily stop playback of the music stream. It can be resumed with the + :func:`unpause` function. + + .. ## pygame.mixer.music.pause ## + +.. function:: unpause + + | :sl:`resume paused music` + | :sg:`unpause() -> None` + + This will resume the playback of a music stream after it has been paused. + + .. ## pygame.mixer.music.unpause ## + +.. function:: fadeout + + | :sl:`stop music playback after fading out` + | :sg:`fadeout(time) -> None` + + Fade out and stop the currently playing music. + + The ``time`` argument denotes the integer milliseconds for which the + fading effect is generated. + + Note, that this function blocks until the music has faded out. Calls + to :func:`fadeout` and :func:`set_volume` will have no effect during + this time. If an event was set using :func:`set_endevent` it will be + called after the music has faded. + + .. ## pygame.mixer.music.fadeout ## + +.. function:: set_volume + + | :sl:`set the music volume` + | :sg:`set_volume(volume) -> None` + + Set the volume of the music playback. + + The ``volume`` argument is a float between ``0.0`` and ``1.0`` that sets + the volume level. When new music is loaded the volume is reset to full + volume. If ``volume`` is a negative value it will be ignored and the + volume will remain set at the current level. If the ``volume`` argument + is greater than ``1.0``, the volume will be set to ``1.0``. + + .. ## pygame.mixer.music.set_volume ## + +.. function:: get_volume + + | :sl:`get the music volume` + | :sg:`get_volume() -> value` + + Returns the current volume for the mixer. The value will be between ``0.0`` + and ``1.0``. + + .. ## pygame.mixer.music.get_volume ## + +.. function:: get_busy + + | :sl:`check if the music stream is playing` + | :sg:`get_busy() -> bool` + + Returns True when the music stream is actively playing. When the music is + idle this returns False. In pygame 2.0.1 and above this function returns + False when the music is paused. In pygame 1 it returns True when the music + is paused. + + .. versionchanged:: 2.0.1 Returns False when music paused. + + .. ## pygame.mixer.music.get_busy ## + +.. function:: set_pos + + | :sl:`set position to play from` + | :sg:`set_pos(pos) -> None` + + This sets the position in the music file where playback will start. + The meaning of "pos", a float (or a number that can be converted to a float), + depends on the music format. + + For ``MOD`` files, pos is the integer pattern number in the module. + For ``OGG`` it is the absolute position, in seconds, from + the beginning of the sound. For ``MP3`` files, it is the relative position, + in seconds, from the current position. For absolute positioning in an ``MP3`` + file, first call :func:`rewind`. + + Other file formats are unsupported. Newer versions of SDL_mixer have + better positioning support than earlier ones. An SDLError is raised if a + particular format does not support positioning. + + Function :func:`set_pos` calls underlining SDL_mixer function + ``Mix_SetMusicPosition``. + + .. versionadded:: 1.9.2 + + .. ## pygame.mixer.music.set_pos ## + +.. function:: get_pos + + | :sl:`get the music play time` + | :sg:`get_pos() -> time` + + This gets the number of milliseconds that the music has been playing for. + The returned time only represents how long the music has been playing; it + does not take into account any starting position offsets. + + .. ## pygame.mixer.music.get_pos ## + +.. function:: queue + + | :sl:`queue a sound file to follow the current` + | :sg:`queue(filename) -> None` + | :sg:`queue(fileobj, namehint="", loops=0) -> None` + + This will load a sound file and queue it. A queued sound file will begin as + soon as the current sound naturally ends. Only one sound can be queued at a + time. Queuing a new sound while another sound is queued will result in the + new sound becoming the queued sound. Also, if the current sound is ever + stopped or changed, the queued sound will be lost. + + If you are loading from a file object, the namehint parameter can be used to specify + the type of music data in the object. For example: :code:`queue(fileobj, "ogg")`. + + The following example will play music by Bach six times, then play music by + Mozart once: + + :: + + pygame.mixer.music.load('bach.ogg') + pygame.mixer.music.play(5) # Plays six times, not five! + pygame.mixer.music.queue('mozart.ogg') + + .. versionchanged:: 2.0.2 Added optional ``namehint`` argument + + .. ## pygame.mixer.music.queue ## + +.. function:: set_endevent + + | :sl:`have the music send an event when playback stops` + | :sg:`set_endevent() -> None` + | :sg:`set_endevent(type) -> None` + + This causes pygame to signal (by means of the event queue) when the music is + done playing. The argument determines the type of event that will be queued. + + The event will be queued every time the music finishes, not just the first + time. To stop the event from being queued, call this method with no + argument. + + .. ## pygame.mixer.music.set_endevent ## + +.. function:: get_endevent + + | :sl:`get the event a channel sends when playback stops` + | :sg:`get_endevent() -> type` + + Returns the event type to be sent every time the music finishes playback. If + there is no endevent the function returns ``pygame.NOEVENT``. + + .. ## pygame.mixer.music.get_endevent ## + +.. ## pygame.mixer.music ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/overlay.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/overlay.rst.txt new file mode 100644 index 0000000..04ff9ae --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/overlay.rst.txt @@ -0,0 +1,79 @@ +.. include:: common.txt + +:mod:`pygame.Overlay` +===================== + +.. currentmodule:: pygame + +.. warning:: + This module is non functional in pygame 2.0 and above, unless you have manually compiled pygame with SDL1. + This module will not be supported in the future. + +.. class:: Overlay + + | :sl:`pygame object for video overlay graphics` + | :sg:`Overlay(format, (width, height)) -> Overlay` + + The Overlay objects provide support for accessing hardware video overlays. + Video overlays do not use standard ``RGB`` pixel formats, and can use + multiple resolutions of data to create a single image. + + The Overlay objects represent lower level access to the display hardware. To + use the object you must understand the technical details of video overlays. + + The Overlay format determines the type of pixel data used. Not all hardware + will support all types of overlay formats. Here is a list of available + format types: + + :: + + YV12_OVERLAY, IYUV_OVERLAY, YUY2_OVERLAY, UYVY_OVERLAY, YVYU_OVERLAY + + The width and height arguments control the size for the overlay image data. + The overlay image can be displayed at any size, not just the resolution of + the overlay. + + The overlay objects are always visible, and always show above the regular + display contents. + + .. method:: display + + | :sl:`set the overlay pixel data` + | :sg:`display((y, u, v)) -> None` + | :sg:`display() -> None` + + Display the YUV data in SDL's overlay planes. The y, u, and v arguments + are strings of binary data. The data must be in the correct format used + to create the Overlay. + + If no argument is passed in, the Overlay will simply be redrawn with the + current data. This can be useful when the Overlay is not really hardware + accelerated. + + The strings are not validated, and improperly sized strings could crash + the program. + + .. ## Overlay.display ## + + .. method:: set_location + + | :sl:`control where the overlay is displayed` + | :sg:`set_location(rect) -> None` + + Set the location for the overlay. The overlay will always be shown + relative to the main display Surface. This does not actually redraw the + overlay, it will be updated on the next call to ``Overlay.display()``. + + .. ## Overlay.set_location ## + + .. method:: get_hardware + + | :sl:`test if the Overlay is hardware accelerated` + | :sg:`get_hardware(rect) -> int` + + Returns a True value when the Overlay is hardware accelerated. If the + platform does not support acceleration, software rendering is used. + + .. ## Overlay.get_hardware ## + + .. ## pygame.Overlay ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/pixelarray.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/pixelarray.rst.txt new file mode 100644 index 0000000..da1d93a --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/pixelarray.rst.txt @@ -0,0 +1,295 @@ +.. include:: common.txt + +:class:`pygame.PixelArray` +========================== + +.. currentmodule:: pygame + +.. class:: PixelArray + + | :sl:`pygame object for direct pixel access of surfaces` + | :sg:`PixelArray(Surface) -> PixelArray` + + The PixelArray wraps a Surface and provides direct access to the + surface's pixels. A pixel array can be one or two dimensional. + A two dimensional array, like its surface, is indexed [column, row]. + Pixel arrays support slicing, both for returning a subarray or + for assignment. A pixel array sliced on a single column or row + returns a one dimensional pixel array. Arithmetic and other operations + are not supported. A pixel array can be safely assigned to itself. + Finally, pixel arrays export an array struct interface, allowing + them to interact with :mod:`pygame.pixelcopy` methods and NumPy + arrays. + + A PixelArray pixel item can be assigned a raw integer values, a + :class:`pygame.Color` instance, or a (r, g, b[, a]) tuple. + + :: + + pxarray[x, y] = 0xFF00FF + pxarray[x, y] = pygame.Color(255, 0, 255) + pxarray[x, y] = (255, 0, 255) + + However, only a pixel's integer value is returned. So, to compare a pixel + to a particular color the color needs to be first mapped using + the :meth:`Surface.map_rgb()` method of the Surface object for which the + PixelArray was created. + + :: + + pxarray = pygame.PixelArray(surface) + # Check, if the first pixel at the topleft corner is blue + if pxarray[0, 0] == surface.map_rgb((0, 0, 255)): + ... + + When assigning to a range of of pixels, a non tuple sequence of colors or + a PixelArray can be used as the value. For a sequence, the length must + match the PixelArray width. + + :: + + pxarray[a:b] = 0xFF00FF # set all pixels to 0xFF00FF + pxarray[a:b] = (0xFF00FF, 0xAACCEE, ... ) # first pixel = 0xFF00FF, + # second pixel = 0xAACCEE, ... + pxarray[a:b] = [(255, 0, 255), (170, 204, 238), ...] # same as above + pxarray[a:b] = [(255, 0, 255), 0xAACCEE, ...] # same as above + pxarray[a:b] = otherarray[x:y] # slice sizes must match + + For PixelArray assignment, if the right hand side array has a row length + of 1, then the column is broadcast over the target array's rows. An + array of height 1 is broadcast over the target's columns, and is equivalent + to assigning a 1D PixelArray. + + Subscript slices can also be used to assign to a rectangular subview of + the target PixelArray. + + :: + + # Create some new PixelArray objects providing a different view + # of the original array/surface. + newarray = pxarray[2:4, 3:5] + otherarray = pxarray[::2, ::2] + + Subscript slices can also be used to do fast rectangular pixel manipulations + instead of iterating over the x or y axis. The + + :: + + pxarray[::2, :] = (0, 0, 0) # Make even columns black. + pxarray[::2] = (0, 0, 0) # Same as [::2, :] + + During its lifetime, the PixelArray locks the surface, thus you explicitly + have to close() it once its not used any more and the surface should perform + operations in the same scope. It is best to use it as a context manager + using the with PixelArray(surf) as pixel_array: style. So it works on pypy too. + + A simple ``:`` slice index for the column can be omitted. + + :: + + pxarray[::2, ...] = (0, 0, 0) # Same as pxarray[::2, :] + pxarray[...] = (255, 0, 0) # Same as pxarray[:] + + A note about PixelArray to PixelArray assignment, for arrays with an + item size of 3 (created from 24 bit surfaces) pixel values are translated + from the source to the destinations format. The red, green, and blue + color elements of each pixel are shifted to match the format of the + target surface. For all other pixel sizes no such remapping occurs. + This should change in later pygame releases, where format conversions + are performed for all pixel sizes. To avoid code breakage when full mapped + copying is implemented it is suggested PixelArray to PixelArray copies be + only between surfaces of identical format. + + .. versionadded:: 1.9.4 + + - close() method was added. For explicitly cleaning up. + - being able to use PixelArray as a context manager for cleanup. + - both of these are useful for when working without reference counting (pypy). + + .. versionadded:: 1.9.2 + + - array struct interface + - transpose method + - broadcasting for a length 1 dimension + + .. versionchanged:: 1.9.2 + + - A 2D PixelArray can have a length 1 dimension. + Only an integer index on a 2D PixelArray returns a 1D array. + - For assignment, a tuple can only be a color. Any other sequence type + is a sequence of colors. + + + .. versionadded: 1.8.0 + Subscript support + + .. versionadded: 1.8.1 + Methods :meth:`make_surface`, :meth:`replace`, :meth:`extract`, and + :meth:`compare` + + .. versionadded: 1.9.2 + Properties :attr:`itemsize`, :attr:`ndim`, :attr:`shape`, + and :attr:`strides` + + .. versionadded: 1.9.2 + Array struct interface + + .. versionadded: 1.9.4 + Methods :meth:`close` + + .. attribute:: surface + + | :sl:`Gets the Surface the PixelArray uses.` + | :sg:`surface -> Surface` + + The Surface the PixelArray was created for. + + .. ## PixelArray.surface ## + + .. attribute:: itemsize + + | :sl:`Returns the byte size of a pixel array item` + | :sg:`itemsize -> int` + + This is the same as :meth:`Surface.get_bytesize` for the + pixel array's surface. + + .. versionadded:: 1.9.2 + + .. attribute:: ndim + + | :sl:`Returns the number of dimensions.` + | :sg:`ndim -> int` + + A pixel array can be 1 or 2 dimensional. + + .. versionadded:: 1.9.2 + + .. attribute:: shape + + | :sl:`Returns the array size.` + | :sg:`shape -> tuple of int's` + + A tuple or length :attr:`ndim` giving the length of each + dimension. Analogous to :meth:`Surface.get_size`. + + .. versionadded:: 1.9.2 + + .. attribute:: strides + + | :sl:`Returns byte offsets for each array dimension.` + | :sg:`strides -> tuple of int's` + + A tuple or length :attr:`ndim` byte counts. When a stride is + multiplied by the corresponding index it gives the offset + of that index from the start of the array. A stride is negative + for an array that has is inverted (has a negative step). + + .. versionadded:: 1.9.2 + + .. method:: make_surface + + | :sl:`Creates a new Surface from the current PixelArray.` + | :sg:`make_surface() -> Surface` + + Creates a new Surface from the current PixelArray. Depending on the + current PixelArray the size, pixel order etc. will be different from the + original Surface. + + :: + + # Create a new surface flipped around the vertical axis. + sf = pxarray[:,::-1].make_surface () + + .. versionadded:: 1.8.1 + + .. ## PixelArray.make_surface ## + + .. method:: replace + + | :sl:`Replaces the passed color in the PixelArray with another one.` + | :sg:`replace(color, repcolor, distance=0, weights=(0.299, 0.587, 0.114)) -> None` + + Replaces the pixels with the passed color in the PixelArray by changing + them them to the passed replacement color. + + It uses a simple weighted Euclidean distance formula to calculate the + distance between the colors. The distance space ranges from 0.0 to 1.0 + and is used as threshold for the color detection. This causes the + replacement to take pixels with a similar, but not exactly identical + color, into account as well. + + This is an in place operation that directly affects the pixels of the + PixelArray. + + .. versionadded:: 1.8.1 + + .. ## PixelArray.replace ## + + .. method:: extract + + | :sl:`Extracts the passed color from the PixelArray.` + | :sg:`extract(color, distance=0, weights=(0.299, 0.587, 0.114)) -> PixelArray` + + Extracts the passed color by changing all matching pixels to white, while + non-matching pixels are changed to black. This returns a new PixelArray + with the black/white color mask. + + It uses a simple weighted Euclidean distance formula to calculate the + distance between the colors. The distance space ranges from 0.0 to 1.0 + and is used as threshold for the color detection. This causes the + extraction to take pixels with a similar, but not exactly identical + color, into account as well. + + .. versionadded:: 1.8.1 + + .. ## PixelArray.extract ## + + .. method:: compare + + | :sl:`Compares the PixelArray with another one.` + | :sg:`compare(array, distance=0, weights=(0.299, 0.587, 0.114)) -> PixelArray` + + Compares the contents of the PixelArray with those from the passed in + PixelArray. It returns a new PixelArray with a black/white color mask + that indicates the differences (black) of both arrays. Both PixelArray + objects must have identical bit depths and dimensions. + + It uses a simple weighted Euclidean distance formula to calculate the + distance between the colors. The distance space ranges from 0.0 to 1.0 + and is used as a threshold for the color detection. This causes the + comparison to mark pixels with a similar, but not exactly identical + color, as white. + + .. versionadded:: 1.8.1 + + .. ## PixelArray.compare ## + + .. method:: transpose + + | :sl:`Exchanges the x and y axis.` + | :sg:`transpose() -> PixelArray` + + This method returns a new view of the pixel array with the rows and + columns swapped. So for a (w, h) sized array a (h, w) slice is returned. + If an array is one dimensional, then a length 1 x dimension is added, + resulting in a 2D pixel array. + + .. versionadded:: 1.9.2 + + .. ## PixelArray.transpose ## + + .. method:: close + + | :sl:`Closes the PixelArray, and releases Surface lock.` + | :sg:`transpose() -> PixelArray` + + This method is for explicitly closing the PixelArray, and releasing + a lock on the Suface. + + .. versionadded:: 1.9.4 + + .. ## PixelArray.close ## + + + .. ## pygame.PixelArray ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/pixelcopy.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/pixelcopy.rst.txt new file mode 100644 index 0000000..dd8ecf7 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/pixelcopy.rst.txt @@ -0,0 +1,104 @@ +.. include:: common.txt + +:mod:`pygame.pixelcopy` +======================= + +.. module:: pygame.pixelcopy + :synopsis: pygame module for general pixel array copying + +| :sl:`pygame module for general pixel array copying` + +The ``pygame.pixelcopy`` module contains functions for copying between +surfaces and objects exporting an array structure interface. It is a backend +for :mod:`pygame.surfarray`, adding NumPy support. But pixelcopy is more +general, and intended for direct use. + +The array struct interface exposes an array's data in a standard way. +It was introduced in NumPy. In Python 2.7 and above it is replaced by the +new buffer protocol, though the buffer protocol is still a work in progress. +The array struct interface, on the other hand, is stable and works with earlier +Python versions. So for now the array struct interface is the predominate way +pygame handles array introspection. + +For 2d arrays of integer pixel values, the values are mapped to the +pixel format of the related surface. To get the actual color of a pixel +value use :meth:`pygame.Surface.unmap_rgb`. 2d arrays can only be used +directly between surfaces having the same pixel layout. + +New in pygame 1.9.2. + +.. function:: surface_to_array + + | :sl:`copy surface pixels to an array object` + | :sg:`surface_to_array(array, surface, kind='P', opaque=255, clear=0) -> None` + + The surface_to_array function copies pixels from a Surface object + to a 2D or 3D array. Depending on argument ``kind`` and the target array + dimension, a copy may be raw pixel value, RGB, a color component slice, + or colorkey alpha transparency value. Recognized ``kind`` values are the + single character codes 'P', 'R', 'G', 'B', 'A', and 'C'. Kind codes are case + insensitive, so 'p' is equivalent to 'P'. The first two dimensions + of the target must be the surface size (w, h). + + The default 'P' kind code does a direct raw integer pixel (mapped) value + copy to a 2D array and a 'RGB' pixel component (unmapped) copy to a 3D array + having shape (w, h, 3). For an 8 bit colormap surface this means the + table index is copied to a 2D array, not the table value itself. A 2D + array's item size must be at least as large as the surface's pixel + byte size. The item size of a 3D array must be at least one byte. + + For the 'R', 'G', 'B', and 'A' copy kinds a single color component + of the unmapped surface pixels are copied to the target 2D array. + For kind 'A' and surfaces with source alpha (the surface was created with + the SRCALPHA flag), has a colorkey + (set with :meth:`Surface.set_colorkey() `), + or has a blanket alpha + (set with :meth:`Surface.set_alpha() `) + then the alpha values are those expected for a SDL surface. + If a surface has no explicit alpha value, then the target array + is filled with the value of the optional ``opaque`` surface_to_array + argument (default 255: not transparent). + + Copy kind 'C' is a special case for alpha copy of a source surface + with colorkey. Unlike the 'A' color component copy, the ``clear`` + argument value is used for colorkey matches, ``opaque`` otherwise. + By default, a match has alpha 0 (totally transparent), while everything + else is alpha 255 (totally opaque). It is a more general implementation + of :meth:`pygame.surfarray.array_colorkey`. + + Specific to surface_to_array, a ValueError is raised for target arrays + with incorrect shape or item size. A TypeError is raised for an incorrect + kind code. Surface specific problems, such as locking, raise a pygame.error. + + .. ## pygame.pixelcopy.surface_to_array ## + +.. function:: array_to_surface + + | :sl:`copy an array object to a surface` + | :sg:`array_to_surface(, ) -> None` + + See :func:`pygame.surfarray.blit_array`. + + .. ## pygame.pixelcopy.array_to_surface ## + +.. function:: map_array + + | :sl:`copy an array to another array, using surface format` + | :sg:`map_array(, , ) -> None` + + Map an array of color element values - (w, h, ..., 3) - to an array of + pixels - (w, h) according to the format of . + + .. ## pygame.pixelcopy.map_array ## + +.. function:: make_surface + + | :sl:`Copy an array to a new surface` + | :sg:`pygame.pixelcopy.make_surface(array) -> Surface` + + Create a new Surface that best resembles the data and format of the array. + The array can be 2D or 3D with any sized integer values. + + .. ## pygame.pixelcopy.make_surface ## + +.. ## pygame.pixelcopy ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/pygame.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/pygame.rst.txt new file mode 100644 index 0000000..33d6802 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/pygame.rst.txt @@ -0,0 +1,488 @@ +.. include:: common.txt + +:mod:`pygame` +============= + +.. module:: pygame + :synopsis: the top level pygame package + +| :sl:`the top level pygame package` + +The pygame package represents the top-level package for others to use. Pygame +itself is broken into many submodules, but this does not affect programs that +use pygame. + +As a convenience, most of the top-level variables in pygame have been placed +inside a module named :mod:`pygame.locals`. This is meant to be used with +``from pygame.locals import *``, in addition to ``import pygame``. + +When you ``import pygame`` all available pygame submodules are automatically +imported. Be aware that some of the pygame modules are considered *optional*, +and may not be available. In that case, pygame will provide a placeholder +object instead of the module, which can be used to test for availability. + +.. function:: init + + | :sl:`initialize all imported pygame modules` + | :sg:`init() -> (numpass, numfail)` + + Initialize all imported pygame modules. No exceptions will be raised if a + module fails, but the total number if successful and failed inits will be + returned as a tuple. You can always initialize individual modules manually, + but :func:`pygame.init` is a convenient way to get everything started. The + ``init()`` functions for individual modules will raise exceptions when they + fail. + + You may want to initialize the different modules separately to speed up your + program or to not use modules your game does not require. + + It is safe to call this ``init()`` more than once as repeated calls will have + no effect. This is true even if you have ``pygame.quit()`` all the modules. + + .. ## pygame.init ## + +.. function:: quit + + | :sl:`uninitialize all pygame modules` + | :sg:`quit() -> None` + + Uninitialize all pygame modules that have previously been initialized. When + the Python interpreter shuts down, this method is called regardless, so your + program should not need it, except when it wants to terminate its pygame + resources and continue. It is safe to call this function more than once as + repeated calls have no effect. + + .. note:: + Calling :func:`pygame.quit` will not exit your program. Consider letting + your program end in the same way a normal Python program will end. + + .. ## pygame.quit ## + +.. function:: get_init + + | :sl:`returns True if pygame is currently initialized` + | :sg:`get_init() -> bool` + + Returns ``True`` if pygame is currently initialized. + + .. versionadded:: 1.9.5 + + .. ## pygame.get_init ## + +.. exception:: error + + | :sl:`standard pygame exception` + | :sg:`raise pygame.error(message)` + + This exception is raised whenever a pygame or SDL operation fails. You + can catch any anticipated problems and deal with the error. The exception is + always raised with a descriptive message about the problem. + + Derived from the ``RuntimeError`` exception, which can also be used to catch + these raised errors. + + .. ## pygame.error ## + +.. function:: get_error + + | :sl:`get the current error message` + | :sg:`get_error() -> errorstr` + + SDL maintains an internal error message. This message will usually be + given to you when :func:`pygame.error` is raised, so this function will + rarely be needed. + + .. ## pygame.get_error ## + +.. function:: set_error + + | :sl:`set the current error message` + | :sg:`set_error(error_msg) -> None` + + SDL maintains an internal error message. This message will usually be + given to you when :func:`pygame.error` is raised, so this function will + rarely be needed. + + .. ## pygame.set_error ## + +.. function:: get_sdl_version + + | :sl:`get the version number of SDL` + | :sg:`get_sdl_version() -> major, minor, patch` + + Returns the three version numbers of the SDL library. This version is built + at compile time. It can be used to detect which features may or may not be + available through pygame. + + .. versionadded:: 1.7.0 + + .. ## pygame.get_sdl_version ## + +.. function:: get_sdl_byteorder + + | :sl:`get the byte order of SDL` + | :sg:`get_sdl_byteorder() -> int` + + Returns the byte order of the SDL library. It returns ``1234`` for little + endian byte order and ``4321`` for big endian byte order. + + .. versionadded:: 1.8 + + .. ## pygame.get_sdl_byteorder ## + +.. function:: register_quit + + | :sl:`register a function to be called when pygame quits` + | :sg:`register_quit(callable) -> None` + + When :func:`pygame.quit` is called, all registered quit functions are + called. Pygame modules do this automatically when they are initializing, so + this function will rarely be needed. + + .. ## pygame.register_quit ## + +.. function:: encode_string + + | :sl:`Encode a Unicode or bytes object` + | :sg:`encode_string([obj [, encoding [, errors [, etype]]]]) -> bytes or None` + + obj: If Unicode, encode; if bytes, return unaltered; if anything else, + return ``None``; if not given, raise ``SyntaxError``. + + encoding (string): If present, encoding to use. The default is + ``'unicode_escape'``. + + errors (string): If given, how to handle unencodable characters. The default + is ``'backslashreplace'``. + + etype (exception type): If given, the exception type to raise for an + encoding error. The default is ``UnicodeEncodeError``, as returned by + ``PyUnicode_AsEncodedString()``. For the default encoding and errors values + there should be no encoding errors. + + This function is used in encoding file paths. Keyword arguments are + supported. + + .. versionadded:: 1.9.2 (primarily for use in unit tests) + + .. ## pygame.encode_string ## + +.. function:: encode_file_path + + | :sl:`Encode a Unicode or bytes object as a file system path` + | :sg:`encode_file_path([obj [, etype]]) -> bytes or None` + + obj: If Unicode, encode; if bytes, return unaltered; if anything else, + return ``None``; if not given, raise ``SyntaxError``. + + etype (exception type): If given, the exception type to raise for an + encoding error. The default is ``UnicodeEncodeError``, as returned by + ``PyUnicode_AsEncodedString()``. + + This function is used to encode file paths in pygame. Encoding is to the + codec as returned by ``sys.getfilesystemencoding()``. Keyword arguments are + supported. + + .. versionadded:: 1.9.2 (primarily for use in unit tests) + + .. ## pygame.encode_file_path ## + + +:mod:`pygame.version` +===================== + +.. module:: pygame.version + :synopsis: small module containing version information + +| :sl:`small module containing version information` + +This module is automatically imported into the pygame package and can be used to +check which version of pygame has been imported. + +.. data:: ver + + | :sl:`version number as a string` + | :sg:`ver = '1.2'` + + This is the version represented as a string. It can contain a micro release + number as well, e.g. ``'1.5.2'`` + + .. ## pygame.version.ver ## + +.. data:: vernum + + | :sl:`tupled integers of the version` + | :sg:`vernum = (1, 5, 3)` + + This version information can easily be compared with other version + numbers of the same format. An example of checking pygame version numbers + would look like this: + + :: + + if pygame.version.vernum < (1, 5): + print('Warning, older version of pygame (%s)' % pygame.version.ver) + disable_advanced_features = True + + .. versionadded:: 1.9.6 Attributes ``major``, ``minor``, and ``patch``. + + :: + + vernum.major == vernum[0] + vernum.minor == vernum[1] + vernum.patch == vernum[2] + + .. versionchanged:: 1.9.6 + ``str(pygame.version.vernum)`` returns a string like ``"2.0.0"`` instead + of ``"(2, 0, 0)"``. + + .. versionchanged:: 1.9.6 + ``repr(pygame.version.vernum)`` returns a string like + ``"PygameVersion(major=2, minor=0, patch=0)"`` instead of ``"(2, 0, 0)"``. + + .. ## pygame.version.vernum ## + +.. data:: rev + + | :sl:`repository revision of the build` + | :sg:`rev = 'a6f89747b551+'` + + The Mercurial node identifier of the repository checkout from which this + package was built. If the identifier ends with a plus sign '+' then the + package contains uncommitted changes. Please include this revision number + in bug reports, especially for non-release pygame builds. + + Important note: pygame development has moved to github, this variable is + obsolete now. As soon as development shifted to github, this variable started + returning an empty string ``""``. + It has always been returning an empty string since ``v1.9.5``. + + .. versionchanged:: 1.9.5 + Always returns an empty string ``""``. + + .. ## pygame.version.rev ## + +.. data:: SDL + + | :sl:`tupled integers of the SDL library version` + | :sg:`SDL = '(2, 0, 12)'` + + This is the SDL library version represented as an extended tuple. It also has + attributes 'major', 'minor' & 'patch' that can be accessed like this: + + :: + + >>> pygame.version.SDL.major + 2 + + printing the whole thing returns a string like this: + + :: + + >>> pygame.version.SDL + SDLVersion(major=2, minor=0, patch=12) + + .. versionadded:: 2.0.0 + + .. ## pygame.version.SDL ## + +.. ## pygame.version ## + +.. ## pygame ## + +.. _environment-variables: + +**Setting Environment Variables** + +Some aspects of pygame's behaviour can be controlled by setting environment variables, they cover a wide +range of the library's functionality. Some of the variables are from pygame itself, while others come from +the underlying C SDL library that pygame uses. + +In python, environment variables are usually set in code like this:: + + import os + os.environ['NAME_OF_ENVIRONMENT_VARIABLE'] = 'value_to_set' + +Or to preserve users ability to override the variable:: + + import os + os.environ['ENV_VAR'] = os.environ.get('ENV_VAR', 'value') + +If the variable is more useful for users of an app to set than the developer then they can set it like this: + +**Windows**:: + + set NAME_OF_ENVIRONMENT_VARIABLE=value_to_set + python my_application.py + +**Linux/Mac**:: + + ENV_VAR=value python my_application.py + +For some variables they need to be set before initialising pygame, some must be set before even importing pygame, +and others can simply be set right before the area of code they control is run. + +Below is a list of environment variables, their settable values, and a brief description of what they do. + +| + +**Pygame Environment Variables** + +These variables are defined by pygame itself. + +| + +:: + + PYGAME_DISPLAY - Experimental (subject to change) + Set index of the display to use, "0" is the default. + +This sets the display where pygame will open its window +or screen. The value set here will be used if set before +calling :func:`pygame.display.set_mode()`, and as long as no +'display' parameter is passed into :func:`pygame.display.set_mode()`. + +| + +:: + + PYGAME_FORCE_SCALE - + Set to "photo" or "default". + +This forces set_mode() to use the SCALED display mode and, +if "photo" is set, makes the scaling use the slowest, but +highest quality anisotropic scaling algorithm, if it is +available. Must be set before calling :func:`pygame.display.set_mode()`. + +| + +:: + + PYGAME_BLEND_ALPHA_SDL2 - New in pygame 2.0.0 + Set to "1" to enable the SDL2 blitter. + +This makes pygame use the SDL2 blitter for all alpha +blending. The SDL2 blitter is sometimes faster than +the default blitter but uses a different formula so +the final colours may differ. Must be set before +:func:`pygame.init()` is called. + +| + +:: + + PYGAME_HIDE_SUPPORT_PROMPT - + Set to "1" to hide the prompt. + +This stops the welcome message popping up in the +console that tells you which version of python, +pygame & SDL you are using. Must be set before +importing pygame. + +| + +:: + + PYGAME_FREETYPE - + Set to "1" to enable. + +This switches the pygame.font module to a pure +freetype implementation that bypasses SDL_ttf. +See the font module for why you might want to +do this. Must be set before importing pygame. + +| + +:: + + PYGAME_CAMERA - + Set to "opencv" or "vidcapture" + +Forces the library backend used in the camera +module, overriding the platform defaults. Must +be set before calling :func:`pygame.camera.init()`. + +In pygame 2.0.3, backends can be set programmatically instead, and the old +OpenCV backend has been replaced with one on top of "opencv-python," rather +than the old "highgui" OpenCV port. Also, there is a new native Windows +backend available. + +| +| + +**SDL Environment Variables** + +These variables are defined by SDL. + +For documentation on the environment variables available in +pygame 1 try `here +`__. +For Pygame 2, some selected environment variables are listed below. + +| + +:: + + SDL_VIDEO_CENTERED - + Set to "1" to enable centering the window. + +This will make the pygame window open in the centre of the display. +Must be set before calling :func:`pygame.display.set_mode()`. + +| + +:: + + SDL_VIDEO_WINDOW_POS - + Set to "x,y" to position the top left corner of the window. + +This allows control over the placement of the pygame window within +the display. Must be set before calling :func:`pygame.display.set_mode()`. + +| + +:: + + SDL_VIDEODRIVER - + Set to "drivername" to change the video driver used. + +On some platforms there are multiple video drivers available and +this allows users to pick between them. More information is available +`here `__. Must be set before +calling :func:`pygame.init()` or :func:`pygame.display.init()`. + +| + +:: + + SDL_AUDIODRIVER - + Set to "drivername" to change the audio driver used. + +On some platforms there are multiple audio drivers available and +this allows users to pick between them. More information is available +`here `__. Must be set before +calling :func:`pygame.init()` or :func:`pygame.mixer.init()`. + +| + +:: + + SDL_VIDEO_ALLOW_SCREENSAVER + Set to "1" to allow screensavers while pygame apps are running. + +By default pygame apps disable screensavers while +they are running. Setting this environment variable allows users or +developers to change that and make screensavers run again. + +| + +:: + + SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR + Set to "0" to re-enable the compositor. + +By default SDL tries to disable the X11 compositor for all pygame +apps. This is usually a good thing as it's faster, however if you +have an app which *doesn't* update every frame and are using linux +you may want to disable this bypass. The bypass has reported problems +on KDE linux. This variable is only used on x11/linux platforms. diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/rect.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/rect.rst.txt new file mode 100644 index 0000000..c1c30a5 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/rect.rst.txt @@ -0,0 +1,391 @@ +.. include:: common.txt + +:mod:`pygame.Rect` +================== + +.. currentmodule:: pygame + +.. class:: Rect + + | :sl:`pygame object for storing rectangular coordinates` + | :sg:`Rect(left, top, width, height) -> Rect` + | :sg:`Rect((left, top), (width, height)) -> Rect` + | :sg:`Rect(object) -> Rect` + + Pygame uses Rect objects to store and manipulate rectangular areas. A Rect + can be created from a combination of left, top, width, and height values. + Rects can also be created from python objects that are already a Rect or + have an attribute named "rect". + + Any pygame function that requires a Rect argument also accepts any of these + values to construct a Rect. This makes it easier to create Rects on the fly + as arguments to functions. + + The Rect functions that change the position or size of a Rect return a new + copy of the Rect with the affected changes. The original Rect is not + modified. Some methods have an alternate "in-place" version that returns + None but affects the original Rect. These "in-place" methods are denoted + with the "ip" suffix. + + The Rect object has several virtual attributes which can be used to move and + align the Rect: + + :: + + x,y + top, left, bottom, right + topleft, bottomleft, topright, bottomright + midtop, midleft, midbottom, midright + center, centerx, centery + size, width, height + w,h + + All of these attributes can be assigned to: + + :: + + rect1.right = 10 + rect2.center = (20,30) + + Assigning to size, width or height changes the dimensions of the rectangle; + all other assignments move the rectangle without resizing it. Notice that + some attributes are integers and others are pairs of integers. + + If a Rect has a nonzero width or height, it will return ``True`` for a + nonzero test. Some methods return a Rect with 0 size to represent an invalid + rectangle. A Rect with a 0 size will not collide when using collision + detection methods (e.g. :meth:`collidepoint`, :meth:`colliderect`, etc.). + + The coordinates for Rect objects are all integers. The size values can be + programmed to have negative values, but these are considered illegal Rects + for most operations. + + There are several collision tests between other rectangles. Most python + containers can be searched for collisions against a single Rect. + + The area covered by a Rect does not include the right- and bottom-most edge + of pixels. If one Rect's bottom border is another Rect's top border (i.e., + rect1.bottom=rect2.top), the two meet exactly on the screen but do not + overlap, and ``rect1.colliderect(rect2)`` returns false. + + .. versionadded:: 1.9.2 + The Rect class can be subclassed. Methods such as ``copy()`` and ``move()`` + will recognize this and return instances of the subclass. + However, the subclass's ``__init__()`` method is not called, + and ``__new__()`` is assumed to take no arguments. So these methods should be + overridden if any extra attributes need to be copied. + + .. method:: copy + + | :sl:`copy the rectangle` + | :sg:`copy() -> Rect` + + Returns a new rectangle having the same position and size as the original. + + New in pygame 1.9 + + .. ## Rect.copy ## + + .. method:: move + + | :sl:`moves the rectangle` + | :sg:`move(x, y) -> Rect` + + Returns a new rectangle that is moved by the given offset. The x and y + arguments can be any integer value, positive or negative. + + .. ## Rect.move ## + + .. method:: move_ip + + | :sl:`moves the rectangle, in place` + | :sg:`move_ip(x, y) -> None` + + Same as the ``Rect.move()`` method, but operates in place. + + .. ## Rect.move_ip ## + + .. method:: inflate + + | :sl:`grow or shrink the rectangle size` + | :sg:`inflate(x, y) -> Rect` + + Returns a new rectangle with the size changed by the given offset. The + rectangle remains centered around its current center. Negative values + will shrink the rectangle. Note, uses integers, if the offset given is + too small(< 2 > -2), center will be off. + + .. ## Rect.inflate ## + + .. method:: inflate_ip + + | :sl:`grow or shrink the rectangle size, in place` + | :sg:`inflate_ip(x, y) -> None` + + Same as the ``Rect.inflate()`` method, but operates in place. + + .. ## Rect.inflate_ip ## + + .. method:: update + + | :sl:`sets the position and size of the rectangle` + | :sg:`update(left, top, width, height) -> None` + | :sg:`update((left, top), (width, height)) -> None` + | :sg:`update(object) -> None` + + Sets the position and size of the rectangle, in place. See + parameters for :meth:`pygame.Rect` for the parameters of this function. + + .. versionadded:: 2.0.1 + + .. ## Rect.update ## + + .. method:: clamp + + | :sl:`moves the rectangle inside another` + | :sg:`clamp(Rect) -> Rect` + + Returns a new rectangle that is moved to be completely inside the + argument Rect. If the rectangle is too large to fit inside, it is + centered inside the argument Rect, but its size is not changed. + + .. ## Rect.clamp ## + + .. method:: clamp_ip + + | :sl:`moves the rectangle inside another, in place` + | :sg:`clamp_ip(Rect) -> None` + + Same as the ``Rect.clamp()`` method, but operates in place. + + .. ## Rect.clamp_ip ## + + .. method:: clip + + | :sl:`crops a rectangle inside another` + | :sg:`clip(Rect) -> Rect` + + Returns a new rectangle that is cropped to be completely inside the + argument Rect. If the two rectangles do not overlap to begin with, a Rect + with 0 size is returned. + + .. ## Rect.clip ## + + .. method:: clipline + + | :sl:`crops a line inside a rectangle` + | :sg:`clipline(x1, y1, x2, y2) -> ((cx1, cy1), (cx2, cy2))` + | :sg:`clipline(x1, y1, x2, y2) -> ()` + | :sg:`clipline((x1, y1), (x2, y2)) -> ((cx1, cy1), (cx2, cy2))` + | :sg:`clipline((x1, y1), (x2, y2)) -> ()` + | :sg:`clipline((x1, y1, x2, y2)) -> ((cx1, cy1), (cx2, cy2))` + | :sg:`clipline((x1, y1, x2, y2)) -> ()` + | :sg:`clipline(((x1, y1), (x2, y2))) -> ((cx1, cy1), (cx2, cy2))` + | :sg:`clipline(((x1, y1), (x2, y2))) -> ()` + + Returns the coordinates of a line that is cropped to be completely inside + the rectangle. If the line does not overlap the rectangle, then an empty + tuple is returned. + + The line to crop can be any of the following formats (floats can be used + in place of ints, but they will be truncated): + + - four ints + - 2 lists/tuples/Vector2s of 2 ints + - a list/tuple of four ints + - a list/tuple of 2 lists/tuples/Vector2s of 2 ints + + :returns: a tuple with the coordinates of the given line cropped to be + completely inside the rectangle is returned, if the given line does + not overlap the rectangle, an empty tuple is returned + :rtype: tuple(tuple(int, int), tuple(int, int)) or () + + :raises TypeError: if the line coordinates are not given as one of the + above described line formats + + .. note :: + This method can be used for collision detection between a rect and a + line. See example code below. + + .. note :: + The ``rect.bottom`` and ``rect.right`` attributes of a + :mod:`pygame.Rect` always lie one pixel outside of its actual border. + + :: + + # Example using clipline(). + clipped_line = rect.clipline(line) + + if clipped_line: + # If clipped_line is not an empty tuple then the line + # collides/overlaps with the rect. The returned value contains + # the endpoints of the clipped line. + start, end = clipped_line + x1, y1 = start + x2, y2 = end + else: + print("No clipping. The line is fully outside the rect.") + + .. versionadded:: 2.0.0 + + .. ## Rect.clipline ## + + .. method:: union + + | :sl:`joins two rectangles into one` + | :sg:`union(Rect) -> Rect` + + Returns a new rectangle that completely covers the area of the two + provided rectangles. There may be area inside the new Rect that is not + covered by the originals. + + .. ## Rect.union ## + + .. method:: union_ip + + | :sl:`joins two rectangles into one, in place` + | :sg:`union_ip(Rect) -> None` + + Same as the ``Rect.union()`` method, but operates in place. + + .. ## Rect.union_ip ## + + .. method:: unionall + + | :sl:`the union of many rectangles` + | :sg:`unionall(Rect_sequence) -> Rect` + + Returns the union of one rectangle with a sequence of many rectangles. + + .. ## Rect.unionall ## + + .. method:: unionall_ip + + | :sl:`the union of many rectangles, in place` + | :sg:`unionall_ip(Rect_sequence) -> None` + + The same as the ``Rect.unionall()`` method, but operates in place. + + .. ## Rect.unionall_ip ## + + .. method:: fit + + | :sl:`resize and move a rectangle with aspect ratio` + | :sg:`fit(Rect) -> Rect` + + Returns a new rectangle that is moved and resized to fit another. The + aspect ratio of the original Rect is preserved, so the new rectangle may + be smaller than the target in either width or height. + + .. ## Rect.fit ## + + .. method:: normalize + + | :sl:`correct negative sizes` + | :sg:`normalize() -> None` + + This will flip the width or height of a rectangle if it has a negative + size. The rectangle will remain in the same place, with only the sides + swapped. + + .. ## Rect.normalize ## + + .. method:: contains + + | :sl:`test if one rectangle is inside another` + | :sg:`contains(Rect) -> bool` + + Returns true when the argument is completely inside the Rect. + + .. ## Rect.contains ## + + .. method:: collidepoint + + | :sl:`test if a point is inside a rectangle` + | :sg:`collidepoint(x, y) -> bool` + | :sg:`collidepoint((x,y)) -> bool` + + Returns true if the given point is inside the rectangle. A point along + the right or bottom edge is not considered to be inside the rectangle. + + .. note :: + For collision detection between a rect and a line the :meth:`clipline` + method can be used. + + .. ## Rect.collidepoint ## + + .. method:: colliderect + + | :sl:`test if two rectangles overlap` + | :sg:`colliderect(Rect) -> bool` + + Returns true if any portion of either rectangle overlap (except the + top+bottom or left+right edges). + + .. note :: + For collision detection between a rect and a line the :meth:`clipline` + method can be used. + + .. ## Rect.colliderect ## + + .. method:: collidelist + + | :sl:`test if one rectangle in a list intersects` + | :sg:`collidelist(list) -> index` + + Test whether the rectangle collides with any in a sequence of rectangles. + The index of the first collision found is returned. If no collisions are + found an index of -1 is returned. + + .. ## Rect.collidelist ## + + .. method:: collidelistall + + | :sl:`test if all rectangles in a list intersect` + | :sg:`collidelistall(list) -> indices` + + Returns a list of all the indices that contain rectangles that collide + with the Rect. If no intersecting rectangles are found, an empty list is + returned. + + .. ## Rect.collidelistall ## + + .. method:: collidedict + + | :sl:`test if one rectangle in a dictionary intersects` + | :sg:`collidedict(dict) -> (key, value)` + | :sg:`collidedict(dict) -> None` + | :sg:`collidedict(dict, use_values=0) -> (key, value)` + | :sg:`collidedict(dict, use_values=0) -> None` + + Returns the first key and value pair that intersects with the calling + Rect object. If no collisions are found, ``None`` is returned. If + ``use_values`` is 0 (default) then the dict's keys will be used in the + collision detection, otherwise the dict's values will be used. + + .. note :: + Rect objects cannot be used as keys in a dictionary (they are not + hashable), so they must be converted to a tuple. + e.g. ``rect.collidedict({tuple(key_rect) : value})`` + + .. ## Rect.collidedict ## + + .. method:: collidedictall + + | :sl:`test if all rectangles in a dictionary intersect` + | :sg:`collidedictall(dict) -> [(key, value), ...]` + | :sg:`collidedictall(dict, use_values=0) -> [(key, value), ...]` + + Returns a list of all the key and value pairs that intersect with the + calling Rect object. If no collisions are found an empty list is returned. + If ``use_values`` is 0 (default) then the dict's keys will be used in the + collision detection, otherwise the dict's values will be used. + + .. note :: + Rect objects cannot be used as keys in a dictionary (they are not + hashable), so they must be converted to a tuple. + e.g. ``rect.collidedictall({tuple(key_rect) : value})`` + + .. ## Rect.collidedictall ## + + .. ## pygame.Rect ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/scrap.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/scrap.rst.txt new file mode 100644 index 0000000..2b52337 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/scrap.rst.txt @@ -0,0 +1,240 @@ +.. include:: common.txt + +:mod:`pygame.scrap` +=================== + +.. module:: pygame.scrap + :synopsis: pygame module for clipboard support. + +| :sl:`pygame module for clipboard support.` + +**EXPERIMENTAL!**: This API may change or disappear in later pygame releases. If +you use this, your code may break with the next pygame release. + +The scrap module is for transferring data to/from the clipboard. This allows +for cutting and pasting data between pygame and other applications. Some basic +data (MIME) types are defined and registered: + +:: + + pygame string + constant value description + -------------------------------------------------- + SCRAP_TEXT "text/plain" plain text + SCRAP_BMP "image/bmp" BMP encoded image data + SCRAP_PBM "image/pbm" PBM encoded image data + SCRAP_PPM "image/ppm" PPM encoded image data + +``pygame.SCRAP_PPM``, ``pygame.SCRAP_PBM`` and ``pygame.SCRAP_BMP`` are +suitable for surface buffers to be shared with other applications. +``pygame.SCRAP_TEXT`` is an alias for the plain text clipboard type. + +Depending on the platform, additional types are automatically registered when +data is placed into the clipboard to guarantee a consistent sharing behaviour +with other applications. The following listed types can be used as strings to +be passed to the respective :mod:`pygame.scrap` module functions. + +For **Windows** platforms, these additional types are supported automatically +and resolve to their internal definitions: + +:: + + "text/plain;charset=utf-8" UTF-8 encoded text + "audio/wav" WAV encoded audio + "image/tiff" TIFF encoded image data + +For **X11** platforms, these additional types are supported automatically and +resolve to their internal definitions: + +:: + + "text/plain;charset=utf-8" UTF-8 encoded text + "UTF8_STRING" UTF-8 encoded text + "COMPOUND_TEXT" COMPOUND text + +User defined types can be used, but the data might not be accessible by other +applications unless they know what data type to look for. +Example: Data placed into the clipboard by +``pygame.scrap.put("my_data_type", byte_data)`` can only be accessed by +applications which query the clipboard for the ``"my_data_type"`` data type. + +For an example of how the scrap module works refer to the examples page +(:func:`pygame.examples.scrap_clipboard.main`) or the code directly in GitHub +(`pygame/examples/scrap_clipboard.py `_). + +.. versionadded:: 1.8 + +.. note:: + The scrap module is currently only supported for Windows, X11 and Mac OS X. + On Mac OS X only text works at the moment - other types may be supported in + future releases. + +.. function:: init + + | :sl:`Initializes the scrap module.` + | :sg:`init() -> None` + + Initialize the scrap module. + + :raises pygame.error: if unable to initialize scrap module + + .. note:: The scrap module requires :func:`pygame.display.set_mode()` be + called before being initialized. + + .. ## pygame.scrap.init ## + +.. function:: get_init + + | :sl:`Returns True if the scrap module is currently initialized.` + | :sg:`get_init() -> bool` + + Gets the scrap module's initialization state. + + :returns: ``True`` if the :mod:`pygame.scrap` module is currently + initialized, ``False`` otherwise + :rtype: bool + + .. versionadded:: 1.9.5 + + .. ## pygame.scrap.get_init ## + +.. function:: get + + | :sl:`Gets the data for the specified type from the clipboard.` + | :sg:`get(type) -> bytes | None` + + Retrieves the data for the specified type from the clipboard. The data is + returned as a byte string and might need further processing (such as + decoding to Unicode). + + :param string type: data type to retrieve from the clipboard + + :returns: data (bytes object) for the given type identifier or ``None`` if + no data for the given type is available + :rtype: bytes | None + + :: + + text = pygame.scrap.get(pygame.SCRAP_TEXT) + if text: + print("There is text in the clipboard.") + else: + print("There does not seem to be text in the clipboard.") + + .. ## pygame.scrap.get ## + +.. function:: get_types + + | :sl:`Gets a list of the available clipboard types.` + | :sg:`get_types() -> list` + + Gets a list of data type string identifiers for the data currently + available on the clipboard. Each identifier can be used in the + :func:`pygame.scrap.get()` method to get the clipboard content of the + specific type. + + :returns: list of strings of the available clipboard data types, if there + is no data in the clipboard an empty list is returned + :rtype: list + + :: + + for t in pygame.scrap.get_types(): + if "text" in t: + # There is some content with the word "text" in its type string. + print(pygame.scrap.get(t)) + + .. ## pygame.scrap.get_types ## + +.. function:: put + + | :sl:`Places data into the clipboard.` + | :sg:`put(type, data) -> None` + + Places data for a given clipboard type into the clipboard. The data must + be a string buffer. The type is a string identifying the type of data to be + placed into the clipboard. This can be one of the predefined + ``pygame.SCRAP_PBM``, ``pygame.SCRAP_PPM``, ``pygame.SCRAP_BMP`` or + ``pygame.SCRAP_TEXT`` values or a user defined string identifier. + + :param string type: type identifier of the data to be placed into the + clipboard + :param data: data to be place into the clipboard, a bytes object + :type data: bytes + + :raises pygame.error: if unable to put the data into the clipboard + + :: + + with open("example.bmp", "rb") as fp: + pygame.scrap.put(pygame.SCRAP_BMP, fp.read()) + # The image data is now on the clipboard for other applications to access + # it. + pygame.scrap.put(pygame.SCRAP_TEXT, b"A text to copy") + pygame.scrap.put("Plain text", b"Data for user defined type 'Plain text'") + + .. ## pygame.scrap.put ## + +.. function:: contains + + | :sl:`Checks whether data for a given type is available in the clipboard.` + | :sg:`contains(type) -> bool` + + Checks whether data for the given type is currently available in the + clipboard. + + :param string type: data type to check availability of + + :returns: ``True`` if data for the passed type is available in the + clipboard, ``False`` otherwise + :rtype: bool + + :: + + if pygame.scrap.contains(pygame.SCRAP_TEXT): + print("There is text in the clipboard.") + if pygame.scrap.contains("own_data_type"): + print("There is stuff in the clipboard.") + + .. ## pygame.scrap.contains ## + +.. function:: lost + + | :sl:`Indicates if the clipboard ownership has been lost by the pygame application.` + | :sg:`lost() -> bool` + + Indicates if the clipboard ownership has been lost by the pygame + application. + + :returns: ``True``, if the clipboard ownership has been lost by the pygame + application, ``False`` if the pygame application still owns the clipboard + :rtype: bool + + :: + + if pygame.scrap.lost(): + print("The clipboard is in use by another application.") + + .. ## pygame.scrap.lost ## + +.. function:: set_mode + + | :sl:`Sets the clipboard access mode.` + | :sg:`set_mode(mode) -> None` + + Sets the access mode for the clipboard. This is only of interest for X11 + environments where clipboard modes ``pygame.SCRAP_SELECTION`` (for mouse + selections) and ``pygame.SCRAP_CLIPBOARD`` (for the clipboard) are + available. Setting the mode to ``pygame.SCRAP_SELECTION`` in other + environments will not change the mode from ``pygame.SCRAP_CLIPBOARD``. + + :param mode: access mode, supported values are ``pygame.SCRAP_CLIPBOARD`` + and ``pygame.SCRAP_SELECTION`` (``pygame.SCRAP_SELECTION`` only has an + effect when used on X11 platforms) + + :raises ValueError: if the ``mode`` parameter is not + ``pygame.SCRAP_CLIPBOARD`` or ``pygame.SCRAP_SELECTION`` + + .. ## pygame.scrap.set_mode ## + +.. ## pygame.scrap ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/sdl2_controller.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/sdl2_controller.rst.txt new file mode 100644 index 0000000..dcfee7d --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/sdl2_controller.rst.txt @@ -0,0 +1,287 @@ +.. include:: common.txt + +:mod:`pygame._sdl2.controller` +============================== + +.. module:: pygame._sdl2.controller + :synopsis: pygame module to work with controllers + +| :sl:`Pygame module to work with controllers.` + +This module offers control over common controller types like the dualshock 4 or +the xbox 360 controllers: They have two analog sticks, two triggers, two shoulder buttons, +a dpad, 4 buttons on the side, 2 (or 3) buttons in the middle. + +Pygame uses xbox controllers naming conventions (like a, b, x, y for buttons) but +they always refer to the same buttons. For example ``CONTROLLER_BUTTON_X`` is +always the leftmost button of the 4 buttons on the right. + +Controllers can generate the following events:: + + CONTROLLERAXISMOTION, CONTROLLERBUTTONDOWN, CONTROLLERBUTTONUP, + CONTROLLERDEVICEREMAPPED, CONTROLLERDEVICEADDED, CONTROLLERDEVICEREMOVED + +Additionally if pygame is built with SDL 2.0.14 or higher the following events can also be generated +(to get the version of sdl pygame is built with use :meth:`pygame.version.SDL`):: + + CONTROLLERTOUCHPADDOWN, CONTROLLERTOUCHPADMOTION, CONTROLLERTOUCHPADUP + +These events can be enabled/disabled by :meth:`pygame._sdl2.controller.set_eventstate` +Note that controllers can generate joystick events as well. This function only toggles +events related to controllers. + +.. note:: + See the :mod:`pygame.joystick` for a more versatile but more advanced api. + +.. versionadded:: 2 This module requires SDL2. + +.. function:: init + + | :sl:`initialize the controller module` + | :sg:`init() -> None` + + Initialize the controller module. + + .. ## pygame._sdl2.controller.init ## + +.. function:: quit + + | :sl:`Uninitialize the controller module.` + | :sg:`quit() -> None` + + Uninitialize the controller module. + + .. ## pygame._sdl2.controller.quit ## + +.. function:: get_init + + | :sl:`Returns True if the controller module is initialized.` + | :sg:`get_init() -> bool` + + Test if ``pygame._sdl2.controller.init()`` was called. + + .. ## pygame._sdl2.controller.get_init ## + +.. function:: set_eventstate + + | :sl:`Sets the current state of events related to controllers` + | :sg:`set_eventstate(state) -> None` + + Enable or disable events connected to controllers. + + .. note:: + Controllers can still generate joystick events, which will not be toggled by this function. + + .. versionchanged:: 2.0.2: Changed return type from int to None + + .. ## pygame._sdl2.controller.set_eventstate ## + +.. function:: get_eventstate + + | :sl:`Gets the current state of events related to controllers` + | :sg:`get_eventstate() -> bool` + + Returns the current state of events related to controllers, True meaning + events will be posted. + + .. versionadded:: 2.0.2 + + .. ## pygame._sdl2.controller.get_eventstate ## + +.. function:: get_count + + | :sl:`Get the number of joysticks connected` + | :sg:`get_count() -> int` + + Get the number of joysticks connected. + + .. ## pygame._sdl2.controller.get_count ## + +.. function:: is_controller + + | :sl:`Check if the given joystick is supported by the game controller interface` + | :sg:`is_controller(index) -> bool` + + Returns True if the index given can be used to create a controller object. + + .. ## pygame._sdl2.controller.is_controller ## + +.. function:: name_forindex + + | :sl:`Get the name of the contoller` + | :sg:`name_forindex(index) -> name or None` + + Returns the name of controller, or None if there's no name or the + index is invalid. + + .. ## pygame._sdl2.controller.name_forindex ## + +.. class:: Controller + + | :sl:`Create a new Controller object.` + | :sg:`Controller(index) -> Controller` + + Create a new Controller object. Index should be integer between + 0 and ``pygame._sdl2.contoller.get_count()``. Controllers also + can be created from a ``pygame.joystick.Joystick`` using + ``pygame._sdl2.controller.from_joystick``. Controllers are + initialized on creation. + + .. method:: quit + + | :sl:`uninitialize the Controller` + | :sg:`quit() -> None` + + Close a Controller object. After this the pygame event queue will no longer + receive events from the device. + + It is safe to call this more than once. + + .. ## Controller.quit ## + + .. method:: get_init + + | :sl:`check if the Controller is initialized` + | :sg:`get_init() -> bool` + + Returns True if the Controller object is currently initialised. + + .. ## Controller.get_init ## + + .. staticmethod:: from_joystick + + | :sl:`Create a Controller from a pygame.joystick.Joystick object` + | :sg:`from_joystick(joystick) -> Controller` + + Create a Controller object from a ``pygame.joystick.Joystick`` object + + .. ## Controller.from_joystick ## + + .. method:: attached + + | :sl:`Check if the Controller has been opened and is currently connected.` + | :sg:`attached() -> bool` + + Returns True if the Controller object is opened and connected. + + .. ## Controller.attached ## + + .. method:: as_joystick + + | :sl:`Returns a pygame.joystick.Joystick() object` + | :sg:`as_joystick() -> Joystick object` + + Returns a pygame.joystick.Joystick() object created from this controller's index + + .. ## Controller.as_joystick ## + + .. method:: get_axis + + | :sl:`Get the current state of a joystick axis` + | :sg:`get_axis(axis) -> int` + + Get the current state of a trigger or joystick axis. + The axis argument must be one of the following constants:: + + CONTROLLER_AXIS_LEFTX, CONTROLLER_AXIS_LEFTY, + CONTROLLER_AXIS_RIGHTX, CONTROLLER_AXIS_RIGHTY, + CONTROLLER_AXIS_TRIGGERLEFT, CONTROLLER_AXIS_TRIGGERRIGHT + + Joysticks can return a value between -32768 and 32767. Triggers however + can only return a value between 0 and 32768. + + .. ## Controller.get_axis ## + + .. method:: get_button + + | :sl:`Get the current state of a button` + | :sg:`get_button(button) -> bool` + + Get the current state of a button, True meaning it is pressed down. + The button argument must be one of the following constants:: + + CONTROLLER_BUTTON_A, CONTROLLER_BUTTON_B, + CONTROLLER_BUTTON_X, CONTROLLER_BUTTON_Y + CONTROLLER_BUTTON_DPAD_UP, CONTROLLER_BUTTON_DPAD_DOWN, + CONTROLLER_BUTTON_DPAD_LEFT, CONTROLLER_BUTTON_DPAD_RIGHT, + CONTROLLER_BUTTON_LEFTSHOULDER, CONTROLLER_BUTTON_RIGHTSHOULDER, + CONTROLLER_BUTTON_LEFTSTICK, CONTROLLER_BUTTON_RIGHTSTICK, + CONTROLLER_BUTTON_BACK, CONTROLLER_BUTTON_GUIDE, + CONTROLLER_BUTTON_START + + + .. ## Controller.get_button ## + + .. method:: get_mapping + + | :sl:`Get the mapping assigned to the controller` + | :sg:`get_mapping() -> mapping` + + Returns a dict containing the mapping of the Controller. For more + information see :meth:`Controller.set_mapping()` + + .. versionchanged:: 2.0.2: Return type changed from ``str`` to ``dict`` + + .. ## Contorller.get_mapping ## + + .. method:: set_mapping + + | :sl:`Assign a mapping to the controller` + | :sg:`set_mapping(mapping) -> int` + + Rebind buttons, axes, triggers and dpads. The mapping should be a + dict containing all buttons, hats and axes. The easiest way to get this + is to use the dict returned by :meth:`Controller.get_mapping`. To edit + this mapping assign a value to the original button. The value of the + dictionary must be a button, hat or axis represented in the following way: + + * For a button use: bX where X is the index of the button. + * For a hat use: hX.Y where X is the index and the Y is the direction (up: 1, right: 2, down: 3, left: 4). + * For an axis use: aX where x is the index of the axis. + + An example of mapping:: + + mapping = controller.get_mapping() # Get current mapping + mapping["a"] = "b3" # Remap button a to y + mapping["y"] = "b0" # Remap button y to a + controller.set_mapping(mapping) # Set the mapping + + + The function will return 1 if a new mapping is added or 0 if an existing one is updated. + + .. versionchanged:: 2.0.2: Renamed from ``add_mapping`` to ``set_mapping`` + .. versionchanged:: 2.0.2: Argument type changed from ``str`` to ``dict`` + + .. ## Contorller.set_mapping ## + + .. method:: rumble + + | :sl:`Start a rumbling effect` + | :sg:`rumble(low_frequency, high_frequency, duration) -> bool` + + Start a rumble effect on the controller, with the specified strength ranging + from 0 to 1. Duration is length of the effect, in ms. Setting the duration + to 0 will play the effect until another one overwrites it or + :meth:`Controller.stop_rumble` is called. If an effect is already + playing, then it will be overwritten. + + Returns True if the rumble was played successfully or False if the + controller does not support it or :meth:`pygame.version.SDL` is below 2.0.9. + + .. versionadded:: 2.0.2 + + .. ## Contorller.rumble ## + + .. method:: stop_rumble + + | :sl:`Stop any rumble effect playing` + | :sg:`stop_rumble() -> None` + + Stops any rumble effect playing on the controller. See + :meth:`Controller.rumble` for more information. + + .. versionadded:: 2.0.2 + + .. ## Contorller.stop_rumble ## + +.. ## pygame._sdl2.controller ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/sdl2_video.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/sdl2_video.rst.txt new file mode 100644 index 0000000..c822be2 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/sdl2_video.rst.txt @@ -0,0 +1,334 @@ +.. include:: common.txt + +:mod:`pygame.sdl2_video` +======================== + +.. module:: pygame._sdl2.video + :synopsis: Experimental pygame module for porting new SDL video systems + +.. warning:: + This module isn't ready for prime time yet, it's still in development. + These docs are primarily meant to help the pygame developers and super-early adopters + who are in communication with the developers. This API will change. + +| :sl:`Experimental pygame module for porting new SDL video systems` + +.. class:: Window + + | :sl:`pygame object that represents a window` + | :sg:`Window(title="pygame", size=(640, 480), position=None, fullscreen=False, fullscreen_desktop=False, keywords) -> Window` + + .. classmethod:: from_display_module + + | :sl:`Creates window using window created by pygame.display.set_mode().` + | :sg:`from_display_module() -> Window` + + .. attribute:: grab + + | :sl:`Gets or sets whether the mouse is confined to the window.` + | :sg:`grab -> bool` + + .. attribute:: relative_mouse + + | :sl:`Gets or sets the window's relative mouse motion state.` + | :sg:`relative_mouse -> bool` + + .. method:: set_windowed + + | :sl:`Enable windowed mode (exit fullscreen).` + | :sg:`set_windowed() -> None` + + .. method:: set_fullscreen + + | :sl:`Enter fullscreen.` + | :sg:`set_fullscreen(desktop=False) -> None` + + .. attribute:: title + + | :sl:`Gets or sets whether the window title.` + | :sg:`title -> string` + + .. method:: destroy + + | :sl:`Destroys the window.` + | :sg:`destroy() -> None` + + .. method:: hide + + | :sl:`Hide the window.` + | :sg:`hide() -> None` + + .. method:: show + + | :sl:`Show the window.` + | :sg:`show() -> None` + + .. method:: focus + + | :sl:`Raise the window above other windows and set the input focus. The "input_only" argument is only supported on X11.` + | :sg:`focus(input_only=False) -> None` + + .. method:: restore + + | :sl:`Restore the size and position of a minimized or maximized window.` + | :sg:`restore() -> None` + + .. method:: maximize + + | :sl:`Maximize the window.` + | :sg:`maximize() -> None` + + .. method:: minimize + + | :sl:`Minimize the window.` + | :sg:`maximize() -> None` + + .. attribute:: resizable + + | :sl:`Gets and sets whether the window is resizable.` + | :sg:`resizable -> bool` + + .. attribute:: borderless + + | :sl:`Add or remove the border from the window.` + | :sg:`borderless -> bool` + + .. method:: set_icon + + | :sl:`Set the icon for the window.` + | :sg:`set_icon(surface) -> None` + + .. attribute:: id + + | :sl:`Get the unique window ID. *Read-only*` + | :sg:`id -> int` + + .. attribute:: size + + | :sl:`Gets and sets the window size.` + | :sg:`size -> (int, int)` + + .. attribute:: position + + | :sl:`Gets and sets the window position.` + | :sg:`position -> (int, int) or WINDOWPOS_CENTERED or WINDOWPOS_UNDEFINED` + + .. attribute:: opacity + + | :sl:`Gets and sets the window opacity. Between 0.0 (fully transparent) and 1.0 (fully opaque).` + | :sg:`opacity -> float` + + .. attribute:: brightness + + | :sl:`Gets and sets the brightness (gamma multiplier) for the display that owns the window.` + | :sg:`brightness -> float` + + .. attribute:: display_index + + | :sl:`Get the index of the display that owns the window. *Read-only*` + | :sg:`display_index -> int` + + .. method:: set_modal_for + + | :sl:`Set the window as a modal for a parent window. This function is only supported on X11.` + | :sg:`set_modal_for(Window) -> None` + +.. class:: Texture + + | :sl:`pygame object that representing a Texture.` + | :sg:`Texture(renderer, size, depth=0, static=False, streaming=False, target=False) -> Texture` + + .. staticmethod:: from_surface + + | :sl:`Create a texture from an existing surface.` + | :sg:`from_surface(renderer, surface) -> Texture` + + .. attribute:: renderer + + | :sl:`Gets the renderer associated with the Texture. *Read-only*` + | :sg:`renderer -> Renderer` + + .. attribute:: width + + | :sl:`Gets the width of the Texture. *Read-only*` + | :sg:`width -> int` + + .. attribute:: height + + | :sl:`Gets the height of the Texture. *Read-only*` + | :sg:`height -> int` + + .. attribute:: alpha + + | :sl:`Gets and sets an additional alpha value multiplied into render copy operations.` + | :sg:`alpha -> int` + + .. attribute:: blend_mode + + | :sl:`Gets and sets the blend mode for the Texture.` + | :sg:`blend_mode -> int` + + .. attribute:: color + + | :sl:`Gets and sets an additional color value multiplied into render copy operations.` + | :sg:`color -> color` + + .. method:: get_rect + + | :sl:`Get the rectangular area of the texture.` + | :sg:`get_rect(**kwargs) -> Rect` + + .. method:: draw + + | :sl:`Copy a portion of the texture to the rendering target.` + | :sg:`draw(srcrect=None, dstrect=None, angle=0, origin=None, flipX=False, flipY=False) -> None` + + .. method:: update + + | :sl:`Update the texture with a Surface. WARNING: Slow operation, use sparingly.` + | :sg:`update(surface, area=None) -> None` + +.. class:: Image + + | :sl:`Easy way to use a portion of a Texture without worrying about srcrect all the time.` + | :sg:`Image(textureOrImage, srcrect=None) -> Image` + + .. method:: get_rect + + | :sl:`Get the rectangular area of the Image.` + | :sg:`get_rect() -> Rect` + + .. method:: draw + + | :sl:`Copy a portion of the Image to the rendering target.` + | :sg:`draw(srcrect=None, dstrect=None) -> None` + + .. attribute:: angle + + | :sl:`Gets and sets the angle the Image draws itself with.` + | :sg:`angle -> float` + + .. attribute:: origin + + | :sl:`Gets and sets the origin. Origin=None means the Image will be rotated around its center.` + | :sg:`origin -> (float, float) or None.` + + .. attribute:: flipX + + | :sl:`Gets and sets whether the Image is flipped on the x axis.` + | :sg:`flipX -> bool` + + .. attribute:: flipY + + | :sl:`Gets and sets whether the Image is flipped on the y axis.` + | :sg:`flipY -> bool` + + .. attribute:: color + + | :sl:`Gets and sets the Image color modifier.` + | :sg:`color -> Color` + + .. attribute:: alpha + + | :sl:`Gets and sets the Image alpha modifier.` + | :sg:`alpha -> float` + + .. attribute:: blend_mode + + | :sl:`Gets and sets the blend mode for the Image.` + | :sg:`blend_mode -> int` + + .. attribute:: texture + + | :sl:`Gets and sets the Texture the Image is based on.` + | :sg:`texture -> Texture` + + .. attribute:: srcrect + + | :sl:`Gets and sets the Rect the Image is based on.` + | :sg:`srcrect -> Rect` + +.. class:: Renderer + + | :sl:`Create a 2D rendering context for a window.` + | :sg:`Renderer(window, index=-1, accelerated=-1, vsync=False, target_texture=False) -> Renderer` + + .. classmethod:: from_window + + | :sl:`Easy way to create a Renderer.` + | :sg:`from_window(window) -> Renderer` + + .. attribute:: draw_blend_mode + + | :sl:`Gets and sets the blend mode used by the drawing functions.` + | :sg:`draw_blend_mode -> int` + + .. attribute:: draw_color + + | :sl:`Gets and sets the color used by the drawing functions.` + | :sg:`draw_color -> Color` + + .. method:: clear + + | :sl:`Clear the current rendering target with the drawing color.` + | :sg:`clear() -> None` + + .. method:: present + + | :sl:`Updates the screen with any new rendering since previous call.` + | :sg:`present() -> None` + + .. method:: get_viewport + + | :sl:`Returns the drawing area on the target.` + | :sg:`get_viewport() -> Rect` + + .. method:: set_viewport + + | :sl:`Set the drawing area on the target. If area is None, the entire target will be used.` + | :sg:`set_viewport(area) -> None` + + .. attribute:: logical_size + + | :sl:`Gets and sets the logical size.` + | :sg:`logical_size -> (int width, int height)` + + .. attribute:: scale + + | :sl:`Gets and sets the scale.` + | :sg:`scale -> (float x_scale, float y_scale)` + + .. attribute:: target + + | :sl:`Gets and sets the render target. None represents the default target (the renderer).` + | :sg:`target -> Texture or None` + + .. method:: blit + + | :sl:`For compatibility purposes. Textures created by different Renderers cannot be shared!` + | :sg:`blit(soure, dest, area=None, special_flags=0)-> Rect` + + .. method:: draw_line + + | :sl:`Draws a line.` + | :sg:`draw_line(p1, p2) -> None` + + .. method:: draw_point + + | :sl:`Draws a point.` + | :sg:`draw_point(point) -> None` + + .. method:: draw_rect + + | :sl:`Draws a rectangle.` + | :sg:`draw_rect(rect)-> None` + + .. method:: fill_rect + + | :sl:`Fills a rectangle.` + | :sg:`fill_rect(rect)-> None` + + .. method:: to_surface + + | :sl:`Read pixels from current render target and create a pygame.Surface. WARNING: Slow operation, use sparingly.` + | :sg:`to_surface(surface=None, area=None)-> Surface` \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/sndarray.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/sndarray.rst.txt new file mode 100644 index 0000000..2a17764 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/sndarray.rst.txt @@ -0,0 +1,95 @@ +.. include:: common.txt + +:mod:`pygame.sndarray` +====================== + +.. module:: pygame.sndarray + :synopsis: pygame module for accessing sound sample data + +| :sl:`pygame module for accessing sound sample data` + +Functions to convert between NumPy arrays and Sound objects. This +module will only be functional when pygame can use the external NumPy +package. If NumPy can't be imported, ``surfarray`` becomes a ``MissingModule`` +object. + +Sound data is made of thousands of samples per second, and each sample is the +amplitude of the wave at a particular moment in time. For example, in 22-kHz +format, element number 5 of the array is the amplitude of the wave after +5/22000 seconds. + +The arrays are indexed by the ``X`` axis first, followed by the ``Y`` axis. +Each sample is an 8-bit or 16-bit integer, depending on the data format. A +stereo sound file has two values per sample, while a mono sound file only has +one. + +.. function:: array + + | :sl:`copy Sound samples into an array` + | :sg:`array(Sound) -> array` + + Creates a new array for the sound data and copies the samples. The array + will always be in the format returned from ``pygame.mixer.get_init()``. + + .. ## pygame.sndarray.array ## + +.. function:: samples + + | :sl:`reference Sound samples into an array` + | :sg:`samples(Sound) -> array` + + Creates a new array that directly references the samples in a Sound object. + Modifying the array will change the Sound. The array will always be in the + format returned from ``pygame.mixer.get_init()``. + + .. ## pygame.sndarray.samples ## + +.. function:: make_sound + + | :sl:`convert an array into a Sound object` + | :sg:`make_sound(array) -> Sound` + + Create a new playable Sound object from an array. The mixer module must be + initialized and the array format must be similar to the mixer audio format. + + .. ## pygame.sndarray.make_sound ## + +.. function:: use_arraytype + + | :sl:`Sets the array system to be used for sound arrays` + | :sg:`use_arraytype (arraytype) -> None` + + DEPRECATED: Uses the requested array type for the module functions. The + only supported arraytype is ``'numpy'``. Other values will raise ValueError. + Using this function will raise a ``DeprecationWarning``. + .. ## pygame.sndarray.use_arraytype ## + +.. function:: get_arraytype + + | :sl:`Gets the currently active array type.` + | :sg:`get_arraytype () -> str` + + DEPRECATED: Returns the currently active array type. This will be a value of the + ``get_arraytypes()`` tuple and indicates which type of array module is used + for the array creation. Using this function will raise a ``DeprecationWarning``. + + .. versionadded:: 1.8 + + .. ## pygame.sndarray.get_arraytype ## + +.. function:: get_arraytypes + + | :sl:`Gets the array system types currently supported.` + | :sg:`get_arraytypes () -> tuple` + + DEPRECATED: Checks, which array systems are available and returns them as a tuple of + strings. The values of the tuple can be used directly in the + :func:`pygame.sndarray.use_arraytype` () method. If no supported array + system could be found, None will be returned. Using this function will raise a + ``DeprecationWarning``. + + .. versionadded:: 1.8 + + .. ## pygame.sndarray.get_arraytypes ## + +.. ## pygame.sndarray ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/sprite.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/sprite.rst.txt new file mode 100644 index 0000000..e5b8cf8 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/sprite.rst.txt @@ -0,0 +1,879 @@ +.. include:: common.txt + +:mod:`pygame.sprite` +==================== + +.. module:: pygame.sprite + :synopsis: pygame module with basic game object classes + +| :sl:`pygame module with basic game object classes` + +This module contains several simple classes to be used within games. There is +the main Sprite class and several Group classes that contain Sprites. The use +of these classes is entirely optional when using pygame. The classes are fairly +lightweight and only provide a starting place for the code that is common to +most games. + +The Sprite class is intended to be used as a base class for the different types +of objects in the game. There is also a base Group class that simply stores +sprites. A game could create new types of Group classes that operate on +specially customized Sprite instances they contain. + +The basic Sprite class can draw the Sprites it contains to a Surface. The +``Group.draw()`` method requires that each Sprite have a ``Surface.image`` +attribute and a ``Surface.rect``. The ``Group.clear()`` method requires these +same attributes, and can be used to erase all the Sprites with background. +There are also more advanced Groups: ``pygame.sprite.RenderUpdates()`` and +``pygame.sprite.OrderedUpdates()``. + +Lastly, this module contains several collision functions. These help find +sprites inside multiple groups that have intersecting bounding rectangles. To +find the collisions, the Sprites are required to have a ``Surface.rect`` +attribute assigned. + +The groups are designed for high efficiency in removing and adding Sprites to +them. They also allow cheap testing to see if a Sprite already exists in a +Group. A given Sprite can exist in any number of groups. A game could use some +groups to control object rendering, and a completely separate set of groups to +control interaction or player movement. Instead of adding type attributes or +bools to a derived Sprite class, consider keeping the Sprites inside organized +Groups. This will allow for easier lookup later in the game. + +Sprites and Groups manage their relationships with the ``add()`` and +``remove()`` methods. These methods can accept a single or multiple targets for +membership. The default initializers for these classes also takes a single or +list of targets for initial membership. It is safe to repeatedly add and remove +the same Sprite from a Group. + +While it is possible to design sprite and group classes that don't derive from +the Sprite and AbstractGroup classes below, it is strongly recommended that you +extend those when you add a Sprite or Group class. + +Sprites are not thread safe. So lock them yourself if using threads. + +.. class:: Sprite + + | :sl:`Simple base class for visible game objects.` + | :sg:`Sprite(*groups) -> Sprite` + + The base class for visible game objects. Derived classes will want to + override the ``Sprite.update()`` and assign a ``Sprite.image`` and + ``Sprite.rect`` attributes. The initializer can accept any number of Group + instances to be added to. + + When subclassing the Sprite, be sure to call the base initializer before + adding the Sprite to Groups. For example: + + .. code-block:: python + + class Block(pygame.sprite.Sprite): + + # Constructor. Pass in the color of the block, + # and its x and y position + def __init__(self, color, width, height): + # Call the parent class (Sprite) constructor + pygame.sprite.Sprite.__init__(self) + + # Create an image of the block, and fill it with a color. + # This could also be an image loaded from the disk. + self.image = pygame.Surface([width, height]) + self.image.fill(color) + + # Fetch the rectangle object that has the dimensions of the image + # Update the position of this object by setting the values of rect.x and rect.y + self.rect = self.image.get_rect() + + .. method:: update + + | :sl:`method to control sprite behavior` + | :sg:`update(*args, **kwargs) -> None` + + The default implementation of this method does nothing; it's just a + convenient "hook" that you can override. This method is called by + ``Group.update()`` with whatever arguments you give it. + + There is no need to use this method if not using the convenience method + by the same name in the Group class. + + .. ## Sprite.update ## + + .. method:: add + + | :sl:`add the sprite to groups` + | :sg:`add(*groups) -> None` + + Any number of Group instances can be passed as arguments. The Sprite will + be added to the Groups it is not already a member of. + + .. ## Sprite.add ## + + .. method:: remove + + | :sl:`remove the sprite from groups` + | :sg:`remove(*groups) -> None` + + Any number of Group instances can be passed as arguments. The Sprite will + be removed from the Groups it is currently a member of. + + .. ## Sprite.remove ## + + .. method:: kill + + | :sl:`remove the Sprite from all Groups` + | :sg:`kill() -> None` + + The Sprite is removed from all the Groups that contain it. This won't + change anything about the state of the Sprite. It is possible to continue + to use the Sprite after this method has been called, including adding it + to Groups. + + .. ## Sprite.kill ## + + .. method:: alive + + | :sl:`does the sprite belong to any groups` + | :sg:`alive() -> bool` + + Returns True when the Sprite belongs to one or more Groups. + + .. ## Sprite.alive ## + + .. method:: groups + + | :sl:`list of Groups that contain this Sprite` + | :sg:`groups() -> group_list` + + Return a list of all the Groups that contain this Sprite. + + .. ## Sprite.groups ## + + .. ## pygame.sprite.Sprite ## + +.. class:: DirtySprite + + | :sl:`A subclass of Sprite with more attributes and features.` + | :sg:`DirtySprite(*groups) -> DirtySprite` + + Extra DirtySprite attributes with their default values: + + dirty = 1 + + :: + + if set to 1, it is repainted and then set to 0 again + if set to 2 then it is always dirty ( repainted each frame, + flag is not reset) + 0 means that it is not dirty and therefore not repainted again + + blendmode = 0 + + :: + + its the special_flags argument of blit, blendmodes + + source_rect = None + + :: + + source rect to use, remember that it is relative to + topleft (0,0) of self.image + + visible = 1 + + :: + + normally 1, if set to 0 it will not be repainted + (you must set it dirty too to be erased from screen) + + layer = 0 + + :: + + (READONLY value, it is read when adding it to the + LayeredDirty, for details see doc of LayeredDirty) + + .. ## ## + + .. ## pygame.sprite.DirtySprite ## + +.. class:: Group + + | :sl:`A container class to hold and manage multiple Sprite objects.` + | :sg:`Group(*sprites) -> Group` + + A simple container for Sprite objects. This class can be inherited to create + containers with more specific behaviors. The constructor takes any number of + Sprite arguments to add to the Group. The group supports the following + standard Python operations: + + :: + + in test if a Sprite is contained + len the number of Sprites contained + bool test if any Sprites are contained + iter iterate through all the Sprites + + The Sprites in the Group are ordered only on python 3.6 and higher. + Below python 3.6 drawing and iterating over the Sprites is in no particular order. + + .. method:: sprites + + | :sl:`list of the Sprites this Group contains` + | :sg:`sprites() -> sprite_list` + + Return a list of all the Sprites this group contains. You can also get an + iterator from the group, but you cannot iterate over a Group while + modifying it. + + .. ## Group.sprites ## + + .. method:: copy + + | :sl:`duplicate the Group` + | :sg:`copy() -> Group` + + Creates a new Group with all the same Sprites as the original. If you + have subclassed Group, the new object will have the same (sub-)class as + the original. This only works if the derived class's constructor takes + the same arguments as the Group class's. + + .. ## Group.copy ## + + .. method:: add + + | :sl:`add Sprites to this Group` + | :sg:`add(*sprites) -> None` + + Add any number of Sprites to this Group. This will only add Sprites that + are not already members of the Group. + + Each sprite argument can also be a iterator containing Sprites. + + .. ## Group.add ## + + .. method:: remove + + | :sl:`remove Sprites from the Group` + | :sg:`remove(*sprites) -> None` + + Remove any number of Sprites from the Group. This will only remove + Sprites that are already members of the Group. + + Each sprite argument can also be a iterator containing Sprites. + + .. ## Group.remove ## + + .. method:: has + + | :sl:`test if a Group contains Sprites` + | :sg:`has(*sprites) -> bool` + + Return True if the Group contains all of the given sprites. This is + similar to using the "in" operator on the Group ("if sprite in group: + ..."), which tests if a single Sprite belongs to a Group. + + Each sprite argument can also be a iterator containing Sprites. + + .. ## Group.has ## + + .. method:: update + + | :sl:`call the update method on contained Sprites` + | :sg:`update(*args, **kwargs) -> None` + + Calls the ``update()`` method on all Sprites in the Group. The base + Sprite class has an update method that takes any number of arguments and + does nothing. The arguments passed to ``Group.update()`` will be passed + to each Sprite. + + There is no way to get the return value from the ``Sprite.update()`` + methods. + + .. ## Group.update ## + + .. method:: draw + + | :sl:`blit the Sprite images` + | :sg:`draw(Surface) -> List[Rect]` + + Draws the contained Sprites to the Surface argument. This uses the + ``Sprite.image`` attribute for the source surface, and ``Sprite.rect`` + for the position. + + The Group does not keep sprites in any order, so the draw order is + arbitrary. + + .. ## Group.draw ## + + .. method:: clear + + | :sl:`draw a background over the Sprites` + | :sg:`clear(Surface_dest, background) -> None` + + Erases the Sprites used in the last ``Group.draw()`` call. The + destination Surface is cleared by filling the drawn Sprite positions with + the background. + + The background is usually a Surface image the same dimensions as the + destination Surface. However, it can also be a callback function that + takes two arguments; the destination Surface and an area to clear. The + background callback function will be called several times each clear. + + Here is an example callback that will clear the Sprites with solid red: + + :: + + def clear_callback(surf, rect): + color = 255, 0, 0 + surf.fill(color, rect) + + .. ## Group.clear ## + + .. method:: empty + + | :sl:`remove all Sprites` + | :sg:`empty() -> None` + + Removes all Sprites from this Group. + + .. ## Group.empty ## + + .. ## pygame.sprite.Group ## + +.. class:: RenderPlain + + | :sl:`Same as pygame.sprite.Group` + + This class is an alias to ``pygame.sprite.Group()``. It has no additional functionality. + + .. ## pygame.sprite.RenderClear ## + +.. class:: RenderClear + + | :sl:`Same as pygame.sprite.Group` + + This class is an alias to ``pygame.sprite.Group()``. It has no additional functionality. + + .. ## pygame.sprite.RenderClear ## + +.. class:: RenderUpdates + + | :sl:`Group sub-class that tracks dirty updates.` + | :sg:`RenderUpdates(*sprites) -> RenderUpdates` + + This class is derived from ``pygame.sprite.Group()``. It has an extended + ``draw()`` method that tracks the changed areas of the screen. + + .. method:: draw + + | :sl:`blit the Sprite images and track changed areas` + | :sg:`draw(surface) -> Rect_list` + + Draws all the Sprites to the surface, the same as ``Group.draw()``. This + method also returns a list of Rectangular areas on the screen that have + been changed. The returned changes include areas of the screen that have + been affected by previous ``Group.clear()`` calls. + + The returned Rect list should be passed to ``pygame.display.update()``. + This will help performance on software driven display modes. This type of + updating is usually only helpful on destinations with non-animating + backgrounds. + + .. ## RenderUpdates.draw ## + + .. ## pygame.sprite.RenderUpdates ## + +.. function:: OrderedUpdates + + | :sl:`RenderUpdates sub-class that draws Sprites in order of addition.` + | :sg:`OrderedUpdates(*spites) -> OrderedUpdates` + + This class derives from ``pygame.sprite.RenderUpdates()``. It maintains the + order in which the Sprites were added to the Group for rendering. This makes + adding and removing Sprites from the Group a little slower than regular + Groups. + + .. ## pygame.sprite.OrderedUpdates ## + +.. class:: LayeredUpdates + + | :sl:`LayeredUpdates is a sprite group that handles layers and draws like OrderedUpdates.` + | :sg:`LayeredUpdates(*spites, **kwargs) -> LayeredUpdates` + + This group is fully compatible with :class:`pygame.sprite.Sprite`. + + You can set the default layer through kwargs using 'default_layer' and an + integer for the layer. The default layer is 0. + + If the sprite you add has an attribute _layer then that layer will be used. + If the \**kwarg contains 'layer' then the sprites passed will be added to + that layer (overriding the ``sprite.layer`` attribute). If neither sprite + has attribute layer nor \**kwarg then the default layer is used to add the + sprites. + + .. versionadded:: 1.8 + + .. method:: add + + | :sl:`add a sprite or sequence of sprites to a group` + | :sg:`add(*sprites, **kwargs) -> None` + + If the ``sprite(s)`` have an attribute layer then that is used for the + layer. If \**kwargs contains 'layer' then the ``sprite(s)`` will be added + to that argument (overriding the sprite layer attribute). If neither is + passed then the ``sprite(s)`` will be added to the default layer. + + .. ## LayeredUpdates.add ## + + .. method:: sprites + + | :sl:`returns a ordered list of sprites (first back, last top).` + | :sg:`sprites() -> sprites` + + .. ## LayeredUpdates.sprites ## + + .. method:: draw + + | :sl:`draw all sprites in the right order onto the passed surface.` + | :sg:`draw(surface) -> Rect_list` + + .. ## LayeredUpdates.draw ## + + .. method:: get_sprites_at + + | :sl:`returns a list with all sprites at that position.` + | :sg:`get_sprites_at(pos) -> colliding_sprites` + + Bottom sprites first, top last. + + .. ## LayeredUpdates.get_sprites_at ## + + .. method:: get_sprite + + | :sl:`returns the sprite at the index idx from the groups sprites` + | :sg:`get_sprite(idx) -> sprite` + + Raises IndexOutOfBounds if the idx is not within range. + + .. ## LayeredUpdates.get_sprite ## + + .. method:: remove_sprites_of_layer + + | :sl:`removes all sprites from a layer and returns them as a list.` + | :sg:`remove_sprites_of_layer(layer_nr) -> sprites` + + .. ## LayeredUpdates.remove_sprites_of_layer ## + + .. method:: layers + + | :sl:`returns a list of layers defined (unique), sorted from bottom up.` + | :sg:`layers() -> layers` + + .. ## LayeredUpdates.layers ## + + .. method:: change_layer + + | :sl:`changes the layer of the sprite` + | :sg:`change_layer(sprite, new_layer) -> None` + + sprite must have been added to the renderer. It is not checked. + + .. ## LayeredUpdates.change_layer ## + + .. method:: get_layer_of_sprite + + | :sl:`returns the layer that sprite is currently in.` + | :sg:`get_layer_of_sprite(sprite) -> layer` + + If the sprite is not found then it will return the default layer. + + .. ## LayeredUpdates.get_layer_of_sprite ## + + .. method:: get_top_layer + + | :sl:`returns the top layer` + | :sg:`get_top_layer() -> layer` + + .. ## LayeredUpdates.get_top_layer ## + + .. method:: get_bottom_layer + + | :sl:`returns the bottom layer` + | :sg:`get_bottom_layer() -> layer` + + .. ## LayeredUpdates.get_bottom_layer ## + + .. method:: move_to_front + + | :sl:`brings the sprite to front layer` + | :sg:`move_to_front(sprite) -> None` + + Brings the sprite to front, changing sprite layer to topmost layer (added + at the end of that layer). + + .. ## LayeredUpdates.move_to_front ## + + .. method:: move_to_back + + | :sl:`moves the sprite to the bottom layer` + | :sg:`move_to_back(sprite) -> None` + + Moves the sprite to the bottom layer, moving it behind all other layers + and adding one additional layer. + + .. ## LayeredUpdates.move_to_back ## + + .. method:: get_top_sprite + + | :sl:`returns the topmost sprite` + | :sg:`get_top_sprite() -> Sprite` + + .. ## LayeredUpdates.get_top_sprite ## + + .. method:: get_sprites_from_layer + + | :sl:`returns all sprites from a layer, ordered by how they where added` + | :sg:`get_sprites_from_layer(layer) -> sprites` + + Returns all sprites from a layer, ordered by how they where added. It + uses linear search and the sprites are not removed from layer. + + .. ## LayeredUpdates.get_sprites_from_layer ## + + .. method:: switch_layer + + | :sl:`switches the sprites from layer1 to layer2` + | :sg:`switch_layer(layer1_nr, layer2_nr) -> None` + + The layers number must exist, it is not checked. + + .. ## LayeredUpdates.switch_layer ## + + .. ## pygame.sprite.LayeredUpdates ## + +.. class:: LayeredDirty + + | :sl:`LayeredDirty group is for DirtySprite objects. Subclasses LayeredUpdates.` + | :sg:`LayeredDirty(*spites, **kwargs) -> LayeredDirty` + + This group requires :class:`pygame.sprite.DirtySprite` or any sprite that + has the following attributes: + + :: + + image, rect, dirty, visible, blendmode (see doc of DirtySprite). + + It uses the dirty flag technique and is therefore faster than the + :class:`pygame.sprite.RenderUpdates` if you have many static sprites. It + also switches automatically between dirty rect update and full screen + drawing, so you do not have to worry what would be faster. + + Same as for the :class:`pygame.sprite.Group`. You can specify some + additional attributes through kwargs: + + :: + + _use_update: True/False default is False + _default_layer: default layer where sprites without a layer are added. + _time_threshold: threshold time for switching between dirty rect mode + and fullscreen mode, defaults to 1000./80 == 1000./fps + + .. versionadded:: 1.8 + + .. method:: draw + + | :sl:`draw all sprites in the right order onto the passed surface.` + | :sg:`draw(surface, bgd=None) -> Rect_list` + + You can pass the background too. If a background is already set, then the + bgd argument has no effect. + + .. ## LayeredDirty.draw ## + + .. method:: clear + + | :sl:`used to set background` + | :sg:`clear(surface, bgd) -> None` + + .. ## LayeredDirty.clear ## + + .. method:: repaint_rect + + | :sl:`repaints the given area` + | :sg:`repaint_rect(screen_rect) -> None` + + screen_rect is in screen coordinates. + + .. ## LayeredDirty.repaint_rect ## + + .. method:: set_clip + + | :sl:`clip the area where to draw. Just pass None (default) to reset the clip` + | :sg:`set_clip(screen_rect=None) -> None` + + .. ## LayeredDirty.set_clip ## + + .. method:: get_clip + + | :sl:`clip the area where to draw. Just pass None (default) to reset the clip` + | :sg:`get_clip() -> Rect` + + .. ## LayeredDirty.get_clip ## + + .. method:: change_layer + + | :sl:`changes the layer of the sprite` + | :sg:`change_layer(sprite, new_layer) -> None` + + sprite must have been added to the renderer. It is not checked. + + .. ## LayeredDirty.change_layer ## + + .. method:: set_timing_treshold + + | :sl:`sets the threshold in milliseconds` + | :sg:`set_timing_treshold(time_ms) -> None` + + DEPRECATED: Use set_timing_threshold() instead. + + .. deprecated:: 2.1.1 + + .. ## LayeredDirty.set_timing_treshold ## + + .. method:: set_timing_threshold + + | :sl:`sets the threshold in milliseconds` + | :sg:`set_timing_threshold(time_ms) -> None` + + Defaults to 1000.0 / 80.0. This means that the screen will be painted + using the flip method rather than the update method if the update + method is taking so long to update the screen that the frame rate falls + below 80 frames per second. + + .. versionadded:: 2.1.1 + + :raises TypeError: if ``time_ms`` is not int or float + + .. ## LayeredDirty.set_timing_threshold ## + + .. ## pygame.sprite.LayeredDirty ## + +.. function:: GroupSingle + + | :sl:`Group container that holds a single sprite.` + | :sg:`GroupSingle(sprite=None) -> GroupSingle` + + The GroupSingle container only holds a single Sprite. When a new Sprite is + added, the old one is removed. + + There is a special property, ``GroupSingle.sprite``, that accesses the + Sprite that this Group contains. It can be None when the Group is empty. The + property can also be assigned to add a Sprite into the GroupSingle + container. + + .. ## pygame.sprite.GroupSingle ## + +.. function:: spritecollide + + | :sl:`Find sprites in a group that intersect another sprite.` + | :sg:`spritecollide(sprite, group, dokill, collided = None) -> Sprite_list` + + Return a list containing all Sprites in a Group that intersect with another + Sprite. Intersection is determined by comparing the ``Sprite.rect`` + attribute of each Sprite. + + The dokill argument is a bool. If set to True, all Sprites that collide will + be removed from the Group. + + The collided argument is a callback function used to calculate if two + sprites are colliding. it should take two sprites as values, and return a + bool value indicating if they are colliding. If collided is not passed, all + sprites must have a "rect" value, which is a rectangle of the sprite area, + which will be used to calculate the collision. + + collided callables: + + :: + + collide_rect, collide_rect_ratio, collide_circle, + collide_circle_ratio, collide_mask + + Example: + + .. code-block:: python + + # See if the Sprite block has collided with anything in the Group block_list + # The True flag will remove the sprite in block_list + blocks_hit_list = pygame.sprite.spritecollide(player, block_list, True) + + # Check the list of colliding sprites, and add one to the score for each one + for block in blocks_hit_list: + score +=1 + + .. ## pygame.sprite.spritecollide ## + +.. function:: collide_rect + + | :sl:`Collision detection between two sprites, using rects.` + | :sg:`collide_rect(left, right) -> bool` + + Tests for collision between two sprites. Uses the pygame rect colliderect + function to calculate the collision. Intended to be passed as a collided + callback function to the \*collide functions. Sprites must have a "rect" + attributes. + + .. versionadded:: 1.8 + + .. ## pygame.sprite.collide_rect ## + +.. function:: collide_rect_ratio + + | :sl:`Collision detection between two sprites, using rects scaled to a ratio.` + | :sg:`collide_rect_ratio(ratio) -> collided_callable` + + A callable class that checks for collisions between two sprites, using a + scaled version of the sprites rects. + + Is created with a ratio, the instance is then intended to be passed as a + collided callback function to the \*collide functions. + + A ratio is a floating point number - 1.0 is the same size, 2.0 is twice as + big, and 0.5 is half the size. + + .. versionadded:: 1.8.1 + + .. ## pygame.sprite.collide_rect_ratio ## + +.. function:: collide_circle + + | :sl:`Collision detection between two sprites, using circles.` + | :sg:`collide_circle(left, right) -> bool` + + Tests for collision between two sprites, by testing to see if two circles + centered on the sprites overlap. If the sprites have a "radius" attribute, + that is used to create the circle, otherwise a circle is created that is big + enough to completely enclose the sprites rect as given by the "rect" + attribute. Intended to be passed as a collided callback function to the + \*collide functions. Sprites must have a "rect" and an optional "radius" + attribute. + + .. versionadded:: 1.8.1 + + .. ## pygame.sprite.collide_circle ## + +.. function:: collide_circle_ratio + + | :sl:`Collision detection between two sprites, using circles scaled to a ratio.` + | :sg:`collide_circle_ratio(ratio) -> collided_callable` + + A callable class that checks for collisions between two sprites, using a + scaled version of the sprites radius. + + Is created with a floating point ratio, the instance is then intended to be + passed as a collided callback function to the \*collide functions. + + A ratio is a floating point number - 1.0 is the same size, 2.0 is twice as + big, and 0.5 is half the size. + + The created callable tests for collision between two sprites, by testing to + see if two circles centered on the sprites overlap, after scaling the + circles radius by the stored ratio. If the sprites have a "radius" + attribute, that is used to create the circle, otherwise a circle is created + that is big enough to completely enclose the sprites rect as given by the + "rect" attribute. Intended to be passed as a collided callback function to + the \*collide functions. Sprites must have a "rect" and an optional "radius" + attribute. + + .. versionadded:: 1.8.1 + + .. ## pygame.sprite.collide_circle_ratio ## + +.. function:: collide_mask + + | :sl:`Collision detection between two sprites, using masks.` + | :sg:`collide_mask(sprite1, sprite2) -> (int, int)` + | :sg:`collide_mask(sprite1, sprite2) -> None` + + Tests for collision between two sprites, by testing if their bitmasks + overlap (uses :func:`pygame.mask.Mask.overlap`). If the sprites have a + ``mask`` attribute, it is used as the mask, otherwise a mask is created from + the sprite's ``image`` (uses :func:`pygame.mask.from_surface`). Sprites must + have a ``rect`` attribute; the ``mask`` attribute is optional. + + The first point of collision between the masks is returned. The collision + point is offset from ``sprite1``'s mask's topleft corner (which is always + (0, 0)). The collision point is a position within the mask and is not + related to the actual screen position of ``sprite1``. + + This function is intended to be passed as a ``collided`` callback function + to the group collide functions (see :meth:`spritecollide`, + :meth:`groupcollide`, :meth:`spritecollideany`). + + .. note:: + To increase performance, create and set a ``mask`` attibute for all + sprites that will use this function to check for collisions. Otherwise, + each time this function is called it will create new masks. + + .. note:: + A new mask needs to be recreated each time a sprite's image is changed + (e.g. if a new image is used or the existing image is rotated). + + :: + + # Example of mask creation for a sprite. + sprite.mask = pygame.mask.from_surface(sprite.image) + + :returns: first point of collision between the masks or ``None`` if no + collision + :rtype: tuple(int, int) or NoneType + + .. versionadded:: 1.8.0 + + .. ## pygame.sprite.collide_mask ## + +.. function:: groupcollide + + | :sl:`Find all sprites that collide between two groups.` + | :sg:`groupcollide(group1, group2, dokill1, dokill2, collided = None) -> Sprite_dict` + + This will find collisions between all the Sprites in two groups. + Collision is determined by comparing the ``Sprite.rect`` attribute of + each Sprite or by using the collided function if it is not None. + + Every Sprite inside group1 is added to the return dictionary. The value for + each item is the list of Sprites in group2 that intersect. + + If either dokill argument is True, the colliding Sprites will be removed + from their respective Group. + + The collided argument is a callback function used to calculate if two sprites are + colliding. It should take two sprites as values and return a bool value + indicating if they are colliding. If collided is not passed, then all + sprites must have a "rect" value, which is a rectangle of the sprite area, + which will be used to calculate the collision. + + .. ## pygame.sprite.groupcollide ## + +.. function:: spritecollideany + + | :sl:`Simple test if a sprite intersects anything in a group.` + | :sg:`spritecollideany(sprite, group, collided = None) -> Sprite` Collision with the returned sprite. + | :sg:`spritecollideany(sprite, group, collided = None) -> None` No collision + + If the sprite collides with any single sprite in the group, a single + sprite from the group is returned. On no collision None is returned. + + If you don't need all the features of the ``pygame.sprite.spritecollide()`` function, this + function will be a bit quicker. + + The collided argument is a callback function used to calculate if two sprites are + colliding. It should take two sprites as values and return a bool value + indicating if they are colliding. If collided is not passed, then all + sprites must have a "rect" value, which is a rectangle of the sprite area, + which will be used to calculate the collision. + + .. ## pygame.sprite.spritecollideany ## + +.. ## ## + +.. ## pygame.sprite ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/surface.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/surface.rst.txt new file mode 100644 index 0000000..4ed77a6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/surface.rst.txt @@ -0,0 +1,902 @@ +.. include:: common.txt + +:mod:`pygame.Surface` +===================== + +.. currentmodule:: pygame + +.. class:: Surface + + | :sl:`pygame object for representing images` + | :sg:`Surface((width, height), flags=0, depth=0, masks=None) -> Surface` + | :sg:`Surface((width, height), flags=0, Surface) -> Surface` + + A pygame Surface is used to represent any image. The Surface has a fixed + resolution and pixel format. Surfaces with 8-bit pixels use a color palette + to map to 24-bit color. + + Call :meth:`pygame.Surface()` to create a new image object. The Surface will + be cleared to all black. The only required arguments are the sizes. With no + additional arguments, the Surface will be created in a format that best + matches the display Surface. + + The pixel format can be controlled by passing the bit depth or an existing + Surface. The flags argument is a bitmask of additional features for the + surface. You can pass any combination of these flags: + + :: + + HWSURFACE (obsolete in pygame 2) creates the image in video memory + SRCALPHA the pixel format will include a per-pixel alpha + + Both flags are only a request, and may not be possible for all displays and + formats. + + Advance users can combine a set of bitmasks with a depth value. The masks + are a set of 4 integers representing which bits in a pixel will represent + each color. Normal Surfaces should not require the masks argument. + + Surfaces can have many extra attributes like alpha planes, colorkeys, source + rectangle clipping. These functions mainly effect how the Surface is blitted + to other Surfaces. The blit routines will attempt to use hardware + acceleration when possible, otherwise they will use highly optimized + software blitting methods. + + There are three types of transparency supported in pygame: colorkeys, + surface alphas, and pixel alphas. Surface alphas can be mixed with + colorkeys, but an image with per pixel alphas cannot use the other modes. + Colorkey transparency makes a single color value transparent. Any pixels + matching the colorkey will not be drawn. The surface alpha value is a single + value that changes the transparency for the entire image. A surface alpha of + 255 is opaque, and a value of 0 is completely transparent. + + Per pixel alphas are different because they store a transparency value for + every pixel. This allows for the most precise transparency effects, but it + also the slowest. Per pixel alphas cannot be mixed with surface alpha and + colorkeys. + + There is support for pixel access for the Surfaces. Pixel access on hardware + surfaces is slow and not recommended. Pixels can be accessed using the + :meth:`get_at()` and :meth:`set_at()` functions. These methods are fine for + simple access, but will be considerably slow when doing of pixel work with + them. If you plan on doing a lot of pixel level work, it is recommended to + use a :class:`pygame.PixelArray`, which gives an array like view of the + surface. For involved mathematical manipulations try the + :mod:`pygame.surfarray` module (It's quite quick, but requires NumPy.) + + Any functions that directly access a surface's pixel data will need that + surface to be lock()'ed. These functions can :meth:`lock()` and + :meth:`unlock()` the surfaces themselves without assistance. But, if a + function will be called many times, there will be a lot of overhead for + multiple locking and unlocking of the surface. It is best to lock the + surface manually before making the function call many times, and then + unlocking when you are finished. All functions that need a locked surface + will say so in their docs. Remember to leave the Surface locked only while + necessary. + + Surface pixels are stored internally as a single number that has all the + colors encoded into it. Use the :meth:`map_rgb()` and + :meth:`unmap_rgb()` to convert between individual red, green, and blue + values into a packed integer for that Surface. + + Surfaces can also reference sections of other Surfaces. These are created + with the :meth:`subsurface()` method. Any change to either Surface will + effect the other. + + Each Surface contains a clipping area. By default the clip area covers the + entire Surface. If it is changed, all drawing operations will only effect + the smaller area. + + .. method:: blit + + | :sl:`draw one image onto another` + | :sg:`blit(source, dest, area=None, special_flags=0) -> Rect` + + Draws a source Surface onto this Surface. The draw can be positioned with + the dest argument. The dest argument can either be a pair of coordinates representing the position of + the upper left corner of the blit or a Rect, where the upper left corner of the rectangle will be used as the + position for the blit. The size of the destination rectangle does not + effect the blit. + + An optional area rectangle can be passed as well. This represents a + smaller portion of the source Surface to draw. + + .. versionadded:: 1.8 + Optional ``special_flags``: ``BLEND_ADD``, ``BLEND_SUB``, + ``BLEND_MULT``, ``BLEND_MIN``, ``BLEND_MAX``. + + .. versionadded:: 1.8.1 + Optional ``special_flags``: ``BLEND_RGBA_ADD``, ``BLEND_RGBA_SUB``, + ``BLEND_RGBA_MULT``, ``BLEND_RGBA_MIN``, ``BLEND_RGBA_MAX`` + ``BLEND_RGB_ADD``, ``BLEND_RGB_SUB``, ``BLEND_RGB_MULT``, + ``BLEND_RGB_MIN``, ``BLEND_RGB_MAX``. + + .. versionadded:: 1.9.2 + Optional ``special_flags``: ``BLEND_PREMULTIPLIED`` + + .. versionadded:: 2.0.0 + Optional ``special_flags``: ``BLEND_ALPHA_SDL2`` - Uses the SDL2 blitter for alpha blending, + this gives different results than the default blitter, which is modelled after SDL1, due to + different approximations used for the alpha blending formula. The SDL2 blitter also supports + RLE on alpha blended surfaces which the pygame one does not. + + The return rectangle is the area of the affected pixels, excluding any + pixels outside the destination Surface, or outside the clipping area. + + Pixel alphas will be ignored when blitting to an 8 bit Surface. + + For a surface with colorkey or blanket alpha, a blit to self may give + slightly different colors than a non self-blit. + + .. ## Surface.blit ## + + .. method:: blits + + | :sl:`draw many images onto another` + | :sg:`blits(blit_sequence=((source, dest), ...), doreturn=1) -> [Rect, ...] or None` + | :sg:`blits(((source, dest, area), ...)) -> [Rect, ...]` + | :sg:`blits(((source, dest, area, special_flags), ...)) -> [Rect, ...]` + + Draws many surfaces onto this Surface. It takes a sequence as input, + with each of the elements corresponding to the ones of :meth:`blit()`. + It needs at minimum a sequence of (source, dest). + + :param blit_sequence: a sequence of surfaces and arguments to blit them, + they correspond to the :meth:`blit()` arguments + :param doreturn: if ``True``, return a list of rects of the areas changed, + otherwise return ``None`` + + :returns: a list of rects of the areas changed if ``doreturn`` is + ``True``, otherwise ``None`` + :rtype: list or None + + New in pygame 1.9.4. + + .. ## Surface.blits ## + + + .. method:: convert + + | :sl:`change the pixel format of an image` + | :sg:`convert(Surface=None) -> Surface` + | :sg:`convert(depth, flags=0) -> Surface` + | :sg:`convert(masks, flags=0) -> Surface` + + Creates a new copy of the Surface with the pixel format changed. The new + pixel format can be determined from another existing Surface. Otherwise + depth, flags, and masks arguments can be used, similar to the + :meth:`pygame.Surface()` call. + + If no arguments are passed the new Surface will have the same pixel + format as the display Surface. This is always the fastest format for + blitting. It is a good idea to convert all Surfaces before they are + blitted many times. + + The converted Surface will have no pixel alphas. They will be stripped if + the original had them. See :meth:`convert_alpha()` for preserving or + creating per-pixel alphas. + + The new copy will have the same class as the copied surface. This lets + as Surface subclass inherit this method without the need to override, + unless subclass specific instance attributes also need copying. + + .. ## Surface.convert ## + + .. method:: convert_alpha + + | :sl:`change the pixel format of an image including per pixel alphas` + | :sg:`convert_alpha(Surface) -> Surface` + | :sg:`convert_alpha() -> Surface` + + Creates a new copy of the surface with the desired pixel format. The new + surface will be in a format suited for quick blitting to the given format + with per pixel alpha. If no surface is given, the new surface will be + optimized for blitting to the current display. + + Unlike the :meth:`convert()` method, the pixel format for the new + image will not be exactly the same as the requested source, but it will + be optimized for fast alpha blitting to the destination. + + As with :meth:`convert()` the returned surface has the same class as + the converted surface. + + .. ## Surface.convert_alpha ## + + .. method:: copy + + | :sl:`create a new copy of a Surface` + | :sg:`copy() -> Surface` + + Makes a duplicate copy of a Surface. The new surface will have the same + pixel formats, color palettes, transparency settings, and class as the + original. If a Surface subclass also needs to copy any instance specific + attributes then it should override ``copy()``. + + .. ## Surface.copy ## + + .. method:: fill + + | :sl:`fill Surface with a solid color` + | :sg:`fill(color, rect=None, special_flags=0) -> Rect` + + Fill the Surface with a solid color. If no rect argument is given the + entire Surface will be filled. The rect argument will limit the fill to a + specific area. The fill will also be contained by the Surface clip area. + + The color argument can be either a ``RGB`` sequence, a ``RGBA`` sequence + or a mapped color index. If using ``RGBA``, the Alpha (A part of + ``RGBA``) is ignored unless the surface uses per pixel alpha (Surface has + the ``SRCALPHA`` flag). + + .. versionadded:: 1.8 + Optional ``special_flags``: ``BLEND_ADD``, ``BLEND_SUB``, + ``BLEND_MULT``, ``BLEND_MIN``, ``BLEND_MAX``. + + .. versionadded:: 1.8.1 + Optional ``special_flags``: ``BLEND_RGBA_ADD``, ``BLEND_RGBA_SUB``, + ``BLEND_RGBA_MULT``, ``BLEND_RGBA_MIN``, ``BLEND_RGBA_MAX`` + ``BLEND_RGB_ADD``, ``BLEND_RGB_SUB``, ``BLEND_RGB_MULT``, + ``BLEND_RGB_MIN``, ``BLEND_RGB_MAX``. + + This will return the affected Surface area. + + .. ## Surface.fill ## + + .. method:: scroll + + | :sl:`Shift the surface image in place` + | :sg:`scroll(dx=0, dy=0) -> None` + + Move the image by dx pixels right and dy pixels down. dx and dy may be + negative for left and up scrolls respectively. Areas of the surface that + are not overwritten retain their original pixel values. Scrolling is + contained by the Surface clip area. It is safe to have dx and dy values + that exceed the surface size. + + .. versionadded:: 1.9 + + .. ## Surface.scroll ## + + .. method:: set_colorkey + + | :sl:`Set the transparent colorkey` + | :sg:`set_colorkey(Color, flags=0) -> None` + | :sg:`set_colorkey(None) -> None` + + Set the current color key for the Surface. When blitting this Surface + onto a destination, any pixels that have the same color as the colorkey + will be transparent. The color can be an ``RGB`` color or a mapped color + integer. If ``None`` is passed, the colorkey will be unset. + + The colorkey will be ignored if the Surface is formatted to use per pixel + alpha values. The colorkey can be mixed with the full Surface alpha + value. + + The optional flags argument can be set to ``pygame.RLEACCEL`` to provide + better performance on non accelerated displays. An ``RLEACCEL`` Surface + will be slower to modify, but quicker to blit as a source. + + .. ## Surface.set_colorkey ## + + .. method:: get_colorkey + + | :sl:`Get the current transparent colorkey` + | :sg:`get_colorkey() -> RGB or None` + + Return the current colorkey value for the Surface. If the colorkey is not + set then ``None`` is returned. + + .. ## Surface.get_colorkey ## + + .. method:: set_alpha + + | :sl:`set the alpha value for the full Surface image` + | :sg:`set_alpha(value, flags=0) -> None` + | :sg:`set_alpha(None) -> None` + + Set the current alpha value for the Surface. When blitting this Surface + onto a destination, the pixels will be drawn slightly transparent. The + alpha value is an integer from 0 to 255, 0 is fully transparent and 255 + is fully opaque. If ``None`` is passed for the alpha value, then alpha + blending will be disabled, including per-pixel alpha. + + This value is different than the per pixel Surface alpha. For a surface + with per pixel alpha, blanket alpha is ignored and ``None`` is returned. + + .. versionchanged:: 2.0 per-surface alpha can be combined with per-pixel + alpha. + + The optional flags argument can be set to ``pygame.RLEACCEL`` to provide + better performance on non accelerated displays. An ``RLEACCEL`` Surface + will be slower to modify, but quicker to blit as a source. + + .. ## Surface.set_alpha ## + + .. method:: get_alpha + + | :sl:`get the current Surface transparency value` + | :sg:`get_alpha() -> int_value` + + Return the current alpha value for the Surface. + + .. ## Surface.get_alpha ## + + .. method:: lock + + | :sl:`lock the Surface memory for pixel access` + | :sg:`lock() -> None` + + Lock the pixel data of a Surface for access. On accelerated Surfaces, the + pixel data may be stored in volatile video memory or nonlinear compressed + forms. When a Surface is locked the pixel memory becomes available to + access by regular software. Code that reads or writes pixel values will + need the Surface to be locked. + + Surfaces should not remain locked for more than necessary. A locked + Surface can often not be displayed or managed by pygame. + + Not all Surfaces require locking. The :meth:`mustlock()` method can + determine if it is actually required. There is no performance penalty for + locking and unlocking a Surface that does not need it. + + All pygame functions will automatically lock and unlock the Surface data + as needed. If a section of code is going to make calls that will + repeatedly lock and unlock the Surface many times, it can be helpful to + wrap the block inside a lock and unlock pair. + + It is safe to nest locking and unlocking calls. The surface will only be + unlocked after the final lock is released. + + .. ## Surface.lock ## + + .. method:: unlock + + | :sl:`unlock the Surface memory from pixel access` + | :sg:`unlock() -> None` + + Unlock the Surface pixel data after it has been locked. The unlocked + Surface can once again be drawn and managed by pygame. See the + :meth:`lock()` documentation for more details. + + All pygame functions will automatically lock and unlock the Surface data + as needed. If a section of code is going to make calls that will + repeatedly lock and unlock the Surface many times, it can be helpful to + wrap the block inside a lock and unlock pair. + + It is safe to nest locking and unlocking calls. The surface will only be + unlocked after the final lock is released. + + .. ## Surface.unlock ## + + .. method:: mustlock + + | :sl:`test if the Surface requires locking` + | :sg:`mustlock() -> bool` + + Returns ``True`` if the Surface is required to be locked to access pixel + data. Usually pure software Surfaces do not require locking. This method + is rarely needed, since it is safe and quickest to just lock all Surfaces + as needed. + + All pygame functions will automatically lock and unlock the Surface data + as needed. If a section of code is going to make calls that will + repeatedly lock and unlock the Surface many times, it can be helpful to + wrap the block inside a lock and unlock pair. + + .. ## Surface.mustlock ## + + .. method:: get_locked + + | :sl:`test if the Surface is current locked` + | :sg:`get_locked() -> bool` + + Returns ``True`` when the Surface is locked. It doesn't matter how many + times the Surface is locked. + + .. ## Surface.get_locked ## + + .. method:: get_locks + + | :sl:`Gets the locks for the Surface` + | :sg:`get_locks() -> tuple` + + Returns the currently existing locks for the Surface. + + .. ## Surface.get_locks ## + + .. method:: get_at + + | :sl:`get the color value at a single pixel` + | :sg:`get_at((x, y)) -> Color` + + Return a copy of the ``RGBA`` Color value at the given pixel. If the + Surface has no per pixel alpha, then the alpha value will always be 255 + (opaque). If the pixel position is outside the area of the Surface an + ``IndexError`` exception will be raised. + + Getting and setting pixels one at a time is generally too slow to be used + in a game or realtime situation. It is better to use methods which + operate on many pixels at a time like with the blit, fill and draw + methods - or by using :mod:`pygame.surfarray`/:mod:`pygame.PixelArray`. + + This function will temporarily lock and unlock the Surface as needed. + + .. versionadded:: 1.9 + Returning a Color instead of tuple. Use ``tuple(surf.get_at((x,y)))`` + if you want a tuple, and not a Color. This should only matter if + you want to use the color as a key in a dict. + + .. ## Surface.get_at ## + + .. method:: set_at + + | :sl:`set the color value for a single pixel` + | :sg:`set_at((x, y), Color) -> None` + + Set the ``RGBA`` or mapped integer color value for a single pixel. If the + Surface does not have per pixel alphas, the alpha value is ignored. + Setting pixels outside the Surface area or outside the Surface clipping + will have no effect. + + Getting and setting pixels one at a time is generally too slow to be used + in a game or realtime situation. + + This function will temporarily lock and unlock the Surface as needed. + + .. ## Surface.set_at ## + + .. method:: get_at_mapped + + | :sl:`get the mapped color value at a single pixel` + | :sg:`get_at_mapped((x, y)) -> Color` + + Return the integer value of the given pixel. If the pixel position is + outside the area of the Surface an ``IndexError`` exception will be + raised. + + This method is intended for pygame unit testing. It unlikely has any use + in an application. + + This function will temporarily lock and unlock the Surface as needed. + + .. versionadded:: 1.9.2 + + .. ## Surface.get_at_mapped ## + + .. method:: get_palette + + | :sl:`get the color index palette for an 8-bit Surface` + | :sg:`get_palette() -> [RGB, RGB, RGB, ...]` + + Return a list of up to 256 color elements that represent the indexed + colors used in an 8-bit Surface. The returned list is a copy of the + palette, and changes will have no effect on the Surface. + + Returning a list of ``Color(with length 3)`` instances instead of tuples. + + .. versionadded:: 1.9 + + .. ## Surface.get_palette ## + + .. method:: get_palette_at + + | :sl:`get the color for a single entry in a palette` + | :sg:`get_palette_at(index) -> RGB` + + Returns the red, green, and blue color values for a single index in a + Surface palette. The index should be a value from 0 to 255. + + .. versionadded:: 1.9 + Returning ``Color(with length 3)`` instance instead of a tuple. + + .. ## Surface.get_palette_at ## + + .. method:: set_palette + + | :sl:`set the color palette for an 8-bit Surface` + | :sg:`set_palette([RGB, RGB, RGB, ...]) -> None` + + Set the full palette for an 8-bit Surface. This will replace the colors in + the existing palette. A partial palette can be passed and only the first + colors in the original palette will be changed. + + This function has no effect on a Surface with more than 8-bits per pixel. + + .. ## Surface.set_palette ## + + .. method:: set_palette_at + + | :sl:`set the color for a single index in an 8-bit Surface palette` + | :sg:`set_palette_at(index, RGB) -> None` + + Set the palette value for a single entry in a Surface palette. The index + should be a value from 0 to 255. + + This function has no effect on a Surface with more than 8-bits per pixel. + + .. ## Surface.set_palette_at ## + + .. method:: map_rgb + + | :sl:`convert a color into a mapped color value` + | :sg:`map_rgb(Color) -> mapped_int` + + Convert an ``RGBA`` color into the mapped integer value for this Surface. + The returned integer will contain no more bits than the bit depth of the + Surface. Mapped color values are not often used inside pygame, but can be + passed to most functions that require a Surface and a color. + + See the Surface object documentation for more information about colors + and pixel formats. + + .. ## Surface.map_rgb ## + + .. method:: unmap_rgb + + | :sl:`convert a mapped integer color value into a Color` + | :sg:`unmap_rgb(mapped_int) -> Color` + + Convert an mapped integer color into the ``RGB`` color components for + this Surface. Mapped color values are not often used inside pygame, but + can be passed to most functions that require a Surface and a color. + + See the Surface object documentation for more information about colors + and pixel formats. + + .. ## Surface.unmap_rgb ## + + .. method:: set_clip + + | :sl:`set the current clipping area of the Surface` + | :sg:`set_clip(rect) -> None` + | :sg:`set_clip(None) -> None` + + Each Surface has an active clipping area. This is a rectangle that + represents the only pixels on the Surface that can be modified. If + ``None`` is passed for the rectangle the full Surface will be available + for changes. + + The clipping area is always restricted to the area of the Surface itself. + If the clip rectangle is too large it will be shrunk to fit inside the + Surface. + + .. ## Surface.set_clip ## + + .. method:: get_clip + + | :sl:`get the current clipping area of the Surface` + | :sg:`get_clip() -> Rect` + + Return a rectangle of the current clipping area. The Surface will always + return a valid rectangle that will never be outside the bounds of the + image. If the Surface has had ``None`` set for the clipping area, the + Surface will return a rectangle with the full area of the Surface. + + .. ## Surface.get_clip ## + + .. method:: subsurface + + | :sl:`create a new surface that references its parent` + | :sg:`subsurface(Rect) -> Surface` + + Returns a new Surface that shares its pixels with its new parent. The new + Surface is considered a child of the original. Modifications to either + Surface pixels will effect each other. Surface information like clipping + area and color keys are unique to each Surface. + + The new Surface will inherit the palette, color key, and alpha settings + from its parent. + + It is possible to have any number of subsurfaces and subsubsurfaces on + the parent. It is also possible to subsurface the display Surface if the + display mode is not hardware accelerated. + + See :meth:`get_offset()` and :meth:`get_parent()` to learn more + about the state of a subsurface. + + A subsurface will have the same class as the parent surface. + + .. ## Surface.subsurface ## + + .. method:: get_parent + + | :sl:`find the parent of a subsurface` + | :sg:`get_parent() -> Surface` + + Returns the parent Surface of a subsurface. If this is not a subsurface + then ``None`` will be returned. + + .. ## Surface.get_parent ## + + .. method:: get_abs_parent + + | :sl:`find the top level parent of a subsurface` + | :sg:`get_abs_parent() -> Surface` + + Returns the parent Surface of a subsurface. If this is not a subsurface + then this surface will be returned. + + .. ## Surface.get_abs_parent ## + + .. method:: get_offset + + | :sl:`find the position of a child subsurface inside a parent` + | :sg:`get_offset() -> (x, y)` + + Get the offset position of a child subsurface inside of a parent. If the + Surface is not a subsurface this will return (0, 0). + + .. ## Surface.get_offset ## + + .. method:: get_abs_offset + + | :sl:`find the absolute position of a child subsurface inside its top level parent` + | :sg:`get_abs_offset() -> (x, y)` + + Get the offset position of a child subsurface inside of its top level + parent Surface. If the Surface is not a subsurface this will return (0, + 0). + + .. ## Surface.get_abs_offset ## + + .. method:: get_size + + | :sl:`get the dimensions of the Surface` + | :sg:`get_size() -> (width, height)` + + Return the width and height of the Surface in pixels. + + .. ## Surface.get_size ## + + .. method:: get_width + + | :sl:`get the width of the Surface` + | :sg:`get_width() -> width` + + Return the width of the Surface in pixels. + + .. ## Surface.get_width ## + + .. method:: get_height + + | :sl:`get the height of the Surface` + | :sg:`get_height() -> height` + + Return the height of the Surface in pixels. + + .. ## Surface.get_height ## + + .. method:: get_rect + + | :sl:`get the rectangular area of the Surface` + | :sg:`get_rect(\**kwargs) -> Rect` + + Returns a new rectangle covering the entire surface. This rectangle will + always start at (0, 0) with a width and height the same size as the image. + + You can pass keyword argument values to this function. These named values + will be applied to the attributes of the Rect before it is returned. An + example would be ``mysurf.get_rect(center=(100, 100))`` to create a + rectangle for the Surface centered at a given position. + + .. ## Surface.get_rect ## + + .. method:: get_bitsize + + | :sl:`get the bit depth of the Surface pixel format` + | :sg:`get_bitsize() -> int` + + Returns the number of bits used to represent each pixel. This value may + not exactly fill the number of bytes used per pixel. For example a 15 bit + Surface still requires a full 2 bytes. + + .. ## Surface.get_bitsize ## + + .. method:: get_bytesize + + | :sl:`get the bytes used per Surface pixel` + | :sg:`get_bytesize() -> int` + + Return the number of bytes used per pixel. + + .. ## Surface.get_bytesize ## + + .. method:: get_flags + + | :sl:`get the additional flags used for the Surface` + | :sg:`get_flags() -> int` + + Returns a set of current Surface features. Each feature is a bit in the + flags bitmask. Typical flags are ``RLEACCEL``, ``SRCALPHA``, and + ``SRCCOLORKEY``. + + Here is a more complete list of flags. A full list can be found in + ``SDL_video.h`` + + :: + + SWSURFACE 0x00000000 # Surface is in system memory + HWSURFACE 0x00000001 # (obsolete in pygame 2) Surface is in video memory + ASYNCBLIT 0x00000004 # (obsolete in pygame 2) Use asynchronous blits if possible + + See :func:`pygame.display.set_mode()` for flags exclusive to the + display surface. + + Used internally (read-only) + + :: + + HWACCEL 0x00000100 # Blit uses hardware acceleration + SRCCOLORKEY 0x00001000 # Blit uses a source color key + RLEACCELOK 0x00002000 # Private flag + RLEACCEL 0x00004000 # Surface is RLE encoded + SRCALPHA 0x00010000 # Blit uses source alpha blending + PREALLOC 0x01000000 # Surface uses preallocated memory + + .. ## Surface.get_flags ## + + .. method:: get_pitch + + | :sl:`get the number of bytes used per Surface row` + | :sg:`get_pitch() -> int` + + Return the number of bytes separating each row in the Surface. Surfaces + in video memory are not always linearly packed. Subsurfaces will also + have a larger pitch than their real width. + + This value is not needed for normal pygame usage. + + .. ## Surface.get_pitch ## + + .. method:: get_masks + + | :sl:`the bitmasks needed to convert between a color and a mapped integer` + | :sg:`get_masks() -> (R, G, B, A)` + + Returns the bitmasks used to isolate each color in a mapped integer. + + This value is not needed for normal pygame usage. + + .. ## Surface.get_masks ## + + .. method:: set_masks + + | :sl:`set the bitmasks needed to convert between a color and a mapped integer` + | :sg:`set_masks((r,g,b,a)) -> None` + + This is not needed for normal pygame usage. + + .. note:: In SDL2, the masks are read-only and accordingly this method will raise + an AttributeError if called. + + .. versionadded:: 1.8.1 + + .. ## Surface.set_masks ## + + .. method:: get_shifts + + | :sl:`the bit shifts needed to convert between a color and a mapped integer` + | :sg:`get_shifts() -> (R, G, B, A)` + + Returns the pixel shifts need to convert between each color and a mapped + integer. + + This value is not needed for normal pygame usage. + + .. ## Surface.get_shifts ## + + .. method:: set_shifts + + | :sl:`sets the bit shifts needed to convert between a color and a mapped integer` + | :sg:`set_shifts((r,g,b,a)) -> None` + + This is not needed for normal pygame usage. + + .. note:: In SDL2, the shifts are read-only and accordingly this method will raise + an AttributeError if called. + + .. versionadded:: 1.8.1 + + .. ## Surface.set_shifts ## + + .. method:: get_losses + + | :sl:`the significant bits used to convert between a color and a mapped integer` + | :sg:`get_losses() -> (R, G, B, A)` + + Return the least significant number of bits stripped from each color in a + mapped integer. + + This value is not needed for normal pygame usage. + + .. ## Surface.get_losses ## + + .. method:: get_bounding_rect + + | :sl:`find the smallest rect containing data` + | :sg:`get_bounding_rect(min_alpha = 1) -> Rect` + + Returns the smallest rectangular region that contains all the pixels in + the surface that have an alpha value greater than or equal to the minimum + alpha value. + + This function will temporarily lock and unlock the Surface as needed. + + .. versionadded:: 1.8 + + .. ## Surface.get_bounding_rect ## + + .. method:: get_view + + | :sl:`return a buffer view of the Surface's pixels.` + | :sg:`get_view(='2') -> BufferProxy` + + Return an object which exports a surface's internal pixel buffer as + a C level array struct, Python level array interface or a C level + buffer interface. The new buffer protocol is supported. + + The kind argument is the length 1 string '0', '1', '2', '3', + 'r', 'g', 'b', or 'a'. The letters are case insensitive; + 'A' will work as well. The argument can be either a Unicode or byte (char) + string. The default is '2'. + + '0' returns a contiguous unstructured bytes view. No surface shape + information is given. A ``ValueError`` is raised if the surface's pixels + are discontinuous. + + '1' returns a (surface-width * surface-height) array of continuous + pixels. A ``ValueError`` is raised if the surface pixels are + discontinuous. + + '2' returns a (surface-width, surface-height) array of raw pixels. + The pixels are surface-bytesize-d unsigned integers. The pixel format is + surface specific. The 3 byte unsigned integers of 24 bit surfaces are + unlikely accepted by anything other than other pygame functions. + + '3' returns a (surface-width, surface-height, 3) array of ``RGB`` color + components. Each of the red, green, and blue components are unsigned + bytes. Only 24-bit and 32-bit surfaces are supported. The color + components must be in either ``RGB`` or ``BGR`` order within the pixel. + + 'r' for red, 'g' for green, 'b' for blue, and 'a' for alpha return a + (surface-width, surface-height) view of a single color component within a + surface: a color plane. Color components are unsigned bytes. Both 24-bit + and 32-bit surfaces support 'r', 'g', and 'b'. Only 32-bit surfaces with + ``SRCALPHA`` support 'a'. + + The surface is locked only when an exposed interface is accessed. + For new buffer interface accesses, the surface is unlocked once the + last buffer view is released. For array interface and old buffer + interface accesses, the surface remains locked until the BufferProxy + object is released. + + .. versionadded:: 1.9.2 + + .. method:: get_buffer + + | :sl:`acquires a buffer object for the pixels of the Surface.` + | :sg:`get_buffer() -> BufferProxy` + + Return a buffer object for the pixels of the Surface. The buffer can be + used for direct pixel access and manipulation. Surface pixel data is + represented as an unstructured block of memory, with a start address + and length in bytes. The data need not be contiguous. Any gaps are + included in the length, but otherwise ignored. + + This method implicitly locks the Surface. The lock will be released when + the returned :mod:`pygame.BufferProxy` object is garbage collected. + + .. versionadded:: 1.8 + + .. ## Surface.get_buffer ## + + .. attribute:: _pixels_address + + | :sl:`pixel buffer address` + | :sg:`_pixels_address -> int` + + The starting address of the surface's raw pixel bytes. + + .. versionadded:: 1.9.2 + + .. ## pygame.Surface ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/surfarray.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/surfarray.rst.txt new file mode 100644 index 0000000..c29723a --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/surfarray.rst.txt @@ -0,0 +1,337 @@ +.. include:: common.txt + +:mod:`pygame.surfarray` +======================= + +.. module:: pygame.surfarray + :synopsis: pygame module for accessing surface pixel data using array interfaces + +| :sl:`pygame module for accessing surface pixel data using array interfaces` + +Functions to convert between NumPy arrays and Surface objects. This module +will only be functional when pygame can use the external NumPy package. +If NumPy can't be imported, ``surfarray`` becomes a ``MissingModule`` object. + +Every pixel is stored as a single integer value to represent the red, green, +and blue colors. The 8-bit images use a value that looks into a colormap. Pixels +with higher depth use a bit packing process to place three or four values into +a single number. + +The arrays are indexed by the ``X`` axis first, followed by the ``Y`` axis. +Arrays that treat the pixels as a single integer are referred to as 2D arrays. +This module can also separate the red, green, and blue color values into +separate indices. These types of arrays are referred to as 3D arrays, and the +last index is 0 for red, 1 for green, and 2 for blue. + +The pixels of a 2D array as returned by :func:`array2d` and :func:`pixels2d` +are mapped to the specific surface. Use :meth:`pygame.Surface.unmap_rgb` +to convert to a color, and :meth:`pygame.Surface.map_rgb` to get the surface +specific pixel value of a color. Integer pixel values can only be used directly +between surfaces with matching pixel layouts (see :class:`pygame.Surface`). + +All functions that refer to "array" will copy the surface information to a new +numpy array. All functions that refer to "pixels" will directly reference the +pixels from the surface and any changes performed to the array will make changes +in the surface. As this last functions share memory with the surface, this one +will be locked during the lifetime of the array. + +.. function:: array2d + + | :sl:`Copy pixels into a 2d array` + | :sg:`array2d(Surface) -> array` + + Copy the :meth:`mapped ` (raw) pixels from a Surface + into a 2D array. + The bit depth of the surface will control the size of the integer values, + and will work for any type of pixel format. + + This function will temporarily lock the Surface as pixels are copied + (see the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method). + + .. ## pygame.surfarray.array2d ## + +.. function:: pixels2d + + | :sl:`Reference pixels into a 2d array` + | :sg:`pixels2d(Surface) -> array` + + Create a new 2D array that directly references the pixel values in a + Surface. Any changes to the array will affect the pixels in the Surface. + This is a fast operation since no data is copied. + + Pixels from a 24-bit Surface cannot be referenced, but all other Surface bit + depths can. + + The Surface this references will remain locked for the lifetime of the array, + since the array generated by this function shares memory with the surface. + See the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method. + + .. ## pygame.surfarray.pixels2d ## + +.. function:: array3d + + | :sl:`Copy pixels into a 3d array` + | :sg:`array3d(Surface) -> array` + + Copy the pixels from a Surface into a 3D array. The bit depth of the surface + will control the size of the integer values, and will work for any type of + pixel format. + + This function will temporarily lock the Surface as pixels are copied (see + the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method). + + .. ## pygame.surfarray.array3d ## + +.. function:: pixels3d + + | :sl:`Reference pixels into a 3d array` + | :sg:`pixels3d(Surface) -> array` + + Create a new 3D array that directly references the pixel values in a + Surface. Any changes to the array will affect the pixels in the Surface. + This is a fast operation since no data is copied. + + This will only work on Surfaces that have 24-bit or 32-bit formats. Lower + pixel formats cannot be referenced. + + The Surface this references will remain locked for the lifetime of the array, + since the array generated by this function shares memory with the surface. + See the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method. + + .. ## pygame.surfarray.pixels3d ## + +.. function:: array_alpha + + | :sl:`Copy pixel alphas into a 2d array` + | :sg:`array_alpha(Surface) -> array` + + Copy the pixel alpha values (degree of transparency) from a Surface into a + 2D array. This will work for any type of Surface format. Surfaces without a + pixel alpha will return an array with all opaque values. + + This function will temporarily lock the Surface as pixels are copied (see + the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method). + + .. ## pygame.surfarray.array_alpha ## + +.. function:: pixels_alpha + + | :sl:`Reference pixel alphas into a 2d array` + | :sg:`pixels_alpha(Surface) -> array` + + Create a new 2D array that directly references the alpha values (degree of + transparency) in a Surface. Any changes to the array will affect the pixels + in the Surface. This is a fast operation since no data is copied. + + This can only work on 32-bit Surfaces with a per-pixel alpha value. + + The Surface this references will remain locked for the lifetime of the array, + since the array generated by this function shares memory with the surface. + See the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method. + + .. ## pygame.surfarray.pixels_alpha ## + +.. function:: array_red + + | :sl:`Copy red pixels into a 2d array` + | :sg:`array_red(Surface) -> array` + + Copy the pixel red values from a Surface into a 2D array. This will work + for any type of Surface format. + + This function will temporarily lock the Surface as pixels are copied (see + the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method). + + .. versionadded:: 2.0.2 + + .. ## pygame.surfarray.array_red ## + +.. function:: pixels_red + + | :sl:`Reference pixel red into a 2d array.` + | :sg:`pixels_red (Surface) -> array` + + Create a new 2D array that directly references the red values in a Surface. + Any changes to the array will affect the pixels in the Surface. This is a + fast operation since no data is copied. + + This can only work on 24-bit or 32-bit Surfaces. + + The Surface this references will remain locked for the lifetime of the array, + since the array generated by this function shares memory with the surface. + See the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method. + + .. ## pygame.surfarray.pixels_red ## + +.. function:: array_green + + | :sl:`Copy green pixels into a 2d array` + | :sg:`array_green(Surface) -> array` + + Copy the pixel green values from a Surface into a 2D array. This will work + for any type of Surface format. + + This function will temporarily lock the Surface as pixels are copied (see + the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method). + + .. versionadded:: 2.0.2 + + .. ## pygame.surfarray.array_green ## + +.. function:: pixels_green + + | :sl:`Reference pixel green into a 2d array.` + | :sg:`pixels_green (Surface) -> array` + + Create a new 2D array that directly references the green values in a + Surface. Any changes to the array will affect the pixels in the Surface. + This is a fast operation since no data is copied. + + This can only work on 24-bit or 32-bit Surfaces. + + The Surface this references will remain locked for the lifetime of the array, + since the array generated by this function shares memory with the surface. + See the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method. + + .. ## pygame.surfarray.pixels_green ## + +.. function:: array_blue + + | :sl:`Copy blue pixels into a 2d array` + | :sg:`array_blue(Surface) -> array` + + Copy the pixel blue values from a Surface into a 2D array. This will work + for any type of Surface format. + + This function will temporarily lock the Surface as pixels are copied (see + the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method). + + .. versionadded:: 2.0.2 + + .. ## pygame.surfarray.array_blue ## + +.. function:: pixels_blue + + | :sl:`Reference pixel blue into a 2d array.` + | :sg:`pixels_blue (Surface) -> array` + + Create a new 2D array that directly references the blue values in a Surface. + Any changes to the array will affect the pixels in the Surface. This is a + fast operation since no data is copied. + + This can only work on 24-bit or 32-bit Surfaces. + + The Surface this references will remain locked for the lifetime of the array, + since the array generated by this function shares memory with the surface. + See the :meth:`pygame.Surface.lock` - lock the Surface memory for pixel + access method. + + .. ## pygame.surfarray.pixels_blue ## + +.. function:: array_colorkey + + | :sl:`Copy the colorkey values into a 2d array` + | :sg:`array_colorkey(Surface) -> array` + + Create a new array with the colorkey transparency value from each pixel. If + the pixel matches the colorkey it will be fully transparent; otherwise it + will be fully opaque. + + This will work on any type of Surface format. If the image has no colorkey a + solid opaque array will be returned. + + This function will temporarily lock the Surface as pixels are copied. + + .. ## pygame.surfarray.array_colorkey ## + +.. function:: make_surface + + | :sl:`Copy an array to a new surface` + | :sg:`make_surface(array) -> Surface` + + Create a new Surface that best resembles the data and format on the array. + The array can be 2D or 3D with any sized integer values. Function + make_surface uses the array struct interface to acquire array properties, + so is not limited to just NumPy arrays. See :mod:`pygame.pixelcopy`. + + New in pygame 1.9.2: array struct interface support. + + .. ## pygame.surfarray.make_surface ## + +.. function:: blit_array + + | :sl:`Blit directly from a array values` + | :sg:`blit_array(Surface, array) -> None` + + Directly copy values from an array into a Surface. This is faster than + converting the array into a Surface and blitting. The array must be the same + dimensions as the Surface and will completely replace all pixel values. Only + integer, ASCII character and record arrays are accepted. + + This function will temporarily lock the Surface as the new values are + copied. + + .. ## pygame.surfarray.blit_array ## + +.. function:: map_array + + | :sl:`Map a 3d array into a 2d array` + | :sg:`map_array(Surface, array3d) -> array2d` + + Convert a 3D array into a 2D array. This will use the given Surface format + to control the conversion. Palette surface formats are supported for NumPy + arrays. + + .. ## pygame.surfarray.map_array ## + +.. function:: use_arraytype + + | :sl:`Sets the array system to be used for surface arrays` + | :sg:`use_arraytype (arraytype) -> None` + + DEPRECATED: Uses the requested array type for the module functions. + The only supported arraytype is ``'numpy'``. Other values will raise + ValueError. Using this function will raise a ``DeprecationWarning``. + + .. ## pygame.surfarray.use_arraytype ## + +.. function:: get_arraytype + + | :sl:`Gets the currently active array type.` + | :sg:`get_arraytype () -> str` + + DEPRECATED: Returns the currently active array type. This will be a value of the + ``get_arraytypes()`` tuple and indicates which type of array module is used + for the array creation. Using this function will raise a ``DeprecationWarning``. + + .. versionadded:: 1.8 + + .. ## pygame.surfarray.get_arraytype ## + +.. function:: get_arraytypes + + | :sl:`Gets the array system types currently supported.` + | :sg:`get_arraytypes () -> tuple` + + DEPRECATED: Checks, which array systems are available and returns them as a tuple of + strings. The values of the tuple can be used directly in the + :func:`pygame.surfarray.use_arraytype` () method. If no supported array + system could be found, None will be returned. Using this function will raise a + ``DeprecationWarning``. + + .. versionadded:: 1.8 + + .. ## pygame.surfarray.get_arraytypes ## + +.. ## pygame.surfarray ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/tests.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/tests.rst.txt new file mode 100644 index 0000000..09be45d --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/tests.rst.txt @@ -0,0 +1,108 @@ +.. include:: common.txt + +:mod:`pygame.tests` +=================== + +.. module:: pygame.tests + :synopsis: Pygame unit test suite package + +| :sl:`Pygame unit test suite package` + +A quick way to run the test suite package from the command line is to import +the go submodule with the Python -m option: + +:: + + python -m pygame.tests [] + +Command line option --help displays a usage message. Available options +correspond to the :func:`pygame.tests.run` arguments. + +The xxxx_test submodules of the tests package are unit test suites for +individual parts of pygame. Each can also be run as a main program. This is +useful if the test, such as cdrom_test, is interactive. + +For pygame development the test suite can be run from a pygame distribution +root directory. Program ``run_tests.py`` is provided for convenience, though +test/go.py can be run directly. + +Module level tags control which modules are included in a unit test run. Tags +are assigned to a unit test module with a corresponding _tags.py module. +The tags module has the global __tags__, a list of tag names. For example, +``cdrom_test.py`` has a tag file ``cdrom_tags.py`` containing a tags list that +has the 'interactive' string. The 'interactive' tag indicates ``cdrom_test.py`` +expects user input. It is excluded from a ``run_tests.py`` or +``pygame.tests.go`` run. Two other tags that are excluded are 'ignore' and +'subprocess_ignore'. These two tags indicate unit tests that will not run on a +particular platform, or for which no corresponding pygame module is available. +The test runner will list each excluded module along with the tag responsible. + +.. function:: run + + | :sl:`Run the pygame unit test suite` + | :sg:`run(*args, **kwds) -> tuple` + + Positional arguments (optional): + + :: + + The names of tests to include. If omitted then all tests are run. Test names + need not include the trailing '_test'. + + Keyword arguments: + + :: + + incomplete - fail incomplete tests (default False) + nosubprocess - run all test suites in the current process + (default False, use separate subprocesses) + dump - dump failures/errors as dict ready to eval (default False) + file - if provided, the name of a file into which to dump failures/errors + timings - if provided, the number of times to run each individual test to + get an average run time (default is run each test once) + exclude - A list of TAG names to exclude from the run + show_output - show silenced stderr/stdout on errors (default False) + all - dump all results, not just errors (default False) + randomize - randomize order of tests (default False) + seed - if provided, a seed randomizer integer + multi_thread - if provided, the number of THREADS in which to run + subprocessed tests + time_out - if subprocess is True then the time limit in seconds before + killing a test (default 30) + fake - if provided, the name of the fake tests package in the + run_tests__tests subpackage to run instead of the normal + pygame tests + python - the path to a python executable to run subprocessed tests + (default sys.executable) + + Return value: + + :: + + A tuple of total number of tests run, dictionary of error information. + The dictionary is empty if no errors were recorded. + + By default individual test modules are run in separate subprocesses. This + recreates normal pygame usage where ``pygame.init()`` and ``pygame.quit()`` + are called only once per program execution, and avoids unfortunate + interactions between test modules. Also, a time limit is placed on test + execution, so frozen tests are killed when there time allotment expired. Use + the single process option if threading is not working properly or if tests + are taking too long. It is not guaranteed that all tests will pass in single + process mode. + + Tests are run in a randomized order if the randomize argument is True or a + seed argument is provided. If no seed integer is provided then the system + time is used. + + Individual test modules may have a __tags__ attribute, a list of tag strings + used to selectively omit modules from a run. By default only 'interactive' + modules such as cdrom_test are ignored. An interactive module must be run + from the console as a Python program. + + This function can only be called once per Python session. It is not + reentrant. + + .. ## pygame.tests.run ## + +.. ## pygame.tests ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/time.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/time.rst.txt new file mode 100644 index 0000000..4c513c4 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/time.rst.txt @@ -0,0 +1,165 @@ +.. include:: common.txt + +:mod:`pygame.time` +================== + +.. module:: pygame.time + :synopsis: pygame module for monitoring time + +| :sl:`pygame module for monitoring time` + +Times in pygame are represented in milliseconds (1/1000 seconds). Most +platforms have a limited time resolution of around 10 milliseconds. This +resolution, in milliseconds, is given in the ``TIMER_RESOLUTION`` constant. + +.. function:: get_ticks + + | :sl:`get the time in milliseconds` + | :sg:`get_ticks() -> milliseconds` + + Return the number of milliseconds since ``pygame.init()`` was called. Before + pygame is initialized this will always be 0. + + .. ## pygame.time.get_ticks ## + +.. function:: wait + + | :sl:`pause the program for an amount of time` + | :sg:`wait(milliseconds) -> time` + + Will pause for a given number of milliseconds. This function sleeps the + process to share the processor with other programs. A program that waits for + even a few milliseconds will consume very little processor time. It is + slightly less accurate than the ``pygame.time.delay()`` function. + + This returns the actual number of milliseconds used. + + .. ## pygame.time.wait ## + +.. function:: delay + + | :sl:`pause the program for an amount of time` + | :sg:`delay(milliseconds) -> time` + + Will pause for a given number of milliseconds. This function will use the + processor (rather than sleeping) in order to make the delay more accurate + than ``pygame.time.wait()``. + + This returns the actual number of milliseconds used. + + .. ## pygame.time.delay ## + +.. function:: set_timer + + | :sl:`repeatedly create an event on the event queue` + | :sg:`set_timer(event, millis) -> None` + | :sg:`set_timer(event, millis, loops=0) -> None` + + Set an event to appear on the event queue every given number of milliseconds. + The first event will not appear until the amount of time has passed. + + The ``event`` attribute can be a ``pygame.event.Event`` object or an integer + type that denotes an event. + + ``loops`` is an integer that denotes the number of events posted. If 0 (default) + then the events will keep getting posted, unless explicitly stopped. + + To disable the timer for such an event, call the function again with the same + event argument with ``millis`` argument set to 0. + + It is also worth mentioning that a particular event type can only be put on a + timer once. In other words, there cannot be two timers for the same event type. + Setting an event timer for a particular event discards the old one for that + event type. + + ``loops`` replaces the ``once`` argument, and this does not break backward + compatability + + .. versionadded:: 2.0.0.dev3 once argument added. + .. versionchanged:: 2.0.1 event argument supports ``pygame.event.Event`` object + .. versionadded:: 2.0.1 added loops argument to replace once argument + + .. ## pygame.time.set_timer ## + +.. class:: Clock + + | :sl:`create an object to help track time` + | :sg:`Clock() -> Clock` + + Creates a new Clock object that can be used to track an amount of time. The + clock also provides several functions to help control a game's framerate. + + .. method:: tick + + | :sl:`update the clock` + | :sg:`tick(framerate=0) -> milliseconds` + + This method should be called once per frame. It will compute how many + milliseconds have passed since the previous call. + + If you pass the optional framerate argument the function will delay to + keep the game running slower than the given ticks per second. This can be + used to help limit the runtime speed of a game. By calling + ``Clock.tick(40)`` once per frame, the program will never run at more + than 40 frames per second. + + Note that this function uses SDL_Delay function which is not accurate on + every platform, but does not use much CPU. Use tick_busy_loop if you want + an accurate timer, and don't mind chewing CPU. + + .. ## Clock.tick ## + + .. method:: tick_busy_loop + + | :sl:`update the clock` + | :sg:`tick_busy_loop(framerate=0) -> milliseconds` + + This method should be called once per frame. It will compute how many + milliseconds have passed since the previous call. + + If you pass the optional framerate argument the function will delay to + keep the game running slower than the given ticks per second. This can be + used to help limit the runtime speed of a game. By calling + ``Clock.tick_busy_loop(40)`` once per frame, the program will never run at + more than 40 frames per second. + + Note that this function uses :func:`pygame.time.delay`, which uses lots + of CPU in a busy loop to make sure that timing is more accurate. + + .. versionadded:: 1.8 + + .. ## Clock.tick_busy_loop ## + + .. method:: get_time + + | :sl:`time used in the previous tick` + | :sg:`get_time() -> milliseconds` + + The number of milliseconds that passed between the previous two calls to + ``Clock.tick()``. + + .. ## Clock.get_time ## + + .. method:: get_rawtime + + | :sl:`actual time used in the previous tick` + | :sg:`get_rawtime() -> milliseconds` + + Similar to ``Clock.get_time()``, but does not include any time used + while ``Clock.tick()`` was delaying to limit the framerate. + + .. ## Clock.get_rawtime ## + + .. method:: get_fps + + | :sl:`compute the clock framerate` + | :sg:`get_fps() -> float` + + Compute your game's framerate (in frames per second). It is computed by + averaging the last ten calls to ``Clock.tick()``. + + .. ## Clock.get_fps ## + + .. ## pygame.time.Clock ## + +.. ## pygame.time ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/touch.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/touch.rst.txt new file mode 100644 index 0000000..320da05 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/touch.rst.txt @@ -0,0 +1,66 @@ +.. include:: common.txt + +:mod:`pygame._sdl2.touch` +========================= + +.. module:: pygame._sdl2.touch + :synopsis: pygame module to work with touch input + +| :sl:`pygame module to work with touch input` + +.. versionadded:: 2 This module requires SDL2. + +.. function:: get_num_devices + + | :sl:`get the number of touch devices` + | :sg:`get_num_devices() -> int` + + Return the number of available touch devices. + + .. ## pygame._sdl2.touch.get_num_devices ## + +.. function:: get_device + + | :sl:`get the a touch device id for a given index` + | :sg:`get_device(index) -> touchid` + + :param int index: This number is at least 0 and less than the + :func:`number of devices `. + + Return an integer id associated with the given ``index``. + + .. ## pygame._sdl2.touch.get_device ## + +.. function:: get_num_fingers + + | :sl:`the number of active fingers for a given touch device` + | :sg:`get_num_fingers(touchid) -> int` + + Return the number of fingers active for the touch device + whose id is `touchid`. + + .. ## pygame._sdl2.touch.get_num_fingers ## + +.. function:: get_finger + + | :sl:`get information about an active finger` + | :sg:`get_finger(touchid, index) -> int` + + :param int touchid: The touch device id. + :param int index: The index of the finger to return + information about, between 0 and the + :func:`number of active fingers `. + + Return a dict for the finger ``index`` active on ``touchid``. + The dict contains these keys: + + :: + + id the id of the finger (an integer). + x the normalized x position of the finger, between 0 and 1. + y the normalized y position of the finger, between 0 and 1. + pressure the amount of pressure applied by the finger, between 0 and 1. + + .. ## pygame._sdl2.touch.get_finger ## + +.. ## pygame._sdl2.touch ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/transform.rst.txt b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/transform.rst.txt new file mode 100644 index 0000000..29a4c43 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_sources/ref/transform.rst.txt @@ -0,0 +1,271 @@ +.. include:: common.txt + +:mod:`pygame.transform` +======================= + +.. module:: pygame.transform + :synopsis: pygame module to transform surfaces + +| :sl:`pygame module to transform surfaces` + +A Surface transform is an operation that moves or resizes the pixels. All these +functions take a Surface to operate on and return a new Surface with the +results. + +Some of the transforms are considered destructive. These means every time they +are performed they lose pixel data. Common examples of this are resizing and +rotating. For this reason, it is better to re-transform the original surface +than to keep transforming an image multiple times. (For example, suppose you +are animating a bouncing spring which expands and contracts. If you applied the +size changes incrementally to the previous images, you would lose detail. +Instead, always begin with the original image and scale to the desired size.) + +.. versionchanged:: 2.0.2 transform functions now support keyword arguments. + +.. function:: flip + + | :sl:`flip vertically and horizontally` + | :sg:`flip(surface, flip_x, flip_y) -> Surface` + + This can flip a Surface either vertically, horizontally, or both. + The arguments ``flip_x`` and ``flip_y`` are booleans that control whether + to flip each axis. Flipping a Surface is non-destructive and returns a new + Surface with the same dimensions. + + .. ## pygame.transform.flip ## + +.. function:: scale + + | :sl:`resize to new resolution` + | :sg:`scale(surface, size, dest_surface=None) -> Surface` + + Resizes the Surface to a new size, given as (width, height). + This is a fast scale operation that does not sample the results. + + An optional destination surface can be used, rather than have it create a + new one. This is quicker if you want to repeatedly scale something. However + the destination must be the same size as the size (width, height) passed in. Also + the destination surface must be the same format. + + .. ## pygame.transform.scale ## + +.. function:: rotate + + | :sl:`rotate an image` + | :sg:`rotate(surface, angle) -> Surface` + + Unfiltered counterclockwise rotation. The angle argument represents degrees + and can be any floating point value. Negative angle amounts will rotate + clockwise. + + Unless rotating by 90 degree increments, the image will be padded larger to + hold the new size. If the image has pixel alphas, the padded area will be + transparent. Otherwise pygame will pick a color that matches the Surface + colorkey or the topleft pixel value. + + .. ## pygame.transform.rotate ## + +.. function:: rotozoom + + | :sl:`filtered scale and rotation` + | :sg:`rotozoom(surface, angle, scale) -> Surface` + + This is a combined scale and rotation transform. The resulting Surface will + be a filtered 32-bit Surface. The scale argument is a floating point value + that will be multiplied by the current resolution. The angle argument is a + floating point value that represents the counterclockwise degrees to rotate. + A negative rotation angle will rotate clockwise. + + .. ## pygame.transform.rotozoom ## + +.. function:: scale2x + + | :sl:`specialized image doubler` + | :sg:`scale2x(surface, dest_surface=None) -> Surface` + + This will return a new image that is double the size of the original. It + uses the AdvanceMAME Scale2X algorithm which does a 'jaggie-less' scale of + bitmap graphics. + + This really only has an effect on simple images with solid colors. On + photographic and antialiased images it will look like a regular unfiltered + scale. + + An optional destination surface can be used, rather than have it create a + new one. This is quicker if you want to repeatedly scale something. However + the destination must be twice the size of the source surface passed in. Also + the destination surface must be the same format. + + .. ## pygame.transform.scale2x ## + +.. function:: smoothscale + + | :sl:`scale a surface to an arbitrary size smoothly` + | :sg:`smoothscale(surface, size, dest_surface=None) -> Surface` + + Uses one of two different algorithms for scaling each dimension of the input + surface as required. For shrinkage, the output pixels are area averages of + the colors they cover. For expansion, a bilinear filter is used. For the + x86-64 and i686 architectures, optimized ``MMX`` routines are included and + will run much faster than other machine types. The size is a 2 number + sequence for (width, height). This function only works for 24-bit or 32-bit + surfaces. An exception will be thrown if the input surface bit depth is less + than 24. + + .. versionadded:: 1.8 + + .. ## pygame.transform.smoothscale ## + +.. function:: get_smoothscale_backend + + | :sl:`return smoothscale filter version in use: 'GENERIC', 'MMX', or 'SSE'` + | :sg:`get_smoothscale_backend() -> string` + + Shows whether or not smoothscale is using ``MMX`` or ``SSE`` acceleration. + If no acceleration is available then "GENERIC" is returned. For a x86 + processor the level of acceleration to use is determined at runtime. + + This function is provided for pygame testing and debugging. + + .. ## pygame.transform.get_smoothscale_backend ## + +.. function:: set_smoothscale_backend + + | :sl:`set smoothscale filter version to one of: 'GENERIC', 'MMX', or 'SSE'` + | :sg:`set_smoothscale_backend(backend) -> None` + + Sets smoothscale acceleration. Takes a string argument. A value of 'GENERIC' + turns off acceleration. 'MMX' uses ``MMX`` instructions only. 'SSE' allows + ``SSE`` extensions as well. A value error is raised if type is not + recognized or not supported by the current processor. + + This function is provided for pygame testing and debugging. If smoothscale + causes an invalid instruction error then it is a pygame/SDL bug that should + be reported. Use this function as a temporary fix only. + + .. ## pygame.transform.set_smoothscale_backend ## + +.. function:: chop + + | :sl:`gets a copy of an image with an interior area removed` + | :sg:`chop(surface, rect) -> Surface` + + Extracts a portion of an image. All vertical and horizontal pixels + surrounding the given rectangle area are removed. The corner areas (diagonal + to the rect) are then brought together. (The original image is not altered + by this operation.) + + ``NOTE``: If you want a "crop" that returns the part of an image within a + rect, you can blit with a rect to a new surface or copy a subsurface. + + .. ## pygame.transform.chop ## + +.. function:: laplacian + + | :sl:`find edges in a surface` + | :sg:`laplacian(surface, dest_surface=None) -> Surface` + + Finds the edges in a surface using the laplacian algorithm. + + .. versionadded:: 1.8 + + .. ## pygame.transform.laplacian ## + +.. function:: average_surfaces + + | :sl:`find the average surface from many surfaces.` + | :sg:`average_surfaces(surfaces, dest_surface=None, palette_colors=1) -> Surface` + + Takes a sequence of surfaces and returns a surface with average colors from + each of the surfaces. + + palette_colors - if true we average the colors in palette, otherwise we + average the pixel values. This is useful if the surface is actually + greyscale colors, and not palette colors. + + Note, this function currently does not handle palette using surfaces + correctly. + + .. versionadded:: 1.8 + .. versionadded:: 1.9 ``palette_colors`` argument + + .. ## pygame.transform.average_surfaces ## + +.. function:: average_color + + | :sl:`finds the average color of a surface` + | :sg:`average_color(surface, rect=None) -> Color` + + Finds the average color of a Surface or a region of a surface specified by a + Rect, and returns it as a Color. + + .. ## pygame.transform.average_color ## + +.. function:: threshold + + | :sl:`finds which, and how many pixels in a surface are within a threshold of a 'search_color' or a 'search_surf'.` + | :sg:`threshold(dest_surface, surface, search_color, threshold=(0,0,0,0), set_color=(0,0,0,0), set_behavior=1, search_surf=None, inverse_set=False) -> num_threshold_pixels` + + This versatile function can be used for find colors in a 'surf' close to a 'search_color' + or close to colors in a separate 'search_surf'. + + It can also be used to transfer pixels into a 'dest_surf' that match or don't match. + + By default it sets pixels in the 'dest_surf' where all of the pixels NOT within the + threshold are changed to set_color. If inverse_set is optionally set to True, + the pixels that ARE within the threshold are changed to set_color. + + If the optional 'search_surf' surface is given, it is used to threshold against + rather than the specified 'set_color'. That is, it will find each pixel in the + 'surf' that is within the 'threshold' of the pixel at the same coordinates + of the 'search_surf'. + + :param dest_surf: Surface we are changing. See 'set_behavior'. + Should be None if counting (set_behavior is 0). + :type dest_surf: pygame.Surface or None + + :param pygame.Surface surf: Surface we are looking at. + + :param pygame.Color search_color: Color we are searching for. + + :param pygame.Color threshold: Within this distance from search_color (or search_surf). + You can use a threshold of (r,g,b,a) where the r,g,b can have different + thresholds. So you could use an r threshold of 40 and a blue threshold of 2 + if you like. + + :param set_color: Color we set in dest_surf. + :type set_color: pygame.Color or None + + :param int set_behavior: + - set_behavior=1 (default). Pixels in dest_surface will be changed to 'set_color'. + - set_behavior=0 we do not change 'dest_surf', just count. Make dest_surf=None. + - set_behavior=2 pixels set in 'dest_surf' will be from 'surf'. + + :param search_surf: + - search_surf=None (default). Search against 'search_color' instead. + - search_surf=Surface. Look at the color in 'search_surf' rather than using 'search_color'. + :type search_surf: pygame.Surface or None + + :param bool inverse_set: + - False, default. Pixels outside of threshold are changed. + - True, Pixels within threshold are changed. + + :rtype: int + :returns: The number of pixels that are within the 'threshold' in 'surf' + compared to either 'search_color' or `search_surf`. + + :Examples: + + See the threshold tests for a full of examples: https://github.com/pygame/pygame/blob/master/test/transform_test.py + + .. literalinclude:: ../../../test/transform_test.py + :pyobject: TransformModuleTest.test_threshold_dest_surf_not_change + + + .. versionadded:: 1.8 + .. versionchanged:: 1.9.4 + Fixed a lot of bugs and added keyword arguments. Test your code. + + .. ## pygame.transform.threshold ## + +.. ## pygame.transform ## diff --git a/venv/Lib/site-packages/pygame/docs/generated/_static/basic.css b/venv/Lib/site-packages/pygame/docs/generated/_static/basic.css new file mode 100644 index 0000000..603f6a8 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_static/basic.css @@ -0,0 +1,905 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 450px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a.brackets:before, +span.brackets > a:before{ + content: "["; +} + +a.brackets:after, +span.brackets > a:after { + content: "]"; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +dl.footnote > dt, +dl.citation > dt { + float: left; + margin-right: 0.5em; +} + +dl.footnote > dd, +dl.citation > dd { + margin-bottom: 0em; +} + +dl.footnote > dd:after, +dl.citation > dd:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dt:after { + content: ":"; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/_static/doctools.js b/venv/Lib/site-packages/pygame/docs/generated/_static/doctools.js new file mode 100644 index 0000000..8cbf1b1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_static/doctools.js @@ -0,0 +1,323 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { + this.initOnKeyListeners(); + } + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keydown(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box, textarea, dropdown or button + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' + && activeElementType !== 'BUTTON' && !event.altKey && !event.ctrlKey && !event.metaKey + && !event.shiftKey) { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + break; + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + break; + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/venv/Lib/site-packages/pygame/docs/generated/_static/documentation_options.js b/venv/Lib/site-packages/pygame/docs/generated/_static/documentation_options.js new file mode 100644 index 0000000..278cfec --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_static/documentation_options.js @@ -0,0 +1,12 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '2.1.2', + LANGUAGE: 'None', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false +}; \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/_static/file.png b/venv/Lib/site-packages/pygame/docs/generated/_static/file.png new file mode 100644 index 0000000..a858a41 Binary files /dev/null and b/venv/Lib/site-packages/pygame/docs/generated/_static/file.png differ diff --git a/venv/Lib/site-packages/pygame/docs/generated/_static/jquery-3.5.1.js b/venv/Lib/site-packages/pygame/docs/generated/_static/jquery-3.5.1.js new file mode 100644 index 0000000..5093733 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/_static/jquery-3.5.1.js @@ -0,0 +1,10872 @@ +/*! + * jQuery JavaScript Library v3.5.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2020-05-04T22:49Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + return typeof obj === "function" && typeof obj.nodeType !== "number"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.5.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.5 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2020-03-14 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem.namespaceURI, + docElem = ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); + } : + function( a, b ) { + if ( b ) { + while ( ( b = b.parentNode ) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( ( cur = cur.parentNode ) ) { + ap.unshift( cur ); + } + cur = b; + while ( ( cur = cur.parentNode ) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[ i ] === bp[ i ] ) { + i++; + } + + return i ? + + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[ i ], bp[ i ] ) : + + // Otherwise nodes in our document sort first + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( support.matchesSelector && documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + /* eslint-disable max-len */ + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + /* eslint-enable max-len */ + + }; + }, + + "CHILD": function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + "not": markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element (issue #299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + "has": markFunction( function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + } ), + + "contains": markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); + }, + + "selected": function( elem ) { + + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos[ "empty" ]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo( function() { + return [ 0 ]; + } ), + + "last": createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + "even": createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "odd": createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rcombinators.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + } ); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + } ); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; + } + } ); +} + +return Sizzle; + +} )( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + return result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + delegateType: delegateType + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px"; + tr.style.height = "1px"; + trChild.style.height = "9px"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( + dataPriv.get( cur, "events" ) || Object.create( null ) + )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script + if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/c_api/base.html b/venv/Lib/site-packages/pygame/docs/generated/c_api/base.html new file mode 100644 index 0000000..6486af9 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/c_api/base.html @@ -0,0 +1,365 @@ + + + + + + + + + High level API exported by pygame.base — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

src_c/base.c

+

This extension module defines general purpose routines for starting and stopping +SDL as well as various conversion routines uses elsewhere in pygame.

+

C header: src_c/include/pygame.h

+
+
+PyObject *pgExc_SDLError
+

This is pygame.error, the exception type used to raise SDL errors.

+
+ +
+
+int pg_mod_autoinit(const char *modname)
+

Inits a pygame module, which has the name modname +Return 1 on success, 0 on error, with python +error set.

+
+ +
+
+void pg_mod_autoquit(const char *modname)
+

Quits a pygame module, which has the name modname

+
+ +
+
+void pg_RegisterQuit(void (*f)(void))
+

Register function f as a callback on Pygame termination. +Multiple functions can be registered. +Functions are called in the reverse order they were registered.

+
+ +
+
+int pg_IntFromObj(PyObject *obj, int *val)
+

Convert number like object obj to C int and place in argument val. +Return 1 on success, else 0. +No Python exceptions are raised.

+
+ +
+
+int pg_IntFromObjIndex(PyObject *obj, int index, int *val)
+

Convert number like object at position i in sequence obj +to C int and place in argument val. +Return 1 on success, 0 on failure. +No Python exceptions are raised.

+
+ +
+
+int pg_TwoIntsFromObj(PyObject *obj, int *val1, int *v2)
+

Convert the two number like objects in length 2 sequence obj +to C int and place in arguments val1 and val2 respectively. +Return 1 on success, 0 on failure. +No Python exceptions are raised.

+
+ +
+
+int pg_FloatFromObj(PyObject *obj, float *val)
+

Convert number like object obj to C float and place in argument val. +Returns 1 on success, 0 on failure. +No Python exceptions are raised.

+
+ +
+
+int pg_FloatFromObjIndex(PyObject *obj, int index, float *val)
+

Convert number like object at position i in sequence obj +to C float and place in argument val. +Return 1 on success, else 0. +No Python exceptions are raised.

+
+ +
+
+int pg_TwoFloatsFromObj(PyObject *obj, float *val1, float *val2)
+

Convert the two number like objects in length 2 sequence obj +to C float and place in arguments val1 and val2 respectively. +Return 1 on success, else 0. +No Python exceptions are raised.

+
+ +
+
+int pg_UintFromObj(PyObject *obj, Uint32 *val)
+

Convert number like object obj to unsigned 32 bit integer and place +in argument val. +Return 1 on success, else 0. +No Python exceptions are raised.

+
+ +
+
+int pg_UintFromObjIndex(PyObject *obj, int _index, Uint32 *val)
+

Convert number like object at position i in sequence obj +to unsigned 32 bit integer and place in argument val. +Return 1 on success, else 0. +No Python exceptions are raised.

+
+ +
+
+int pg_RGBAFromObj(PyObject *obj, Uint8 *RGBA)
+

Convert the color represented by object obj into a red, green, blue, alpha +length 4 C array RGBA. +The object must be a length 3 or 4 sequence of numbers having values +between 0 and 255 inclusive. +For a length 3 sequence an alpha value of 255 is assumed. +Return 1 on success, 0 otherwise. +No Python exceptions are raised.

+
+ +
+
+type pg_buffer
+
+
+Py_buffer view
+

A standard buffer description

+
+ +
+
+PyObject *consumer
+

The object holding the buffer

+
+ +
+
+pybuffer_releaseproc release_buffer
+

A buffer release callback.

+
+ +
+ +
+
+PyObject *pgExc_BufferError
+

Python exception type raised for any pg_buffer related errors.

+
+ +
+
+PyObject *pgBuffer_AsArrayInterface(Py_buffer *view_p)
+

Return a Python array interface object representation of buffer view_p. +On failure raise a Python exception and return NULL.

+
+ +
+
+PyObject *pgBuffer_AsArrayStruct(Py_buffer *view_p)
+

Return a Python array struct object representation of buffer view_p. +On failure raise a Python exception and return NULL.

+
+ +
+
+int pgObject_GetBuffer(PyObject *obj, pg_buffer *pg_view_p, int flags)
+

Request a buffer for object obj. +Argument flags are PyBUF options. +Return the buffer description in pg_view_p. +An object may support the Python buffer interface, the NumPy array interface, +or the NumPy array struct interface. +Return 0 on success, raise a Python exception and return -1 on failure.

+
+ +
+
+void pgBuffer_Release(Pg_buffer *pg_view_p)
+

Release the Pygame pg_view_p buffer.

+
+ +
+
+int pgDict_AsBuffer(Pg_buffer *pg_view_p, PyObject *dict, int flags)
+

Write the array interface dictionary buffer description dict into a Pygame +buffer description struct pg_view_p. +The flags PyBUF options describe the view type requested. +Return 0 on success, or raise a Python exception and return -1 on failure.

+
+ +
+
+void import_pygame_base()
+

Import the pygame.base module C API into an extension module. +On failure raise a Python exception.

+
+ +
+
+SDL_Window *pg_GetDefaultWindow(void)
+

Return the Pygame default SDL window created by a +pygame.display.set_mode() call, or NULL.

+

Availability: SDL 2.

+
+ +
+
+void pg_SetDefaultWindow(SDL_Window *win)
+

Replace the Pygame default window with win. +The previous window, if any, is destroyed. +Argument win may be NULL. +This function is called by pygame.display.set_mode().

+

Availability: SDL 2.

+
+ +
+
+pgSurfaceObject *pg_GetDefaultWindowSurface(void)
+

Return a borrowed reference to the Pygame default window display surface, +or NULL if no default window is open.

+

Availability: SDL 2.

+
+ +
+
+void pg_SetDefaultWindowSurface(pgSurfaceObject *screen)
+

Replace the Pygame default display surface with object screen. +The previous surface object, if any, is invalidated. +Argument screen may be NULL. +This functions is called by pygame.display.set_mode().

+

Availability: SDL 2.

+
+ +
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/c_api/bufferproxy.html b/venv/Lib/site-packages/pygame/docs/generated/c_api/bufferproxy.html new file mode 100644 index 0000000..2b2b352 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/c_api/bufferproxy.html @@ -0,0 +1,183 @@ + + + + + + + + + Class BufferProxy API exported by pgyame.bufferproxy — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

src_c/bufferproxy.c

+

This extension module defines Python type pygame.BufferProxypygame object to export a surface buffer through an array protocol.

+

Header file: src_c/include/pygame_bufferproxy.h

+
+
+PyTypeObject *pgBufproxy_Type
+

The pygame buffer proxy object type pygame.BufferProxy.

+
+ +
+
+int pgBufproxy_Check(PyObject *x)
+

Return true if Python object x is a pygame.BufferProxy instance, +false otherwise. +This will return false on pygame.BufferProxy subclass instances as well.

+
+ +
+
+PyObject *pgBufproxy_New(PyObject *obj, getbufferproc get_buffer)
+

Return a new pygame.BufferProxy instance. +Argument obj is the Python object that has its data exposed. +It may be NULL. +Argument get_buffer is the pg_buffer get callback. +It must not be NULL. +On failure raise a Python error and return NULL.

+
+ +
+
+PyObject *pgBufproxy_GetParent(PyObject *obj)
+

Return the Python object wrapped by buffer proxy obj. +Argument obj must not be NULL. +On failure, raise a Python error and return NULL.

+
+ +
+
+int pgBufproxy_Trip(PyObject *obj)
+

Cause the buffer proxy object obj to create a pg_buffer view of its parent. +Argument obj must not be NULL. +Return 0 on success, otherwise raise a Python error and return -1.

+
+ +
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/c_api/cdrom.html b/venv/Lib/site-packages/pygame/docs/generated/c_api/cdrom.html new file mode 100644 index 0000000..07f524a --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/c_api/cdrom.html @@ -0,0 +1,178 @@ + + + + + + + + + API exported by pygame.cdrom — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

src_c/cdrom.c

+

The pygame.cdrompygame module for audio cdrom control extension module. Only available for SDL 1.

+

Header file: src_c/include/pygame.h

+
+
+type pgCDObject
+

The pygame.cdrom.CD instance C struct.

+
+ +
+
+PyTypeObject pgCD_Type
+

The pygame.cdrom.CD Python type.

+
+ +
+
+PyObject *pgCD_New(int id)
+

Return a new pygame.cdrom.CD instance for CD drive id. +On error raise a Python exception and return NULL.

+
+ +
+
+int pgCD_Check(PyObject *x)
+

Return true if x is a pygame.cdrom.CD instance. +Will return false for a subclass of CD. +This is a macro. No check is made that x is not NULL.

+
+ +
+
+int pgCD_AsID(PyObject *x)
+

Return the CD identifier associated with the pygame.cdrom.CD +instance x. +This is a macro. No check is made that x is a pygame.cdrom.CD +instance or is not NULL.

+
+ +
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/c_api/color.html b/venv/Lib/site-packages/pygame/docs/generated/c_api/color.html new file mode 100644 index 0000000..7fef935 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/c_api/color.html @@ -0,0 +1,172 @@ + + + + + + + + + Class Color API exported by pygame.color — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

src_c/color.c

+

This extension module defines the Python type pygame.Colorpygame object for color representations.

+

Header file: src_c/include/pygame.h

+
+
+PyTypeObject *pgColor_Type
+

The Pygame color object type pygame.Color.

+
+ +
+
+int pgColor_Check(PyObject *obj)
+

Return true if obj is an instance of type pgColor_Type, +but not a pgColor_Type subclass instance. +This macro does not check if obj is not NULL or indeed a Python type.

+
+ +
+
+PyObject *pgColor_New(Uint8 rgba[])
+

Return a new pygame.Color instance for the the four element array rgba. +On failure, raise a Python exception and return NULL.

+
+ +
+
+PyObject *pgColor_NewLength(Uint8 rgba[], Uint8 length)
+

Return a new pygame.Color instance having length elements, +with element values taken from the first length elements of array rgba. +Argument length must be between 1 and 4 inclusive. +On failure, raise a Python exception and return NULL.

+
+ +
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/c_api/display.html b/venv/Lib/site-packages/pygame/docs/generated/c_api/display.html new file mode 100644 index 0000000..c83184f --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/c_api/display.html @@ -0,0 +1,177 @@ + + + + + + + + + API exported by pygame.display — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

src_c/display.c

+

This is the pygame.displaypygame module to control the display window and screen extension module.

+

Header file: src_c/include/pygame.h

+
+
+type pgVidInfoObject
+

A pygame object that wraps an SDL_VideoInfo struct. +The object returned by pgyame.display.Info().

+
+ +
+
+PyTypeObject *pgVidInfo_Type
+

The pgVidInfoObject object Python type.

+
+ +
+
+SDL_VideoInfo pgVidInfo_AsVidInfo(PyObject *obj)
+

Return the SDL_VideoInfo field of obj, a pgVidInfo_Type instance. +This macro does not check that obj is not NULL or an actual pgVidInfoObject object.

+
+ +
+
+PyObject *pgVidInfo_New(SDL_VideoInfo *i)
+

Return a new pgVidInfoObject object for the SDL_VideoInfo i. +On failure, raise a Python exception and return NULL.

+
+ +
+
+int pgVidInfo_Check(PyObject *x)
+

Return true if x is a pgVidInfo_Type instance

+

Will return false if x is a subclass of pgVidInfo_Type. +This macro does not check that x is not NULL.

+
+ +
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/c_api/event.html b/venv/Lib/site-packages/pygame/docs/generated/c_api/event.html new file mode 100644 index 0000000..be5bf1d --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/c_api/event.html @@ -0,0 +1,192 @@ + + + + + + + + + API exported by pygame.event — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

src_c/event.c

+

The extsion module pygame.eventpygame module for interacting with events and queues.

+

Header file: src_c/include/pygame.h

+
+
+type pgEventObject
+

The pygame.event.EventType object C struct.

+
+
+int type
+

The event type code.

+
+ +
+ +
+
+type pgEvent_Type
+

The pygame event object type pygame.event.EventType.

+
+ +
+
+int pgEvent_Check(PyObject *x)
+

Return true if x is a pygame event instance

+

Will return false if x is a subclass of event. +This is a macro. No check is made that x is not NULL.

+
+ +
+
+PyObject *pgEvent_New(SDL_Event *event)
+

Return a new pygame event instance for the SDL event. +If event is NULL then create an empty event object. +On failure raise a Python exception and return NULL.

+
+ +
+
+PyObject *pgEvent_New2(int type, PyObject *dict)
+

Return a new pygame event instance of SDL type and with +attribute dictionary dict. +If dict is NULL an empty attribute dictionary is created. +On failure raise a Python exception and return NULL.

+
+ +
+
+int pgEvent_FillUserEvent(pgEventObject *e, SDL_Event *event)
+

Fill SDL event event with information from pygame user event instance e. +Return 0 on success, -1 otherwise.

+
+ +
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/c_api/freetype.html b/venv/Lib/site-packages/pygame/docs/generated/c_api/freetype.html new file mode 100644 index 0000000..db0f46a --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/c_api/freetype.html @@ -0,0 +1,180 @@ + + + + + + + + + API exported by pygame._freetype — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

src_c/_freetype.c

+

This extension module defines Python type pygame.freetype.FontCreate a new Font instance from a supported font file..

+

Header file: src_c/include/pygame_freetype.h

+
+
+type pgFontObject
+

The pygame.freetype.Font instance C struct.

+
+ +
+
+type pgFont_Type
+

The pygame.freetype.Font Python type.

+
+ +
+
+PyObject *pgFont_New(const char *filename, long font_index)
+

Open the font file with path filename and return a new +new pygame.freetype.Font instance for that font. +Set font_index to 0 unless the file contains multiple, indexed, fonts. +On error raise a Python exception and return NULL.

+
+ +
+
+int pgFont_Check(PyObject *x)
+

Return true if x is a pygame.freetype.Font instance. +Will return false for a subclass of Font. +This is a macro. No check is made that x is not NULL.

+
+ +
+
+int pgFont_IS_ALIVE(PyObject *o)
+

Return true if pygame.freetype.Font object o +is an open font file. +This is a macro. No check is made that o is not NULL +or not a Font instance.

+
+ +
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/c_api/mixer.html b/venv/Lib/site-packages/pygame/docs/generated/c_api/mixer.html new file mode 100644 index 0000000..2128b79 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/c_api/mixer.html @@ -0,0 +1,213 @@ + + + + + + + + + API exported by pygame.mixer — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

src_c/mixer.c

+

Python types and module startup/shutdown functions defined in the +pygame.mixerpygame module for loading and playing sounds extension module.

+

Header file: src_c/include/pygame_mixer.h

+
+
+type pgSoundObject
+

The pygame.mixer.Sound instance C structure.

+
+ +
+
+PyTypeObject *pgSound_Type
+

The pygame.mixer.Sound Python type.

+
+ +
+
+PyObject *pgSound_New(Mix_Chunk *chunk)
+

Return a new pygame.mixer.Sound instance for the SDL mixer chunk chunk. +On failure, raise a Python exception and return NULL.

+
+ +
+
+int pgSound_Check(PyObject *obj)
+

Return true if obj is an instance of type pgSound_Type, +but not a pgSound_Type subclass instance. +A macro.

+
+ +
+
+Mix_Chunk *pgSound_AsChunk(PyObject *x)
+

Return the SDL Mix_Chunk struct associated with the +pgSound_Type instance x. +A macro that does no NULL or Python type check on x.

+
+ +
+
+type pgChannelObject
+

The pygame.mixer.Channel instance C structure.

+
+ +
+
+PyTypeObject *pgChannel_Type
+

The pygame.mixer.Channel Python type.

+
+ +
+
+PyObject *pgChannel_New(int channelnum)
+

Return a new pygame.mixer.Channel instance for the SDL mixer +channel channelnum. +On failure, raise a Python exception and return NULL.

+
+ +
+
+int pgChannel_Check(PyObject *obj)
+

Return true if obj is an instance of type pgChannel_Type, +but not a pgChannel_Type subclass instance. +A macro.

+
+ +
+
+int pgChannel_AsInt(PyObject *x)
+

Return the SDL mixer music channel number associated with pgChannel_Type instance x. +A macro that does no NULL or Python type check on x.

+
+ +
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/c_api/rect.html b/venv/Lib/site-packages/pygame/docs/generated/c_api/rect.html new file mode 100644 index 0000000..21708e3 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/c_api/rect.html @@ -0,0 +1,202 @@ + + + + + + + + + Class Rect API exported by pygame.rect — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

src_c/rect.c

+

This extension module defines Python type pygame.Rectpygame object for storing rectangular coordinates.

+

Header file: src_c/include/pygame.h

+
+
+type pgRectObject
+
+
+SDL_Rect r
+
+ +

The Pygame rectangle type instance.

+
+ +
+
+PyTypeObject *pgRect_Type
+

The Pygame rectangle object type pygame.Rect.

+
+ +
+
+SDL_Rect pgRect_AsRect(PyObject *obj)
+

A macro to access the SDL_Rect field of a pygame.Rect instance.

+
+ +
+
+PyObject *pgRect_New(SDL_Rect *r)
+

Return a new pygame.Rect instance from the SDL_Rect r. +On failure, raise a Python exception and return NULL.

+
+ +
+
+PyObject *pgRect_New4(int x, int y, int w, int h)
+

Return a new pygame.Rect instance with position (x, y) and +size (w, h). +On failure raise a Python exception and return NULL.

+
+ +
+
+SDL_Rect *pgRect_FromObject(PyObject *obj, SDL_Rect *temp)
+

Translate a Python rectangle representation as a Pygame SDL_Rect. +A rectangle can be a length 4 sequence integers (x, y, w, h), +or a length 2 sequence of position (x, y) and size (w, h), +or a length 1 tuple containing a rectangle representation, +or have a method rect that returns a rectangle. +Pass a pointer to a locally declared SDL_Rect as temp. +Do not rely on this being filled in; use the function's return value instead. +On success, return a pointer to a SDL_Rect representation +of the rectangle, else return NULL. +No Python exceptions are raised.

+
+ +
+
+void pgRect_Normalize(SDL_Rect *rect)
+

Normalize the given rect. A rect with a negative size (negative width and/or +height) will be adjusted to have a positive size.

+
+ +
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/c_api/rwobject.html b/venv/Lib/site-packages/pygame/docs/generated/c_api/rwobject.html new file mode 100644 index 0000000..f767e41 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/c_api/rwobject.html @@ -0,0 +1,207 @@ + + + + + + + + + API exported by pygame.rwobject — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

src_c/rwobject.c

+

This extension module implements functions for wrapping a Python file like +object in a SDL_RWops struct for SDL file access.

+

Header file: src_c/include/pygame.h

+
+
+SDL_RWops *pgRWops_FromObject(PyObject *obj)
+

Return a SDL_RWops struct filled to access obj. +If obj is a string then let SDL open the file it names. +Otherwise, if obj is a Python file-like object then use its read, write, +seek, tell, and close methods. If threads are available, +the Python GIL is acquired before calling any of the obj methods. +On error raise a Python exception and return NULL.

+
+ +
+
+SDL_RWops *pgRWops_FromFileObject(PyObject *obj)
+

Return a SDL_RWops struct filled to access the Python file-like object obj. +Uses its read, write, seek, tell, and close methods. +If threads are available, the Python GIL is acquired before calling any of the obj methods. +On error raise a Python exception and return NULL.

+
+ +
+
+int pgRWops_IsFileObject(SDL_RWops *rw)
+

Return true if rw is a Python file-like object wrapper returned by pgRWops_FromObject() +or pgRWops_FromFileObject().

+
+ +
+
+char *pgRWops_GetFileExtension(SDL_RWops *rw)
+

Return a string that contains the file extension of the original file +loaded into the SDL_RWops object, or NULL if the SDL_RWops object comes +from a file object.

+
+ +
+
+int pgRWops_ReleaseObject(SDL_RWops *context)
+

Free a SDL_RWops struct. If it is attached to a Python file-like object, decrement its +refcount. Otherwise, close the file handle. +Return 0 on success. On error, raise a Python exception and return a negative value.

+
+ +
+
+PyObject *pg_EncodeFilePath(PyObject *obj, PyObject *eclass)
+

Return the file path obj as a byte string properly encoded for the OS. +Null bytes are forbidden in the encoded file path. +On error raise a Python exception and return NULL, +using eclass as the exception type if it is not NULL. +If obj is NULL assume an exception was already raised and pass it on.

+
+ +
+
+PyObject *pg_EncodeString(PyObject *obj, const char *encoding, const char *errors, PyObject *eclass)
+

Return string obj as an encoded byte string. +The C string arguments encoding and errors are the same as for +PyUnicode_AsEncodedString(). +On error raise a Python exception and return NULL, +using eclass as the exception type if it is not NULL. +If obj is NULL assume an exception was already raised and pass it on.

+
+ +
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/c_api/slots.html b/venv/Lib/site-packages/pygame/docs/generated/c_api/slots.html new file mode 100644 index 0000000..852765d --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/c_api/slots.html @@ -0,0 +1,157 @@ + + + + + + + + + Slots and c_api - Making functions and data available from other modules — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+

One example is pg_RGBAFromObj where the implementation is defined in base.c, and also exported in base.c (and _pygame.h).

+

base.c has this exposing the pg_RGBAFromObj function to the c_api structure:

+
+

c_api[12] = pg_RGBAFromObj;

+
+

Then in src_c/include/_pygame.h there is an

+
+

#define pg_RGBAFromObj.

+
+

Also in _pygame.h, it needs to define the number of slots the base module uses. This is PYGAMEAPI_BASE_NUMSLOTS. So if you were adding another function, you need to increment this PYGAMEAPI_BASE_NUMSLOTS number.

+

Then to use the pg_RGBAFromObj in other files,

+
    +
  1. include the "pygame.h" file,

  2. +
  3. they have to make sure base is imported with:

    +
    +

    import_pygame_base();

    +
    +
  4. +
+

Examples that use pg_RGBAFromObj are: _freetype.c, color.c, gfxdraw.c, and surface.c.

+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/c_api/surface.html b/venv/Lib/site-packages/pygame/docs/generated/c_api/surface.html new file mode 100644 index 0000000..4013702 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/c_api/surface.html @@ -0,0 +1,194 @@ + + + + + + + + + Class Surface API exported by pygame.surface — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

src_c/surface.c

+

This extension module defines Python type pygame.Surfacepygame object for representing images.

+

Header file: src_c/include/pygame.h

+
+
+type pgSurfaceObject
+

A pygame.Surface instance.

+
+ +
+
+PyTypeObject *pgSurface_Type
+

The pygame.Surface Python type.

+
+ +
+
+int pgSurface_Check(PyObject *x)
+

Return true if x is a pygame.Surface instance

+

Will return false if x is a subclass of Surface. +This is a macro. No check is made that x is not NULL.

+
+ +
+
+pgSurfaceObject *pgSurface_New(SDL_Surface *s)
+

Return a new new pygame surface instance for SDL surface s. +Return NULL on error.

+
+ +
+
+SDL_Surface *pgSurface_AsSurface(PyObject *x)
+

Return a pointer the SDL surface represented by the pygame Surface instance +x.

+

This is a macro. Argument x is assumed to be a Surface, or subclass of +Surface, instance.

+
+ +
+
+int pgSurface_Blit(PyObject *dstobj, PyObject *srcobj, SDL_Rect *dstrect, SDL_Rect *srcrect, int the_args)
+

Blit the srcrect portion of Surface srcobj onto Surface dstobj at srcobj

+

Argument the_args indicates the type of blit to perform: +Normal blit (0), PYGAME_BLEND_ADD, PYGAME_BLEND_SUB, +PYGAME_BLEND_SUB, PYGAME_BLEND_MULT, PYGAME_BLEND_MIN, +PYGAME_BLEND_MAX, PYGAME_BLEND_RGBA_ADD, PYGAME_BLEND_RGBA_SUB, +PYGAME_BLEND_RGBA_MULT, PYGAME_BLEND_RGBA_MIN, +PYGAME_BLEND_RGBA_MAX, PYGAME_BLEND_ALPHA_SDL2 and PYGAME_BLEND_PREMULTIPLIED. +Argument dstrect is updated to the actual area on dstobj affected +by the blit.

+

The C version of the pygame.Surface.blit() method. +Return 1 on success, 0 on an exception.

+
+ +
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/c_api/surflock.html b/venv/Lib/site-packages/pygame/docs/generated/c_api/surflock.html new file mode 100644 index 0000000..f25e3b4 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/c_api/surflock.html @@ -0,0 +1,231 @@ + + + + + + + + + API exported by pygame.surflock — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

src_c/surflock.c

+

This extension module implements SDL surface locking for the +pygame.Surfacepygame object for representing images type.

+

Header file: src_c/include/pygame.h

+
+
+type pgLifetimeLockObject
+
+
+PyObject *surface
+

An SDL locked pygame surface.

+
+ +
+
+PyObject *lockobj
+

The Python object which owns the lock on the surface. +This field does not own a reference to the object.

+
+ +

The lifetime lock type instance. +A lifetime lock pairs a locked pygame surface with +the Python object that locked the surface for modification. +The lock is removed automatically when the lifetime lock instance +is garbage collected.

+
+ +
+
+PyTypeObject *pgLifetimeLock_Type
+

The pygame internal surflock lifetime lock object type.

+
+ +
+
+int pgLifetimeLock_Check(PyObject *x)
+

Return true if Python object x is a pgLifetimeLock_Type instance, +false otherwise. +This will return false on pgLifetimeLock_Type subclass instances as well.

+
+ +
+
+void pgSurface_Prep(pgSurfaceObject *surfobj)
+

If surfobj is a subsurface, then lock the parent surface with surfobj +the owner of the lock.

+
+ +
+
+void pgSurface_Unprep(pgSurfaceObject *surfobj)
+

If surfobj is a subsurface, then release its lock on the parent surface.

+
+ +
+
+int pgSurface_Lock(pgSurfaceObject *surfobj)
+

Lock pygame surface surfobj, with surfobj owning its own lock.

+
+ +
+
+int pgSurface_LockBy(pgSurfaceObject *surfobj, PyObject *lockobj)
+

Lock pygame surface surfobj with Python object lockobj the owning +the lock.

+

The surface will keep a weak reference to object lockobj, +and eventually remove the lock on itself if lockobj is garbage collected. +However, it is best if lockobj also keep a reference to the locked surface +and call to pgSurface_UnLockBy() when finished with the surface.

+
+ +
+
+int pgSurface_UnLock(pgSurfaceObject *surfobj)
+

Remove the pygame surface surfobj object's lock on itself.

+
+ +
+
+int pgSurface_UnLockBy(pgSurfaceObject *surfobj, PyObject *lockobj)
+

Remove the lock on pygame surface surfobj owned by Python object lockobj.

+
+ +
+
+PyObject *pgSurface_LockLifetime(PyObject *surfobj, PyObject *lockobj)
+

Lock pygame surface surfobj for Python object lockobj and return a +new pgLifetimeLock_Type instance for the lock.

+

This function is not called anywhere within pygame. +It and pgLifetimeLock_Type are candidates for removal.

+
+ +
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/c_api/version.html b/venv/Lib/site-packages/pygame/docs/generated/c_api/version.html new file mode 100644 index 0000000..e05ad33 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/c_api/version.html @@ -0,0 +1,173 @@ + + + + + + + + + API exported by pygame.version — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

src_py/version.py

+

Header file: src_c/include/pygame.h

+

Version information can be retrieved at compile-time using these macros.

+
+

New in pygame 1.9.5.

+
+
+
+PG_MAJOR_VERSION
+
+ +
+
+PG_MINOR_VERSION
+
+ +
+
+PG_PATCH_VERSION
+
+ +
+
+PG_VERSIONNUM(MAJOR, MINOR, PATCH)
+

Returns an integer representing the given version.

+
+ +
+
+PG_VERSION_ATLEAST(MAJOR, MINOR, PATCH)
+

Returns true if the current version is at least equal +to the specified version.

+
+ +
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/filepaths.html b/venv/Lib/site-packages/pygame/docs/generated/filepaths.html new file mode 100644 index 0000000..be6419c --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/filepaths.html @@ -0,0 +1,145 @@ + + + + + + + + + File Path Function Arguments — pygame v2.1.2 documentation + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+

A pygame function or method which takes a file path argument will accept +either a Unicode or a byte (8-bit or ASCII character) string. +Unicode strings are translated to Python's default filesystem encoding, +as returned by sys.getfilesystemencoding(). A Unicode code point +above U+FFFF (\uFFFF) can be coded directly with a 32-bit escape sequences +(\Uxxxxxxxx), even for Python interpreters built with an UCS-2 +(16-bit character) Unicode type. Byte strings are passed +to the operating system unchanged.

+

Null characters (\x00) are not permitted in the path, raising an exception. +An exception is also raised if an Unicode file path cannot be encoded. +How UTF-16 surrogate codes are handled is Python-interpreter-dependent. +Use UTF-32 code points and 32-bit escape sequences instead. +The exception types are function-dependent.

+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/genindex.html b/venv/Lib/site-packages/pygame/docs/generated/genindex.html new file mode 100644 index 0000000..45d036c --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/genindex.html @@ -0,0 +1,2604 @@ + + + + + + + + Index — pygame v2.1.2 documentation + + + + + + + + + + + + +
+
+
+ + +

Index

+ +
+ _ + | A + | B + | C + | D + | E + | F + | G + | H + | I + | J + | K + | L + | M + | N + | O + | P + | Q + | R + | S + | T + | U + | V + | W + +
+

_

+ + + +
+ +

A

+ + + +
+ +

B

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

H

+ + + +
+ +

I

+ + + +
+ +

J

+ + + +
+ +

K

+ + + +
+ +

L

+ + + +
+ +

M

+ + + +
+ +

N

+ + + +
+ +

O

+ + + +
+ +

P

+ + + +
+ +

Q

+ + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + + +
+ +

V

+ + + +
+ +

W

+ + + +
+ + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/index.html b/venv/Lib/site-packages/pygame/docs/generated/index.html new file mode 100644 index 0000000..6cc1417 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/index.html @@ -0,0 +1,258 @@ + + + + + + + + + Pygame Front Page — pygame v2.1.2 documentation + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+

Pygame Front Page

+
+
+
+

Documents

+
+
Readme

Basic information about pygame: what it is, who is involved, and where to find it.

+
+
Install

Steps needed to compile pygame on several platforms. +Also help on finding and installing prebuilt binaries for your system.

+
+
File Path Function Arguments

How pygame handles file system paths.

+
+
LGPL License

This is the license pygame is distributed under. +It provides for pygame to be distributed with open source and commercial software. +Generally, if pygame is not changed, it can be used with any type of program.

+
+
+
+
+

Tutorials

+
+
Introduction to Pygame

An introduction to the basics of pygame. +This is written for users of Python and appeared in volume two of the Py magazine.

+
+
Import and Initialize

The beginning steps on importing and initializing pygame. +The pygame package is made of several modules. +Some modules are not included on all platforms.

+
+
How do I move an Image?

A basic tutorial that covers the concepts behind 2D computer animation. +Information about drawing and clearing objects to make them appear animated.

+
+
Chimp Tutorial, Line by Line

The pygame examples include a simple program with an interactive fist and a chimpanzee. +This was inspired by the annoying flash banner of the early 2000s. +This tutorial examines every line of code used in the example.

+
+
Sprite Module Introduction

Pygame includes a higher level sprite module to help organize games. +The sprite module includes several classes that help manage details found in almost all games types. +The Sprite classes are a bit more advanced than the regular pygame modules, +and need more understanding to be properly used.

+
+
Surfarray Introduction

Pygame used the NumPy python module to allow efficient per pixel effects on images. +Using the surface arrays is an advanced feature that allows custom effects and filters. +This also examines some of the simple effects from the pygame example, arraydemo.py.

+
+
Camera Module Introduction

Pygame, as of 1.9, has a camera module that allows you to capture images, +watch live streams, and do some basic computer vision. +This tutorial covers those use cases.

+
+
Newbie Guide

A list of thirteen helpful tips for people to get comfortable using pygame.

+
+
Making Games Tutorial

A large tutorial that covers the bigger topics needed to create an entire game.

+
+
Display Modes

Getting a display surface for the screen.

+
+
한국어 튜토리얼 (Korean Tutorial)

빨간블록 검은블록

+
+
+
+
+

Reference

+
+
Index

A list of all functions, classes, and methods in the pygame package.

+
+
pygame.BufferProxy

An array protocol view of surface pixels

+
+
pygame.Color

Color representation.

+
+
pygame.cursors

Loading and compiling cursor images.

+
+
pygame.display

Configure the display surface.

+
+
pygame.draw

Drawing simple shapes like lines and ellipses to surfaces.

+
+
pygame.event

Manage the incoming events from various input devices and the windowing platform.

+
+
pygame.examples

Various programs demonstrating the use of individual pygame modules.

+
+
pygame.font

Loading and rendering TrueType fonts.

+
+
pygame.freetype

Enhanced pygame module for loading and rendering font faces.

+
+
pygame.gfxdraw

Anti-aliasing draw functions.

+
+
pygame.image

Loading, saving, and transferring of surfaces.

+
+
pygame.joystick

Manage the joystick devices.

+
+
pygame.key

Manage the keyboard device.

+
+
pygame.locals

Pygame constants.

+
+
pygame.mixer

Load and play sounds

+
+
pygame.mouse

Manage the mouse device and display.

+
+
pygame.mixer.music

Play streaming music tracks.

+
+
pygame

Top level functions to manage pygame.

+
+
pygame.PixelArray

Manipulate image pixel data.

+
+
pygame.Rect

Flexible container for a rectangle.

+
+
pygame.scrap

Native clipboard access.

+
+
pygame.sndarray

Manipulate sound sample data.

+
+
pygame.sprite

Higher level objects to represent game images.

+
+
pygame.Surface

Objects for images and the screen.

+
+
pygame.surfarray

Manipulate image pixel data.

+
+
pygame.tests

Test pygame.

+
+
pygame.time

Manage timing and framerate.

+
+
pygame.transform

Resize and move images.

+
+
pygame C API

The C api shared amongst pygame extension modules.

+
+
Search Page

Search pygame documents by keyword.

+
+
+
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/py-modindex.html b/venv/Lib/site-packages/pygame/docs/generated/py-modindex.html new file mode 100644 index 0000000..45a5aa1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/py-modindex.html @@ -0,0 +1,251 @@ + + + + + + + + Python Module Index — pygame v2.1.2 documentation + + + + + + + + + + + + + + + +
+
+
+ + +

Python Module Index

+ +
+ . | + p +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ .
    + pygame._sdl2.controller + pygame module to work with controllers
    + pygame._sdl2.touch + pygame module to work with touch input
    + pygame._sdl2.video + Experimental pygame module for porting new SDL video systems
    + pygame.camera + pygame module for camera use
    + pygame.cdrom + pygame module for audio cdrom control
    + pygame.cursors + pygame module for cursor resources
    + pygame.display + pygame module to control the display window and screen
    + pygame.draw + pygame module for drawing shapes
    + pygame.event + pygame module for interacting with events and queues
    + pygame.examples + module of example programs
    + pygame.fastevent + pygame module for interacting with events and queues from multiple +threads.
    + pygame.font + pygame module for loading and rendering fonts
    + pygame.freetype + Enhanced pygame module for loading and rendering computer fonts
    + pygame.gfxdraw + pygame module for drawing shapes
    + pygame.image + pygame module for image transfer
    + pygame.joystick + Pygame module for interacting with joysticks, gamepads, and trackballs.
    + pygame.key + pygame module to work with the keyboard
    + pygame.locals + pygame constants
    + pygame.mask + pygame module for image masks.
    + pygame.math + pygame module for vector classes
    + pygame.midi + pygame module for interacting with midi input and output.
    + pygame.mixer + pygame module for loading and playing sounds
    + pygame.mixer.music + pygame module for controlling streamed audio
    + pygame.mouse + pygame module to work with the mouse
    + pygame.pixelcopy + pygame module for general pixel array copying
    + pygame.scrap + pygame module for clipboard support.
    + pygame.sndarray + pygame module for accessing sound sample data
    + pygame.sprite + pygame module with basic game object classes
    + pygame.surfarray + pygame module for accessing surface pixel data using array interfaces
    + pygame.tests + Pygame unit test suite package
    + pygame.time + pygame module for monitoring time
    + pygame.transform + pygame module to transform surfaces
    + pygame.version + small module containing version information
 
+ p
+ pygame + the top level pygame package
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/bufferproxy.html b/venv/Lib/site-packages/pygame/docs/generated/ref/bufferproxy.html new file mode 100644 index 0000000..d41ad94 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/bufferproxy.html @@ -0,0 +1,283 @@ + + + + + + + + + pygame.BufferProxy — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.BufferProxy
+
+
pygame object to export a surface buffer through an array protocol
+
BufferProxy(<parent>) -> BufferProxy
+
+ +++++ + + + + + + + + + + + + + + + + + + +
+Return wrapped exporting object.
+The size, in bytes, of the exported buffer.
+A copy of the exported buffer as a single block of bytes.
+Write raw bytes to object buffer.
+

BufferProxy is a pygame support type, designed as the return value +of the Surface.get_buffer() and Surface.get_view() methods. +For all Python versions a BufferProxy object exports a C struct +and Python level array interface on behalf of its parent object's buffer. +A new buffer interface is also exported. +In pygame, BufferProxy is key to implementing the +pygame.surfarraypygame module for accessing surface pixel data using array interfaces module.

+

BufferProxy instances can be created directly from Python code, +either for a parent that exports an interface, or from a Python dict +describing an object's buffer layout. The dict entries are based on the +Python level array interface mapping. The following keys are recognized:

+
+
+
"shape"tuple

The length of each array dimension as a tuple of integers. The +length of the tuple is the number of dimensions in the array.

+
+
"typestr"string

The array element type as a length 3 string. The first character +gives byteorder, '<' for little-endian, '>' for big-endian, and +'|' for not applicable. The second character is the element type, +'i' for signed integer, 'u' for unsigned integer, 'f' for floating +point, and 'V' for an chunk of bytes. The third character gives the +bytesize of the element, from '1' to '9' bytes. So, for example, +"<u4" is an unsigned 4 byte little-endian integer, such as a +32 bit pixel on a PC, while "|V3" would represent a 24 bit pixel, +which has no integer equivalent.

+
+
"data"tuple

The physical buffer start address and a read-only flag as a length +2 tuple. The address is an integer value, while the read-only flag +is a bool—False for writable, True for read-only.

+
+
"strides"tuple(optional)

Array stride information as a tuple of integers. It is required +only of non C-contiguous arrays. The tuple length must match +that of "shape".

+
+
"parent"object(optional)

The exporting object. It can be used to keep the parent object +alive while its buffer is visible.

+
+
"before"callable(optional)

Callback invoked when the BufferProxy instance +exports the buffer. The callback is given one argument, the +"parent" object if given, otherwise None. +The callback is useful for setting a lock on the parent.

+
+
"after"callable(optional)

Callback invoked when an exported buffer is released. +The callback is passed on argument, the "parent" object if given, +otherwise None. The callback is useful for releasing a lock on the +parent.

+
+
+
+

The BufferProxy class supports subclassing, instance variables, and weak +references.

+
+

New in pygame 1.8.0.

+
+
+

Extended in pygame 1.9.2.

+
+
+
+parent
+
+
Return wrapped exporting object.
+
parent -> Surface
+
parent -> <parent>
+
+

The Surface which returned the BufferProxy object or +the object passed to a BufferProxy call.

+
+ +
+
+length
+
+
The size, in bytes, of the exported buffer.
+
length -> int
+
+

The number of valid bytes of data exported. For discontinuous data, +that is data which is not a single block of memory, the bytes within +the gaps are excluded from the count. This property is equivalent to +the Py_buffer C struct len field.

+
+ +
+
+raw
+
+
A copy of the exported buffer as a single block of bytes.
+
raw -> bytes
+
+

The buffer data as a str/bytes object. +Any gaps in the exported data are removed.

+
+ +
+
+write()
+
+
Write raw bytes to object buffer.
+
write(buffer, offset=0)
+
+

Overwrite bytes in the parent object's data. The data must be C or F +contiguous, otherwise a ValueError is raised. Argument buffer is a +str/bytes object. An optional offset gives a +start position, in bytes, within the buffer where overwriting begins. +If the offset is negative or greater that or equal to the buffer proxy's +length value, an IndexException is raised. +If len(buffer) > proxy.length + offset, a ValueError is raised.

+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/camera.html b/venv/Lib/site-packages/pygame/docs/generated/ref/camera.html new file mode 100644 index 0000000..1ee0b29 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/camera.html @@ -0,0 +1,472 @@ + + + + + + + + + pygame.camera — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.camera
+
+
pygame module for camera use
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + +
+Module init
+Get the backends supported on this system
+Surface colorspace conversion
+returns a list of available cameras
+load a camera
+

Pygame currently supports Linux (V4L2) and Windows (MSMF) cameras natively, +with wider platform support available via an integrated OpenCV backend.

+
+

New in pygame 2.0.2: Windows native camera support

+
+
+

New in pygame 2.0.3: New OpenCV backends

+
+

EXPERIMENTAL!: This API may change or disappear in later pygame releases. If +you use this, your code will very likely break with the next pygame release.

+

The Bayer to RGB function is based on:

+
Sonix SN9C101 based webcam basic I/F routines
+Copyright (C) 2004 Takafumi Mizuno <taka-qce@ls-a.jp>
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+
+

New in pygame 1.9.0.

+
+
+pygame.camera.init()
+
+
Module init
+
init(backend = None) -> None
+
+

This function starts up the camera module, choosing the best webcam backend +it can find for your system. This is not guaranteed to succeed, and may even +attempt to import third party modules, like OpenCV. If you want to +override its backend choice, you can call pass the name of the backend you +want into this function. More about backends in +get_backends().

+
+

Changed in pygame 2.0.3: Option to explicitly select backend

+
+
+ +
+
+pygame.camera.get_backends()
+
+
Get the backends supported on this system
+
get_backends() -> [str]
+
+

This function returns every backend it thinks has a possibility of working +on your system, in order of priority.

+

pygame.camera Backends:

+
Backend           OS        Description
+---------------------------------------------------------------------------------
+_camera (MSMF)    Windows   Builtin, works on Windows 8+ Python3
+_camera (V4L2)    Linux     Builtin
+OpenCV            Any       Uses `opencv-python` module, can't enumerate cameras
+OpenCV-Mac        Mac       Same as OpenCV, but has camera enumeration
+VideoCapture      Windows   Uses abandoned `VideoCapture` module, can't enumerate
+                            cameras, may be removed in the future
+
+
+

There are two main differences among backends.

+

The _camera backends are built in to pygame itself, and require no third +party imports. All the other backends do. For the OpenCV and VideoCapture +backends, those modules need to be installed on your system.

+

The other big difference is "camera enumeration." Some backends don't have +a way to list out camera names, or even the number of cameras on the +system. In these cases, list_cameras() will return +something like [0]. If you know you have multiple cameras on the +system, these backend ports will pass through a "camera index number" +through if you use that as the device parameter.

+
+

New in pygame 2.0.3.

+
+
+ +
+
+pygame.camera.colorspace()
+
+
Surface colorspace conversion
+
colorspace(Surface, format, DestSurface = None) -> Surface
+
+

Allows for conversion from "RGB" to a destination colorspace of "HSV" or +"YUV". The source and destination surfaces must be the same size and pixel +depth. This is useful for computer vision on devices with limited processing +power. Capture as small of an image as possible, transform.scale() it +even smaller, and then convert the colorspace to YUV or HSV before +doing any processing on it.

+
+ +
+
+pygame.camera.list_cameras()
+
+
returns a list of available cameras
+
list_cameras() -> [cameras]
+
+

Checks the computer for available cameras and returns a list of strings of +camera names, ready to be fed into pygame.camera.Cameraload a camera.

+

If the camera backend doesn't support webcam enumeration, this will return +something like [0]. See get_backends() for much more +information.

+
+ +
+
+pygame.camera.Camera
+
+
load a camera
+
Camera(device, (width, height), format) -> Camera
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+opens, initializes, and starts capturing
+stops, uninitializes, and closes the camera
+gets current values of user controls
+changes camera settings if supported by the camera
+returns the dimensions of the images being recorded
+checks if a frame is ready
+captures an image as a Surface
+returns an unmodified image as bytes
+

Loads a camera. On Linux, the device is typically something like +"/dev/video0". Default width and height are 640 by 480. +Format is the desired colorspace of the output. +This is useful for computer vision purposes. The default is +RGB. The following are supported:

+
+
    +
  • RGB - Red, Green, Blue

  • +
  • YUV - Luma, Blue Chrominance, Red Chrominance

  • +
  • HSV - Hue, Saturation, Value

  • +
+
+
+
+start()
+
+
opens, initializes, and starts capturing
+
start() -> None
+
+

Opens the camera device, attempts to initialize it, and begins recording +images to a buffer. The camera must be started before any of the below +functions can be used.

+
+ +
+
+stop()
+
+
stops, uninitializes, and closes the camera
+
stop() -> None
+
+

Stops recording, uninitializes the camera, and closes it. Once a camera +is stopped, the below functions cannot be used until it is started again.

+
+ +
+
+get_controls()
+
+
gets current values of user controls
+
get_controls() -> (hflip = bool, vflip = bool, brightness)
+
+

If the camera supports it, get_controls will return the current settings +for horizontal and vertical image flip as bools and brightness as an int. +If unsupported, it will return the default values of (0, 0, 0). Note that +the return values here may be different than those returned by +set_controls, though these are more likely to be correct.

+
+ +
+
+set_controls()
+
+
changes camera settings if supported by the camera
+
set_controls(hflip = bool, vflip = bool, brightness) -> (hflip = bool, vflip = bool, brightness)
+
+

Allows you to change camera settings if the camera supports it. The +return values will be the input values if the camera claims it succeeded +or the values previously in use if not. Each argument is optional, and +the desired one can be chosen by supplying the keyword, like hflip. Note +that the actual settings being used by the camera may not be the same as +those returned by set_controls. On Windows, hflip and vflip are +implemented by pygame, not by the Camera, so they should always work, but +brightness is unsupported.

+
+ +
+
+get_size()
+
+
returns the dimensions of the images being recorded
+
get_size() -> (width, height)
+
+

Returns the current dimensions of the images being captured by the +camera. This will return the actual size, which may be different than the +one specified during initialization if the camera did not support that +size.

+
+ +
+
+query_image()
+
+
checks if a frame is ready
+
query_image() -> bool
+
+

If an image is ready to get, it returns true. Otherwise it returns false. +Note that some webcams will always return False and will only queue a +frame when called with a blocking function like get_image(). +On Windows (MSMF), and the OpenCV backends, query_image() +should be reliable, though. This is useful to separate the framerate of +the game from that of the camera without having to use threading.

+
+ +
+
+get_image()
+
+
captures an image as a Surface
+
get_image(Surface = None) -> Surface
+
+

Pulls an image off of the buffer as an RGB Surface. It can optionally +reuse an existing Surface to save time. The bit-depth of the surface is +24 bits on Linux, 32 bits on Windows, or the same as the optionally +supplied Surface.

+
+ +
+
+get_raw()
+
+
returns an unmodified image as bytes
+
get_raw() -> bytes
+
+

Gets an image from a camera as a string in the native pixelformat of the +camera. Useful for integration with other libraries. This returns a +bytes object

+
+ +
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/cdrom.html b/venv/Lib/site-packages/pygame/docs/generated/ref/cdrom.html new file mode 100644 index 0000000..8cdfa31 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/cdrom.html @@ -0,0 +1,592 @@ + + + + + + + + + pygame.cdrom — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.cdrom
+
+
pygame module for audio cdrom control
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + +
+initialize the cdrom module
+uninitialize the cdrom module
+true if the cdrom module is initialized
+number of cd drives on the system
+class to manage a cdrom drive
+
+

Warning

+

This module is non functional in pygame 2.0 and above, unless you have manually compiled pygame with SDL1. +This module will not be supported in the future. +One alternative for python cdrom functionality is pycdio.

+
+

The cdrom module manages the CD and DVD drives on a computer. It can +also control the playback of audio CDs. This module needs to be initialized +before it can do anything. Each CD object you create represents a cdrom +drive and must also be initialized individually before it can do most things.

+
+
+pygame.cdrom.init()
+
+
initialize the cdrom module
+
init() -> None
+
+

Initialize the cdrom module. This will scan the system for all CD +devices. The module must be initialized before any other functions will +work. This automatically happens when you call pygame.init().

+

It is safe to call this function more than once.

+
+ +
+
+pygame.cdrom.quit()
+
+
uninitialize the cdrom module
+
quit() -> None
+
+

Uninitialize the cdrom module. After you call this any existing CD +objects will no longer work.

+

It is safe to call this function more than once.

+
+ +
+
+pygame.cdrom.get_init()
+
+
true if the cdrom module is initialized
+
get_init() -> bool
+
+

Test if the cdrom module is initialized or not. This is different than the +CD.init() since each drive must also be initialized individually.

+
+ +
+
+pygame.cdrom.get_count()
+
+
number of cd drives on the system
+
get_count() -> count
+
+

Return the number of cd drives on the system. When you create CD objects +you need to pass an integer id that must be lower than this count. The count +will be 0 if there are no drives on the system.

+
+ +
+
+pygame.cdrom.CD
+
+
class to manage a cdrom drive
+
CD(id) -> CD
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+initialize a cdrom drive for use
+uninitialize a cdrom drive for use
+true if this cd device initialized
+start playing audio
+stop audio playback
+temporarily stop audio playback
+unpause audio playback
+eject or open the cdrom drive
+the index of the cdrom drive
+the system name of the cdrom drive
+true if the drive is playing audio
+true if the drive is paused
+the current audio playback position
+False if a cdrom is in the drive
+the number of tracks on the cdrom
+true if the cdrom track has audio data
+get all track information
+start time of a cdrom track
+length of a cdrom track
+

You can create a CD object for each cdrom on the system. Use +pygame.cdrom.get_count() to determine how many drives actually exist. +The id argument is an integer of the drive, starting at zero.

+

The CD object is not initialized, you can only call CD.get_id() and +CD.get_name() on an uninitialized drive.

+

It is safe to create multiple CD objects for the same drive, they will +all cooperate normally.

+
+
+init()
+
+
initialize a cdrom drive for use
+
init() -> None
+
+

Initialize the cdrom drive for use. The drive must be initialized for +most CD methods to work. Even if the rest of pygame has been +initialized.

+

There may be a brief pause while the drive is initialized. Avoid +CD.init() if the program should not stop for a second or two.

+
+ +
+
+quit()
+
+
uninitialize a cdrom drive for use
+
quit() -> None
+
+

Uninitialize a drive for use. Call this when your program will not be +accessing the drive for awhile.

+
+ +
+
+get_init()
+
+
true if this cd device initialized
+
get_init() -> bool
+
+

Test if this CDROM device is initialized. This is different than the +pygame.cdrom.init() since each drive must also be initialized +individually.

+
+ +
+
+play()
+
+
start playing audio
+
play(track, start=None, end=None) -> None
+
+

Playback audio from an audio cdrom in the drive. Besides the track number +argument, you can also pass a starting and ending time for playback. The +start and end time are in seconds, and can limit the section of an audio +track played.

+

If you pass a start time but no end, the audio will play to the end of +the track. If you pass a start time and 'None' for the end time, the +audio will play to the end of the entire disc.

+

See the CD.get_numtracks() and CD.get_track_audio() to find +tracks to playback.

+

Note, track 0 is the first track on the CD. Track numbers start at +zero.

+
+ +
+
+stop()
+
+
stop audio playback
+
stop() -> None
+
+

Stops playback of audio from the cdrom. This will also lose the current +playback position. This method does nothing if the drive isn't already +playing audio.

+
+ +
+
+pause()
+
+
temporarily stop audio playback
+
pause() -> None
+
+

Temporarily stop audio playback on the CD. The playback can be +resumed at the same point with the CD.resume() method. If the CD +is not playing this method does nothing.

+

Note, track 0 is the first track on the CD. Track numbers start at +zero.

+
+ +
+
+resume()
+
+
unpause audio playback
+
resume() -> None
+
+

Unpause a paused CD. If the CD is not paused or already playing, +this method does nothing.

+
+ +
+
+eject()
+
+
eject or open the cdrom drive
+
eject() -> None
+
+

This will open the cdrom drive and eject the cdrom. If the drive is +playing or paused it will be stopped.

+
+ +
+
+get_id()
+
+
the index of the cdrom drive
+
get_id() -> id
+
+

Returns the integer id that was used to create the CD instance. This +method can work on an uninitialized CD.

+
+ +
+
+get_name()
+
+
the system name of the cdrom drive
+
get_name() -> name
+
+

Return the string name of the drive. This is the system name used to +represent the drive. It is often the drive letter or device name. This +method can work on an uninitialized CD.

+
+ +
+
+get_busy()
+
+
true if the drive is playing audio
+
get_busy() -> bool
+
+

Returns True if the drive busy playing back audio.

+
+ +
+
+get_paused()
+
+
true if the drive is paused
+
get_paused() -> bool
+
+

Returns True if the drive is currently paused.

+
+ +
+
+get_current()
+
+
the current audio playback position
+
get_current() -> track, seconds
+
+

Returns both the current track and time of that track. This method works +when the drive is either playing or paused.

+

Note, track 0 is the first track on the CD. Track numbers start at +zero.

+
+ +
+
+get_empty()
+
+
False if a cdrom is in the drive
+
get_empty() -> bool
+
+

Return False if there is a cdrom currently in the drive. If the drive is +empty this will return True.

+
+ +
+
+get_numtracks()
+
+
the number of tracks on the cdrom
+
get_numtracks() -> count
+
+

Return the number of tracks on the cdrom in the drive. This will return +zero of the drive is empty or has no tracks.

+
+ +
+
+get_track_audio()
+
+
true if the cdrom track has audio data
+
get_track_audio(track) -> bool
+
+

Determine if a track on a cdrom contains audio data. You can also call +CD.num_tracks() and CD.get_all() to determine more information +about the cdrom.

+

Note, track 0 is the first track on the CD. Track numbers start at +zero.

+
+ +
+
+get_all()
+
+
get all track information
+
get_all() -> [(audio, start, end, length), ...]
+
+

Return a list with information for every track on the cdrom. The +information consists of a tuple with four values. The audio value is True +if the track contains audio data. The start, end, and length values are +floating point numbers in seconds. Start and end represent absolute times +on the entire disc.

+
+ +
+
+get_track_start()
+
+
start time of a cdrom track
+
get_track_start(track) -> seconds
+
+

Return the absolute time in seconds where at start of the cdrom track.

+

Note, track 0 is the first track on the CD. Track numbers start at +zero.

+
+ +
+
+get_track_length()
+
+
length of a cdrom track
+
get_track_length(track) -> seconds
+
+

Return a floating point value in seconds of the length of the cdrom +track.

+

Note, track 0 is the first track on the CD. Track numbers start at +zero.

+
+ +
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/color.html b/venv/Lib/site-packages/pygame/docs/generated/ref/color.html new file mode 100644 index 0000000..1de2df9 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/color.html @@ -0,0 +1,508 @@ + + + + + + + + + pygame.Color — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.Color
+
+
pygame object for color representations
+
Color(r, g, b) -> Color
+
Color(r, g, b, a=255) -> Color
+
Color(color_value) -> Color
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Gets or sets the red value of the Color.
+Gets or sets the green value of the Color.
+Gets or sets the blue value of the Color.
+Gets or sets the alpha value of the Color.
+Gets or sets the CMY representation of the Color.
+Gets or sets the HSVA representation of the Color.
+Gets or sets the HSLA representation of the Color.
+Gets or sets the I1I2I3 representation of the Color.
+Returns the normalized RGBA values of the Color.
+Applies a certain gamma value to the Color.
+Set the number of elements in the Color to 1,2,3, or 4.
+returns a linear interpolation to the given Color.
+returns a Color where the r,g,b components have been multiplied by the alpha.
+Sets the elements of the color
+

The Color class represents RGBA color values using a value range of +0 to 255 inclusive. It allows basic arithmetic operations — binary +operations +, -, *, //, %, and unary operation ~ — to +create new colors, supports conversions to other color spaces such as HSV +or HSL and lets you adjust single color channels. +Alpha defaults to 255 (fully opaque) when not given. +The arithmetic operations and correct_gamma() method preserve subclasses. +For the binary operators, the class of the returned color is that of the +left hand color object of the operator.

+

Color objects support equality comparison with other color objects and 3 or +4 element tuples of integers. There was a bug in pygame 1.8.1 +where the default alpha was 0, not 255 like previously.

+

Color objects export the C level array interface. The interface exports a +read-only one dimensional unsigned byte array of the same assigned length +as the color. The new buffer interface is also exported, with the same +characteristics as the array interface.

+

The floor division, //, and modulus, %, operators do not raise +an exception for division by zero. Instead, if a color, or alpha, channel +in the right hand color is 0, then the result is 0. For example:

+
# These expressions are True
+Color(255, 255, 255, 255) // Color(0, 64, 64, 64) == Color(0, 3, 3, 3)
+Color(255, 255, 255, 255) % Color(64, 64, 64, 0) == Color(63, 63, 63, 0)
+
+
+

Use int(color) to return the immutable integer value of the color, +usable as a dict key. This integer value differs from the mapped +pixel values of pygame.Surface.get_at_mapped()get the mapped color value at a single pixel, +pygame.Surface.map_rgb()convert a color into a mapped color value and pygame.Surface.unmap_rgb()convert a mapped integer color value into a Color. +It can be passed as a color_value argument to Color +(useful with sets).

+

See Named Colors for samples of the available named colors.

+
+
Parameters
+
    +
  • r (int) -- red value in the range of 0 to 255 inclusive

  • +
  • g (int) -- green value in the range of 0 to 255 inclusive

  • +
  • b (int) -- blue value in the range of 0 to 255 inclusive

  • +
  • a (int) -- (optional) alpha value in the range of 0 to 255 inclusive, +default is 255

  • +
  • color_value (Color or str or int or tuple(int, int, int, [int]) or +list(int, int, int, [int])) --

    color value (see note below for the supported formats)

    +
    +

    Note

    +
    +
    Supported color_value formats:
    +
    - Color object: clones the given Color object
    +
    - Color name: str: name of the color to use, e.g. 'red' +(all the supported name strings can be found in the + Named Colors, with sample swatches)
    +
    - HTML color format str: '#rrggbbaa' or '#rrggbb', +where rr, gg, bb, and aa are 2-digit hex numbers in the range +of 0 to 0xFF inclusive, the aa (alpha) value defaults to 0xFF +if not provided
    +
    - hex number str: '0xrrggbbaa' or '0xrrggbb', where +rr, gg, bb, and aa are 2-digit hex numbers in the range of 0x00 +to 0xFF inclusive, the aa (alpha) value defaults to 0xFF if not +provided
    +
    - int: int value of the color to use, using hex numbers can +make this parameter more readable, e.g. 0xrrggbbaa, where rr, +gg, bb, and aa are 2-digit hex numbers in the range of 0x00 to +0xFF inclusive, note that the aa (alpha) value is not optional for +the int format and must be provided
    +
    - tuple/list of int color values: (R, G, B, A) or +(R, G, B), where R, G, B, and A are int values in the range of +0 to 255 inclusive, the A (alpha) value defaults to 255 if not +provided
    +
    +
    +
    +
    +

  • +
+
+
Returns
+

a newly created Color object

+
+
Return type
+

Color

+
+
+
+

Changed in pygame 2.0.0: Support for tuples, lists, and Color objects when creating +Color objects.

+
+
+

Changed in pygame 1.9.2: Color objects export the C level array interface.

+
+
+

Changed in pygame 1.9.0: Color objects support 4-element tuples of integers.

+
+
+

Changed in pygame 1.8.1: New implementation of the class.

+
+
+
+r
+
+
Gets or sets the red value of the Color.
+
r -> int
+
+

The red value of the Color.

+
+ +
+
+g
+
+
Gets or sets the green value of the Color.
+
g -> int
+
+

The green value of the Color.

+
+ +
+
+b
+
+
Gets or sets the blue value of the Color.
+
b -> int
+
+

The blue value of the Color.

+
+ +
+
+a
+
+
Gets or sets the alpha value of the Color.
+
a -> int
+
+

The alpha value of the Color.

+
+ +
+
+cmy
+
+
Gets or sets the CMY representation of the Color.
+
cmy -> tuple
+
+

The CMY representation of the Color. The CMY components are in +the ranges C = [0, 1], M = [0, 1], Y = [0, 1]. Note that this +will not return the absolutely exact CMY values for the set RGB +values in all cases. Due to the RGB mapping from 0-255 and the +CMY mapping from 0-1 rounding errors may cause the CMY values to +differ slightly from what you might expect.

+
+ +
+
+hsva
+
+
Gets or sets the HSVA representation of the Color.
+
hsva -> tuple
+
+

The HSVA representation of the Color. The HSVA components are in +the ranges H = [0, 360], S = [0, 100], V = [0, 100], A = [0, +100]. Note that this will not return the absolutely exact HSV values +for the set RGB values in all cases. Due to the RGB mapping from +0-255 and the HSV mapping from 0-100 and 0-360 rounding errors may +cause the HSV values to differ slightly from what you might expect.

+
+ +
+
+hsla
+
+
Gets or sets the HSLA representation of the Color.
+
hsla -> tuple
+
+

The HSLA representation of the Color. The HSLA components are in +the ranges H = [0, 360], S = [0, 100], V = [0, 100], A = [0, +100]. Note that this will not return the absolutely exact HSL values +for the set RGB values in all cases. Due to the RGB mapping from +0-255 and the HSL mapping from 0-100 and 0-360 rounding errors may +cause the HSL values to differ slightly from what you might expect.

+
+ +
+
+i1i2i3
+
+
Gets or sets the I1I2I3 representation of the Color.
+
i1i2i3 -> tuple
+
+

The I1I2I3 representation of the Color. The I1I2I3 components are +in the ranges I1 = [0, 1], I2 = [-0.5, 0.5], I3 = [-0.5, +0.5]. Note that this will not return the absolutely exact I1I2I3 +values for the set RGB values in all cases. Due to the RGB +mapping from 0-255 and the I1I2I3 mapping from 0-1 rounding errors +may cause the I1I2I3 values to differ slightly from what you might +expect.

+
+ +
+
+normalize()
+
+
Returns the normalized RGBA values of the Color.
+
normalize() -> tuple
+
+

Returns the normalized RGBA values of the Color as floating point +values.

+
+ +
+
+correct_gamma()
+
+
Applies a certain gamma value to the Color.
+
correct_gamma (gamma) -> Color
+
+

Applies a certain gamma value to the Color and returns a new Color with +the adjusted RGBA values.

+
+ +
+
+set_length()
+
+
Set the number of elements in the Color to 1,2,3, or 4.
+
set_length(len) -> None
+
+

The default Color length is 4. Colors can have lengths 1,2,3 or 4. This +is useful if you want to unpack to r,g,b and not r,g,b,a. If you want to +get the length of a Color do len(acolor).

+
+

New in pygame 1.9.0.

+
+
+ +
+
+lerp()
+
+
returns a linear interpolation to the given Color.
+
lerp(Color, float) -> Color
+
+

Returns a Color which is a linear interpolation between self and the +given Color in RGBA space. The second parameter determines how far +between self and other the result is going to be. +It must be a value between 0 and 1 where 0 means self and 1 means +other will be returned.

+
+

New in pygame 2.0.1.

+
+
+ +
+
+premul_alpha()
+
+
returns a Color where the r,g,b components have been multiplied by the alpha.
+
premul_alpha() -> Color
+
+

Returns a new Color where each of the red, green and blue colour +channels have been multiplied by the alpha channel of the original +color. The alpha channel remains unchanged.

+

This is useful when working with the BLEND_PREMULTIPLIED blending mode +flag for pygame.Surface.blit()draw one image onto another, which assumes that all surfaces using +it are using pre-multiplied alpha colors.

+
+

New in pygame 2.0.0.

+
+
+ +
+
+update()
+
+
Sets the elements of the color
+
update(r, g, b) -> None
+
update(r, g, b, a=255) -> None
+
update(color_value) -> None
+
+

Sets the elements of the color. See parameters for pygame.Color()pygame object for color representations for the +parameters of this function. If the alpha value was not set it will not change.

+
+

New in pygame 2.0.1.

+
+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/color_list.html b/venv/Lib/site-packages/pygame/docs/generated/ref/color_list.html new file mode 100644 index 0000000..269c796 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/color_list.html @@ -0,0 +1,2813 @@ + + + + + + + + + Named Colors — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+

pygame.Colorpygame object for color representations lets you specify any of these named colors when creating a new +pygame.Color (taken from the +colordict module).

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Name

Color

aliceblue

████████

antiquewhite

████████

antiquewhite1

████████

antiquewhite2

████████

antiquewhite3

████████

antiquewhite4

████████

aqua

████████

aquamarine

████████

aquamarine1

████████

aquamarine2

████████

aquamarine3

████████

aquamarine4

████████

azure

████████

azure1

████████

azure2

████████

azure3

████████

azure4

████████

beige

████████

bisque

████████

bisque1

████████

bisque2

████████

bisque3

████████

bisque4

████████

black

████████

blanchedalmond

████████

blue

████████

blue1

████████

blue2

████████

blue3

████████

blue4

████████

blueviolet

████████

brown

████████

brown1

████████

brown2

████████

brown3

████████

brown4

████████

burlywood

████████

burlywood1

████████

burlywood2

████████

burlywood3

████████

burlywood4

████████

cadetblue

████████

cadetblue1

████████

cadetblue2

████████

cadetblue3

████████

cadetblue4

████████

chartreuse

████████

chartreuse1

████████

chartreuse2

████████

chartreuse3

████████

chartreuse4

████████

chocolate

████████

chocolate1

████████

chocolate2

████████

chocolate3

████████

chocolate4

████████

coral

████████

coral1

████████

coral2

████████

coral3

████████

coral4

████████

cornflowerblue

████████

cornsilk

████████

cornsilk1

████████

cornsilk2

████████

cornsilk3

████████

cornsilk4

████████

crimson

████████

cyan

████████

cyan1

████████

cyan2

████████

cyan3

████████

cyan4

████████

darkblue

████████

darkcyan

████████

darkgoldenrod

████████

darkgoldenrod1

████████

darkgoldenrod2

████████

darkgoldenrod3

████████

darkgoldenrod4

████████

darkgray

████████

darkgreen

████████

darkgrey

████████

darkkhaki

████████

darkmagenta

████████

darkolivegreen

████████

darkolivegreen1

████████

darkolivegreen2

████████

darkolivegreen3

████████

darkolivegreen4

████████

darkorange

████████

darkorange1

████████

darkorange2

████████

darkorange3

████████

darkorange4

████████

darkorchid

████████

darkorchid1

████████

darkorchid2

████████

darkorchid3

████████

darkorchid4

████████

darkred

████████

darksalmon

████████

darkseagreen

████████

darkseagreen1

████████

darkseagreen2

████████

darkseagreen3

████████

darkseagreen4

████████

darkslateblue

████████

darkslategray

████████

darkslategray1

████████

darkslategray2

████████

darkslategray3

████████

darkslategray4

████████

darkslategrey

████████

darkturquoise

████████

darkviolet

████████

deeppink

████████

deeppink1

████████

deeppink2

████████

deeppink3

████████

deeppink4

████████

deepskyblue

████████

deepskyblue1

████████

deepskyblue2

████████

deepskyblue3

████████

deepskyblue4

████████

dimgray

████████

dimgrey

████████

dodgerblue

████████

dodgerblue1

████████

dodgerblue2

████████

dodgerblue3

████████

dodgerblue4

████████

firebrick

████████

firebrick1

████████

firebrick2

████████

firebrick3

████████

firebrick4

████████

floralwhite

████████

forestgreen

████████

fuchsia

████████

gainsboro

████████

ghostwhite

████████

gold

████████

gold1

████████

gold2

████████

gold3

████████

gold4

████████

goldenrod

████████

goldenrod1

████████

goldenrod2

████████

goldenrod3

████████

goldenrod4

████████

gray

████████

gray0

████████

gray1

████████

gray2

████████

gray3

████████

gray4

████████

gray5

████████

gray6

████████

gray7

████████

gray8

████████

gray9

████████

gray10

████████

gray11

████████

gray12

████████

gray13

████████

gray14

████████

gray15

████████

gray16

████████

gray17

████████

gray18

████████

gray19

████████

gray20

████████

gray21

████████

gray22

████████

gray23

████████

gray24

████████

gray25

████████

gray26

████████

gray27

████████

gray28

████████

gray29

████████

gray30

████████

gray31

████████

gray32

████████

gray33

████████

gray34

████████

gray35

████████

gray36

████████

gray37

████████

gray38

████████

gray39

████████

gray40

████████

gray41

████████

gray42

████████

gray43

████████

gray44

████████

gray45

████████

gray46

████████

gray47

████████

gray48

████████

gray49

████████

gray50

████████

gray51

████████

gray52

████████

gray53

████████

gray54

████████

gray55

████████

gray56

████████

gray57

████████

gray58

████████

gray59

████████

gray60

████████

gray61

████████

gray62

████████

gray63

████████

gray64

████████

gray65

████████

gray66

████████

gray67

████████

gray68

████████

gray69

████████

gray70

████████

gray71

████████

gray72

████████

gray73

████████

gray74

████████

gray75

████████

gray76

████████

gray77

████████

gray78

████████

gray79

████████

gray80

████████

gray81

████████

gray82

████████

gray83

████████

gray84

████████

gray85

████████

gray86

████████

gray87

████████

gray88

████████

gray89

████████

gray90

████████

gray91

████████

gray92

████████

gray93

████████

gray94

████████

gray95

████████

gray96

████████

gray97

████████

gray98

████████

gray99

████████

gray100

████████

green

████████

green1

████████

green2

████████

green3

████████

green4

████████

greenyellow

████████

grey

████████

grey0

████████

grey1

████████

grey2

████████

grey3

████████

grey4

████████

grey5

████████

grey6

████████

grey7

████████

grey8

████████

grey9

████████

grey10

████████

grey11

████████

grey12

████████

grey13

████████

grey14

████████

grey15

████████

grey16

████████

grey17

████████

grey18

████████

grey19

████████

grey20

████████

grey21

████████

grey22

████████

grey23

████████

grey24

████████

grey25

████████

grey26

████████

grey27

████████

grey28

████████

grey29

████████

grey30

████████

grey31

████████

grey32

████████

grey33

████████

grey34

████████

grey35

████████

grey36

████████

grey37

████████

grey38

████████

grey39

████████

grey40

████████

grey41

████████

grey42

████████

grey43

████████

grey44

████████

grey45

████████

grey46

████████

grey47

████████

grey48

████████

grey49

████████

grey50

████████

grey51

████████

grey52

████████

grey53

████████

grey54

████████

grey55

████████

grey56

████████

grey57

████████

grey58

████████

grey59

████████

grey60

████████

grey61

████████

grey62

████████

grey63

████████

grey64

████████

grey65

████████

grey66

████████

grey67

████████

grey68

████████

grey69

████████

grey70

████████

grey71

████████

grey72

████████

grey73

████████

grey74

████████

grey75

████████

grey76

████████

grey77

████████

grey78

████████

grey79

████████

grey80

████████

grey81

████████

grey82

████████

grey83

████████

grey84

████████

grey85

████████

grey86

████████

grey87

████████

grey88

████████

grey89

████████

grey90

████████

grey91

████████

grey92

████████

grey93

████████

grey94

████████

grey95

████████

grey96

████████

grey97

████████

grey98

████████

grey99

████████

grey100

████████

honeydew

████████

honeydew1

████████

honeydew2

████████

honeydew3

████████

honeydew4

████████

hotpink

████████

hotpink1

████████

hotpink2

████████

hotpink3

████████

hotpink4

████████

indianred

████████

indianred1

████████

indianred2

████████

indianred3

████████

indianred4

████████

indigo

████████

ivory

████████

ivory1

████████

ivory2

████████

ivory3

████████

ivory4

████████

khaki

████████

khaki1

████████

khaki2

████████

khaki3

████████

khaki4

████████

lavender

████████

lavenderblush

████████

lavenderblush1

████████

lavenderblush2

████████

lavenderblush3

████████

lavenderblush4

████████

lawngreen

████████

lemonchiffon

████████

lemonchiffon1

████████

lemonchiffon2

████████

lemonchiffon3

████████

lemonchiffon4

████████

lightblue

████████

lightblue1

████████

lightblue2

████████

lightblue3

████████

lightblue4

████████

lightcoral

████████

lightcyan

████████

lightcyan1

████████

lightcyan2

████████

lightcyan3

████████

lightcyan4

████████

lightgoldenrod

████████

lightgoldenrod1

████████

lightgoldenrod2

████████

lightgoldenrod3

████████

lightgoldenrod4

████████

lightgoldenrodyellow

████████

lightgray

████████

lightgreen

████████

lightgrey

████████

lightpink

████████

lightpink1

████████

lightpink2

████████

lightpink3

████████

lightpink4

████████

lightsalmon

████████

lightsalmon1

████████

lightsalmon2

████████

lightsalmon3

████████

lightsalmon4

████████

lightseagreen

████████

lightskyblue

████████

lightskyblue1

████████

lightskyblue2

████████

lightskyblue3

████████

lightskyblue4

████████

lightslateblue

████████

lightslategray

████████

lightslategrey

████████

lightsteelblue

████████

lightsteelblue1

████████

lightsteelblue2

████████

lightsteelblue3

████████

lightsteelblue4

████████

lightyellow

████████

lightyellow1

████████

lightyellow2

████████

lightyellow3

████████

lightyellow4

████████

lime

████████

limegreen

████████

linen

████████

magenta

████████

magenta1

████████

magenta2

████████

magenta3

████████

magenta4

████████

maroon

████████

maroon1

████████

maroon2

████████

maroon3

████████

maroon4

████████

mediumaquamarine

████████

mediumblue

████████

mediumorchid

████████

mediumorchid1

████████

mediumorchid2

████████

mediumorchid3

████████

mediumorchid4

████████

mediumpurple

████████

mediumpurple1

████████

mediumpurple2

████████

mediumpurple3

████████

mediumpurple4

████████

mediumseagreen

████████

mediumslateblue

████████

mediumspringgreen

████████

mediumturquoise

████████

mediumvioletred

████████

midnightblue

████████

mintcream

████████

mistyrose

████████

mistyrose1

████████

mistyrose2

████████

mistyrose3

████████

mistyrose4

████████

moccasin

████████

navajowhite

████████

navajowhite1

████████

navajowhite2

████████

navajowhite3

████████

navajowhite4

████████

navy

████████

navyblue

████████

oldlace

████████

olive

████████

olivedrab

████████

olivedrab1

████████

olivedrab2

████████

olivedrab3

████████

olivedrab4

████████

orange

████████

orange1

████████

orange2

████████

orange3

████████

orange4

████████

orangered

████████

orangered1

████████

orangered2

████████

orangered3

████████

orangered4

████████

orchid

████████

orchid1

████████

orchid2

████████

orchid3

████████

orchid4

████████

palegoldenrod

████████

palegreen

████████

palegreen1

████████

palegreen2

████████

palegreen3

████████

palegreen4

████████

paleturquoise

████████

paleturquoise1

████████

paleturquoise2

████████

paleturquoise3

████████

paleturquoise4

████████

palevioletred

████████

palevioletred1

████████

palevioletred2

████████

palevioletred3

████████

palevioletred4

████████

papayawhip

████████

peachpuff

████████

peachpuff1

████████

peachpuff2

████████

peachpuff3

████████

peachpuff4

████████

peru

████████

pink

████████

pink1

████████

pink2

████████

pink3

████████

pink4

████████

plum

████████

plum1

████████

plum2

████████

plum3

████████

plum4

████████

powderblue

████████

purple

████████

purple1

████████

purple2

████████

purple3

████████

purple4

████████

red

████████

red1

████████

red2

████████

red3

████████

red4

████████

rosybrown

████████

rosybrown1

████████

rosybrown2

████████

rosybrown3

████████

rosybrown4

████████

royalblue

████████

royalblue1

████████

royalblue2

████████

royalblue3

████████

royalblue4

████████

saddlebrown

████████

salmon

████████

salmon1

████████

salmon2

████████

salmon3

████████

salmon4

████████

sandybrown

████████

seagreen

████████

seagreen1

████████

seagreen2

████████

seagreen3

████████

seagreen4

████████

seashell

████████

seashell1

████████

seashell2

████████

seashell3

████████

seashell4

████████

sienna

████████

sienna1

████████

sienna2

████████

sienna3

████████

sienna4

████████

silver

████████

skyblue

████████

skyblue1

████████

skyblue2

████████

skyblue3

████████

skyblue4

████████

slateblue

████████

slateblue1

████████

slateblue2

████████

slateblue3

████████

slateblue4

████████

slategray

████████

slategray1

████████

slategray2

████████

slategray3

████████

slategray4

████████

slategrey

████████

snow

████████

snow1

████████

snow2

████████

snow3

████████

snow4

████████

springgreen

████████

springgreen1

████████

springgreen2

████████

springgreen3

████████

springgreen4

████████

steelblue

████████

steelblue1

████████

steelblue2

████████

steelblue3

████████

steelblue4

████████

tan

████████

tan1

████████

tan2

████████

tan3

████████

tan4

████████

teal

████████

thistle

████████

thistle1

████████

thistle2

████████

thistle3

████████

thistle4

████████

tomato

████████

tomato1

████████

tomato2

████████

tomato3

████████

tomato4

████████

turquoise

████████

turquoise1

████████

turquoise2

████████

turquoise3

████████

turquoise4

████████

violet

████████

violetred

████████

violetred1

████████

violetred2

████████

violetred3

████████

violetred4

████████

wheat

████████

wheat1

████████

wheat2

████████

wheat3

████████

wheat4

████████

white

████████

whitesmoke

████████

yellow

████████

yellow1

████████

yellow2

████████

yellow3

████████

yellow4

████████

yellowgreen

████████

+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/cursors.html b/venv/Lib/site-packages/pygame/docs/generated/ref/cursors.html new file mode 100644 index 0000000..81e4c20 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/cursors.html @@ -0,0 +1,452 @@ + + + + + + + + + pygame.cursors — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.cursors
+
+
pygame module for cursor resources
+
+ +++++ + + + + + + + + + + + + + + +
+create binary cursor data from simple strings
+load cursor data from an XBM file
+pygame object representing a cursor
+

Pygame offers control over the system hardware cursor. Pygame supports +black and white cursors (bitmap cursors), as well as system variant cursors and color cursors. +You control the cursor with functions inside pygame.mousepygame module to work with the mouse.

+

This cursors module contains functions for loading and decoding various +cursor formats. These allow you to easily store your cursors in external files +or directly as encoded python strings.

+

The module includes several standard cursors. The pygame.mouse.set_cursor()set the mouse cursor to a new cursor +function takes several arguments. All those arguments have been stored in a +single tuple you can call like this:

+
>>> pygame.mouse.set_cursor(*pygame.cursors.arrow)
+
+
+

The following variables can be passed to pygame.mouse.set_cursor function:

+
+
    +
  • pygame.cursors.arrow

  • +
  • pygame.cursors.diamond

  • +
  • pygame.cursors.broken_x

  • +
  • pygame.cursors.tri_left

  • +
  • pygame.cursors.tri_right

  • +
+
+

This module also contains a few cursors as formatted strings. You'll need to +pass these to pygame.cursors.compile() function before you can use them. +The example call would look like this:

+
>>> cursor = pygame.cursors.compile(pygame.cursors.textmarker_strings)
+>>> pygame.mouse.set_cursor((8, 16), (0, 0), *cursor)
+
+
+

The following strings can be converted into cursor bitmaps with +pygame.cursors.compile() :

+
+
    +
  • pygame.cursors.thickarrow_strings

  • +
  • pygame.cursors.sizer_x_strings

  • +
  • pygame.cursors.sizer_y_strings

  • +
  • pygame.cursors.sizer_xy_strings

  • +
  • pygame.cursor.textmarker_strings

  • +
+
+
+
+pygame.cursors.compile()
+
+
create binary cursor data from simple strings
+
compile(strings, black='X', white='.', xor='o') -> data, mask
+
+

A sequence of strings can be used to create binary cursor data for the +system cursor. This returns the binary data in the form of two tuples. +Those can be passed as the third and fourth arguments respectively of the +pygame.mouse.set_cursor()set the mouse cursor to a new cursor function.

+

If you are creating your own cursor strings, you can use any value represent +the black and white pixels. Some system allow you to set a special toggle +color for the system color, this is also called the xor color. If the system +does not support xor cursors, that color will simply be black.

+

The height must be divisible by 8. The width of the strings must all be equal +and be divisible by 8. If these two conditions are not met, ValueError is +raised. +An example set of cursor strings looks like this

+
thickarrow_strings = (               #sized 24x24
+  "XX                      ",
+  "XXX                     ",
+  "XXXX                    ",
+  "XX.XX                   ",
+  "XX..XX                  ",
+  "XX...XX                 ",
+  "XX....XX                ",
+  "XX.....XX               ",
+  "XX......XX              ",
+  "XX.......XX             ",
+  "XX........XX            ",
+  "XX........XXX           ",
+  "XX......XXXXX           ",
+  "XX.XXX..XX              ",
+  "XXXX XX..XX             ",
+  "XX   XX..XX             ",
+  "     XX..XX             ",
+  "      XX..XX            ",
+  "      XX..XX            ",
+  "       XXXX             ",
+  "       XX               ",
+  "                        ",
+  "                        ",
+  "                        ")
+
+
+
+ +
+
+pygame.cursors.load_xbm()
+
+
load cursor data from an XBM file
+
load_xbm(cursorfile) -> cursor_args
+
load_xbm(cursorfile, maskfile) -> cursor_args
+
+

This loads cursors for a simple subset of XBM files. XBM files are +traditionally used to store cursors on UNIX systems, they are an ASCII +format used to represent simple images.

+

Sometimes the black and white color values will be split into two separate +XBM files. You can pass a second maskfile argument to load the two +images into a single cursor.

+

The cursorfile and maskfile arguments can either be filenames or file-like +object with the readlines method.

+

The return value cursor_args can be passed directly to the +pygame.mouse.set_cursor() function.

+
+ +
+
+pygame.cursors.Cursor
+
+
pygame object representing a cursor
+
Cursor(size, hotspot, xormasks, andmasks) -> Cursor
+
Cursor(hotspot, surface) -> Cursor
+
Cursor(constant) -> Cursor
+
Cursor(Cursor) -> Cursor
+
Cursor() -> Cursor
+
+ +++++ + + + + + + + + + + + + + + +
+
+Gets the cursor type
+Gets the cursor data
+

In pygame 2, there are 3 types of cursors you can create to give your +game that little bit of extra polish. There's bitmap type cursors, +which existed in pygame 1.x, and are compiled from a string or load from an xbm file. +Then there are system type cursors, where you choose a preset that will +convey the same meaning but look native across different operating systems. +Finally you can create a color cursor, which displays a pygame surface as the cursor.

+

Creating a system cursor

+

Choose a constant from this list, pass it into pygame.cursors.Cursor(constant), +and you're good to go. Be advised that not all systems support every system +cursor, and you may get a substitution instead. For example, on MacOS, +WAIT/WAITARROW should show up as an arrow, and SIZENWSE/SIZENESW/SIZEALL +should show up as a closed hand. And on Wayland, every SIZE cursor should +show up as a hand.

+
Pygame Cursor Constant           Description
+--------------------------------------------
+pygame.SYSTEM_CURSOR_ARROW       arrow
+pygame.SYSTEM_CURSOR_IBEAM       i-beam
+pygame.SYSTEM_CURSOR_WAIT        wait
+pygame.SYSTEM_CURSOR_CROSSHAIR   crosshair
+pygame.SYSTEM_CURSOR_WAITARROW   small wait cursor
+                                 (or wait if not available)
+pygame.SYSTEM_CURSOR_SIZENWSE    double arrow pointing
+                                 northwest and southeast
+pygame.SYSTEM_CURSOR_SIZENESW    double arrow pointing
+                                 northeast and southwest
+pygame.SYSTEM_CURSOR_SIZEWE      double arrow pointing
+                                 west and east
+pygame.SYSTEM_CURSOR_SIZENS      double arrow pointing
+                                 north and south
+pygame.SYSTEM_CURSOR_SIZEALL     four pointed arrow pointing
+                                 north, south, east, and west
+pygame.SYSTEM_CURSOR_NO          slashed circle or crossbones
+pygame.SYSTEM_CURSOR_HAND        hand
+
+
+

Creating a cursor without passing arguments

+

In addition to the cursor constants available and described above, +you can also call pygame.cursors.Cursor(), and your cursor is ready (doing that is the same as +calling pygame.cursors.Cursor(pygame.SYSTEM_CURSOR_ARROW). +Doing one of those calls actually creates a system cursor using the default native image.

+

Creating a color cursor

+

To create a color cursor, create a Cursor from a hotspot and a surface. +hotspot is an (x,y) coordinate that determines where in the cursor the exact point is. +The hotspot position must be within the bounds of the surface.

+

Creating a bitmap cursor

+

When the mouse cursor is visible, it will be displayed as a black and white +bitmap using the given bitmask arrays. The size is a sequence containing +the cursor width and height. hotspot is a sequence containing the cursor +hotspot position.

+

A cursor has a width and height, but a mouse position is represented by a +set of point coordinates. So the value passed into the cursor hotspot +variable helps pygame to actually determine at what exact point the cursor +is at.

+

xormasks is a sequence of bytes containing the cursor xor data masks. +Lastly andmasks, a sequence of bytes containing the cursor bitmask data. +To create these variables, we can make use of the +pygame.cursors.compile()create binary cursor data from simple strings function.

+

Width and height must be a multiple of 8, and the mask arrays must be the +correct size for the given width and height. Otherwise an exception is raised.

+
+
+copy()
+
+| :sl:`copy the current cursor`
+
+| :sg:`copy() -> Cursor`
+

Returns a new Cursor object with the same data and hotspot as the original.

+
+ +
+
+type
+
+
Gets the cursor type
+
type -> string
+
+

The type will be "system", "bitmap", or "color".

+
+ +
+
+data
+
+
Gets the cursor data
+
data -> tuple
+
+

Returns the data that was used to create this cursor object, wrapped up in a tuple.

+
+ +
+

New in pygame 2.0.1.

+
+
+ +

Example code for creating and settings cursors. (Click the mouse to switch cursor)

+
# pygame setup
+import pygame as pg
+
+pg.init()
+screen = pg.display.set_mode([600, 400])
+pg.display.set_caption("Example code for the cursors module")
+
+# create a system cursor
+system = pg.cursors.Cursor(pg.SYSTEM_CURSOR_NO)
+
+# create bitmap cursors
+bitmap_1 = pg.cursors.Cursor(*pg.cursors.arrow)
+bitmap_2 = pg.cursors.Cursor(
+    (24, 24), (0, 0), *pg.cursors.compile(pg.cursors.thickarrow_strings)
+)
+
+# create a color cursor
+surf = pg.Surface((40, 40)) # you could also load an image 
+surf.fill((120, 50, 50))        # and use that as your surface
+color = pg.cursors.Cursor((20, 20), surf)
+
+cursors = [system, bitmap_1, bitmap_2, color]
+cursor_index = 0
+
+pg.mouse.set_cursor(cursors[cursor_index])
+
+clock = pg.time.Clock()
+going = True
+while going:
+    clock.tick(60)
+    screen.fill((0, 75, 30))
+    pg.display.flip()
+
+    for event in pg.event.get():
+        if event.type == pg.QUIT or (event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE):
+            going = False
+
+        # if the mouse is clicked it will switch to a new cursor
+        if event.type == pg.MOUSEBUTTONDOWN:
+            cursor_index += 1
+            cursor_index %= len(cursors)
+            pg.mouse.set_cursor(cursors[cursor_index])
+
+pg.quit()
+
+
+
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/display.html b/venv/Lib/site-packages/pygame/docs/generated/ref/display.html new file mode 100644 index 0000000..edaab32 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/display.html @@ -0,0 +1,990 @@ + + + + + + + + + pygame.display — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.display
+
+
pygame module to control the display window and screen
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Initialize the display module
+Uninitialize the display module
+Returns True if the display module has been initialized
+Initialize a window or screen for display
+Get a reference to the currently set display surface
+Update the full display Surface to the screen
+Update portions of the screen for software displays
+Get the name of the pygame display backend
+Create a video display information object
+Get information about the current windowing system
+Get sizes of active desktops
+Get list of available fullscreen modes
+Pick the best color depth for a display mode
+Get the value for an OpenGL flag for the current display
+Request an OpenGL display attribute for the display mode
+Returns True when the display is active on the screen
+Iconify the display surface
+Switch between fullscreen and windowed displays
+Change the hardware gamma ramps
+Change the hardware gamma ramps with a custom lookup
+Change the system image for the display window
+Set the current window caption
+Get the current window caption
+Set the display color palette for indexed displays
+Return the number of displays
+Return the size of the window or screen
+Return whether the screensaver is allowed to run.
+Set whether the screensaver may run
+

This module offers control over the pygame display. Pygame has a single display +Surface that is either contained in a window or runs full screen. Once you +create the display you treat it as a regular Surface. Changes are not +immediately visible onscreen; you must choose one of the two flipping functions +to update the actual display.

+

The origin of the display, where x = 0 and y = 0, is the top left of the +screen. Both axes increase positively towards the bottom right of the screen.

+

The pygame display can actually be initialized in one of several modes. By +default, the display is a basic software driven framebuffer. You can request +special modules like automatic scaling or OpenGL support. These are +controlled by flags passed to pygame.display.set_mode().

+

Pygame can only have a single display active at any time. Creating a new one +with pygame.display.set_mode() will close the previous display. To detect +the number and size of attached screens, you can use +pygame.display.get_desktop_sizes and then select appropriate window size +and display index to pass to pygame.display.set_mode().

+

For backward compatibility pygame.display allows precise control over +the pixel format or display resolutions. This used to be necessary with old +grahics cards and CRT screens, but is usually not needed any more. Use the +functions pygame.display.mode_ok(), pygame.display.list_modes(), and +pygame.display.Info() to query detailed information about the display.

+

Once the display Surface is created, the functions from this module affect the +single existing display. The Surface becomes invalid if the module is +uninitialized. If a new display mode is set, the existing Surface will +automatically switch to operate on the new display.

+

When the display mode is set, several events are placed on the pygame event +queue. pygame.QUIT is sent when the user has requested the program to +shut down. The window will receive pygame.ACTIVEEVENT events as the display +gains and loses input focus. If the display is set with the +pygame.RESIZABLE flag, pygame.VIDEORESIZE events will be sent when the +user adjusts the window dimensions. Hardware displays that draw direct to the +screen will get pygame.VIDEOEXPOSE events when portions of the window must +be redrawn.

+

A new windowevent API was introduced in pygame 2.0.1. Check event module docs +for more information on that

+

Some display environments have an option for automatically stretching all +windows. When this option is enabled, this automatic stretching distorts the +appearance of the pygame window. In the pygame examples directory, there is +example code (prevent_display_stretching.py) which shows how to disable this +automatic stretching of the pygame display on Microsoft Windows (Vista or newer +required).

+
+
+pygame.display.init()
+
+
Initialize the display module
+
init() -> None
+
+

Initializes the pygame display module. The display module cannot do anything +until it is initialized. This is usually handled for you automatically when +you call the higher level pygame.init().

+

Pygame will select from one of several internal display backends when it is +initialized. The display mode will be chosen depending on the platform and +permissions of current user. Before the display module is initialized the +environment variable SDL_VIDEODRIVER can be set to control which backend +is used. The systems with multiple choices are listed here.

+
Windows : windib, directx
+Unix    : x11, dga, fbcon, directfb, ggi, vgl, svgalib, aalib
+
+
+

On some platforms it is possible to embed the pygame display into an already +existing window. To do this, the environment variable SDL_WINDOWID must +be set to a string containing the window id or handle. The environment +variable is checked when the pygame display is initialized. Be aware that +there can be many strange side effects when running in an embedded display.

+

It is harmless to call this more than once, repeated calls have no effect.

+
+ +
+
+pygame.display.quit()
+
+
Uninitialize the display module
+
quit() -> None
+
+

This will shut down the entire display module. This means any active +displays will be closed. This will also be handled automatically when the +program exits.

+

It is harmless to call this more than once, repeated calls have no effect.

+
+ +
+
+pygame.display.get_init()
+
+
Returns True if the display module has been initialized
+
get_init() -> bool
+
+

Returns True if the pygame.displaypygame module to control the display window and screen module is currently initialized.

+
+ +
+
+pygame.display.set_mode()
+
+
Initialize a window or screen for display
+
set_mode(size=(0, 0), flags=0, depth=0, display=0, vsync=0) -> Surface
+
+

This function will create a display Surface. The arguments passed in are +requests for a display type. The actual created display will be the best +possible match supported by the system.

+

Note that calling this function implicitly initializes pygame.display, if +it was not initialized before.

+

The size argument is a pair of numbers representing the width and +height. The flags argument is a collection of additional options. The depth +argument represents the number of bits to use for color.

+

The Surface that gets returned can be drawn to like a regular Surface but +changes will eventually be seen on the monitor.

+

If no size is passed or is set to (0, 0) and pygame uses SDL +version 1.2.10 or above, the created Surface will have the same size as the +current screen resolution. If only the width or height are set to 0, the +Surface will have the same width or height as the screen resolution. Using a +SDL version prior to 1.2.10 will raise an exception.

+

It is usually best to not pass the depth argument. It will default to the +best and fastest color depth for the system. If your game requires a +specific color format you can control the depth with this argument. Pygame +will emulate an unavailable color depth which can be slow.

+

When requesting fullscreen display modes, sometimes an exact match for the +requested size cannot be made. In these situations pygame will select +the closest compatible match. The returned surface will still always match +the requested size.

+

On high resolution displays(4k, 1080p) and tiny graphics games (640x480) +show up very small so that they are unplayable. SCALED scales up the window +for you. The game thinks it's a 640x480 window, but really it can be bigger. +Mouse events are scaled for you, so your game doesn't need to do it. Note +that SCALED is considered an experimental API and may change in future +releases.

+

The flags argument controls which type of display you want. There are +several to choose from, and you can even combine multiple types using the +bitwise or operator, (the pipe "|" character). Here are the display +flags you will want to choose from:

+
pygame.FULLSCREEN    create a fullscreen display
+pygame.DOUBLEBUF     (obsolete in pygame 2) recommended for HWSURFACE or OPENGL
+pygame.HWSURFACE     (obsolete in pygame 2) hardware accelerated, only in FULLSCREEN
+pygame.OPENGL        create an OpenGL-renderable display
+pygame.RESIZABLE     display window should be sizeable
+pygame.NOFRAME       display window will have no border or controls
+pygame.SCALED        resolution depends on desktop size and scale graphics
+pygame.SHOWN         window is opened in visible mode (default)
+pygame.HIDDEN        window is opened in hidden mode
+
+
+
+

New in pygame 2.0.0: SCALED, SHOWN and HIDDEN

+
+

By setting the vsync parameter to 1, it is possible to get a display +with vertical sync, but you are not guaranteed to get one. The request only +works at all for calls to set_mode() with the pygame.OPENGL or +pygame.SCALED flags set, and is still not guaranteed even with one of +those set. What you get depends on the hardware and driver configuration +of the system pygame is running on. Here is an example usage of a call +to set_mode() that may give you a display with vsync:

+
flags = pygame.OPENGL | pygame.FULLSCREEN
+window_surface = pygame.display.set_mode((1920, 1080), flags, vsync=1)
+
+
+

Vsync behaviour is considered experimental, and may change in future releases.

+
+

New in pygame 2.0.0: vsync

+
+

Basic example:

+
# Open a window on the screen
+screen_width=700
+screen_height=400
+screen=pygame.display.set_mode([screen_width, screen_height])
+
+
+

The display index 0 means the default display is used. If no display +index argument is provided, the default display can be overridden with an +environment variable.

+
+

Changed in pygame 1.9.5: display argument added

+
+
+ +
+
+pygame.display.get_surface()
+
+
Get a reference to the currently set display surface
+
get_surface() -> Surface
+
+

Return a reference to the currently set display Surface. If no display mode +has been set this will return None.

+
+ +
+
+pygame.display.flip()
+
+
Update the full display Surface to the screen
+
flip() -> None
+
+

This will update the contents of the entire display. If your display mode is +using the flags pygame.HWSURFACE and pygame.DOUBLEBUF on pygame 1, +this will wait for a vertical retrace and swap the surfaces.

+

When using an pygame.OPENGL display mode this will perform a gl buffer +swap.

+
+ +
+
+pygame.display.update()
+
+
Update portions of the screen for software displays
+
update(rectangle=None) -> None
+
update(rectangle_list) -> None
+
+

This function is like an optimized version of pygame.display.flip() for +software displays. It allows only a portion of the screen to updated, +instead of the entire area. If no argument is passed it updates the entire +Surface area like pygame.display.flip().

+

Note that calling display.update(None) means no part of the window is +updated. Whereas display.update() means the whole window is updated.

+

You can pass the function a single rectangle, or a sequence of rectangles. +It is more efficient to pass many rectangles at once than to call update +multiple times with single or a partial list of rectangles. If passing a +sequence of rectangles it is safe to include None values in the list, which +will be skipped.

+

This call cannot be used on pygame.OPENGL displays and will generate an +exception.

+
+ +
+
+pygame.display.get_driver()
+
+
Get the name of the pygame display backend
+
get_driver() -> name
+
+

Pygame chooses one of many available display backends when it is +initialized. This returns the internal name used for the display backend. +This can be used to provide limited information about what display +capabilities might be accelerated. See the SDL_VIDEODRIVER flags in +pygame.display.set_mode() to see some of the common options.

+
+ +
+
+pygame.display.Info()
+
+
Create a video display information object
+
Info() -> VideoInfo
+
+

Creates a simple object containing several attributes to describe the +current graphics environment. If this is called before +pygame.display.set_mode() some platforms can provide information about +the default display mode. This can also be called after setting the display +mode to verify specific display options were satisfied. The VidInfo object +has several attributes:

+
hw:         1 if the display is hardware accelerated
+wm:         1 if windowed display modes can be used
+video_mem:  The megabytes of video memory on the display. This is 0 if
+            unknown
+bitsize:    Number of bits used to store each pixel
+bytesize:   Number of bytes used to store each pixel
+masks:      Four values used to pack RGBA values into pixels
+shifts:     Four values used to pack RGBA values into pixels
+losses:     Four values used to pack RGBA values into pixels
+blit_hw:    1 if hardware Surface blitting is accelerated
+blit_hw_CC: 1 if hardware Surface colorkey blitting is accelerated
+blit_hw_A:  1 if hardware Surface pixel alpha blitting is accelerated
+blit_sw:    1 if software Surface blitting is accelerated
+blit_sw_CC: 1 if software Surface colorkey blitting is accelerated
+blit_sw_A:  1 if software Surface pixel alpha blitting is accelerated
+current_h, current_w:  Height and width of the current video mode, or
+            of the desktop mode if called before the display.set_mode
+            is called. (current_h, current_w are available since
+            SDL 1.2.10, and pygame 1.8.0). They are -1 on error, or if
+            an old SDL is being used.
+
+
+
+ +
+
+pygame.display.get_wm_info()
+
+
Get information about the current windowing system
+
get_wm_info() -> dict
+
+

Creates a dictionary filled with string keys. The strings and values are +arbitrarily created by the system. Some systems may have no information and +an empty dictionary will be returned. Most platforms will return a "window" +key with the value set to the system id for the current display.

+
+

New in pygame 1.7.1.

+
+
+ +
+
+pygame.display.get_desktop_sizes()
+
+
Get sizes of active desktops
+
get_desktop_sizes() -> list
+
+

This function returns the sizes of the currrently configured +virtual desktops as a list of (x, y) tuples of integers.

+

The length of the list is not the same as the number of attached monitors, +as a desktop can be mirrored across multiple monitors. The desktop sizes +do not indicate the maximum monitor resolutions supported by the hardware, +but the desktop size configured in the operating system.

+

In order to fit windows into the desktop as it is currently configured, and +to respect the resolution configured by the operating system in fullscreen +mode, this function should be used to replace many use cases of +pygame.display.list_modes() whenever applicable.

+
+

New in pygame 2.0.0.

+
+
+ +
+
+pygame.display.list_modes()
+
+
Get list of available fullscreen modes
+
list_modes(depth=0, flags=pygame.FULLSCREEN, display=0) -> list
+
+

This function returns a list of possible sizes for a specified color +depth. The return value will be an empty list if no display modes are +available with the given arguments. A return value of -1 means that +any requested size should work (this is likely the case for windowed +modes). Mode sizes are sorted from biggest to smallest.

+

If depth is 0, the current/best color depth for the display is used. +The flags defaults to pygame.FULLSCREEN, but you may need to add +additional flags for specific fullscreen modes.

+

The display index 0 means the default display is used.

+

Since pygame 2.0, pygame.display.get_desktop_sizes() has taken over +some use cases from pygame.display.list_modes():

+

To find a suitable size for non-fullscreen windows, it is preferable to +use pygame.display.get_desktop_sizes() to get the size of the current +desktop, and to then choose a smaller window size. This way, the window is +guaranteed to fit, even when the monitor is configured to a lower resolution +than the maximum supported by the hardware.

+

To avoid changing the physical monitor resolution, it is also preferable to +use pygame.display.get_desktop_sizes() to determine the fullscreen +resolution. Developers are strongly advised to default to the current +physical monitor resolution unless the user explicitly requests a different +one (e.g. in an options menu or configuration file).

+
+

Changed in pygame 1.9.5: display argument added

+
+
+ +
+
+pygame.display.mode_ok()
+
+
Pick the best color depth for a display mode
+
mode_ok(size, flags=0, depth=0, display=0) -> depth
+
+

This function uses the same arguments as pygame.display.set_mode(). It +is used to determine if a requested display mode is available. It will +return 0 if the display mode cannot be set. Otherwise it will return a +pixel depth that best matches the display asked for.

+

Usually the depth argument is not passed, but some platforms can support +multiple display depths. If passed it will hint to which depth is a better +match.

+

The function will return 0 if the passed display flags cannot be set.

+

The display index 0 means the default display is used.

+
+

Changed in pygame 1.9.5: display argument added

+
+
+ +
+
+pygame.display.gl_get_attribute()
+
+
Get the value for an OpenGL flag for the current display
+
gl_get_attribute(flag) -> value
+
+

After calling pygame.display.set_mode() with the pygame.OPENGL flag, +it is a good idea to check the value of any requested OpenGL attributes. See +pygame.display.gl_set_attribute() for a list of valid flags.

+
+ +
+
+pygame.display.gl_set_attribute()
+
+
Request an OpenGL display attribute for the display mode
+
gl_set_attribute(flag, value) -> None
+
+

When calling pygame.display.set_mode() with the pygame.OPENGL flag, +Pygame automatically handles setting the OpenGL attributes like color and +double-buffering. OpenGL offers several other attributes you may want control +over. Pass one of these attributes as the flag, and its appropriate value. +This must be called before pygame.display.set_mode().

+

Many settings are the requested minimum. Creating a window with an OpenGL context +will fail if OpenGL cannot provide the requested attribute, but it may for example +give you a stencil buffer even if you request none, or it may give you a larger +one than requested.

+

The OPENGL flags are:

+
GL_ALPHA_SIZE, GL_DEPTH_SIZE, GL_STENCIL_SIZE, GL_ACCUM_RED_SIZE,
+GL_ACCUM_GREEN_SIZE,  GL_ACCUM_BLUE_SIZE, GL_ACCUM_ALPHA_SIZE,
+GL_MULTISAMPLEBUFFERS, GL_MULTISAMPLESAMPLES, GL_STEREO
+
+
+

GL_MULTISAMPLEBUFFERS

+
+

Whether to enable multisampling anti-aliasing. +Defaults to 0 (disabled).

+

Set GL_MULTISAMPLESAMPLES to a value +above 0 to control the amount of anti-aliasing. +A typical value is 2 or 3.

+
+

GL_STENCIL_SIZE

+
+

Minimum bit size of the stencil buffer. Defaults to 0.

+
+

GL_DEPTH_SIZE

+
+

Minimum bit size of the depth buffer. Defaults to 16.

+
+

GL_STEREO

+
+

1 enables stereo 3D. Defaults to 0.

+
+

GL_BUFFER_SIZE

+
+

Minimum bit size of the frame buffer. Defaults to 0.

+
+
+

New in pygame 2.0.0: Additional attributes:

+
+
GL_ACCELERATED_VISUAL,
+GL_CONTEXT_MAJOR_VERSION, GL_CONTEXT_MINOR_VERSION,
+GL_CONTEXT_FLAGS, GL_CONTEXT_PROFILE_MASK,
+GL_SHARE_WITH_CURRENT_CONTEXT,
+GL_CONTEXT_RELEASE_BEHAVIOR,
+GL_FRAMEBUFFER_SRGB_CAPABLE
+
+
+

GL_CONTEXT_PROFILE_MASK

+
+

Sets the OpenGL profile to one of these values:

+
GL_CONTEXT_PROFILE_CORE             disable deprecated features
+GL_CONTEXT_PROFILE_COMPATIBILITY    allow deprecated features
+GL_CONTEXT_PROFILE_ES               allow only the ES feature
+                                    subset of OpenGL
+
+
+
+

GL_ACCELERATED_VISUAL

+
+

Set to 1 to require hardware acceleration, or 0 to force software render. +By default, both are allowed.

+
+
+ +
+
+pygame.display.get_active()
+
+
Returns True when the display is active on the screen
+
get_active() -> bool
+
+

Returns True when the display Surface is considered actively +renderable on the screen and may be visible to the user. This is +the default state immediately after pygame.display.set_mode(). +This method may return True even if the application is fully hidden +behind another application window.

+

This will return False if the display Surface has been iconified or +minimized (either via pygame.display.iconify() or via an OS +specific method such as the minimize-icon available on most +desktops).

+

The method can also return False for other reasons without the +application being explicitly iconified or minimized by the user. A +notable example being if the user has multiple virtual desktops and +the display Surface is not on the active virtual desktop.

+
+

Note

+

This function returning True is unrelated to whether the +application has input focus. Please see +pygame.key.get_focused() and pygame.mouse.get_focused() +for APIs related to input focus.

+
+
+ +
+
+pygame.display.iconify()
+
+
Iconify the display surface
+
iconify() -> bool
+
+

Request the window for the display surface be iconified or hidden. Not all +systems and displays support an iconified display. The function will return +True if successful.

+

When the display is iconified pygame.display.get_active() will return +False. The event queue should receive an ACTIVEEVENT event when the +window has been iconified. Additionally, the event queue also recieves a +WINDOWEVENT_MINIMIZED event when the window has been iconified on pygame 2.

+
+ +
+
+pygame.display.toggle_fullscreen()
+
+
Switch between fullscreen and windowed displays
+
toggle_fullscreen() -> int
+
+

Switches the display window between windowed and fullscreen modes. +Display driver support is not great when using pygame 1, but with +pygame 2 it is the most reliable method to switch to and from fullscreen.

+

Supported display drivers in pygame 1:

+
+
    +
  • x11 (Linux/Unix)

  • +
  • wayland (Linux/Unix)

  • +
+
+

Supported display drivers in pygame 2:

+
+
    +
  • windows (Windows)

  • +
  • x11 (Linux/Unix)

  • +
  • wayland (Linux/Unix)

  • +
  • cocoa (OSX/Mac)

  • +
+
+
+

Note

+

toggle_fullscreen() doesn't work on Windows +unless the window size is in pygame.display.list_modes()Get list of available fullscreen modes or +the window is created with the flag pygame.SCALED. +See issue #2380.

+
+
+ +
+
+pygame.display.set_gamma()
+
+
Change the hardware gamma ramps
+
set_gamma(red, green=None, blue=None) -> bool
+
+

Set the red, green, and blue gamma values on the display hardware. If the +green and blue arguments are not passed, they will both be the same as red. +Not all systems and hardware support gamma ramps, if the function succeeds +it will return True.

+

A gamma value of 1.0 creates a linear color table. Lower values will +darken the display and higher values will brighten.

+
+ +
+
+pygame.display.set_gamma_ramp()
+
+
Change the hardware gamma ramps with a custom lookup
+
set_gamma_ramp(red, green, blue) -> bool
+
+

Set the red, green, and blue gamma ramps with an explicit lookup table. Each +argument should be sequence of 256 integers. The integers should range +between 0 and 0xffff. Not all systems and hardware support gamma +ramps, if the function succeeds it will return True.

+
+ +
+
+pygame.display.set_icon()
+
+
Change the system image for the display window
+
set_icon(Surface) -> None
+
+

Sets the runtime icon the system will use to represent the display window. +All windows default to a simple pygame logo for the window icon.

+

Note that calling this function implicitly initializes pygame.display, if +it was not initialized before.

+

You can pass any surface, but most systems want a smaller image around +32x32. The image can have colorkey transparency which will be passed to the +system.

+

Some systems do not allow the window icon to change after it has been shown. +This function can be called before pygame.display.set_mode() to create +the icon before the display mode is set.

+
+ +
+
+pygame.display.set_caption()
+
+
Set the current window caption
+
set_caption(title, icontitle=None) -> None
+
+

If the display has a window title, this function will change the name on the +window. In pygame 1.x, some systems supported an alternate shorter title to +be used for minimized displays, but in pygame 2 icontitle does nothing.

+
+ +
+
+pygame.display.get_caption()
+
+
Get the current window caption
+
get_caption() -> (title, icontitle)
+
+

Returns the title and icontitle for the display window. In pygame 2.x +these will always be the same value.

+
+ +
+
+pygame.display.set_palette()
+
+
Set the display color palette for indexed displays
+
set_palette(palette=None) -> None
+
+

This will change the video display color palette for 8-bit displays. This +does not change the palette for the actual display Surface, only the palette +that is used to display the Surface. If no palette argument is passed, the +system default palette will be restored. The palette is a sequence of +RGB triplets.

+
+ +
+
+pygame.display.get_num_displays()
+
+
Return the number of displays
+
get_num_displays() -> int
+
+

Returns the number of available displays. This is always 1 if +pygame.get_sdl_version()get the version number of SDL returns a major version number below 2.

+
+

New in pygame 1.9.5.

+
+
+ +
+
+pygame.display.get_window_size()
+
+
Return the size of the window or screen
+
get_window_size() -> tuple
+
+

Returns the size of the window initialized with pygame.display.set_mode()Initialize a window or screen for display. +This may differ from the size of the display surface if SCALED is used.

+
+

New in pygame 2.0.0.

+
+
+ +
+
+pygame.display.get_allow_screensaver()
+
+
Return whether the screensaver is allowed to run.
+
get_allow_screensaver() -> bool
+
+

Return whether screensaver is allowed to run whilst the app is running. +Default is False. +By default pygame does not allow the screensaver during game play.

+
+

Note

+

Some platforms do not have a screensaver or support +disabling the screensaver. Please see +pygame.display.set_allow_screensaver()Set whether the screensaver may run for +caveats with screensaver support.

+
+
+

New in pygame 2.0.0.

+
+
+ +
+
+pygame.display.set_allow_screensaver()
+
+
Set whether the screensaver may run
+
set_allow_screensaver(bool) -> None
+
+

Change whether screensavers should be allowed whilst the app is running. +The default value of the argument to the function is True. +By default pygame does not allow the screensaver during game play.

+

If the screensaver has been disallowed due to this function, it will automatically +be allowed to run when pygame.quit()uninitialize all pygame modules is called.

+

It is possible to influence the default value via the environment variable +SDL_HINT_VIDEO_ALLOW_SCREENSAVER, which can be set to either 0 (disable) +or 1 (enable).

+
+

Note

+

Disabling screensaver is subject to platform support. +When platform support is absent, this function will +silently appear to work even though the screensaver state +is unchanged. The lack of feedback is due to SDL not +providing any supported method for determining whether +it supports changing the screensaver state. +SDL_HINT_VIDEO_ALLOW_SCREENSAVER is available in SDL 2.0.2 or later. +SDL1.2 does not implement this.

+
+
+

New in pygame 2.0.0.

+
+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/draw.html b/venv/Lib/site-packages/pygame/docs/generated/ref/draw.html new file mode 100644 index 0000000..a8a7bb6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/draw.html @@ -0,0 +1,971 @@ + + + + + + + + + pygame.draw — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.draw
+
+
pygame module for drawing shapes
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+draw a rectangle
+draw a polygon
+draw a circle
+draw an ellipse
+draw an elliptical arc
+draw a straight line
+draw multiple contiguous straight line segments
+draw a straight antialiased line
+draw multiple contiguous straight antialiased line segments
+

Draw several simple shapes to a surface. These functions will work for +rendering to any format of surface. Rendering to hardware surfaces will be +slower than regular software surfaces.

+

Most of the functions take a width argument to represent the size of stroke +(thickness) around the edge of the shape. If a width of 0 is passed the shape +will be filled (solid).

+

All the drawing functions respect the clip area for the surface and will be +constrained to that area. The functions return a rectangle representing the +bounding area of changed pixels. This bounding rectangle is the 'minimum' +bounding box that encloses the affected area.

+

All the drawing functions accept a color argument that can be one of the +following formats:

+
+
+
+

A color's alpha value will be written directly into the surface (if the +surface contains pixel alphas), but the draw function will not draw +transparently.

+

These functions temporarily lock the surface they are operating on. Many +sequential drawing calls can be sped up by locking and unlocking the surface +object around the draw calls (see pygame.Surface.lock()lock the Surface memory for pixel access and +pygame.Surface.unlock()unlock the Surface memory from pixel access).

+
+

Note

+

See the pygame.gfxdrawpygame module for drawing shapes module for alternative draw methods.

+
+
+
+pygame.draw.rect()
+
+
draw a rectangle
+
rect(surface, color, rect) -> Rect
+
rect(surface, color, rect, width=0, border_radius=0, border_top_left_radius=-1, border_top_right_radius=-1, border_bottom_left_radius=-1, border_bottom_right_radius=-1) -> Rect
+
+

Draws a rectangle on the given surface.

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • color (Color or int or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
  • rect (Rect) -- rectangle to draw, position and dimensions

  • +
  • width (int) --

    (optional) used for line thickness or to indicate that +the rectangle is to be filled (not to be confused with the width value +of the rect parameter)

    +
    +
    +
    if width == 0, (default) fill the rectangle
    +
    if width > 0, used for line thickness
    +
    if width < 0, nothing will be drawn
    +

    +
    +
    +

    Note

    +

    When using width values > 1, the edge lines will grow +outside the original boundary of the rect. For more details on +how the thickness for edge lines grow, refer to the width notes +of the pygame.draw.line()draw a straight line function.

    +
    +
    +

  • +
  • border_radius (int) -- (optional) used for drawing rectangle with rounded corners. +The supported range is [0, min(height, width) / 2], with 0 representing a rectangle +without rounded corners.

  • +
  • border_top_left_radius (int) -- (optional) used for setting the value of top left +border. If you don't set this value, it will use the border_radius value.

  • +
  • border_top_right_radius (int) -- (optional) used for setting the value of top right +border. If you don't set this value, it will use the border_radius value.

  • +
  • border_bottom_left_radius (int) -- (optional) used for setting the value of bottom left +border. If you don't set this value, it will use the border_radius value.

  • +
  • border_bottom_right_radius (int) --

    (optional) used for setting the value of bottom right +border. If you don't set this value, it will use the border_radius value.

    +
    +
    +
    if border_radius < 1 it will draw rectangle without rounded corners
    +
    if any of border radii has the value < 0 it will use value of the border_radius
    +
    If sum of radii on the same side of the rectangle is greater than the rect size the radii
    +
    will get scaled
    +
    +
    +

  • +
+
+
Returns
+

a rect bounding the changed pixels, if nothing is drawn the +bounding rect's position will be the position of the given rect +parameter and its width and height will be 0

+
+
Return type
+

Rect

+
+
+
+

Note

+

The pygame.Surface.fill()fill Surface with a solid color method works just as well for drawing +filled rectangles and can be hardware accelerated on some platforms with +both software and hardware display modes.

+
+
+

Changed in pygame 2.0.0: Added support for keyword arguments.

+
+
+

Changed in pygame 2.0.0.dev8: Added support for border radius.

+
+
+ +
+
+pygame.draw.polygon()
+
+
draw a polygon
+
polygon(surface, color, points) -> Rect
+
polygon(surface, color, points, width=0) -> Rect
+
+

Draws a polygon on the given surface.

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • color (Color or int or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
  • points (tuple(coordinate) or list(coordinate)) -- a sequence of 3 or more (x, y) coordinates that make up the +vertices of the polygon, each coordinate in the sequence must be a +tuple/list/pygame.math.Vector2a 2-Dimensional Vector of 2 ints/floats, +e.g. [(x1, y1), (x2, y2), (x3, y3)]

  • +
  • width (int) --

    (optional) used for line thickness or to indicate that +the polygon is to be filled

    +
    +
    +
    if width == 0, (default) fill the polygon
    +
    if width > 0, used for line thickness
    +
    if width < 0, nothing will be drawn
    +

    +
    +
    +

    Note

    +

    When using width values > 1, the edge lines will grow +outside the original boundary of the polygon. For more details on +how the thickness for edge lines grow, refer to the width notes +of the pygame.draw.line()draw a straight line function.

    +
    +
    +

  • +
+
+
Returns
+

a rect bounding the changed pixels, if nothing is drawn the +bounding rect's position will be the position of the first point in the +points parameter (float values will be truncated) and its width and +height will be 0

+
+
Return type
+

Rect

+
+
Raises
+
    +
  • ValueError -- if len(points) < 3 (must have at least 3 points)

  • +
  • TypeError -- if points is not a sequence or points does not +contain number pairs

  • +
+
+
+
+

Note

+

For an aapolygon, use aalines() with closed=True.

+
+
+

Changed in pygame 2.0.0: Added support for keyword arguments.

+
+
+ +
+
+pygame.draw.circle()
+
+
draw a circle
+
circle(surface, color, center, radius) -> Rect
+
circle(surface, color, center, radius, width=0, draw_top_right=None, draw_top_left=None, draw_bottom_left=None, draw_bottom_right=None) -> Rect
+
+

Draws a circle on the given surface.

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • color (Color or int or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
  • center (tuple(int or float, int or float) or +list(int or float, int or float) or Vector2(int or float, int or float)) -- center point of the circle as a sequence of 2 ints/floats, +e.g. (x, y)

  • +
  • radius (int or float) -- radius of the circle, measured from the center parameter, +nothing will be drawn if the radius is less than 1

  • +
  • width (int) --

    (optional) used for line thickness or to indicate that +the circle is to be filled

    +
    +
    +
    if width == 0, (default) fill the circle
    +
    if width > 0, used for line thickness
    +
    if width < 0, nothing will be drawn
    +

    +
    +
    +

    Note

    +

    When using width values > 1, the edge lines will only grow +inward.

    +
    +
    +

  • +
  • draw_top_right (bool) -- (optional) if this is set to True then the top right corner +of the circle will be drawn

  • +
  • draw_top_left (bool) -- (optional) if this is set to True then the top left corner +of the circle will be drawn

  • +
  • draw_bottom_left (bool) -- (optional) if this is set to True then the bottom left corner +of the circle will be drawn

  • +
  • draw_bottom_right (bool) --

    (optional) if this is set to True then the bottom right corner +of the circle will be drawn

    +
    +
    +
    if any of the draw_circle_part is True then it will draw all circle parts that have the True
    +
    value, otherwise it will draw the entire circle.
    +
    +
    +

  • +
+
+
Returns
+

a rect bounding the changed pixels, if nothing is drawn the +bounding rect's position will be the center parameter value (float +values will be truncated) and its width and height will be 0

+
+
Return type
+

Rect

+
+
Raises
+
    +
  • TypeError -- if center is not a sequence of two numbers

  • +
  • TypeError -- if radius is not a number

  • +
+
+
+
+

Changed in pygame 2.0.0: Added support for keyword arguments. +Nothing is drawn when the radius is 0 (a pixel at the center coordinates +used to be drawn when the radius equaled 0). +Floats, and Vector2 are accepted for the center param. +The drawing algorithm was improved to look more like a circle.

+
+
+

Changed in pygame 2.0.0.dev8: Added support for drawing circle quadrants.

+
+
+ +
+
+pygame.draw.ellipse()
+
+
draw an ellipse
+
ellipse(surface, color, rect) -> Rect
+
ellipse(surface, color, rect, width=0) -> Rect
+
+

Draws an ellipse on the given surface.

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • color (Color or int or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
  • rect (Rect) -- rectangle to indicate the position and dimensions of the +ellipse, the ellipse will be centered inside the rectangle and bounded +by it

  • +
  • width (int) --

    (optional) used for line thickness or to indicate that +the ellipse is to be filled (not to be confused with the width value +of the rect parameter)

    +
    +
    +
    if width == 0, (default) fill the ellipse
    +
    if width > 0, used for line thickness
    +
    if width < 0, nothing will be drawn
    +

    +
    +
    +

    Note

    +

    When using width values > 1, the edge lines will only grow +inward from the original boundary of the rect parameter.

    +
    +
    +

  • +
+
+
Returns
+

a rect bounding the changed pixels, if nothing is drawn the +bounding rect's position will be the position of the given rect +parameter and its width and height will be 0

+
+
Return type
+

Rect

+
+
+
+

Changed in pygame 2.0.0: Added support for keyword arguments.

+
+
+ +
+
+pygame.draw.arc()
+
+
draw an elliptical arc
+
arc(surface, color, rect, start_angle, stop_angle) -> Rect
+
arc(surface, color, rect, start_angle, stop_angle, width=1) -> Rect
+
+

Draws an elliptical arc on the given surface.

+

The two angle arguments are given in radians and indicate the start and stop +positions of the arc. The arc is drawn in a counterclockwise direction from +the start_angle to the stop_angle.

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • color (Color or int or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
  • rect (Rect) -- rectangle to indicate the position and dimensions of the +ellipse which the arc will be based on, the ellipse will be centered +inside the rectangle

  • +
  • start_angle (float) -- start angle of the arc in radians

  • +
  • stop_angle (float) --

    stop angle of the arc in +radians

    +
    +
    +
    if start_angle < stop_angle, the arc is drawn in a +counterclockwise direction from the start_angle to the +stop_angle
    +
    if start_angle > stop_angle, tau (tau == 2 * pi) will be added +to the stop_angle, if the resulting stop angle value is greater +than the start_angle the above start_angle < stop_angle case +applies, otherwise nothing will be drawn
    +
    if start_angle == stop_angle, nothing will be drawn
    +

    +
    +
    +

  • +
  • width (int) --

    (optional) used for line thickness (not to be confused +with the width value of the rect parameter)

    +
    +
    +
    if width == 0, nothing will be drawn
    +
    if width > 0, (default is 1) used for line thickness
    +
    if width < 0, same as width == 0
    +
    +
    +

    Note

    +

    When using width values > 1, the edge lines will only grow +inward from the original boundary of the rect parameter.

    +
    +
    +

  • +
+
+
Returns
+

a rect bounding the changed pixels, if nothing is drawn the +bounding rect's position will be the position of the given rect +parameter and its width and height will be 0

+
+
Return type
+

Rect

+
+
+
+

Changed in pygame 2.0.0: Added support for keyword arguments.

+
+
+ +
+
+pygame.draw.line()
+
+
draw a straight line
+
line(surface, color, start_pos, end_pos) -> Rect
+
line(surface, color, start_pos, end_pos, width=1) -> Rect
+
+

Draws a straight line on the given surface. There are no endcaps. For thick +lines the ends are squared off.

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • color (Color or int or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
  • start_pos (tuple(int or float, int or float) or +list(int or float, int or float) or Vector2(int or float, int or float)) -- start position of the line, (x, y)

  • +
  • end_pos (tuple(int or float, int or float) or +list(int or float, int or float) or Vector2(int or float, int or float)) -- end position of the line, (x, y)

  • +
  • width (int) --

    (optional) used for line thickness

    +
    +
    if width >= 1, used for line thickness (default is 1)
    +
    if width < 1, nothing will be drawn
    +

    +
    +
    +

    Note

    +

    When using width values > 1, lines will grow as follows.

    +

    For odd width values, the thickness of each line grows with the +original line being in the center.

    +

    For even width values, the thickness of each line grows with the +original line being offset from the center (as there is no exact +center line drawn). As a result, lines with a slope < 1 +(horizontal-ish) will have 1 more pixel of thickness below the +original line (in the y direction). Lines with a slope >= 1 +(vertical-ish) will have 1 more pixel of thickness to the right of +the original line (in the x direction).

    +
    +

  • +
+
+
Returns
+

a rect bounding the changed pixels, if nothing is drawn the +bounding rect's position will be the start_pos parameter value (float +values will be truncated) and its width and height will be 0

+
+
Return type
+

Rect

+
+
Raises
+

TypeError -- if start_pos or end_pos is not a sequence of +two numbers

+
+
+
+

Changed in pygame 2.0.0: Added support for keyword arguments.

+
+
+ +
+
+pygame.draw.lines()
+
+
draw multiple contiguous straight line segments
+
lines(surface, color, closed, points) -> Rect
+
lines(surface, color, closed, points, width=1) -> Rect
+
+

Draws a sequence of contiguous straight lines on the given surface. There are +no endcaps or miter joints. For thick lines the ends are squared off. +Drawing thick lines with sharp corners can have undesired looking results.

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • color (Color or int or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
  • closed (bool) -- if True an additional line segment is drawn between +the first and last points in the points sequence

  • +
  • points (tuple(coordinate) or list(coordinate)) -- a sequence of 2 or more (x, y) coordinates, where each +coordinate in the sequence must be a +tuple/list/pygame.math.Vector2a 2-Dimensional Vector of 2 ints/floats and adjacent +coordinates will be connected by a line segment, e.g. for the +points [(x1, y1), (x2, y2), (x3, y3)] a line segment will be drawn +from (x1, y1) to (x2, y2) and from (x2, y2) to (x3, y3), +additionally if the closed parameter is True another line segment +will be drawn from (x3, y3) to (x1, y1)

  • +
  • width (int) --

    (optional) used for line thickness

    +
    +
    if width >= 1, used for line thickness (default is 1)
    +
    if width < 1, nothing will be drawn
    +

    +
    +
    +

    Note

    +

    When using width values > 1 refer to the width notes +of line() for details on how thick lines grow.

    +
    +

  • +
+
+
Returns
+

a rect bounding the changed pixels, if nothing is drawn the +bounding rect's position will be the position of the first point in the +points parameter (float values will be truncated) and its width and +height will be 0

+
+
Return type
+

Rect

+
+
Raises
+
    +
  • ValueError -- if len(points) < 2 (must have at least 2 points)

  • +
  • TypeError -- if points is not a sequence or points does not +contain number pairs

  • +
+
+
+
+

Changed in pygame 2.0.0: Added support for keyword arguments.

+
+
+ +
+
+pygame.draw.aaline()
+
+
draw a straight antialiased line
+
aaline(surface, color, start_pos, end_pos) -> Rect
+
aaline(surface, color, start_pos, end_pos, blend=1) -> Rect
+
+

Draws a straight antialiased line on the given surface.

+

The line has a thickness of one pixel and the endpoints have a height and +width of one pixel each.

+
+
The way a line and its endpoints are drawn:

If both endpoints are equal, only a single pixel is drawn (after +rounding floats to nearest integer).

+

Otherwise if the line is not steep (i.e. if the length along the x-axis +is greater than the height along the y-axis):

+
+

For each endpoint:

+
+

If x, the endpoint's x-coordinate, is a whole number find +which pixels would be covered by it and draw them.

+

Otherwise:

+
+

Calculate the position of the nearest point with a whole number +for its x-coordinate, when extending the line past the +endpoint.

+

Find which pixels would be covered and how much by that point.

+

If the endpoint is the left one, multiply the coverage by (1 - +the decimal part of x).

+

Otherwise multiply the coverage by the decimal part of x.

+

Then draw those pixels.

+
+
e.g.:
+
The left endpoint of the line ((1, 1.3), (5, 3)) would +cover 70% of the pixel (1, 1) and 30% of the pixel +(1, 2) while the right one would cover 100% of the +pixel (5, 3).
+
The left endpoint of the line ((1.2, 1.4), (4.6, 3.1)) +would cover 56% (i.e. 0.8 * 70%) of the pixel (1, 1) +and 24% (i.e. 0.8 * 30%) of the pixel (1, 2) while +the right one would cover 42% (i.e. 0.6 * 70%) of the +pixel (5, 3) and 18% (i.e. 0.6 * 30%) of the pixel +(5, 4) while the right
+
+
+
+
+
+

Then for each point between the endpoints, along the line, whose +x-coordinate is a whole number:

+
+

Find which pixels would be covered and how much by that point and +draw them.

+
+
e.g.:
+
The points along the line ((1, 1), (4, 2.5)) would be +(2, 1.5) and (3, 2) and would cover 50% of the pixel +(2, 1), 50% of the pixel (2, 2) and 100% of the pixel +(3, 2).
+
The points along the line ((1.2, 1.4), (4.6, 3.1)) would +be (2, 1.8) (covering 20% of the pixel (2, 1) and 80% +of the pixel (2, 2)), (3, 2.3) (covering 70% of the +pixel (3, 2) and 30% of the pixel (3, 3)) and (4, +2.8) (covering 20% of the pixel (2, 1) and 80% of the +pixel (2, 2))
+
+
+
+
+
+

Otherwise do the same for steep lines as for non-steep lines except +along the y-axis instead of the x-axis (using y instead of x, +top instead of left and bottom instead of right).

+
+
+
+

Note

+

Regarding float values for coordinates, a point with coordinate +consisting of two whole numbers is considered being right in the center +of said pixel (and having a height and width of 1 pixel would therefore +completely cover it), while a point with coordinate where one (or both) +of the numbers have non-zero decimal parts would be partially covering +two (or four if both numbers have decimal parts) adjacent pixels, e.g. +the point (1.4, 2) covers 60% of the pixel (1, 2) and 40% of the +pixel (2,2).

+
+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • color (Color or int or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
  • start_pos (tuple(int or float, int or float) or +list(int or float, int or float) or Vector2(int or float, int or float)) -- start position of the line, (x, y)

  • +
  • end_pos (tuple(int or float, int or float) or +list(int or float, int or float) or Vector2(int or float, int or float)) -- end position of the line, (x, y)

  • +
  • blend (int) -- (optional) if non-zero (default) the line will be blended +with the surface's existing pixel shades, otherwise it will overwrite them

  • +
+
+
Returns
+

a rect bounding the changed pixels, if nothing is drawn the +bounding rect's position will be the start_pos parameter value (float +values will be truncated) and its width and height will be 0

+
+
Return type
+

Rect

+
+
Raises
+

TypeError -- if start_pos or end_pos is not a sequence of +two numbers

+
+
+
+

Changed in pygame 2.0.0: Added support for keyword arguments.

+
+
+ +
+
+pygame.draw.aalines()
+
+
draw multiple contiguous straight antialiased line segments
+
aalines(surface, color, closed, points) -> Rect
+
aalines(surface, color, closed, points, blend=1) -> Rect
+
+

Draws a sequence of contiguous straight antialiased lines on the given +surface.

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • color (Color or int or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
  • closed (bool) -- if True an additional line segment is drawn between +the first and last points in the points sequence

  • +
  • points (tuple(coordinate) or list(coordinate)) -- a sequence of 2 or more (x, y) coordinates, where each +coordinate in the sequence must be a +tuple/list/pygame.math.Vector2a 2-Dimensional Vector of 2 ints/floats and adjacent +coordinates will be connected by a line segment, e.g. for the +points [(x1, y1), (x2, y2), (x3, y3)] a line segment will be drawn +from (x1, y1) to (x2, y2) and from (x2, y2) to (x3, y3), +additionally if the closed parameter is True another line segment +will be drawn from (x3, y3) to (x1, y1)

  • +
  • blend (int) -- (optional) if non-zero (default) each line will be blended +with the surface's existing pixel shades, otherwise the pixels will be +overwritten

  • +
+
+
Returns
+

a rect bounding the changed pixels, if nothing is drawn the +bounding rect's position will be the position of the first point in the +points parameter (float values will be truncated) and its width and +height will be 0

+
+
Return type
+

Rect

+
+
Raises
+
    +
  • ValueError -- if len(points) < 2 (must have at least 2 points)

  • +
  • TypeError -- if points is not a sequence or points does not +contain number pairs

  • +
+
+
+
+

Changed in pygame 2.0.0: Added support for keyword arguments.

+
+
+ +
+draw module example +
+

Example code for draw module.

+
+
+
# Import a library of functions called 'pygame'
+import pygame
+from math import pi
+ 
+# Initialize the game engine
+pygame.init()
+ 
+# Define the colors we will use in RGB format
+BLACK = (  0,   0,   0)
+WHITE = (255, 255, 255)
+BLUE =  (  0,   0, 255)
+GREEN = (  0, 255,   0)
+RED =   (255,   0,   0)
+ 
+# Set the height and width of the screen
+size = [400, 300]
+screen = pygame.display.set_mode(size)
+ 
+pygame.display.set_caption("Example code for the draw module")
+ 
+#Loop until the user clicks the close button.
+done = False
+clock = pygame.time.Clock()
+ 
+while not done:
+ 
+    # This limits the while loop to a max of 10 times per second.
+    # Leave this out and we will use all CPU we can.
+    clock.tick(10)
+     
+    for event in pygame.event.get(): # User did something
+        if event.type == pygame.QUIT: # If user clicked close
+            done=True # Flag that we are done so we exit this loop
+ 
+    # All drawing code happens after the for loop and but
+    # inside the main while done==False loop.
+     
+    # Clear the screen and set the screen background
+    screen.fill(WHITE)
+ 
+    # Draw on the screen a GREEN line from (0, 0) to (50, 30) 
+    # 5 pixels wide.
+    pygame.draw.line(screen, GREEN, [0, 0], [50,30], 5)
+ 
+    # Draw on the screen 3 BLACK lines, each 5 pixels wide.
+    # The 'False' means the first and last points are not connected.
+    pygame.draw.lines(screen, BLACK, False, [[0, 80], [50, 90], [200, 80], [220, 30]], 5)
+    
+    # Draw on the screen a GREEN line from (0, 50) to (50, 80) 
+    # Because it is an antialiased line, it is 1 pixel wide.
+    pygame.draw.aaline(screen, GREEN, [0, 50],[50, 80], True)
+
+    # Draw a rectangle outline
+    pygame.draw.rect(screen, BLACK, [75, 10, 50, 20], 2)
+     
+    # Draw a solid rectangle
+    pygame.draw.rect(screen, BLACK, [150, 10, 50, 20])
+
+    # Draw a rectangle with rounded corners
+    pygame.draw.rect(screen, GREEN, [115, 210, 70, 40], 10, border_radius=15)
+    pygame.draw.rect(screen, RED, [135, 260, 50, 30], 0, border_radius=10, border_top_left_radius=0,
+                     border_bottom_right_radius=15)
+
+    # Draw an ellipse outline, using a rectangle as the outside boundaries
+    pygame.draw.ellipse(screen, RED, [225, 10, 50, 20], 2) 
+
+    # Draw an solid ellipse, using a rectangle as the outside boundaries
+    pygame.draw.ellipse(screen, RED, [300, 10, 50, 20]) 
+ 
+    # This draws a triangle using the polygon command
+    pygame.draw.polygon(screen, BLACK, [[100, 100], [0, 200], [200, 200]], 5)
+  
+    # Draw an arc as part of an ellipse. 
+    # Use radians to determine what angle to draw.
+    pygame.draw.arc(screen, BLACK,[210, 75, 150, 125], 0, pi/2, 2)
+    pygame.draw.arc(screen, GREEN,[210, 75, 150, 125], pi/2, pi, 2)
+    pygame.draw.arc(screen, BLUE, [210, 75, 150, 125], pi,3*pi/2, 2)
+    pygame.draw.arc(screen, RED,  [210, 75, 150, 125], 3*pi/2, 2*pi, 2)
+    
+    # Draw a circle
+    pygame.draw.circle(screen, BLUE, [60, 250], 40)
+
+    # Draw only one circle quadrant
+    pygame.draw.circle(screen, BLUE, [250, 250], 40, 0, draw_top_right=True)
+    pygame.draw.circle(screen, RED, [250, 250], 40, 30, draw_top_left=True)
+    pygame.draw.circle(screen, GREEN, [250, 250], 40, 20, draw_bottom_left=True)
+    pygame.draw.circle(screen, BLACK, [250, 250], 40, 10, draw_bottom_right=True)
+
+    # Go ahead and update the screen with what we've drawn.
+    # This MUST happen after all the other drawing commands.
+    pygame.display.flip()
+ 
+# Be IDLE friendly
+pygame.quit()
+
+
+
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/event.html b/venv/Lib/site-packages/pygame/docs/generated/ref/event.html new file mode 100644 index 0000000..4906eb6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/event.html @@ -0,0 +1,715 @@ + + + + + + + + + pygame.event — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.event
+
+
pygame module for interacting with events and queues
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+internally process pygame event handlers
+get events from the queue
+get a single event from the queue
+wait for a single event from the queue
+test if event types are waiting on the queue
+remove all events from the queue
+get the string name from an event id
+control which events are allowed on the queue
+control which events are allowed on the queue
+test if a type of event is blocked from the queue
+control the sharing of input devices with other applications
+test if the program is sharing input devices
+place a new event on the queue
+make custom user event type
+create a new event object
+pygame object for representing events
+

Pygame handles all its event messaging through an event queue. The routines in +this module help you manage that event queue. The input queue is heavily +dependent on the pygame.displaypygame module to control the display window and screen module. If the display has not been +initialized and a video mode not set, the event queue may not work properly.

+

The event queue has an upper limit on the number of events it can hold. When +the queue becomes full new events are quietly dropped. To prevent lost events, +especially input events which signal a quit command, your program must handle +events every frame (with pygame.event.get(), pygame.event.pump(), +pygame.event.wait(), pygame.event.peek() or pygame.event.clear()) +and process them. Not handling events may cause your system to decide your +program has locked up. To speed up queue processing use +pygame.event.set_blocked()control which events are allowed on the queue to limit which events get queued.

+

To get the state of various input devices, you can forego the event queue and +access the input devices directly with their appropriate modules: +pygame.mousepygame module to work with the mouse, pygame.keypygame module to work with the keyboard, and pygame.joystickPygame module for interacting with joysticks, gamepads, and trackballs.. If you use +this method, remember that pygame requires some form of communication with the +system window manager and other parts of the platform. To keep pygame in sync +with the system, you will need to call pygame.event.pump()internally process pygame event handlers to keep +everything current. Usually, this should be called once per game loop. +Note: Joysticks will not send any events until the device has been initialized.

+

The event queue contains pygame.event.EventTypepygame object for representing events event objects. +There are a variety of ways to access the queued events, from simply +checking for the existence of events, to grabbing them directly off the stack. +The event queue also offers some simple filtering which can slightly help +performance by blocking certain event types from the queue. Use +pygame.event.set_allowed()control which events are allowed on the queue and pygame.event.set_blocked()control which events are allowed on the queue to +change this filtering. By default, all event types can be placed on the queue.

+

All pygame.event.EventTypepygame object for representing events instances contain an event type identifier +and attributes specific to that event type. The event type identifier is +accessible as the pygame.event.EventType.typeevent type identifier. property. Any of the +event specific attributes can be accessed through the +pygame.event.EventType.__dict__event attribute dictionary attribute or directly as an attribute +of the event object (as member lookups are passed through to the object's +dictionary values). The event object has no method functions. Users can create +their own new events with the pygame.event.Event()create a new event object function.

+

The event type identifier is in between the values of NOEVENT and +NUMEVENTS. User defined events should have a value in the inclusive range +of USEREVENT to NUMEVENTS - 1. User defined events can get a custom +event number with pygame.event.custom_type()make custom user event type. +It is recommended all user events follow this system.

+

Events support equality and inequality comparisons. Two events are equal if +they are the same type and have identical attribute values.

+

While debugging and experimenting, you can print an event object for a quick +display of its type and members. The function pygame.event.event_name()get the string name from an event id +can be used to get a string representing the name of the event type.

+

Events that come from the system will have a guaranteed set of member +attributes based on the type. The following is a list event types with their +specific attributes.

+
QUIT              none
+ACTIVEEVENT       gain, state
+KEYDOWN           key, mod, unicode, scancode
+KEYUP             key, mod, unicode, scancode
+MOUSEMOTION       pos, rel, buttons, touch
+MOUSEBUTTONUP     pos, button, touch
+MOUSEBUTTONDOWN   pos, button, touch
+JOYAXISMOTION     joy (deprecated), instance_id, axis, value
+JOYBALLMOTION     joy (deprecated), instance_id, ball, rel
+JOYHATMOTION      joy (deprecated), instance_id, hat, value
+JOYBUTTONUP       joy (deprecated), instance_id, button
+JOYBUTTONDOWN     joy (deprecated), instance_id, button
+VIDEORESIZE       size, w, h
+VIDEOEXPOSE       none
+USEREVENT         code
+
+
+
+

Changed in pygame 2.0.0: The joy attribute was deprecated, instance_id was added.

+
+
+

Changed in pygame 2.0.1: The unicode attribute was added to KEYUP event.

+
+

You can also find a list of constants for keyboard keys +here.

+
+

+
+

On MacOSX when a file is opened using a pygame application, a USEREVENT +with its code attribute set to pygame.USEREVENT_DROPFILE is generated. +There is an additional attribute called filename where the name of the file +being accessed is stored.

+
USEREVENT         code=pygame.USEREVENT_DROPFILE, filename
+
+
+
+

New in pygame 1.9.2.

+
+
+

+
+

When compiled with SDL2, pygame has these additional events and their +attributes.

+
AUDIODEVICEADDED   which, iscapture
+AUDIODEVICEREMOVED which, iscapture
+FINGERMOTION       touch_id, finger_id, x, y, dx, dy
+FINGERDOWN         touch_id, finger_id, x, y, dx, dy
+FINGERUP           touch_id, finger_id, x, y, dx, dy
+MOUSEWHEEL         which, flipped, x, y, touch
+MULTIGESTURE       touch_id, x, y, pinched, rotated, num_fingers
+TEXTEDITING        text, start, length
+TEXTINPUT          text
+
+
+
+

New in pygame 1.9.5.

+
+
+

Changed in pygame 2.0.2: Fixed amount horizontal scroll (x, positive to the right and negative to the left).

+
+
+

Changed in pygame 2.0.2: The touch attribute was added to all the MOUSE events.

+
+

The touch attribute of MOUSE events indicates whether or not the events were generated +by a touch input device, and not a real mouse. You might want to ignore such events, if your application +already handles FINGERMOTION, FINGERDOWN and FINGERUP events.

+
+

+
+

Many new events were introduced in pygame 2.

+

pygame can recognize text or files dropped in its window. If a file +is dropped, DROPFILE event will be sent, file will be its path. +The DROPTEXT event is only supported on X11.

+

MIDIIN and MIDIOUT are events reserved for pygame.midipygame module for interacting with midi input and output. use.

+

pygame 2 also supports controller hot-plugging

+
DROPBEGIN
+DROPCOMPLETE
+DROPFILE                 file
+DROPTEXT                 text
+MIDIIN
+MIDIOUT
+CONTROLLERDEVICEADDED    device_index
+JOYDEVICEADDED           device_index
+CONTROLLERDEVICEREMOVED  instance_id
+JOYDEVICEREMOVED         instance_id
+CONTROLLERDEVICEREMAPPED instance_id
+
+
+

Also in this version, instance_id attributes were added to joystick events, +and the joy attribute was deprecated.

+
+

New in pygame 2.0.0.

+
+

Since pygame 2.0.1, there are a new set of events, called window events. +Here is a list of all window events, along with a short description

+
Event type                Short description
+
+WINDOWSHOWN            Window became shown
+WINDOWHIDDEN           Window became hidden
+WINDOWEXPOSED          Window got updated by some external event
+WINDOWMOVED            Window got moved
+WINDOWRESIZED          Window got resized
+WINDOWSIZECHANGED      Window changed its size
+WINDOWMINIMIZED        Window was minimized
+WINDOWMAXIMIZED        Window was maximized
+WINDOWRESTORED         Window was restored
+WINDOWENTER            Mouse entered the window
+WINDOWLEAVE            Mouse left the window
+WINDOWFOCUSGAINED      Window gained focus
+WINDOWFOCUSLOST        Window lost focus
+WINDOWCLOSE            Window was closed
+WINDOWTAKEFOCUS        Window was offered focus
+WINDOWHITTEST          Window has a special hit test
+
+
+

If SDL version used is less than 2.0.5, the last two events WINDOWTAKEFOCUS +and WINDOWHITTEST will not work.

+

Most these window events do not have any attributes, except WINDOWMOVED, +WINDOWRESIZED and WINDOWSIZECHANGED, these have x and y attributes

+
+

+
+
+
+pygame.event.pump()
+
+
internally process pygame event handlers
+
pump() -> None
+
+

For each frame of your game, you will need to make some sort of call to the +event queue. This ensures your program can internally interact with the rest +of the operating system. If you are not using other event functions in your +game, you should call pygame.event.pump() to allow pygame to handle +internal actions.

+

This function is not necessary if your program is consistently processing +events on the queue through the other pygame.eventpygame module for interacting with events and queues functions.

+

There are important things that must be dealt with internally in the event +queue. The main window may need to be repainted or respond to the system. If +you fail to make a call to the event queue for too long, the system may +decide your program has locked up.

+
+

Caution

+

This function should only be called in the thread that initialized pygame.displaypygame module to control the display window and screen.

+
+
+ +
+
+pygame.event.get()
+
+
get events from the queue
+
get(eventtype=None) -> Eventlist
+
get(eventtype=None, pump=True) -> Eventlist
+
get(eventtype=None, pump=True, exclude=None) -> Eventlist
+
+

This will get all the messages and remove them from the queue. If a type or +sequence of types is given only those messages will be removed from the +queue and returned.

+

If a type or sequence of types is passed in the exclude argument +instead, then all only other messages will be removed from the queue. If +an exclude parameter is passed, the eventtype parameter must be +None.

+

If you are only taking specific events from the queue, be aware that the +queue could eventually fill up with the events you are not interested.

+

If pump is True (the default), then pygame.event.pump()internally process pygame event handlers will be called.

+
+

Changed in pygame 1.9.5: Added pump argument

+
+
+

Changed in pygame 2.0.2: Added exclude argument

+
+
+ +
+
+pygame.event.poll()
+
+
get a single event from the queue
+
poll() -> EventType instance
+
+

Returns a single event from the queue. If the event queue is empty an event +of type pygame.NOEVENT will be returned immediately. The returned event +is removed from the queue.

+
+

Caution

+

This function should only be called in the thread that initialized pygame.displaypygame module to control the display window and screen.

+
+
+ +
+
+pygame.event.wait()
+
+
wait for a single event from the queue
+
wait() -> EventType instance
+
wait(timeout) -> EventType instance
+
+

Returns a single event from the queue. If the queue is empty this function +will wait until one is created. From pygame 2.0.0, if a timeout argument +is given, the function will return an event of type pygame.NOEVENT +if no events enter the queue in timeout milliseconds. The event is removed +from the queue once it has been returned. While the program is waiting it will +sleep in an idle state. This is important for programs that want to share the +system with other applications.

+
+

Changed in pygame 2.0.0.dev13: Added timeout argument

+
+
+

Caution

+

This function should only be called in the thread that initialized pygame.displaypygame module to control the display window and screen.

+
+
+ +
+
+pygame.event.peek()
+
+
test if event types are waiting on the queue
+
peek(eventtype=None) -> bool
+
peek(eventtype=None, pump=True) -> bool
+
+

Returns True if there are any events of the given type waiting on the +queue. If a sequence of event types is passed, this will return True if +any of those events are on the queue.

+

If pump is True (the default), then pygame.event.pump()internally process pygame event handlers will be called.

+
+

Changed in pygame 1.9.5: Added pump argument

+
+
+ +
+
+pygame.event.clear()
+
+
remove all events from the queue
+
clear(eventtype=None) -> None
+
clear(eventtype=None, pump=True) -> None
+
+

Removes all events from the queue. If eventtype is given, removes the given event +or sequence of events. This has the same effect as pygame.event.get()get events from the queue except None +is returned. It can be slightly more efficient when clearing a full event queue.

+

If pump is True (the default), then pygame.event.pump()internally process pygame event handlers will be called.

+
+

Changed in pygame 1.9.5: Added pump argument

+
+
+ +
+
+pygame.event.event_name()
+
+
get the string name from an event id
+
event_name(type) -> string
+
+

Returns a string representing the name (in CapWords style) of the given +event type.

+

"UserEvent" is returned for all values in the user event id range. +"Unknown" is returned when the event type does not exist.

+
+ +
+
+pygame.event.set_blocked()
+
+
control which events are allowed on the queue
+
set_blocked(type) -> None
+
set_blocked(typelist) -> None
+
set_blocked(None) -> None
+
+

The given event types are not allowed to appear on the event queue. By +default all events can be placed on the queue. It is safe to disable an +event type multiple times.

+

If None is passed as the argument, ALL of the event types are blocked +from being placed on the queue.

+
+ +
+
+pygame.event.set_allowed()
+
+
control which events are allowed on the queue
+
set_allowed(type) -> None
+
set_allowed(typelist) -> None
+
set_allowed(None) -> None
+
+

The given event types are allowed to appear on the event queue. By default, +all event types can be placed on the queue. It is safe to enable an event +type multiple times.

+

If None is passed as the argument, ALL of the event types are allowed +to be placed on the queue.

+
+ +
+
+pygame.event.get_blocked()
+
+
test if a type of event is blocked from the queue
+
get_blocked(type) -> bool
+
get_blocked(typelist) -> bool
+
+

Returns True if the given event type is blocked from the queue. If a +sequence of event types is passed, this will return True if any of those +event types are blocked.

+
+ +
+
+pygame.event.set_grab()
+
+
control the sharing of input devices with other applications
+
set_grab(bool) -> None
+
+

When your program runs in a windowed environment, it will share the mouse +and keyboard devices with other applications that have focus. If your +program sets the event grab to True, it will lock all input into your +program.

+

It is best to not always grab the input, since it prevents the user from +doing other things on their system.

+
+ +
+
+pygame.event.get_grab()
+
+
test if the program is sharing input devices
+
get_grab() -> bool
+
+

Returns True when the input events are grabbed for this application.

+
+ +
+
+pygame.event.post()
+
+
place a new event on the queue
+
post(Event) -> bool
+
+

Places the given event at the end of the event queue.

+

This is usually used for placing custom events on the event queue. +Any type of event can be posted, and the events posted can have any attributes.

+

This returns a boolean on whether the event was posted or not. Blocked events +cannot be posted, and this function returns False if you try to post them.

+
+

Changed in pygame 2.0.1: returns a boolean, previously returned None

+
+
+ +
+
+pygame.event.custom_type()
+
+
make custom user event type
+
custom_type() -> int
+
+

Reserves a pygame.USEREVENT for a custom use.

+

If too many events are made a pygame.errorstandard pygame exception is raised.

+
+

New in pygame 2.0.0.dev3.

+
+
+ +
+
+pygame.event.Event()
+
+
create a new event object
+
Event(type, dict) -> EventType instance
+
Event(type, **attributes) -> EventType instance
+
+

Creates a new event with the given type and attributes. The attributes can +come from a dictionary argument with string keys or from keyword arguments.

+
+ +
+
+pygame.event.EventType
+
+
pygame object for representing events
+
+ +++++ + + + + + + + + + + +
+event type identifier.
+event attribute dictionary
+

A pygame object that represents an event. User event instances are created +with an pygame.event.Event()create a new event object function call. The EventType type +is not directly callable. EventType instances support attribute +assignment and deletion.

+
+
+type
+
+
event type identifier.
+
type -> int
+
+

Read-only. The event type identifier. For user created event +objects, this is the type argument passed to +pygame.event.Event()create a new event object.

+

For example, some predefined event identifiers are QUIT and +MOUSEMOTION.

+
+ +
+
+__dict__
+
+
event attribute dictionary
+
__dict__ -> dict
+
+

Read-only. The event type specific attributes of an event. The +dict attribute is a synonym for backward compatibility.

+

For example, the attributes of a KEYDOWN event would be unicode, +key, and mod

+
+ +
+

New in pygame 1.9.2: Mutable attributes.

+
+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/examples.html b/venv/Lib/site-packages/pygame/docs/generated/ref/examples.html new file mode 100644 index 0000000..22322e1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/examples.html @@ -0,0 +1,712 @@ + + + + + + + + + pygame.examples — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.examples
+
+
module of example programs
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+play the full aliens example
+run a simple starfield example
+hit the moving chimp
+display animated objects on the screen
+run a font rendering example
+run a FreeType rendering example
+display a vertical gradient
+display pygame events
+show various surfarray effects
+load and play a sound
+play various sndarray effects
+display an animated liquid effect
+display an animated 3D cube using OpenGL
+access the clipboard
+display multiple images bounce off each other using collision detection
+show lots of sprites moving around
+write an image file that is smoothscaled copy of an input file
+demonstrate joystick functionality
+demonstrate the various surface.fill method blend options
+uses alternative additive fill to that of surface.fill
+display two different custom cursors
+display various pixelarray generated effects
+interactively scale an image using smoothscale
+run a midi example
+run a Surface.scroll example that shows a magnified image
+display video captured live from an attached camera
+play an audio file
+

These examples should help get you started with pygame. Here is a brief rundown +of what you get. The source code for these examples is in the public domain. +Feel free to use for your own projects.

+

There are several ways to run the examples. First they can be run as +stand-alone programs. Second they can be imported and their main() methods +called (see below). Finally, the easiest way is to use the python -m option:

+
python -m pygame.examples.<example name> <example arguments>
+
+
+

eg:

+
python -m pygame.examples.scaletest someimage.png
+
+
+

Resources such as images and sounds for the examples are found in the +pygame/examples/data subdirectory.

+

You can find where the example files are installed by using the following +commands inside the python interpreter.

+
>>> import pygame.examples.scaletest
+>>> pygame.examples.scaletest.__file__
+'/usr/lib/python2.6/site-packages/pygame/examples/scaletest.py'
+
+
+

On each OS and version of Python the location will be slightly different. +For example on Windows it might be in 'C:/Python26/Lib/site-packages/pygame/examples/' +On Mac OS X it might be in '/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/pygame/examples/'

+

You can also run the examples in the python interpreter by calling each modules main() function.

+
>>> import pygame.examples.scaletest
+>>> pygame.examples.scaletest.main()
+
+
+

We're always on the lookout for more examples and/or example requests. Code +like this is probably the best way to start getting involved with python +gaming.

+

examples as a package is new to pygame 1.9.0. But most of the examples came with +pygame much earlier.

+
+
+aliens.main()
+
+
play the full aliens example
+
aliens.main() -> None
+
+

This started off as a port of the SDL demonstration, Aliens. Now it has +evolved into something sort of resembling fun. This demonstrates a lot of +different uses of sprites and optimized blitting. Also transparency, +colorkeys, fonts, sound, music, joystick, and more. (PS, my high score is +117! goodluck)

+
+ +
+
+stars.main()
+
+
run a simple starfield example
+
stars.main() -> None
+
+

A simple starfield example. You can change the center of perspective by +leftclicking the mouse on the screen.

+
+ +
+
+chimp.main()
+
+
hit the moving chimp
+
chimp.main() -> None
+
+

This simple example is derived from the line-by-line tutorial that comes +with pygame. It is based on a 'popular' web banner. Note there are comments +here, but for the full explanation, follow along in the tutorial.

+
+ +
+
+moveit.main()
+
+
display animated objects on the screen
+
moveit.main() -> None
+
+

This is the full and final example from the Pygame Tutorial, "How Do I Make +It Move". It creates 10 objects and animates them on the screen.

+

Note it's a bit scant on error checking, but it's easy to read. :] +Fortunately, this is python, and we needn't wrestle with a pile of error +codes.

+
+ +
+
+fonty.main()
+
+
run a font rendering example
+
fonty.main() -> None
+
+

Super quick, super simple application demonstrating the different ways to +render fonts with the font module

+
+ +
+
+freetype_misc.main()
+
+
run a FreeType rendering example
+
freetype_misc.main() -> None
+
+

A showcase of rendering features the pygame.freetype.FontCreate a new Font instance from a supported font file. +class provides in addition to those available with pygame.font.Fontcreate a new Font object from a file. +It is a demonstration of direct to surface rendering, with vertical text +and rotated text, opaque text and semi transparent text, horizontally +stretched text and vertically stretched text.

+
+ +
+
+vgrade.main()
+
+
display a vertical gradient
+
vgrade.main() -> None
+
+

Demonstrates creating a vertical gradient with pixelcopy and NumPy python. +The app will create a new gradient every half second and report the time +needed to create and display the image. If you're not prepared to start +working with the NumPy arrays, don't worry about the source for this one :]

+
+ +
+
+eventlist.main()
+
+
display pygame events
+
eventlist.main() -> None
+
+

Eventlist is a sloppy style of pygame, but is a handy tool for learning +about pygame events and input. At the top of the screen are the state of +several device values, and a scrolling list of events are displayed on the +bottom.

+

This is not quality 'ui' code at all, but you can see how to implement very +non-interactive status displays, or even a crude text output control.

+
+ +
+
+arraydemo.main()
+
+
show various surfarray effects
+
arraydemo.main(arraytype=None) -> None
+
+

Another example filled with various surfarray effects. It requires the +surfarray and image modules to be installed. This little demo can also make +a good starting point for any of your own tests with surfarray

+

The arraytype parameter is deprecated; passing any value besides 'numpy' +will raise ValueError.

+
+ +
+
+sound.main()
+
+
load and play a sound
+
sound.main(file_path=None) -> None
+
+

Extremely basic testing of the mixer module. Load a sound and play it. All +from the command shell, no graphics.

+

If provided, use the audio file 'file_path', otherwise use a default file.

+

sound.py optional command line argument: an audio file

+
+ +
+
+sound_array_demos.main()
+
+
play various sndarray effects
+
sound_array_demos.main(arraytype=None) -> None
+
+

Uses sndarray and NumPy to create offset faded copies of the +original sound. Currently it just uses hardcoded values for the number of +echoes and the delay. Easy for you to recreate as needed.

+

The arraytype parameter is deprecated; passing any value besides 'numpy' +will raise ValueError.

+
+ +
+
+liquid.main()
+
+
display an animated liquid effect
+
liquid.main() -> None
+
+

This example was created in a quick comparison with the BlitzBasic gaming +language. Nonetheless, it demonstrates a quick 8-bit setup (with colormap).

+
+ +
+
+glcube.main()
+
+
display an animated 3D cube using OpenGL
+
glcube.main() -> None
+
+

Using PyOpenGL and pygame, this creates a spinning 3D multicolored cube.

+
+ +
+
+scrap_clipboard.main()
+
+
access the clipboard
+
scrap_clipboard.main() -> None
+
+

A simple demonstration example for the clipboard support.

+
+ +
+
+mask.main()
+
+
display multiple images bounce off each other using collision detection
+
mask.main(*args) -> None
+
+

Positional arguments:

+
one or more image file names.
+
+
+

This pygame.masks demo will display multiple moving sprites bouncing off +each other. More than one sprite image can be provided.

+

If run as a program then mask.py takes one or more image files as +command line arguments.

+
+ +
+
+testsprite.main()
+
+
show lots of sprites moving around
+
testsprite.main(update_rects = True, use_static = False, use_FastRenderGroup = False, screen_dims = [640, 480], use_alpha = False, flags = 0) -> None
+
+

Optional keyword arguments:

+
update_rects - use the RenderUpdate sprite group class
+use_static - include non-moving images
+use_FastRenderGroup - Use the FastRenderGroup sprite group
+screen_dims - pygame window dimensions
+use_alpha - use alpha blending
+flags - additional display mode flags
+
+
+

Like the testsprite.c that comes with SDL, this pygame version shows +lots of sprites moving around.

+

If run as a stand-alone program then no command line arguments are taken.

+
+ +
+
+headless_no_windows_needed.main()
+
+
write an image file that is smoothscaled copy of an input file
+
headless_no_windows_needed.main(fin, fout, w, h) -> None
+
+

arguments:

+
fin - name of an input image file
+fout - name of the output file to create/overwrite
+w, h - size of the rescaled image, as integer width and height
+
+
+

How to use pygame with no windowing system, like on headless servers.

+

Thumbnail generation with scaling is an example of what you can do with +pygame.

+

NOTE: the pygame scale function uses MMX/SSE if available, and can be +run in multiple threads.

+

If headless_no_windows_needed.py is run as a program it takes the +following command line arguments:

+
-scale inputimage outputimage new_width new_height
+eg. -scale in.png outpng 50 50
+
+
+
+ +
+
+joystick.main()
+
+
demonstrate joystick functionality
+
joystick.main() -> None
+
+

A demo showing full joystick support.

+
+

New in pygame 2.0.2.

+
+
+ +
+
+blend_fill.main()
+
+
demonstrate the various surface.fill method blend options
+
blend_fill.main() -> None
+
+

A interactive demo that lets one choose which BLEND_xxx option to apply to a +surface.

+
+ +
+
+blit_blends.main()
+
+
uses alternative additive fill to that of surface.fill
+
blit_blends.main() -> None
+
+

Fake additive blending. Using NumPy. it doesn't clamp. Press r,g,b Somewhat +like blend_fill.

+
+ +
+
+cursors.main()
+
+
display two different custom cursors
+
cursors.main() -> None
+
+

Display an arrow or circle with crossbar cursor.

+
+ +
+
+pixelarray.main()
+
+
display various pixelarray generated effects
+
pixelarray.main() -> None
+
+

Display various pixelarray generated effects.

+
+ +
+
+scaletest.main()
+
+
interactively scale an image using smoothscale
+
scaletest.main(imagefile, convert_alpha=False, run_speed_test=True) -> None
+
+

arguments:

+
imagefile - file name of source image (required)
+convert_alpha - use convert_alpha() on the surf (default False)
+run_speed_test - (default False)
+
+
+

A smoothscale example that resized an image on the screen. Vertical and +horizontal arrow keys are used to change the width and height of the +displayed image. If the convert_alpha option is True then the source image +is forced to have source alpha, whether or not the original images does. If +run_speed_test is True then a background timing test is performed instead of +the interactive scaler.

+

If scaletest.py is run as a program then the command line options are:

+
ImageFile [-t] [-convert_alpha]
+[-t] = Run Speed Test
+[-convert_alpha] = Use convert_alpha() on the surf.
+
+
+
+ +
+
+midi.main()
+
+
run a midi example
+
midi.main(mode='output', device_id=None) -> None
+
+

Arguments:

+
mode - if 'output' run a midi keyboard output example
+          'input' run a midi event logger input example
+          'list' list available midi devices
+       (default 'output')
+device_id - midi device number; if None then use the default midi input or
+            output device for the system
+
+
+

The output example shows how to translate mouse clicks or computer keyboard +events into midi notes. It implements a rudimentary button widget and state +machine.

+

The input example shows how to translate midi input to pygame events.

+

With the use of a virtual midi patch cord the output and input examples can +be run as separate processes and connected so the keyboard output is +displayed on a console.

+

new to pygame 1.9.0

+
+ +
+
+scroll.main()
+
+
run a Surface.scroll example that shows a magnified image
+
scroll.main(image_file=None) -> None
+
+

This example shows a scrollable image that has a zoom factor of eight. It +uses the Surface.scroll() +function to shift the image on the display surface. +A clip rectangle protects a margin area. If called as a function, +the example accepts an optional image file path. If run as a program it +takes an optional file path command line argument. If no file is provided a +default image file is used.

+

When running click on a black triangle to move one pixel in the direction +the triangle points. Or use the arrow keys. Close the window or press +ESC to quit.

+
+ +
+
+camera.main()
+
+
display video captured live from an attached camera
+
camera.main() -> None
+
+

A simple live video player, it uses the first available camera it finds on +the system.

+
+ +
+
+playmus.main()
+
+
play an audio file
+
playmus.main(file_path) -> None
+
+

A simple music player with window and keyboard playback control. Playback can +be paused and rewound to the beginning.

+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/fastevent.html b/venv/Lib/site-packages/pygame/docs/generated/ref/fastevent.html new file mode 100644 index 0000000..c5c8d33 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/fastevent.html @@ -0,0 +1,286 @@ + + + + + + + + + pygame.fastevent — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.fastevent
+
+
pygame module for interacting with events and queues
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+initialize pygame.fastevent
+returns True if the fastevent module is currently initialized
+internally process pygame event handlers
+wait for an event
+get an available event
+get all events from the queue
+place an event on the queue
+

IMPORTANT NOTE: THIS MODULE IS DEPRECATED IN PYGAME 2.2

+

In older pygame versions before pygame 2, pygame.eventpygame module for interacting with events and queues was not well +suited for posting events from different threads. This module served as a +replacement (with less features) for multithreaded use. Now, the usage of this +module is highly discouraged in favour of use of the main pygame.eventpygame module for interacting with events and queues +module. This module will be removed in a future pygame version.

+

Below, the legacy docs of the module is provided

+
+
+pygame.fastevent.init()
+
+
initialize pygame.fastevent
+
init() -> None
+
+

Initialize the pygame.fastevent module.

+
+ +
+
+pygame.fastevent.get_init()
+
+
returns True if the fastevent module is currently initialized
+
get_init() -> bool
+
+

Returns True if the pygame.fastevent module is currently initialized.

+
+ +
+
+pygame.fastevent.pump()
+
+
internally process pygame event handlers
+
pump() -> None
+
+

For each frame of your game, you will need to make some sort of call to the +event queue. This ensures your program can internally interact with the rest +of the operating system.

+

This function is not necessary if your program is consistently processing +events on the queue through the other pygame.fasteventpygame module for interacting with events and queues functions.

+

There are important things that must be dealt with internally in the event +queue. The main window may need to be repainted or respond to the system. If +you fail to make a call to the event queue for too long, the system may +decide your program has locked up.

+
+ +
+
+pygame.fastevent.wait()
+
+
wait for an event
+
wait() -> Event
+
+

Returns the current event on the queue. If there are no messages +waiting on the queue, this will not return until one is available. +Sometimes it is important to use this wait to get events from the queue, +it will allow your application to idle when the user isn't doing anything +with it.

+
+ +
+
+pygame.fastevent.poll()
+
+
get an available event
+
poll() -> Event
+
+

Returns next event on queue. If there is no event waiting on the queue, +this will return an event with type NOEVENT.

+
+ +
+
+pygame.fastevent.get()
+
+
get all events from the queue
+
get() -> list of Events
+
+

This will get all the messages and remove them from the queue.

+
+ +
+
+pygame.fastevent.post()
+
+
place an event on the queue
+
post(Event) -> None
+
+

This will post your own event objects onto the event queue. You can post +any event type you want, but some care must be taken. For example, if you +post a MOUSEBUTTONDOWN event to the queue, it is likely any code receiving +the event will expect the standard MOUSEBUTTONDOWN attributes to be +available, like 'pos' and 'button'.

+

Because pygame.fastevent.post() may have to wait for the queue to empty, +you can get into a dead lock if you try to append an event on to a full +queue from the thread that processes events. For that reason I do not +recommend using this function in the main thread of an SDL program.

+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/font.html b/venv/Lib/site-packages/pygame/docs/generated/ref/font.html new file mode 100644 index 0000000..322a582 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/font.html @@ -0,0 +1,698 @@ + + + + + + + + + pygame.font — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.font
+
+
pygame module for loading and rendering fonts
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+initialize the font module
+uninitialize the font module
+true if the font module is initialized
+get the filename of the default font
+get all available fonts
+find a specific font on the system
+create a Font object from the system fonts
+create a new Font object from a file
+

The font module allows for rendering TrueType fonts into a new Surface object. +It accepts any UCS-2 character ('u0001' to 'uFFFF'). This module is optional +and requires SDL_ttf as a dependency. You should test that pygame.fontpygame module for loading and rendering fonts +is available and initialized before attempting to use the module.

+

Most of the work done with fonts are done by using the actual Font objects. The +module by itself only has routines to initialize the module and create Font +objects with pygame.font.Font().

+

You can load fonts from the system by using the pygame.font.SysFont() +function. There are a few other functions to help lookup the system fonts.

+

Pygame comes with a builtin default font. This can always be accessed by +passing None as the font name.

+

To use the pygame.freetypeEnhanced pygame module for loading and rendering computer fonts based pygame.ftfont as +pygame.fontpygame module for loading and rendering fonts define the environment variable PYGAME_FREETYPE before the +first import of pygamethe top level pygame package. Module pygame.ftfont is a pygame.fontpygame module for loading and rendering fonts +compatible module that passes all but one of the font module unit tests: +it does not have the UCS-2 limitation of the SDL_ttf based font module, so +fails to raise an exception for a code point greater than 'uFFFF'. If +pygame.freetypeEnhanced pygame module for loading and rendering computer fonts is unavailable then the SDL_ttf font module will be +loaded instead.

+
+
+pygame.font.init()
+
+
initialize the font module
+
init() -> None
+
+

This method is called automatically by pygame.init(). It initializes the +font module. The module must be initialized before any other functions will +work.

+

It is safe to call this function more than once.

+
+ +
+
+pygame.font.quit()
+
+
uninitialize the font module
+
quit() -> None
+
+

Manually uninitialize SDL_ttf's font system. This is called automatically by +pygame.quit().

+

It is safe to call this function even if font is currently not initialized.

+
+ +
+
+pygame.font.get_init()
+
+
true if the font module is initialized
+
get_init() -> bool
+
+

Test if the font module is initialized or not.

+
+ +
+
+pygame.font.get_default_font()
+
+
get the filename of the default font
+
get_default_font() -> string
+
+

Return the filename of the system font. This is not the full path to the +file. This file can usually be found in the same directory as the font +module, but it can also be bundled in separate archives.

+
+ +
+
+pygame.font.get_fonts()
+
+
get all available fonts
+
get_fonts() -> list of strings
+
+

Returns a list of all the fonts available on the system. The names of the +fonts will be set to lowercase with all spaces and punctuation removed. This +works on most systems, but some will return an empty list if they cannot +find fonts.

+
+ +
+
+pygame.font.match_font()
+
+
find a specific font on the system
+
match_font(name, bold=False, italic=False) -> path
+
+

Returns the full path to a font file on the system. If bold or italic are +set to true, this will attempt to find the correct family of font.

+

The font name can also be an iterable of font names, a string of +comma-separated font names, or a bytes of comma-separated font names, in +which case the set of names will be searched in order. +If none of the given names are found, None is returned.

+
+

New in pygame 2.0.1: Accept an iterable of font names.

+
+

Example:

+
print pygame.font.match_font('bitstreamverasans')
+# output is: /usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf
+# (but only if you have Vera on your system)
+
+
+
+ +
+
+pygame.font.SysFont()
+
+
create a Font object from the system fonts
+
SysFont(name, size, bold=False, italic=False) -> Font
+
+

Return a new Font object that is loaded from the system fonts. The font will +match the requested bold and italic flags. Pygame uses a small set of common +font aliases. If the specific font you ask for is not available, a reasonable +alternative may be used. If a suitable system font is not found this will +fall back on loading the default pygame font.

+

The font name can also be an iterable of font names, a string of +comma-separated font names, or a bytes of comma-separated font names, in +which case the set of names will be searched in order.

+
+

New in pygame 2.0.1: Accept an iterable of font names.

+
+
+ +
+
+pygame.font.Font
+
+
create a new Font object from a file
+
Font(filename, size) -> Font
+
Font(pathlib.Path, size) -> Font
+
Font(object, size) -> Font
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Gets or sets whether the font should be rendered in (faked) bold.
+Gets or sets whether the font should be rendered in (faked) italics.
+Gets or sets whether the font should be rendered with an underline.
+draw text on a new Surface
+determine the amount of space needed to render text
+control if text is rendered with an underline
+check if text will be rendered with an underline
+enable fake rendering of bold text
+check if text will be rendered bold
+enable fake rendering of italic text
+gets the metrics for each character in the passed string
+check if the text will be rendered italic
+get the line space of the font text
+get the height of the font
+get the ascent of the font
+get the descent of the font
+

Load a new font from a given filename or a python file object. The size is +the height of the font in pixels. If the filename is None the pygame default +font will be loaded. If a font cannot be loaded from the arguments given an +exception will be raised. Once the font is created the size cannot be +changed.

+

Font objects are mainly used to render text into new Surface objects. The +render can emulate bold or italic features, but it is better to load from a +font with actual italic or bold glyphs. The rendered text can be regular +strings or unicode.

+
+
+bold
+
+
Gets or sets whether the font should be rendered in (faked) bold.
+
bold -> bool
+
+

Whether the font should be rendered in bold.

+

When set to True, this enables the bold rendering of text. This +is a fake stretching of the font that doesn't look good on many +font types. If possible load the font from a real bold font +file. While bold, the font will have a different width than when +normal. This can be mixed with the italic and underline modes.

+
+

New in pygame 2.0.0.

+
+
+ +
+
+italic
+
+
Gets or sets whether the font should be rendered in (faked) italics.
+
italic -> bool
+
+

Whether the font should be rendered in italic.

+

When set to True, this enables fake rendering of italic +text. This is a fake skewing of the font that doesn't look good +on many font types. If possible load the font from a real italic +font file. While italic the font will have a different width +than when normal. This can be mixed with the bold and underline +modes.

+
+

New in pygame 2.0.0.

+
+
+ +
+
+underline
+
+
Gets or sets whether the font should be rendered with an underline.
+
underline -> bool
+
+

Whether the font should be rendered in underline.

+

When set to True, all rendered fonts will include an +underline. The underline is always one pixel thick, regardless +of font size. This can be mixed with the bold and italic modes.

+
+

New in pygame 2.0.0.

+
+
+ +
+
+render()
+
+
draw text on a new Surface
+
render(text, antialias, color, background=None) -> Surface
+
+

This creates a new Surface with the specified text rendered on it. pygame +provides no way to directly draw text on an existing Surface: instead you +must use Font.render() to create an image (Surface) of the text, then +blit this image onto another Surface.

+

The text can only be a single line: newline characters are not rendered. +Null characters ('x00') raise a TypeError. Both Unicode and char (byte) +strings are accepted. For Unicode strings only UCS-2 characters +('u0001' to 'uFFFF') were previously supported and any greater unicode +codepoint would raise a UnicodeError. Now, characters in the UCS-4 range +are supported. For char strings a LATIN1 encoding is assumed. The +antialias argument is a boolean: if true the characters will have smooth +edges. The color argument is the color of the text +[e.g.: (0,0,255) for blue]. The optional background argument is a color +to use for the text background. If no background is passed the area +outside the text will be transparent.

+

The Surface returned will be of the dimensions required to hold the text. +(the same as those returned by Font.size()). If an empty string is passed +for the text, a blank surface will be returned that is zero pixel wide and +the height of the font.

+

Depending on the type of background and antialiasing used, this returns +different types of Surfaces. For performance reasons, it is good to know +what type of image will be used. If antialiasing is not used, the return +image will always be an 8-bit image with a two-color palette. If the +background is transparent a colorkey will be set. Antialiased images are +rendered to 24-bit RGB images. If the background is transparent a +pixel alpha will be included.

+

Optimization: if you know that the final destination for the text (on the +screen) will always have a solid background, and the text is antialiased, +you can improve performance by specifying the background color. This will +cause the resulting image to maintain transparency information by +colorkey rather than (much less efficient) alpha values.

+

If you render '\n' an unknown char will be rendered. Usually a +rectangle. Instead you need to handle new lines yourself.

+

Font rendering is not thread safe: only a single thread can render text +at any time.

+
+

Changed in pygame 2.0.3: Rendering UCS_4 unicode works and does not +raise an exception. Use if hasattr(pygame.font, 'UCS_4'): to see if +pygame supports rendering UCS_4 unicode including more languages and +emoji.

+
+
+ +
+
+size()
+
+
determine the amount of space needed to render text
+
size(text) -> (width, height)
+
+

Returns the dimensions needed to render the text. This can be used to +help determine the positioning needed for text before it is rendered. It +can also be used for wordwrapping and other layout effects.

+

Be aware that most fonts use kerning which adjusts the widths for +specific letter pairs. For example, the width for "ae" will not always +match the width for "a" + "e".

+
+ +
+
+set_underline()
+
+
control if text is rendered with an underline
+
set_underline(bool) -> None
+
+

When enabled, all rendered fonts will include an underline. The underline +is always one pixel thick, regardless of font size. This can be mixed +with the bold and italic modes.

+
+

Note

+

This is the same as the underline attribute.

+
+
+ +
+
+get_underline()
+
+
check if text will be rendered with an underline
+
get_underline() -> bool
+
+

Return True when the font underline is enabled.

+
+
+

Note

+

This is the same as the underline attribute.

+
+
+
+ +
+
+set_bold()
+
+
enable fake rendering of bold text
+
set_bold(bool) -> None
+
+

Enables the bold rendering of text. This is a fake stretching of the font +that doesn't look good on many font types. If possible load the font from +a real bold font file. While bold, the font will have a different width +than when normal. This can be mixed with the italic and underline modes.

+
+

Note

+

This is the same as the bold attribute.

+
+
+ +
+
+get_bold()
+
+
check if text will be rendered bold
+
get_bold() -> bool
+
+

Return True when the font bold rendering mode is enabled.

+
+

Note

+

This is the same as the bold attribute.

+
+
+ +
+
+set_italic()
+
+
enable fake rendering of italic text
+
set_italic(bool) -> None
+
+

Enables fake rendering of italic text. This is a fake skewing of the font +that doesn't look good on many font types. If possible load the font from +a real italic font file. While italic the font will have a different +width than when normal. This can be mixed with the bold and underline +modes.

+
+

Note

+

This is the same as the italic attribute.

+
+
+ +
+
+metrics()
+
+
gets the metrics for each character in the passed string
+
metrics(text) -> list
+
+

The list contains tuples for each character, which contain the minimum +X offset, the maximum X offset, the minimum Y offset, the +maximum Y offset and the advance offset (bearing plus width) of the +character. [(minx, maxx, miny, maxy, advance), (minx, maxx, miny, maxy, +advance), ...]. None is entered in the list for each unrecognized +character.

+
+ +
+
+get_italic()
+
+
check if the text will be rendered italic
+
get_italic() -> bool
+
+

Return True when the font italic rendering mode is enabled.

+
+

Note

+

This is the same as the italic attribute.

+
+
+ +
+
+get_linesize()
+
+
get the line space of the font text
+
get_linesize() -> int
+
+

Return the height in pixels for a line of text with the font. When +rendering multiple lines of text this is the recommended amount of space +between lines.

+
+ +
+
+get_height()
+
+
get the height of the font
+
get_height() -> int
+
+

Return the height in pixels of the actual rendered text. This is the +average size for each glyph in the font.

+
+ +
+
+get_ascent()
+
+
get the ascent of the font
+
get_ascent() -> int
+
+

Return the height in pixels for the font ascent. The ascent is the number +of pixels from the font baseline to the top of the font.

+
+ +
+
+get_descent()
+
+
get the descent of the font
+
get_descent() -> int
+
+

Return the height in pixels for the font descent. The descent is the +number of pixels from the font baseline to the bottom of the font.

+
+ +
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/freetype.html b/venv/Lib/site-packages/pygame/docs/generated/ref/freetype.html new file mode 100644 index 0000000..8c293e8 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/freetype.html @@ -0,0 +1,1270 @@ + + + + + + + + + pygame.freetype — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.freetype
+
+
Enhanced pygame module for loading and rendering computer fonts
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Return the latest FreeType error
+Return the FreeType version
+Initialize the underlying FreeType library.
+Shut down the underlying FreeType library.
+Returns True if the FreeType module is currently initialized.
+DEPRECATED: Use get_init() instead.
+Return the glyph case size
+Return the default pixel size in dots per inch
+Set the default pixel size in dots per inch for the module
+create a Font object from the system fonts
+Get the filename of the default font
+Create a new Font instance from a supported font file.
+

The pygame.freetype module is a replacement for pygame.fontpygame module for loading and rendering fonts. +It has all of the functionality of the original, plus many new features. +Yet is has absolutely no dependencies on the SDL_ttf library. +It is implemented directly on the FreeType 2 library. +The pygame.freetype module is not itself backward compatible with +pygame.fontpygame module for loading and rendering fonts. +Instead, use the pygame.ftfont module as a drop-in replacement +for pygame.fontpygame module for loading and rendering fonts.

+

All font file formats supported by FreeType can be rendered by +pygame.freetype, namely TTF, Type1, CFF, OpenType, +SFNT, PCF, FNT, BDF, PFR and Type42 fonts. +All glyphs having UTF-32 code points are accessible +(see Font.ucs4).

+

Most work on fonts is done using Font instances. +The module itself only has routines for initialization and creation +of Font objects. +You can load fonts from the system using the SysFont() function.

+

Extra support of bitmap fonts is available. Available bitmap sizes can +be listed (see Font.get_sizes()). For bitmap only fonts Font +can set the size for you (see the Font.size property).

+

For now undefined character codes are replaced with the .notdef +(not defined) character. +How undefined codes are handled may become configurable in a future release.

+

Pygame comes with a built-in default font. This can always be accessed by +passing None as the font name to the Font constructor.

+

Extra rendering features available to pygame.freetype.FontCreate a new Font instance from a supported font file. +are direct to surface rendering (see Font.render_to()), character kerning +(see Font.kerning), vertical layout (see Font.vertical), +rotation of rendered text (see Font.rotation), +and the strong style (see Font.strong). +Some properties are configurable, such as +strong style strength (see Font.strength) and underline positioning +(see Font.underline_adjustment). Text can be positioned by the upper +right corner of the text box or by the text baseline (see Font.origin). +Finally, a font's vertical and horizontal size can be adjusted separately +(see Font.size). +The pygame.examples.freetype_misc +example shows these features in use.

+

The pygame package does not import freetype automatically when +loaded. This module must be imported explicitly to be used.

+
import pygame
+import pygame.freetype
+
+
+
+

New in pygame 1.9.2: freetype

+
+
+
+pygame.freetype.get_error()
+
+
Return the latest FreeType error
+
get_error() -> str
+
get_error() -> None
+
+

Return a description of the last error which occurred in the FreeType2 +library, or None if no errors have occurred.

+
+ +
+
+pygame.freetype.get_version()
+
+
Return the FreeType version
+
get_version() -> (int, int, int)
+
+

Returns the version of the FreeType library in use by this module.

+

Note that the freetype module depends on the FreeType 2 library. +It will not compile with the original FreeType 1.0. Hence, the first element +of the tuple will always be "2".

+
+ +
+
+pygame.freetype.init()
+
+
Initialize the underlying FreeType library.
+
init(cache_size=64, resolution=72) -> None
+
+

This function initializes the underlying FreeType library and must be +called before trying to use any of the functionality of the freetype +module.

+

However, pygame.init()initialize all imported pygame modules will automatically call this function +if the freetype module is already imported. It is safe to call this +function more than once.

+

Optionally, you may specify a default cache_size for the Glyph cache: the +maximum number of glyphs that will be cached at any given time by the +module. Exceedingly small values will be automatically tuned for +performance. Also a default pixel resolution, in dots per inch, can +be given to adjust font scaling.

+
+ +
+
+pygame.freetype.quit()
+
+
Shut down the underlying FreeType library.
+
quit() -> None
+
+

This function closes the freetype module. After calling this +function, you should not invoke any class, method or function related to the +freetype module as they are likely to fail or might give unpredictable +results. It is safe to call this function even if the module hasn't been +initialized yet.

+
+ +
+
+pygame.freetype.get_init()
+
+
Returns True if the FreeType module is currently initialized.
+
get_init() -> bool
+
+

Returns True if the pygame.freetype module is currently initialized.

+
+

New in pygame 1.9.5.

+
+
+ +
+
+pygame.freetype.was_init()
+
+
DEPRECATED: Use get_init() instead.
+
was_init() -> bool
+
+

DEPRECATED: Returns True if the pygame.freetype module is currently +initialized. Use get_init() instead.

+
+ +
+
+pygame.freetype.get_cache_size()
+
+
Return the glyph case size
+
get_cache_size() -> long
+
+

See pygame.freetype.init()Initialize the underlying FreeType library..

+
+ +
+
+pygame.freetype.get_default_resolution()
+
+
Return the default pixel size in dots per inch
+
get_default_resolution() -> long
+
+

Returns the default pixel size, in dots per inch, for the module. +The default is 72 DPI.

+
+ +
+
+pygame.freetype.set_default_resolution()
+
+
Set the default pixel size in dots per inch for the module
+
set_default_resolution([resolution])
+
+

Set the default pixel size, in dots per inch, for the module. If the +optional argument is omitted or zero the resolution is reset to 72 DPI.

+
+ +
+
+pygame.freetype.SysFont()
+
+
create a Font object from the system fonts
+
SysFont(name, size, bold=False, italic=False) -> Font
+
+

Return a new Font object that is loaded from the system fonts. The font will +match the requested bold and italic flags. Pygame uses a small set of +common font aliases. If the specific font you ask for is not available, a +reasonable alternative may be used. If a suitable system font is not found +this will fall back on loading the default pygame font.

+

The font name can also be an iterable of font names, a string of +comma-separated font names, or a bytes of comma-separated font names, in +which case the set of names will be searched in order.

+
+

New in pygame 2.0.1: Accept an iterable of font names.

+
+
+ +
+
+pygame.freetype.get_default_font()
+
+
Get the filename of the default font
+
get_default_font() -> string
+
+

Return the filename of the default pygame font. This is not the full path +to the file. The file is usually in the same directory as the font module, +but can also be bundled in a separate archive.

+
+ +
+
+pygame.freetype.Font
+
+
Create a new Font instance from a supported font file.
+
Font(file, size=0, font_index=0, resolution=0, ucs4=False) -> Font
+
Font(pathlib.Path) -> Font
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Proper font name.
+Font file path
+The default point size used in rendering
+Return the size and offset of rendered text
+Return the glyph metrics for the given text
+The unscaled height of the font in font units
+The unscaled ascent of the font in font units
+The unscaled descent of the font in font units
+The scaled ascent of the font in pixels
+The scaled descent of the font in pixels
+The scaled height of the font in pixels
+The scaled bounding box height of the font in pixels
+return the available sizes of embedded bitmaps
+Return rendered text as a surface
+Render text onto an existing surface
+Return rendered text as a string of bytes
+Render text into an array of ints
+The font's style flags
+The state of the font's underline style flag
+The state of the font's strong style flag
+The state of the font's oblique style flag
+The state of the font's wide style flag
+The strength associated with the strong or wide font styles
+Adjustment factor for the underline position
+Gets whether the font is fixed-width
+the number of available bitmap sizes for the font
+Gets whether the font is scalable
+allow the use of embedded bitmaps in an outline font file
+Font anti-aliasing mode
+Character kerning mode
+Font vertical mode
+text rotation in degrees counterclockwise
+default foreground color
+default background color
+Font render to text origin mode
+padded boundary mode
+Enable UCS-4 mode
+Pixel resolution in dots per inch
+

Argument file can be either a string representing the font's filename, a +file-like object containing the font, or None; if None, a default, +Pygame, font is used.

+

Optionally, a size argument may be specified to set the default size in +points, which determines the size of the rendered characters. +The size can also be passed explicitly to each method call. +Because of the way the caching system works, specifying a default size on +the constructor doesn't imply a performance gain over manually passing +the size on each function call. If the font is bitmap and no size +is given, the default size is set to the first available size for the font.

+

If the font file has more than one font, the font to load can be chosen with +the index argument. An exception is raised for an out-of-range font index +value.

+

The optional resolution argument sets the pixel size, in dots per inch, +for use in scaling glyphs for this Font instance. If 0 then the default +module value, set by init(), is used. The Font object's +resolution can only be changed by re-initializing the Font instance.

+

The optional ucs4 argument, an integer, sets the default text translation +mode: 0 (False) recognize UTF-16 surrogate pairs, any other value (True), +to treat Unicode text as UCS-4, with no surrogate pairs. See +Font.ucs4.

+
+
+name
+
+
Proper font name.
+
name -> string
+
+

Read only. Returns the real (long) name of the font, as +recorded in the font file.

+
+ +
+
+path
+
+
Font file path
+
path -> unicode
+
+

Read only. Returns the path of the loaded font file

+
+ +
+
+size
+
+
The default point size used in rendering
+
size -> float
+
size -> (float, float)
+
+

Get or set the default size for text metrics and rendering. It can be +a single point size, given as a Python int or float, or a +font ppem (width, height) tuple. Size values are non-negative. +A zero size or width represents an undefined size. In this case +the size must be given as a method argument, or an exception is +raised. A zero width but non-zero height is a ValueError.

+

For a scalable font, a single number value is equivalent to a tuple +with width equal height. A font can be stretched vertically with +height set greater than width, or horizontally with width set +greater than height. For embedded bitmaps, as listed by get_sizes(), +use the nominal width and height to select an available size.

+

Font size differs for a non-scalable, bitmap, font. During a +method call it must match one of the available sizes returned by +method get_sizes(). If not, an exception is raised. +If the size is a single number, the size is first matched against the +point size value. If no match, then the available size with the +same nominal width and height is chosen.

+
+ +
+
+get_rect()
+
+
Return the size and offset of rendered text
+
get_rect(text, style=STYLE_DEFAULT, rotation=0, size=0) -> rect
+
+

Gets the final dimensions and origin, in pixels, of text using the +optional size in points, style, and rotation. For other +relevant render properties, and for any optional argument not given, +the default values set for the Font instance are used.

+

Returns a Rect instance containing the +width and height of the text's bounding box and the position of the +text's origin. +The origin is useful in aligning separately rendered pieces of text. +It gives the baseline position and bearing at the start of the text. +See the render_to() method for an example.

+

If text is a char (byte) string, its encoding is assumed to be +LATIN1.

+

Optionally, text can be None, which will return the bounding +rectangle for the text passed to a previous get_rect(), +render(), render_to(), render_raw(), or +render_raw_to() call. See render_to() for more +details.

+
+ +
+
+get_metrics()
+
+
Return the glyph metrics for the given text
+
get_metrics(text, size=0) -> [(...), ...]
+
+

Returns the glyph metrics for each character in text.

+

The glyph metrics are returned as a list of tuples. Each tuple gives +metrics of a single character glyph. The glyph metrics are:

+
(min_x, max_x, min_y, max_y, horizontal_advance_x, horizontal_advance_y)
+
+
+

The bounding box min_x, max_x, min_y, and max_y values are returned as +grid-fitted pixel coordinates of type int. The advance values are +float values.

+

The calculations are done using the font's default size in points. +Optionally you may specify another point size with the size argument.

+

The metrics are adjusted for the current rotation, strong, and oblique +settings.

+

If text is a char (byte) string, then its encoding is assumed to be +LATIN1.

+
+ +
+
+height
+
+
The unscaled height of the font in font units
+
height -> int
+
+

Read only. Gets the height of the font. This is the average value of all +glyphs in the font.

+
+ +
+
+ascender
+
+
The unscaled ascent of the font in font units
+
ascender -> int
+
+

Read only. Return the number of units from the font's baseline to +the top of the bounding box.

+
+ +
+
+descender
+
+
The unscaled descent of the font in font units
+
descender -> int
+
+

Read only. Return the height in font units for the font descent. +The descent is the number of units from the font's baseline to the +bottom of the bounding box.

+
+ +
+
+get_sized_ascender()
+
+
The scaled ascent of the font in pixels
+
get_sized_ascender(<size>=0) -> int
+
+

Return the number of units from the font's baseline to the top of the +bounding box. It is not adjusted for strong or rotation.

+
+ +
+
+get_sized_descender()
+
+
The scaled descent of the font in pixels
+
get_sized_descender(<size>=0) -> int
+
+

Return the number of pixels from the font's baseline to the top of the +bounding box. It is not adjusted for strong or rotation.

+
+ +
+
+get_sized_height()
+
+
The scaled height of the font in pixels
+
get_sized_height(<size>=0) -> int
+
+

Returns the height of the font. This is the average value of all +glyphs in the font. It is not adjusted for strong or rotation.

+
+ +
+
+get_sized_glyph_height()
+
+
The scaled bounding box height of the font in pixels
+
get_sized_glyph_height(<size>=0) -> int
+
+

Return the glyph bounding box height of the font in pixels. +This is the average value of all glyphs in the font. +It is not adjusted for strong or rotation.

+
+ +
+
+get_sizes()
+
+
return the available sizes of embedded bitmaps
+
get_sizes() -> [(int, int, int, float, float), ...]
+
get_sizes() -> []
+
+

Returns a list of tuple records, one for each point size +supported. Each tuple containing the point size, the height in pixels, +width in pixels, horizontal ppem (nominal width) in fractional pixels, +and vertical ppem (nominal height) in fractional pixels.

+
+ +
+
+render()
+
+
Return rendered text as a surface
+
render(text, fgcolor=None, bgcolor=None, style=STYLE_DEFAULT, rotation=0, size=0) -> (Surface, Rect)
+
+

Returns a new Surface, +with the text rendered to it +in the color given by 'fgcolor'. If no foreground color is given, +the default foreground color, fgcolor is used. +If bgcolor is given, the surface +will be filled with this color. When no background color is given, +the surface background is transparent, zero alpha. Normally the returned +surface has a 32 bit pixel size. However, if bgcolor is None +and anti-aliasing is disabled a monochrome 8 bit colorkey surface, +with colorkey set for the background color, is returned.

+

The return value is a tuple: the new surface and the bounding +rectangle giving the size and origin of the rendered text.

+

If an empty string is passed for text then the returned Rect is zero +width and the height of the font.

+

Optional fgcolor, style, rotation, and size arguments override +the default values set for the Font instance.

+

If text is a char (byte) string, then its encoding is assumed to be +LATIN1.

+

Optionally, text can be None, which will render the text +passed to a previous get_rect(), render(), render_to(), +render_raw(), or render_raw_to() call. +See render_to() for details.

+
+ +
+
+render_to()
+
+
Render text onto an existing surface
+
render_to(surf, dest, text, fgcolor=None, bgcolor=None, style=STYLE_DEFAULT, rotation=0, size=0) -> Rect
+
+

Renders the string text to the pygame.Surfacepygame object for representing images surf, +at position dest, a (x, y) surface coordinate pair. +If either x or y is not an integer it is converted to one if possible. +Any sequence where the first two items are x and y positional elements +is accepted, including a Rect instance. +As with render(), +optional fgcolor, style, rotation, and size argument are +available.

+

If a background color bgcolor is given, the text bounding box is +first filled with that color. The text is blitted next. +Both the background fill and text rendering involve full alpha blits. +That is, the alpha values of the foreground, background, and destination +target surface all affect the blit.

+

The return value is a rectangle giving the size and position of the +rendered text within the surface.

+

If an empty string is passed for text then the returned +Rect is zero width and the height of the font. +The rect will test False.

+

Optionally, text can be set None, which will re-render text +passed to a previous render_to(), get_rect(), render(), +render_raw(), or render_raw_to() call. Primarily, this +feature is an aid to using render_to() in combination with +get_rect(). An example:

+
def word_wrap(surf, text, font, color=(0, 0, 0)):
+    font.origin = True
+    words = text.split(' ')
+    width, height = surf.get_size()
+    line_spacing = font.get_sized_height() + 2
+    x, y = 0, line_spacing
+    space = font.get_rect(' ')
+    for word in words:
+        bounds = font.get_rect(word)
+        if x + bounds.width + bounds.x >= width:
+            x, y = 0, y + line_spacing
+        if x + bounds.width + bounds.x >= width:
+            raise ValueError("word too wide for the surface")
+        if y + bounds.height - bounds.y >= height:
+            raise ValueError("text to long for the surface")
+        font.render_to(surf, (x, y), None, color)
+        x += bounds.width + space.width
+    return x, y
+
+
+

When render_to() is called with the same +font properties ― size, style, strength, +wide, antialiased, vertical, rotation, +kerning, and use_bitmap_strikes ― as get_rect(), +render_to() will use the layout calculated by get_rect(). +Otherwise, render_to() will recalculate the layout if called +with a text string or one of the above properties has changed +after the get_rect() call.

+

If text is a char (byte) string, then its encoding is assumed to be +LATIN1.

+
+ +
+
+render_raw()
+
+
Return rendered text as a string of bytes
+
render_raw(text, style=STYLE_DEFAULT, rotation=0, size=0, invert=False) -> (bytes, (int, int))
+
+

Like render() but with the pixels returned as a byte string +of 8-bit gray-scale values. The foreground color is 255, the +background 0, useful as an alpha mask for a foreground pattern.

+
+ +
+
+render_raw_to()
+
+
Render text into an array of ints
+
render_raw_to(array, text, dest=None, style=STYLE_DEFAULT, rotation=0, size=0, invert=False) -> Rect
+
+

Render to an array object exposing an array struct interface. The array +must be two dimensional with integer items. The default dest value, +None, is equivalent to position (0, 0). See render_to(). +As with the other render methods, text can be None to +render a text string passed previously to another method.

+

The return value is a pygame.Rect()pygame object for storing rectangular coordinates giving the size and position of +the rendered text.

+
+ +
+
+style
+
+
The font's style flags
+
style -> int
+
+

Gets or sets the default style of the Font. This default style will be +used for all text rendering and size calculations unless overridden +specifically a render or get_rect() call. +The style value may be a bit-wise OR of one or more of the following +constants:

+
STYLE_NORMAL
+STYLE_UNDERLINE
+STYLE_OBLIQUE
+STYLE_STRONG
+STYLE_WIDE
+STYLE_DEFAULT
+
+
+

These constants may be found on the FreeType constants module. +Optionally, the default style can be modified or obtained accessing the +individual style attributes (underline, oblique, strong).

+

The STYLE_OBLIQUE and STYLE_STRONG styles are for +scalable fonts only. An attempt to set either for a bitmap font raises +an AttributeError. An attempt to set either for an inactive font, +as returned by Font.__new__(), raises a RuntimeError.

+

Assigning STYLE_DEFAULT to the style property leaves +the property unchanged, as this property defines the default. +The style property will never return STYLE_DEFAULT.

+
+ +
+
+underline
+
+
The state of the font's underline style flag
+
underline -> bool
+
+

Gets or sets whether the font will be underlined when drawing text. This +default style value will be used for all text rendering and size +calculations unless overridden specifically in a render or +get_rect() call, via the 'style' parameter.

+
+ +
+
+strong
+
+
The state of the font's strong style flag
+
strong -> bool
+
+

Gets or sets whether the font will be bold when drawing text. This +default style value will be used for all text rendering and size +calculations unless overridden specifically in a render or +get_rect() call, via the 'style' parameter.

+
+ +
+
+oblique
+
+
The state of the font's oblique style flag
+
oblique -> bool
+
+

Gets or sets whether the font will be rendered as oblique. This +default style value will be used for all text rendering and size +calculations unless overridden specifically in a render or +get_rect() call, via the style parameter.

+

The oblique style is only supported for scalable (outline) fonts. +An attempt to set this style on a bitmap font will raise an +AttributeError. If the font object is inactive, as returned by +Font.__new__(), setting this property raises a RuntimeError.

+
+ +
+
+wide
+
+
The state of the font's wide style flag
+
wide -> bool
+
+

Gets or sets whether the font will be stretched horizontally +when drawing text. It produces a result similar to +pygame.font.Fontcreate a new Font object from a file's bold. This style not available for +rotated text.

+
+ +
+
+strength
+
+
The strength associated with the strong or wide font styles
+
strength -> float
+
+

The amount by which a font glyph's size is enlarged for the +strong or wide transformations, as a fraction of the untransformed +size. For the wide style only the horizontal dimension is +increased. For strong text both the horizontal and vertical +dimensions are enlarged. A wide style of strength 0.08333 ( 1/12 ) is +equivalent to the pygame.font.Fontcreate a new Font object from a file bold style. +The default is 0.02778 ( 1/36 ).

+

The strength style is only supported for scalable (outline) fonts. +An attempt to set this property on a bitmap font will raise an +AttributeError. If the font object is inactive, as returned by +Font.__new__(), assignment to this property raises a RuntimeError.

+
+ +
+
+underline_adjustment
+
+
Adjustment factor for the underline position
+
underline_adjustment -> float
+
+

Gets or sets a factor which, when positive, is multiplied with the +font's underline offset to adjust the underline position. A negative +value turns an underline into a strike-through or overline. It is +multiplied with the ascender. Accepted values range between -2.0 and 2.0 +inclusive. A value of 0.5 closely matches Tango underlining. A value of +1.0 mimics pygame.font.Fontcreate a new Font object from a file underlining.

+
+ +
+
+fixed_width
+
+
Gets whether the font is fixed-width
+
fixed_width -> bool
+
+

Read only. Returns True if the font contains fixed-width +characters (for example Courier, Bitstream Vera Sans Mono, Andale Mono).

+
+ +
+
+fixed_sizes
+
+
the number of available bitmap sizes for the font
+
fixed_sizes -> int
+
+

Read only. Returns the number of point sizes for which the font contains +bitmap character images. If zero then the font is not a bitmap font. +A scalable font may contain pre-rendered point sizes as strikes.

+
+ +
+
+scalable
+
+
Gets whether the font is scalable
+
scalable -> bool
+
+

Read only. Returns True if the font contains outline glyphs. +If so, the point size is not limited to available bitmap sizes.

+
+ +
+
+use_bitmap_strikes
+
+
allow the use of embedded bitmaps in an outline font file
+
use_bitmap_strikes -> bool
+
+

Some scalable fonts include embedded bitmaps for particular point +sizes. This property controls whether or not those bitmap strikes +are used. Set it False to disable the loading of any bitmap +strike. Set it True, the default, to permit bitmap strikes +for a non-rotated render with no style other than wide or +underline. This property is ignored for bitmap fonts.

+

See also fixed_sizes and get_sizes().

+
+ +
+
+antialiased
+
+
Font anti-aliasing mode
+
antialiased -> bool
+
+

Gets or sets the font's anti-aliasing mode. This defaults to +True on all fonts, which are rendered with full 8 bit blending.

+

Set to False to do monochrome rendering. This should +provide a small speed gain and reduce cache memory size.

+
+ +
+
+kerning
+
+
Character kerning mode
+
kerning -> bool
+
+

Gets or sets the font's kerning mode. This defaults to False +on all fonts, which will be rendered without kerning.

+

Set to True to add kerning between character pairs, if supported +by the font, when positioning glyphs.

+
+ +
+
+vertical
+
+
Font vertical mode
+
vertical -> bool
+
+

Gets or sets whether the characters are laid out vertically rather +than horizontally. May be useful when rendering Kanji or some other +vertical script.

+

Set to True to switch to a vertical text layout. The default +is False, place horizontally.

+

Note that the Font class does not automatically determine +script orientation. Vertical layout must be selected explicitly.

+

Also note that several font formats (especially bitmap based ones) don't +contain the necessary metrics to draw glyphs vertically, so drawing in +those cases will give unspecified results.

+
+ +
+
+rotation
+
+
text rotation in degrees counterclockwise
+
rotation -> int
+
+

Gets or sets the baseline angle of the rendered text. The angle is +represented as integer degrees. The default angle is 0, with horizontal +text rendered along the X-axis, and vertical text along the Y-axis. +A positive value rotates these axes counterclockwise that many degrees. +A negative angle corresponds to a clockwise rotation. The rotation +value is normalized to a value within the range 0 to 359 inclusive +(eg. 390 -> 390 - 360 -> 30, -45 -> 360 + -45 -> 315, +720 -> 720 - (2 * 360) -> 0).

+

Only scalable (outline) fonts can be rotated. An attempt to change +the rotation of a bitmap font raises an AttributeError. +An attempt to change the rotation of an inactive font instance, as +returned by Font.__new__(), raises a RuntimeError.

+
+ +
+
+fgcolor
+
+
default foreground color
+
fgcolor -> Color
+
+

Gets or sets the default glyph rendering color. It is initially opaque +black ― (0, 0, 0, 255). Applies to render() and render_to().

+
+ +
+
+bgcolor
+
+
default background color
+
bgcolor -> Color
+
+

Gets or sets the default background rendering color. Initially it is +unset and text will render with a transparent background by default. +Applies to render() and render_to().

+
+ +
+

New in pygame 2.0.0.

+
+
+
+origin
+
+
Font render to text origin mode
+
origin -> bool
+
+

If set True, render_to() and render_raw_to() will +take the dest position to be that of the text origin, as opposed to +the top-left corner of the bounding box. See get_rect() for +details.

+
+ +
+
+pad
+
+
padded boundary mode
+
pad -> bool
+
+

If set True, then the text boundary rectangle will be inflated +to match that of font.Font. +Otherwise, the boundary rectangle is just large enough for the text.

+
+ +
+
+ucs4
+
+
Enable UCS-4 mode
+
ucs4 -> bool
+
+

Gets or sets the decoding of Unicode text. By default, the +freetype module performs UTF-16 surrogate pair decoding on Unicode text. +This allows 32-bit escape sequences ('Uxxxxxxxx') between 0x10000 and +0x10FFFF to represent their corresponding UTF-32 code points on Python +interpreters built with a UCS-2 Unicode type (on Windows, for instance). +It also means character values within the UTF-16 surrogate area (0xD800 +to 0xDFFF) are considered part of a surrogate pair. A malformed surrogate +pair will raise a UnicodeEncodeError. Setting ucs4 True turns +surrogate pair decoding off, allowing access the full UCS-4 character +range to a Python interpreter built with four-byte Unicode character +support.

+
+ +
+
+resolution
+
+
Pixel resolution in dots per inch
+
resolution -> int
+
+

Read only. Gets pixel size used in scaling font glyphs for this +Font instance.

+
+ +
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/gfxdraw.html b/venv/Lib/site-packages/pygame/docs/generated/ref/gfxdraw.html new file mode 100644 index 0000000..c97f7be --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/gfxdraw.html @@ -0,0 +1,1058 @@ + + + + + + + + + pygame.gfxdraw — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.gfxdraw
+
+
pygame module for drawing shapes
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+draw a pixel
+draw a horizontal line
+draw a vertical line
+draw a line
+draw a rectangle
+draw a filled rectangle
+draw a circle
+draw an antialiased circle
+draw a filled circle
+draw an ellipse
+draw an antialiased ellipse
+draw a filled ellipse
+draw an arc
+draw a pie
+draw a trigon/triangle
+draw an antialiased trigon/triangle
+draw a filled trigon/triangle
+draw a polygon
+draw an antialiased polygon
+draw a filled polygon
+draw a textured polygon
+draw a Bezier curve
+

EXPERIMENTAL!: This API may change or disappear in later pygame releases. If +you use this, your code may break with the next pygame release.

+

The pygame package does not import gfxdraw automatically when loaded, so it +must imported explicitly to be used.

+
import pygame
+import pygame.gfxdraw
+
+
+

For all functions the arguments are strictly positional and integers are +accepted for coordinates and radii. The color argument can be one of the +following formats:

+
+
+
+

The functions rectangle() and box() will accept any (x, y, w, h) +sequence for their rect argument, though pygame.Rectpygame object for storing rectangular coordinates instances are +preferred.

+

To draw a filled antialiased shape, first use the antialiased (aa*) version +of the function, and then use the filled (filled_*) version. +For example:

+
col = (255, 0, 0)
+surf.fill((255, 255, 255))
+pygame.gfxdraw.aacircle(surf, x, y, 30, col)
+pygame.gfxdraw.filled_circle(surf, x, y, 30, col)
+
+
+
+

Note

+

For threading, each of the functions releases the GIL during the C part of +the call.

+
+
+

Note

+

See the pygame.drawpygame module for drawing shapes module for alternative draw methods. +The pygame.gfxdraw module differs from the pygame.drawpygame module for drawing shapes module in +the API it uses and the different draw functions available. +pygame.gfxdraw wraps the primitives from the library called SDL_gfx, +rather than using modified versions.

+
+
+

New in pygame 1.9.0.

+
+
+
+pygame.gfxdraw.pixel()
+
+
draw a pixel
+
pixel(surface, x, y, color) -> None
+
+

Draws a single pixel, at position (x ,y), on the given surface.

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • x (int) -- x coordinate of the pixel

  • +
  • y (int) -- y coordinate of the pixel

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+ +
+
+pygame.gfxdraw.hline()
+
+
draw a horizontal line
+
hline(surface, x1, x2, y, color) -> None
+
+

Draws a straight horizontal line ((x1, y) to (x2, y)) on the given +surface. There are no endcaps.

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • x1 (int) -- x coordinate of one end of the line

  • +
  • x2 (int) -- x coordinate of the other end of the line

  • +
  • y (int) -- y coordinate of the line

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+ +
+
+pygame.gfxdraw.vline()
+
+
draw a vertical line
+
vline(surface, x, y1, y2, color) -> None
+
+

Draws a straight vertical line ((x, y1) to (x, y2)) on the given +surface. There are no endcaps.

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • x (int) -- x coordinate of the line

  • +
  • y1 (int) -- y coordinate of one end of the line

  • +
  • y2 (int) -- y coordinate of the other end of the line

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+ +
+
+pygame.gfxdraw.line()
+
+
draw a line
+
line(surface, x1, y1, x2, y2, color) -> None
+
+

Draws a straight line ((x1, y1) to (x2, y2)) on the given surface. +There are no endcaps.

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • x1 (int) -- x coordinate of one end of the line

  • +
  • y1 (int) -- y coordinate of one end of the line

  • +
  • x2 (int) -- x coordinate of the other end of the line

  • +
  • y2 (int) -- y coordinate of the other end of the line

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+ +
+
+pygame.gfxdraw.rectangle()
+
+
draw a rectangle
+
rectangle(surface, rect, color) -> None
+
+

Draws an unfilled rectangle on the given surface. For a filled rectangle use +box().

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • rect (Rect) -- rectangle to draw, position and dimensions

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+

Note

+

The rect.bottom and rect.right attributes of a pygame.Rectpygame object for storing rectangular coordinates +always lie one pixel outside of its actual border. Therefore, these +values will not be included as part of the drawing.

+
+
+ +
+
+pygame.gfxdraw.box()
+
+
draw a filled rectangle
+
box(surface, rect, color) -> None
+
+

Draws a filled rectangle on the given surface. For an unfilled rectangle use +rectangle().

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • rect (Rect) -- rectangle to draw, position and dimensions

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+

Note

+

The rect.bottom and rect.right attributes of a pygame.Rectpygame object for storing rectangular coordinates +always lie one pixel outside of its actual border. Therefore, these +values will not be included as part of the drawing.

+
+
+

Note

+

The pygame.Surface.fill()fill Surface with a solid color method works just as well for drawing +filled rectangles. In fact pygame.Surface.fill()fill Surface with a solid color can be hardware +accelerated on some platforms with both software and hardware display +modes.

+
+
+ +
+
+pygame.gfxdraw.circle()
+
+
draw a circle
+
circle(surface, x, y, r, color) -> None
+
+

Draws an unfilled circle on the given surface. For a filled circle use +filled_circle().

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • x (int) -- x coordinate of the center of the circle

  • +
  • y (int) -- y coordinate of the center of the circle

  • +
  • r (int) -- radius of the circle

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+ +
+
+pygame.gfxdraw.aacircle()
+
+
draw an antialiased circle
+
aacircle(surface, x, y, r, color) -> None
+
+

Draws an unfilled antialiased circle on the given surface.

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • x (int) -- x coordinate of the center of the circle

  • +
  • y (int) -- y coordinate of the center of the circle

  • +
  • r (int) -- radius of the circle

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+ +
+
+pygame.gfxdraw.filled_circle()
+
+
draw a filled circle
+
filled_circle(surface, x, y, r, color) -> None
+
+

Draws a filled circle on the given surface. For an unfilled circle use +circle().

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • x (int) -- x coordinate of the center of the circle

  • +
  • y (int) -- y coordinate of the center of the circle

  • +
  • r (int) -- radius of the circle

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+ +
+
+pygame.gfxdraw.ellipse()
+
+
draw an ellipse
+
ellipse(surface, x, y, rx, ry, color) -> None
+
+

Draws an unfilled ellipse on the given surface. For a filled ellipse use +filled_ellipse().

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • x (int) -- x coordinate of the center of the ellipse

  • +
  • y (int) -- y coordinate of the center of the ellipse

  • +
  • rx (int) -- horizontal radius of the ellipse

  • +
  • ry (int) -- vertical radius of the ellipse

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+ +
+
+pygame.gfxdraw.aaellipse()
+
+
draw an antialiased ellipse
+
aaellipse(surface, x, y, rx, ry, color) -> None
+
+

Draws an unfilled antialiased ellipse on the given surface.

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • x (int) -- x coordinate of the center of the ellipse

  • +
  • y (int) -- y coordinate of the center of the ellipse

  • +
  • rx (int) -- horizontal radius of the ellipse

  • +
  • ry (int) -- vertical radius of the ellipse

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+ +
+
+pygame.gfxdraw.filled_ellipse()
+
+
draw a filled ellipse
+
filled_ellipse(surface, x, y, rx, ry, color) -> None
+
+

Draws a filled ellipse on the given surface. For an unfilled ellipse use +ellipse().

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • x (int) -- x coordinate of the center of the ellipse

  • +
  • y (int) -- y coordinate of the center of the ellipse

  • +
  • rx (int) -- horizontal radius of the ellipse

  • +
  • ry (int) -- vertical radius of the ellipse

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+ +
+
+pygame.gfxdraw.arc()
+
+
draw an arc
+
arc(surface, x, y, r, start_angle, stop_angle, color) -> None
+
+

Draws an arc on the given surface. For an arc with its endpoints connected +to its center use pie().

+

The two angle arguments are given in degrees and indicate the start and stop +positions of the arc. The arc is drawn in a clockwise direction from the +start_angle to the stop_angle. If start_angle == stop_angle, +nothing will be drawn

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • x (int) -- x coordinate of the center of the arc

  • +
  • y (int) -- y coordinate of the center of the arc

  • +
  • r (int) -- radius of the arc

  • +
  • start_angle (int) -- start angle in degrees

  • +
  • stop_angle (int) -- stop angle in degrees

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+

Note

+

This function uses degrees while the pygame.draw.arc()draw an elliptical arc function +uses radians.

+
+
+ +
+
+pygame.gfxdraw.pie()
+
+
draw a pie
+
pie(surface, x, y, r, start_angle, stop_angle, color) -> None
+
+

Draws an unfilled pie on the given surface. A pie is an arc() with its +endpoints connected to its center.

+

The two angle arguments are given in degrees and indicate the start and stop +positions of the pie. The pie is drawn in a clockwise direction from the +start_angle to the stop_angle. If start_angle == stop_angle, +a straight line will be drawn from the center position at the given angle, +to a length of the radius.

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • x (int) -- x coordinate of the center of the pie

  • +
  • y (int) -- y coordinate of the center of the pie

  • +
  • r (int) -- radius of the pie

  • +
  • start_angle (int) -- start angle in degrees

  • +
  • stop_angle (int) -- stop angle in degrees

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+ +
+
+pygame.gfxdraw.trigon()
+
+
draw a trigon/triangle
+
trigon(surface, x1, y1, x2, y2, x3, y3, color) -> None
+
+

Draws an unfilled trigon (triangle) on the given surface. For a filled +trigon use filled_trigon().

+

A trigon can also be drawn using polygon() e.g. +polygon(surface, ((x1, y1), (x2, y2), (x3, y3)), color)

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • x1 (int) -- x coordinate of the first corner of the trigon

  • +
  • y1 (int) -- y coordinate of the first corner of the trigon

  • +
  • x2 (int) -- x coordinate of the second corner of the trigon

  • +
  • y2 (int) -- y coordinate of the second corner of the trigon

  • +
  • x3 (int) -- x coordinate of the third corner of the trigon

  • +
  • y3 (int) -- y coordinate of the third corner of the trigon

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+ +
+
+pygame.gfxdraw.aatrigon()
+
+
draw an antialiased trigon/triangle
+
aatrigon(surface, x1, y1, x2, y2, x3, y3, color) -> None
+
+

Draws an unfilled antialiased trigon (triangle) on the given surface.

+

An aatrigon can also be drawn using aapolygon() e.g. +aapolygon(surface, ((x1, y1), (x2, y2), (x3, y3)), color)

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • x1 (int) -- x coordinate of the first corner of the trigon

  • +
  • y1 (int) -- y coordinate of the first corner of the trigon

  • +
  • x2 (int) -- x coordinate of the second corner of the trigon

  • +
  • y2 (int) -- y coordinate of the second corner of the trigon

  • +
  • x3 (int) -- x coordinate of the third corner of the trigon

  • +
  • y3 (int) -- y coordinate of the third corner of the trigon

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+ +
+
+pygame.gfxdraw.filled_trigon()
+
+
draw a filled trigon/triangle
+
filled_trigon(surface, x1, y1, x2, y2, x3, y3, color) -> None
+
+

Draws a filled trigon (triangle) on the given surface. For an unfilled +trigon use trigon().

+

A filled_trigon can also be drawn using filled_polygon() e.g. +filled_polygon(surface, ((x1, y1), (x2, y2), (x3, y3)), color)

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • x1 (int) -- x coordinate of the first corner of the trigon

  • +
  • y1 (int) -- y coordinate of the first corner of the trigon

  • +
  • x2 (int) -- x coordinate of the second corner of the trigon

  • +
  • y2 (int) -- y coordinate of the second corner of the trigon

  • +
  • x3 (int) -- x coordinate of the third corner of the trigon

  • +
  • y3 (int) -- y coordinate of the third corner of the trigon

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+ +
+
+pygame.gfxdraw.polygon()
+
+
draw a polygon
+
polygon(surface, points, color) -> None
+
+

Draws an unfilled polygon on the given surface. For a filled polygon use +filled_polygon().

+

The adjacent coordinates in the points argument, as well as the first +and last points, will be connected by line segments. +e.g. For the points [(x1, y1), (x2, y2), (x3, y3)] a line segment will +be drawn from (x1, y1) to (x2, y2), from (x2, y2) to +(x3, y3), and from (x3, y3) to (x1, y1).

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • points (tuple(coordinate) or list(coordinate)) -- a sequence of 3 or more (x, y) coordinates, where each +coordinate in the sequence must be a +tuple/list/pygame.math.Vector2a 2-Dimensional Vector of 2 ints/floats (float values +will be truncated)

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
Raises
+
    +
  • ValueError -- if len(points) < 3 (must have at least 3 points)

  • +
  • IndexError -- if len(coordinate) < 2 (each coordinate must have +at least 2 items)

  • +
+
+
+
+ +
+
+pygame.gfxdraw.aapolygon()
+
+
draw an antialiased polygon
+
aapolygon(surface, points, color) -> None
+
+

Draws an unfilled antialiased polygon on the given surface.

+

The adjacent coordinates in the points argument, as well as the first +and last points, will be connected by line segments. +e.g. For the points [(x1, y1), (x2, y2), (x3, y3)] a line segment will +be drawn from (x1, y1) to (x2, y2), from (x2, y2) to +(x3, y3), and from (x3, y3) to (x1, y1).

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • points (tuple(coordinate) or list(coordinate)) -- a sequence of 3 or more (x, y) coordinates, where each +coordinate in the sequence must be a +tuple/list/pygame.math.Vector2a 2-Dimensional Vector of 2 ints/floats (float values +will be truncated)

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
Raises
+
    +
  • ValueError -- if len(points) < 3 (must have at least 3 points)

  • +
  • IndexError -- if len(coordinate) < 2 (each coordinate must have +at least 2 items)

  • +
+
+
+
+ +
+
+pygame.gfxdraw.filled_polygon()
+
+
draw a filled polygon
+
filled_polygon(surface, points, color) -> None
+
+

Draws a filled polygon on the given surface. For an unfilled polygon use +polygon().

+

The adjacent coordinates in the points argument, as well as the first +and last points, will be connected by line segments. +e.g. For the points [(x1, y1), (x2, y2), (x3, y3)] a line segment will +be drawn from (x1, y1) to (x2, y2), from (x2, y2) to +(x3, y3), and from (x3, y3) to (x1, y1).

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • points (tuple(coordinate) or list(coordinate)) -- a sequence of 3 or more (x, y) coordinates, where each +coordinate in the sequence must be a +tuple/list/pygame.math.Vector2a 2-Dimensional Vector of 2 ints/floats (float values +will be truncated)`

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
Raises
+
    +
  • ValueError -- if len(points) < 3 (must have at least 3 points)

  • +
  • IndexError -- if len(coordinate) < 2 (each coordinate must have +at least 2 items)

  • +
+
+
+
+ +
+
+pygame.gfxdraw.textured_polygon()
+
+
draw a textured polygon
+
textured_polygon(surface, points, texture, tx, ty) -> None
+
+

Draws a textured polygon on the given surface. For better performance, the +surface and the texture should have the same format.

+

A per-pixel alpha texture blit to a per-pixel alpha surface will differ from +a pygame.Surface.blit()draw one image onto another blit. Also, a per-pixel alpha texture cannot be +used with an 8-bit per pixel destination.

+

The adjacent coordinates in the points argument, as well as the first +and last points, will be connected by line segments. +e.g. For the points [(x1, y1), (x2, y2), (x3, y3)] a line segment will +be drawn from (x1, y1) to (x2, y2), from (x2, y2) to +(x3, y3), and from (x3, y3) to (x1, y1).

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • points (tuple(coordinate) or list(coordinate)) -- a sequence of 3 or more (x, y) coordinates, where each +coordinate in the sequence must be a +tuple/list/pygame.math.Vector2a 2-Dimensional Vector of 2 ints/floats (float values +will be truncated)

  • +
  • texture (Surface) -- texture to draw on the polygon

  • +
  • tx (int) -- x offset of the texture

  • +
  • ty (int) -- y offset of the texture

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
Raises
+
    +
  • ValueError -- if len(points) < 3 (must have at least 3 points)

  • +
  • IndexError -- if len(coordinate) < 2 (each coordinate must have +at least 2 items)

  • +
+
+
+
+ +
+
+pygame.gfxdraw.bezier()
+
+
draw a Bezier curve
+
bezier(surface, points, steps, color) -> None
+
+

Draws a Bézier curve on the given surface.

+
+
Parameters
+
    +
  • surface (Surface) -- surface to draw on

  • +
  • points (tuple(coordinate) or list(coordinate)) -- a sequence of 3 or more (x, y) coordinates used to form a +curve, where each coordinate in the sequence must be a +tuple/list/pygame.math.Vector2a 2-Dimensional Vector of 2 ints/floats (float values +will be truncated)

  • +
  • steps (int) -- number of steps for the interpolation, the minimum is 2

  • +
  • color (Color or tuple(int, int, int, [int])) -- color to draw with, the alpha value is optional if using a +tuple (RGB[A])

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
Raises
+
    +
  • ValueError -- if steps < 2

  • +
  • ValueError -- if len(points) < 3 (must have at least 3 points)

  • +
  • IndexError -- if len(coordinate) < 2 (each coordinate must have +at least 2 items)

  • +
+
+
+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/image.html b/venv/Lib/site-packages/pygame/docs/generated/ref/image.html new file mode 100644 index 0000000..2444caa --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/image.html @@ -0,0 +1,459 @@ + + + + + + + + + pygame.image — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.image
+
+
pygame module for image transfer
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+load new image from a file (or file-like object)
+save an image to file (or file-like object)
+get version number of the SDL_Image library being used
+test if extended image formats can be loaded
+transfer image to string buffer
+create new Surface from a string buffer
+create a new Surface that shares data inside a bytes buffer
+load new BMP image from a file (or file-like object)
+load an image from a file (or file-like object)
+save a png/jpg image to file (or file-like object)
+

The image module contains functions for loading and saving pictures, as well as +transferring Surfaces to formats usable by other packages.

+

Note that there is no Image class; an image is loaded as a Surface object. The +Surface class allows manipulation (drawing lines, setting pixels, capturing +regions, etc.).

+

The image module is a required dependency of pygame, but it only optionally +supports any extended file formats. By default it can only load uncompressed +BMP images. When built with full image support, the pygame.image.load() +function can support the following formats.

+
+
    +
  • BMP

  • +
  • GIF (non-animated)

  • +
  • JPEG

  • +
  • LBM (and PBM, PGM, PPM)

  • +
  • PCX

  • +
  • PNG

  • +
  • PNM

  • +
  • SVG (limited support, using Nano SVG)

  • +
  • TGA (uncompressed)

  • +
  • TIFF

  • +
  • WEBP

  • +
  • XPM

  • +
+
+
+

New in pygame 2.0: Loading SVG, WebP, PNM

+
+

Saving images only supports a limited set of formats. You can save to the +following formats.

+
+
    +
  • BMP

  • +
  • JPEG

  • +
  • PNG

  • +
  • TGA

  • +
+
+

JPEG and JPG, as well as TIF and TIFF refer to the same file format

+
+

New in pygame 1.8: Saving PNG and JPEG files.

+
+
+
+pygame.image.load()
+
+
load new image from a file (or file-like object)
+
load(filename) -> Surface
+
load(fileobj, namehint="") -> Surface
+
+

Load an image from a file source. You can pass either a filename, a Python +file-like object, or a pathlib.Path.

+

Pygame will automatically determine the image type (e.g., GIF or bitmap) +and create a new Surface object from the data. In some cases it will need to +know the file extension (e.g., GIF images should end in ".gif"). If you +pass a raw file-like object, you may also want to pass the original filename +as the namehint argument.

+

The returned Surface will contain the same color format, colorkey and alpha +transparency as the file it came from. You will often want to call +Surface.convert() with no arguments, to create a copy that will draw +more quickly on the screen.

+

For alpha transparency, like in .png images, use the convert_alpha() +method after loading so that the image has per pixel transparency.

+

pygame may not always be built to support all image formats. At minimum it +will support uncompressed BMP. If pygame.image.get_extended() +returns 'True', you should be able to load most images (including PNG, JPG +and GIF).

+

You should use os.path.join() for compatibility.

+
eg. asurf = pygame.image.load(os.path.join('data', 'bla.png'))
+
+
+
+ +
+
+pygame.image.save()
+
+
save an image to file (or file-like object)
+
save(Surface, filename) -> None
+
save(Surface, fileobj, namehint="") -> None
+
+

This will save your Surface as either a BMP, TGA, PNG, or +JPEG image. If the filename extension is unrecognized it will default to +TGA. Both TGA, and BMP file formats create uncompressed files. +You can pass a filename, a pathlib.Path or a Python file-like object. +For file-like object, the image is saved to TGA format unless +a namehint with a recognizable extension is passed in.

+
+

Note

+

When saving to a file-like object, it seems that for most formats, +the object needs to be flushed after saving to it to make loading +from it possible.

+
+
+

Changed in pygame 1.8: Saving PNG and JPEG files.

+
+
+

Changed in pygame 2.0.0: The namehint parameter was added to make it possible +to save other formats than TGA to a file-like object. +Saving to a file-like object with JPEG is possible.

+
+
+ +
+
+pygame.image.get_sdl_image_version()
+
+
get version number of the SDL_Image library being used
+
get_sdl_image_version() -> None
+
get_sdl_image_version() -> (major, minor, patch)
+
+

If pygame is built with extended image formats, then this function will +return the SDL_Image library's version number as a tuple of 3 integers +(major, minor, patch). If not, then it will return None.

+
+

New in pygame 2.0.0.

+
+
+ +
+
+pygame.image.get_extended()
+
+
test if extended image formats can be loaded
+
get_extended() -> bool
+
+

If pygame is built with extended image formats this function will return +True. It is still not possible to determine which formats will be available, +but generally you will be able to load them all.

+
+ +
+
+pygame.image.tostring()
+
+
transfer image to string buffer
+
tostring(Surface, format, flipped=False) -> string
+
+

Creates a string that can be transferred with the 'fromstring' method in +other Python imaging packages. Some Python image packages prefer their +images in bottom-to-top format (PyOpenGL for example). If you pass True for +the flipped argument, the string buffer will be vertically flipped.

+

The format argument is a string of one of the following values. Note that +only 8-bit Surfaces can use the "P" format. The other formats will work for +any Surface. Also note that other Python image packages support more formats +than pygame.

+
+
    +
  • P, 8-bit palettized Surfaces

  • +
  • RGB, 24-bit image

  • +
  • RGBX, 32-bit image with unused space

  • +
  • RGBA, 32-bit image with an alpha channel

  • +
  • ARGB, 32-bit image with alpha channel first

  • +
  • RGBA_PREMULT, 32-bit image with colors scaled by alpha channel

  • +
  • ARGB_PREMULT, 32-bit image with colors scaled by alpha channel, alpha channel first

  • +
+
+
+ +
+
+pygame.image.fromstring()
+
+
create new Surface from a string buffer
+
fromstring(string, size, format, flipped=False) -> Surface
+
+

This function takes arguments similar to pygame.image.tostring(). The +size argument is a pair of numbers representing the width and height. Once +the new Surface is created you can destroy the string buffer.

+

The size and format image must compute the exact same size as the passed +string buffer. Otherwise an exception will be raised.

+

See the pygame.image.frombuffer() method for a potentially faster way to +transfer images into pygame.

+
+ +
+
+pygame.image.frombuffer()
+
+
create a new Surface that shares data inside a bytes buffer
+
frombuffer(bytes, size, format) -> Surface
+
+

Create a new Surface that shares pixel data directly from a bytes buffer. +This method takes similar arguments to pygame.image.fromstring(), but +is unable to vertically flip the source data.

+

This will run much faster than pygame.image.fromstring()create new Surface from a string buffer, since no +pixel data must be allocated and copied.

+

It accepts the following 'format' arguments:

+
+
    +
  • P, 8-bit palettized Surfaces

  • +
  • RGB, 24-bit image

  • +
  • BGR, 24-bit image, red and blue channels swapped.

  • +
  • RGBX, 32-bit image with unused space

  • +
  • RGBA, 32-bit image with an alpha channel

  • +
  • ARGB, 32-bit image with alpha channel first

  • +
+
+
+ +
+
+pygame.image.load_basic()
+
+
load new BMP image from a file (or file-like object)
+
load_basic(file) -> Surface
+
+

Load an image from a file source. You can pass either a filename or a Python +file-like object, or a pathlib.Path.

+

This function only supports loading "basic" image format, ie BMP +format. +This function is always available, no matter how pygame was built.

+
+ +
+
+pygame.image.load_extended()
+
+
load an image from a file (or file-like object)
+
load_extended(filename) -> Surface
+
load_extended(fileobj, namehint="") -> Surface
+
+

This function is similar to pygame.image.load(), except that this +function can only be used if pygame was built with extended image format +support.

+

From version 2.0.1, this function is always available, but raises an +error if extended image formats are not supported. Previously, this +function may or may not be available, depending on the state of +extended image format support.

+
+

Changed in pygame 2.0.1.

+
+
+ +
+
+pygame.image.save_extended()
+
+
save a png/jpg image to file (or file-like object)
+
save_extended(Surface, filename) -> None
+
save_extended(Surface, fileobj, namehint="") -> None
+
+

This will save your Surface as either a PNG or JPEG image.

+

Incase the image is being saved to a file-like object, this function +uses the namehint argument to determine the format of the file being +saved. Saves to JPEG incase the namehint was not specified while +saving to file-like object.

+
+

Changed in pygame 2.0.1: This function is always available, but raises an +error if extended image formats are not supported. +Previously, this function may or may not be +available, depending on the state of extended image +format support.

+
+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/joystick.html b/venv/Lib/site-packages/pygame/docs/generated/ref/joystick.html new file mode 100644 index 0000000..703da99 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/joystick.html @@ -0,0 +1,984 @@ + + + + + + + + + pygame.joystick — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.joystick
+
+
Pygame module for interacting with joysticks, gamepads, and trackballs.
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + +
+Initialize the joystick module.
+Uninitialize the joystick module.
+Returns True if the joystick module is initialized.
+Returns the number of joysticks.
+Create a new Joystick object.
+

The joystick module manages the joystick devices on a computer. +Joystick devices include trackballs and video-game-style +gamepads, and the module allows the use of multiple buttons and "hats". +Computers may manage multiple joysticks at a time.

+

Each instance of the Joystick class represents one gaming device plugged +into the computer. If a gaming pad has multiple joysticks on it, then the +joystick object can actually represent multiple joysticks on that single +game device.

+

For a quick way to initialise the joystick module and get a list of Joystick instances +use the following code:

+
pygame.joystick.init()
+joysticks = [pygame.joystick.Joystick(x) for x in range(pygame.joystick.get_count())]
+
+
+

The following event types will be generated by the joysticks

+
JOYAXISMOTION JOYBALLMOTION JOYBUTTONDOWN JOYBUTTONUP JOYHATMOTION
+
+
+

And in pygame 2, which supports hotplugging:

+
JOYDEVICEADDED JOYDEVICEREMOVED
+
+
+

Note that in pygame 2, joysticks events use a unique "instance ID". The device index +passed in the constructor to a Joystick object is not unique after devices have +been added and removed. You must call Joystick.get_instance_id() to find +the instance ID that was assigned to a Joystick on opening.

+

The event queue needs to be pumped frequently for some of the methods to work. +So call one of pygame.event.get, pygame.event.wait, or pygame.event.pump regularly.

+
+
+pygame.joystick.init()
+
+
Initialize the joystick module.
+
init() -> None
+
+

This function is called automatically by pygame.init().

+

It initializes the joystick module. The module must be initialized before any +other functions will work.

+

It is safe to call this function more than once.

+
+ +
+
+pygame.joystick.quit()
+
+
Uninitialize the joystick module.
+
quit() -> None
+
+

Uninitialize the joystick module. After you call this any existing joystick +objects will no longer work.

+

It is safe to call this function more than once.

+
+ +
+
+pygame.joystick.get_init()
+
+
Returns True if the joystick module is initialized.
+
get_init() -> bool
+
+

Test if the pygame.joystick.init() function has been called.

+
+ +
+
+pygame.joystick.get_count()
+
+
Returns the number of joysticks.
+
get_count() -> count
+
+

Return the number of joystick devices on the system. The count will be 0 +if there are no joysticks on the system.

+

When you create Joystick objects using Joystick(id), you pass an integer +that must be lower than this count.

+
+ +
+
+pygame.joystick.Joystick
+
+
Create a new Joystick object.
+
Joystick(id) -> Joystick
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+initialize the Joystick
+uninitialize the Joystick
+check if the Joystick is initialized
+get the device index (deprecated)
+get the joystick instance id
+get the joystick GUID
+get the approximate power status of the device
+get the Joystick system name
+get the number of axes on a Joystick
+get the current position of an axis
+get the number of trackballs on a Joystick
+get the relative position of a trackball
+get the number of buttons on a Joystick
+get the current button state
+get the number of hat controls on a Joystick
+get the position of a joystick hat
+Start a rumbling effect
+Stop any rumble effect playing
+

Create a new joystick to access a physical device. The id argument must be a +value from 0 to pygame.joystick.get_count() - 1.

+

Joysticks are initialised on creation and are shut down when deallocated. +Once the device is initialized the pygame event queue will start receiving +events about its input.

+
+

Changed in pygame 2.0.0: Joystick objects are now opened immediately on creation.

+
+
+
+init()
+
+
initialize the Joystick
+
init() -> None
+
+

Initialize the joystick, if it has been closed. It is safe to call this +even if the joystick is already initialized.

+
+

Deprecated since pygame 2.0.0: In future it will not be possible to reinitialise a closed Joystick +object. Will be removed in Pygame 2.1.

+
+
+ +
+
+quit()
+
+
uninitialize the Joystick
+
quit() -> None
+
+

Close a Joystick object. After this the pygame event queue will no longer +receive events from the device.

+

It is safe to call this more than once.

+
+ +
+
+get_init()
+
+
check if the Joystick is initialized
+
get_init() -> bool
+
+

Return True if the Joystick object is currently initialised.

+
+ +
+
+get_id()
+
+
get the device index (deprecated)
+
get_id() -> int
+
+

Returns the original device index for this device. This is the same +value that was passed to the Joystick() constructor. This method can +safely be called while the Joystick is not initialized.

+
+

Deprecated since pygame 2.0.0: The original device index is not useful in pygame 2. Use +get_instance_id() instead. Will be removed in Pygame 2.1.

+
+
+ +
+
+get_instance_id() int
+
+
get the joystick instance id
+
get_instance_id() -> int
+
+

Get the joystick instance ID. This matches the instance_id field +that is given in joystick events.

+
+

New in pygame 2.0.0dev11.

+
+
+ +
+
+get_guid() str
+
+
get the joystick GUID
+
get_guid() -> str
+
+

Get the GUID string. This identifies the exact hardware of the joystick +device.

+
+

New in pygame 2.0.0dev11.

+
+
+ +
+
+get_power_level() str
+
+
get the approximate power status of the device
+
get_power_level() -> str
+
+

Get a string giving the power status of the device.

+

One of: empty, low, medium, full, wired, max, or +unknown.

+
+

New in pygame 2.0.0dev11.

+
+
+ +
+
+get_name()
+
+
get the Joystick system name
+
get_name() -> string
+
+

Returns the system name for this joystick device. It is unknown what name +the system will give to the Joystick, but it should be a unique name that +identifies the device. This method can safely be called while the +Joystick is not initialized.

+
+ +
+
+get_numaxes()
+
+
get the number of axes on a Joystick
+
get_numaxes() -> int
+
+

Returns the number of input axes are on a Joystick. There will usually be +two for the position. Controls like rudders and throttles are treated as +additional axes.

+

The pygame.JOYAXISMOTION events will be in the range from -1.0 +to 1.0. A value of 0.0 means the axis is centered. Gamepad devices +will usually be -1, 0, or 1 with no values in between. Older +analog joystick axes will not always use the full -1 to 1 range, +and the centered value will be some area around 0.

+

Analog joysticks usually have a bit of noise in their axis, which will +generate a lot of rapid small motion events.

+
+ +
+
+get_axis()
+
+
get the current position of an axis
+
get_axis(axis_number) -> float
+
+

Returns the current position of a joystick axis. The value will range +from -1 to 1 with a value of 0 being centered. You may want +to take into account some tolerance to handle jitter, and joystick drift +may keep the joystick from centering at 0 or using the full range of +position values.

+

The axis number must be an integer from 0 to get_numaxes() - 1.

+

When using gamepads both the control sticks and the analog triggers are +usually reported as axes.

+
+ +
+
+get_numballs()
+
+
get the number of trackballs on a Joystick
+
get_numballs() -> int
+
+

Returns the number of trackball devices on a Joystick. These devices work +similar to a mouse but they have no absolute position; they only have +relative amounts of movement.

+

The pygame.JOYBALLMOTION event will be sent when the trackball is +rolled. It will report the amount of movement on the trackball.

+
+ +
+
+get_ball()
+
+
get the relative position of a trackball
+
get_ball(ball_number) -> x, y
+
+

Returns the relative movement of a joystick button. The value is a x, y +pair holding the relative movement since the last call to get_ball.

+

The ball number must be an integer from 0 to get_numballs() - 1.

+
+ +
+
+get_numbuttons()
+
+
get the number of buttons on a Joystick
+
get_numbuttons() -> int
+
+

Returns the number of pushable buttons on the joystick. These buttons +have a boolean (on or off) state.

+

Buttons generate a pygame.JOYBUTTONDOWN and pygame.JOYBUTTONUP +event when they are pressed and released.

+
+ +
+
+get_button()
+
+
get the current button state
+
get_button(button) -> bool
+
+

Returns the current state of a joystick button.

+
+ +
+
+get_numhats()
+
+
get the number of hat controls on a Joystick
+
get_numhats() -> int
+
+

Returns the number of joystick hats on a Joystick. Hat devices are like +miniature digital joysticks on a joystick. Each hat has two axes of +input.

+

The pygame.JOYHATMOTION event is generated when the hat changes +position. The position attribute for the event contains a pair of +values that are either -1, 0, or 1. A position of (0, 0) +means the hat is centered.

+
+ +
+
+get_hat()
+
+
get the position of a joystick hat
+
get_hat(hat_number) -> x, y
+
+

Returns the current position of a position hat. The position is given as +two values representing the x and y position for the hat. (0, 0) +means centered. A value of -1 means left/down and a value of 1 means +right/up: so (-1, 0) means left; (1, 0) means right; (0, 1) means +up; (1, 1) means upper-right; etc.

+

This value is digital, i.e., each coordinate can be -1, 0 or 1 +but never in-between.

+

The hat number must be between 0 and get_numhats() - 1.

+
+ +
+
+rumble()
+
+
Start a rumbling effect
+
rumble(low_frequency, high_frequency, duration) -> bool
+
+

Start a rumble effect on the joystick, with the specified strength ranging +from 0 to 1. Duration is length of the effect, in ms. Setting the duration +to 0 will play the effect until another one overwrites it or +Joystick.stop_rumble() is called. If an effect is already +playing, then it will be overwritten.

+

Returns True if the rumble was played successfully or False if the +joystick does not support it or pygame.version.SDL()tupled integers of the SDL library version is below 2.0.9.

+
+

New in pygame 2.0.2.

+
+
+ +
+
+stop_rumble()
+
+
Stop any rumble effect playing
+
stop_rumble() -> None
+
+

Stops any rumble effect playing on the joystick. See +Joystick.rumble() for more information.

+
+

New in pygame 2.0.2.

+
+
+ +
+ +
+joystick module example +
+

Example code for joystick module.

+
+
+
import pygame
+
+
+# Define some colors.
+BLACK = pygame.Color('black')
+WHITE = pygame.Color('white')
+
+
+# This is a simple class that will help us print to the screen.
+# It has nothing to do with the joysticks, just outputting the
+# information.
+class TextPrint(object):
+    def __init__(self):
+        self.reset()
+        self.font = pygame.font.Font(None, 20)
+
+    def tprint(self, screen, textString):
+        textBitmap = self.font.render(textString, True, BLACK)
+        screen.blit(textBitmap, (self.x, self.y))
+        self.y += self.line_height
+
+    def reset(self):
+        self.x = 10
+        self.y = 10
+        self.line_height = 15
+
+    def indent(self):
+        self.x += 10
+
+    def unindent(self):
+        self.x -= 10
+
+
+pygame.init()
+
+# Set the width and height of the screen (width, height).
+screen = pygame.display.set_mode((500, 700))
+
+pygame.display.set_caption("My Game")
+
+# Loop until the user clicks the close button.
+done = False
+
+# Used to manage how fast the screen updates.
+clock = pygame.time.Clock()
+
+# Initialize the joysticks.
+pygame.joystick.init()
+
+# Get ready to print.
+textPrint = TextPrint()
+
+# -------- Main Program Loop -----------
+while not done:
+    #
+    # EVENT PROCESSING STEP
+    #
+    # Possible joystick actions: JOYAXISMOTION, JOYBALLMOTION, JOYBUTTONDOWN,
+    # JOYBUTTONUP, JOYHATMOTION
+    for event in pygame.event.get(): # User did something.
+        if event.type == pygame.QUIT: # If user clicked close.
+            done = True # Flag that we are done so we exit this loop.
+        elif event.type == pygame.JOYBUTTONDOWN:
+            print("Joystick button pressed.")
+        elif event.type == pygame.JOYBUTTONUP:
+            print("Joystick button released.")
+
+    #
+    # DRAWING STEP
+    #
+    # First, clear the screen to white. Don't put other drawing commands
+    # above this, or they will be erased with this command.
+    screen.fill(WHITE)
+    textPrint.reset()
+
+    # Get count of joysticks.
+    joystick_count = pygame.joystick.get_count()
+
+    textPrint.tprint(screen, "Number of joysticks: {}".format(joystick_count))
+    textPrint.indent()
+
+    # For each joystick:
+    for i in range(joystick_count):
+        joystick = pygame.joystick.Joystick(i)
+        joystick.init()
+
+        try:
+            jid = joystick.get_instance_id()
+        except AttributeError:
+            # get_instance_id() is an SDL2 method
+            jid = joystick.get_id()
+        textPrint.tprint(screen, "Joystick {}".format(jid))
+        textPrint.indent()
+
+        # Get the name from the OS for the controller/joystick.
+        name = joystick.get_name()
+        textPrint.tprint(screen, "Joystick name: {}".format(name))
+
+        try:
+            guid = joystick.get_guid()
+        except AttributeError:
+            # get_guid() is an SDL2 method
+            pass
+        else:
+            textPrint.tprint(screen, "GUID: {}".format(guid))
+
+        # Usually axis run in pairs, up/down for one, and left/right for
+        # the other.
+        axes = joystick.get_numaxes()
+        textPrint.tprint(screen, "Number of axes: {}".format(axes))
+        textPrint.indent()
+
+        for i in range(axes):
+            axis = joystick.get_axis(i)
+            textPrint.tprint(screen, "Axis {} value: {:>6.3f}".format(i, axis))
+        textPrint.unindent()
+
+        buttons = joystick.get_numbuttons()
+        textPrint.tprint(screen, "Number of buttons: {}".format(buttons))
+        textPrint.indent()
+
+        for i in range(buttons):
+            button = joystick.get_button(i)
+            textPrint.tprint(screen,
+                             "Button {:>2} value: {}".format(i, button))
+        textPrint.unindent()
+
+        hats = joystick.get_numhats()
+        textPrint.tprint(screen, "Number of hats: {}".format(hats))
+        textPrint.indent()
+
+        # Hat position. All or nothing for direction, not a float like
+        # get_axis(). Position is a tuple of int values (x, y).
+        for i in range(hats):
+            hat = joystick.get_hat(i)
+            textPrint.tprint(screen, "Hat {} value: {}".format(i, str(hat)))
+        textPrint.unindent()
+
+        textPrint.unindent()
+
+    #
+    # ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
+    #
+
+    # Go ahead and update the screen with what we've drawn.
+    pygame.display.flip()
+
+    # Limit to 20 frames per second.
+    clock.tick(20)
+
+# Close the window and quit.
+# If you forget this line, the program will 'hang'
+# on exit if running from IDLE.
+pygame.quit()
+
+
+
+

Common Controller Axis Mappings

+

Controller mappings are drawn from the underlying SDL library which pygame uses and they differ +between pygame 1 and pygame 2. Below are a couple of mappings for two popular game pads.

+

Pygame 2

+

Axis and hat mappings are listed from -1 to +1.

+

X-Box 360 Controller (name: "Xbox 360 Controller")

+

In pygame 2 the X360 controller mapping has 6 Axes, 11 buttons and 1 hat.

+
    +
  • Left Stick:

    +
    Left -> Right   - Axis 0
    +Up   -> Down    - Axis 1
    +
    +
    +
  • +
  • Right Stick:

    +
    Left -> Right   - Axis 3
    +Up   -> Down    - Axis 4
    +
    +
    +
  • +
  • Left Trigger:

    +
    Out -> In       - Axis 2
    +
    +
    +
  • +
  • Right Trigger:

    +
    Out -> In       - Axis 5
    +
    +
    +
  • +
  • Buttons:

    +
    A Button        - Button 0
    +B Button        - Button 1
    +X Button        - Button 2
    +Y Button        - Button 3
    +Left Bumper     - Button 4
    +Right Bumper    - Button 5
    +Back Button     - Button 6
    +Start Button    - Button 7
    +L. Stick In     - Button 8
    +R. Stick In     - Button 9
    +Guide Button    - Button 10
    +
    +
    +
  • +
  • Hat/D-pad:

    +
    Down -> Up      - Y Axis
    +Left -> Right   - X Axis
    +
    +
    +
  • +
+

Playstation 4 Controller (name: "PS4 Controller")

+

In pygame 2 the PS4 controller mapping has 6 Axes and 16 buttons.

+
    +
  • Left Stick:

    +
    Left -> Right   - Axis 0
    +Up   -> Down    - Axis 1
    +
    +
    +
  • +
  • Right Stick:

    +
    Left -> Right   - Axis 2
    +Up   -> Down    - Axis 3
    +
    +
    +
  • +
  • Left Trigger:

    +
    Out -> In       - Axis 4
    +
    +
    +
  • +
  • Right Trigger:

    +
    Out -> In       - Axis 5
    +
    +
    +
  • +
  • Buttons:

    +
    Cross Button    - Button 0
    +Circle Button   - Button 1
    +Square Button   - Button 2
    +Triangle Button - Button 3
    +Share Button    - Button 4
    +PS Button       - Button 5
    +Options Button  - Button 6
    +L. Stick In     - Button 7
    +R. Stick In     - Button 8
    +Left Bumper     - Button 9
    +Right Bumper    - Button 10
    +D-pad Up        - Button 11
    +D-pad Down      - Button 12
    +D-pad Left      - Button 13
    +D-pad Right     - Button 14
    +Touch Pad Click - Button 15
    +
    +
    +
  • +
+

Pygame 1

+

Axis and hat mappings are listed from -1 to +1.

+

X-Box 360 Controller (name: "Controller (XBOX 360 For Windows)")

+

In pygame 1 the X360 controller mapping has 5 Axes, 10 buttons and 1 hat.

+
    +
  • Left Stick:

    +
    Left -> Right   - Axis 0
    +Up   -> Down    - Axis 1
    +
    +
    +
  • +
  • Right Stick:

    +
    Left -> Right   - Axis 4
    +Up   -> Down    - Axis 3
    +
    +
    +
  • +
  • Left Trigger & Right Trigger:

    +
    RT -> LT        - Axis 2
    +
    +
    +
  • +
  • Buttons:

    +
    A Button        - Button 0
    +B Button        - Button 1
    +X Button        - Button 2
    +Y Button        - Button 3
    +Left Bumper     - Button 4
    +Right Bumper    - Button 5
    +Back Button     - Button 6
    +Start Button    - Button 7
    +L. Stick In     - Button 8
    +R. Stick In     - Button 9
    +
    +
    +
  • +
  • Hat/D-pad:

    +
    Down -> Up      - Y Axis
    +Left -> Right   - X Axis
    +
    +
    +
  • +
+

Playstation 4 Controller (name: "Wireless Controller")

+

In pygame 1 the PS4 controller mapping has 6 Axes and 14 buttons and 1 hat.

+
    +
  • Left Stick:

    +
    Left -> Right   - Axis 0
    +Up   -> Down    - Axis 1
    +
    +
    +
  • +
  • Right Stick:

    +
    Left -> Right   - Axis 2
    +Up   -> Down    - Axis 3
    +
    +
    +
  • +
  • Left Trigger:

    +
    Out -> In       - Axis 5
    +
    +
    +
  • +
  • Right Trigger:

    +
    Out -> In       - Axis 4
    +
    +
    +
  • +
  • Buttons:

    +
    Cross Button    - Button 0
    +Circle Button   - Button 1
    +Square Button   - Button 2
    +Triangle Button - Button 3
    +Left Bumper     - Button 4
    +Right Bumper    - Button 5
    +L. Trigger(Full)- Button 6
    +R. Trigger(Full)- Button 7
    +Share Button    - Button 8
    +Options Button  - Button 9
    +L. Stick In     - Button 10
    +R. Stick In     - Button 11
    +PS Button       - Button 12
    +Touch Pad Click - Button 13
    +
    +
    +
  • +
  • Hat/D-pad:

    +
    Down -> Up      - Y Axis
    +Left -> Right   - X Axis
    +
    +
    +
  • +
+
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/key.html b/venv/Lib/site-packages/pygame/docs/generated/ref/key.html new file mode 100644 index 0000000..c662fb2 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/key.html @@ -0,0 +1,628 @@ + + + + + + + + + pygame.key — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.key
+
+
pygame module to work with the keyboard
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+true if the display is receiving keyboard input from the system
+get the state of all keyboard buttons
+determine which modifier keys are being held
+temporarily set which modifier keys are pressed
+control how held keys are repeated
+see how held keys are repeated
+get the name of a key identifier
+get the key identifier from a key name
+start handling Unicode text input events
+stop handling Unicode text input events
+controls the position of the candidate list
+

This module contains functions for dealing with the keyboard.

+

The pygame.eventpygame module for interacting with events and queues queue gets pygame.KEYDOWN and pygame.KEYUP +events when the keyboard buttons are pressed and released. Both events have +key and mod attributes.

+
+
    +
  • key: an integer ID representing every key +on the keyboard

  • +
  • mod: a bitmask of all the modifier keys +that were in a pressed state when the event occurred

  • +
+
+

The pygame.KEYDOWN event has the additional attributes unicode and +scancode.

+
+
    +
  • unicode: a single character string that is the fully translated +character entered, this takes into account the shift and composition keys

  • +
  • scancode: the platform-specific key code, which could be different from +keyboard to keyboard, but is useful for key selection of weird keys like +the multimedia keys

  • +
+
+
+

New in pygame 2.0.0: The pygame.TEXTINPUT event is preferred to the unicode attribute +of pygame.KEYDOWN. The attribute text contains the input.

+
+

The following is a list of all the constants (from pygame.localspygame constants) used to +represent keyboard keys.

+

Portability note: The integers for key constants differ between pygame 1 and 2. +Always use key constants (K_a) rather than integers directly (97) so +that your key handling code works well on both pygame 1 and pygame 2.

+
pygame
+Constant      ASCII   Description
+---------------------------------
+K_BACKSPACE   \b      backspace
+K_TAB         \t      tab
+K_CLEAR               clear
+K_RETURN      \r      return
+K_PAUSE               pause
+K_ESCAPE      ^[      escape
+K_SPACE               space
+K_EXCLAIM     !       exclaim
+K_QUOTEDBL    "       quotedbl
+K_HASH        #       hash
+K_DOLLAR      $       dollar
+K_AMPERSAND   &       ampersand
+K_QUOTE               quote
+K_LEFTPAREN   (       left parenthesis
+K_RIGHTPAREN  )       right parenthesis
+K_ASTERISK    *       asterisk
+K_PLUS        +       plus sign
+K_COMMA       ,       comma
+K_MINUS       -       minus sign
+K_PERIOD      .       period
+K_SLASH       /       forward slash
+K_0           0       0
+K_1           1       1
+K_2           2       2
+K_3           3       3
+K_4           4       4
+K_5           5       5
+K_6           6       6
+K_7           7       7
+K_8           8       8
+K_9           9       9
+K_COLON       :       colon
+K_SEMICOLON   ;       semicolon
+K_LESS        <       less-than sign
+K_EQUALS      =       equals sign
+K_GREATER     >       greater-than sign
+K_QUESTION    ?       question mark
+K_AT          @       at
+K_LEFTBRACKET [       left bracket
+K_BACKSLASH   \       backslash
+K_RIGHTBRACKET ]      right bracket
+K_CARET       ^       caret
+K_UNDERSCORE  _       underscore
+K_BACKQUOTE   `       grave
+K_a           a       a
+K_b           b       b
+K_c           c       c
+K_d           d       d
+K_e           e       e
+K_f           f       f
+K_g           g       g
+K_h           h       h
+K_i           i       i
+K_j           j       j
+K_k           k       k
+K_l           l       l
+K_m           m       m
+K_n           n       n
+K_o           o       o
+K_p           p       p
+K_q           q       q
+K_r           r       r
+K_s           s       s
+K_t           t       t
+K_u           u       u
+K_v           v       v
+K_w           w       w
+K_x           x       x
+K_y           y       y
+K_z           z       z
+K_DELETE              delete
+K_KP0                 keypad 0
+K_KP1                 keypad 1
+K_KP2                 keypad 2
+K_KP3                 keypad 3
+K_KP4                 keypad 4
+K_KP5                 keypad 5
+K_KP6                 keypad 6
+K_KP7                 keypad 7
+K_KP8                 keypad 8
+K_KP9                 keypad 9
+K_KP_PERIOD   .       keypad period
+K_KP_DIVIDE   /       keypad divide
+K_KP_MULTIPLY *       keypad multiply
+K_KP_MINUS    -       keypad minus
+K_KP_PLUS     +       keypad plus
+K_KP_ENTER    \r      keypad enter
+K_KP_EQUALS   =       keypad equals
+K_UP                  up arrow
+K_DOWN                down arrow
+K_RIGHT               right arrow
+K_LEFT                left arrow
+K_INSERT              insert
+K_HOME                home
+K_END                 end
+K_PAGEUP              page up
+K_PAGEDOWN            page down
+K_F1                  F1
+K_F2                  F2
+K_F3                  F3
+K_F4                  F4
+K_F5                  F5
+K_F6                  F6
+K_F7                  F7
+K_F8                  F8
+K_F9                  F9
+K_F10                 F10
+K_F11                 F11
+K_F12                 F12
+K_F13                 F13
+K_F14                 F14
+K_F15                 F15
+K_NUMLOCK             numlock
+K_CAPSLOCK            capslock
+K_SCROLLOCK           scrollock
+K_RSHIFT              right shift
+K_LSHIFT              left shift
+K_RCTRL               right control
+K_LCTRL               left control
+K_RALT                right alt
+K_LALT                left alt
+K_RMETA               right meta
+K_LMETA               left meta
+K_LSUPER              left Windows key
+K_RSUPER              right Windows key
+K_MODE                mode shift
+K_HELP                help
+K_PRINT               print screen
+K_SYSREQ              sysrq
+K_BREAK               break
+K_MENU                menu
+K_POWER               power
+K_EURO                Euro
+K_AC_BACK             Android back button
+
+
+

The keyboard also has a list of modifier states (from pygame.localspygame constants) that +can be assembled by bitwise-ORing them together.

+
pygame
+Constant      Description
+-------------------------
+KMOD_NONE     no modifier keys pressed
+KMOD_LSHIFT   left shift
+KMOD_RSHIFT   right shift
+KMOD_SHIFT    left shift or right shift or both
+KMOD_LCTRL    left control
+KMOD_RCTRL    right control
+KMOD_CTRL     left control or right control or both
+KMOD_LALT     left alt
+KMOD_RALT     right alt
+KMOD_ALT      left alt or right alt or both
+KMOD_LMETA    left meta
+KMOD_RMETA    right meta
+KMOD_META     left meta or right meta or both
+KMOD_CAPS     caps lock
+KMOD_NUM      num lock
+KMOD_MODE     AltGr
+
+
+

The modifier information is contained in the mod attribute of the +pygame.KEYDOWN and pygame.KEYUP events. The mod attribute is a +bitmask of all the modifier keys that were in a pressed state when the event +occurred. The modifier information can be decoded using a bitwise AND (except +for KMOD_NONE, which should be compared using equals ==). For example:

+
for event in pygame.event.get():
+    if event.type == pygame.KEYDOWN or event.type == pygame.KEYUP:
+        if event.mod == pygame.KMOD_NONE:
+            print('No modifier keys were in a pressed state when this '
+                  'event occurred.')
+        else:
+            if event.mod & pygame.KMOD_LSHIFT:
+                print('Left shift was in a pressed state when this event '
+                      'occurred.')
+            if event.mod & pygame.KMOD_RSHIFT:
+                print('Right shift was in a pressed state when this event '
+                      'occurred.')
+            if event.mod & pygame.KMOD_SHIFT:
+                print('Left shift or right shift or both were in a '
+                      'pressed state when this event occurred.')
+
+
+
+
+pygame.key.get_focused()
+
+
true if the display is receiving keyboard input from the system
+
get_focused() -> bool
+
+

Returns True when the display window has keyboard focus from the +system. If the display needs to ensure it does not lose keyboard focus, it +can use pygame.event.set_grab()control the sharing of input devices with other applications to grab all input.

+
+ +
+
+pygame.key.get_pressed()
+
+
get the state of all keyboard buttons
+
get_pressed() -> bools
+
+

Returns a sequence of boolean values representing the state of every key on +the keyboard. Use the key constant values to index the array. A True +value means that the button is pressed.

+
+

Note

+

Getting the list of pushed buttons with this function is not the proper +way to handle text entry from the user. There is no way to know the order +of keys pressed, and rapidly pushed keys can be completely unnoticed +between two calls to pygame.key.get_pressed(). There is also no way to +translate these pushed keys into a fully translated character value. See +the pygame.KEYDOWN events on the pygame.eventpygame module for interacting with events and queues queue for this +functionality.

+
+
+ +
+
+pygame.key.get_mods()
+
+
determine which modifier keys are being held
+
get_mods() -> int
+
+

Returns a single integer representing a bitmask of all the modifier keys +being held. Using bitwise operators you can test if specific +modifier keys are pressed.

+
+ +
+
+pygame.key.set_mods()
+
+
temporarily set which modifier keys are pressed
+
set_mods(int) -> None
+
+

Create a bitmask of the modifier key constants +you want to impose on your program.

+
+ +
+
+pygame.key.set_repeat()
+
+
control how held keys are repeated
+
set_repeat() -> None
+
set_repeat(delay) -> None
+
set_repeat(delay, interval) -> None
+
+

When the keyboard repeat is enabled, keys that are held down will generate +multiple pygame.KEYDOWN events. The delay parameter is the number of +milliseconds before the first repeated pygame.KEYDOWN event will be sent. +After that, another pygame.KEYDOWN event will be sent every interval +milliseconds. If a delay value is provided and an interval value is +not provided or is 0, then the interval will be set to the same value as +delay.

+

To disable key repeat call this function with no arguments or with delay +set to 0.

+

When pygame is initialized the key repeat is disabled.

+
+
Raises
+

ValueError -- if delay or interval is < 0

+
+
+
+

Changed in pygame 2.0.0: A ValueError is now raised (instead of a +pygame.error) if delay or interval is < 0.

+
+
+ +
+
+pygame.key.get_repeat()
+
+
see how held keys are repeated
+
get_repeat() -> (delay, interval)
+
+

Get the delay and interval keyboard repeat values. Refer to +pygame.key.set_repeat()control how held keys are repeated for a description of these values.

+
+

New in pygame 1.8.

+
+
+ +
+
+pygame.key.name()
+
+
get the name of a key identifier
+
name(key) -> string
+
+

Get the descriptive name of the button from a keyboard button id constant.

+
+ +
+
+pygame.key.key_code()
+
+
get the key identifier from a key name
+
key_code(name=string) -> int
+
+

Get the key identifier code from the descriptive name of the key. This +returns an integer matching one of the K_* keycodes. For example:

+
>>> pygame.key.key_code("return") == pygame.K_RETURN
+True
+>>> pygame.key.key_code("0") == pygame.K_0
+True
+>>> pygame.key.key_code("space") == pygame.K_SPACE
+True
+
+
+
+
Raises
+
    +
  • ValueError -- if the key name is not known.

  • +
  • NotImplementedError -- if used with SDL 1.

  • +
+
+
+
+

New in pygame 2.0.0.

+
+
+ +
+
+pygame.key.start_text_input()
+
+
start handling Unicode text input events
+
start_text_input() -> None
+
+

Start receiving pygame.TEXTEDITING and pygame.TEXTINPUT +events. If applicable, show the on-screen keyboard or IME editor.

+

For many languages, key presses will automatically generate a +corresponding pygame.TEXTINPUT event. Special keys like +escape or function keys, and certain key combinations will not +generate pygame.TEXTINPUT events.

+

In other languages, entering a single symbol may require multiple +key presses, or a language-specific user interface. In this case, +pygame.TEXTINPUT events are preferable to pygame.KEYDOWN +events for text input.

+

A pygame.TEXTEDITING event is received when an IME composition +is started or changed. It contains the composition text, length, +and editing start position within the composition (attributes +text, length, and start, respectively). +When the composition is committed (or non-IME input is received), +a pygame.TEXTINPUT event is generated.

+

Text input events handling is on by default.

+
+

New in pygame 2.0.0.

+
+
+ +
+
+pygame.key.stop_text_input()
+
+
stop handling Unicode text input events
+
stop_text_input() -> None
+
+

Stop receiving pygame.TEXTEDITING and pygame.TEXTINPUT +events. If an on-screen keyboard or IME editor was shown with +pygame.key.start_text_input(), hide it again.

+

Text input events handling is on by default.

+

To avoid triggering the IME editor or the on-screen keyboard +when the user is holding down a key during gameplay, text input +should be disabled once text entry is finished, or when the user +clicks outside of a text box.

+
+

New in pygame 2.0.0.

+
+
+ +
+
+pygame.key.set_text_input_rect()
+
+
controls the position of the candidate list
+
set_text_input_rect(Rect) -> None
+
+

This sets the rectangle used for typing with an IME. +It controls where the candidate list will open, if supported.

+
+

New in pygame 2.0.0.

+
+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/locals.html b/venv/Lib/site-packages/pygame/docs/generated/ref/locals.html new file mode 100644 index 0000000..baa5f8e --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/locals.html @@ -0,0 +1,161 @@ + + + + + + + + + pygame.locals — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.locals
+
+
pygame constants
+
+

This module contains various constants used by pygame. Its contents are +automatically placed in the pygame module namespace. However, an application +can use pygame.locals to include only the pygame constants with a from +pygame.locals import *.

+

Detailed descriptions of the various constants can be found throughout the +pygame documentation. Here are the locations of some of them.

+
+
+
+
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/mask.html b/venv/Lib/site-packages/pygame/docs/generated/ref/mask.html new file mode 100644 index 0000000..88e1219 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/mask.html @@ -0,0 +1,1123 @@ + + + + + + + + + pygame.mask — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.mask
+
+
pygame module for image masks.
+
+ +++++ + + + + + + + + + + + + + + +
+Creates a Mask from the given surface
+Creates a mask by thresholding Surfaces
+pygame object for representing 2D bitmasks
+

Useful for fast pixel perfect collision detection. A mask uses 1 bit per-pixel +to store which parts collide.

+
+

New in pygame 1.8.

+
+
+

Changed in pygame 2.0.2: Mask functions now support keyword arguments.

+
+
+

Changed in pygame 2.0.2: Mask functions that take positions or offsets now +support pygame.math.Vector2a 2-Dimensional Vector arguments.

+
+
+
+pygame.mask.from_surface()
+
+
Creates a Mask from the given surface
+
from_surface(surface) -> Mask
+
from_surface(surface, threshold=127) -> Mask
+
+

Creates a Mask object from the given surface by setting all the +opaque pixels and not setting the transparent pixels.

+

If the surface uses a color-key, then it is used to decide which bits in +the resulting mask are set. All the pixels that are not equal to the +color-key are set and the pixels equal to the color-key are not set.

+

If a color-key is not used, then the alpha value of each pixel is used to +decide which bits in the resulting mask are set. All the pixels that have an +alpha value greater than the threshold parameter are set and the +pixels with an alpha value less than or equal to the threshold are +not set.

+
+
Parameters
+
    +
  • surface (Surface) -- the surface to create the mask from

  • +
  • threshold (int) -- (optional) the alpha threshold (default is 127) to +compare with each surface pixel's alpha value, if the surface is +color-keyed this parameter is ignored

  • +
+
+
Returns
+

a newly created Mask object from the given surface

+
+
Return type
+

Mask

+
+
+
+

Note

+

This function is used to create the masks for +pygame.sprite.collide_mask()Collision detection between two sprites, using masks..

+
+
+ +
+
+pygame.mask.from_threshold()
+
+
Creates a mask by thresholding Surfaces
+
from_threshold(surface, color) -> Mask
+
from_threshold(surface, color, threshold=(0, 0, 0, 255), othersurface=None, palette_colors=1) -> Mask
+
+

This is a more featureful method of getting a Mask from a surface.

+

If the optional othersurface is not used, all the pixels within the +threshold of the color parameter are set in the resulting mask.

+

If the optional othersurface is used, every pixel in the first surface +that is within the threshold of the corresponding pixel in +othersurface is set in the resulting mask.

+
+
Parameters
+
    +
  • surface (Surface) -- the surface to create the mask from

  • +
  • color (Color or int or tuple(int, int, int, [int]) or list[int, int, int, [int]]) -- color used to check if the surface's pixels are within the +given threshold range, this parameter is ignored if the optional +othersurface parameter is supplied

  • +
  • threshold (Color or int or tuple(int, int, int, [int]) or list[int, int, int, [int]]) -- (optional) the threshold range used to check the difference +between two colors (default is (0, 0, 0, 255))

  • +
  • othersurface (Surface) -- (optional) used to check whether the pixels of +the first surface are within the given threshold range of the pixels +from this surface (default is None)

  • +
  • palette_colors (int) -- (optional) indicates whether to use the palette +colors or not, a nonzero value causes the palette colors to be used and a +0 causes them not to be used (default is 1)

  • +
+
+
Returns
+

a newly created Mask object from the given surface

+
+
Return type
+

Mask

+
+
+
+ +
+
+pygame.mask.Mask
+
+
pygame object for representing 2D bitmasks
+
Mask(size=(width, height)) -> Mask
+
Mask(size=(width, height), fill=False) -> Mask
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Returns a new copy of the mask
+Returns the size of the mask
+Returns a Rect based on the size of the mask
+Gets the bit at the given position
+Sets the bit at the given position
+Returns the point of intersection
+Returns the number of overlapping set bits
+Returns a mask of the overlapping set bits
+Sets all bits to 1
+Sets all bits to 0
+Flips all the bits
+Resizes a mask
+Draws a mask onto another
+Erases a mask from another
+Returns the number of set bits
+Returns the centroid of the set bits
+Returns the orientation of the set bits
+Returns a list of points outlining an object
+Returns the convolution of this mask with another mask
+Returns a mask containing a connected component
+Returns a list of masks of connected components
+Returns a list of bounding rects of connected components
+Returns a surface with the mask drawn on it
+

A Mask object is used to represent a 2D bitmask. Each bit in +the mask represents a pixel. 1 is used to indicate a set bit and 0 is used +to indicate an unset bit. Set bits in a mask can be used to detect collisions +with other masks and their set bits.

+

A filled mask has all of its bits set to 1, conversely an +unfilled/cleared/empty mask has all of its bits set to 0. Masks can be +created unfilled (default) or filled by using the fill parameter. Masks +can also be cleared or filled using the pygame.mask.Mask.clear()Sets all bits to 0 and +pygame.mask.Mask.fill()Sets all bits to 1 methods respectively.

+

A mask's coordinates start in the top left corner at (0, 0) just like +pygame.Surfacepygame object for representing images. Individual bits can be accessed using the +pygame.mask.Mask.get_at()Gets the bit at the given position and pygame.mask.Mask.set_at()Sets the bit at the given position +methods.

+

The methods overlap(), overlap_area(), overlap_mask(), +draw(), erase(), and convolve() use an offset parameter +to indicate the offset of another mask's top left corner from the calling +mask's top left corner. The calling mask's top left corner is considered to +be the origin (0, 0). Offsets are a sequence of two values +(x_offset, y_offset). Positive and negative offset values are supported.

+
           0 to x (x_offset)
+           :    :
+   0 ..... +----:---------+
+   to      |    :         |
+   y .......... +-----------+
+(y_offset) |    | othermask |
+           |    +-----------+
+           | calling_mask |
+           +--------------+
+
+
+
+
Parameters
+
    +
  • size -- the dimensions of the mask (width and height)

  • +
  • fill (bool) -- (optional) create an unfilled mask (default: False) or +filled mask (True)

  • +
+
+
Returns
+

a newly created Mask object

+
+
Return type
+

Mask

+
+
+
+

Changed in pygame 2.0.0: Shallow copy support added. The Mask class supports the special +method __copy__() and shallow copying via copy.copy(mask).

+
+
+

Changed in pygame 2.0.0: Subclassing support added. The Mask class +can be used as a base class.

+
+
+

Changed in pygame 1.9.5: Added support for keyword arguments.

+
+
+

Changed in pygame 1.9.5: Added the optional keyword parameter fill.

+
+
+

Changed in pygame 1.9.5: Added support for masks with a width and/or a +height of 0.

+
+
+
+copy()
+
+
Returns a new copy of the mask
+
copy() -> Mask
+
+
+
Returns
+

a new copy of this mask, the new mask will have the same width, +height, and set/unset bits as the original

+
+
Return type
+

Mask

+
+
+
+

Note

+

If a mask subclass needs to copy any instance specific attributes +then it should override the __copy__() method. The overridden +__copy__() method needs to call super().__copy__() and then +copy the required data as in the following example code.

+
class SubMask(pygame.mask.Mask):
+    def __copy__(self):
+        new_mask = super().__copy__()
+        # Do any SubMask attribute copying here.
+        return new_mask
+
+
+
+
+

New in pygame 2.0.0.

+
+
+ +
+
+get_size()
+
+
Returns the size of the mask
+
get_size() -> (width, height)
+
+
+
Returns
+

the size of the mask, (width, height)

+
+
Return type
+

tuple(int, int)

+
+
+
+ +
+
+get_rect()
+
+
Returns a Rect based on the size of the mask
+
get_rect(**kwargs) -> Rect
+
+

Returns a new pygame.Rect()pygame object for storing rectangular coordinates object based on the size of this mask. +The rect's default position will be (0, 0) and its default width and +height will be the same as this mask's. The rect's attributes can be +altered via pygame.Rect()pygame object for storing rectangular coordinates attribute keyword arguments/values passed +into this method. As an example, a_mask.get_rect(center=(10, 5)) would +create a pygame.Rect()pygame object for storing rectangular coordinates based on the mask's size centered at the +given position.

+
+
Parameters
+

kwargs (dict) -- pygame.Rect()pygame object for storing rectangular coordinates attribute keyword arguments/values +that will be applied to the rect

+
+
Returns
+

a new pygame.Rect()pygame object for storing rectangular coordinates object based on the size of this mask +with any pygame.Rect()pygame object for storing rectangular coordinates attribute keyword arguments/values applied +to it

+
+
Return type
+

Rect

+
+
+
+

New in pygame 2.0.0.

+
+
+ +
+
+get_at()
+
+
Gets the bit at the given position
+
get_at(pos) -> int
+
+
+
Parameters
+

pos -- the position of the bit to get (x, y)

+
+
Returns
+

1 if the bit is set, 0 if the bit is not set

+
+
Return type
+

int

+
+
Raises
+

IndexError -- if the position is outside of the mask's bounds

+
+
+
+ +
+
+set_at()
+
+
Sets the bit at the given position
+
set_at(pos) -> None
+
set_at(pos, value=1) -> None
+
+
+
Parameters
+
    +
  • pos -- the position of the bit to set (x, y)

  • +
  • value (int) -- any nonzero int will set the bit to 1, 0 will set the +bit to 0 (default is 1)

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
Raises
+

IndexError -- if the position is outside of the mask's bounds

+
+
+
+ +
+
+overlap()
+
+
Returns the point of intersection
+
overlap(other, offset) -> (x, y)
+
overlap(other, offset) -> None
+
+

Returns the first point of intersection encountered between this mask and +other. A point of intersection is 2 overlapping set bits.

+

The current algorithm searches the overlapping area in +sizeof(unsigned long int) * CHAR_BIT bit wide column blocks (the value +of sizeof(unsigned long int) * CHAR_BIT is platform dependent, for +clarity it will be referred to as W). Starting at the top left corner +it checks bits 0 to W - 1 of the first row ((0, 0) to +(W - 1, 0)) then continues to the next row ((0, 1) to +(W - 1, 1)). Once this entire column block is checked, it continues to +the next one (W to 2 * W - 1). This is repeated until it finds a +point of intersection or the entire overlapping area is checked.

+
+
Parameters
+
    +
  • other (Mask) -- the other mask to overlap with this mask

  • +
  • offset -- the offset of other from this mask, for more +details refer to the Mask offset notes

  • +
+
+
Returns
+

point of intersection or None if no intersection

+
+
Return type
+

tuple(int, int) or NoneType

+
+
+
+ +
+
+overlap_area()
+
+
Returns the number of overlapping set bits
+
overlap_area(other, offset) -> numbits
+
+

Returns the number of overlapping set bits between between this mask and +other.

+

This can be useful for collision detection. An approximate collision +normal can be found by calculating the gradient of the overlapping area +through the finite difference.

+
dx = mask.overlap_area(other, (x + 1, y)) - mask.overlap_area(other, (x - 1, y))
+dy = mask.overlap_area(other, (x, y + 1)) - mask.overlap_area(other, (x, y - 1))
+
+
+
+
Parameters
+
    +
  • other (Mask) -- the other mask to overlap with this mask

  • +
  • offset -- the offset of other from this mask, for more +details refer to the Mask offset notes

  • +
+
+
Returns
+

the number of overlapping set bits

+
+
Return type
+

int

+
+
+
+ +
+
+overlap_mask()
+
+
Returns a mask of the overlapping set bits
+
overlap_mask(other, offset) -> Mask
+
+

Returns a Mask, the same size as this mask, containing the +overlapping set bits between this mask and other.

+
+
Parameters
+
    +
  • other (Mask) -- the other mask to overlap with this mask

  • +
  • offset -- the offset of other from this mask, for more +details refer to the Mask offset notes

  • +
+
+
Returns
+

a newly created Mask with the overlapping bits set

+
+
Return type
+

Mask

+
+
+
+ +
+
+fill()
+
+
Sets all bits to 1
+
fill() -> None
+
+

Sets all bits in the mask to 1.

+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+ +
+
+clear()
+
+
Sets all bits to 0
+
clear() -> None
+
+

Sets all bits in the mask to 0.

+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+ +
+
+invert()
+
+
Flips all the bits
+
invert() -> None
+
+

Flips all of the bits in the mask. All the set bits are cleared to 0 and +all the unset bits are set to 1.

+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+ +
+
+scale()
+
+
Resizes a mask
+
scale((width, height)) -> Mask
+
+

Creates a new Mask of the requested size with its bits scaled +from this mask.

+
+
Parameters
+

size -- the width and height (size) of the mask to create

+
+
Returns
+

a new Mask object with its bits scaled from this mask

+
+
Return type
+

Mask

+
+
Raises
+

ValueError -- if width < 0 or height < 0

+
+
+
+ +
+
+draw()
+
+
Draws a mask onto another
+
draw(other, offset) -> None
+
+

Performs a bitwise OR, drawing othermask onto this mask.

+
+
Parameters
+
    +
  • other (Mask) -- the mask to draw onto this mask

  • +
  • offset -- the offset of other from this mask, for more +details refer to the Mask offset notes

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+ +
+
+erase()
+
+
Erases a mask from another
+
erase(other, offset) -> None
+
+

Erases (clears) all bits set in other from this mask.

+
+
Parameters
+
    +
  • other (Mask) -- the mask to erase from this mask

  • +
  • offset -- the offset of other from this mask, for more +details refer to the Mask offset notes

  • +
+
+
Returns
+

None

+
+
Return type
+

NoneType

+
+
+
+ +
+
+count()
+
+
Returns the number of set bits
+
count() -> bits
+
+
+
Returns
+

the number of set bits in the mask

+
+
Return type
+

int

+
+
+
+ +
+
+centroid()
+
+
Returns the centroid of the set bits
+
centroid() -> (x, y)
+
+

Finds the centroid (the center mass of the set bits) for this mask.

+
+
Returns
+

a coordinate tuple indicating the centroid of the mask, it will +return (0, 0) if the mask has no bits set

+
+
Return type
+

tuple(int, int)

+
+
+
+ +
+
+angle()
+
+
Returns the orientation of the set bits
+
angle() -> theta
+
+

Finds the approximate orientation (from -90 to 90 degrees) of the set bits +in the mask. This works best if performed on a mask with only one +connected component.

+
+
Returns
+

the orientation of the set bits in the mask, it will return +0.0 if the mask has no bits set

+
+
Return type
+

float

+
+
+
+

Note

+

See connected_component() for details on how a connected +component is calculated.

+
+
+ +
+
+outline()
+
+
Returns a list of points outlining an object
+
outline() -> [(x, y), ...]
+
outline(every=1) -> [(x, y), ...]
+
+

Returns a list of points of the outline of the first connected component +encountered in the mask. To find a connected component, the mask is +searched per row (left to right) starting in the top left corner.

+

The every optional parameter skips set bits in the outline. For +example, setting it to 10 would return a list of every 10th set bit in the +outline.

+
+
Parameters
+

every (int) -- (optional) indicates the number of bits to skip over in +the outline (default is 1)

+
+
Returns
+

a list of points outlining the first connected component +encountered, an empty list is returned if the mask has no bits set

+
+
Return type
+

list[tuple(int, int)]

+
+
+
+

Note

+

See connected_component() for details on how a connected +component is calculated.

+
+
+ +
+
+convolve()
+
+
Returns the convolution of this mask with another mask
+
convolve(other) -> Mask
+
convolve(other, output=None, offset=(0, 0)) -> Mask
+
+

Convolve this mask with the given other Mask.

+
+
Parameters
+
    +
  • other (Mask) -- mask to convolve this mask with

  • +
  • output (Mask or NoneType) -- (optional) mask for output (default is None)

  • +
  • offset -- the offset of other from this mask, (default is +(0, 0))

  • +
+
+
Returns
+

a Mask with the (i - offset[0], j - offset[1]) bit +set, if shifting other (such that its bottom right corner is at +(i, j)) causes it to overlap with this mask

+

If an output Mask is specified, the output is drawn onto it and +it is returned. Otherwise a mask of size (MAX(0, width + other mask's +width - 1), MAX(0, height + other mask's height - 1)) is created and +returned.

+

+
+
Return type
+

Mask

+
+
+
+ +
+
+connected_component()
+
+
Returns a mask containing a connected component
+
connected_component() -> Mask
+
connected_component(pos) -> Mask
+
+

A connected component is a group (1 or more) of connected set bits +(orthogonally and diagonally). The SAUF algorithm, which checks 8 point +connectivity, is used to find a connected component in the mask.

+

By default this method will return a Mask containing the largest +connected component in the mask. Optionally, a bit coordinate can be +specified and the connected component containing it will be returned. If +the bit at the given location is not set, the returned Mask will +be empty (no bits set).

+
+
Parameters
+

pos -- (optional) selects the connected component that contains the +bit at this position

+
+
Returns
+

a Mask object (same size as this mask) with the largest +connected component from this mask, if this mask has no bits set then +an empty mask will be returned

+

If the pos parameter is provided then the mask returned will have +the connected component that contains this position. An empty mask will +be returned if the pos parameter selects an unset bit.

+

+
+
Return type
+

Mask

+
+
Raises
+

IndexError -- if the optional pos parameter is outside of the +mask's bounds

+
+
+
+ +
+
+connected_components()
+
+
Returns a list of masks of connected components
+
connected_components() -> [Mask, ...]
+
connected_components(minimum=0) -> [Mask, ...]
+
+

Provides a list containing a Mask object for each connected +component.

+
+
Parameters
+

minimum (int) -- (optional) indicates the minimum number of bits (to +filter out noise) per connected component (default is 0, which equates +to no minimum and is equivalent to setting it to 1, as a connected +component must have at least 1 bit set)

+
+
Returns
+

a list containing a Mask object for each connected +component, an empty list is returned if the mask has no bits set

+
+
Return type
+

list[Mask]

+
+
+
+

Note

+

See connected_component() for details on how a connected +component is calculated.

+
+
+ +
+
+get_bounding_rects()
+
+
Returns a list of bounding rects of connected components
+
get_bounding_rects() -> [Rect, ...]
+
+

Provides a list containing a bounding rect for each connected component.

+
+
Returns
+

a list containing a bounding rect for each connected component, +an empty list is returned if the mask has no bits set

+
+
Return type
+

list[Rect]

+
+
+
+

Note

+

See connected_component() for details on how a connected +component is calculated.

+
+
+ +
+
+to_surface()
+
+
Returns a surface with the mask drawn on it
+
to_surface() -> Surface
+
to_surface(surface=None, setsurface=None, unsetsurface=None, setcolor=(255, 255, 255, 255), unsetcolor=(0, 0, 0, 255), dest=(0, 0)) -> Surface
+
+

Draws this mask on the given surface. Set bits (bits set to 1) and unset +bits (bits set to 0) can be drawn onto a surface.

+
+
Parameters
+
    +
  • surface (Surface or None) -- (optional) Surface to draw mask onto, if no surface is +provided one will be created (default is None, which will cause a +surface with the parameters +Surface(size=mask.get_size(), flags=SRCALPHA, depth=32) to be +created, drawn on, and returned)

  • +
  • setsurface (Surface or None) -- (optional) use this surface's color values to draw +set bits (default is None), if this surface is smaller than the +mask any bits outside its bounds will use the setcolor value

  • +
  • unsetsurface (Surface or None) -- (optional) use this surface's color values to draw +unset bits (default is None), if this surface is smaller than the +mask any bits outside its bounds will use the unsetcolor value

  • +
  • setcolor (Color or str or int or tuple(int, int, int, [int]) or +list(int, int, int, [int]) or None) -- (optional) color to draw set bits (default is +(255, 255, 255, 255), white), use None to skip drawing the set +bits, the setsurface parameter (if set) will takes precedence over +this parameter

  • +
  • unsetcolor (Color or str or int or tuple(int, int, int, [int]) or +list(int, int, int, [int]) or None) -- (optional) color to draw unset bits (default is +(0, 0, 0, 255), black), use None to skip drawing the unset +bits, the unsetsurface parameter (if set) will takes precedence +over this parameter

  • +
  • dest (Rect or tuple(int, int) or list(int, int) or Vector2(int, int)) -- (optional) surface destination of where to position the +topleft corner of the mask being drawn (default is (0, 0)), if a +Rect is used as the dest parameter, its x and y attributes +will be used as the destination, NOTE1: rects with a negative width +or height value will not be normalized before using their x and +y values, NOTE2: this destination value is only used to +position the mask on the surface, it does not offset the setsurface +and unsetsurface from the mask, they are always aligned with the +mask (i.e. position (0, 0) on the mask always corresponds to +position (0, 0) on the setsurface and unsetsurface)

  • +
+
+
Returns
+

the surface parameter (or a newly created surface if no +surface parameter was provided) with this mask drawn on it

+
+
Return type
+

Surface

+
+
Raises
+

ValueError -- if the setsurface parameter or unsetsurface +parameter does not have the same format (bytesize/bitsize/alpha) as +the surface parameter

+
+
+
+

Note

+

To skip drawing the set bits, both setsurface and setcolor must +be None. The setsurface parameter defaults to None, but +setcolor defaults to a color value and therefore must be set to +None.

+
+
+

Note

+

To skip drawing the unset bits, both unsetsurface and +unsetcolor must be None. The unsetsurface parameter +defaults to None, but unsetcolor defaults to a color value and +therefore must be set to None.

+
+
+

New in pygame 2.0.0.

+
+
+ +
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/math.html b/venv/Lib/site-packages/pygame/docs/generated/ref/math.html new file mode 100644 index 0000000..fe824c5 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/math.html @@ -0,0 +1,1509 @@ + + + + + + + + + pygame.math — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.math
+
+
pygame module for vector classes
+
+ +++++ + + + + + + + + + + +
+a 2-Dimensional Vector
+a 3-Dimensional Vector
+

The pygame math module currently provides Vector classes in two and three +dimensions, Vector2 and Vector3 respectively.

+

They support the following numerical operations: vec+vec, vec-vec, +vec*number, number*vec, vec/number, vec//number, vec+=vec, +vec-=vec, vec*=number, vec/=number, vec//=number.

+

All these operations will be performed elementwise. +In addition vec*vec will perform a scalar-product (a.k.a. dot-product). +If you want to multiply every element from vector v with every element from +vector w you can use the elementwise method: v.elementwise() * w

+

The coordinates of a vector can be retrieved or set using attributes or +subscripts

+
v = pygame.Vector3()
+
+v.x = 5
+v[1] = 2 * v.x
+print(v[1]) # 10
+
+v.x == v[0]
+v.y == v[1]
+v.z == v[2]
+
+
+

Multiple coordinates can be set using slices or swizzling

+
v = pygame.Vector2()
+v.xy = 1, 2
+v[:] = 1, 2
+
+
+
+

New in pygame 1.9.2pre.

+
+
+

Changed in pygame 1.9.4: Removed experimental notice.

+
+
+

Changed in pygame 1.9.4: Allow scalar construction like GLSL Vector2(2) == Vector2(2.0, 2.0)

+
+
+

Changed in pygame 1.9.4: pygame.mathpygame module for vector classes required import. More convenient pygame.Vector2 and pygame.Vector3.

+
+
+
+pygame.math.Vector2
+
+
a 2-Dimensional Vector
+
Vector2() -> Vector2
+
Vector2(int) -> Vector2
+
Vector2(float) -> Vector2
+
Vector2(Vector2) -> Vector2
+
Vector2(x, y) -> Vector2
+
Vector2((x, y)) -> Vector2
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+calculates the dot- or scalar-product with the other vector
+calculates the cross- or vector-product
+returns the Euclidean magnitude of the vector.
+returns the squared magnitude of the vector.
+returns the Euclidean length of the vector.
+returns the squared Euclidean length of the vector.
+returns a vector with the same direction but length 1.
+normalizes the vector in place so that its length is 1.
+tests if the vector is normalized i.e. has length == 1.
+scales the vector to a given length.
+returns a vector reflected of a given normal.
+reflect the vector of a given normal in place.
+calculates the Euclidean distance to a given vector.
+calculates the squared Euclidean distance to a given vector.
+returns a linear interpolation to the given vector.
+returns a spherical interpolation to the given vector.
+The next operation will be performed elementwise.
+rotates a vector by a given angle in degrees.
+rotates a vector by a given angle in radians.
+rotates the vector by a given angle in degrees in place.
+rotates the vector by a given angle in radians in place.
+rotates the vector by a given angle in radians in place.
+calculates the angle to a given vector in degrees.
+returns a tuple with radial distance and azimuthal angle.
+Sets x and y from a polar coordinates tuple.
+projects a vector onto another.
+Returns a copy of itself.
+Sets the coordinates of the vector.
+

Some general information about the Vector2 class.

+
+
+dot()
+
+
calculates the dot- or scalar-product with the other vector
+
dot(Vector2) -> float
+
+
+ +
+
+cross()
+
+
calculates the cross- or vector-product
+
cross(Vector2) -> Vector2
+
+

calculates the third component of the cross-product.

+
+ +
+
+magnitude()
+
+
returns the Euclidean magnitude of the vector.
+
magnitude() -> float
+
+

calculates the magnitude of the vector which follows from the +theorem: vec.magnitude() == math.sqrt(vec.x**2 + vec.y**2)

+
+ +
+
+magnitude_squared()
+
+
returns the squared magnitude of the vector.
+
magnitude_squared() -> float
+
+

calculates the magnitude of the vector which follows from the +theorem: vec.magnitude_squared() == vec.x**2 + vec.y**2. This +is faster than vec.magnitude() because it avoids the square root.

+
+ +
+
+length()
+
+
returns the Euclidean length of the vector.
+
length() -> float
+
+

calculates the Euclidean length of the vector which follows from the +Pythagorean theorem: vec.length() == math.sqrt(vec.x**2 + vec.y**2)

+
+ +
+
+length_squared()
+
+
returns the squared Euclidean length of the vector.
+
length_squared() -> float
+
+

calculates the Euclidean length of the vector which follows from the +Pythagorean theorem: vec.length_squared() == vec.x**2 + vec.y**2. +This is faster than vec.length() because it avoids the square root.

+
+ +
+
+normalize()
+
+
returns a vector with the same direction but length 1.
+
normalize() -> Vector2
+
+

Returns a new vector that has length equal to 1 and the same +direction as self.

+
+ +
+
+normalize_ip()
+
+
normalizes the vector in place so that its length is 1.
+
normalize_ip() -> None
+
+

Normalizes the vector so that it has length equal to 1. +The direction of the vector is not changed.

+
+ +
+
+is_normalized()
+
+
tests if the vector is normalized i.e. has length == 1.
+
is_normalized() -> Bool
+
+

Returns True if the vector has length equal to 1. Otherwise +it returns False.

+
+ +
+
+scale_to_length()
+
+
scales the vector to a given length.
+
scale_to_length(float) -> None
+
+

Scales the vector so that it has the given length. The direction of the +vector is not changed. You can also scale to length 0. If the vector +is the zero vector (i.e. has length 0 thus no direction) a +ValueError is raised.

+
+ +
+
+reflect()
+
+
returns a vector reflected of a given normal.
+
reflect(Vector2) -> Vector2
+
+

Returns a new vector that points in the direction as if self would bounce +of a surface characterized by the given surface normal. The length of the +new vector is the same as self's.

+
+ +
+
+reflect_ip()
+
+
reflect the vector of a given normal in place.
+
reflect_ip(Vector2) -> None
+
+

Changes the direction of self as if it would have been reflected of a +surface with the given surface normal.

+
+ +
+
+distance_to()
+
+
calculates the Euclidean distance to a given vector.
+
distance_to(Vector2) -> float
+
+
+ +
+
+distance_squared_to()
+
+
calculates the squared Euclidean distance to a given vector.
+
distance_squared_to(Vector2) -> float
+
+
+ +
+
+lerp()
+
+
returns a linear interpolation to the given vector.
+
lerp(Vector2, float) -> Vector2
+
+

Returns a Vector which is a linear interpolation between self and the +given Vector. The second parameter determines how far between self and +other the result is going to be. It must be a value between 0 and 1 +where 0 means self and 1 means other will be returned.

+
+ +
+
+slerp()
+
+
returns a spherical interpolation to the given vector.
+
slerp(Vector2, float) -> Vector2
+
+

Calculates the spherical interpolation from self to the given Vector. The +second argument - often called t - must be in the range [-1, 1]. It +parametrizes where - in between the two vectors - the result should be. +If a negative value is given the interpolation will not take the +complement of the shortest path.

+
+ +
+
+elementwise()
+
+
The next operation will be performed elementwise.
+
elementwise() -> VectorElementwiseProxy
+
+

Applies the following operation to each element of the vector.

+
+ +
+
+rotate()
+
+
rotates a vector by a given angle in degrees.
+
rotate(angle) -> Vector2
+
+

Returns a vector which has the same length as self but is rotated +counterclockwise by the given angle in degrees. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+ +
+
+rotate_rad()
+
+
rotates a vector by a given angle in radians.
+
rotate_rad(angle) -> Vector2
+
+

Returns a vector which has the same length as self but is rotated +counterclockwise by the given angle in radians. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+

New in pygame 2.0.0.

+
+
+ +
+
+rotate_ip()
+
+
rotates the vector by a given angle in degrees in place.
+
rotate_ip(angle) -> None
+
+

Rotates the vector counterclockwise by the given angle in degrees. The +length of the vector is not changed. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+ +
+
+rotate_ip_rad()
+
+
rotates the vector by a given angle in radians in place.
+
rotate_ip_rad(angle) -> None
+
+

DEPRECATED: Use rotate_rad_ip() instead.

+
+

New in pygame 2.0.0.

+
+
+

Deprecated since pygame 2.1.1.

+
+
+ +
+
+rotate_rad_ip()
+
+
rotates the vector by a given angle in radians in place.
+
rotate_rad_ip(angle) -> None
+
+

Rotates the vector counterclockwise by the given angle in radians. The +length of the vector is not changed. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+

New in pygame 2.1.1.

+
+
+ +
+
+angle_to()
+
+
calculates the angle to a given vector in degrees.
+
angle_to(Vector2) -> float
+
+

Returns the angle between self and the given vector.

+
+ +
+
+as_polar()
+
+
returns a tuple with radial distance and azimuthal angle.
+
as_polar() -> (r, phi)
+
+

Returns a tuple (r, phi) where r is the radial distance, and phi +is the azimuthal angle.

+
+ +
+
+from_polar()
+
+
Sets x and y from a polar coordinates tuple.
+
from_polar((r, phi)) -> None
+
+

Sets x and y from a tuple (r, phi) where r is the radial distance, and +phi is the azimuthal angle.

+
+ +
+
+project()
+
+
projects a vector onto another.
+
project(Vector2) -> Vector2
+
+

Returns the projected vector. This is useful for collision detection in finding the components in a certain direction (e.g. in direction of the wall). +For a more detailed explanation see Wikipedia.

+
+

New in pygame 2.0.2.

+
+
+ +
+
+copy()
+
+
Returns a copy of itself.
+
copy() -> Vector2
+
+

Returns a new Vector2 having the same dimensions.

+
+

New in pygame 2.1.1.

+
+
+ +
+
+update()
+
+
Sets the coordinates of the vector.
+
update() -> None
+
update(int) -> None
+
update(float) -> None
+
update(Vector2) -> None
+
update(x, y) -> None
+
update((x, y)) -> None
+
+

Sets coordinates x and y in place.

+
+

New in pygame 1.9.5.

+
+
+ +
+ +
+
+pygame.math.Vector3
+
+
a 3-Dimensional Vector
+
Vector3() -> Vector3
+
Vector3(int) -> Vector3
+
Vector3(float) -> Vector3
+
Vector3(Vector3) -> Vector3
+
Vector3(x, y, z) -> Vector3
+
Vector3((x, y, z)) -> Vector3
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+calculates the dot- or scalar-product with the other vector
+calculates the cross- or vector-product
+returns the Euclidean magnitude of the vector.
+returns the squared Euclidean magnitude of the vector.
+returns the Euclidean length of the vector.
+returns the squared Euclidean length of the vector.
+returns a vector with the same direction but length 1.
+normalizes the vector in place so that its length is 1.
+tests if the vector is normalized i.e. has length == 1.
+scales the vector to a given length.
+returns a vector reflected of a given normal.
+reflect the vector of a given normal in place.
+calculates the Euclidean distance to a given vector.
+calculates the squared Euclidean distance to a given vector.
+returns a linear interpolation to the given vector.
+returns a spherical interpolation to the given vector.
+The next operation will be performed elementwise.
+rotates a vector by a given angle in degrees.
+rotates a vector by a given angle in radians.
+rotates the vector by a given angle in degrees in place.
+rotates the vector by a given angle in radians in place.
+rotates the vector by a given angle in radians in place.
+rotates a vector around the x-axis by the angle in degrees.
+rotates a vector around the x-axis by the angle in radians.
+rotates the vector around the x-axis by the angle in degrees in place.
+rotates the vector around the x-axis by the angle in radians in place.
+rotates the vector around the x-axis by the angle in radians in place.
+rotates a vector around the y-axis by the angle in degrees.
+rotates a vector around the y-axis by the angle in radians.
+rotates the vector around the y-axis by the angle in degrees in place.
+rotates the vector around the y-axis by the angle in radians in place.
+rotates the vector around the y-axis by the angle in radians in place.
+rotates a vector around the z-axis by the angle in degrees.
+rotates a vector around the z-axis by the angle in radians.
+rotates the vector around the z-axis by the angle in degrees in place.
+rotates the vector around the z-axis by the angle in radians in place.
+rotates the vector around the z-axis by the angle in radians in place.
+calculates the angle to a given vector in degrees.
+returns a tuple with radial distance, inclination and azimuthal angle.
+Sets x, y and z from a spherical coordinates 3-tuple.
+projects a vector onto another.
+Returns a copy of itself.
+Sets the coordinates of the vector.
+

Some general information about the Vector3 class.

+
+
+dot()
+
+
calculates the dot- or scalar-product with the other vector
+
dot(Vector3) -> float
+
+
+ +
+
+cross()
+
+
calculates the cross- or vector-product
+
cross(Vector3) -> Vector3
+
+

calculates the cross-product.

+
+ +
+
+magnitude()
+
+
returns the Euclidean magnitude of the vector.
+
magnitude() -> float
+
+

calculates the magnitude of the vector which follows from the +theorem: vec.magnitude() == math.sqrt(vec.x**2 + vec.y**2 + vec.z**2)

+
+ +
+
+magnitude_squared()
+
+
returns the squared Euclidean magnitude of the vector.
+
magnitude_squared() -> float
+
+

calculates the magnitude of the vector which follows from the +theorem: +vec.magnitude_squared() == vec.x**2 + vec.y**2 + vec.z**2. +This is faster than vec.magnitude() because it avoids the +square root.

+
+ +
+
+length()
+
+
returns the Euclidean length of the vector.
+
length() -> float
+
+

calculates the Euclidean length of the vector which follows from the +Pythagorean theorem: +vec.length() == math.sqrt(vec.x**2 + vec.y**2 + vec.z**2)

+
+ +
+
+length_squared()
+
+
returns the squared Euclidean length of the vector.
+
length_squared() -> float
+
+

calculates the Euclidean length of the vector which follows from the +Pythagorean theorem: +vec.length_squared() == vec.x**2 + vec.y**2 + vec.z**2. +This is faster than vec.length() because it avoids the square root.

+
+ +
+
+normalize()
+
+
returns a vector with the same direction but length 1.
+
normalize() -> Vector3
+
+

Returns a new vector that has length equal to 1 and the same +direction as self.

+
+ +
+
+normalize_ip()
+
+
normalizes the vector in place so that its length is 1.
+
normalize_ip() -> None
+
+

Normalizes the vector so that it has length equal to 1. The +direction of the vector is not changed.

+
+ +
+
+is_normalized()
+
+
tests if the vector is normalized i.e. has length == 1.
+
is_normalized() -> Bool
+
+

Returns True if the vector has length equal to 1. Otherwise it +returns False.

+
+ +
+
+scale_to_length()
+
+
scales the vector to a given length.
+
scale_to_length(float) -> None
+
+

Scales the vector so that it has the given length. The direction of the +vector is not changed. You can also scale to length 0. If the vector +is the zero vector (i.e. has length 0 thus no direction) a +ValueError is raised.

+
+ +
+
+reflect()
+
+
returns a vector reflected of a given normal.
+
reflect(Vector3) -> Vector3
+
+

Returns a new vector that points in the direction as if self would bounce +of a surface characterized by the given surface normal. The length of the +new vector is the same as self's.

+
+ +
+
+reflect_ip()
+
+
reflect the vector of a given normal in place.
+
reflect_ip(Vector3) -> None
+
+

Changes the direction of self as if it would have been reflected of a +surface with the given surface normal.

+
+ +
+
+distance_to()
+
+
calculates the Euclidean distance to a given vector.
+
distance_to(Vector3) -> float
+
+
+ +
+
+distance_squared_to()
+
+
calculates the squared Euclidean distance to a given vector.
+
distance_squared_to(Vector3) -> float
+
+
+ +
+
+lerp()
+
+
returns a linear interpolation to the given vector.
+
lerp(Vector3, float) -> Vector3
+
+

Returns a Vector which is a linear interpolation between self and the +given Vector. The second parameter determines how far between self an +other the result is going to be. It must be a value between 0 and +1, where 0 means self and 1 means other will be returned.

+
+ +
+
+slerp()
+
+
returns a spherical interpolation to the given vector.
+
slerp(Vector3, float) -> Vector3
+
+

Calculates the spherical interpolation from self to the given Vector. The +second argument - often called t - must be in the range [-1, 1]. It +parametrizes where - in between the two vectors - the result should be. +If a negative value is given the interpolation will not take the +complement of the shortest path.

+
+ +
+
+elementwise()
+
+
The next operation will be performed elementwise.
+
elementwise() -> VectorElementwiseProxy
+
+

Applies the following operation to each element of the vector.

+
+ +
+
+rotate()
+
+
rotates a vector by a given angle in degrees.
+
rotate(angle, Vector3) -> Vector3
+
+

Returns a vector which has the same length as self but is rotated +counterclockwise by the given angle in degrees around the given axis. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+ +
+
+rotate_rad()
+
+
rotates a vector by a given angle in radians.
+
rotate_rad(angle, Vector3) -> Vector3
+
+

Returns a vector which has the same length as self but is rotated +counterclockwise by the given angle in radians around the given axis. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+

New in pygame 2.0.0.

+
+
+ +
+
+rotate_ip()
+
+
rotates the vector by a given angle in degrees in place.
+
rotate_ip(angle, Vector3) -> None
+
+

Rotates the vector counterclockwise around the given axis by the given +angle in degrees. The length of the vector is not changed. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+ +
+
+rotate_ip_rad()
+
+
rotates the vector by a given angle in radians in place.
+
rotate_ip_rad(angle, Vector3) -> None
+
+

DEPRECATED: Use rotate_rad_ip() instead.

+
+

New in pygame 2.0.0.

+
+
+

Deprecated since pygame 2.1.1.

+
+
+ +
+
+rotate_rad_ip()
+
+
rotates the vector by a given angle in radians in place.
+
rotate_rad_ip(angle, Vector3) -> None
+
+

Rotates the vector counterclockwise around the given axis by the given +angle in radians. The length of the vector is not changed. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+

New in pygame 2.1.1.

+
+
+ +
+
+rotate_x()
+
+
rotates a vector around the x-axis by the angle in degrees.
+
rotate_x(angle) -> Vector3
+
+

Returns a vector which has the same length as self but is rotated +counterclockwise around the x-axis by the given angle in degrees. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+ +
+
+rotate_x_rad()
+
+
rotates a vector around the x-axis by the angle in radians.
+
rotate_x_rad(angle) -> Vector3
+
+

Returns a vector which has the same length as self but is rotated +counterclockwise around the x-axis by the given angle in radians. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+

New in pygame 2.0.0.

+
+
+ +
+
+rotate_x_ip()
+
+
rotates the vector around the x-axis by the angle in degrees in place.
+
rotate_x_ip(angle) -> None
+
+

Rotates the vector counterclockwise around the x-axis by the given angle +in degrees. The length of the vector is not changed. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+ +
+
+rotate_x_ip_rad()
+
+
rotates the vector around the x-axis by the angle in radians in place.
+
rotate_x_ip_rad(angle) -> None
+
+

DEPRECATED: Use rotate_x_rad_ip() instead.

+
+

New in pygame 2.0.0.

+
+
+

Deprecated since pygame 2.1.1.

+
+
+ +
+
+rotate_x_rad_ip()
+
+
rotates the vector around the x-axis by the angle in radians in place.
+
rotate_x_rad_ip(angle) -> None
+
+

Rotates the vector counterclockwise around the x-axis by the given angle +in radians. The length of the vector is not changed. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+

New in pygame 2.1.1.

+
+
+ +
+
+rotate_y()
+
+
rotates a vector around the y-axis by the angle in degrees.
+
rotate_y(angle) -> Vector3
+
+

Returns a vector which has the same length as self but is rotated +counterclockwise around the y-axis by the given angle in degrees. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+ +
+
+rotate_y_rad()
+
+
rotates a vector around the y-axis by the angle in radians.
+
rotate_y_rad(angle) -> Vector3
+
+

Returns a vector which has the same length as self but is rotated +counterclockwise around the y-axis by the given angle in radians. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+

New in pygame 2.0.0.

+
+
+ +
+
+rotate_y_ip()
+
+
rotates the vector around the y-axis by the angle in degrees in place.
+
rotate_y_ip(angle) -> None
+
+

Rotates the vector counterclockwise around the y-axis by the given angle +in degrees. The length of the vector is not changed. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+ +
+
+rotate_y_ip_rad()
+
+
rotates the vector around the y-axis by the angle in radians in place.
+
rotate_y_ip_rad(angle) -> None
+
+

DEPRECATED: Use rotate_y_rad_ip() instead.

+
+

New in pygame 2.0.0.

+
+
+

Deprecated since pygame 2.1.1.

+
+
+ +
+
+rotate_y_rad_ip()
+
+
rotates the vector around the y-axis by the angle in radians in place.
+
rotate_y_rad_ip(angle) -> None
+
+

Rotates the vector counterclockwise around the y-axis by the given angle +in radians. The length of the vector is not changed. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+

New in pygame 2.1.1.

+
+
+ +
+
+rotate_z()
+
+
rotates a vector around the z-axis by the angle in degrees.
+
rotate_z(angle) -> Vector3
+
+

Returns a vector which has the same length as self but is rotated +counterclockwise around the z-axis by the given angle in degrees. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+ +
+
+rotate_z_rad()
+
+
rotates a vector around the z-axis by the angle in radians.
+
rotate_z_rad(angle) -> Vector3
+
+

Returns a vector which has the same length as self but is rotated +counterclockwise around the z-axis by the given angle in radians. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+

New in pygame 2.0.0.

+
+
+ +
+
+rotate_z_ip()
+
+
rotates the vector around the z-axis by the angle in degrees in place.
+
rotate_z_ip(angle) -> None
+
+

Rotates the vector counterclockwise around the z-axis by the given angle +in degrees. The length of the vector is not changed. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+ +
+
+rotate_z_ip_rad()
+
+
rotates the vector around the z-axis by the angle in radians in place.
+
rotate_z_ip_rad(angle) -> None
+
+

DEPRECATED: Use rotate_z_rad_ip() instead.

+
+

Deprecated since pygame 2.1.1.

+
+
+ +
+
+rotate_z_rad_ip()
+
+
rotates the vector around the z-axis by the angle in radians in place.
+
rotate_z_rad_ip(angle) -> None
+
+

Rotates the vector counterclockwise around the z-axis by the given angle +in radians. The length of the vector is not changed. +(Note that due to pygame's inverted y coordinate system, the rotation +will look clockwise if displayed).

+
+

New in pygame 2.1.1.

+
+
+ +
+
+angle_to()
+
+
calculates the angle to a given vector in degrees.
+
angle_to(Vector3) -> float
+
+

Returns the angle between self and the given vector.

+
+ +
+
+as_spherical()
+
+
returns a tuple with radial distance, inclination and azimuthal angle.
+
as_spherical() -> (r, theta, phi)
+
+

Returns a tuple (r, theta, phi) where r is the radial distance, theta is +the inclination angle and phi is the azimuthal angle.

+
+ +
+
+from_spherical()
+
+
Sets x, y and z from a spherical coordinates 3-tuple.
+
from_spherical((r, theta, phi)) -> None
+
+

Sets x, y and z from a tuple (r, theta, phi) where r is the radial +distance, theta is the inclination angle and phi is the azimuthal angle.

+
+ +
+
+project()
+
+
projects a vector onto another.
+
project(Vector3) -> Vector3
+
+

Returns the projected vector. This is useful for collision detection in finding the components in a certain direction (e.g. in direction of the wall). +For a more detailed explanation see Wikipedia.

+
+

New in pygame 2.0.2.

+
+
+ +
+
+copy()
+
+
Returns a copy of itself.
+
copy() -> Vector3
+
+

Returns a new Vector3 having the same dimensions.

+
+

New in pygame 2.1.1.

+
+
+ +
+
+update()
+
+
Sets the coordinates of the vector.
+
update() -> None
+
update(int) -> None
+
update(float) -> None
+
update(Vector3) -> None
+
update(x, y, z) -> None
+
update((x, y, z)) -> None
+
+

Sets coordinates x, y, and z in place.

+
+

New in pygame 1.9.5.

+
+
+ +
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/midi.html b/venv/Lib/site-packages/pygame/docs/generated/ref/midi.html new file mode 100644 index 0000000..de8cabe --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/midi.html @@ -0,0 +1,845 @@ + + + + + + + + + pygame.midi — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.midi
+
+
pygame module for interacting with midi input and output.
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+initialize the midi module
+uninitialize the midi module
+returns True if the midi module is currently initialized
+Input is used to get midi input from midi devices.
+Output is used to send midi to an output device
+gets the number of devices.
+gets default input device number
+gets default output device number
+returns information about a midi device
+converts midi events to pygame events
+returns the current time in ms of the PortMidi timer
+Converts a frequency into a MIDI note. Rounds to the closest midi note.
+Converts a midi note to a frequency.
+Returns the Ansi Note name for a midi number.
+exception that pygame.midi functions and classes can raise
+
+

New in pygame 1.9.0.

+
+

The midi module can send output to midi devices and get input from midi +devices. It can also list midi devices on the system.

+

The midi module supports real and virtual midi devices.

+

It uses the portmidi library. Is portable to which ever platforms portmidi +supports (currently Windows, Mac OS X, and Linux).

+

This uses pyportmidi for now, but may use its own bindings at some point in the +future. The pyportmidi bindings are included with pygame.

+
+

+
+
+

New in pygame 2.0.0.

+
+

These are pygame events (pygame.eventpygame module for interacting with events and queues) reserved for midi use. The +MIDIIN event is used by pygame.midi.midis2events()converts midi events to pygame events when converting +midi events to pygame events.

+
MIDIIN
+MIDIOUT
+
+
+
+

+
+
+
+pygame.midi.init()
+
+
initialize the midi module
+
init() -> None
+
+

Initializes the pygame.midipygame module for interacting with midi input and output. module. Must be called before using the +pygame.midipygame module for interacting with midi input and output. module.

+

It is safe to call this more than once.

+
+ +
+
+pygame.midi.quit()
+
+
uninitialize the midi module
+
quit() -> None
+
+

Uninitializes the pygame.midipygame module for interacting with midi input and output. module. If pygame.midi.init()initialize the midi module was +called to initialize the pygame.midipygame module for interacting with midi input and output. module, then this function will +be called automatically when your program exits.

+

It is safe to call this function more than once.

+
+ +
+
+pygame.midi.get_init()
+
+
returns True if the midi module is currently initialized
+
get_init() -> bool
+
+

Gets the initialization state of the pygame.midipygame module for interacting with midi input and output. module.

+
+
Returns
+

True if the pygame.midipygame module for interacting with midi input and output. module is currently initialized.

+
+
Return type
+

bool

+
+
+
+

New in pygame 1.9.5.

+
+
+ +
+
+pygame.midi.Input
+
+
Input is used to get midi input from midi devices.
+
Input(device_id) -> None
+
Input(device_id, buffer_size) -> None
+
+ +++++ + + + + + + + + + + + + + + +
+closes a midi stream, flushing any pending buffers.
+returns True if there's data, or False if not.
+reads num_events midi events from the buffer.
+
+
Parameters
+
    +
  • device_id (int) -- midi device id

  • +
  • buffer_size (int) -- (optional) the number of input events to be buffered

  • +
+
+
+
+
+close()
+
+
closes a midi stream, flushing any pending buffers.
+
close() -> None
+
+

PortMidi attempts to close open streams when the application exits.

+
+

Note

+

This is particularly difficult under Windows.

+
+
+ +
+
+poll()
+
+
returns True if there's data, or False if not.
+
poll() -> bool
+
+

Used to indicate if any data exists.

+
+
Returns
+

True if there is data, False otherwise

+
+
Return type
+

bool

+
+
Raises
+

MidiException -- on error

+
+
+
+ +
+
+read()
+
+
reads num_events midi events from the buffer.
+
read(num_events) -> midi_event_list
+
+

Reads from the input buffer and gives back midi events.

+
+
Parameters
+

num_events (int) -- number of input events to read

+
+
Returns
+

the format for midi_event_list is +[[[status, data1, data2, data3], timestamp], ...]

+
+
Return type
+

list

+
+
+
+ +
+ +
+
+pygame.midi.Output
+
+
Output is used to send midi to an output device
+
Output(device_id) -> None
+
Output(device_id, latency=0) -> None
+
Output(device_id, buffer_size=256) -> None
+
Output(device_id, latency, buffer_size) -> None
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+terminates outgoing messages immediately
+closes a midi stream, flushing any pending buffers.
+turns a midi note off (note must be on)
+turns a midi note on (note must be off)
+select an instrument, with a value between 0 and 127
+modify the pitch of a channel.
+writes a list of midi data to the Output
+writes up to 3 bytes of midi data to the Output
+writes a timestamped system-exclusive midi message.
+

The buffer_size specifies the number of output events to be buffered +waiting for output. In some cases (see below) PortMidi does not buffer +output at all and merely passes data to a lower-level API, in which case +buffersize is ignored.

+

latency is the delay in milliseconds applied to timestamps to determine +when the output should actually occur. If latency is <<0, 0 is assumed.

+

If latency is zero, timestamps are ignored and all output is delivered +immediately. If latency is greater than zero, output is delayed until the +message timestamp plus the latency. In some cases, PortMidi can obtain +better timing than your application by passing timestamps along to the +device driver or hardware. Latency may also help you to synchronize midi +data to audio data by matching midi latency to the audio buffer latency.

+
+

Note

+

Time is measured relative to the time source indicated by time_proc. +Timestamps are absolute, not relative delays or offsets.

+
+
+
+abort()
+
+
terminates outgoing messages immediately
+
abort() -> None
+
+

The caller should immediately close the output port; this call may result +in transmission of a partial midi message. There is no abort for Midi +input because the user can simply ignore messages in the buffer and close +an input device at any time.

+
+ +
+
+close()
+
+
closes a midi stream, flushing any pending buffers.
+
close() -> None
+
+

PortMidi attempts to close open streams when the application exits.

+
+

Note

+

This is particularly difficult under Windows.

+
+
+ +
+
+note_off()
+
+
turns a midi note off (note must be on)
+
note_off(note, velocity=None, channel=0) -> None
+
+

Turn a note off in the output stream. The note must already be on for +this to work correctly.

+
+ +
+
+note_on()
+
+
turns a midi note on (note must be off)
+
note_on(note, velocity=None, channel=0) -> None
+
+

Turn a note on in the output stream. The note must already be off for +this to work correctly.

+
+ +
+
+set_instrument()
+
+
select an instrument, with a value between 0 and 127
+
set_instrument(instrument_id, channel=0) -> None
+
+

Select an instrument.

+
+ +
+
+pitch_bend()
+
+
modify the pitch of a channel.
+
set_instrument(value=0, channel=0) -> None
+
+

Adjust the pitch of a channel. The value is a signed integer +from -8192 to +8191. For example, 0 means "no change", +4096 is +typically a semitone higher, and -8192 is 1 whole tone lower (though +the musical range corresponding to the pitch bend range can also be +changed in some synthesizers).

+

If no value is given, the pitch bend is returned to "no change".

+
+

New in pygame 1.9.4.

+
+
+ +
+
+write()
+
+
writes a list of midi data to the Output
+
write(data) -> None
+
+

Writes series of MIDI information in the form of a list.

+
+
Parameters
+

data (list) -- data to write, the expected format is +[[[status, data1=0, data2=0, ...], timestamp], ...] +with the data# fields being optional

+
+
Raises
+

IndexError -- if more than 1024 elements in the data list

+
+
+

Example:

+
# Program change at time 20000 and 500ms later send note 65 with
+# velocity 100.
+write([[[0xc0, 0, 0], 20000], [[0x90, 60, 100], 20500]])
+
+
+
+

Note

+
    +
  • Timestamps will be ignored if latency = 0

  • +
  • To get a note to play immediately, send MIDI info with timestamp +read from function Time

  • +
  • Optional data fields: write([[[0xc0, 0, 0], 20000]]) is +equivalent to write([[[0xc0], 20000]])

  • +
+
+
+ +
+
+write_short()
+
+
writes up to 3 bytes of midi data to the Output
+
write_short(status) -> None
+
write_short(status, data1=0, data2=0) -> None
+
+

Output MIDI information of 3 bytes or less. The data fields are +optional and assumed to be 0 if omitted.

+

Examples of status byte values:

+
0xc0  # program change
+0x90  # note on
+# etc.
+
+
+

Example:

+
# note 65 on with velocity 100
+write_short(0x90, 65, 100)
+
+
+
+ +
+
+write_sys_ex()
+
+
writes a timestamped system-exclusive midi message.
+
write_sys_ex(when, msg) -> None
+
+

Writes a timestamped system-exclusive midi message.

+
+
Parameters
+
    +
  • msg (list[int] or str) -- midi message

  • +
  • when -- timestamp in milliseconds

  • +
+
+
+

Example:

+
midi_output.write_sys_ex(0, '\xF0\x7D\x10\x11\x12\x13\xF7')
+
+# is equivalent to
+
+midi_output.write_sys_ex(pygame.midi.time(),
+                         [0xF0, 0x7D, 0x10, 0x11, 0x12, 0x13, 0xF7])
+
+
+
+ +
+ +
+
+pygame.midi.get_count()
+
+
gets the number of devices.
+
get_count() -> num_devices
+
+

Device ids range from 0 to get_count() - 1

+
+ +
+
+pygame.midi.get_default_input_id()
+
+
gets default input device number
+
get_default_input_id() -> default_id
+
+

The following describes the usage details for this function and the +get_default_output_id() function.

+

Return the default device ID or -1 if there are no devices. The result +can be passed to the Input/Output class.

+

On a PC the user can specify a default device by setting an environment +variable. To use device #1, for example:

+
set PM_RECOMMENDED_INPUT_DEVICE=1
+or
+set PM_RECOMMENDED_OUTPUT_DEVICE=1
+
+
+

The user should first determine the available device ID by using the +supplied application "testin" or "testout".

+

In general, the registry is a better place for this kind of info. With +USB devices that can come and go, using integers is not very reliable +for device identification. Under Windows, if PM_RECOMMENDED_INPUT_DEVICE +(or PM_RECOMMENDED_OUTPUT_DEVICE) is NOT found in the environment, +then the default device is obtained by looking for a string in the registry +under:

+
HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Input_Device
+or
+HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Output_Device
+
+
+

The number of the first device with a substring that matches the +string exactly is returned. For example, if the string in the registry is +"USB" and device 1 is named "In USB MidiSport 1x1", then that will be +the default input because it contains the string "USB".

+

In addition to the name, get_device_info() returns "interf", which is +the interface name. The "interface" is the underlying software system or +API used by PortMidi to access devices. Supported interfaces:

+
MMSystem   # the only Win32 interface currently supported
+ALSA       # the only Linux interface currently supported
+CoreMIDI   # the only Mac OS X interface currently supported
+# DirectX - not implemented
+# OSS     - not implemented
+
+
+

To specify both the interface and the device name in the registry, separate +the two with a comma and a space. The string before the comma must be a +substring of the "interf" string and the string after the space must be a +substring of the "name" name string in order to match the device. e.g.:

+
MMSystem, In USB MidiSport 1x1
+
+
+
+

Note

+

In the current release, the default is simply the first device (the +input or output device with the lowest PmDeviceID).

+
+
+ +
+
+pygame.midi.get_default_output_id()
+
+
gets default output device number
+
get_default_output_id() -> default_id
+
+

See get_default_input_id() for usage details.

+
+ +
+
+pygame.midi.get_device_info()
+
+
returns information about a midi device
+
get_device_info(an_id) -> (interf, name, input, output, opened)
+
get_device_info(an_id) -> None
+
+

Gets the device info for a given id.

+
+
Parameters
+

an_id (int) -- id of the midi device being queried

+
+
Returns
+

if the id is out of range None is returned, otherwise +a tuple of (interf, name, input, output, opened) is returned.

+
+
    +
  • interf: string describing the device interface (e.g. 'ALSA')

  • +
  • name: string name of the device (e.g. 'Midi Through Port-0')

  • +
  • input: 1 if the device is an input device, otherwise 0

  • +
  • output: 1 if the device is an output device, otherwise 0

  • +
  • opened: 1 if the device is opened, otherwise 0

  • +
+
+

+
+
Return type
+

tuple or None

+
+
+
+ +
+
+pygame.midi.midis2events()
+
+
converts midi events to pygame events
+
midis2events(midi_events, device_id) -> [Event, ...]
+
+

Takes a sequence of midi events and returns list of pygame events.

+

The midi_events data is expected to be a sequence of +((status, data1, data2, data3), timestamp) midi events (all values +required).

+
+
Returns
+

a list of pygame events of event type MIDIIN

+
+
Return type
+

list

+
+
+
+ +
+
+pygame.midi.time()
+
+
returns the current time in ms of the PortMidi timer
+
time() -> time
+
+

The time is reset to 0 when the pygame.midipygame module for interacting with midi input and output. module is initialized.

+
+ +
+
+pygame.midi.frequency_to_midi()
+
+
Converts a frequency into a MIDI note. Rounds to the closest midi note.
+
frequency_to_midi(midi_note) -> midi_note
+
+

example:

+
frequency_to_midi(27.5) == 21
+
+
+
+

New in pygame 1.9.5.

+
+
+ +
+
+pygame.midi.midi_to_frequency()
+
+
Converts a midi note to a frequency.
+
midi_to_frequency(midi_note) -> frequency
+
+

example:

+
midi_to_frequency(21) == 27.5
+
+
+
+

New in pygame 1.9.5.

+
+
+ +
+
+pygame.midi.midi_to_ansi_note()
+
+
Returns the Ansi Note name for a midi number.
+
midi_to_ansi_note(midi_note) -> ansi_note
+
+

example:

+
midi_to_ansi_note(21) == 'A0'
+
+
+
+

New in pygame 1.9.5.

+
+
+ +
+
+exception pygame.midi.MidiException
+
+
exception that pygame.midi functions and classes can raise
+
MidiException(errno) -> None
+
+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/mixer.html b/venv/Lib/site-packages/pygame/docs/generated/ref/mixer.html new file mode 100644 index 0000000..76c2ca9 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/mixer.html @@ -0,0 +1,995 @@ + + + + + + + + + pygame.mixer — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.mixer
+
+
pygame module for loading and playing sounds
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+initialize the mixer module
+preset the mixer init arguments
+uninitialize the mixer
+test if the mixer is initialized
+stop playback of all sound channels
+temporarily stop playback of all sound channels
+resume paused playback of sound channels
+fade out the volume on all sounds before stopping
+set the total number of playback channels
+get the total number of playback channels
+reserve channels from being automatically used
+find an unused channel
+test if any sound is being mixed
+get the mixer's SDL version
+Create a new Sound object from a file or buffer object
+Create a Channel object for controlling playback
+

This module contains classes for loading Sound objects and controlling +playback. The mixer module is optional and depends on SDL_mixer. Your program +should test that pygame.mixerpygame module for loading and playing sounds is available and initialized before using +it.

+

The mixer module has a limited number of channels for playback of sounds. +Usually programs tell pygame to start playing audio and it selects an available +channel automatically. The default is 8 simultaneous channels, but complex +programs can get more precise control over the number of channels and their +use.

+

All sound playback is mixed in background threads. When you begin to play a +Sound object, it will return immediately while the sound continues to play. A +single Sound object can also be actively played back multiple times.

+

The mixer also has a special streaming channel. This is for music playback and +is accessed through the pygame.mixer.musicpygame module for controlling streamed audio module. Consider using this +module for playing long running music. Unlike mixer module, the music module +streams the music from the files without loading music at once into memory.

+

The mixer module must be initialized like other pygame modules, but it has some +extra conditions. The pygame.mixer.init() function takes several optional +arguments to control the playback rate and sample size. Pygame will default to +reasonable values, but pygame cannot perform Sound resampling, so the mixer +should be initialized to match the values of your audio resources.

+

NOTE: For less laggy sound use a smaller buffer size. The default +is set to reduce the chance of scratchy sounds on some computers. You can +change the default buffer by calling pygame.mixer.pre_init()preset the mixer init arguments before +pygame.mixer.init()initialize the mixer module or pygame.init()initialize all imported pygame modules is called. For example: +pygame.mixer.pre_init(44100,-16,2, 1024)

+
+
+pygame.mixer.init()
+
+
initialize the mixer module
+
init(frequency=44100, size=-16, channels=2, buffer=512, devicename=None, allowedchanges=AUDIO_ALLOW_FREQUENCY_CHANGE | AUDIO_ALLOW_CHANNELS_CHANGE) -> None
+
+

Initialize the mixer module for Sound loading and playback. The default +arguments can be overridden to provide specific audio mixing. Keyword +arguments are accepted. For backwards compatibility, argument values of +0 are replaced with the startup defaults, except for allowedchanges, +where -1 is used. (startup defaults may be changed by a pre_init() call).

+

The size argument represents how many bits are used for each audio sample. +If the value is negative then signed sample values will be used. Positive +values mean unsigned audio samples will be used. An invalid value raises an +exception.

+

The channels argument is used to specify whether to use mono or stereo. 1 +for mono and 2 for stereo.

+

The buffer argument controls the number of internal samples used in the +sound mixer. The default value should work for most cases. It can be lowered +to reduce latency, but sound dropout may occur. It can be raised to larger +values to ensure playback never skips, but it will impose latency on sound +playback. The buffer size must be a power of two (if not it is rounded up to +the next nearest power of 2).

+

Some platforms require the pygame.mixerpygame module for loading and playing sounds module to be initialized +after the display modules have initialized. The top level pygame.init() +takes care of this automatically, but cannot pass any arguments to the mixer +init. To solve this, mixer has a function pygame.mixer.pre_init() to set +the proper defaults before the toplevel init is used.

+

When using allowedchanges=0 it will convert the samples at runtime to match +what the hardware supports. For example a sound card may not +support 16bit sound samples, so instead it will use 8bit samples internally. +If AUDIO_ALLOW_FORMAT_CHANGE is supplied, then the requested format will +change to the closest that SDL2 supports.

+

Apart from 0, allowedchanged accepts the following constants ORed together:

+
+
    +
  • AUDIO_ALLOW_FREQUENCY_CHANGE

  • +
  • AUDIO_ALLOW_FORMAT_CHANGE

  • +
  • AUDIO_ALLOW_CHANNELS_CHANGE

  • +
  • AUDIO_ALLOW_ANY_CHANGE

  • +
+
+

It is safe to call this more than once, but after the mixer is initialized +you cannot change the playback arguments without first calling +pygame.mixer.quit().

+
+

Changed in pygame 1.8: The default buffersize changed from 1024 to 3072.

+
+
+

Changed in pygame 1.9.1: The default buffersize changed from 3072 to 4096.

+
+
+

Changed in pygame 2.0.0: The default buffersize changed from 4096 to 512.

+
+
+

Changed in pygame 2.0.0: The default frequency changed from 22050 to 44100.

+
+
+

Changed in pygame 2.0.0: size can be 32 (32-bit floats).

+
+
+

Changed in pygame 2.0.0: channels can also be 4 or 6.

+
+
+

New in pygame 2.0.0: allowedchanges, devicename arguments added

+
+
+ +
+
+pygame.mixer.pre_init()
+
+
preset the mixer init arguments
+
pre_init(frequency=44100, size=-16, channels=2, buffer=512, devicename=None, allowedchanges=AUDIO_ALLOW_FREQUENCY_CHANGE | AUDIO_ALLOW_CHANNELS_CHANGE) -> None
+
+

Call pre_init to change the defaults used when the real +pygame.mixer.init() is called. Keyword arguments are accepted. The best +way to set custom mixer playback values is to call +pygame.mixer.pre_init() before calling the top level pygame.init(). +For backwards compatibility, argument values of 0 are replaced with the +startup defaults, except for allowedchanges, where -1 is used.

+
+

Changed in pygame 1.8: The default buffersize changed from 1024 to 3072.

+
+
+

Changed in pygame 1.9.1: The default buffersize changed from 3072 to 4096.

+
+
+

Changed in pygame 2.0.0: The default buffersize changed from 4096 to 512.

+
+
+

Changed in pygame 2.0.0: The default frequency changed from 22050 to 44100.

+
+
+

New in pygame 2.0.0: allowedchanges, devicename arguments added

+
+
+ +
+
+pygame.mixer.quit()
+
+
uninitialize the mixer
+
quit() -> None
+
+

This will uninitialize pygame.mixerpygame module for loading and playing sounds. All playback will stop and any +loaded Sound objects may not be compatible with the mixer if it is +reinitialized later.

+
+ +
+
+pygame.mixer.get_init()
+
+
test if the mixer is initialized
+
get_init() -> (frequency, format, channels)
+
+

If the mixer is initialized, this returns the playback arguments it is +using. If the mixer has not been initialized this returns None.

+
+ +
+
+pygame.mixer.stop()
+
+
stop playback of all sound channels
+
stop() -> None
+
+

This will stop all playback of all active mixer channels.

+
+ +
+
+pygame.mixer.pause()
+
+
temporarily stop playback of all sound channels
+
pause() -> None
+
+

This will temporarily stop all playback on the active mixer channels. The +playback can later be resumed with pygame.mixer.unpause()

+
+ +
+
+pygame.mixer.unpause()
+
+
resume paused playback of sound channels
+
unpause() -> None
+
+

This will resume all active sound channels after they have been paused.

+
+ +
+
+pygame.mixer.fadeout()
+
+
fade out the volume on all sounds before stopping
+
fadeout(time) -> None
+
+

This will fade out the volume on all active channels over the time argument +in milliseconds. After the sound is muted the playback will stop.

+
+ +
+
+pygame.mixer.set_num_channels()
+
+
set the total number of playback channels
+
set_num_channels(count) -> None
+
+

Sets the number of available channels for the mixer. The default value is 8. +The value can be increased or decreased. If the value is decreased, sounds +playing on the truncated channels are stopped.

+
+ +
+
+pygame.mixer.get_num_channels()
+
+
get the total number of playback channels
+
get_num_channels() -> count
+
+

Returns the number of currently active playback channels.

+
+ +
+
+pygame.mixer.set_reserved()
+
+
reserve channels from being automatically used
+
set_reserved(count) -> count
+
+

The mixer can reserve any number of channels that will not be automatically +selected for playback by Sounds. If sounds are currently playing on the +reserved channels they will not be stopped.

+

This allows the application to reserve a specific number of channels for +important sounds that must not be dropped or have a guaranteed channel to +play on.

+

Will return number of channels actually reserved, this may be less than requested +depending on the number of channels previously allocated.

+
+ +
+
+pygame.mixer.find_channel()
+
+
find an unused channel
+
find_channel(force=False) -> Channel
+
+

This will find and return an inactive Channel object. If there are no +inactive Channels this function will return None. If there are no +inactive channels and the force argument is True, this will find the +Channel with the longest running Sound and return it.

+
+ +
+
+pygame.mixer.get_busy()
+
+
test if any sound is being mixed
+
get_busy() -> bool
+
+

Returns True if the mixer is busy mixing any channels. If the mixer is +idle then this return False.

+
+ +
+
+pygame.mixer.get_sdl_mixer_version()
+
+
get the mixer's SDL version
+
get_sdl_mixer_version() -> (major, minor, patch)
+
get_sdl_mixer_version(linked=True) -> (major, minor, patch)
+
+
+
Parameters
+

linked (bool) -- if True (default) the linked version number is +returned, otherwise the compiled version number is returned

+
+
Returns
+

the mixer's SDL library version number (linked or compiled +depending on the linked parameter) as a tuple of 3 integers +(major, minor, patch)

+
+
Return type
+

tuple

+
+
+
+

Note

+

The linked and compile version numbers should be the same.

+
+
+

New in pygame 2.0.0.

+
+
+ +
+
+pygame.mixer.Sound
+
+
Create a new Sound object from a file or buffer object
+
Sound(filename) -> Sound
+
Sound(file=filename) -> Sound
+
Sound(file=pathlib_path) -> Sound
+
Sound(buffer) -> Sound
+
Sound(buffer=buffer) -> Sound
+
Sound(object) -> Sound
+
Sound(file=object) -> Sound
+
Sound(array=object) -> Sound
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+begin sound playback
+stop sound playback
+stop sound playback after fading out
+set the playback volume for this Sound
+get the playback volume
+count how many times this Sound is playing
+get the length of the Sound
+return a bytestring copy of the Sound samples.
+

Load a new sound buffer from a filename, a python file object or a readable +buffer object. Limited resampling will be performed to help the sample match +the initialize arguments for the mixer. A Unicode string can only be a file +pathname. A bytes object can be either a pathname or a buffer object. +Use the 'file' or 'buffer' keywords to avoid ambiguity; otherwise Sound may +guess wrong. If the array keyword is used, the object is expected to export +a new buffer interface (The object is checked for a buffer interface first.)

+

The Sound object represents actual sound sample data. Methods that change +the state of the Sound object will the all instances of the Sound playback. +A Sound object also exports a new buffer interface.

+

The Sound can be loaded from an OGG audio file or from an uncompressed +WAV.

+

Note: The buffer will be copied internally, no data will be shared between +it and the Sound object.

+

For now buffer and array support is consistent with sndarray.make_sound +for Numeric arrays, in that sample sign and byte order are ignored. This +will change, either by correctly handling sign and byte order, or by raising +an exception when different. Also, source samples are truncated to fit the +audio sample size. This will not change.

+
+

New in pygame 1.8: pygame.mixer.Sound(buffer)

+
+
+

New in pygame 1.9.2: pygame.mixer.SoundCreate a new Sound object from a file or buffer object keyword arguments and array interface support

+
+
+

New in pygame 2.0.1: pathlib.Path support on Python 3.

+
+
+
+play()
+
+
begin sound playback
+
play(loops=0, maxtime=0, fade_ms=0) -> Channel
+
+

Begin playback of the Sound (i.e., on the computer's speakers) on an +available Channel. This will forcibly select a Channel, so playback may +cut off a currently playing sound if necessary.

+

The loops argument controls how many times the sample will be repeated +after being played the first time. A value of 5 means that the sound will +be played once, then repeated five times, and so is played a total of six +times. The default value (zero) means the Sound is not repeated, and so +is only played once. If loops is set to -1 the Sound will loop +indefinitely (though you can still call stop() to stop it).

+

The maxtime argument can be used to stop playback after a given number of +milliseconds.

+

The fade_ms argument will make the sound start playing at 0 volume and +fade up to full volume over the time given. The sample may end before the +fade-in is complete.

+

This returns the Channel object for the channel that was selected.

+
+ +
+
+stop()
+
+
stop sound playback
+
stop() -> None
+
+

This will stop the playback of this Sound on any active Channels.

+
+ +
+
+fadeout()
+
+
stop sound playback after fading out
+
fadeout(time) -> None
+
+

This will stop playback of the sound after fading it out over the time +argument in milliseconds. The Sound will fade and stop on all actively +playing channels.

+
+ +
+
+set_volume()
+
+
set the playback volume for this Sound
+
set_volume(value) -> None
+
+

This will set the playback volume (loudness) for this Sound. This will +immediately affect the Sound if it is playing. It will also affect any +future playback of this Sound.

+
+
Parameters
+

value (float) --

volume in the range of 0.0 to 1.0 (inclusive)

+
+
If value < 0.0, the volume will not be changed
+
If value > 1.0, the volume will be set to 1.0
+
+

+
+
+
+ +
+
+get_volume()
+
+
get the playback volume
+
get_volume() -> value
+
+

Return a value from 0.0 to 1.0 representing the volume for this Sound.

+
+ +
+
+get_num_channels()
+
+
count how many times this Sound is playing
+
get_num_channels() -> count
+
+

Return the number of active channels this sound is playing on.

+
+ +
+
+get_length()
+
+
get the length of the Sound
+
get_length() -> seconds
+
+

Return the length of this Sound in seconds.

+
+ +
+
+get_raw()
+
+
return a bytestring copy of the Sound samples.
+
get_raw() -> bytes
+
+

Return a copy of the Sound object buffer as a bytes.

+
+

New in pygame 1.9.2.

+
+
+ +
+ +
+
+pygame.mixer.Channel
+
+
Create a Channel object for controlling playback
+
Channel(id) -> Channel
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+play a Sound on a specific Channel
+stop playback on a Channel
+temporarily stop playback of a channel
+resume pause playback of a channel
+stop playback after fading channel out
+set the volume of a playing channel
+get the volume of the playing channel
+check if the channel is active
+get the currently playing Sound
+queue a Sound object to follow the current
+return any Sound that is queued
+have the channel send an event when playback stops
+get the event a channel sends when playback stops
+

Return a Channel object for one of the current channels. The id must be a +value from 0 to the value of pygame.mixer.get_num_channels().

+

The Channel object can be used to get fine control over the playback of +Sounds. A channel can only playback a single Sound at time. Using channels +is entirely optional since pygame can manage them by default.

+
+
+play()
+
+
play a Sound on a specific Channel
+
play(Sound, loops=0, maxtime=0, fade_ms=0) -> None
+
+

This will begin playback of a Sound on a specific Channel. If the Channel +is currently playing any other Sound it will be stopped.

+

The loops argument has the same meaning as in Sound.play(): it is the +number of times to repeat the sound after the first time. If it is 3, the +sound will be played 4 times (the first time, then three more). If loops +is -1 then the playback will repeat indefinitely.

+

As in Sound.play(), the maxtime argument can be used to stop playback +of the Sound after a given number of milliseconds.

+

As in Sound.play(), the fade_ms argument can be used fade in the +sound.

+
+ +
+
+stop()
+
+
stop playback on a Channel
+
stop() -> None
+
+

Stop sound playback on a channel. After playback is stopped the channel +becomes available for new Sounds to play on it.

+
+ +
+
+pause()
+
+
temporarily stop playback of a channel
+
pause() -> None
+
+

Temporarily stop the playback of sound on a channel. It can be resumed at +a later time with Channel.unpause()

+
+ +
+
+unpause()
+
+
resume pause playback of a channel
+
unpause() -> None
+
+

Resume the playback on a paused channel.

+
+ +
+
+fadeout()
+
+
stop playback after fading channel out
+
fadeout(time) -> None
+
+

Stop playback of a channel after fading out the sound over the given time +argument in milliseconds.

+
+ +
+
+set_volume()
+
+
set the volume of a playing channel
+
set_volume(value) -> None
+
set_volume(left, right) -> None
+
+

Set the volume (loudness) of a playing sound. When a channel starts to +play its volume value is reset. This only affects the current sound. The +value argument is between 0.0 and 1.0.

+

If one argument is passed, it will be the volume of both speakers. If two +arguments are passed and the mixer is in stereo mode, the first argument +will be the volume of the left speaker and the second will be the volume +of the right speaker. (If the second argument is None, the first +argument will be the volume of both speakers.)

+

If the channel is playing a Sound on which set_volume() has also been +called, both calls are taken into account. For example:

+
sound = pygame.mixer.Sound("s.wav")
+channel = s.play()      # Sound plays at full volume by default
+sound.set_volume(0.9)   # Now plays at 90% of full volume.
+sound.set_volume(0.6)   # Now plays at 60% (previous value replaced).
+channel.set_volume(0.5) # Now plays at 30% (0.6 * 0.5).
+
+
+
+ +
+
+get_volume()
+
+
get the volume of the playing channel
+
get_volume() -> value
+
+

Return the volume of the channel for the current playing sound. This does +not take into account stereo separation used by +Channel.set_volume(). The Sound object also has its own volume +which is mixed with the channel.

+
+ +
+
+get_busy()
+
+
check if the channel is active
+
get_busy() -> bool
+
+

Returns True if the channel is actively mixing sound. If the channel +is idle this returns False.

+
+ +
+
+get_sound()
+
+
get the currently playing Sound
+
get_sound() -> Sound
+
+

Return the actual Sound object currently playing on this channel. If the +channel is idle None is returned.

+
+ +
+
+queue()
+
+
queue a Sound object to follow the current
+
queue(Sound) -> None
+
+

When a Sound is queued on a Channel, it will begin playing immediately +after the current Sound is finished. Each channel can only have a single +Sound queued at a time. The queued Sound will only play if the current +playback finished automatically. It is cleared on any other call to +Channel.stop() or Channel.play().

+

If there is no sound actively playing on the Channel then the Sound will +begin playing immediately.

+
+ +
+
+get_queue()
+
+
return any Sound that is queued
+
get_queue() -> Sound
+
+

If a Sound is already queued on this channel it will be returned. Once +the queued sound begins playback it will no longer be on the queue.

+
+ +
+
+set_endevent()
+
+
have the channel send an event when playback stops
+
set_endevent() -> None
+
set_endevent(type) -> None
+
+

When an endevent is set for a channel, it will send an event to the +pygame queue every time a sound finishes playing on that channel (not +just the first time). Use pygame.event.get() to retrieve the endevent +once it's sent.

+

Note that if you called Sound.play(n) or Channel.play(sound,n), +the end event is sent only once: after the sound has been played "n+1" +times (see the documentation of Sound.play).

+

If Channel.stop() or Channel.play() is called while the sound was +still playing, the event will be posted immediately.

+

The type argument will be the event id sent to the queue. This can be any +valid event type, but a good choice would be a value between +pygame.locals.USEREVENT and pygame.locals.NUMEVENTS. If no type +argument is given then the Channel will stop sending endevents.

+
+ +
+
+get_endevent()
+
+
get the event a channel sends when playback stops
+
get_endevent() -> type
+
+

Returns the event type to be sent every time the Channel finishes +playback of a Sound. If there is no endevent the function returns +pygame.NOEVENT.

+
+ +
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/mouse.html b/venv/Lib/site-packages/pygame/docs/generated/ref/mouse.html new file mode 100644 index 0000000..1af1d62 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/mouse.html @@ -0,0 +1,406 @@ + + + + + + + + + pygame.mouse — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.mouse
+
+
pygame module to work with the mouse
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+get the state of the mouse buttons
+get the mouse cursor position
+get the amount of mouse movement
+set the mouse cursor position
+hide or show the mouse cursor
+get the current visibility state of the mouse cursor
+check if the display is receiving mouse input
+set the mouse cursor to a new cursor
+get the current mouse cursor
+

The mouse functions can be used to get the current state of the mouse device. +These functions can also alter the system cursor for the mouse.

+

When the display mode is set, the event queue will start receiving mouse +events. The mouse buttons generate pygame.MOUSEBUTTONDOWN and +pygame.MOUSEBUTTONUP events when they are pressed and released. These +events contain a button attribute representing which button was pressed. The +mouse wheel will generate pygame.MOUSEBUTTONDOWN and +pygame.MOUSEBUTTONUP events when rolled. The button will be set to 4 +when the wheel is rolled up, and to button 5 when the wheel is rolled down. +Whenever the mouse is moved it generates a pygame.MOUSEMOTION event. The +mouse movement is broken into small and accurate motion events. As the mouse +is moving many motion events will be placed on the queue. Mouse motion events +that are not properly cleaned from the event queue are the primary reason the +event queue fills up.

+

If the mouse cursor is hidden, and input is grabbed to the current display the +mouse will enter a virtual input mode, where the relative movements of the +mouse will never be stopped by the borders of the screen. See the functions +pygame.mouse.set_visible() and pygame.event.set_grab() to get this +configured.

+

Mouse Wheel Behavior in pygame 2

+

There is proper functionality for mouse wheel behaviour with pygame 2 supporting +pygame.MOUSEWHEEL events. The new events support horizontal and vertical +scroll movements, with signed integer values representing the amount scrolled +(x and y), as well as flipped direction (the set positive and +negative values for each axis is flipped). Read more about SDL2 +input-related changes here https://wiki.libsdl.org/MigrationGuide#Input

+

In pygame 2, the mouse wheel functionality can be used by listening for the +pygame.MOUSEWHEEL type of an event (Bear in mind they still emit +pygame.MOUSEBUTTONDOWN events like in pygame 1.x, as well). +When this event is triggered, a developer can access the appropriate Event object +with pygame.event.get(). The object can be used to access data about the mouse +scroll, such as which (it will tell you what exact mouse device trigger the event).

+
+
Code example of mouse scroll (tested on 2.0.0.dev7)
+
# Taken from husano896's PR thread (slightly modified)
+import pygame
+from pygame.locals import *
+pygame.init()
+screen = pygame.display.set_mode((640, 480))
+clock = pygame.time.Clock()
+
+def main():
+   while True:
+      for event in pygame.event.get():
+            if event.type == QUIT:
+               pygame.quit()
+               return
+            elif event.type == MOUSEWHEEL:
+               print(event)
+               print(event.x, event.y)
+               print(event.flipped)
+               print(event.which)
+               # can access properties with
+               # proper notation(ex: event.y)
+      clock.tick(60)
+
+# Execute game:
+main()
+
+
+
+
+
+pygame.mouse.get_pressed()
+
+
get the state of the mouse buttons
+
get_pressed(num_buttons=3) -> (button1, button2, button3)
+
get_pressed(num_buttons=5) -> (button1, button2, button3, button4, button5)
+
+

Returns a sequence of booleans representing the state of all the mouse +buttons. A true value means the mouse is currently being pressed at the time +of the call.

+

Note, to get all of the mouse events it is better to use either +pygame.event.wait() or pygame.event.get() and check all of those +events to see if they are MOUSEBUTTONDOWN, MOUSEBUTTONUP, or +MOUSEMOTION.

+

Note, that on X11 some X servers use middle button emulation. When you +click both buttons 1 and 3 at the same time a 2 button event +can be emitted.

+

Note, remember to call pygame.event.get() before this function. +Otherwise it will not work as expected.

+

To support five button mice, an optional parameter num_buttons has been +added in pygame 2. When this is set to 5, button4 and button5 +are added to the returned tuple. Only 3 and 5 are valid values +for this parameter.

+
+

Changed in pygame 2.0.0: num_buttons argument added

+
+
+ +
+
+pygame.mouse.get_pos()
+
+
get the mouse cursor position
+
get_pos() -> (x, y)
+
+

Returns the x and y position of the mouse cursor. The position is +relative to the top-left corner of the display. The cursor position can be +located outside of the display window, but is always constrained to the +screen.

+
+ +
+
+pygame.mouse.get_rel()
+
+
get the amount of mouse movement
+
get_rel() -> (x, y)
+
+

Returns the amount of movement in x and y since the previous call to +this function. The relative movement of the mouse cursor is constrained to +the edges of the screen, but see the virtual input mouse mode for a way +around this. Virtual input mode is described at the top of the page.

+
+ +
+
+pygame.mouse.set_pos()
+
+
set the mouse cursor position
+
set_pos([x, y]) -> None
+
+

Set the current mouse position to arguments given. If the mouse cursor is +visible it will jump to the new coordinates. Moving the mouse will generate +a new pygame.MOUSEMOTION event.

+
+ +
+
+pygame.mouse.set_visible()
+
+
hide or show the mouse cursor
+
set_visible(bool) -> bool
+
+

If the bool argument is true, the mouse cursor will be visible. This will +return the previous visible state of the cursor.

+
+ +
+
+pygame.mouse.get_visible()
+
+
get the current visibility state of the mouse cursor
+
get_visible() -> bool
+
+

Get the current visibility state of the mouse cursor. True if the mouse is +visible, False otherwise.

+
+

New in pygame 2.0.0.

+
+
+ +
+
+pygame.mouse.get_focused()
+
+
check if the display is receiving mouse input
+
get_focused() -> bool
+
+

Returns true when pygame is receiving mouse input events (or, in windowing +terminology, is "active" or has the "focus").

+

This method is most useful when working in a window. By contrast, in +full-screen mode, this method always returns true.

+

Note: under MS Windows, the window that has the mouse focus also has the +keyboard focus. But under X-Windows, one window can receive mouse events and +another receive keyboard events. pygame.mouse.get_focused() indicates +whether the pygame window receives mouse events.

+
+ +
+
+pygame.mouse.set_cursor()
+
+
set the mouse cursor to a new cursor
+
set_cursor(pygame.cursors.Cursor) -> None
+
set_cursor(size, hotspot, xormasks, andmasks) -> None
+
set_cursor(hotspot, surface) -> None
+
set_cursor(constant) -> None
+
+

Set the mouse cursor to something new. This function accepts either an explicit +Cursor object or arguments to create a Cursor object.

+

See pygame.cursors.Cursorpygame object representing a cursor for help creating cursors and for examples.

+
+

Changed in pygame 2.0.1.

+
+
+ +
+
+pygame.mouse.get_cursor()
+
+
get the current mouse cursor
+
get_cursor() -> pygame.cursors.Cursor
+
+

Get the information about the mouse system cursor. The return value contains +the same data as the arguments passed into pygame.mouse.set_cursor()set the mouse cursor to a new cursor.

+
+

Note

+

Code that unpacked a get_cursor() call into +size, hotspot, xormasks, andmasks will still work, +assuming the call returns an old school type cursor.

+
+
+

Changed in pygame 2.0.1.

+
+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/music.html b/venv/Lib/site-packages/pygame/docs/generated/ref/music.html new file mode 100644 index 0000000..f9d86ba --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/music.html @@ -0,0 +1,502 @@ + + + + + + + + + pygame.mixer.music — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.mixer.music
+
+
pygame module for controlling streamed audio
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Load a music file for playback
+Unload the currently loaded music to free up resources
+Start the playback of the music stream
+restart music
+stop the music playback
+temporarily stop music playback
+resume paused music
+stop music playback after fading out
+set the music volume
+get the music volume
+check if the music stream is playing
+set position to play from
+get the music play time
+queue a sound file to follow the current
+have the music send an event when playback stops
+get the event a channel sends when playback stops
+

The music module is closely tied to pygame.mixerpygame module for loading and playing sounds. Use the music module +to control the playback of music in the sound mixer.

+

The difference between the music playback and regular Sound playback is that +the music is streamed, and never actually loaded all at once. The mixer system +only supports a single music stream at once.

+

On older pygame versions, MP3 support was limited under Mac and Linux. This +changed in pygame v2.0.2 which got improved MP3 support. Consider using +OGG file format for music as that can give slightly better compression than +MP3 in most cases.

+
+
+pygame.mixer.music.load()
+
+
Load a music file for playback
+
load(filename) -> None
+
load(fileobj, namehint="") -> None
+
+

This will load a music filename/file object and prepare it for playback. If +a music stream is already playing it will be stopped. This does not start +the music playing.

+

If you are loading from a file object, the namehint parameter can be used to specify +the type of music data in the object. For example: load(fileobj, "ogg").

+
+

Changed in pygame 2.0.2: Added optional namehint argument

+
+
+ +
+
+pygame.mixer.music.unload()
+
+
Unload the currently loaded music to free up resources
+
unload() -> None
+
+

This closes resources like files for any music that may be loaded.

+
+

New in pygame 2.0.0.

+
+
+ +
+
+pygame.mixer.music.play()
+
+
Start the playback of the music stream
+
play(loops=0, start=0.0, fade_ms=0) -> None
+
+

This will play the loaded music stream. If the music is already playing it +will be restarted.

+

loops is an optional integer argument, which is 0 by default, which +indicates how many times to repeat the music. The music repeats indefinitely if +this argument is set to -1.

+

start is an optional float argument, which is 0.0 by default, which +denotes the position in time from which the music starts playing. The starting +position depends on the format of the music played. MP3 and OGG use +the position as time in seconds. For MP3 files the start time position +selected may not be accurate as things like variable bit rate encoding and ID3 +tags can throw off the timing calculations. For MOD music it is the pattern +order number. Passing a start position will raise a NotImplementedError if +the start position cannot be set.

+

fade_ms is an optional integer argument, which is 0 by default, +which denotes the period of time (in milliseconds) over which the music +will fade up from volume level 0.0 to full volume (or the volume level +previously set by set_volume()). The sample may end before the fade-in +is complete. If the music is already streaming fade_ms is ignored.

+
+

Changed in pygame 2.0.0: Added optional fade_ms argument

+
+
+ +
+
+pygame.mixer.music.rewind()
+
+
restart music
+
rewind() -> None
+
+

Resets playback of the current music to the beginning. If pause() has +previoulsy been used to pause the music, the music will remain paused.

+
+

Note

+

rewind() supports a limited number of file types and notably +WAV files are NOT supported. For unsupported file types use play() +which will restart the music that's already playing (note that this +will start the music playing again even if previously paused).

+
+
+ +
+
+pygame.mixer.music.stop()
+
+
stop the music playback
+
stop() -> None
+
+

Stops the music playback if it is currently playing. +endevent will be triggered, if set. +It won't unload the music.

+
+ +
+
+pygame.mixer.music.pause()
+
+
temporarily stop music playback
+
pause() -> None
+
+

Temporarily stop playback of the music stream. It can be resumed with the +unpause() function.

+
+ +
+
+pygame.mixer.music.unpause()
+
+
resume paused music
+
unpause() -> None
+
+

This will resume the playback of a music stream after it has been paused.

+
+ +
+
+pygame.mixer.music.fadeout()
+
+
stop music playback after fading out
+
fadeout(time) -> None
+
+

Fade out and stop the currently playing music.

+

The time argument denotes the integer milliseconds for which the +fading effect is generated.

+

Note, that this function blocks until the music has faded out. Calls +to fadeout() and set_volume() will have no effect during +this time. If an event was set using set_endevent() it will be +called after the music has faded.

+
+ +
+
+pygame.mixer.music.set_volume()
+
+
set the music volume
+
set_volume(volume) -> None
+
+

Set the volume of the music playback.

+

The volume argument is a float between 0.0 and 1.0 that sets +the volume level. When new music is loaded the volume is reset to full +volume. If volume is a negative value it will be ignored and the +volume will remain set at the current level. If the volume argument +is greater than 1.0, the volume will be set to 1.0.

+
+ +
+
+pygame.mixer.music.get_volume()
+
+
get the music volume
+
get_volume() -> value
+
+

Returns the current volume for the mixer. The value will be between 0.0 +and 1.0.

+
+ +
+
+pygame.mixer.music.get_busy()
+
+
check if the music stream is playing
+
get_busy() -> bool
+
+

Returns True when the music stream is actively playing. When the music is +idle this returns False. In pygame 2.0.1 and above this function returns +False when the music is paused. In pygame 1 it returns True when the music +is paused.

+
+

Changed in pygame 2.0.1: Returns False when music paused.

+
+
+ +
+
+pygame.mixer.music.set_pos()
+
+
set position to play from
+
set_pos(pos) -> None
+
+

This sets the position in the music file where playback will start. +The meaning of "pos", a float (or a number that can be converted to a float), +depends on the music format.

+

For MOD files, pos is the integer pattern number in the module. +For OGG it is the absolute position, in seconds, from +the beginning of the sound. For MP3 files, it is the relative position, +in seconds, from the current position. For absolute positioning in an MP3 +file, first call rewind().

+

Other file formats are unsupported. Newer versions of SDL_mixer have +better positioning support than earlier ones. An SDLError is raised if a +particular format does not support positioning.

+

Function set_pos() calls underlining SDL_mixer function +Mix_SetMusicPosition.

+
+

New in pygame 1.9.2.

+
+
+ +
+
+pygame.mixer.music.get_pos()
+
+
get the music play time
+
get_pos() -> time
+
+

This gets the number of milliseconds that the music has been playing for. +The returned time only represents how long the music has been playing; it +does not take into account any starting position offsets.

+
+ +
+
+pygame.mixer.music.queue()
+
+
queue a sound file to follow the current
+
queue(filename) -> None
+
queue(fileobj, namehint="", loops=0) -> None
+
+

This will load a sound file and queue it. A queued sound file will begin as +soon as the current sound naturally ends. Only one sound can be queued at a +time. Queuing a new sound while another sound is queued will result in the +new sound becoming the queued sound. Also, if the current sound is ever +stopped or changed, the queued sound will be lost.

+

If you are loading from a file object, the namehint parameter can be used to specify +the type of music data in the object. For example: queue(fileobj, "ogg").

+

The following example will play music by Bach six times, then play music by +Mozart once:

+
pygame.mixer.music.load('bach.ogg')
+pygame.mixer.music.play(5)        # Plays six times, not five!
+pygame.mixer.music.queue('mozart.ogg')
+
+
+
+

Changed in pygame 2.0.2: Added optional namehint argument

+
+
+ +
+
+pygame.mixer.music.set_endevent()
+
+
have the music send an event when playback stops
+
set_endevent() -> None
+
set_endevent(type) -> None
+
+

This causes pygame to signal (by means of the event queue) when the music is +done playing. The argument determines the type of event that will be queued.

+

The event will be queued every time the music finishes, not just the first +time. To stop the event from being queued, call this method with no +argument.

+
+ +
+
+pygame.mixer.music.get_endevent()
+
+
get the event a channel sends when playback stops
+
get_endevent() -> type
+
+

Returns the event type to be sent every time the music finishes playback. If +there is no endevent the function returns pygame.NOEVENT.

+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/overlay.html b/venv/Lib/site-packages/pygame/docs/generated/ref/overlay.html new file mode 100644 index 0000000..00ecdca --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/overlay.html @@ -0,0 +1,231 @@ + + + + + + + + + pygame.Overlay — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

Warning

+

This module is non functional in pygame 2.0 and above, unless you have manually compiled pygame with SDL1. +This module will not be supported in the future.

+
+
+
+pygame.Overlay
+
+
pygame object for video overlay graphics
+
Overlay(format, (width, height)) -> Overlay
+
+ +++++ + + + + + + + + + + + + + + +
+set the overlay pixel data
+control where the overlay is displayed
+test if the Overlay is hardware accelerated
+

The Overlay objects provide support for accessing hardware video overlays. +Video overlays do not use standard RGB pixel formats, and can use +multiple resolutions of data to create a single image.

+

The Overlay objects represent lower level access to the display hardware. To +use the object you must understand the technical details of video overlays.

+

The Overlay format determines the type of pixel data used. Not all hardware +will support all types of overlay formats. Here is a list of available +format types:

+
YV12_OVERLAY, IYUV_OVERLAY, YUY2_OVERLAY, UYVY_OVERLAY, YVYU_OVERLAY
+
+
+

The width and height arguments control the size for the overlay image data. +The overlay image can be displayed at any size, not just the resolution of +the overlay.

+

The overlay objects are always visible, and always show above the regular +display contents.

+
+
+display()
+
+
set the overlay pixel data
+
display((y, u, v)) -> None
+
display() -> None
+
+

Display the YUV data in SDL's overlay planes. The y, u, and v arguments +are strings of binary data. The data must be in the correct format used +to create the Overlay.

+

If no argument is passed in, the Overlay will simply be redrawn with the +current data. This can be useful when the Overlay is not really hardware +accelerated.

+

The strings are not validated, and improperly sized strings could crash +the program.

+
+ +
+
+set_location()
+
+
control where the overlay is displayed
+
set_location(rect) -> None
+
+

Set the location for the overlay. The overlay will always be shown +relative to the main display Surface. This does not actually redraw the +overlay, it will be updated on the next call to Overlay.display().

+
+ +
+
+get_hardware()
+
+
test if the Overlay is hardware accelerated
+
get_hardware(rect) -> int
+
+

Returns a True value when the Overlay is hardware accelerated. If the +platform does not support acceleration, software rendering is used.

+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/pixelarray.html b/venv/Lib/site-packages/pygame/docs/generated/ref/pixelarray.html new file mode 100644 index 0000000..dad2d87 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/pixelarray.html @@ -0,0 +1,486 @@ + + + + + + + + + pygame.PixelArray — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.PixelArray
+
+
pygame object for direct pixel access of surfaces
+
PixelArray(Surface) -> PixelArray
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Gets the Surface the PixelArray uses.
+Returns the byte size of a pixel array item
+Returns the number of dimensions.
+Returns the array size.
+Returns byte offsets for each array dimension.
+Creates a new Surface from the current PixelArray.
+Replaces the passed color in the PixelArray with another one.
+Extracts the passed color from the PixelArray.
+Compares the PixelArray with another one.
+Exchanges the x and y axis.
+Closes the PixelArray, and releases Surface lock.
+

The PixelArray wraps a Surface and provides direct access to the +surface's pixels. A pixel array can be one or two dimensional. +A two dimensional array, like its surface, is indexed [column, row]. +Pixel arrays support slicing, both for returning a subarray or +for assignment. A pixel array sliced on a single column or row +returns a one dimensional pixel array. Arithmetic and other operations +are not supported. A pixel array can be safely assigned to itself. +Finally, pixel arrays export an array struct interface, allowing +them to interact with pygame.pixelcopypygame module for general pixel array copying methods and NumPy +arrays.

+

A PixelArray pixel item can be assigned a raw integer values, a +pygame.Colorpygame object for color representations instance, or a (r, g, b[, a]) tuple.

+
pxarray[x, y] = 0xFF00FF
+pxarray[x, y] = pygame.Color(255, 0, 255)
+pxarray[x, y] = (255, 0, 255)
+
+
+

However, only a pixel's integer value is returned. So, to compare a pixel +to a particular color the color needs to be first mapped using +the Surface.map_rgb() method of the Surface object for which the +PixelArray was created.

+
pxarray = pygame.PixelArray(surface)
+# Check, if the first pixel at the topleft corner is blue
+if pxarray[0, 0] == surface.map_rgb((0, 0, 255)):
+    ...
+
+
+

When assigning to a range of of pixels, a non tuple sequence of colors or +a PixelArray can be used as the value. For a sequence, the length must +match the PixelArray width.

+
pxarray[a:b] = 0xFF00FF                   # set all pixels to 0xFF00FF
+pxarray[a:b] = (0xFF00FF, 0xAACCEE, ... ) # first pixel = 0xFF00FF,
+                                          # second pixel  = 0xAACCEE, ...
+pxarray[a:b] = [(255, 0, 255), (170, 204, 238), ...] # same as above
+pxarray[a:b] = [(255, 0, 255), 0xAACCEE, ...]        # same as above
+pxarray[a:b] = otherarray[x:y]            # slice sizes must match
+
+
+

For PixelArray assignment, if the right hand side array has a row length +of 1, then the column is broadcast over the target array's rows. An +array of height 1 is broadcast over the target's columns, and is equivalent +to assigning a 1D PixelArray.

+

Subscript slices can also be used to assign to a rectangular subview of +the target PixelArray.

+
# Create some new PixelArray objects providing a different view
+# of the original array/surface.
+newarray = pxarray[2:4, 3:5]
+otherarray = pxarray[::2, ::2]
+
+
+

Subscript slices can also be used to do fast rectangular pixel manipulations +instead of iterating over the x or y axis. The

+
pxarray[::2, :] = (0, 0, 0)               # Make even columns black.
+pxarray[::2] = (0, 0, 0)                  # Same as [::2, :]
+
+
+

During its lifetime, the PixelArray locks the surface, thus you explicitly +have to close() it once its not used any more and the surface should perform +operations in the same scope. It is best to use it as a context manager +using the with PixelArray(surf) as pixel_array: style. So it works on pypy too.

+

A simple : slice index for the column can be omitted.

+
pxarray[::2, ...] = (0, 0, 0)             # Same as pxarray[::2, :]
+pxarray[...] = (255, 0, 0)                # Same as pxarray[:]
+
+
+

A note about PixelArray to PixelArray assignment, for arrays with an +item size of 3 (created from 24 bit surfaces) pixel values are translated +from the source to the destinations format. The red, green, and blue +color elements of each pixel are shifted to match the format of the +target surface. For all other pixel sizes no such remapping occurs. +This should change in later pygame releases, where format conversions +are performed for all pixel sizes. To avoid code breakage when full mapped +copying is implemented it is suggested PixelArray to PixelArray copies be +only between surfaces of identical format.

+
+

New in pygame 1.9.4:

+
    +
  • close() method was added. For explicitly cleaning up.

  • +
  • being able to use PixelArray as a context manager for cleanup.

  • +
  • both of these are useful for when working without reference counting (pypy).

  • +
+
+
+

New in pygame 1.9.2:

+
    +
  • array struct interface

  • +
  • transpose method

  • +
  • broadcasting for a length 1 dimension

  • +
+
+
+

Changed in pygame 1.9.2:

+
    +
  • A 2D PixelArray can have a length 1 dimension. +Only an integer index on a 2D PixelArray returns a 1D array.

  • +
  • For assignment, a tuple can only be a color. Any other sequence type +is a sequence of colors.

  • +
+
+
+
+surface
+
+
Gets the Surface the PixelArray uses.
+
surface -> Surface
+
+

The Surface the PixelArray was created for.

+
+ +
+
+itemsize
+
+
Returns the byte size of a pixel array item
+
itemsize -> int
+
+

This is the same as Surface.get_bytesize() for the +pixel array's surface.

+
+

New in pygame 1.9.2.

+
+
+ +
+
+ndim
+
+
Returns the number of dimensions.
+
ndim -> int
+
+

A pixel array can be 1 or 2 dimensional.

+
+

New in pygame 1.9.2.

+
+
+ +
+
+shape
+
+
Returns the array size.
+
shape -> tuple of int's
+
+

A tuple or length ndim giving the length of each +dimension. Analogous to Surface.get_size().

+
+

New in pygame 1.9.2.

+
+
+ +
+
+strides
+
+
Returns byte offsets for each array dimension.
+
strides -> tuple of int's
+
+

A tuple or length ndim byte counts. When a stride is +multiplied by the corresponding index it gives the offset +of that index from the start of the array. A stride is negative +for an array that has is inverted (has a negative step).

+
+

New in pygame 1.9.2.

+
+
+ +
+
+make_surface()
+
+
Creates a new Surface from the current PixelArray.
+
make_surface() -> Surface
+
+

Creates a new Surface from the current PixelArray. Depending on the +current PixelArray the size, pixel order etc. will be different from the +original Surface.

+
# Create a new surface flipped around the vertical axis.
+sf = pxarray[:,::-1].make_surface ()
+
+
+
+

New in pygame 1.8.1.

+
+
+ +
+
+replace()
+
+
Replaces the passed color in the PixelArray with another one.
+
replace(color, repcolor, distance=0, weights=(0.299, 0.587, 0.114)) -> None
+
+

Replaces the pixels with the passed color in the PixelArray by changing +them them to the passed replacement color.

+

It uses a simple weighted Euclidean distance formula to calculate the +distance between the colors. The distance space ranges from 0.0 to 1.0 +and is used as threshold for the color detection. This causes the +replacement to take pixels with a similar, but not exactly identical +color, into account as well.

+

This is an in place operation that directly affects the pixels of the +PixelArray.

+
+

New in pygame 1.8.1.

+
+
+ +
+
+extract()
+
+
Extracts the passed color from the PixelArray.
+
extract(color, distance=0, weights=(0.299, 0.587, 0.114)) -> PixelArray
+
+

Extracts the passed color by changing all matching pixels to white, while +non-matching pixels are changed to black. This returns a new PixelArray +with the black/white color mask.

+

It uses a simple weighted Euclidean distance formula to calculate the +distance between the colors. The distance space ranges from 0.0 to 1.0 +and is used as threshold for the color detection. This causes the +extraction to take pixels with a similar, but not exactly identical +color, into account as well.

+
+

New in pygame 1.8.1.

+
+
+ +
+
+compare()
+
+
Compares the PixelArray with another one.
+
compare(array, distance=0, weights=(0.299, 0.587, 0.114)) -> PixelArray
+
+

Compares the contents of the PixelArray with those from the passed in +PixelArray. It returns a new PixelArray with a black/white color mask +that indicates the differences (black) of both arrays. Both PixelArray +objects must have identical bit depths and dimensions.

+

It uses a simple weighted Euclidean distance formula to calculate the +distance between the colors. The distance space ranges from 0.0 to 1.0 +and is used as a threshold for the color detection. This causes the +comparison to mark pixels with a similar, but not exactly identical +color, as white.

+
+

New in pygame 1.8.1.

+
+
+ +
+
+transpose()
+
+
Exchanges the x and y axis.
+
transpose() -> PixelArray
+
+

This method returns a new view of the pixel array with the rows and +columns swapped. So for a (w, h) sized array a (h, w) slice is returned. +If an array is one dimensional, then a length 1 x dimension is added, +resulting in a 2D pixel array.

+
+

New in pygame 1.9.2.

+
+
+ +
+
+close()
+
+
Closes the PixelArray, and releases Surface lock.
+
transpose() -> PixelArray
+
+

This method is for explicitly closing the PixelArray, and releasing +a lock on the Suface.

+
+

New in pygame 1.9.4.

+
+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/pixelcopy.html b/venv/Lib/site-packages/pygame/docs/generated/ref/pixelcopy.html new file mode 100644 index 0000000..55fa60a --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/pixelcopy.html @@ -0,0 +1,262 @@ + + + + + + + + + pygame.pixelcopy — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.pixelcopy
+
+
pygame module for general pixel array copying
+
+ +++++ + + + + + + + + + + + + + + + + + + +
+copy surface pixels to an array object
+copy an array object to a surface
+copy an array to another array, using surface format
+Copy an array to a new surface
+

The pygame.pixelcopy module contains functions for copying between +surfaces and objects exporting an array structure interface. It is a backend +for pygame.surfarraypygame module for accessing surface pixel data using array interfaces, adding NumPy support. But pixelcopy is more +general, and intended for direct use.

+

The array struct interface exposes an array's data in a standard way. +It was introduced in NumPy. In Python 2.7 and above it is replaced by the +new buffer protocol, though the buffer protocol is still a work in progress. +The array struct interface, on the other hand, is stable and works with earlier +Python versions. So for now the array struct interface is the predominate way +pygame handles array introspection.

+

For 2d arrays of integer pixel values, the values are mapped to the +pixel format of the related surface. To get the actual color of a pixel +value use pygame.Surface.unmap_rgb()convert a mapped integer color value into a Color. 2d arrays can only be used +directly between surfaces having the same pixel layout.

+

New in pygame 1.9.2.

+
+
+pygame.pixelcopy.surface_to_array()
+
+
copy surface pixels to an array object
+
surface_to_array(array, surface, kind='P', opaque=255, clear=0) -> None
+
+

The surface_to_array function copies pixels from a Surface object +to a 2D or 3D array. Depending on argument kind and the target array +dimension, a copy may be raw pixel value, RGB, a color component slice, +or colorkey alpha transparency value. Recognized kind values are the +single character codes 'P', 'R', 'G', 'B', 'A', and 'C'. Kind codes are case +insensitive, so 'p' is equivalent to 'P'. The first two dimensions +of the target must be the surface size (w, h).

+

The default 'P' kind code does a direct raw integer pixel (mapped) value +copy to a 2D array and a 'RGB' pixel component (unmapped) copy to a 3D array +having shape (w, h, 3). For an 8 bit colormap surface this means the +table index is copied to a 2D array, not the table value itself. A 2D +array's item size must be at least as large as the surface's pixel +byte size. The item size of a 3D array must be at least one byte.

+

For the 'R', 'G', 'B', and 'A' copy kinds a single color component +of the unmapped surface pixels are copied to the target 2D array. +For kind 'A' and surfaces with source alpha (the surface was created with +the SRCALPHA flag), has a colorkey +(set with Surface.set_colorkey()), +or has a blanket alpha +(set with Surface.set_alpha()) +then the alpha values are those expected for a SDL surface. +If a surface has no explicit alpha value, then the target array +is filled with the value of the optional opaque surface_to_array +argument (default 255: not transparent).

+

Copy kind 'C' is a special case for alpha copy of a source surface +with colorkey. Unlike the 'A' color component copy, the clear +argument value is used for colorkey matches, opaque otherwise. +By default, a match has alpha 0 (totally transparent), while everything +else is alpha 255 (totally opaque). It is a more general implementation +of pygame.surfarray.array_colorkey()Copy the colorkey values into a 2d array.

+

Specific to surface_to_array, a ValueError is raised for target arrays +with incorrect shape or item size. A TypeError is raised for an incorrect +kind code. Surface specific problems, such as locking, raise a pygame.error.

+
+ +
+
+pygame.pixelcopy.array_to_surface()
+
+
copy an array object to a surface
+
array_to_surface(<surface>, <array>) -> None
+
+

See pygame.surfarray.blit_array()Blit directly from a array values.

+
+ +
+
+pygame.pixelcopy.map_array()
+
+
copy an array to another array, using surface format
+
map_array(<array>, <array>, <surface>) -> None
+
+

Map an array of color element values - (w, h, ..., 3) - to an array of +pixels - (w, h) according to the format of <surface>.

+
+ +
+
+pygame.pixelcopy.make_surface()
+
+
Copy an array to a new surface
+
pygame.pixelcopy.make_surface(array) -> Surface
+
+

Create a new Surface that best resembles the data and format of the array. +The array can be 2D or 3D with any sized integer values.

+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/pygame.html b/venv/Lib/site-packages/pygame/docs/generated/ref/pygame.html new file mode 100644 index 0000000..8b48ddd --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/pygame.html @@ -0,0 +1,693 @@ + + + + + + + + + pygame — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame
+
+
the top level pygame package
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+initialize all imported pygame modules
+uninitialize all pygame modules
+returns True if pygame is currently initialized
+standard pygame exception
+get the current error message
+set the current error message
+get the version number of SDL
+get the byte order of SDL
+register a function to be called when pygame quits
+Encode a Unicode or bytes object
+Encode a Unicode or bytes object as a file system path
+

The pygame package represents the top-level package for others to use. Pygame +itself is broken into many submodules, but this does not affect programs that +use pygame.

+

As a convenience, most of the top-level variables in pygame have been placed +inside a module named pygame.localspygame constants. This is meant to be used with +from pygame.locals import *, in addition to import pygame.

+

When you import pygame all available pygame submodules are automatically +imported. Be aware that some of the pygame modules are considered optional, +and may not be available. In that case, pygame will provide a placeholder +object instead of the module, which can be used to test for availability.

+
+
+pygame.init()
+
+
initialize all imported pygame modules
+
init() -> (numpass, numfail)
+
+

Initialize all imported pygame modules. No exceptions will be raised if a +module fails, but the total number if successful and failed inits will be +returned as a tuple. You can always initialize individual modules manually, +but pygame.init()initialize all imported pygame modules is a convenient way to get everything started. The +init() functions for individual modules will raise exceptions when they +fail.

+

You may want to initialize the different modules separately to speed up your +program or to not use modules your game does not require.

+

It is safe to call this init() more than once as repeated calls will have +no effect. This is true even if you have pygame.quit() all the modules.

+
+ +
+
+pygame.quit()
+
+
uninitialize all pygame modules
+
quit() -> None
+
+

Uninitialize all pygame modules that have previously been initialized. When +the Python interpreter shuts down, this method is called regardless, so your +program should not need it, except when it wants to terminate its pygame +resources and continue. It is safe to call this function more than once as +repeated calls have no effect.

+
+

Note

+

Calling pygame.quit()uninitialize all pygame modules will not exit your program. Consider letting +your program end in the same way a normal Python program will end.

+
+
+ +
+
+pygame.get_init()
+
+
returns True if pygame is currently initialized
+
get_init() -> bool
+
+

Returns True if pygame is currently initialized.

+
+

New in pygame 1.9.5.

+
+
+ +
+
+exception pygame.error
+
+
standard pygame exception
+
raise pygame.error(message)
+
+

This exception is raised whenever a pygame or SDL operation fails. You +can catch any anticipated problems and deal with the error. The exception is +always raised with a descriptive message about the problem.

+

Derived from the RuntimeError exception, which can also be used to catch +these raised errors.

+
+ +
+
+pygame.get_error()
+
+
get the current error message
+
get_error() -> errorstr
+
+

SDL maintains an internal error message. This message will usually be +given to you when pygame.error()standard pygame exception is raised, so this function will +rarely be needed.

+
+ +
+
+pygame.set_error()
+
+
set the current error message
+
set_error(error_msg) -> None
+
+

SDL maintains an internal error message. This message will usually be +given to you when pygame.error()standard pygame exception is raised, so this function will +rarely be needed.

+
+ +
+
+pygame.get_sdl_version()
+
+
get the version number of SDL
+
get_sdl_version() -> major, minor, patch
+
+

Returns the three version numbers of the SDL library. This version is built +at compile time. It can be used to detect which features may or may not be +available through pygame.

+
+

New in pygame 1.7.0.

+
+
+ +
+
+pygame.get_sdl_byteorder()
+
+
get the byte order of SDL
+
get_sdl_byteorder() -> int
+
+

Returns the byte order of the SDL library. It returns 1234 for little +endian byte order and 4321 for big endian byte order.

+
+

New in pygame 1.8.

+
+
+ +
+
+pygame.register_quit()
+
+
register a function to be called when pygame quits
+
register_quit(callable) -> None
+
+

When pygame.quit()uninitialize all pygame modules is called, all registered quit functions are +called. Pygame modules do this automatically when they are initializing, so +this function will rarely be needed.

+
+ +
+
+pygame.encode_string()
+
+
Encode a Unicode or bytes object
+
encode_string([obj [, encoding [, errors [, etype]]]]) -> bytes or None
+
+

obj: If Unicode, encode; if bytes, return unaltered; if anything else, +return None; if not given, raise SyntaxError.

+

encoding (string): If present, encoding to use. The default is +'unicode_escape'.

+

errors (string): If given, how to handle unencodable characters. The default +is 'backslashreplace'.

+

etype (exception type): If given, the exception type to raise for an +encoding error. The default is UnicodeEncodeError, as returned by +PyUnicode_AsEncodedString(). For the default encoding and errors values +there should be no encoding errors.

+

This function is used in encoding file paths. Keyword arguments are +supported.

+
+

New in pygame 1.9.2: (primarily for use in unit tests)

+
+
+ +
+
+pygame.encode_file_path()
+
+
Encode a Unicode or bytes object as a file system path
+
encode_file_path([obj [, etype]]) -> bytes or None
+
+

obj: If Unicode, encode; if bytes, return unaltered; if anything else, +return None; if not given, raise SyntaxError.

+

etype (exception type): If given, the exception type to raise for an +encoding error. The default is UnicodeEncodeError, as returned by +PyUnicode_AsEncodedString().

+

This function is used to encode file paths in pygame. Encoding is to the +codec as returned by sys.getfilesystemencoding(). Keyword arguments are +supported.

+
+

New in pygame 1.9.2: (primarily for use in unit tests)

+
+
+ +
+ +
+
+
+
+pygame.version
+
+
small module containing version information
+
+ +++++ + + + + + + + + + + + + + + + + + + +
+version number as a string
+tupled integers of the version
+repository revision of the build
+tupled integers of the SDL library version
+

This module is automatically imported into the pygame package and can be used to +check which version of pygame has been imported.

+
+
+pygame.version.ver
+
+
version number as a string
+
ver = '1.2'
+
+

This is the version represented as a string. It can contain a micro release +number as well, e.g. '1.5.2'

+
+ +
+
+pygame.version.vernum
+
+
tupled integers of the version
+
vernum = (1, 5, 3)
+
+

This version information can easily be compared with other version +numbers of the same format. An example of checking pygame version numbers +would look like this:

+
if pygame.version.vernum < (1, 5):
+    print('Warning, older version of pygame (%s)' %  pygame.version.ver)
+    disable_advanced_features = True
+
+
+
+

New in pygame 1.9.6: Attributes major, minor, and patch.

+
+
vernum.major == vernum[0]
+vernum.minor == vernum[1]
+vernum.patch == vernum[2]
+
+
+
+

Changed in pygame 1.9.6: str(pygame.version.vernum) returns a string like "2.0.0" instead +of "(2, 0, 0)".

+
+
+

Changed in pygame 1.9.6: repr(pygame.version.vernum) returns a string like +"PygameVersion(major=2, minor=0, patch=0)" instead of "(2, 0, 0)".

+
+
+ +
+
+pygame.version.rev
+
+
repository revision of the build
+
rev = 'a6f89747b551+'
+
+

The Mercurial node identifier of the repository checkout from which this +package was built. If the identifier ends with a plus sign '+' then the +package contains uncommitted changes. Please include this revision number +in bug reports, especially for non-release pygame builds.

+

Important note: pygame development has moved to github, this variable is +obsolete now. As soon as development shifted to github, this variable started +returning an empty string "". +It has always been returning an empty string since v1.9.5.

+
+

Changed in pygame 1.9.5: Always returns an empty string "".

+
+
+ +
+
+pygame.version.SDL
+
+
tupled integers of the SDL library version
+
SDL = '(2, 0, 12)'
+
+

This is the SDL library version represented as an extended tuple. It also has +attributes 'major', 'minor' & 'patch' that can be accessed like this:

+
>>> pygame.version.SDL.major
+2
+
+
+

printing the whole thing returns a string like this:

+
>>> pygame.version.SDL
+SDLVersion(major=2, minor=0, patch=12)
+
+
+
+

New in pygame 2.0.0.

+
+
+ +

Setting Environment Variables

+

Some aspects of pygame's behaviour can be controlled by setting environment variables, they cover a wide +range of the library's functionality. Some of the variables are from pygame itself, while others come from +the underlying C SDL library that pygame uses.

+

In python, environment variables are usually set in code like this:

+
import os
+os.environ['NAME_OF_ENVIRONMENT_VARIABLE'] = 'value_to_set'
+
+
+

Or to preserve users ability to override the variable:

+
import os
+os.environ['ENV_VAR'] = os.environ.get('ENV_VAR', 'value')
+
+
+

If the variable is more useful for users of an app to set than the developer then they can set it like this:

+

Windows:

+
set NAME_OF_ENVIRONMENT_VARIABLE=value_to_set
+python my_application.py
+
+
+

Linux/Mac:

+
ENV_VAR=value python my_application.py
+
+
+

For some variables they need to be set before initialising pygame, some must be set before even importing pygame, +and others can simply be set right before the area of code they control is run.

+

Below is a list of environment variables, their settable values, and a brief description of what they do.

+
+

+
+

Pygame Environment Variables

+

These variables are defined by pygame itself.

+
+

+
+
PYGAME_DISPLAY - Experimental (subject to change)
+Set index of the display to use, "0" is the default.
+
+
+

This sets the display where pygame will open its window +or screen. The value set here will be used if set before +calling pygame.display.set_mode()Initialize a window or screen for display, and as long as no +'display' parameter is passed into pygame.display.set_mode()Initialize a window or screen for display.

+
+

+
+
PYGAME_FORCE_SCALE -
+Set to "photo" or "default".
+
+
+

This forces set_mode() to use the SCALED display mode and, +if "photo" is set, makes the scaling use the slowest, but +highest quality anisotropic scaling algorithm, if it is +available. Must be set before calling pygame.display.set_mode()Initialize a window or screen for display.

+
+

+
+
PYGAME_BLEND_ALPHA_SDL2 - New in pygame 2.0.0
+Set to "1" to enable the SDL2 blitter.
+
+
+

This makes pygame use the SDL2 blitter for all alpha +blending. The SDL2 blitter is sometimes faster than +the default blitter but uses a different formula so +the final colours may differ. Must be set before +pygame.init()initialize all imported pygame modules is called.

+
+

+
+
PYGAME_HIDE_SUPPORT_PROMPT -
+Set to "1" to hide the prompt.
+
+
+

This stops the welcome message popping up in the +console that tells you which version of python, +pygame & SDL you are using. Must be set before +importing pygame.

+
+

+
+
PYGAME_FREETYPE -
+Set to "1" to enable.
+
+
+

This switches the pygame.font module to a pure +freetype implementation that bypasses SDL_ttf. +See the font module for why you might want to +do this. Must be set before importing pygame.

+
+

+
+
PYGAME_CAMERA -
+Set to "opencv" or "vidcapture"
+
+
+

Forces the library backend used in the camera +module, overriding the platform defaults. Must +be set before calling pygame.camera.init()Module init.

+

In pygame 2.0.3, backends can be set programmatically instead, and the old +OpenCV backend has been replaced with one on top of "opencv-python," rather +than the old "highgui" OpenCV port. Also, there is a new native Windows +backend available.

+
+

+

+
+

SDL Environment Variables

+

These variables are defined by SDL.

+

For documentation on the environment variables available in +pygame 1 try here. +For Pygame 2, some selected environment variables are listed below.

+
+

+
+
SDL_VIDEO_CENTERED -
+Set to "1" to enable centering the window.
+
+
+

This will make the pygame window open in the centre of the display. +Must be set before calling pygame.display.set_mode()Initialize a window or screen for display.

+
+

+
+
SDL_VIDEO_WINDOW_POS -
+Set to "x,y" to position the top left corner of the window.
+
+
+

This allows control over the placement of the pygame window within +the display. Must be set before calling pygame.display.set_mode()Initialize a window or screen for display.

+
+

+
+
SDL_VIDEODRIVER -
+Set to "drivername" to change the video driver used.
+
+
+

On some platforms there are multiple video drivers available and +this allows users to pick between them. More information is available +here. Must be set before +calling pygame.init()initialize all imported pygame modules or pygame.display.init()Initialize the display module.

+
+

+
+
SDL_AUDIODRIVER -
+Set to "drivername" to change the audio driver used.
+
+
+

On some platforms there are multiple audio drivers available and +this allows users to pick between them. More information is available +here. Must be set before +calling pygame.init()initialize all imported pygame modules or pygame.mixer.init()initialize the mixer module.

+
+

+
+
SDL_VIDEO_ALLOW_SCREENSAVER
+Set to "1" to allow screensavers while pygame apps are running.
+
+
+

By default pygame apps disable screensavers while +they are running. Setting this environment variable allows users or +developers to change that and make screensavers run again.

+
+

+
+
SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR
+Set to "0" to re-enable the compositor.
+
+
+

By default SDL tries to disable the X11 compositor for all pygame +apps. This is usually a good thing as it's faster, however if you +have an app which doesn't update every frame and are using linux +you may want to disable this bypass. The bypass has reported problems +on KDE linux. This variable is only used on x11/linux platforms.

+
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/rect.html b/venv/Lib/site-packages/pygame/docs/generated/ref/rect.html new file mode 100644 index 0000000..11c4188 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/rect.html @@ -0,0 +1,672 @@ + + + + + + + + + pygame.Rect — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.Rect
+
+
pygame object for storing rectangular coordinates
+
Rect(left, top, width, height) -> Rect
+
Rect((left, top), (width, height)) -> Rect
+
Rect(object) -> Rect
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+copy the rectangle
+moves the rectangle
+moves the rectangle, in place
+grow or shrink the rectangle size
+grow or shrink the rectangle size, in place
+sets the position and size of the rectangle
+moves the rectangle inside another
+moves the rectangle inside another, in place
+crops a rectangle inside another
+crops a line inside a rectangle
+joins two rectangles into one
+joins two rectangles into one, in place
+the union of many rectangles
+the union of many rectangles, in place
+resize and move a rectangle with aspect ratio
+correct negative sizes
+test if one rectangle is inside another
+test if a point is inside a rectangle
+test if two rectangles overlap
+test if one rectangle in a list intersects
+test if all rectangles in a list intersect
+test if one rectangle in a dictionary intersects
+test if all rectangles in a dictionary intersect
+

Pygame uses Rect objects to store and manipulate rectangular areas. A Rect +can be created from a combination of left, top, width, and height values. +Rects can also be created from python objects that are already a Rect or +have an attribute named "rect".

+

Any pygame function that requires a Rect argument also accepts any of these +values to construct a Rect. This makes it easier to create Rects on the fly +as arguments to functions.

+

The Rect functions that change the position or size of a Rect return a new +copy of the Rect with the affected changes. The original Rect is not +modified. Some methods have an alternate "in-place" version that returns +None but affects the original Rect. These "in-place" methods are denoted +with the "ip" suffix.

+

The Rect object has several virtual attributes which can be used to move and +align the Rect:

+
x,y
+top, left, bottom, right
+topleft, bottomleft, topright, bottomright
+midtop, midleft, midbottom, midright
+center, centerx, centery
+size, width, height
+w,h
+
+
+

All of these attributes can be assigned to:

+
rect1.right = 10
+rect2.center = (20,30)
+
+
+

Assigning to size, width or height changes the dimensions of the rectangle; +all other assignments move the rectangle without resizing it. Notice that +some attributes are integers and others are pairs of integers.

+

If a Rect has a nonzero width or height, it will return True for a +nonzero test. Some methods return a Rect with 0 size to represent an invalid +rectangle. A Rect with a 0 size will not collide when using collision +detection methods (e.g. collidepoint(), colliderect(), etc.).

+

The coordinates for Rect objects are all integers. The size values can be +programmed to have negative values, but these are considered illegal Rects +for most operations.

+

There are several collision tests between other rectangles. Most python +containers can be searched for collisions against a single Rect.

+

The area covered by a Rect does not include the right- and bottom-most edge +of pixels. If one Rect's bottom border is another Rect's top border (i.e., +rect1.bottom=rect2.top), the two meet exactly on the screen but do not +overlap, and rect1.colliderect(rect2) returns false.

+
+

New in pygame 1.9.2: The Rect class can be subclassed. Methods such as copy() and move() +will recognize this and return instances of the subclass. +However, the subclass's __init__() method is not called, +and __new__() is assumed to take no arguments. So these methods should be +overridden if any extra attributes need to be copied.

+
+
+
+copy()
+
+
copy the rectangle
+
copy() -> Rect
+
+

Returns a new rectangle having the same position and size as the original.

+

New in pygame 1.9

+
+ +
+
+move()
+
+
moves the rectangle
+
move(x, y) -> Rect
+
+

Returns a new rectangle that is moved by the given offset. The x and y +arguments can be any integer value, positive or negative.

+
+ +
+
+move_ip()
+
+
moves the rectangle, in place
+
move_ip(x, y) -> None
+
+

Same as the Rect.move() method, but operates in place.

+
+ +
+
+inflate()
+
+
grow or shrink the rectangle size
+
inflate(x, y) -> Rect
+
+

Returns a new rectangle with the size changed by the given offset. The +rectangle remains centered around its current center. Negative values +will shrink the rectangle. Note, uses integers, if the offset given is +too small(< 2 > -2), center will be off.

+
+ +
+
+inflate_ip()
+
+
grow or shrink the rectangle size, in place
+
inflate_ip(x, y) -> None
+
+

Same as the Rect.inflate() method, but operates in place.

+
+ +
+
+update()
+
+
sets the position and size of the rectangle
+
update(left, top, width, height) -> None
+
update((left, top), (width, height)) -> None
+
update(object) -> None
+
+

Sets the position and size of the rectangle, in place. See +parameters for pygame.Rect()pygame object for storing rectangular coordinates for the parameters of this function.

+
+

New in pygame 2.0.1.

+
+
+ +
+
+clamp()
+
+
moves the rectangle inside another
+
clamp(Rect) -> Rect
+
+

Returns a new rectangle that is moved to be completely inside the +argument Rect. If the rectangle is too large to fit inside, it is +centered inside the argument Rect, but its size is not changed.

+
+ +
+
+clamp_ip()
+
+
moves the rectangle inside another, in place
+
clamp_ip(Rect) -> None
+
+

Same as the Rect.clamp() method, but operates in place.

+
+ +
+
+clip()
+
+
crops a rectangle inside another
+
clip(Rect) -> Rect
+
+

Returns a new rectangle that is cropped to be completely inside the +argument Rect. If the two rectangles do not overlap to begin with, a Rect +with 0 size is returned.

+
+ +
+
+clipline()
+
+
crops a line inside a rectangle
+
clipline(x1, y1, x2, y2) -> ((cx1, cy1), (cx2, cy2))
+
clipline(x1, y1, x2, y2) -> ()
+
clipline((x1, y1), (x2, y2)) -> ((cx1, cy1), (cx2, cy2))
+
clipline((x1, y1), (x2, y2)) -> ()
+
clipline((x1, y1, x2, y2)) -> ((cx1, cy1), (cx2, cy2))
+
clipline((x1, y1, x2, y2)) -> ()
+
clipline(((x1, y1), (x2, y2))) -> ((cx1, cy1), (cx2, cy2))
+
clipline(((x1, y1), (x2, y2))) -> ()
+
+

Returns the coordinates of a line that is cropped to be completely inside +the rectangle. If the line does not overlap the rectangle, then an empty +tuple is returned.

+

The line to crop can be any of the following formats (floats can be used +in place of ints, but they will be truncated):

+
+
    +
  • four ints

  • +
  • 2 lists/tuples/Vector2s of 2 ints

  • +
  • a list/tuple of four ints

  • +
  • a list/tuple of 2 lists/tuples/Vector2s of 2 ints

  • +
+
+
+
Returns
+

a tuple with the coordinates of the given line cropped to be +completely inside the rectangle is returned, if the given line does +not overlap the rectangle, an empty tuple is returned

+
+
Return type
+

tuple(tuple(int, int), tuple(int, int)) or ()

+
+
Raises
+

TypeError -- if the line coordinates are not given as one of the +above described line formats

+
+
+
+

Note

+

This method can be used for collision detection between a rect and a +line. See example code below.

+
+
+

Note

+

The rect.bottom and rect.right attributes of a +pygame.Rectpygame object for storing rectangular coordinates always lie one pixel outside of its actual border.

+
+
# Example using clipline().
+clipped_line = rect.clipline(line)
+
+if clipped_line:
+    # If clipped_line is not an empty tuple then the line
+    # collides/overlaps with the rect. The returned value contains
+    # the endpoints of the clipped line.
+    start, end = clipped_line
+    x1, y1 = start
+    x2, y2 = end
+else:
+    print("No clipping. The line is fully outside the rect.")
+
+
+
+

New in pygame 2.0.0.

+
+
+ +
+
+union()
+
+
joins two rectangles into one
+
union(Rect) -> Rect
+
+

Returns a new rectangle that completely covers the area of the two +provided rectangles. There may be area inside the new Rect that is not +covered by the originals.

+
+ +
+
+union_ip()
+
+
joins two rectangles into one, in place
+
union_ip(Rect) -> None
+
+

Same as the Rect.union() method, but operates in place.

+
+ +
+
+unionall()
+
+
the union of many rectangles
+
unionall(Rect_sequence) -> Rect
+
+

Returns the union of one rectangle with a sequence of many rectangles.

+
+ +
+
+unionall_ip()
+
+
the union of many rectangles, in place
+
unionall_ip(Rect_sequence) -> None
+
+

The same as the Rect.unionall() method, but operates in place.

+
+ +
+
+fit()
+
+
resize and move a rectangle with aspect ratio
+
fit(Rect) -> Rect
+
+

Returns a new rectangle that is moved and resized to fit another. The +aspect ratio of the original Rect is preserved, so the new rectangle may +be smaller than the target in either width or height.

+
+ +
+
+normalize()
+
+
correct negative sizes
+
normalize() -> None
+
+

This will flip the width or height of a rectangle if it has a negative +size. The rectangle will remain in the same place, with only the sides +swapped.

+
+ +
+
+contains()
+
+
test if one rectangle is inside another
+
contains(Rect) -> bool
+
+

Returns true when the argument is completely inside the Rect.

+
+ +
+
+collidepoint()
+
+
test if a point is inside a rectangle
+
collidepoint(x, y) -> bool
+
collidepoint((x,y)) -> bool
+
+

Returns true if the given point is inside the rectangle. A point along +the right or bottom edge is not considered to be inside the rectangle.

+
+

Note

+

For collision detection between a rect and a line the clipline() +method can be used.

+
+
+ +
+
+colliderect()
+
+
test if two rectangles overlap
+
colliderect(Rect) -> bool
+
+

Returns true if any portion of either rectangle overlap (except the +top+bottom or left+right edges).

+
+

Note

+

For collision detection between a rect and a line the clipline() +method can be used.

+
+
+ +
+
+collidelist()
+
+
test if one rectangle in a list intersects
+
collidelist(list) -> index
+
+

Test whether the rectangle collides with any in a sequence of rectangles. +The index of the first collision found is returned. If no collisions are +found an index of -1 is returned.

+
+ +
+
+collidelistall()
+
+
test if all rectangles in a list intersect
+
collidelistall(list) -> indices
+
+

Returns a list of all the indices that contain rectangles that collide +with the Rect. If no intersecting rectangles are found, an empty list is +returned.

+
+ +
+
+collidedict()
+
+
test if one rectangle in a dictionary intersects
+
collidedict(dict) -> (key, value)
+
collidedict(dict) -> None
+
collidedict(dict, use_values=0) -> (key, value)
+
collidedict(dict, use_values=0) -> None
+
+

Returns the first key and value pair that intersects with the calling +Rect object. If no collisions are found, None is returned. If +use_values is 0 (default) then the dict's keys will be used in the +collision detection, otherwise the dict's values will be used.

+
+

Note

+

Rect objects cannot be used as keys in a dictionary (they are not +hashable), so they must be converted to a tuple. +e.g. rect.collidedict({tuple(key_rect) : value})

+
+
+ +
+
+collidedictall()
+
+
test if all rectangles in a dictionary intersect
+
collidedictall(dict) -> [(key, value), ...]
+
collidedictall(dict, use_values=0) -> [(key, value), ...]
+
+

Returns a list of all the key and value pairs that intersect with the +calling Rect object. If no collisions are found an empty list is returned. +If use_values is 0 (default) then the dict's keys will be used in the +collision detection, otherwise the dict's values will be used.

+
+

Note

+

Rect objects cannot be used as keys in a dictionary (they are not +hashable), so they must be converted to a tuple. +e.g. rect.collidedictall({tuple(key_rect) : value})

+
+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/scrap.html b/venv/Lib/site-packages/pygame/docs/generated/ref/scrap.html new file mode 100644 index 0000000..96c7eec --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/scrap.html @@ -0,0 +1,458 @@ + + + + + + + + + pygame.scrap — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.scrap
+
+
pygame module for clipboard support.
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Initializes the scrap module.
+Returns True if the scrap module is currently initialized.
+Gets the data for the specified type from the clipboard.
+Gets a list of the available clipboard types.
+Places data into the clipboard.
+Checks whether data for a given type is available in the clipboard.
+Indicates if the clipboard ownership has been lost by the pygame application.
+Sets the clipboard access mode.
+

EXPERIMENTAL!: This API may change or disappear in later pygame releases. If +you use this, your code may break with the next pygame release.

+

The scrap module is for transferring data to/from the clipboard. This allows +for cutting and pasting data between pygame and other applications. Some basic +data (MIME) types are defined and registered:

+
 pygame         string
+constant        value        description
+--------------------------------------------------
+SCRAP_TEXT   "text/plain"    plain text
+SCRAP_BMP    "image/bmp"     BMP encoded image data
+SCRAP_PBM    "image/pbm"     PBM encoded image data
+SCRAP_PPM    "image/ppm"     PPM encoded image data
+
+
+

pygame.SCRAP_PPM, pygame.SCRAP_PBM and pygame.SCRAP_BMP are +suitable for surface buffers to be shared with other applications. +pygame.SCRAP_TEXT is an alias for the plain text clipboard type.

+

Depending on the platform, additional types are automatically registered when +data is placed into the clipboard to guarantee a consistent sharing behaviour +with other applications. The following listed types can be used as strings to +be passed to the respective pygame.scrappygame module for clipboard support. module functions.

+

For Windows platforms, these additional types are supported automatically +and resolve to their internal definitions:

+
"text/plain;charset=utf-8"   UTF-8 encoded text
+"audio/wav"                  WAV encoded audio
+"image/tiff"                 TIFF encoded image data
+
+
+

For X11 platforms, these additional types are supported automatically and +resolve to their internal definitions:

+
"text/plain;charset=utf-8"   UTF-8 encoded text
+"UTF8_STRING"                UTF-8 encoded text
+"COMPOUND_TEXT"              COMPOUND text
+
+
+

User defined types can be used, but the data might not be accessible by other +applications unless they know what data type to look for. +Example: Data placed into the clipboard by +pygame.scrap.put("my_data_type", byte_data) can only be accessed by +applications which query the clipboard for the "my_data_type" data type.

+

For an example of how the scrap module works refer to the examples page +(pygame.examples.scrap_clipboard.main()access the clipboard) or the code directly in GitHub +(pygame/examples/scrap_clipboard.py).

+
+

New in pygame 1.8.

+
+
+

Note

+

The scrap module is currently only supported for Windows, X11 and Mac OS X. +On Mac OS X only text works at the moment - other types may be supported in +future releases.

+
+
+
+pygame.scrap.init()
+
+
Initializes the scrap module.
+
init() -> None
+
+

Initialize the scrap module.

+
+
Raises
+

pygame.errorstandard pygame exception -- if unable to initialize scrap module

+
+
+
+

Note

+

The scrap module requires pygame.display.set_mode()Initialize a window or screen for display be +called before being initialized.

+
+
+ +
+
+pygame.scrap.get_init()
+
+
Returns True if the scrap module is currently initialized.
+
get_init() -> bool
+
+

Gets the scrap module's initialization state.

+
+
Returns
+

True if the pygame.scrappygame module for clipboard support. module is currently +initialized, False otherwise

+
+
Return type
+

bool

+
+
+
+

New in pygame 1.9.5.

+
+
+ +
+
+pygame.scrap.get()
+
+
Gets the data for the specified type from the clipboard.
+
get(type) -> bytes | None
+
+

Retrieves the data for the specified type from the clipboard. The data is +returned as a byte string and might need further processing (such as +decoding to Unicode).

+
+
Parameters
+

type (string) -- data type to retrieve from the clipboard

+
+
Returns
+

data (bytes object) for the given type identifier or None if +no data for the given type is available

+
+
Return type
+

bytes | None

+
+
+
text = pygame.scrap.get(pygame.SCRAP_TEXT)
+if text:
+    print("There is text in the clipboard.")
+else:
+    print("There does not seem to be text in the clipboard.")
+
+
+
+ +
+
+pygame.scrap.get_types()
+
+
Gets a list of the available clipboard types.
+
get_types() -> list
+
+

Gets a list of data type string identifiers for the data currently +available on the clipboard. Each identifier can be used in the +pygame.scrap.get()Gets the data for the specified type from the clipboard. method to get the clipboard content of the +specific type.

+
+
Returns
+

list of strings of the available clipboard data types, if there +is no data in the clipboard an empty list is returned

+
+
Return type
+

list

+
+
+
for t in pygame.scrap.get_types():
+    if "text" in t:
+        # There is some content with the word "text" in its type string.
+        print(pygame.scrap.get(t))
+
+
+
+ +
+
+pygame.scrap.put()
+
+
Places data into the clipboard.
+
put(type, data) -> None
+
+

Places data for a given clipboard type into the clipboard. The data must +be a string buffer. The type is a string identifying the type of data to be +placed into the clipboard. This can be one of the predefined +pygame.SCRAP_PBM, pygame.SCRAP_PPM, pygame.SCRAP_BMP or +pygame.SCRAP_TEXT values or a user defined string identifier.

+
+
Parameters
+
    +
  • type (string) -- type identifier of the data to be placed into the +clipboard

  • +
  • data (bytes) -- data to be place into the clipboard, a bytes object

  • +
+
+
Raises
+

pygame.errorstandard pygame exception -- if unable to put the data into the clipboard

+
+
+
with open("example.bmp", "rb") as fp:
+    pygame.scrap.put(pygame.SCRAP_BMP, fp.read())
+# The image data is now on the clipboard for other applications to access
+# it.
+pygame.scrap.put(pygame.SCRAP_TEXT, b"A text to copy")
+pygame.scrap.put("Plain text", b"Data for user defined type 'Plain text'")
+
+
+
+ +
+
+pygame.scrap.contains()
+
+
Checks whether data for a given type is available in the clipboard.
+
contains(type) -> bool
+
+

Checks whether data for the given type is currently available in the +clipboard.

+
+
Parameters
+

type (string) -- data type to check availability of

+
+
Returns
+

True if data for the passed type is available in the +clipboard, False otherwise

+
+
Return type
+

bool

+
+
+
if pygame.scrap.contains(pygame.SCRAP_TEXT):
+    print("There is text in the clipboard.")
+if pygame.scrap.contains("own_data_type"):
+    print("There is stuff in the clipboard.")
+
+
+
+ +
+
+pygame.scrap.lost()
+
+
Indicates if the clipboard ownership has been lost by the pygame application.
+
lost() -> bool
+
+

Indicates if the clipboard ownership has been lost by the pygame +application.

+
+
Returns
+

True, if the clipboard ownership has been lost by the pygame +application, False if the pygame application still owns the clipboard

+
+
Return type
+

bool

+
+
+
if pygame.scrap.lost():
+    print("The clipboard is in use by another application.")
+
+
+
+ +
+
+pygame.scrap.set_mode()
+
+
Sets the clipboard access mode.
+
set_mode(mode) -> None
+
+

Sets the access mode for the clipboard. This is only of interest for X11 +environments where clipboard modes pygame.SCRAP_SELECTION (for mouse +selections) and pygame.SCRAP_CLIPBOARD (for the clipboard) are +available. Setting the mode to pygame.SCRAP_SELECTION in other +environments will not change the mode from pygame.SCRAP_CLIPBOARD.

+
+
Parameters
+

mode -- access mode, supported values are pygame.SCRAP_CLIPBOARD +and pygame.SCRAP_SELECTION (pygame.SCRAP_SELECTION only has an +effect when used on X11 platforms)

+
+
Raises
+

ValueError -- if the mode parameter is not +pygame.SCRAP_CLIPBOARD or pygame.SCRAP_SELECTION

+
+
+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/sdl2_controller.html b/venv/Lib/site-packages/pygame/docs/generated/ref/sdl2_controller.html new file mode 100644 index 0000000..a62ed46 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/sdl2_controller.html @@ -0,0 +1,569 @@ + + + + + + + + + pygame._sdl2.controller — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame._sdl2.controller
+
+
Pygame module to work with controllers.
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+initialize the controller module
+Uninitialize the controller module.
+Returns True if the controller module is initialized.
+Sets the current state of events related to controllers
+Gets the current state of events related to controllers
+Get the number of joysticks connected
+Check if the given joystick is supported by the game controller interface
+Get the name of the contoller
+Create a new Controller object.
+

This module offers control over common controller types like the dualshock 4 or +the xbox 360 controllers: They have two analog sticks, two triggers, two shoulder buttons, +a dpad, 4 buttons on the side, 2 (or 3) buttons in the middle.

+

Pygame uses xbox controllers naming conventions (like a, b, x, y for buttons) but +they always refer to the same buttons. For example CONTROLLER_BUTTON_X is +always the leftmost button of the 4 buttons on the right.

+

Controllers can generate the following events:

+
CONTROLLERAXISMOTION, CONTROLLERBUTTONDOWN, CONTROLLERBUTTONUP,
+CONTROLLERDEVICEREMAPPED, CONTROLLERDEVICEADDED, CONTROLLERDEVICEREMOVED
+
+
+

Additionally if pygame is built with SDL 2.0.14 or higher the following events can also be generated +(to get the version of sdl pygame is built with use pygame.version.SDL()tupled integers of the SDL library version):

+
CONTROLLERTOUCHPADDOWN, CONTROLLERTOUCHPADMOTION, CONTROLLERTOUCHPADUP
+
+
+

These events can be enabled/disabled by pygame._sdl2.controller.set_eventstate()Sets the current state of events related to controllers +Note that controllers can generate joystick events as well. This function only toggles +events related to controllers.

+
+

Note

+

See the pygame.joystickPygame module for interacting with joysticks, gamepads, and trackballs. for a more versatile but more advanced api.

+
+
+

New in pygame 2: This module requires SDL2.

+
+
+
+pygame._sdl2.controller.init()
+
+
initialize the controller module
+
init() -> None
+
+

Initialize the controller module.

+
+ +
+
+pygame._sdl2.controller.quit()
+
+
Uninitialize the controller module.
+
quit() -> None
+
+

Uninitialize the controller module.

+
+ +
+
+pygame._sdl2.controller.get_init()
+
+
Returns True if the controller module is initialized.
+
get_init() -> bool
+
+

Test if pygame._sdl2.controller.init() was called.

+
+
+
+ +
+
+pygame._sdl2.controller.set_eventstate()
+
+
Sets the current state of events related to controllers
+
set_eventstate(state) -> None
+
+

Enable or disable events connected to controllers.

+
+

Note

+

Controllers can still generate joystick events, which will not be toggled by this function.

+
+
+

Changed in pygame 2.0.2:: Changed return type from int to None

+
+
+ +
+
+pygame._sdl2.controller.get_eventstate()
+
+
Gets the current state of events related to controllers
+
get_eventstate() -> bool
+
+

Returns the current state of events related to controllers, True meaning +events will be posted.

+
+

New in pygame 2.0.2.

+
+
+ +
+
+pygame._sdl2.controller.get_count()
+
+
Get the number of joysticks connected
+
get_count() -> int
+
+

Get the number of joysticks connected.

+
+ +
+
+pygame._sdl2.controller.is_controller()
+
+
Check if the given joystick is supported by the game controller interface
+
is_controller(index) -> bool
+
+

Returns True if the index given can be used to create a controller object.

+
+ +
+
+pygame._sdl2.controller.name_forindex()
+
+
Get the name of the contoller
+
name_forindex(index) -> name or None
+
+

Returns the name of controller, or None if there's no name or the +index is invalid.

+
+ +
+
+pygame._sdl2.controller.Controller
+
+
+
Create a new Controller object.
+
Controller(index) -> Controller
+
+

Create a new Controller object. Index should be integer between +0 and pygame._sdl2.contoller.get_count(). Controllers also +can be created from a pygame.joystick.Joystick using +pygame._sdl2.controller.from_joystick. Controllers are +initialized on creation.

+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+uninitialize the Controller
+check if the Controller is initialized
+Create a Controller from a pygame.joystick.Joystick object
+Check if the Controller has been opened and is currently connected.
+Returns a pygame.joystick.Joystick() object
+Get the current state of a joystick axis
+Get the current state of a button
+Get the mapping assigned to the controller
+Assign a mapping to the controller
+Start a rumbling effect
+Stop any rumble effect playing
+
+
+quit()
+
+
uninitialize the Controller
+
quit() -> None
+
+

Close a Controller object. After this the pygame event queue will no longer +receive events from the device.

+

It is safe to call this more than once.

+
+ +
+
+get_init()
+
+
check if the Controller is initialized
+
get_init() -> bool
+
+

Returns True if the Controller object is currently initialised.

+
+ +
+
+static from_joystick()
+
+
Create a Controller from a pygame.joystick.Joystick object
+
from_joystick(joystick) -> Controller
+
+

Create a Controller object from a pygame.joystick.Joystick object

+
+ +
+
+attached()
+
+
Check if the Controller has been opened and is currently connected.
+
attached() -> bool
+
+

Returns True if the Controller object is opened and connected.

+
+ +
+
+as_joystick()
+
+
Returns a pygame.joystick.Joystick() object
+
as_joystick() -> Joystick object
+
+

Returns a pygame.joystick.Joystick() object created from this controller's index

+
+ +
+
+get_axis()
+
+
Get the current state of a joystick axis
+
get_axis(axis) -> int
+
+

Get the current state of a trigger or joystick axis. +The axis argument must be one of the following constants:

+
CONTROLLER_AXIS_LEFTX, CONTROLLER_AXIS_LEFTY,
+CONTROLLER_AXIS_RIGHTX, CONTROLLER_AXIS_RIGHTY,
+CONTROLLER_AXIS_TRIGGERLEFT, CONTROLLER_AXIS_TRIGGERRIGHT
+
+
+

Joysticks can return a value between -32768 and 32767. Triggers however +can only return a value between 0 and 32768.

+
+ +
+
+get_button()
+
+
Get the current state of a button
+
get_button(button) -> bool
+
+

Get the current state of a button, True meaning it is pressed down. +The button argument must be one of the following constants:

+
CONTROLLER_BUTTON_A, CONTROLLER_BUTTON_B,
+CONTROLLER_BUTTON_X, CONTROLLER_BUTTON_Y
+CONTROLLER_BUTTON_DPAD_UP, CONTROLLER_BUTTON_DPAD_DOWN,
+CONTROLLER_BUTTON_DPAD_LEFT, CONTROLLER_BUTTON_DPAD_RIGHT,
+CONTROLLER_BUTTON_LEFTSHOULDER, CONTROLLER_BUTTON_RIGHTSHOULDER,
+CONTROLLER_BUTTON_LEFTSTICK, CONTROLLER_BUTTON_RIGHTSTICK,
+CONTROLLER_BUTTON_BACK, CONTROLLER_BUTTON_GUIDE,
+CONTROLLER_BUTTON_START
+
+
+
+ +
+
+get_mapping()
+
+
Get the mapping assigned to the controller
+
get_mapping() -> mapping
+
+

Returns a dict containing the mapping of the Controller. For more +information see Controller.set_mapping()

+
+

Changed in pygame 2.0.2:: Return type changed from str to dict

+
+
+ +
+
+set_mapping()
+
+
Assign a mapping to the controller
+
set_mapping(mapping) -> int
+
+

Rebind buttons, axes, triggers and dpads. The mapping should be a +dict containing all buttons, hats and axes. The easiest way to get this +is to use the dict returned by Controller.get_mapping(). To edit +this mapping assign a value to the original button. The value of the +dictionary must be a button, hat or axis represented in the following way:

+
    +
  • For a button use: bX where X is the index of the button.

  • +
  • For a hat use: hX.Y where X is the index and the Y is the direction (up: 1, right: 2, down: 3, left: 4).

  • +
  • For an axis use: aX where x is the index of the axis.

  • +
+

An example of mapping:

+
mapping = controller.get_mapping() # Get current mapping
+mapping["a"] = "b3" # Remap button a to y
+mapping["y"] = "b0" # Remap button y to a
+controller.set_mapping(mapping) # Set the mapping
+
+
+

The function will return 1 if a new mapping is added or 0 if an existing one is updated.

+
+

Changed in pygame 2.0.2:: Renamed from add_mapping to set_mapping

+
+
+

Changed in pygame 2.0.2:: Argument type changed from str to dict

+
+
+ +
+
+rumble()
+
+
Start a rumbling effect
+
rumble(low_frequency, high_frequency, duration) -> bool
+
+

Start a rumble effect on the controller, with the specified strength ranging +from 0 to 1. Duration is length of the effect, in ms. Setting the duration +to 0 will play the effect until another one overwrites it or +Controller.stop_rumble() is called. If an effect is already +playing, then it will be overwritten.

+

Returns True if the rumble was played successfully or False if the +controller does not support it or pygame.version.SDL()tupled integers of the SDL library version is below 2.0.9.

+
+

New in pygame 2.0.2.

+
+
+ +
+
+stop_rumble()
+
+
Stop any rumble effect playing
+
stop_rumble() -> None
+
+

Stops any rumble effect playing on the controller. See +Controller.rumble() for more information.

+
+

New in pygame 2.0.2.

+
+
+ +
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/sdl2_video.html b/venv/Lib/site-packages/pygame/docs/generated/ref/sdl2_video.html new file mode 100644 index 0000000..7968b16 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/sdl2_video.html @@ -0,0 +1,1091 @@ + + + + + + + + + pygame.sdl2_video — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.sdl2_video
+
+

Warning

+

This module isn't ready for prime time yet, it's still in development. +These docs are primarily meant to help the pygame developers and super-early adopters +who are in communication with the developers. This API will change.

+
+ +++++ + + + + + + + + + + + + + + + + + + +
+pygame object that represents a window
+pygame object that representing a Texture.
+Easy way to use a portion of a Texture without worrying about srcrect all the time.
+Create a 2D rendering context for a window.
+
+
Experimental pygame module for porting new SDL video systems
+
+
+
+pygame._sdl2.video.Window
+
+
pygame object that represents a window
+
Window(title="pygame", size=(640, 480), position=None, fullscreen=False, fullscreen_desktop=False, keywords) -> Window
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Creates window using window created by pygame.display.set_mode().
+Gets or sets whether the mouse is confined to the window.
+Gets or sets the window's relative mouse motion state.
+Enable windowed mode (exit fullscreen).
+Enter fullscreen.
+Gets or sets whether the window title.
+Destroys the window.
+Hide the window.
+Show the window.
+Raise the window above other windows and set the input focus. The "input_only" argument is only supported on X11.
+Restore the size and position of a minimized or maximized window.
+Maximize the window.
+Minimize the window.
+Gets and sets whether the window is resizable.
+Add or remove the border from the window.
+Set the icon for the window.
+Get the unique window ID. *Read-only*
+Gets and sets the window size.
+Gets and sets the window position.
+Gets and sets the window opacity. Between 0.0 (fully transparent) and 1.0 (fully opaque).
+Gets and sets the brightness (gamma multiplier) for the display that owns the window.
+Get the index of the display that owns the window. *Read-only*
+Set the window as a modal for a parent window. This function is only supported on X11.
+
+
+classmethod from_display_module()
+
+
Creates window using window created by pygame.display.set_mode().
+
from_display_module() -> Window
+
+
+ +
+
+grab
+
+
Gets or sets whether the mouse is confined to the window.
+
grab -> bool
+
+
+ +
+
+relative_mouse
+
+
Gets or sets the window's relative mouse motion state.
+
relative_mouse -> bool
+
+
+ +
+
+set_windowed()
+
+
Enable windowed mode (exit fullscreen).
+
set_windowed() -> None
+
+
+ +
+
+set_fullscreen()
+
+
Enter fullscreen.
+
set_fullscreen(desktop=False) -> None
+
+
+ +
+
+title
+
+
Gets or sets whether the window title.
+
title -> string
+
+
+ +
+
+destroy()
+
+
Destroys the window.
+
destroy() -> None
+
+
+ +
+
+hide()
+
+
Hide the window.
+
hide() -> None
+
+
+ +
+
+show()
+
+
Show the window.
+
show() -> None
+
+
+ +
+
+focus()
+
+
Raise the window above other windows and set the input focus. The "input_only" argument is only supported on X11.
+
focus(input_only=False) -> None
+
+
+ +
+
+restore()
+
+
Restore the size and position of a minimized or maximized window.
+
restore() -> None
+
+
+ +
+
+maximize()
+
+
Maximize the window.
+
maximize() -> None
+
+
+ +
+
+minimize()
+
+
Minimize the window.
+
maximize() -> None
+
+
+ +
+
+resizable
+
+
Gets and sets whether the window is resizable.
+
resizable -> bool
+
+
+ +
+
+borderless
+
+
Add or remove the border from the window.
+
borderless -> bool
+
+
+ +
+
+set_icon()
+
+
Set the icon for the window.
+
set_icon(surface) -> None
+
+
+ +
+
+id
+
+
Get the unique window ID. *Read-only*
+
id -> int
+
+
+ +
+
+size
+
+
Gets and sets the window size.
+
size -> (int, int)
+
+
+ +
+
+position
+
+
Gets and sets the window position.
+
position -> (int, int) or WINDOWPOS_CENTERED or WINDOWPOS_UNDEFINED
+
+
+ +
+
+opacity
+
+
Gets and sets the window opacity. Between 0.0 (fully transparent) and 1.0 (fully opaque).
+
opacity -> float
+
+
+ +
+
+brightness
+
+
Gets and sets the brightness (gamma multiplier) for the display that owns the window.
+
brightness -> float
+
+
+ +
+
+display_index
+
+
Get the index of the display that owns the window. *Read-only*
+
display_index -> int
+
+
+ +
+
+set_modal_for()
+
+
Set the window as a modal for a parent window. This function is only supported on X11.
+
set_modal_for(Window) -> None
+
+
+ +
+ +
+
+pygame._sdl2.video.Texture
+
+
pygame object that representing a Texture.
+
Texture(renderer, size, depth=0, static=False, streaming=False, target=False) -> Texture
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Create a texture from an existing surface.
+Gets the renderer associated with the Texture. *Read-only*
+Gets the width of the Texture. *Read-only*
+Gets the height of the Texture. *Read-only*
+Gets and sets an additional alpha value multiplied into render copy operations.
+Gets and sets the blend mode for the Texture.
+Gets and sets an additional color value multiplied into render copy operations.
+Get the rectangular area of the texture.
+Copy a portion of the texture to the rendering target.
+Update the texture with a Surface. WARNING: Slow operation, use sparingly.
+
+
+static from_surface()
+
+
Create a texture from an existing surface.
+
from_surface(renderer, surface) -> Texture
+
+
+ +
+
+renderer
+
+
Gets the renderer associated with the Texture. *Read-only*
+
renderer -> Renderer
+
+
+ +
+
+width
+
+
Gets the width of the Texture. *Read-only*
+
width -> int
+
+
+ +
+
+height
+
+
Gets the height of the Texture. *Read-only*
+
height -> int
+
+
+ +
+
+alpha
+
+
Gets and sets an additional alpha value multiplied into render copy operations.
+
alpha -> int
+
+
+ +
+
+blend_mode
+
+
Gets and sets the blend mode for the Texture.
+
blend_mode -> int
+
+
+ +
+
+color
+
+
Gets and sets an additional color value multiplied into render copy operations.
+
color -> color
+
+
+ +
+
+get_rect()
+
+
Get the rectangular area of the texture.
+
get_rect(**kwargs) -> Rect
+
+
+ +
+
+draw()
+
+
Copy a portion of the texture to the rendering target.
+
draw(srcrect=None, dstrect=None, angle=0, origin=None, flipX=False, flipY=False) -> None
+
+
+ +
+
+update()
+
+
Update the texture with a Surface. WARNING: Slow operation, use sparingly.
+
update(surface, area=None) -> None
+
+
+ +
+ +
+
+pygame._sdl2.video.Image
+
+
Easy way to use a portion of a Texture without worrying about srcrect all the time.
+
Image(textureOrImage, srcrect=None) -> Image
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Get the rectangular area of the Image.
+Copy a portion of the Image to the rendering target.
+Gets and sets the angle the Image draws itself with.
+Gets and sets the origin. Origin=None means the Image will be rotated around its center.
+Gets and sets whether the Image is flipped on the x axis.
+Gets and sets whether the Image is flipped on the y axis.
+Gets and sets the Image color modifier.
+Gets and sets the Image alpha modifier.
+Gets and sets the blend mode for the Image.
+Gets and sets the Texture the Image is based on.
+Gets and sets the Rect the Image is based on.
+
+
+get_rect()
+
+
Get the rectangular area of the Image.
+
get_rect() -> Rect
+
+
+ +
+
+draw()
+
+
Copy a portion of the Image to the rendering target.
+
draw(srcrect=None, dstrect=None) -> None
+
+
+ +
+
+angle
+
+
Gets and sets the angle the Image draws itself with.
+
angle -> float
+
+
+ +
+
+origin
+
+
Gets and sets the origin. Origin=None means the Image will be rotated around its center.
+
origin -> (float, float) or None.
+
+
+ +
+
+flipX
+
+
Gets and sets whether the Image is flipped on the x axis.
+
flipX -> bool
+
+
+ +
+
+flipY
+
+
Gets and sets whether the Image is flipped on the y axis.
+
flipY -> bool
+
+
+ +
+
+color
+
+
Gets and sets the Image color modifier.
+
color -> Color
+
+
+ +
+
+alpha
+
+
Gets and sets the Image alpha modifier.
+
alpha -> float
+
+
+ +
+
+blend_mode
+
+
Gets and sets the blend mode for the Image.
+
blend_mode -> int
+
+
+ +
+
+texture
+
+
Gets and sets the Texture the Image is based on.
+
texture -> Texture
+
+
+ +
+
+srcrect
+
+
Gets and sets the Rect the Image is based on.
+
srcrect -> Rect
+
+
+ +
+ +
+
+pygame._sdl2.video.Renderer
+
+
Create a 2D rendering context for a window.
+
Renderer(window, index=-1, accelerated=-1, vsync=False, target_texture=False) -> Renderer
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Easy way to create a Renderer.
+Gets and sets the blend mode used by the drawing functions.
+Gets and sets the color used by the drawing functions.
+Clear the current rendering target with the drawing color.
+Updates the screen with any new rendering since previous call.
+Returns the drawing area on the target.
+Set the drawing area on the target. If area is None, the entire target will be used.
+Gets and sets the logical size.
+Gets and sets the scale.
+Gets and sets the render target. None represents the default target (the renderer).
+For compatibility purposes. Textures created by different Renderers cannot be shared!
+Draws a line.
+Draws a point.
+Draws a rectangle.
+Fills a rectangle.
+Read pixels from current render target and create a pygame.Surface. WARNING: Slow operation, use sparingly.
+
+
+classmethod from_window()
+
+
Easy way to create a Renderer.
+
from_window(window) -> Renderer
+
+
+ +
+
+draw_blend_mode
+
+
Gets and sets the blend mode used by the drawing functions.
+
draw_blend_mode -> int
+
+
+ +
+
+draw_color
+
+
Gets and sets the color used by the drawing functions.
+
draw_color -> Color
+
+
+ +
+
+clear()
+
+
Clear the current rendering target with the drawing color.
+
clear() -> None
+
+
+ +
+
+present()
+
+
Updates the screen with any new rendering since previous call.
+
present() -> None
+
+
+ +
+
+get_viewport()
+
+
Returns the drawing area on the target.
+
get_viewport() -> Rect
+
+
+ +
+
+set_viewport()
+
+
Set the drawing area on the target. If area is None, the entire target will be used.
+
set_viewport(area) -> None
+
+
+ +
+
+logical_size
+
+
Gets and sets the logical size.
+
logical_size -> (int width, int height)
+
+
+ +
+
+scale
+
+
Gets and sets the scale.
+
scale -> (float x_scale, float y_scale)
+
+
+ +
+
+target
+
+
Gets and sets the render target. None represents the default target (the renderer).
+
target -> Texture or None
+
+
+ +
+
+blit()
+
+
For compatibility purposes. Textures created by different Renderers cannot be shared!
+
blit(soure, dest, area=None, special_flags=0)-> Rect
+
+
+ +
+
+draw_line()
+
+
Draws a line.
+
draw_line(p1, p2) -> None
+
+
+ +
+
+draw_point()
+
+
Draws a point.
+
draw_point(point) -> None
+
+
+ +
+
+draw_rect()
+
+
Draws a rectangle.
+
draw_rect(rect)-> None
+
+
+ +
+
+fill_rect()
+
+
Fills a rectangle.
+
fill_rect(rect)-> None
+
+
+ +
+
+to_surface()
+
+
Read pixels from current render target and create a pygame.Surface. WARNING: Slow operation, use sparingly.
+
to_surface(surface=None, area=None)-> Surface
+
+
+ +
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/sndarray.html b/venv/Lib/site-packages/pygame/docs/generated/ref/sndarray.html new file mode 100644 index 0000000..f12d6ee --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/sndarray.html @@ -0,0 +1,274 @@ + + + + + + + + + pygame.sndarray — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.sndarray
+
+
pygame module for accessing sound sample data
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+copy Sound samples into an array
+reference Sound samples into an array
+convert an array into a Sound object
+Sets the array system to be used for sound arrays
+Gets the currently active array type.
+Gets the array system types currently supported.
+

Functions to convert between NumPy arrays and Sound objects. This +module will only be functional when pygame can use the external NumPy +package. If NumPy can't be imported, surfarray becomes a MissingModule +object.

+

Sound data is made of thousands of samples per second, and each sample is the +amplitude of the wave at a particular moment in time. For example, in 22-kHz +format, element number 5 of the array is the amplitude of the wave after +5/22000 seconds.

+

The arrays are indexed by the X axis first, followed by the Y axis. +Each sample is an 8-bit or 16-bit integer, depending on the data format. A +stereo sound file has two values per sample, while a mono sound file only has +one.

+
+
+pygame.sndarray.array()
+
+
copy Sound samples into an array
+
array(Sound) -> array
+
+

Creates a new array for the sound data and copies the samples. The array +will always be in the format returned from pygame.mixer.get_init().

+
+ +
+
+pygame.sndarray.samples()
+
+
reference Sound samples into an array
+
samples(Sound) -> array
+
+

Creates a new array that directly references the samples in a Sound object. +Modifying the array will change the Sound. The array will always be in the +format returned from pygame.mixer.get_init().

+
+ +
+
+pygame.sndarray.make_sound()
+
+
convert an array into a Sound object
+
make_sound(array) -> Sound
+
+

Create a new playable Sound object from an array. The mixer module must be +initialized and the array format must be similar to the mixer audio format.

+
+ +
+
+pygame.sndarray.use_arraytype()
+
+
Sets the array system to be used for sound arrays
+
use_arraytype (arraytype) -> None
+
+

DEPRECATED: Uses the requested array type for the module functions. The +only supported arraytype is 'numpy'. Other values will raise ValueError. +Using this function will raise a DeprecationWarning. +.. ## pygame.sndarray.use_arraytype ##

+
+ +
+
+pygame.sndarray.get_arraytype()
+
+
Gets the currently active array type.
+
get_arraytype () -> str
+
+

DEPRECATED: Returns the currently active array type. This will be a value of the +get_arraytypes() tuple and indicates which type of array module is used +for the array creation. Using this function will raise a DeprecationWarning.

+
+

New in pygame 1.8.

+
+
+ +
+
+pygame.sndarray.get_arraytypes()
+
+
Gets the array system types currently supported.
+
get_arraytypes () -> tuple
+
+

DEPRECATED: Checks, which array systems are available and returns them as a tuple of +strings. The values of the tuple can be used directly in the +pygame.sndarray.use_arraytype()Sets the array system to be used for sound arrays () method. If no supported array +system could be found, None will be returned. Using this function will raise a +DeprecationWarning.

+
+

New in pygame 1.8.

+
+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/sprite.html b/venv/Lib/site-packages/pygame/docs/generated/ref/sprite.html new file mode 100644 index 0000000..653e292 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/sprite.html @@ -0,0 +1,1381 @@ + + + + + + + + + pygame.sprite — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.sprite
+
+
pygame module with basic game object classes
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Simple base class for visible game objects.
+A subclass of Sprite with more attributes and features.
+A container class to hold and manage multiple Sprite objects.
+Same as pygame.sprite.Group
+Same as pygame.sprite.Group
+Group sub-class that tracks dirty updates.
+RenderUpdates sub-class that draws Sprites in order of addition.
+LayeredUpdates is a sprite group that handles layers and draws like OrderedUpdates.
+LayeredDirty group is for DirtySprite objects. Subclasses LayeredUpdates.
+Group container that holds a single sprite.
+Find sprites in a group that intersect another sprite.
+Collision detection between two sprites, using rects.
+Collision detection between two sprites, using rects scaled to a ratio.
+Collision detection between two sprites, using circles.
+Collision detection between two sprites, using circles scaled to a ratio.
+Collision detection between two sprites, using masks.
+Find all sprites that collide between two groups.
+Simple test if a sprite intersects anything in a group.
+

This module contains several simple classes to be used within games. There is +the main Sprite class and several Group classes that contain Sprites. The use +of these classes is entirely optional when using pygame. The classes are fairly +lightweight and only provide a starting place for the code that is common to +most games.

+

The Sprite class is intended to be used as a base class for the different types +of objects in the game. There is also a base Group class that simply stores +sprites. A game could create new types of Group classes that operate on +specially customized Sprite instances they contain.

+

The basic Sprite class can draw the Sprites it contains to a Surface. The +Group.draw() method requires that each Sprite have a Surface.image +attribute and a Surface.rect. The Group.clear() method requires these +same attributes, and can be used to erase all the Sprites with background. +There are also more advanced Groups: pygame.sprite.RenderUpdates() and +pygame.sprite.OrderedUpdates().

+

Lastly, this module contains several collision functions. These help find +sprites inside multiple groups that have intersecting bounding rectangles. To +find the collisions, the Sprites are required to have a Surface.rect +attribute assigned.

+

The groups are designed for high efficiency in removing and adding Sprites to +them. They also allow cheap testing to see if a Sprite already exists in a +Group. A given Sprite can exist in any number of groups. A game could use some +groups to control object rendering, and a completely separate set of groups to +control interaction or player movement. Instead of adding type attributes or +bools to a derived Sprite class, consider keeping the Sprites inside organized +Groups. This will allow for easier lookup later in the game.

+

Sprites and Groups manage their relationships with the add() and +remove() methods. These methods can accept a single or multiple targets for +membership. The default initializers for these classes also takes a single or +list of targets for initial membership. It is safe to repeatedly add and remove +the same Sprite from a Group.

+

While it is possible to design sprite and group classes that don't derive from +the Sprite and AbstractGroup classes below, it is strongly recommended that you +extend those when you add a Sprite or Group class.

+

Sprites are not thread safe. So lock them yourself if using threads.

+
+
+pygame.sprite.Sprite
+
+
Simple base class for visible game objects.
+
Sprite(*groups) -> Sprite
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+method to control sprite behavior
+add the sprite to groups
+remove the sprite from groups
+remove the Sprite from all Groups
+does the sprite belong to any groups
+list of Groups that contain this Sprite
+

The base class for visible game objects. Derived classes will want to +override the Sprite.update() and assign a Sprite.image and +Sprite.rect attributes. The initializer can accept any number of Group +instances to be added to.

+

When subclassing the Sprite, be sure to call the base initializer before +adding the Sprite to Groups. For example:

+
class Block(pygame.sprite.Sprite):
+
+    # Constructor. Pass in the color of the block,
+    # and its x and y position
+    def __init__(self, color, width, height):
+       # Call the parent class (Sprite) constructor
+       pygame.sprite.Sprite.__init__(self)
+
+       # Create an image of the block, and fill it with a color.
+       # This could also be an image loaded from the disk.
+       self.image = pygame.Surface([width, height])
+       self.image.fill(color)
+
+       # Fetch the rectangle object that has the dimensions of the image
+       # Update the position of this object by setting the values of rect.x and rect.y
+       self.rect = self.image.get_rect()
+
+
+
+
+update()
+
+
method to control sprite behavior
+
update(*args, **kwargs) -> None
+
+

The default implementation of this method does nothing; it's just a +convenient "hook" that you can override. This method is called by +Group.update() with whatever arguments you give it.

+

There is no need to use this method if not using the convenience method +by the same name in the Group class.

+
+ +
+
+add()
+
+
add the sprite to groups
+
add(*groups) -> None
+
+

Any number of Group instances can be passed as arguments. The Sprite will +be added to the Groups it is not already a member of.

+
+ +
+
+remove()
+
+
remove the sprite from groups
+
remove(*groups) -> None
+
+

Any number of Group instances can be passed as arguments. The Sprite will +be removed from the Groups it is currently a member of.

+
+ +
+
+kill()
+
+
remove the Sprite from all Groups
+
kill() -> None
+
+

The Sprite is removed from all the Groups that contain it. This won't +change anything about the state of the Sprite. It is possible to continue +to use the Sprite after this method has been called, including adding it +to Groups.

+
+ +
+
+alive()
+
+
does the sprite belong to any groups
+
alive() -> bool
+
+

Returns True when the Sprite belongs to one or more Groups.

+
+ +
+
+groups()
+
+
list of Groups that contain this Sprite
+
groups() -> group_list
+
+

Return a list of all the Groups that contain this Sprite.

+
+ +
+ +
+
+pygame.sprite.DirtySprite
+
+
A subclass of Sprite with more attributes and features.
+
DirtySprite(*groups) -> DirtySprite
+
+

Extra DirtySprite attributes with their default values:

+

dirty = 1

+
if set to 1, it is repainted and then set to 0 again
+if set to 2 then it is always dirty ( repainted each frame,
+flag is not reset)
+0 means that it is not dirty and therefore not repainted again
+
+
+

blendmode = 0

+
its the special_flags argument of blit, blendmodes
+
+
+

source_rect = None

+
source rect to use, remember that it is relative to
+topleft (0,0) of self.image
+
+
+

visible = 1

+
normally 1, if set to 0 it will not be repainted
+(you must set it dirty too to be erased from screen)
+
+
+

layer = 0

+
(READONLY value, it is read when adding it to the
+LayeredDirty, for details see doc of LayeredDirty)
+
+
+
+ +
+
+pygame.sprite.Group
+
+
A container class to hold and manage multiple Sprite objects.
+
Group(*sprites) -> Group
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+list of the Sprites this Group contains
+duplicate the Group
+add Sprites to this Group
+remove Sprites from the Group
+test if a Group contains Sprites
+call the update method on contained Sprites
+blit the Sprite images
+draw a background over the Sprites
+remove all Sprites
+

A simple container for Sprite objects. This class can be inherited to create +containers with more specific behaviors. The constructor takes any number of +Sprite arguments to add to the Group. The group supports the following +standard Python operations:

+
in      test if a Sprite is contained
+len     the number of Sprites contained
+bool    test if any Sprites are contained
+iter    iterate through all the Sprites
+
+
+

The Sprites in the Group are ordered only on python 3.6 and higher. +Below python 3.6 drawing and iterating over the Sprites is in no particular order.

+
+
+sprites()
+
+
list of the Sprites this Group contains
+
sprites() -> sprite_list
+
+

Return a list of all the Sprites this group contains. You can also get an +iterator from the group, but you cannot iterate over a Group while +modifying it.

+
+ +
+
+copy()
+
+
duplicate the Group
+
copy() -> Group
+
+

Creates a new Group with all the same Sprites as the original. If you +have subclassed Group, the new object will have the same (sub-)class as +the original. This only works if the derived class's constructor takes +the same arguments as the Group class's.

+
+ +
+
+add()
+
+
add Sprites to this Group
+
add(*sprites) -> None
+
+

Add any number of Sprites to this Group. This will only add Sprites that +are not already members of the Group.

+

Each sprite argument can also be a iterator containing Sprites.

+
+ +
+
+remove()
+
+
remove Sprites from the Group
+
remove(*sprites) -> None
+
+

Remove any number of Sprites from the Group. This will only remove +Sprites that are already members of the Group.

+

Each sprite argument can also be a iterator containing Sprites.

+
+ +
+
+has()
+
+
test if a Group contains Sprites
+
has(*sprites) -> bool
+
+

Return True if the Group contains all of the given sprites. This is +similar to using the "in" operator on the Group ("if sprite in group: +..."), which tests if a single Sprite belongs to a Group.

+

Each sprite argument can also be a iterator containing Sprites.

+
+ +
+
+update()
+
+
call the update method on contained Sprites
+
update(*args, **kwargs) -> None
+
+

Calls the update() method on all Sprites in the Group. The base +Sprite class has an update method that takes any number of arguments and +does nothing. The arguments passed to Group.update() will be passed +to each Sprite.

+

There is no way to get the return value from the Sprite.update() +methods.

+
+ +
+
+draw()
+
+
blit the Sprite images
+
draw(Surface) -> List[Rect]
+
+

Draws the contained Sprites to the Surface argument. This uses the +Sprite.image attribute for the source surface, and Sprite.rect +for the position.

+

The Group does not keep sprites in any order, so the draw order is +arbitrary.

+
+ +
+
+clear()
+
+
draw a background over the Sprites
+
clear(Surface_dest, background) -> None
+
+

Erases the Sprites used in the last Group.draw() call. The +destination Surface is cleared by filling the drawn Sprite positions with +the background.

+

The background is usually a Surface image the same dimensions as the +destination Surface. However, it can also be a callback function that +takes two arguments; the destination Surface and an area to clear. The +background callback function will be called several times each clear.

+

Here is an example callback that will clear the Sprites with solid red:

+
def clear_callback(surf, rect):
+    color = 255, 0, 0
+    surf.fill(color, rect)
+
+
+
+ +
+
+empty()
+
+
remove all Sprites
+
empty() -> None
+
+

Removes all Sprites from this Group.

+
+ +
+ +
+
+pygame.sprite.RenderPlain
+
+
Same as pygame.sprite.Group
+
+

This class is an alias to pygame.sprite.Group(). It has no additional functionality.

+
+ +
+
+pygame.sprite.RenderClear
+
+
Same as pygame.sprite.Group
+
+

This class is an alias to pygame.sprite.Group(). It has no additional functionality.

+
+ +
+
+pygame.sprite.RenderUpdates
+
+
Group sub-class that tracks dirty updates.
+
RenderUpdates(*sprites) -> RenderUpdates
+
+ +++++ + + + + + + +
+blit the Sprite images and track changed areas
+

This class is derived from pygame.sprite.Group(). It has an extended +draw() method that tracks the changed areas of the screen.

+
+
+draw()
+
+
blit the Sprite images and track changed areas
+
draw(surface) -> Rect_list
+
+

Draws all the Sprites to the surface, the same as Group.draw(). This +method also returns a list of Rectangular areas on the screen that have +been changed. The returned changes include areas of the screen that have +been affected by previous Group.clear() calls.

+

The returned Rect list should be passed to pygame.display.update(). +This will help performance on software driven display modes. This type of +updating is usually only helpful on destinations with non-animating +backgrounds.

+
+ +
+ +
+
+pygame.sprite.OrderedUpdates()
+
+
RenderUpdates sub-class that draws Sprites in order of addition.
+
OrderedUpdates(*spites) -> OrderedUpdates
+
+

This class derives from pygame.sprite.RenderUpdates(). It maintains the +order in which the Sprites were added to the Group for rendering. This makes +adding and removing Sprites from the Group a little slower than regular +Groups.

+
+ +
+
+pygame.sprite.LayeredUpdates
+
+
LayeredUpdates is a sprite group that handles layers and draws like OrderedUpdates.
+
LayeredUpdates(*spites, **kwargs) -> LayeredUpdates
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+add a sprite or sequence of sprites to a group
+returns a ordered list of sprites (first back, last top).
+draw all sprites in the right order onto the passed surface.
+returns a list with all sprites at that position.
+returns the sprite at the index idx from the groups sprites
+removes all sprites from a layer and returns them as a list.
+returns a list of layers defined (unique), sorted from bottom up.
+changes the layer of the sprite
+returns the layer that sprite is currently in.
+returns the top layer
+returns the bottom layer
+brings the sprite to front layer
+moves the sprite to the bottom layer
+returns the topmost sprite
+returns all sprites from a layer, ordered by how they where added
+switches the sprites from layer1 to layer2
+

This group is fully compatible with pygame.sprite.SpriteSimple base class for visible game objects..

+

You can set the default layer through kwargs using 'default_layer' and an +integer for the layer. The default layer is 0.

+

If the sprite you add has an attribute _layer then that layer will be used. +If the **kwarg contains 'layer' then the sprites passed will be added to +that layer (overriding the sprite.layer attribute). If neither sprite +has attribute layer nor **kwarg then the default layer is used to add the +sprites.

+
+

New in pygame 1.8.

+
+
+
+add()
+
+
add a sprite or sequence of sprites to a group
+
add(*sprites, **kwargs) -> None
+
+

If the sprite(s) have an attribute layer then that is used for the +layer. If **kwargs contains 'layer' then the sprite(s) will be added +to that argument (overriding the sprite layer attribute). If neither is +passed then the sprite(s) will be added to the default layer.

+
+ +
+
+sprites()
+
+
returns a ordered list of sprites (first back, last top).
+
sprites() -> sprites
+
+
+ +
+
+draw()
+
+
draw all sprites in the right order onto the passed surface.
+
draw(surface) -> Rect_list
+
+
+ +
+
+get_sprites_at()
+
+
returns a list with all sprites at that position.
+
get_sprites_at(pos) -> colliding_sprites
+
+

Bottom sprites first, top last.

+
+ +
+
+get_sprite()
+
+
returns the sprite at the index idx from the groups sprites
+
get_sprite(idx) -> sprite
+
+

Raises IndexOutOfBounds if the idx is not within range.

+
+ +
+
+remove_sprites_of_layer()
+
+
removes all sprites from a layer and returns them as a list.
+
remove_sprites_of_layer(layer_nr) -> sprites
+
+
+ +
+
+layers()
+
+
returns a list of layers defined (unique), sorted from bottom up.
+
layers() -> layers
+
+
+ +
+
+change_layer()
+
+
changes the layer of the sprite
+
change_layer(sprite, new_layer) -> None
+
+

sprite must have been added to the renderer. It is not checked.

+
+ +
+
+get_layer_of_sprite()
+
+
returns the layer that sprite is currently in.
+
get_layer_of_sprite(sprite) -> layer
+
+

If the sprite is not found then it will return the default layer.

+
+ +
+
+get_top_layer()
+
+
returns the top layer
+
get_top_layer() -> layer
+
+
+ +
+
+get_bottom_layer()
+
+
returns the bottom layer
+
get_bottom_layer() -> layer
+
+
+ +
+
+move_to_front()
+
+
brings the sprite to front layer
+
move_to_front(sprite) -> None
+
+

Brings the sprite to front, changing sprite layer to topmost layer (added +at the end of that layer).

+
+ +
+
+move_to_back()
+
+
moves the sprite to the bottom layer
+
move_to_back(sprite) -> None
+
+

Moves the sprite to the bottom layer, moving it behind all other layers +and adding one additional layer.

+
+ +
+
+get_top_sprite()
+
+
returns the topmost sprite
+
get_top_sprite() -> Sprite
+
+
+ +
+
+get_sprites_from_layer()
+
+
returns all sprites from a layer, ordered by how they where added
+
get_sprites_from_layer(layer) -> sprites
+
+

Returns all sprites from a layer, ordered by how they where added. It +uses linear search and the sprites are not removed from layer.

+
+ +
+
+switch_layer()
+
+
switches the sprites from layer1 to layer2
+
switch_layer(layer1_nr, layer2_nr) -> None
+
+

The layers number must exist, it is not checked.

+
+ +
+ +
+
+pygame.sprite.LayeredDirty
+
+
LayeredDirty group is for DirtySprite objects. Subclasses LayeredUpdates.
+
LayeredDirty(*spites, **kwargs) -> LayeredDirty
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+draw all sprites in the right order onto the passed surface.
+used to set background
+repaints the given area
+clip the area where to draw. Just pass None (default) to reset the clip
+clip the area where to draw. Just pass None (default) to reset the clip
+changes the layer of the sprite
+sets the threshold in milliseconds
+sets the threshold in milliseconds
+

This group requires pygame.sprite.DirtySpriteA subclass of Sprite with more attributes and features. or any sprite that +has the following attributes:

+
image, rect, dirty, visible, blendmode (see doc of DirtySprite).
+
+
+

It uses the dirty flag technique and is therefore faster than the +pygame.sprite.RenderUpdatesGroup sub-class that tracks dirty updates. if you have many static sprites. It +also switches automatically between dirty rect update and full screen +drawing, so you do not have to worry what would be faster.

+

Same as for the pygame.sprite.GroupA container class to hold and manage multiple Sprite objects.. You can specify some +additional attributes through kwargs:

+
_use_update: True/False   default is False
+_default_layer: default layer where sprites without a layer are added.
+_time_threshold: threshold time for switching between dirty rect mode
+    and fullscreen mode, defaults to 1000./80  == 1000./fps
+
+
+
+

New in pygame 1.8.

+
+
+
+draw()
+
+
draw all sprites in the right order onto the passed surface.
+
draw(surface, bgd=None) -> Rect_list
+
+

You can pass the background too. If a background is already set, then the +bgd argument has no effect.

+
+ +
+
+clear()
+
+
used to set background
+
clear(surface, bgd) -> None
+
+
+ +
+
+repaint_rect()
+
+
repaints the given area
+
repaint_rect(screen_rect) -> None
+
+

screen_rect is in screen coordinates.

+
+ +
+
+set_clip()
+
+
clip the area where to draw. Just pass None (default) to reset the clip
+
set_clip(screen_rect=None) -> None
+
+
+ +
+
+get_clip()
+
+
clip the area where to draw. Just pass None (default) to reset the clip
+
get_clip() -> Rect
+
+
+ +
+
+change_layer()
+
+
changes the layer of the sprite
+
change_layer(sprite, new_layer) -> None
+
+

sprite must have been added to the renderer. It is not checked.

+
+ +
+
+set_timing_treshold()
+
+
sets the threshold in milliseconds
+
set_timing_treshold(time_ms) -> None
+
+

DEPRECATED: Use set_timing_threshold() instead.

+
+

Deprecated since pygame 2.1.1.

+
+
+ +
+
+set_timing_threshold()
+
+
sets the threshold in milliseconds
+
set_timing_threshold(time_ms) -> None
+
+

Defaults to 1000.0 / 80.0. This means that the screen will be painted +using the flip method rather than the update method if the update +method is taking so long to update the screen that the frame rate falls +below 80 frames per second.

+
+

New in pygame 2.1.1.

+
+
+
Raises
+

TypeError -- if time_ms is not int or float

+
+
+
+ +
+ +
+
+pygame.sprite.GroupSingle()
+
+
Group container that holds a single sprite.
+
GroupSingle(sprite=None) -> GroupSingle
+
+

The GroupSingle container only holds a single Sprite. When a new Sprite is +added, the old one is removed.

+

There is a special property, GroupSingle.sprite, that accesses the +Sprite that this Group contains. It can be None when the Group is empty. The +property can also be assigned to add a Sprite into the GroupSingle +container.

+
+ +
+
+pygame.sprite.spritecollide()
+
+
Find sprites in a group that intersect another sprite.
+
spritecollide(sprite, group, dokill, collided = None) -> Sprite_list
+
+

Return a list containing all Sprites in a Group that intersect with another +Sprite. Intersection is determined by comparing the Sprite.rect +attribute of each Sprite.

+

The dokill argument is a bool. If set to True, all Sprites that collide will +be removed from the Group.

+

The collided argument is a callback function used to calculate if two +sprites are colliding. it should take two sprites as values, and return a +bool value indicating if they are colliding. If collided is not passed, all +sprites must have a "rect" value, which is a rectangle of the sprite area, +which will be used to calculate the collision.

+

collided callables:

+
collide_rect, collide_rect_ratio, collide_circle,
+collide_circle_ratio, collide_mask
+
+
+

Example:

+
# See if the Sprite block has collided with anything in the Group block_list
+# The True flag will remove the sprite in block_list
+blocks_hit_list = pygame.sprite.spritecollide(player, block_list, True)
+
+# Check the list of colliding sprites, and add one to the score for each one
+for block in blocks_hit_list:
+    score +=1
+
+
+
+ +
+
+pygame.sprite.collide_rect()
+
+
Collision detection between two sprites, using rects.
+
collide_rect(left, right) -> bool
+
+

Tests for collision between two sprites. Uses the pygame rect colliderect +function to calculate the collision. Intended to be passed as a collided +callback function to the *collide functions. Sprites must have a "rect" +attributes.

+
+

New in pygame 1.8.

+
+
+ +
+
+pygame.sprite.collide_rect_ratio()
+
+
Collision detection between two sprites, using rects scaled to a ratio.
+
collide_rect_ratio(ratio) -> collided_callable
+
+

A callable class that checks for collisions between two sprites, using a +scaled version of the sprites rects.

+

Is created with a ratio, the instance is then intended to be passed as a +collided callback function to the *collide functions.

+

A ratio is a floating point number - 1.0 is the same size, 2.0 is twice as +big, and 0.5 is half the size.

+
+

New in pygame 1.8.1.

+
+
+ +
+
+pygame.sprite.collide_circle()
+
+
Collision detection between two sprites, using circles.
+
collide_circle(left, right) -> bool
+
+

Tests for collision between two sprites, by testing to see if two circles +centered on the sprites overlap. If the sprites have a "radius" attribute, +that is used to create the circle, otherwise a circle is created that is big +enough to completely enclose the sprites rect as given by the "rect" +attribute. Intended to be passed as a collided callback function to the +*collide functions. Sprites must have a "rect" and an optional "radius" +attribute.

+
+

New in pygame 1.8.1.

+
+
+ +
+
+pygame.sprite.collide_circle_ratio()
+
+
Collision detection between two sprites, using circles scaled to a ratio.
+
collide_circle_ratio(ratio) -> collided_callable
+
+

A callable class that checks for collisions between two sprites, using a +scaled version of the sprites radius.

+

Is created with a floating point ratio, the instance is then intended to be +passed as a collided callback function to the *collide functions.

+

A ratio is a floating point number - 1.0 is the same size, 2.0 is twice as +big, and 0.5 is half the size.

+

The created callable tests for collision between two sprites, by testing to +see if two circles centered on the sprites overlap, after scaling the +circles radius by the stored ratio. If the sprites have a "radius" +attribute, that is used to create the circle, otherwise a circle is created +that is big enough to completely enclose the sprites rect as given by the +"rect" attribute. Intended to be passed as a collided callback function to +the *collide functions. Sprites must have a "rect" and an optional "radius" +attribute.

+
+

New in pygame 1.8.1.

+
+
+ +
+
+pygame.sprite.collide_mask()
+
+
Collision detection between two sprites, using masks.
+
collide_mask(sprite1, sprite2) -> (int, int)
+
collide_mask(sprite1, sprite2) -> None
+
+

Tests for collision between two sprites, by testing if their bitmasks +overlap (uses pygame.mask.Mask.overlap()Returns the point of intersection). If the sprites have a +mask attribute, it is used as the mask, otherwise a mask is created from +the sprite's image (uses pygame.mask.from_surface()Creates a Mask from the given surface). Sprites must +have a rect attribute; the mask attribute is optional.

+

The first point of collision between the masks is returned. The collision +point is offset from sprite1's mask's topleft corner (which is always +(0, 0)). The collision point is a position within the mask and is not +related to the actual screen position of sprite1.

+

This function is intended to be passed as a collided callback function +to the group collide functions (see spritecollide(), +groupcollide(), spritecollideany()).

+
+

Note

+

To increase performance, create and set a mask attibute for all +sprites that will use this function to check for collisions. Otherwise, +each time this function is called it will create new masks.

+
+
+

Note

+

A new mask needs to be recreated each time a sprite's image is changed +(e.g. if a new image is used or the existing image is rotated).

+
+
# Example of mask creation for a sprite.
+sprite.mask = pygame.mask.from_surface(sprite.image)
+
+
+
+
Returns
+

first point of collision between the masks or None if no +collision

+
+
Return type
+

tuple(int, int) or NoneType

+
+
+
+

New in pygame 1.8.0.

+
+
+ +
+
+pygame.sprite.groupcollide()
+
+
Find all sprites that collide between two groups.
+
groupcollide(group1, group2, dokill1, dokill2, collided = None) -> Sprite_dict
+
+

This will find collisions between all the Sprites in two groups. +Collision is determined by comparing the Sprite.rect attribute of +each Sprite or by using the collided function if it is not None.

+

Every Sprite inside group1 is added to the return dictionary. The value for +each item is the list of Sprites in group2 that intersect.

+

If either dokill argument is True, the colliding Sprites will be removed +from their respective Group.

+

The collided argument is a callback function used to calculate if two sprites are +colliding. It should take two sprites as values and return a bool value +indicating if they are colliding. If collided is not passed, then all +sprites must have a "rect" value, which is a rectangle of the sprite area, +which will be used to calculate the collision.

+
+ +
+
+pygame.sprite.spritecollideany()
+
+
Simple test if a sprite intersects anything in a group.
+
spritecollideany(sprite, group, collided = None) -> Sprite Collision with the returned sprite.
+
spritecollideany(sprite, group, collided = None) -> None No collision
+
+

If the sprite collides with any single sprite in the group, a single +sprite from the group is returned. On no collision None is returned.

+

If you don't need all the features of the pygame.sprite.spritecollide() function, this +function will be a bit quicker.

+

The collided argument is a callback function used to calculate if two sprites are +colliding. It should take two sprites as values and return a bool value +indicating if they are colliding. If collided is not passed, then all +sprites must have a "rect" value, which is a rectangle of the sprite area, +which will be used to calculate the collision.

+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/surface.html b/venv/Lib/site-packages/pygame/docs/generated/ref/surface.html new file mode 100644 index 0000000..8a5da1c --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/surface.html @@ -0,0 +1,1290 @@ + + + + + + + + + pygame.Surface — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.Surface
+
+
pygame object for representing images
+
Surface((width, height), flags=0, depth=0, masks=None) -> Surface
+
Surface((width, height), flags=0, Surface) -> Surface
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+draw one image onto another
+draw many images onto another
+change the pixel format of an image
+change the pixel format of an image including per pixel alphas
+create a new copy of a Surface
+fill Surface with a solid color
+Shift the surface image in place
+Set the transparent colorkey
+Get the current transparent colorkey
+set the alpha value for the full Surface image
+get the current Surface transparency value
+lock the Surface memory for pixel access
+unlock the Surface memory from pixel access
+test if the Surface requires locking
+test if the Surface is current locked
+Gets the locks for the Surface
+get the color value at a single pixel
+set the color value for a single pixel
+get the mapped color value at a single pixel
+get the color index palette for an 8-bit Surface
+get the color for a single entry in a palette
+set the color palette for an 8-bit Surface
+set the color for a single index in an 8-bit Surface palette
+convert a color into a mapped color value
+convert a mapped integer color value into a Color
+set the current clipping area of the Surface
+get the current clipping area of the Surface
+create a new surface that references its parent
+find the parent of a subsurface
+find the top level parent of a subsurface
+find the position of a child subsurface inside a parent
+find the absolute position of a child subsurface inside its top level parent
+get the dimensions of the Surface
+get the width of the Surface
+get the height of the Surface
+get the rectangular area of the Surface
+get the bit depth of the Surface pixel format
+get the bytes used per Surface pixel
+get the additional flags used for the Surface
+get the number of bytes used per Surface row
+the bitmasks needed to convert between a color and a mapped integer
+set the bitmasks needed to convert between a color and a mapped integer
+the bit shifts needed to convert between a color and a mapped integer
+sets the bit shifts needed to convert between a color and a mapped integer
+the significant bits used to convert between a color and a mapped integer
+find the smallest rect containing data
+return a buffer view of the Surface's pixels.
+acquires a buffer object for the pixels of the Surface.
+pixel buffer address
+

A pygame Surface is used to represent any image. The Surface has a fixed +resolution and pixel format. Surfaces with 8-bit pixels use a color palette +to map to 24-bit color.

+

Call pygame.Surface()pygame object for representing images to create a new image object. The Surface will +be cleared to all black. The only required arguments are the sizes. With no +additional arguments, the Surface will be created in a format that best +matches the display Surface.

+

The pixel format can be controlled by passing the bit depth or an existing +Surface. The flags argument is a bitmask of additional features for the +surface. You can pass any combination of these flags:

+
HWSURFACE    (obsolete in pygame 2) creates the image in video memory
+SRCALPHA     the pixel format will include a per-pixel alpha
+
+
+

Both flags are only a request, and may not be possible for all displays and +formats.

+

Advance users can combine a set of bitmasks with a depth value. The masks +are a set of 4 integers representing which bits in a pixel will represent +each color. Normal Surfaces should not require the masks argument.

+

Surfaces can have many extra attributes like alpha planes, colorkeys, source +rectangle clipping. These functions mainly effect how the Surface is blitted +to other Surfaces. The blit routines will attempt to use hardware +acceleration when possible, otherwise they will use highly optimized +software blitting methods.

+

There are three types of transparency supported in pygame: colorkeys, +surface alphas, and pixel alphas. Surface alphas can be mixed with +colorkeys, but an image with per pixel alphas cannot use the other modes. +Colorkey transparency makes a single color value transparent. Any pixels +matching the colorkey will not be drawn. The surface alpha value is a single +value that changes the transparency for the entire image. A surface alpha of +255 is opaque, and a value of 0 is completely transparent.

+

Per pixel alphas are different because they store a transparency value for +every pixel. This allows for the most precise transparency effects, but it +also the slowest. Per pixel alphas cannot be mixed with surface alpha and +colorkeys.

+

There is support for pixel access for the Surfaces. Pixel access on hardware +surfaces is slow and not recommended. Pixels can be accessed using the +get_at() and set_at() functions. These methods are fine for +simple access, but will be considerably slow when doing of pixel work with +them. If you plan on doing a lot of pixel level work, it is recommended to +use a pygame.PixelArraypygame object for direct pixel access of surfaces, which gives an array like view of the +surface. For involved mathematical manipulations try the +pygame.surfarraypygame module for accessing surface pixel data using array interfaces module (It's quite quick, but requires NumPy.)

+

Any functions that directly access a surface's pixel data will need that +surface to be lock()'ed. These functions can lock() and +unlock() the surfaces themselves without assistance. But, if a +function will be called many times, there will be a lot of overhead for +multiple locking and unlocking of the surface. It is best to lock the +surface manually before making the function call many times, and then +unlocking when you are finished. All functions that need a locked surface +will say so in their docs. Remember to leave the Surface locked only while +necessary.

+

Surface pixels are stored internally as a single number that has all the +colors encoded into it. Use the map_rgb() and +unmap_rgb() to convert between individual red, green, and blue +values into a packed integer for that Surface.

+

Surfaces can also reference sections of other Surfaces. These are created +with the subsurface() method. Any change to either Surface will +effect the other.

+

Each Surface contains a clipping area. By default the clip area covers the +entire Surface. If it is changed, all drawing operations will only effect +the smaller area.

+
+
+blit()
+
+
draw one image onto another
+
blit(source, dest, area=None, special_flags=0) -> Rect
+
+

Draws a source Surface onto this Surface. The draw can be positioned with +the dest argument. The dest argument can either be a pair of coordinates representing the position of +the upper left corner of the blit or a Rect, where the upper left corner of the rectangle will be used as the +position for the blit. The size of the destination rectangle does not +effect the blit.

+

An optional area rectangle can be passed as well. This represents a +smaller portion of the source Surface to draw.

+
+

New in pygame 1.8: Optional special_flags: BLEND_ADD, BLEND_SUB, +BLEND_MULT, BLEND_MIN, BLEND_MAX.

+
+
+

New in pygame 1.8.1: Optional special_flags: BLEND_RGBA_ADD, BLEND_RGBA_SUB, +BLEND_RGBA_MULT, BLEND_RGBA_MIN, BLEND_RGBA_MAX +BLEND_RGB_ADD, BLEND_RGB_SUB, BLEND_RGB_MULT, +BLEND_RGB_MIN, BLEND_RGB_MAX.

+
+
+

New in pygame 1.9.2: Optional special_flags: BLEND_PREMULTIPLIED

+
+
+

New in pygame 2.0.0: Optional special_flags: BLEND_ALPHA_SDL2 - Uses the SDL2 blitter for alpha blending, +this gives different results than the default blitter, which is modelled after SDL1, due to +different approximations used for the alpha blending formula. The SDL2 blitter also supports +RLE on alpha blended surfaces which the pygame one does not.

+
+

The return rectangle is the area of the affected pixels, excluding any +pixels outside the destination Surface, or outside the clipping area.

+

Pixel alphas will be ignored when blitting to an 8 bit Surface.

+

For a surface with colorkey or blanket alpha, a blit to self may give +slightly different colors than a non self-blit.

+
+ +
+
+blits()
+
+
draw many images onto another
+
blits(blit_sequence=((source, dest), ...), doreturn=1) -> [Rect, ...] or None
+
blits(((source, dest, area), ...)) -> [Rect, ...]
+
blits(((source, dest, area, special_flags), ...)) -> [Rect, ...]
+
+

Draws many surfaces onto this Surface. It takes a sequence as input, +with each of the elements corresponding to the ones of blit(). +It needs at minimum a sequence of (source, dest).

+
+
Parameters
+
    +
  • blit_sequence -- a sequence of surfaces and arguments to blit them, +they correspond to the blit() arguments

  • +
  • doreturn -- if True, return a list of rects of the areas changed, +otherwise return None

  • +
+
+
Returns
+

a list of rects of the areas changed if doreturn is +True, otherwise None

+
+
Return type
+

list or None

+
+
+

New in pygame 1.9.4.

+
+ +
+
+convert()
+
+
change the pixel format of an image
+
convert(Surface=None) -> Surface
+
convert(depth, flags=0) -> Surface
+
convert(masks, flags=0) -> Surface
+
+

Creates a new copy of the Surface with the pixel format changed. The new +pixel format can be determined from another existing Surface. Otherwise +depth, flags, and masks arguments can be used, similar to the +pygame.Surface()pygame object for representing images call.

+

If no arguments are passed the new Surface will have the same pixel +format as the display Surface. This is always the fastest format for +blitting. It is a good idea to convert all Surfaces before they are +blitted many times.

+

The converted Surface will have no pixel alphas. They will be stripped if +the original had them. See convert_alpha() for preserving or +creating per-pixel alphas.

+

The new copy will have the same class as the copied surface. This lets +as Surface subclass inherit this method without the need to override, +unless subclass specific instance attributes also need copying.

+
+ +
+
+convert_alpha()
+
+
change the pixel format of an image including per pixel alphas
+
convert_alpha(Surface) -> Surface
+
convert_alpha() -> Surface
+
+

Creates a new copy of the surface with the desired pixel format. The new +surface will be in a format suited for quick blitting to the given format +with per pixel alpha. If no surface is given, the new surface will be +optimized for blitting to the current display.

+

Unlike the convert() method, the pixel format for the new +image will not be exactly the same as the requested source, but it will +be optimized for fast alpha blitting to the destination.

+

As with convert() the returned surface has the same class as +the converted surface.

+
+ +
+
+copy()
+
+
create a new copy of a Surface
+
copy() -> Surface
+
+

Makes a duplicate copy of a Surface. The new surface will have the same +pixel formats, color palettes, transparency settings, and class as the +original. If a Surface subclass also needs to copy any instance specific +attributes then it should override copy().

+
+ +
+
+fill()
+
+
fill Surface with a solid color
+
fill(color, rect=None, special_flags=0) -> Rect
+
+

Fill the Surface with a solid color. If no rect argument is given the +entire Surface will be filled. The rect argument will limit the fill to a +specific area. The fill will also be contained by the Surface clip area.

+

The color argument can be either a RGB sequence, a RGBA sequence +or a mapped color index. If using RGBA, the Alpha (A part of +RGBA) is ignored unless the surface uses per pixel alpha (Surface has +the SRCALPHA flag).

+
+

New in pygame 1.8: Optional special_flags: BLEND_ADD, BLEND_SUB, +BLEND_MULT, BLEND_MIN, BLEND_MAX.

+
+
+

New in pygame 1.8.1: Optional special_flags: BLEND_RGBA_ADD, BLEND_RGBA_SUB, +BLEND_RGBA_MULT, BLEND_RGBA_MIN, BLEND_RGBA_MAX +BLEND_RGB_ADD, BLEND_RGB_SUB, BLEND_RGB_MULT, +BLEND_RGB_MIN, BLEND_RGB_MAX.

+
+

This will return the affected Surface area.

+
+ +
+
+scroll()
+
+
Shift the surface image in place
+
scroll(dx=0, dy=0) -> None
+
+

Move the image by dx pixels right and dy pixels down. dx and dy may be +negative for left and up scrolls respectively. Areas of the surface that +are not overwritten retain their original pixel values. Scrolling is +contained by the Surface clip area. It is safe to have dx and dy values +that exceed the surface size.

+
+

New in pygame 1.9.

+
+
+ +
+
+set_colorkey()
+
+
Set the transparent colorkey
+
set_colorkey(Color, flags=0) -> None
+
set_colorkey(None) -> None
+
+

Set the current color key for the Surface. When blitting this Surface +onto a destination, any pixels that have the same color as the colorkey +will be transparent. The color can be an RGB color or a mapped color +integer. If None is passed, the colorkey will be unset.

+

The colorkey will be ignored if the Surface is formatted to use per pixel +alpha values. The colorkey can be mixed with the full Surface alpha +value.

+

The optional flags argument can be set to pygame.RLEACCEL to provide +better performance on non accelerated displays. An RLEACCEL Surface +will be slower to modify, but quicker to blit as a source.

+
+ +
+
+get_colorkey()
+
+
Get the current transparent colorkey
+
get_colorkey() -> RGB or None
+
+

Return the current colorkey value for the Surface. If the colorkey is not +set then None is returned.

+
+ +
+
+set_alpha()
+
+
set the alpha value for the full Surface image
+
set_alpha(value, flags=0) -> None
+
set_alpha(None) -> None
+
+

Set the current alpha value for the Surface. When blitting this Surface +onto a destination, the pixels will be drawn slightly transparent. The +alpha value is an integer from 0 to 255, 0 is fully transparent and 255 +is fully opaque. If None is passed for the alpha value, then alpha +blending will be disabled, including per-pixel alpha.

+

This value is different than the per pixel Surface alpha. For a surface +with per pixel alpha, blanket alpha is ignored and None is returned.

+
+

Changed in pygame 2.0: per-surface alpha can be combined with per-pixel +alpha.

+
+

The optional flags argument can be set to pygame.RLEACCEL to provide +better performance on non accelerated displays. An RLEACCEL Surface +will be slower to modify, but quicker to blit as a source.

+
+ +
+
+get_alpha()
+
+
get the current Surface transparency value
+
get_alpha() -> int_value
+
+

Return the current alpha value for the Surface.

+
+ +
+
+lock()
+
+
lock the Surface memory for pixel access
+
lock() -> None
+
+

Lock the pixel data of a Surface for access. On accelerated Surfaces, the +pixel data may be stored in volatile video memory or nonlinear compressed +forms. When a Surface is locked the pixel memory becomes available to +access by regular software. Code that reads or writes pixel values will +need the Surface to be locked.

+

Surfaces should not remain locked for more than necessary. A locked +Surface can often not be displayed or managed by pygame.

+

Not all Surfaces require locking. The mustlock() method can +determine if it is actually required. There is no performance penalty for +locking and unlocking a Surface that does not need it.

+

All pygame functions will automatically lock and unlock the Surface data +as needed. If a section of code is going to make calls that will +repeatedly lock and unlock the Surface many times, it can be helpful to +wrap the block inside a lock and unlock pair.

+

It is safe to nest locking and unlocking calls. The surface will only be +unlocked after the final lock is released.

+
+ +
+
+unlock()
+
+
unlock the Surface memory from pixel access
+
unlock() -> None
+
+

Unlock the Surface pixel data after it has been locked. The unlocked +Surface can once again be drawn and managed by pygame. See the +lock() documentation for more details.

+

All pygame functions will automatically lock and unlock the Surface data +as needed. If a section of code is going to make calls that will +repeatedly lock and unlock the Surface many times, it can be helpful to +wrap the block inside a lock and unlock pair.

+

It is safe to nest locking and unlocking calls. The surface will only be +unlocked after the final lock is released.

+
+ +
+
+mustlock()
+
+
test if the Surface requires locking
+
mustlock() -> bool
+
+

Returns True if the Surface is required to be locked to access pixel +data. Usually pure software Surfaces do not require locking. This method +is rarely needed, since it is safe and quickest to just lock all Surfaces +as needed.

+

All pygame functions will automatically lock and unlock the Surface data +as needed. If a section of code is going to make calls that will +repeatedly lock and unlock the Surface many times, it can be helpful to +wrap the block inside a lock and unlock pair.

+
+ +
+
+get_locked()
+
+
test if the Surface is current locked
+
get_locked() -> bool
+
+

Returns True when the Surface is locked. It doesn't matter how many +times the Surface is locked.

+
+ +
+
+get_locks()
+
+
Gets the locks for the Surface
+
get_locks() -> tuple
+
+

Returns the currently existing locks for the Surface.

+
+ +
+
+get_at()
+
+
get the color value at a single pixel
+
get_at((x, y)) -> Color
+
+

Return a copy of the RGBA Color value at the given pixel. If the +Surface has no per pixel alpha, then the alpha value will always be 255 +(opaque). If the pixel position is outside the area of the Surface an +IndexError exception will be raised.

+

Getting and setting pixels one at a time is generally too slow to be used +in a game or realtime situation. It is better to use methods which +operate on many pixels at a time like with the blit, fill and draw +methods - or by using pygame.surfarraypygame module for accessing surface pixel data using array interfaces/pygame.PixelArraypygame object for direct pixel access of surfaces.

+

This function will temporarily lock and unlock the Surface as needed.

+
+

New in pygame 1.9: Returning a Color instead of tuple. Use tuple(surf.get_at((x,y))) +if you want a tuple, and not a Color. This should only matter if +you want to use the color as a key in a dict.

+
+
+ +
+
+set_at()
+
+
set the color value for a single pixel
+
set_at((x, y), Color) -> None
+
+

Set the RGBA or mapped integer color value for a single pixel. If the +Surface does not have per pixel alphas, the alpha value is ignored. +Setting pixels outside the Surface area or outside the Surface clipping +will have no effect.

+

Getting and setting pixels one at a time is generally too slow to be used +in a game or realtime situation.

+

This function will temporarily lock and unlock the Surface as needed.

+
+ +
+
+get_at_mapped()
+
+
get the mapped color value at a single pixel
+
get_at_mapped((x, y)) -> Color
+
+

Return the integer value of the given pixel. If the pixel position is +outside the area of the Surface an IndexError exception will be +raised.

+

This method is intended for pygame unit testing. It unlikely has any use +in an application.

+

This function will temporarily lock and unlock the Surface as needed.

+
+

New in pygame 1.9.2.

+
+
+ +
+
+get_palette()
+
+
get the color index palette for an 8-bit Surface
+
get_palette() -> [RGB, RGB, RGB, ...]
+
+

Return a list of up to 256 color elements that represent the indexed +colors used in an 8-bit Surface. The returned list is a copy of the +palette, and changes will have no effect on the Surface.

+

Returning a list of Color(with length 3) instances instead of tuples.

+
+

New in pygame 1.9.

+
+
+ +
+
+get_palette_at()
+
+
get the color for a single entry in a palette
+
get_palette_at(index) -> RGB
+
+

Returns the red, green, and blue color values for a single index in a +Surface palette. The index should be a value from 0 to 255.

+
+

New in pygame 1.9: Returning Color(with length 3) instance instead of a tuple.

+
+
+ +
+
+set_palette()
+
+
set the color palette for an 8-bit Surface
+
set_palette([RGB, RGB, RGB, ...]) -> None
+
+

Set the full palette for an 8-bit Surface. This will replace the colors in +the existing palette. A partial palette can be passed and only the first +colors in the original palette will be changed.

+

This function has no effect on a Surface with more than 8-bits per pixel.

+
+ +
+
+set_palette_at()
+
+
set the color for a single index in an 8-bit Surface palette
+
set_palette_at(index, RGB) -> None
+
+

Set the palette value for a single entry in a Surface palette. The index +should be a value from 0 to 255.

+

This function has no effect on a Surface with more than 8-bits per pixel.

+
+ +
+
+map_rgb()
+
+
convert a color into a mapped color value
+
map_rgb(Color) -> mapped_int
+
+

Convert an RGBA color into the mapped integer value for this Surface. +The returned integer will contain no more bits than the bit depth of the +Surface. Mapped color values are not often used inside pygame, but can be +passed to most functions that require a Surface and a color.

+

See the Surface object documentation for more information about colors +and pixel formats.

+
+ +
+
+unmap_rgb()
+
+
convert a mapped integer color value into a Color
+
unmap_rgb(mapped_int) -> Color
+
+

Convert an mapped integer color into the RGB color components for +this Surface. Mapped color values are not often used inside pygame, but +can be passed to most functions that require a Surface and a color.

+

See the Surface object documentation for more information about colors +and pixel formats.

+
+ +
+
+set_clip()
+
+
set the current clipping area of the Surface
+
set_clip(rect) -> None
+
set_clip(None) -> None
+
+

Each Surface has an active clipping area. This is a rectangle that +represents the only pixels on the Surface that can be modified. If +None is passed for the rectangle the full Surface will be available +for changes.

+

The clipping area is always restricted to the area of the Surface itself. +If the clip rectangle is too large it will be shrunk to fit inside the +Surface.

+
+ +
+
+get_clip()
+
+
get the current clipping area of the Surface
+
get_clip() -> Rect
+
+

Return a rectangle of the current clipping area. The Surface will always +return a valid rectangle that will never be outside the bounds of the +image. If the Surface has had None set for the clipping area, the +Surface will return a rectangle with the full area of the Surface.

+
+ +
+
+subsurface()
+
+
create a new surface that references its parent
+
subsurface(Rect) -> Surface
+
+

Returns a new Surface that shares its pixels with its new parent. The new +Surface is considered a child of the original. Modifications to either +Surface pixels will effect each other. Surface information like clipping +area and color keys are unique to each Surface.

+

The new Surface will inherit the palette, color key, and alpha settings +from its parent.

+

It is possible to have any number of subsurfaces and subsubsurfaces on +the parent. It is also possible to subsurface the display Surface if the +display mode is not hardware accelerated.

+

See get_offset() and get_parent() to learn more +about the state of a subsurface.

+

A subsurface will have the same class as the parent surface.

+
+ +
+
+get_parent()
+
+
find the parent of a subsurface
+
get_parent() -> Surface
+
+

Returns the parent Surface of a subsurface. If this is not a subsurface +then None will be returned.

+
+ +
+
+get_abs_parent()
+
+
find the top level parent of a subsurface
+
get_abs_parent() -> Surface
+
+

Returns the parent Surface of a subsurface. If this is not a subsurface +then this surface will be returned.

+
+ +
+
+get_offset()
+
+
find the position of a child subsurface inside a parent
+
get_offset() -> (x, y)
+
+

Get the offset position of a child subsurface inside of a parent. If the +Surface is not a subsurface this will return (0, 0).

+
+ +
+
+get_abs_offset()
+
+
find the absolute position of a child subsurface inside its top level parent
+
get_abs_offset() -> (x, y)
+
+

Get the offset position of a child subsurface inside of its top level +parent Surface. If the Surface is not a subsurface this will return (0, +0).

+
+ +
+
+get_size()
+
+
get the dimensions of the Surface
+
get_size() -> (width, height)
+
+

Return the width and height of the Surface in pixels.

+
+ +
+
+get_width()
+
+
get the width of the Surface
+
get_width() -> width
+
+

Return the width of the Surface in pixels.

+
+ +
+
+get_height()
+
+
get the height of the Surface
+
get_height() -> height
+
+

Return the height of the Surface in pixels.

+
+ +
+
+get_rect()
+
+
get the rectangular area of the Surface
+
get_rect(**kwargs) -> Rect
+
+

Returns a new rectangle covering the entire surface. This rectangle will +always start at (0, 0) with a width and height the same size as the image.

+

You can pass keyword argument values to this function. These named values +will be applied to the attributes of the Rect before it is returned. An +example would be mysurf.get_rect(center=(100, 100)) to create a +rectangle for the Surface centered at a given position.

+
+ +
+
+get_bitsize()
+
+
get the bit depth of the Surface pixel format
+
get_bitsize() -> int
+
+

Returns the number of bits used to represent each pixel. This value may +not exactly fill the number of bytes used per pixel. For example a 15 bit +Surface still requires a full 2 bytes.

+
+ +
+
+get_bytesize()
+
+
get the bytes used per Surface pixel
+
get_bytesize() -> int
+
+

Return the number of bytes used per pixel.

+
+ +
+
+get_flags()
+
+
get the additional flags used for the Surface
+
get_flags() -> int
+
+

Returns a set of current Surface features. Each feature is a bit in the +flags bitmask. Typical flags are RLEACCEL, SRCALPHA, and +SRCCOLORKEY.

+

Here is a more complete list of flags. A full list can be found in +SDL_video.h

+
SWSURFACE      0x00000000    # Surface is in system memory
+HWSURFACE      0x00000001    # (obsolete in pygame 2) Surface is in video memory
+ASYNCBLIT      0x00000004    # (obsolete in pygame 2) Use asynchronous blits if possible
+
+
+

See pygame.display.set_mode()Initialize a window or screen for display for flags exclusive to the +display surface.

+

Used internally (read-only)

+
HWACCEL        0x00000100    # Blit uses hardware acceleration
+SRCCOLORKEY    0x00001000    # Blit uses a source color key
+RLEACCELOK     0x00002000    # Private flag
+RLEACCEL       0x00004000    # Surface is RLE encoded
+SRCALPHA       0x00010000    # Blit uses source alpha blending
+PREALLOC       0x01000000    # Surface uses preallocated memory
+
+
+
+ +
+
+get_pitch()
+
+
get the number of bytes used per Surface row
+
get_pitch() -> int
+
+

Return the number of bytes separating each row in the Surface. Surfaces +in video memory are not always linearly packed. Subsurfaces will also +have a larger pitch than their real width.

+

This value is not needed for normal pygame usage.

+
+ +
+
+get_masks()
+
+
the bitmasks needed to convert between a color and a mapped integer
+
get_masks() -> (R, G, B, A)
+
+

Returns the bitmasks used to isolate each color in a mapped integer.

+

This value is not needed for normal pygame usage.

+
+ +
+
+set_masks()
+
+
set the bitmasks needed to convert between a color and a mapped integer
+
set_masks((r,g,b,a)) -> None
+
+

This is not needed for normal pygame usage.

+
+

Note

+

In SDL2, the masks are read-only and accordingly this method will raise +an AttributeError if called.

+
+
+

New in pygame 1.8.1.

+
+
+ +
+
+get_shifts()
+
+
the bit shifts needed to convert between a color and a mapped integer
+
get_shifts() -> (R, G, B, A)
+
+

Returns the pixel shifts need to convert between each color and a mapped +integer.

+

This value is not needed for normal pygame usage.

+
+ +
+
+set_shifts()
+
+
sets the bit shifts needed to convert between a color and a mapped integer
+
set_shifts((r,g,b,a)) -> None
+
+

This is not needed for normal pygame usage.

+
+

Note

+

In SDL2, the shifts are read-only and accordingly this method will raise +an AttributeError if called.

+
+
+

New in pygame 1.8.1.

+
+
+ +
+
+get_losses()
+
+
the significant bits used to convert between a color and a mapped integer
+
get_losses() -> (R, G, B, A)
+
+

Return the least significant number of bits stripped from each color in a +mapped integer.

+

This value is not needed for normal pygame usage.

+
+ +
+
+get_bounding_rect()
+
+
find the smallest rect containing data
+
get_bounding_rect(min_alpha = 1) -> Rect
+
+

Returns the smallest rectangular region that contains all the pixels in +the surface that have an alpha value greater than or equal to the minimum +alpha value.

+

This function will temporarily lock and unlock the Surface as needed.

+
+

New in pygame 1.8.

+
+
+ +
+
+get_view()
+
+
return a buffer view of the Surface's pixels.
+
get_view(<kind>='2') -> BufferProxy
+
+

Return an object which exports a surface's internal pixel buffer as +a C level array struct, Python level array interface or a C level +buffer interface. The new buffer protocol is supported.

+

The kind argument is the length 1 string '0', '1', '2', '3', +'r', 'g', 'b', or 'a'. The letters are case insensitive; +'A' will work as well. The argument can be either a Unicode or byte (char) +string. The default is '2'.

+

'0' returns a contiguous unstructured bytes view. No surface shape +information is given. A ValueError is raised if the surface's pixels +are discontinuous.

+

'1' returns a (surface-width * surface-height) array of continuous +pixels. A ValueError is raised if the surface pixels are +discontinuous.

+

'2' returns a (surface-width, surface-height) array of raw pixels. +The pixels are surface-bytesize-d unsigned integers. The pixel format is +surface specific. The 3 byte unsigned integers of 24 bit surfaces are +unlikely accepted by anything other than other pygame functions.

+

'3' returns a (surface-width, surface-height, 3) array of RGB color +components. Each of the red, green, and blue components are unsigned +bytes. Only 24-bit and 32-bit surfaces are supported. The color +components must be in either RGB or BGR order within the pixel.

+

'r' for red, 'g' for green, 'b' for blue, and 'a' for alpha return a +(surface-width, surface-height) view of a single color component within a +surface: a color plane. Color components are unsigned bytes. Both 24-bit +and 32-bit surfaces support 'r', 'g', and 'b'. Only 32-bit surfaces with +SRCALPHA support 'a'.

+

The surface is locked only when an exposed interface is accessed. +For new buffer interface accesses, the surface is unlocked once the +last buffer view is released. For array interface and old buffer +interface accesses, the surface remains locked until the BufferProxy +object is released.

+
+

New in pygame 1.9.2.

+
+
+ +
+
+get_buffer()
+
+
acquires a buffer object for the pixels of the Surface.
+
get_buffer() -> BufferProxy
+
+

Return a buffer object for the pixels of the Surface. The buffer can be +used for direct pixel access and manipulation. Surface pixel data is +represented as an unstructured block of memory, with a start address +and length in bytes. The data need not be contiguous. Any gaps are +included in the length, but otherwise ignored.

+

This method implicitly locks the Surface. The lock will be released when +the returned pygame.BufferProxypygame object to export a surface buffer through an array protocol object is garbage collected.

+
+

New in pygame 1.8.

+
+
+ +
+
+_pixels_address
+
+
pixel buffer address
+
_pixels_address -> int
+
+

The starting address of the surface's raw pixel bytes.

+
+

New in pygame 1.9.2.

+
+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/surfarray.html b/venv/Lib/site-packages/pygame/docs/generated/ref/surfarray.html new file mode 100644 index 0000000..fb22728 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/surfarray.html @@ -0,0 +1,571 @@ + + + + + + + + + pygame.surfarray — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.surfarray
+
+
pygame module for accessing surface pixel data using array interfaces
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Copy pixels into a 2d array
+Reference pixels into a 2d array
+Copy pixels into a 3d array
+Reference pixels into a 3d array
+Copy pixel alphas into a 2d array
+Reference pixel alphas into a 2d array
+Copy red pixels into a 2d array
+Reference pixel red into a 2d array.
+Copy green pixels into a 2d array
+Reference pixel green into a 2d array.
+Copy blue pixels into a 2d array
+Reference pixel blue into a 2d array.
+Copy the colorkey values into a 2d array
+Copy an array to a new surface
+Blit directly from a array values
+Map a 3d array into a 2d array
+Sets the array system to be used for surface arrays
+Gets the currently active array type.
+Gets the array system types currently supported.
+

Functions to convert between NumPy arrays and Surface objects. This module +will only be functional when pygame can use the external NumPy package. +If NumPy can't be imported, surfarray becomes a MissingModule object.

+

Every pixel is stored as a single integer value to represent the red, green, +and blue colors. The 8-bit images use a value that looks into a colormap. Pixels +with higher depth use a bit packing process to place three or four values into +a single number.

+

The arrays are indexed by the X axis first, followed by the Y axis. +Arrays that treat the pixels as a single integer are referred to as 2D arrays. +This module can also separate the red, green, and blue color values into +separate indices. These types of arrays are referred to as 3D arrays, and the +last index is 0 for red, 1 for green, and 2 for blue.

+

The pixels of a 2D array as returned by array2d() and pixels2d() +are mapped to the specific surface. Use pygame.Surface.unmap_rgb()convert a mapped integer color value into a Color +to convert to a color, and pygame.Surface.map_rgb()convert a color into a mapped color value to get the surface +specific pixel value of a color. Integer pixel values can only be used directly +between surfaces with matching pixel layouts (see pygame.Surfacepygame object for representing images).

+

All functions that refer to "array" will copy the surface information to a new +numpy array. All functions that refer to "pixels" will directly reference the +pixels from the surface and any changes performed to the array will make changes +in the surface. As this last functions share memory with the surface, this one +will be locked during the lifetime of the array.

+
+
+pygame.surfarray.array2d()
+
+
Copy pixels into a 2d array
+
array2d(Surface) -> array
+
+

Copy the mapped (raw) pixels from a Surface +into a 2D array. +The bit depth of the surface will control the size of the integer values, +and will work for any type of pixel format.

+

This function will temporarily lock the Surface as pixels are copied +(see the pygame.Surface.lock()lock the Surface memory for pixel access - lock the Surface memory for pixel +access method).

+
+ +
+
+pygame.surfarray.pixels2d()
+
+
Reference pixels into a 2d array
+
pixels2d(Surface) -> array
+
+

Create a new 2D array that directly references the pixel values in a +Surface. Any changes to the array will affect the pixels in the Surface. +This is a fast operation since no data is copied.

+

Pixels from a 24-bit Surface cannot be referenced, but all other Surface bit +depths can.

+

The Surface this references will remain locked for the lifetime of the array, +since the array generated by this function shares memory with the surface. +See the pygame.Surface.lock()lock the Surface memory for pixel access - lock the Surface memory for pixel +access method.

+
+ +
+
+pygame.surfarray.array3d()
+
+
Copy pixels into a 3d array
+
array3d(Surface) -> array
+
+

Copy the pixels from a Surface into a 3D array. The bit depth of the surface +will control the size of the integer values, and will work for any type of +pixel format.

+

This function will temporarily lock the Surface as pixels are copied (see +the pygame.Surface.lock()lock the Surface memory for pixel access - lock the Surface memory for pixel +access method).

+
+ +
+
+pygame.surfarray.pixels3d()
+
+
Reference pixels into a 3d array
+
pixels3d(Surface) -> array
+
+

Create a new 3D array that directly references the pixel values in a +Surface. Any changes to the array will affect the pixels in the Surface. +This is a fast operation since no data is copied.

+

This will only work on Surfaces that have 24-bit or 32-bit formats. Lower +pixel formats cannot be referenced.

+

The Surface this references will remain locked for the lifetime of the array, +since the array generated by this function shares memory with the surface. +See the pygame.Surface.lock()lock the Surface memory for pixel access - lock the Surface memory for pixel +access method.

+
+ +
+
+pygame.surfarray.array_alpha()
+
+
Copy pixel alphas into a 2d array
+
array_alpha(Surface) -> array
+
+

Copy the pixel alpha values (degree of transparency) from a Surface into a +2D array. This will work for any type of Surface format. Surfaces without a +pixel alpha will return an array with all opaque values.

+

This function will temporarily lock the Surface as pixels are copied (see +the pygame.Surface.lock()lock the Surface memory for pixel access - lock the Surface memory for pixel +access method).

+
+ +
+
+pygame.surfarray.pixels_alpha()
+
+
Reference pixel alphas into a 2d array
+
pixels_alpha(Surface) -> array
+
+

Create a new 2D array that directly references the alpha values (degree of +transparency) in a Surface. Any changes to the array will affect the pixels +in the Surface. This is a fast operation since no data is copied.

+

This can only work on 32-bit Surfaces with a per-pixel alpha value.

+

The Surface this references will remain locked for the lifetime of the array, +since the array generated by this function shares memory with the surface. +See the pygame.Surface.lock()lock the Surface memory for pixel access - lock the Surface memory for pixel +access method.

+
+ +
+
+pygame.surfarray.array_red()
+
+
Copy red pixels into a 2d array
+
array_red(Surface) -> array
+
+

Copy the pixel red values from a Surface into a 2D array. This will work +for any type of Surface format.

+

This function will temporarily lock the Surface as pixels are copied (see +the pygame.Surface.lock()lock the Surface memory for pixel access - lock the Surface memory for pixel +access method).

+
+

New in pygame 2.0.2.

+
+
+ +
+
+pygame.surfarray.pixels_red()
+
+
Reference pixel red into a 2d array.
+
pixels_red (Surface) -> array
+
+

Create a new 2D array that directly references the red values in a Surface. +Any changes to the array will affect the pixels in the Surface. This is a +fast operation since no data is copied.

+

This can only work on 24-bit or 32-bit Surfaces.

+

The Surface this references will remain locked for the lifetime of the array, +since the array generated by this function shares memory with the surface. +See the pygame.Surface.lock()lock the Surface memory for pixel access - lock the Surface memory for pixel +access method.

+
+ +
+
+pygame.surfarray.array_green()
+
+
Copy green pixels into a 2d array
+
array_green(Surface) -> array
+
+

Copy the pixel green values from a Surface into a 2D array. This will work +for any type of Surface format.

+

This function will temporarily lock the Surface as pixels are copied (see +the pygame.Surface.lock()lock the Surface memory for pixel access - lock the Surface memory for pixel +access method).

+
+

New in pygame 2.0.2.

+
+
+ +
+
+pygame.surfarray.pixels_green()
+
+
Reference pixel green into a 2d array.
+
pixels_green (Surface) -> array
+
+

Create a new 2D array that directly references the green values in a +Surface. Any changes to the array will affect the pixels in the Surface. +This is a fast operation since no data is copied.

+

This can only work on 24-bit or 32-bit Surfaces.

+

The Surface this references will remain locked for the lifetime of the array, +since the array generated by this function shares memory with the surface. +See the pygame.Surface.lock()lock the Surface memory for pixel access - lock the Surface memory for pixel +access method.

+
+ +
+
+pygame.surfarray.array_blue()
+
+
Copy blue pixels into a 2d array
+
array_blue(Surface) -> array
+
+

Copy the pixel blue values from a Surface into a 2D array. This will work +for any type of Surface format.

+

This function will temporarily lock the Surface as pixels are copied (see +the pygame.Surface.lock()lock the Surface memory for pixel access - lock the Surface memory for pixel +access method).

+
+

New in pygame 2.0.2.

+
+
+ +
+
+pygame.surfarray.pixels_blue()
+
+
Reference pixel blue into a 2d array.
+
pixels_blue (Surface) -> array
+
+

Create a new 2D array that directly references the blue values in a Surface. +Any changes to the array will affect the pixels in the Surface. This is a +fast operation since no data is copied.

+

This can only work on 24-bit or 32-bit Surfaces.

+

The Surface this references will remain locked for the lifetime of the array, +since the array generated by this function shares memory with the surface. +See the pygame.Surface.lock()lock the Surface memory for pixel access - lock the Surface memory for pixel +access method.

+
+ +
+
+pygame.surfarray.array_colorkey()
+
+
Copy the colorkey values into a 2d array
+
array_colorkey(Surface) -> array
+
+

Create a new array with the colorkey transparency value from each pixel. If +the pixel matches the colorkey it will be fully transparent; otherwise it +will be fully opaque.

+

This will work on any type of Surface format. If the image has no colorkey a +solid opaque array will be returned.

+

This function will temporarily lock the Surface as pixels are copied.

+
+ +
+
+pygame.surfarray.make_surface()
+
+
Copy an array to a new surface
+
make_surface(array) -> Surface
+
+

Create a new Surface that best resembles the data and format on the array. +The array can be 2D or 3D with any sized integer values. Function +make_surface uses the array struct interface to acquire array properties, +so is not limited to just NumPy arrays. See pygame.pixelcopypygame module for general pixel array copying.

+

New in pygame 1.9.2: array struct interface support.

+
+ +
+
+pygame.surfarray.blit_array()
+
+
Blit directly from a array values
+
blit_array(Surface, array) -> None
+
+

Directly copy values from an array into a Surface. This is faster than +converting the array into a Surface and blitting. The array must be the same +dimensions as the Surface and will completely replace all pixel values. Only +integer, ASCII character and record arrays are accepted.

+

This function will temporarily lock the Surface as the new values are +copied.

+
+ +
+
+pygame.surfarray.map_array()
+
+
Map a 3d array into a 2d array
+
map_array(Surface, array3d) -> array2d
+
+

Convert a 3D array into a 2D array. This will use the given Surface format +to control the conversion. Palette surface formats are supported for NumPy +arrays.

+
+ +
+
+pygame.surfarray.use_arraytype()
+
+
Sets the array system to be used for surface arrays
+
use_arraytype (arraytype) -> None
+
+

DEPRECATED: Uses the requested array type for the module functions. +The only supported arraytype is 'numpy'. Other values will raise +ValueError. Using this function will raise a DeprecationWarning.

+
+ +
+
+pygame.surfarray.get_arraytype()
+
+
Gets the currently active array type.
+
get_arraytype () -> str
+
+

DEPRECATED: Returns the currently active array type. This will be a value of the +get_arraytypes() tuple and indicates which type of array module is used +for the array creation. Using this function will raise a DeprecationWarning.

+
+

New in pygame 1.8.

+
+
+ +
+
+pygame.surfarray.get_arraytypes()
+
+
Gets the array system types currently supported.
+
get_arraytypes () -> tuple
+
+

DEPRECATED: Checks, which array systems are available and returns them as a tuple of +strings. The values of the tuple can be used directly in the +pygame.surfarray.use_arraytype()Sets the array system to be used for surface arrays () method. If no supported array +system could be found, None will be returned. Using this function will raise a +DeprecationWarning.

+
+

New in pygame 1.8.

+
+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/tests.html b/venv/Lib/site-packages/pygame/docs/generated/ref/tests.html new file mode 100644 index 0000000..ad9bc67 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/tests.html @@ -0,0 +1,241 @@ + + + + + + + + + pygame.tests — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.tests
+
+
Pygame unit test suite package
+
+ +++++ + + + + + + +
+Run the pygame unit test suite
+

A quick way to run the test suite package from the command line is to import +the go submodule with the Python -m option:

+
python -m pygame.tests [<test options>]
+
+
+

Command line option --help displays a usage message. Available options +correspond to the pygame.tests.run()Run the pygame unit test suite arguments.

+

The xxxx_test submodules of the tests package are unit test suites for +individual parts of pygame. Each can also be run as a main program. This is +useful if the test, such as cdrom_test, is interactive.

+

For pygame development the test suite can be run from a pygame distribution +root directory. Program run_tests.py is provided for convenience, though +test/go.py can be run directly.

+

Module level tags control which modules are included in a unit test run. Tags +are assigned to a unit test module with a corresponding <name>_tags.py module. +The tags module has the global __tags__, a list of tag names. For example, +cdrom_test.py has a tag file cdrom_tags.py containing a tags list that +has the 'interactive' string. The 'interactive' tag indicates cdrom_test.py +expects user input. It is excluded from a run_tests.py or +pygame.tests.go run. Two other tags that are excluded are 'ignore' and +'subprocess_ignore'. These two tags indicate unit tests that will not run on a +particular platform, or for which no corresponding pygame module is available. +The test runner will list each excluded module along with the tag responsible.

+
+
+pygame.tests.run()
+
+
Run the pygame unit test suite
+
run(*args, **kwds) -> tuple
+
+

Positional arguments (optional):

+
The names of tests to include. If omitted then all tests are run. Test names
+need not include the trailing '_test'.
+
+
+

Keyword arguments:

+
incomplete - fail incomplete tests (default False)
+nosubprocess - run all test suites in the current process
+               (default False, use separate subprocesses)
+dump - dump failures/errors as dict ready to eval (default False)
+file - if provided, the name of a file into which to dump failures/errors
+timings - if provided, the number of times to run each individual test to
+          get an average run time (default is run each test once)
+exclude - A list of TAG names to exclude from the run
+show_output - show silenced stderr/stdout on errors (default False)
+all - dump all results, not just errors (default False)
+randomize - randomize order of tests (default False)
+seed - if provided, a seed randomizer integer
+multi_thread - if provided, the number of THREADS in which to run
+               subprocessed tests
+time_out - if subprocess is True then the time limit in seconds before
+           killing a test (default 30)
+fake - if provided, the name of the fake tests package in the
+       run_tests__tests subpackage to run instead of the normal
+       pygame tests
+python - the path to a python executable to run subprocessed tests
+         (default sys.executable)
+
+
+

Return value:

+
A tuple of total number of tests run, dictionary of error information.
+The dictionary is empty if no errors were recorded.
+
+
+

By default individual test modules are run in separate subprocesses. This +recreates normal pygame usage where pygame.init() and pygame.quit() +are called only once per program execution, and avoids unfortunate +interactions between test modules. Also, a time limit is placed on test +execution, so frozen tests are killed when there time allotment expired. Use +the single process option if threading is not working properly or if tests +are taking too long. It is not guaranteed that all tests will pass in single +process mode.

+

Tests are run in a randomized order if the randomize argument is True or a +seed argument is provided. If no seed integer is provided then the system +time is used.

+

Individual test modules may have a __tags__ attribute, a list of tag strings +used to selectively omit modules from a run. By default only 'interactive' +modules such as cdrom_test are ignored. An interactive module must be run +from the console as a Python program.

+

This function can only be called once per Python session. It is not +reentrant.

+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/time.html b/venv/Lib/site-packages/pygame/docs/generated/ref/time.html new file mode 100644 index 0000000..112d5f7 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/time.html @@ -0,0 +1,370 @@ + + + + + + + + + pygame.time — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.time
+
+
pygame module for monitoring time
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + +
+get the time in milliseconds
+pause the program for an amount of time
+pause the program for an amount of time
+repeatedly create an event on the event queue
+create an object to help track time
+

Times in pygame are represented in milliseconds (1/1000 seconds). Most +platforms have a limited time resolution of around 10 milliseconds. This +resolution, in milliseconds, is given in the TIMER_RESOLUTION constant.

+
+
+pygame.time.get_ticks()
+
+
get the time in milliseconds
+
get_ticks() -> milliseconds
+
+

Return the number of milliseconds since pygame.init() was called. Before +pygame is initialized this will always be 0.

+
+ +
+
+pygame.time.wait()
+
+
pause the program for an amount of time
+
wait(milliseconds) -> time
+
+

Will pause for a given number of milliseconds. This function sleeps the +process to share the processor with other programs. A program that waits for +even a few milliseconds will consume very little processor time. It is +slightly less accurate than the pygame.time.delay() function.

+

This returns the actual number of milliseconds used.

+
+ +
+
+pygame.time.delay()
+
+
pause the program for an amount of time
+
delay(milliseconds) -> time
+
+

Will pause for a given number of milliseconds. This function will use the +processor (rather than sleeping) in order to make the delay more accurate +than pygame.time.wait().

+

This returns the actual number of milliseconds used.

+
+ +
+
+pygame.time.set_timer()
+
+
repeatedly create an event on the event queue
+
set_timer(event, millis) -> None
+
set_timer(event, millis, loops=0) -> None
+
+

Set an event to appear on the event queue every given number of milliseconds. +The first event will not appear until the amount of time has passed.

+

The event attribute can be a pygame.event.Event object or an integer +type that denotes an event.

+

loops is an integer that denotes the number of events posted. If 0 (default) +then the events will keep getting posted, unless explicitly stopped.

+

To disable the timer for such an event, call the function again with the same +event argument with millis argument set to 0.

+

It is also worth mentioning that a particular event type can only be put on a +timer once. In other words, there cannot be two timers for the same event type. +Setting an event timer for a particular event discards the old one for that +event type.

+

loops replaces the once argument, and this does not break backward +compatability

+
+

New in pygame 2.0.0.dev3: once argument added.

+
+
+

Changed in pygame 2.0.1: event argument supports pygame.event.Event object

+
+
+

New in pygame 2.0.1: added loops argument to replace once argument

+
+
+ +
+
+pygame.time.Clock
+
+
create an object to help track time
+
Clock() -> Clock
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + +
+update the clock
+update the clock
+time used in the previous tick
+actual time used in the previous tick
+compute the clock framerate
+

Creates a new Clock object that can be used to track an amount of time. The +clock also provides several functions to help control a game's framerate.

+
+
+tick()
+
+
update the clock
+
tick(framerate=0) -> milliseconds
+
+

This method should be called once per frame. It will compute how many +milliseconds have passed since the previous call.

+

If you pass the optional framerate argument the function will delay to +keep the game running slower than the given ticks per second. This can be +used to help limit the runtime speed of a game. By calling +Clock.tick(40) once per frame, the program will never run at more +than 40 frames per second.

+

Note that this function uses SDL_Delay function which is not accurate on +every platform, but does not use much CPU. Use tick_busy_loop if you want +an accurate timer, and don't mind chewing CPU.

+
+ +
+
+tick_busy_loop()
+
+
update the clock
+
tick_busy_loop(framerate=0) -> milliseconds
+
+

This method should be called once per frame. It will compute how many +milliseconds have passed since the previous call.

+

If you pass the optional framerate argument the function will delay to +keep the game running slower than the given ticks per second. This can be +used to help limit the runtime speed of a game. By calling +Clock.tick_busy_loop(40) once per frame, the program will never run at +more than 40 frames per second.

+

Note that this function uses pygame.time.delay()pause the program for an amount of time, which uses lots +of CPU in a busy loop to make sure that timing is more accurate.

+
+

New in pygame 1.8.

+
+
+ +
+
+get_time()
+
+
time used in the previous tick
+
get_time() -> milliseconds
+
+

The number of milliseconds that passed between the previous two calls to +Clock.tick().

+
+ +
+
+get_rawtime()
+
+
actual time used in the previous tick
+
get_rawtime() -> milliseconds
+
+

Similar to Clock.get_time(), but does not include any time used +while Clock.tick() was delaying to limit the framerate.

+
+ +
+
+get_fps()
+
+
compute the clock framerate
+
get_fps() -> float
+
+

Compute your game's framerate (in frames per second). It is computed by +averaging the last ten calls to Clock.tick().

+
+ +
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/touch.html b/venv/Lib/site-packages/pygame/docs/generated/ref/touch.html new file mode 100644 index 0000000..198a5ff --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/touch.html @@ -0,0 +1,240 @@ + + + + + + + + + pygame._sdl2.touch — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame._sdl2.touch
+
+
pygame module to work with touch input
+
+ +++++ + + + + + + + + + + + + + + + + + + +
+get the number of touch devices
+get the a touch device id for a given index
+the number of active fingers for a given touch device
+get information about an active finger
+
+

New in pygame 2: This module requires SDL2.

+
+
+
+pygame._sdl2.touch.get_num_devices()
+
+
get the number of touch devices
+
get_num_devices() -> int
+
+

Return the number of available touch devices.

+
+ +
+
+pygame._sdl2.touch.get_device()
+
+
get the a touch device id for a given index
+
get_device(index) -> touchid
+
+
+
Parameters
+

index (int) -- This number is at least 0 and less than the +number of devices.

+
+
+

Return an integer id associated with the given index.

+
+ +
+
+pygame._sdl2.touch.get_num_fingers()
+
+
the number of active fingers for a given touch device
+
get_num_fingers(touchid) -> int
+
+

Return the number of fingers active for the touch device +whose id is touchid.

+
+ +
+
+pygame._sdl2.touch.get_finger()
+
+
get information about an active finger
+
get_finger(touchid, index) -> int
+
+
+
Parameters
+
    +
  • touchid (int) -- The touch device id.

  • +
  • index (int) -- The index of the finger to return +information about, between 0 and the +number of active fingers.

  • +
+
+
+

Return a dict for the finger index active on touchid. +The dict contains these keys:

+
id         the id of the finger (an integer).
+x          the normalized x position of the finger, between 0 and 1.
+y          the normalized y position of the finger, between 0 and 1.
+pressure   the amount of pressure applied by the finger, between 0 and 1.
+
+
+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/ref/transform.html b/venv/Lib/site-packages/pygame/docs/generated/ref/transform.html new file mode 100644 index 0000000..da5a1a5 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/ref/transform.html @@ -0,0 +1,535 @@ + + + + + + + + + pygame.transform — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+
+pygame.transform
+
+
pygame module to transform surfaces
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+flip vertically and horizontally
+resize to new resolution
+rotate an image
+filtered scale and rotation
+specialized image doubler
+scale a surface to an arbitrary size smoothly
+return smoothscale filter version in use: 'GENERIC', 'MMX', or 'SSE'
+set smoothscale filter version to one of: 'GENERIC', 'MMX', or 'SSE'
+gets a copy of an image with an interior area removed
+find edges in a surface
+find the average surface from many surfaces.
+finds the average color of a surface
+finds which, and how many pixels in a surface are within a threshold of a 'search_color' or a 'search_surf'.
+

A Surface transform is an operation that moves or resizes the pixels. All these +functions take a Surface to operate on and return a new Surface with the +results.

+

Some of the transforms are considered destructive. These means every time they +are performed they lose pixel data. Common examples of this are resizing and +rotating. For this reason, it is better to re-transform the original surface +than to keep transforming an image multiple times. (For example, suppose you +are animating a bouncing spring which expands and contracts. If you applied the +size changes incrementally to the previous images, you would lose detail. +Instead, always begin with the original image and scale to the desired size.)

+
+

Changed in pygame 2.0.2: transform functions now support keyword arguments.

+
+
+
+pygame.transform.flip()
+
+
flip vertically and horizontally
+
flip(surface, flip_x, flip_y) -> Surface
+
+

This can flip a Surface either vertically, horizontally, or both. +The arguments flip_x and flip_y are booleans that control whether +to flip each axis. Flipping a Surface is non-destructive and returns a new +Surface with the same dimensions.

+
+ +
+
+pygame.transform.scale()
+
+
resize to new resolution
+
scale(surface, size, dest_surface=None) -> Surface
+
+

Resizes the Surface to a new size, given as (width, height). +This is a fast scale operation that does not sample the results.

+

An optional destination surface can be used, rather than have it create a +new one. This is quicker if you want to repeatedly scale something. However +the destination must be the same size as the size (width, height) passed in. Also +the destination surface must be the same format.

+
+ +
+
+pygame.transform.rotate()
+
+
rotate an image
+
rotate(surface, angle) -> Surface
+
+

Unfiltered counterclockwise rotation. The angle argument represents degrees +and can be any floating point value. Negative angle amounts will rotate +clockwise.

+

Unless rotating by 90 degree increments, the image will be padded larger to +hold the new size. If the image has pixel alphas, the padded area will be +transparent. Otherwise pygame will pick a color that matches the Surface +colorkey or the topleft pixel value.

+
+ +
+
+pygame.transform.rotozoom()
+
+
filtered scale and rotation
+
rotozoom(surface, angle, scale) -> Surface
+
+

This is a combined scale and rotation transform. The resulting Surface will +be a filtered 32-bit Surface. The scale argument is a floating point value +that will be multiplied by the current resolution. The angle argument is a +floating point value that represents the counterclockwise degrees to rotate. +A negative rotation angle will rotate clockwise.

+
+ +
+
+pygame.transform.scale2x()
+
+
specialized image doubler
+
scale2x(surface, dest_surface=None) -> Surface
+
+

This will return a new image that is double the size of the original. It +uses the AdvanceMAME Scale2X algorithm which does a 'jaggie-less' scale of +bitmap graphics.

+

This really only has an effect on simple images with solid colors. On +photographic and antialiased images it will look like a regular unfiltered +scale.

+

An optional destination surface can be used, rather than have it create a +new one. This is quicker if you want to repeatedly scale something. However +the destination must be twice the size of the source surface passed in. Also +the destination surface must be the same format.

+
+ +
+
+pygame.transform.smoothscale()
+
+
scale a surface to an arbitrary size smoothly
+
smoothscale(surface, size, dest_surface=None) -> Surface
+
+

Uses one of two different algorithms for scaling each dimension of the input +surface as required. For shrinkage, the output pixels are area averages of +the colors they cover. For expansion, a bilinear filter is used. For the +x86-64 and i686 architectures, optimized MMX routines are included and +will run much faster than other machine types. The size is a 2 number +sequence for (width, height). This function only works for 24-bit or 32-bit +surfaces. An exception will be thrown if the input surface bit depth is less +than 24.

+
+

New in pygame 1.8.

+
+
+ +
+
+pygame.transform.get_smoothscale_backend()
+
+
return smoothscale filter version in use: 'GENERIC', 'MMX', or 'SSE'
+
get_smoothscale_backend() -> string
+
+

Shows whether or not smoothscale is using MMX or SSE acceleration. +If no acceleration is available then "GENERIC" is returned. For a x86 +processor the level of acceleration to use is determined at runtime.

+

This function is provided for pygame testing and debugging.

+
+ +
+
+pygame.transform.set_smoothscale_backend()
+
+
set smoothscale filter version to one of: 'GENERIC', 'MMX', or 'SSE'
+
set_smoothscale_backend(backend) -> None
+
+

Sets smoothscale acceleration. Takes a string argument. A value of 'GENERIC' +turns off acceleration. 'MMX' uses MMX instructions only. 'SSE' allows +SSE extensions as well. A value error is raised if type is not +recognized or not supported by the current processor.

+

This function is provided for pygame testing and debugging. If smoothscale +causes an invalid instruction error then it is a pygame/SDL bug that should +be reported. Use this function as a temporary fix only.

+
+ +
+
+pygame.transform.chop()
+
+
gets a copy of an image with an interior area removed
+
chop(surface, rect) -> Surface
+
+

Extracts a portion of an image. All vertical and horizontal pixels +surrounding the given rectangle area are removed. The corner areas (diagonal +to the rect) are then brought together. (The original image is not altered +by this operation.)

+

NOTE: If you want a "crop" that returns the part of an image within a +rect, you can blit with a rect to a new surface or copy a subsurface.

+
+ +
+
+pygame.transform.laplacian()
+
+
find edges in a surface
+
laplacian(surface, dest_surface=None) -> Surface
+
+

Finds the edges in a surface using the laplacian algorithm.

+
+

New in pygame 1.8.

+
+
+ +
+
+pygame.transform.average_surfaces()
+
+
find the average surface from many surfaces.
+
average_surfaces(surfaces, dest_surface=None, palette_colors=1) -> Surface
+
+

Takes a sequence of surfaces and returns a surface with average colors from +each of the surfaces.

+

palette_colors - if true we average the colors in palette, otherwise we +average the pixel values. This is useful if the surface is actually +greyscale colors, and not palette colors.

+

Note, this function currently does not handle palette using surfaces +correctly.

+
+

New in pygame 1.8.

+
+
+

New in pygame 1.9: palette_colors argument

+
+
+ +
+
+pygame.transform.average_color()
+
+
finds the average color of a surface
+
average_color(surface, rect=None) -> Color
+
+

Finds the average color of a Surface or a region of a surface specified by a +Rect, and returns it as a Color.

+
+ +
+
+pygame.transform.threshold()
+
+
finds which, and how many pixels in a surface are within a threshold of a 'search_color' or a 'search_surf'.
+
threshold(dest_surface, surface, search_color, threshold=(0,0,0,0), set_color=(0,0,0,0), set_behavior=1, search_surf=None, inverse_set=False) -> num_threshold_pixels
+
+

This versatile function can be used for find colors in a 'surf' close to a 'search_color' +or close to colors in a separate 'search_surf'.

+

It can also be used to transfer pixels into a 'dest_surf' that match or don't match.

+

By default it sets pixels in the 'dest_surf' where all of the pixels NOT within the +threshold are changed to set_color. If inverse_set is optionally set to True, +the pixels that ARE within the threshold are changed to set_color.

+

If the optional 'search_surf' surface is given, it is used to threshold against +rather than the specified 'set_color'. That is, it will find each pixel in the +'surf' that is within the 'threshold' of the pixel at the same coordinates +of the 'search_surf'.

+
+
Parameters
+
+
+
Return type
+

int

+
+
Returns
+

The number of pixels that are within the 'threshold' in 'surf' +compared to either 'search_color' or search_surf.

+
+
Examples
+

+
+

See the threshold tests for a full of examples: https://github.com/pygame/pygame/blob/master/test/transform_test.py

+
    def test_threshold_dest_surf_not_change(self):
+        """the pixels within the threshold.
+
+        All pixels not within threshold are changed to set_color.
+        So there should be none changed in this test.
+        """
+        (w, h) = size = (32, 32)
+        threshold = (20, 20, 20, 20)
+        original_color = (25, 25, 25, 25)
+        original_dest_color = (65, 65, 65, 55)
+        threshold_color = (10, 10, 10, 10)
+        set_color = (255, 10, 10, 10)
+
+        surf = pygame.Surface(size, pygame.SRCALPHA, 32)
+        dest_surf = pygame.Surface(size, pygame.SRCALPHA, 32)
+        search_surf = pygame.Surface(size, pygame.SRCALPHA, 32)
+
+        surf.fill(original_color)
+        search_surf.fill(threshold_color)
+        dest_surf.fill(original_dest_color)
+
+        # set_behavior=1, set dest_surface from set_color.
+        # all within threshold of third_surface, so no color is set.
+
+        THRESHOLD_BEHAVIOR_FROM_SEARCH_COLOR = 1
+        pixels_within_threshold = pygame.transform.threshold(
+            dest_surface=dest_surf,
+            surface=surf,
+            search_color=None,
+            threshold=threshold,
+            set_color=set_color,
+            set_behavior=THRESHOLD_BEHAVIOR_FROM_SEARCH_COLOR,
+            search_surf=search_surf,
+        )
+
+        # # Return, of pixels within threshold is correct
+        self.assertEqual(w * h, pixels_within_threshold)
+
+        # # Size of dest surface is correct
+        dest_rect = dest_surf.get_rect()
+        dest_size = dest_rect.size
+        self.assertEqual(size, dest_size)
+
+        # The color is not the change_color specified for every pixel As all
+        # pixels are within threshold
+
+        for pt in test_utils.rect_area_pts(dest_rect):
+            self.assertNotEqual(dest_surf.get_at(pt), set_color)
+            self.assertEqual(dest_surf.get_at(pt), original_dest_color)
+
+
+
+

New in pygame 1.8.

+
+
+

Changed in pygame 1.9.4: Fixed a lot of bugs and added keyword arguments. Test your code.

+
+
+ +
+ +
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/search.html b/venv/Lib/site-packages/pygame/docs/generated/search.html new file mode 100644 index 0000000..1f1e1b3 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/search.html @@ -0,0 +1,96 @@ + + + + + + + + Search — pygame v2.1.2 documentation + + + + + + + + + + + + + + + + + + +
+
+
+ +

Search

+ + + + +

+ Searching for multiple words only shows matches that contain + all words. +

+ + +
+ + + +
+ + + +
+ +
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/searchindex.js b/venv/Lib/site-packages/pygame/docs/generated/searchindex.js new file mode 100644 index 0000000..16b2a61 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["c_api","c_api/base","c_api/bufferproxy","c_api/cdrom","c_api/color","c_api/display","c_api/event","c_api/freetype","c_api/mixer","c_api/rect","c_api/rwobject","c_api/slots","c_api/surface","c_api/surflock","c_api/version","filepaths","index","ref/bufferproxy","ref/camera","ref/cdrom","ref/color","ref/color_list","ref/cursors","ref/display","ref/draw","ref/event","ref/examples","ref/fastevent","ref/font","ref/freetype","ref/gfxdraw","ref/image","ref/joystick","ref/key","ref/locals","ref/mask","ref/math","ref/midi","ref/mixer","ref/mouse","ref/music","ref/overlay","ref/pixelarray","ref/pixelcopy","ref/pygame","ref/rect","ref/scrap","ref/sdl2_controller","ref/sdl2_video","ref/sndarray","ref/sprite","ref/surface","ref/surfarray","ref/tests","ref/time","ref/touch","ref/transform","tut/CameraIntro","tut/ChimpLineByLine","tut/DisplayModes","tut/ImportInit","tut/MakeGames","tut/MoveIt","tut/PygameIntro","tut/SpriteIntro","tut/SurfarrayIntro","tut/chimp.py","tut/en/Red_or_Black/1.Prolog/introduction","tut/en/Red_or_Black/2.Print_text/Basic TEMPLATE and OUTPUT","tut/en/Red_or_Black/3.Move_text/Basic PROCESS","tut/en/Red_or_Black/4.Control_text/Basic INPUT","tut/en/Red_or_Black/5.HP_bar/Advanced OUTPUT with Advanced PROCESS","tut/en/Red_or_Black/6.Buttons/Advanced INPUT with Advanced OUTPUT","tut/en/Red_or_Black/7.Game_board/Advanced OUTPUT and plus alpha","tut/en/Red_or_Black/8.Epilog/Epilog","tut/ko/\ube68\uac04\ube14\ub85d \uac80\uc740\ube14\ub85d/1.\ud504\ub864\ub85c\uadf8/\uc18c\uac1c","tut/ko/\ube68\uac04\ube14\ub85d \uac80\uc740\ube14\ub85d/2.\ud14d\uc2a4\ud2b8 \ucd9c\ub825/\uae30\ucd08 \ud15c\ud50c\ub9bf\uacfc \ucd9c\ub825","tut/ko/\ube68\uac04\ube14\ub85d \uac80\uc740\ube14\ub85d/3.\ud14d\uc2a4\ud2b8 \uc774\ub3d9/\uae30\ucd08 \ucc98\ub9ac","tut/ko/\ube68\uac04\ube14\ub85d \uac80\uc740\ube14\ub85d/4.\ud14d\uc2a4\ud2b8 \uc870\uc885/\uae30\ucd08 \uc785\ub825","tut/ko/\ube68\uac04\ube14\ub85d \uac80\uc740\ube14\ub85d/5.HP\ubc14/\uc2ec\ud654 \ucd9c\ub825 \uadf8\ub9ac\uace0 \uc2ec\ud654 \ucc98\ub9ac","tut/ko/\ube68\uac04\ube14\ub85d \uac80\uc740\ube14\ub85d/6.\ubc84\ud2bc\ub4e4/\uc2ec\ud654 \uc785\ub825 \uadf8\ub9ac\uace0 \uc2ec\ud654 \ucd9c\ub825","tut/ko/\ube68\uac04\ube14\ub85d \uac80\uc740\ube14\ub85d/7.\uac8c\uc784\ud310/\uc2ec\ud654 \ucd9c\ub825 \uadf8\ub9ac\uace0 \uc870\uae08 \ub354","tut/ko/\ube68\uac04\ube14\ub85d \uac80\uc740\ube14\ub85d/8.\uc5d0\ud544\ub85c\uadf8/\uc5d0\ud544\ub85c\uadf8","tut/ko/\ube68\uac04\ube14\ub85d \uac80\uc740\ube14\ub85d/overview","tut/newbieguide","tut/tom_games2","tut/tom_games3","tut/tom_games4","tut/tom_games5","tut/tom_games6"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":4,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":3,"sphinx.domains.rst":2,"sphinx.domains.std":2,sphinx:56},filenames:["c_api.rst","c_api\\base.rst","c_api\\bufferproxy.rst","c_api\\cdrom.rst","c_api\\color.rst","c_api\\display.rst","c_api\\event.rst","c_api\\freetype.rst","c_api\\mixer.rst","c_api\\rect.rst","c_api\\rwobject.rst","c_api\\slots.rst","c_api\\surface.rst","c_api\\surflock.rst","c_api\\version.rst","filepaths.rst","index.rst","ref\\bufferproxy.rst","ref\\camera.rst","ref\\cdrom.rst","ref\\color.rst","ref\\color_list.rst","ref\\cursors.rst","ref\\display.rst","ref\\draw.rst","ref\\event.rst","ref\\examples.rst","ref\\fastevent.rst","ref\\font.rst","ref\\freetype.rst","ref\\gfxdraw.rst","ref\\image.rst","ref\\joystick.rst","ref\\key.rst","ref\\locals.rst","ref\\mask.rst","ref\\math.rst","ref\\midi.rst","ref\\mixer.rst","ref\\mouse.rst","ref\\music.rst","ref\\overlay.rst","ref\\pixelarray.rst","ref\\pixelcopy.rst","ref\\pygame.rst","ref\\rect.rst","ref\\scrap.rst","ref\\sdl2_controller.rst","ref\\sdl2_video.rst","ref\\sndarray.rst","ref\\sprite.rst","ref\\surface.rst","ref\\surfarray.rst","ref\\tests.rst","ref\\time.rst","ref\\touch.rst","ref\\transform.rst","tut\\CameraIntro.rst","tut\\ChimpLineByLine.rst","tut\\DisplayModes.rst","tut\\ImportInit.rst","tut\\MakeGames.rst","tut\\MoveIt.rst","tut\\PygameIntro.rst","tut\\SpriteIntro.rst","tut\\SurfarrayIntro.rst","tut\\chimp.py.rst","tut\\en\\Red_or_Black\\1.Prolog\\introduction.rst","tut\\en\\Red_or_Black\\2.Print_text\\Basic TEMPLATE and OUTPUT.rst","tut\\en\\Red_or_Black\\3.Move_text\\Basic PROCESS.rst","tut\\en\\Red_or_Black\\4.Control_text\\Basic INPUT.rst","tut\\en\\Red_or_Black\\5.HP_bar\\Advanced OUTPUT with Advanced PROCESS.rst","tut\\en\\Red_or_Black\\6.Buttons\\Advanced INPUT with Advanced OUTPUT.rst","tut\\en\\Red_or_Black\\7.Game_board\\Advanced OUTPUT and plus alpha.rst","tut\\en\\Red_or_Black\\8.Epilog\\Epilog.rst","tut\\ko\\\ube68\uac04\ube14\ub85d \uac80\uc740\ube14\ub85d\\1.\ud504\ub864\ub85c\uadf8\\\uc18c\uac1c.rst","tut\\ko\\\ube68\uac04\ube14\ub85d \uac80\uc740\ube14\ub85d\\2.\ud14d\uc2a4\ud2b8 \ucd9c\ub825\\\uae30\ucd08 \ud15c\ud50c\ub9bf\uacfc \ucd9c\ub825.rst","tut\\ko\\\ube68\uac04\ube14\ub85d \uac80\uc740\ube14\ub85d\\3.\ud14d\uc2a4\ud2b8 \uc774\ub3d9\\\uae30\ucd08 \ucc98\ub9ac.rst","tut\\ko\\\ube68\uac04\ube14\ub85d \uac80\uc740\ube14\ub85d\\4.\ud14d\uc2a4\ud2b8 \uc870\uc885\\\uae30\ucd08 \uc785\ub825.rst","tut\\ko\\\ube68\uac04\ube14\ub85d \uac80\uc740\ube14\ub85d\\5.HP\ubc14\\\uc2ec\ud654 \ucd9c\ub825 \uadf8\ub9ac\uace0 \uc2ec\ud654 \ucc98\ub9ac.rst","tut\\ko\\\ube68\uac04\ube14\ub85d \uac80\uc740\ube14\ub85d\\6.\ubc84\ud2bc\ub4e4\\\uc2ec\ud654 \uc785\ub825 \uadf8\ub9ac\uace0 \uc2ec\ud654 \ucd9c\ub825.rst","tut\\ko\\\ube68\uac04\ube14\ub85d \uac80\uc740\ube14\ub85d\\7.\uac8c\uc784\ud310\\\uc2ec\ud654 \ucd9c\ub825 \uadf8\ub9ac\uace0 \uc870\uae08 \ub354.rst","tut\\ko\\\ube68\uac04\ube14\ub85d \uac80\uc740\ube14\ub85d\\8.\uc5d0\ud544\ub85c\uadf8\\\uc5d0\ud544\ub85c\uadf8.rst","tut\\ko\\\ube68\uac04\ube14\ub85d \uac80\uc740\ube14\ub85d\\overview.rst","tut\\newbieguide.rst","tut\\tom_games2.rst","tut\\tom_games3.rst","tut\\tom_games4.rst","tut\\tom_games5.rst","tut\\tom_games6.rst"],objects:{"":[[14,0,1,"c.PG_MAJOR_VERSION","PG_MAJOR_VERSION"],[14,0,1,"c.PG_MINOR_VERSION","PG_MINOR_VERSION"],[14,0,1,"c.PG_PATCH_VERSION","PG_PATCH_VERSION"],[14,0,1,"c.PG_VERSIONNUM","PG_VERSIONNUM"],[14,0,1,"c.PG_VERSION_ATLEAST","PG_VERSION_ATLEAST"],[1,1,1,"c.import_pygame_base","import_pygame_base"],[1,1,1,"c.pgBuffer_AsArrayInterface","pgBuffer_AsArrayInterface"],[1,1,1,"c.pgBuffer_AsArrayStruct","pgBuffer_AsArrayStruct"],[1,1,1,"c.pgBuffer_Release","pgBuffer_Release"],[2,1,1,"c.pgBufproxy_Check","pgBufproxy_Check"],[2,1,1,"c.pgBufproxy_GetParent","pgBufproxy_GetParent"],[2,1,1,"c.pgBufproxy_New","pgBufproxy_New"],[2,1,1,"c.pgBufproxy_Trip","pgBufproxy_Trip"],[2,3,1,"c.pgBufproxy_Type","pgBufproxy_Type"],[3,4,1,"c.pgCDObject","pgCDObject"],[3,1,1,"c.pgCD_AsID","pgCD_AsID"],[3,1,1,"c.pgCD_Check","pgCD_Check"],[3,1,1,"c.pgCD_New","pgCD_New"],[3,3,1,"c.pgCD_Type","pgCD_Type"],[8,4,1,"c.pgChannelObject","pgChannelObject"],[8,1,1,"c.pgChannel_AsInt","pgChannel_AsInt"],[8,1,1,"c.pgChannel_Check","pgChannel_Check"],[8,1,1,"c.pgChannel_New","pgChannel_New"],[8,3,1,"c.pgChannel_Type","pgChannel_Type"],[4,1,1,"c.pgColor_Check","pgColor_Check"],[4,1,1,"c.pgColor_New","pgColor_New"],[4,1,1,"c.pgColor_NewLength","pgColor_NewLength"],[4,3,1,"c.pgColor_Type","pgColor_Type"],[1,1,1,"c.pgDict_AsBuffer","pgDict_AsBuffer"],[6,4,1,"c.pgEventObject","pgEventObject"],[6,1,1,"c.pgEvent_Check","pgEvent_Check"],[6,1,1,"c.pgEvent_FillUserEvent","pgEvent_FillUserEvent"],[6,1,1,"c.pgEvent_New","pgEvent_New"],[6,1,1,"c.pgEvent_New2","pgEvent_New2"],[6,4,1,"c.pgEvent_Type","pgEvent_Type"],[1,3,1,"c.pgExc_BufferError","pgExc_BufferError"],[1,3,1,"c.pgExc_SDLError","pgExc_SDLError"],[7,4,1,"c.pgFontObject","pgFontObject"],[7,1,1,"c.pgFont_Check","pgFont_Check"],[7,1,1,"c.pgFont_IS_ALIVE","pgFont_IS_ALIVE"],[7,1,1,"c.pgFont_New","pgFont_New"],[7,4,1,"c.pgFont_Type","pgFont_Type"],[13,4,1,"c.pgLifetimeLockObject","pgLifetimeLockObject"],[13,1,1,"c.pgLifetimeLock_Check","pgLifetimeLock_Check"],[13,3,1,"c.pgLifetimeLock_Type","pgLifetimeLock_Type"],[1,1,1,"c.pgObject_GetBuffer","pgObject_GetBuffer"],[10,1,1,"c.pgRWops_FromFileObject","pgRWops_FromFileObject"],[10,1,1,"c.pgRWops_FromObject","pgRWops_FromObject"],[10,1,1,"c.pgRWops_GetFileExtension","pgRWops_GetFileExtension"],[10,1,1,"c.pgRWops_IsFileObject","pgRWops_IsFileObject"],[10,1,1,"c.pgRWops_ReleaseObject","pgRWops_ReleaseObject"],[9,4,1,"c.pgRectObject","pgRectObject"],[9,1,1,"c.pgRect_AsRect","pgRect_AsRect"],[9,1,1,"c.pgRect_FromObject","pgRect_FromObject"],[9,1,1,"c.pgRect_New","pgRect_New"],[9,1,1,"c.pgRect_New4","pgRect_New4"],[9,1,1,"c.pgRect_Normalize","pgRect_Normalize"],[9,3,1,"c.pgRect_Type","pgRect_Type"],[8,4,1,"c.pgSoundObject","pgSoundObject"],[8,1,1,"c.pgSound_AsChunk","pgSound_AsChunk"],[8,1,1,"c.pgSound_Check","pgSound_Check"],[8,1,1,"c.pgSound_New","pgSound_New"],[8,3,1,"c.pgSound_Type","pgSound_Type"],[12,4,1,"c.pgSurfaceObject","pgSurfaceObject"],[12,1,1,"c.pgSurface_AsSurface","pgSurface_AsSurface"],[12,1,1,"c.pgSurface_Blit","pgSurface_Blit"],[12,1,1,"c.pgSurface_Check","pgSurface_Check"],[13,1,1,"c.pgSurface_Lock","pgSurface_Lock"],[13,1,1,"c.pgSurface_LockBy","pgSurface_LockBy"],[13,1,1,"c.pgSurface_LockLifetime","pgSurface_LockLifetime"],[12,1,1,"c.pgSurface_New","pgSurface_New"],[13,1,1,"c.pgSurface_Prep","pgSurface_Prep"],[12,3,1,"c.pgSurface_Type","pgSurface_Type"],[13,1,1,"c.pgSurface_UnLock","pgSurface_UnLock"],[13,1,1,"c.pgSurface_UnLockBy","pgSurface_UnLockBy"],[13,1,1,"c.pgSurface_Unprep","pgSurface_Unprep"],[5,4,1,"c.pgVidInfoObject","pgVidInfoObject"],[5,1,1,"c.pgVidInfo_AsVidInfo","pgVidInfo_AsVidInfo"],[5,1,1,"c.pgVidInfo_Check","pgVidInfo_Check"],[5,1,1,"c.pgVidInfo_New","pgVidInfo_New"],[5,3,1,"c.pgVidInfo_Type","pgVidInfo_Type"],[10,1,1,"c.pg_EncodeFilePath","pg_EncodeFilePath"],[10,1,1,"c.pg_EncodeString","pg_EncodeString"],[1,1,1,"c.pg_FloatFromObj","pg_FloatFromObj"],[1,1,1,"c.pg_FloatFromObjIndex","pg_FloatFromObjIndex"],[1,1,1,"c.pg_GetDefaultWindow","pg_GetDefaultWindow"],[1,1,1,"c.pg_GetDefaultWindowSurface","pg_GetDefaultWindowSurface"],[1,1,1,"c.pg_IntFromObj","pg_IntFromObj"],[1,1,1,"c.pg_IntFromObjIndex","pg_IntFromObjIndex"],[1,1,1,"c.pg_RGBAFromObj","pg_RGBAFromObj"],[1,1,1,"c.pg_RegisterQuit","pg_RegisterQuit"],[1,1,1,"c.pg_SetDefaultWindow","pg_SetDefaultWindow"],[1,1,1,"c.pg_SetDefaultWindowSurface","pg_SetDefaultWindowSurface"],[1,1,1,"c.pg_TwoFloatsFromObj","pg_TwoFloatsFromObj"],[1,1,1,"c.pg_TwoIntsFromObj","pg_TwoIntsFromObj"],[1,1,1,"c.pg_UintFromObj","pg_UintFromObj"],[1,1,1,"c.pg_UintFromObjIndex","pg_UintFromObjIndex"],[1,4,1,"c.pg_buffer","pg_buffer"],[1,1,1,"c.pg_mod_autoinit","pg_mod_autoinit"],[1,1,1,"c.pg_mod_autoquit","pg_mod_autoquit"],[44,5,0,"-","pygame"]],"pygame.BufferProxy":[[17,7,1,"","length"],[17,7,1,"","parent"],[17,7,1,"","raw"],[17,8,1,"","write"]],"pygame.Color":[[20,7,1,"","a"],[20,7,1,"","b"],[20,7,1,"","cmy"],[20,8,1,"","correct_gamma"],[20,7,1,"","g"],[20,7,1,"","hsla"],[20,7,1,"","hsva"],[20,7,1,"","i1i2i3"],[20,8,1,"","lerp"],[20,8,1,"","normalize"],[20,8,1,"","premul_alpha"],[20,7,1,"","r"],[20,8,1,"","set_length"],[20,8,1,"","update"]],"pygame.Overlay":[[41,8,1,"","display"],[41,8,1,"","get_hardware"],[41,8,1,"","set_location"]],"pygame.PixelArray":[[42,8,1,"","close"],[42,8,1,"","compare"],[42,8,1,"","extract"],[42,7,1,"","itemsize"],[42,8,1,"","make_surface"],[42,7,1,"","ndim"],[42,8,1,"","replace"],[42,7,1,"","shape"],[42,7,1,"","strides"],[42,7,1,"","surface"],[42,8,1,"","transpose"]],"pygame.Rect":[[45,8,1,"","clamp"],[45,8,1,"","clamp_ip"],[45,8,1,"","clip"],[45,8,1,"","clipline"],[45,8,1,"","collidedict"],[45,8,1,"","collidedictall"],[45,8,1,"","collidelist"],[45,8,1,"","collidelistall"],[45,8,1,"","collidepoint"],[45,8,1,"","colliderect"],[45,8,1,"","contains"],[45,8,1,"","copy"],[45,8,1,"","fit"],[45,8,1,"","inflate"],[45,8,1,"","inflate_ip"],[45,8,1,"","move"],[45,8,1,"","move_ip"],[45,8,1,"","normalize"],[45,8,1,"","union"],[45,8,1,"","union_ip"],[45,8,1,"","unionall"],[45,8,1,"","unionall_ip"],[45,8,1,"","update"]],"pygame.Surface":[[51,7,1,"","_pixels_address"],[51,8,1,"","blit"],[51,8,1,"","blits"],[51,8,1,"","convert"],[51,8,1,"","convert_alpha"],[51,8,1,"","copy"],[51,8,1,"","fill"],[51,8,1,"","get_abs_offset"],[51,8,1,"","get_abs_parent"],[51,8,1,"","get_alpha"],[51,8,1,"","get_at"],[51,8,1,"","get_at_mapped"],[51,8,1,"","get_bitsize"],[51,8,1,"","get_bounding_rect"],[51,8,1,"","get_buffer"],[51,8,1,"","get_bytesize"],[51,8,1,"","get_clip"],[51,8,1,"","get_colorkey"],[51,8,1,"","get_flags"],[51,8,1,"","get_height"],[51,8,1,"","get_locked"],[51,8,1,"","get_locks"],[51,8,1,"","get_losses"],[51,8,1,"","get_masks"],[51,8,1,"","get_offset"],[51,8,1,"","get_palette"],[51,8,1,"","get_palette_at"],[51,8,1,"","get_parent"],[51,8,1,"","get_pitch"],[51,8,1,"","get_rect"],[51,8,1,"","get_shifts"],[51,8,1,"","get_size"],[51,8,1,"","get_view"],[51,8,1,"","get_width"],[51,8,1,"","lock"],[51,8,1,"","map_rgb"],[51,8,1,"","mustlock"],[51,8,1,"","scroll"],[51,8,1,"","set_alpha"],[51,8,1,"","set_at"],[51,8,1,"","set_clip"],[51,8,1,"","set_colorkey"],[51,8,1,"","set_masks"],[51,8,1,"","set_palette"],[51,8,1,"","set_palette_at"],[51,8,1,"","set_shifts"],[51,8,1,"","subsurface"],[51,8,1,"","unlock"],[51,8,1,"","unmap_rgb"]],"pygame._sdl2":[[47,5,0,"-","controller"],[55,5,0,"-","touch"],[48,5,0,"-","video"]],"pygame._sdl2.controller":[[47,6,1,"","Controller"],[47,9,1,"","get_count"],[47,9,1,"","get_eventstate"],[47,9,1,"","get_init"],[47,9,1,"","init"],[47,9,1,"","is_controller"],[47,9,1,"","name_forindex"],[47,9,1,"","quit"],[47,9,1,"","set_eventstate"]],"pygame._sdl2.controller.Controller":[[47,8,1,"","as_joystick"],[47,8,1,"","attached"],[47,8,1,"","from_joystick"],[47,8,1,"","get_axis"],[47,8,1,"","get_button"],[47,8,1,"","get_init"],[47,8,1,"","get_mapping"],[47,8,1,"","quit"],[47,8,1,"","rumble"],[47,8,1,"","set_mapping"],[47,8,1,"","stop_rumble"]],"pygame._sdl2.touch":[[55,9,1,"","get_device"],[55,9,1,"","get_finger"],[55,9,1,"","get_num_devices"],[55,9,1,"","get_num_fingers"]],"pygame._sdl2.video":[[48,6,1,"","Image"],[48,6,1,"","Renderer"],[48,6,1,"","Texture"],[48,6,1,"","Window"]],"pygame._sdl2.video.Image":[[48,7,1,"","alpha"],[48,7,1,"","angle"],[48,7,1,"","blend_mode"],[48,7,1,"","color"],[48,8,1,"","draw"],[48,7,1,"","flipX"],[48,7,1,"","flipY"],[48,8,1,"","get_rect"],[48,7,1,"","origin"],[48,7,1,"","srcrect"],[48,7,1,"","texture"]],"pygame._sdl2.video.Renderer":[[48,8,1,"","blit"],[48,8,1,"","clear"],[48,7,1,"","draw_blend_mode"],[48,7,1,"","draw_color"],[48,8,1,"","draw_line"],[48,8,1,"","draw_point"],[48,8,1,"","draw_rect"],[48,8,1,"","fill_rect"],[48,8,1,"","from_window"],[48,8,1,"","get_viewport"],[48,7,1,"","logical_size"],[48,8,1,"","present"],[48,7,1,"","scale"],[48,8,1,"","set_viewport"],[48,7,1,"","target"],[48,8,1,"","to_surface"]],"pygame._sdl2.video.Texture":[[48,7,1,"","alpha"],[48,7,1,"","blend_mode"],[48,7,1,"","color"],[48,8,1,"","draw"],[48,8,1,"","from_surface"],[48,8,1,"","get_rect"],[48,7,1,"","height"],[48,7,1,"","renderer"],[48,8,1,"","update"],[48,7,1,"","width"]],"pygame._sdl2.video.Window":[[48,7,1,"","borderless"],[48,7,1,"","brightness"],[48,8,1,"","destroy"],[48,7,1,"","display_index"],[48,8,1,"","focus"],[48,8,1,"","from_display_module"],[48,7,1,"","grab"],[48,8,1,"","hide"],[48,7,1,"","id"],[48,8,1,"","maximize"],[48,8,1,"","minimize"],[48,7,1,"","opacity"],[48,7,1,"","position"],[48,7,1,"","relative_mouse"],[48,7,1,"","resizable"],[48,8,1,"","restore"],[48,8,1,"","set_fullscreen"],[48,8,1,"","set_icon"],[48,8,1,"","set_modal_for"],[48,8,1,"","set_windowed"],[48,8,1,"","show"],[48,7,1,"","size"],[48,7,1,"","title"]],"pygame.camera":[[18,6,1,"","Camera"],[18,9,1,"","colorspace"],[18,9,1,"","get_backends"],[18,9,1,"","init"],[18,9,1,"","list_cameras"]],"pygame.camera.Camera":[[18,8,1,"","get_controls"],[18,8,1,"","get_image"],[18,8,1,"","get_raw"],[18,8,1,"","get_size"],[18,8,1,"","query_image"],[18,8,1,"","set_controls"],[18,8,1,"","start"],[18,8,1,"","stop"]],"pygame.cdrom":[[19,6,1,"","CD"],[19,9,1,"","get_count"],[19,9,1,"","get_init"],[19,9,1,"","init"],[19,9,1,"","quit"]],"pygame.cdrom.CD":[[19,8,1,"","eject"],[19,8,1,"","get_all"],[19,8,1,"","get_busy"],[19,8,1,"","get_current"],[19,8,1,"","get_empty"],[19,8,1,"","get_id"],[19,8,1,"","get_init"],[19,8,1,"","get_name"],[19,8,1,"","get_numtracks"],[19,8,1,"","get_paused"],[19,8,1,"","get_track_audio"],[19,8,1,"","get_track_length"],[19,8,1,"","get_track_start"],[19,8,1,"","init"],[19,8,1,"","pause"],[19,8,1,"","play"],[19,8,1,"","quit"],[19,8,1,"","resume"],[19,8,1,"","stop"]],"pygame.cursors":[[22,6,1,"","Cursor"],[22,9,1,"","compile"],[22,9,1,"","load_xbm"]],"pygame.cursors.Cursor":[[22,8,1,"","copy"],[22,7,1,"","data"],[22,7,1,"","type"]],"pygame.display":[[23,9,1,"","Info"],[23,9,1,"","flip"],[23,9,1,"","get_active"],[23,9,1,"","get_allow_screensaver"],[23,9,1,"","get_caption"],[23,9,1,"","get_desktop_sizes"],[23,9,1,"","get_driver"],[23,9,1,"","get_init"],[23,9,1,"","get_num_displays"],[23,9,1,"","get_surface"],[23,9,1,"","get_window_size"],[23,9,1,"","get_wm_info"],[23,9,1,"","gl_get_attribute"],[23,9,1,"","gl_set_attribute"],[23,9,1,"","iconify"],[23,9,1,"","init"],[23,9,1,"","list_modes"],[23,9,1,"","mode_ok"],[23,9,1,"","quit"],[23,9,1,"","set_allow_screensaver"],[23,9,1,"","set_caption"],[23,9,1,"","set_gamma"],[23,9,1,"","set_gamma_ramp"],[23,9,1,"","set_icon"],[23,9,1,"","set_mode"],[23,9,1,"","set_palette"],[23,9,1,"","toggle_fullscreen"],[23,9,1,"","update"]],"pygame.draw":[[24,9,1,"","aaline"],[24,9,1,"","aalines"],[24,9,1,"","arc"],[24,9,1,"","circle"],[24,9,1,"","ellipse"],[24,9,1,"","line"],[24,9,1,"","lines"],[24,9,1,"","polygon"],[24,9,1,"","rect"]],"pygame.event":[[25,9,1,"","Event"],[25,6,1,"","EventType"],[25,9,1,"","clear"],[25,9,1,"","custom_type"],[25,9,1,"","event_name"],[25,9,1,"","get"],[25,9,1,"","get_blocked"],[25,9,1,"","get_grab"],[25,9,1,"","peek"],[25,9,1,"","poll"],[25,9,1,"","post"],[25,9,1,"","pump"],[25,9,1,"","set_allowed"],[25,9,1,"","set_blocked"],[25,9,1,"","set_grab"],[25,9,1,"","wait"]],"pygame.event.EventType":[[25,7,1,"","__dict__"],[25,7,1,"","type"]],"pygame.examples.aliens":[[26,9,1,"","main"]],"pygame.examples.arraydemo":[[26,9,1,"","main"]],"pygame.examples.blend_fill":[[26,9,1,"","main"]],"pygame.examples.blit_blends":[[26,9,1,"","main"]],"pygame.examples.camera":[[26,9,1,"","main"]],"pygame.examples.chimp":[[26,9,1,"","main"]],"pygame.examples.cursors":[[26,9,1,"","main"]],"pygame.examples.eventlist":[[26,9,1,"","main"]],"pygame.examples.fonty":[[26,9,1,"","main"]],"pygame.examples.freetype_misc":[[26,9,1,"","main"]],"pygame.examples.glcube":[[26,9,1,"","main"]],"pygame.examples.headless_no_windows_needed":[[26,9,1,"","main"]],"pygame.examples.joystick":[[26,9,1,"","main"]],"pygame.examples.liquid":[[26,9,1,"","main"]],"pygame.examples.mask":[[26,9,1,"","main"]],"pygame.examples.midi":[[26,9,1,"","main"]],"pygame.examples.moveit":[[26,9,1,"","main"]],"pygame.examples.pixelarray":[[26,9,1,"","main"]],"pygame.examples.playmus":[[26,9,1,"","main"]],"pygame.examples.scaletest":[[26,9,1,"","main"]],"pygame.examples.scrap_clipboard":[[26,9,1,"","main"]],"pygame.examples.scroll":[[26,9,1,"","main"]],"pygame.examples.sound":[[26,9,1,"","main"]],"pygame.examples.sound_array_demos":[[26,9,1,"","main"]],"pygame.examples.stars":[[26,9,1,"","main"]],"pygame.examples.testsprite":[[26,9,1,"","main"]],"pygame.examples.vgrade":[[26,9,1,"","main"]],"pygame.fastevent":[[27,9,1,"","get"],[27,9,1,"","get_init"],[27,9,1,"","init"],[27,9,1,"","poll"],[27,9,1,"","post"],[27,9,1,"","pump"],[27,9,1,"","wait"]],"pygame.font":[[28,6,1,"","Font"],[28,9,1,"","SysFont"],[28,9,1,"","get_default_font"],[28,9,1,"","get_fonts"],[28,9,1,"","get_init"],[28,9,1,"","init"],[28,9,1,"","match_font"],[28,9,1,"","quit"]],"pygame.font.Font":[[28,7,1,"","bold"],[28,8,1,"","get_ascent"],[28,8,1,"","get_bold"],[28,8,1,"","get_descent"],[28,8,1,"","get_height"],[28,8,1,"","get_italic"],[28,8,1,"","get_linesize"],[28,8,1,"","get_underline"],[28,7,1,"","italic"],[28,8,1,"","metrics"],[28,8,1,"","render"],[28,8,1,"","set_bold"],[28,8,1,"","set_italic"],[28,8,1,"","set_underline"],[28,8,1,"","size"],[28,7,1,"","underline"]],"pygame.freetype":[[29,6,1,"","Font"],[29,9,1,"","SysFont"],[29,9,1,"","get_cache_size"],[29,9,1,"","get_default_font"],[29,9,1,"","get_default_resolution"],[29,9,1,"","get_error"],[29,9,1,"","get_init"],[29,9,1,"","get_version"],[29,9,1,"","init"],[29,9,1,"","quit"],[29,9,1,"","set_default_resolution"],[29,9,1,"","was_init"]],"pygame.freetype.Font":[[29,7,1,"","antialiased"],[29,7,1,"","ascender"],[29,7,1,"","bgcolor"],[29,7,1,"","descender"],[29,7,1,"","fgcolor"],[29,7,1,"","fixed_sizes"],[29,7,1,"","fixed_width"],[29,8,1,"","get_metrics"],[29,8,1,"","get_rect"],[29,8,1,"","get_sized_ascender"],[29,8,1,"","get_sized_descender"],[29,8,1,"","get_sized_glyph_height"],[29,8,1,"","get_sized_height"],[29,8,1,"","get_sizes"],[29,7,1,"","height"],[29,7,1,"","kerning"],[29,7,1,"","name"],[29,7,1,"","oblique"],[29,7,1,"","origin"],[29,7,1,"","pad"],[29,7,1,"","path"],[29,8,1,"","render"],[29,8,1,"","render_raw"],[29,8,1,"","render_raw_to"],[29,8,1,"","render_to"],[29,7,1,"","resolution"],[29,7,1,"","rotation"],[29,7,1,"","scalable"],[29,7,1,"","size"],[29,7,1,"","strength"],[29,7,1,"","strong"],[29,7,1,"","style"],[29,7,1,"","ucs4"],[29,7,1,"","underline"],[29,7,1,"","underline_adjustment"],[29,7,1,"","use_bitmap_strikes"],[29,7,1,"","vertical"],[29,7,1,"","wide"]],"pygame.gfxdraw":[[30,9,1,"","aacircle"],[30,9,1,"","aaellipse"],[30,9,1,"","aapolygon"],[30,9,1,"","aatrigon"],[30,9,1,"","arc"],[30,9,1,"","bezier"],[30,9,1,"","box"],[30,9,1,"","circle"],[30,9,1,"","ellipse"],[30,9,1,"","filled_circle"],[30,9,1,"","filled_ellipse"],[30,9,1,"","filled_polygon"],[30,9,1,"","filled_trigon"],[30,9,1,"","hline"],[30,9,1,"","line"],[30,9,1,"","pie"],[30,9,1,"","pixel"],[30,9,1,"","polygon"],[30,9,1,"","rectangle"],[30,9,1,"","textured_polygon"],[30,9,1,"","trigon"],[30,9,1,"","vline"]],"pygame.image":[[31,9,1,"","frombuffer"],[31,9,1,"","fromstring"],[31,9,1,"","get_extended"],[31,9,1,"","get_sdl_image_version"],[31,9,1,"","load"],[31,9,1,"","load_basic"],[31,9,1,"","load_extended"],[31,9,1,"","save"],[31,9,1,"","save_extended"],[31,9,1,"","tostring"]],"pygame.joystick":[[32,6,1,"","Joystick"],[32,9,1,"","get_count"],[32,9,1,"","get_init"],[32,9,1,"","init"],[32,9,1,"","quit"]],"pygame.joystick.Joystick":[[32,8,1,"","get_axis"],[32,8,1,"","get_ball"],[32,8,1,"","get_button"],[32,8,1,"","get_guid"],[32,8,1,"","get_hat"],[32,8,1,"","get_id"],[32,8,1,"","get_init"],[32,8,1,"","get_instance_id"],[32,8,1,"","get_name"],[32,8,1,"","get_numaxes"],[32,8,1,"","get_numballs"],[32,8,1,"","get_numbuttons"],[32,8,1,"","get_numhats"],[32,8,1,"","get_power_level"],[32,8,1,"","init"],[32,8,1,"","quit"],[32,8,1,"","rumble"],[32,8,1,"","stop_rumble"]],"pygame.key":[[33,9,1,"","get_focused"],[33,9,1,"","get_mods"],[33,9,1,"","get_pressed"],[33,9,1,"","get_repeat"],[33,9,1,"","key_code"],[33,9,1,"","name"],[33,9,1,"","set_mods"],[33,9,1,"","set_repeat"],[33,9,1,"","set_text_input_rect"],[33,9,1,"","start_text_input"],[33,9,1,"","stop_text_input"]],"pygame.mask":[[35,6,1,"","Mask"],[35,9,1,"","from_surface"],[35,9,1,"","from_threshold"]],"pygame.mask.Mask":[[35,8,1,"","angle"],[35,8,1,"","centroid"],[35,8,1,"","clear"],[35,8,1,"","connected_component"],[35,8,1,"","connected_components"],[35,8,1,"","convolve"],[35,8,1,"","copy"],[35,8,1,"","count"],[35,8,1,"","draw"],[35,8,1,"","erase"],[35,8,1,"","fill"],[35,8,1,"","get_at"],[35,8,1,"","get_bounding_rects"],[35,8,1,"","get_rect"],[35,8,1,"","get_size"],[35,8,1,"","invert"],[35,8,1,"","outline"],[35,8,1,"","overlap"],[35,8,1,"","overlap_area"],[35,8,1,"","overlap_mask"],[35,8,1,"","scale"],[35,8,1,"","set_at"],[35,8,1,"","to_surface"]],"pygame.math":[[36,6,1,"","Vector2"],[36,6,1,"","Vector3"]],"pygame.math.Vector2":[[36,8,1,"","angle_to"],[36,8,1,"","as_polar"],[36,8,1,"","copy"],[36,8,1,"","cross"],[36,8,1,"","distance_squared_to"],[36,8,1,"","distance_to"],[36,8,1,"","dot"],[36,8,1,"","elementwise"],[36,8,1,"","from_polar"],[36,8,1,"","is_normalized"],[36,8,1,"","length"],[36,8,1,"","length_squared"],[36,8,1,"","lerp"],[36,8,1,"","magnitude"],[36,8,1,"","magnitude_squared"],[36,8,1,"","normalize"],[36,8,1,"","normalize_ip"],[36,8,1,"","project"],[36,8,1,"","reflect"],[36,8,1,"","reflect_ip"],[36,8,1,"","rotate"],[36,8,1,"","rotate_ip"],[36,8,1,"","rotate_ip_rad"],[36,8,1,"","rotate_rad"],[36,8,1,"","rotate_rad_ip"],[36,8,1,"","scale_to_length"],[36,8,1,"","slerp"],[36,8,1,"","update"]],"pygame.math.Vector3":[[36,8,1,"","angle_to"],[36,8,1,"","as_spherical"],[36,8,1,"","copy"],[36,8,1,"","cross"],[36,8,1,"","distance_squared_to"],[36,8,1,"","distance_to"],[36,8,1,"","dot"],[36,8,1,"","elementwise"],[36,8,1,"","from_spherical"],[36,8,1,"","is_normalized"],[36,8,1,"","length"],[36,8,1,"","length_squared"],[36,8,1,"","lerp"],[36,8,1,"","magnitude"],[36,8,1,"","magnitude_squared"],[36,8,1,"","normalize"],[36,8,1,"","normalize_ip"],[36,8,1,"","project"],[36,8,1,"","reflect"],[36,8,1,"","reflect_ip"],[36,8,1,"","rotate"],[36,8,1,"","rotate_ip"],[36,8,1,"","rotate_ip_rad"],[36,8,1,"","rotate_rad"],[36,8,1,"","rotate_rad_ip"],[36,8,1,"","rotate_x"],[36,8,1,"","rotate_x_ip"],[36,8,1,"","rotate_x_ip_rad"],[36,8,1,"","rotate_x_rad"],[36,8,1,"","rotate_x_rad_ip"],[36,8,1,"","rotate_y"],[36,8,1,"","rotate_y_ip"],[36,8,1,"","rotate_y_ip_rad"],[36,8,1,"","rotate_y_rad"],[36,8,1,"","rotate_y_rad_ip"],[36,8,1,"","rotate_z"],[36,8,1,"","rotate_z_ip"],[36,8,1,"","rotate_z_ip_rad"],[36,8,1,"","rotate_z_rad"],[36,8,1,"","rotate_z_rad_ip"],[36,8,1,"","scale_to_length"],[36,8,1,"","slerp"],[36,8,1,"","update"]],"pygame.midi":[[37,6,1,"","Input"],[37,10,1,"","MidiException"],[37,6,1,"","Output"],[37,9,1,"","frequency_to_midi"],[37,9,1,"","get_count"],[37,9,1,"","get_default_input_id"],[37,9,1,"","get_default_output_id"],[37,9,1,"","get_device_info"],[37,9,1,"","get_init"],[37,9,1,"","init"],[37,9,1,"","midi_to_ansi_note"],[37,9,1,"","midi_to_frequency"],[37,9,1,"","midis2events"],[37,9,1,"","quit"],[37,9,1,"","time"]],"pygame.midi.Input":[[37,8,1,"","close"],[37,8,1,"","poll"],[37,8,1,"","read"]],"pygame.midi.Output":[[37,8,1,"","abort"],[37,8,1,"","close"],[37,8,1,"","note_off"],[37,8,1,"","note_on"],[37,8,1,"","pitch_bend"],[37,8,1,"","set_instrument"],[37,8,1,"","write"],[37,8,1,"","write_short"],[37,8,1,"","write_sys_ex"]],"pygame.mixer":[[38,6,1,"","Channel"],[38,6,1,"","Sound"],[38,9,1,"","fadeout"],[38,9,1,"","find_channel"],[38,9,1,"","get_busy"],[38,9,1,"","get_init"],[38,9,1,"","get_num_channels"],[38,9,1,"","get_sdl_mixer_version"],[38,9,1,"","init"],[40,5,0,"-","music"],[38,9,1,"","pause"],[38,9,1,"","pre_init"],[38,9,1,"","quit"],[38,9,1,"","set_num_channels"],[38,9,1,"","set_reserved"],[38,9,1,"","stop"],[38,9,1,"","unpause"]],"pygame.mixer.Channel":[[38,8,1,"","fadeout"],[38,8,1,"","get_busy"],[38,8,1,"","get_endevent"],[38,8,1,"","get_queue"],[38,8,1,"","get_sound"],[38,8,1,"","get_volume"],[38,8,1,"","pause"],[38,8,1,"","play"],[38,8,1,"","queue"],[38,8,1,"","set_endevent"],[38,8,1,"","set_volume"],[38,8,1,"","stop"],[38,8,1,"","unpause"]],"pygame.mixer.Sound":[[38,8,1,"","fadeout"],[38,8,1,"","get_length"],[38,8,1,"","get_num_channels"],[38,8,1,"","get_raw"],[38,8,1,"","get_volume"],[38,8,1,"","play"],[38,8,1,"","set_volume"],[38,8,1,"","stop"]],"pygame.mixer.music":[[40,9,1,"","fadeout"],[40,9,1,"","get_busy"],[40,9,1,"","get_endevent"],[40,9,1,"","get_pos"],[40,9,1,"","get_volume"],[40,9,1,"","load"],[40,9,1,"","pause"],[40,9,1,"","play"],[40,9,1,"","queue"],[40,9,1,"","rewind"],[40,9,1,"","set_endevent"],[40,9,1,"","set_pos"],[40,9,1,"","set_volume"],[40,9,1,"","stop"],[40,9,1,"","unload"],[40,9,1,"","unpause"]],"pygame.mouse":[[39,9,1,"","get_cursor"],[39,9,1,"","get_focused"],[39,9,1,"","get_pos"],[39,9,1,"","get_pressed"],[39,9,1,"","get_rel"],[39,9,1,"","get_visible"],[39,9,1,"","set_cursor"],[39,9,1,"","set_pos"],[39,9,1,"","set_visible"]],"pygame.pixelcopy":[[43,9,1,"","array_to_surface"],[43,9,1,"","make_surface"],[43,9,1,"","map_array"],[43,9,1,"","surface_to_array"]],"pygame.scrap":[[46,9,1,"","contains"],[46,9,1,"","get"],[46,9,1,"","get_init"],[46,9,1,"","get_types"],[46,9,1,"","init"],[46,9,1,"","lost"],[46,9,1,"","put"],[46,9,1,"","set_mode"]],"pygame.sndarray":[[49,9,1,"","array"],[49,9,1,"","get_arraytype"],[49,9,1,"","get_arraytypes"],[49,9,1,"","make_sound"],[49,9,1,"","samples"],[49,9,1,"","use_arraytype"]],"pygame.sprite":[[50,6,1,"","DirtySprite"],[50,6,1,"","Group"],[50,9,1,"","GroupSingle"],[50,6,1,"","LayeredDirty"],[50,6,1,"","LayeredUpdates"],[50,9,1,"","OrderedUpdates"],[50,6,1,"","RenderClear"],[50,6,1,"","RenderPlain"],[50,6,1,"","RenderUpdates"],[50,6,1,"","Sprite"],[50,9,1,"","collide_circle"],[50,9,1,"","collide_circle_ratio"],[50,9,1,"","collide_mask"],[50,9,1,"","collide_rect"],[50,9,1,"","collide_rect_ratio"],[50,9,1,"","groupcollide"],[50,9,1,"","spritecollide"],[50,9,1,"","spritecollideany"]],"pygame.sprite.Group":[[50,8,1,"","add"],[50,8,1,"","clear"],[50,8,1,"","copy"],[50,8,1,"","draw"],[50,8,1,"","empty"],[50,8,1,"","has"],[50,8,1,"","remove"],[50,8,1,"","sprites"],[50,8,1,"","update"]],"pygame.sprite.LayeredDirty":[[50,8,1,"","change_layer"],[50,8,1,"","clear"],[50,8,1,"","draw"],[50,8,1,"","get_clip"],[50,8,1,"","repaint_rect"],[50,8,1,"","set_clip"],[50,8,1,"","set_timing_threshold"],[50,8,1,"","set_timing_treshold"]],"pygame.sprite.LayeredUpdates":[[50,8,1,"","add"],[50,8,1,"","change_layer"],[50,8,1,"","draw"],[50,8,1,"","get_bottom_layer"],[50,8,1,"","get_layer_of_sprite"],[50,8,1,"","get_sprite"],[50,8,1,"","get_sprites_at"],[50,8,1,"","get_sprites_from_layer"],[50,8,1,"","get_top_layer"],[50,8,1,"","get_top_sprite"],[50,8,1,"","layers"],[50,8,1,"","move_to_back"],[50,8,1,"","move_to_front"],[50,8,1,"","remove_sprites_of_layer"],[50,8,1,"","sprites"],[50,8,1,"","switch_layer"]],"pygame.sprite.RenderUpdates":[[50,8,1,"","draw"]],"pygame.sprite.Sprite":[[50,8,1,"","add"],[50,8,1,"","alive"],[50,8,1,"","groups"],[50,8,1,"","kill"],[50,8,1,"","remove"],[50,8,1,"","update"]],"pygame.surfarray":[[52,9,1,"","array2d"],[52,9,1,"","array3d"],[52,9,1,"","array_alpha"],[52,9,1,"","array_blue"],[52,9,1,"","array_colorkey"],[52,9,1,"","array_green"],[52,9,1,"","array_red"],[52,9,1,"","blit_array"],[52,9,1,"","get_arraytype"],[52,9,1,"","get_arraytypes"],[52,9,1,"","make_surface"],[52,9,1,"","map_array"],[52,9,1,"","pixels2d"],[52,9,1,"","pixels3d"],[52,9,1,"","pixels_alpha"],[52,9,1,"","pixels_blue"],[52,9,1,"","pixels_green"],[52,9,1,"","pixels_red"],[52,9,1,"","use_arraytype"]],"pygame.tests":[[53,9,1,"","run"]],"pygame.time":[[54,6,1,"","Clock"],[54,9,1,"","delay"],[54,9,1,"","get_ticks"],[54,9,1,"","set_timer"],[54,9,1,"","wait"]],"pygame.time.Clock":[[54,8,1,"","get_fps"],[54,8,1,"","get_rawtime"],[54,8,1,"","get_time"],[54,8,1,"","tick"],[54,8,1,"","tick_busy_loop"]],"pygame.transform":[[56,9,1,"","average_color"],[56,9,1,"","average_surfaces"],[56,9,1,"","chop"],[56,9,1,"","flip"],[56,9,1,"","get_smoothscale_backend"],[56,9,1,"","laplacian"],[56,9,1,"","rotate"],[56,9,1,"","rotozoom"],[56,9,1,"","scale"],[56,9,1,"","scale2x"],[56,9,1,"","set_smoothscale_backend"],[56,9,1,"","smoothscale"],[56,9,1,"","threshold"]],"pygame.version":[[44,11,1,"","SDL"],[44,11,1,"","rev"],[44,11,1,"","ver"],[44,11,1,"","vernum"]],pgBuffer_AsArrayInterface:[[1,2,1,"c.pgBuffer_AsArrayInterface","view_p"]],pgBuffer_AsArrayStruct:[[1,2,1,"c.pgBuffer_AsArrayStruct","view_p"]],pgBuffer_Release:[[1,2,1,"c.pgBuffer_Release","pg_view_p"]],pgBufproxy_Check:[[2,2,1,"c.pgBufproxy_Check","x"]],pgBufproxy_GetParent:[[2,2,1,"c.pgBufproxy_GetParent","obj"]],pgBufproxy_New:[[2,2,1,"c.pgBufproxy_New","get_buffer"],[2,2,1,"c.pgBufproxy_New","obj"]],pgBufproxy_Trip:[[2,2,1,"c.pgBufproxy_Trip","obj"]],pgCD_AsID:[[3,2,1,"c.pgCD_AsID","x"]],pgCD_Check:[[3,2,1,"c.pgCD_Check","x"]],pgCD_New:[[3,2,1,"c.pgCD_New","id"]],pgChannel_AsInt:[[8,2,1,"c.pgChannel_AsInt","x"]],pgChannel_Check:[[8,2,1,"c.pgChannel_Check","obj"]],pgChannel_New:[[8,2,1,"c.pgChannel_New","channelnum"]],pgColor_Check:[[4,2,1,"c.pgColor_Check","obj"]],pgColor_New:[[4,2,1,"c.pgColor_New","rgba"]],pgColor_NewLength:[[4,2,1,"c.pgColor_NewLength","length"],[4,2,1,"c.pgColor_NewLength","rgba"]],pgDict_AsBuffer:[[1,2,1,"c.pgDict_AsBuffer","dict"],[1,2,1,"c.pgDict_AsBuffer","flags"],[1,2,1,"c.pgDict_AsBuffer","pg_view_p"]],pgEventObject:[[6,3,1,"c.pgEventObject.type","type"]],pgEvent_Check:[[6,2,1,"c.pgEvent_Check","x"]],pgEvent_FillUserEvent:[[6,2,1,"c.pgEvent_FillUserEvent","e"],[6,2,1,"c.pgEvent_FillUserEvent","event"]],pgEvent_New2:[[6,2,1,"c.pgEvent_New2","dict"],[6,2,1,"c.pgEvent_New2","type"]],pgEvent_New:[[6,2,1,"c.pgEvent_New","event"]],pgFont_Check:[[7,2,1,"c.pgFont_Check","x"]],pgFont_IS_ALIVE:[[7,2,1,"c.pgFont_IS_ALIVE","o"]],pgFont_New:[[7,2,1,"c.pgFont_New","filename"],[7,2,1,"c.pgFont_New","font_index"]],pgLifetimeLockObject:[[13,3,1,"c.pgLifetimeLockObject.lockobj","lockobj"],[13,3,1,"c.pgLifetimeLockObject.surface","surface"]],pgLifetimeLock_Check:[[13,2,1,"c.pgLifetimeLock_Check","x"]],pgObject_GetBuffer:[[1,2,1,"c.pgObject_GetBuffer","flags"],[1,2,1,"c.pgObject_GetBuffer","obj"],[1,2,1,"c.pgObject_GetBuffer","pg_view_p"]],pgRWops_FromFileObject:[[10,2,1,"c.pgRWops_FromFileObject","obj"]],pgRWops_FromObject:[[10,2,1,"c.pgRWops_FromObject","obj"]],pgRWops_GetFileExtension:[[10,2,1,"c.pgRWops_GetFileExtension","rw"]],pgRWops_IsFileObject:[[10,2,1,"c.pgRWops_IsFileObject","rw"]],pgRWops_ReleaseObject:[[10,2,1,"c.pgRWops_ReleaseObject","context"]],pgRectObject:[[9,3,1,"c.pgRectObject.r","r"]],pgRect_AsRect:[[9,2,1,"c.pgRect_AsRect","obj"]],pgRect_FromObject:[[9,2,1,"c.pgRect_FromObject","obj"],[9,2,1,"c.pgRect_FromObject","temp"]],pgRect_New4:[[9,2,1,"c.pgRect_New4","h"],[9,2,1,"c.pgRect_New4","w"],[9,2,1,"c.pgRect_New4","x"],[9,2,1,"c.pgRect_New4","y"]],pgRect_New:[[9,2,1,"c.pgRect_New","r"]],pgRect_Normalize:[[9,2,1,"c.pgRect_Normalize","rect"]],pgSound_AsChunk:[[8,2,1,"c.pgSound_AsChunk","x"]],pgSound_Check:[[8,2,1,"c.pgSound_Check","obj"]],pgSound_New:[[8,2,1,"c.pgSound_New","chunk"]],pgSurface_AsSurface:[[12,2,1,"c.pgSurface_AsSurface","x"]],pgSurface_Blit:[[12,2,1,"c.pgSurface_Blit","dstobj"],[12,2,1,"c.pgSurface_Blit","dstrect"],[12,2,1,"c.pgSurface_Blit","srcobj"],[12,2,1,"c.pgSurface_Blit","srcrect"],[12,2,1,"c.pgSurface_Blit","the_args"]],pgSurface_Check:[[12,2,1,"c.pgSurface_Check","x"]],pgSurface_Lock:[[13,2,1,"c.pgSurface_Lock","surfobj"]],pgSurface_LockBy:[[13,2,1,"c.pgSurface_LockBy","lockobj"],[13,2,1,"c.pgSurface_LockBy","surfobj"]],pgSurface_LockLifetime:[[13,2,1,"c.pgSurface_LockLifetime","lockobj"],[13,2,1,"c.pgSurface_LockLifetime","surfobj"]],pgSurface_New:[[12,2,1,"c.pgSurface_New","s"]],pgSurface_Prep:[[13,2,1,"c.pgSurface_Prep","surfobj"]],pgSurface_UnLock:[[13,2,1,"c.pgSurface_UnLock","surfobj"]],pgSurface_UnLockBy:[[13,2,1,"c.pgSurface_UnLockBy","lockobj"],[13,2,1,"c.pgSurface_UnLockBy","surfobj"]],pgSurface_Unprep:[[13,2,1,"c.pgSurface_Unprep","surfobj"]],pgVidInfo_AsVidInfo:[[5,2,1,"c.pgVidInfo_AsVidInfo","obj"]],pgVidInfo_Check:[[5,2,1,"c.pgVidInfo_Check","x"]],pgVidInfo_New:[[5,2,1,"c.pgVidInfo_New","i"]],pg_EncodeFilePath:[[10,2,1,"c.pg_EncodeFilePath","eclass"],[10,2,1,"c.pg_EncodeFilePath","obj"]],pg_EncodeString:[[10,2,1,"c.pg_EncodeString","eclass"],[10,2,1,"c.pg_EncodeString","encoding"],[10,2,1,"c.pg_EncodeString","errors"],[10,2,1,"c.pg_EncodeString","obj"]],pg_FloatFromObj:[[1,2,1,"c.pg_FloatFromObj","obj"],[1,2,1,"c.pg_FloatFromObj","val"]],pg_FloatFromObjIndex:[[1,2,1,"c.pg_FloatFromObjIndex","index"],[1,2,1,"c.pg_FloatFromObjIndex","obj"],[1,2,1,"c.pg_FloatFromObjIndex","val"]],pg_IntFromObj:[[1,2,1,"c.pg_IntFromObj","obj"],[1,2,1,"c.pg_IntFromObj","val"]],pg_IntFromObjIndex:[[1,2,1,"c.pg_IntFromObjIndex","index"],[1,2,1,"c.pg_IntFromObjIndex","obj"],[1,2,1,"c.pg_IntFromObjIndex","val"]],pg_RGBAFromObj:[[1,2,1,"c.pg_RGBAFromObj","RGBA"],[1,2,1,"c.pg_RGBAFromObj","obj"]],pg_RegisterQuit:[[1,2,1,"c.pg_RegisterQuit","f"]],pg_SetDefaultWindow:[[1,2,1,"c.pg_SetDefaultWindow","win"]],pg_SetDefaultWindowSurface:[[1,2,1,"c.pg_SetDefaultWindowSurface","screen"]],pg_TwoFloatsFromObj:[[1,2,1,"c.pg_TwoFloatsFromObj","obj"],[1,2,1,"c.pg_TwoFloatsFromObj","val1"],[1,2,1,"c.pg_TwoFloatsFromObj","val2"]],pg_TwoIntsFromObj:[[1,2,1,"c.pg_TwoIntsFromObj","obj"],[1,2,1,"c.pg_TwoIntsFromObj","v2"],[1,2,1,"c.pg_TwoIntsFromObj","val1"]],pg_UintFromObj:[[1,2,1,"c.pg_UintFromObj","obj"],[1,2,1,"c.pg_UintFromObj","val"]],pg_UintFromObjIndex:[[1,2,1,"c.pg_UintFromObjIndex","_index"],[1,2,1,"c.pg_UintFromObjIndex","obj"],[1,2,1,"c.pg_UintFromObjIndex","val"]],pg_buffer:[[1,3,1,"c.pg_buffer.consumer","consumer"],[1,3,1,"c.pg_buffer.release_buffer","release_buffer"],[1,3,1,"c.pg_buffer.view","view"]],pg_mod_autoinit:[[1,2,1,"c.pg_mod_autoinit","modname"]],pg_mod_autoquit:[[1,2,1,"c.pg_mod_autoquit","modname"]],pygame:[[17,6,1,"","BufferProxy"],[20,6,1,"","Color"],[41,6,1,"","Overlay"],[42,6,1,"","PixelArray"],[45,6,1,"","Rect"],[51,6,1,"","Surface"],[18,5,0,"-","camera"],[19,5,0,"-","cdrom"],[22,5,0,"-","cursors"],[23,5,0,"-","display"],[24,5,0,"-","draw"],[44,9,1,"","encode_file_path"],[44,9,1,"","encode_string"],[44,10,1,"","error"],[25,5,0,"-","event"],[26,5,0,"-","examples"],[27,5,0,"-","fastevent"],[28,5,0,"-","font"],[29,5,0,"-","freetype"],[44,9,1,"","get_error"],[44,9,1,"","get_init"],[44,9,1,"","get_sdl_byteorder"],[44,9,1,"","get_sdl_version"],[30,5,0,"-","gfxdraw"],[31,5,0,"-","image"],[44,9,1,"","init"],[32,5,0,"-","joystick"],[33,5,0,"-","key"],[34,5,0,"-","locals"],[35,5,0,"-","mask"],[36,5,0,"-","math"],[37,5,0,"-","midi"],[38,5,0,"-","mixer"],[39,5,0,"-","mouse"],[43,5,0,"-","pixelcopy"],[44,9,1,"","quit"],[44,9,1,"","register_quit"],[46,5,0,"-","scrap"],[44,9,1,"","set_error"],[49,5,0,"-","sndarray"],[50,5,0,"-","sprite"],[52,5,0,"-","surfarray"],[53,5,0,"-","tests"],[54,5,0,"-","time"],[56,5,0,"-","transform"],[44,5,0,"-","version"]]},objnames:{"0":["c","macro","C macro"],"1":["c","function","C function"],"10":["py","exception","Python exception"],"11":["py","data","Python data"],"2":["c","functionParam","C function parameter"],"3":["c","member","C member"],"4":["c","type","C type"],"5":["py","module","Python module"],"6":["py","class","Python class"],"7":["py","attribute","Python attribute"],"8":["py","method","Python method"],"9":["py","function","Python function"]},objtypes:{"0":"c:macro","1":"c:function","10":"py:exception","11":"py:data","2":"c:functionParam","3":"c:member","4":"c:type","5":"py:module","6":"py:class","7":"py:attribute","8":"py:method","9":"py:function"},terms:{"0":[1,2,6,7,10,12,17,18,19,20,22,23,24,25,26,28,29,30,31,32,33,35,36,37,38,39,40,41,42,43,44,45,47,48,50,51,52,54,55,56,57,58,59,62,63,64,65,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84,85,86,88,89],"02778":29,"08333":29,"0\uac1c":[78,79],"0\ucc28\uc6d0":81,"0d":73,"0dev11":32,"0x00":20,"0x00000000":51,"0x00000001":51,"0x00000004":51,"0x00000100":51,"0x00001000":51,"0x00002000":51,"0x00004000":51,"0x00010000":51,"0x01000000":51,"0x10":37,"0x10000":29,"0x10ffff":29,"0x11":37,"0x12":37,"0x13":37,"0x7d":37,"0x90":37,"0xaacce":42,"0xc0":37,"0xd800":29,"0xdfff":29,"0xf0":37,"0xf7":37,"0xff":20,"0xff00ff":42,"0xffff":23,"0xrrggbb":20,"0xrrggbbaa":20,"1":[1,2,3,4,6,9,12,14,16,17,18,20,22,23,24,25,26,28,29,30,31,32,33,35,36,37,38,39,40,42,43,44,45,46,47,48,49,50,51,52,54,55,56,57,58,59,60,62,63,64,65,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,83,84],"10":[23,24,26,32,35,36,45,54,56,58,62,63,65,66,68,69,70,71,72,73,76,77,78,79,80,81,84,85,88,89],"100":[20,24,37,51,57,62,65,84],"1000":[50,54,84],"1024":[37,38],"105":57,"1080":[23,59],"1080p":23,"10\ub610\ub294":79,"10\uc758":76,"10\uc774":77,"10th":35,"11":[32,68,69,76,77],"114":42,"115":24,"117":26,"11\uc744":77,"11\uc758":76,"11\uc774":77,"12":[11,29,32,44,58,66,68,76],"120":22,"1234":44,"125":24,"127":[35,37,71,72,73,79,80,81],"128":65,"1280":[58,66],"13":[32,63,65,68,76,89],"135":24,"14":[32,47,68,76],"140":[67,68,69,70,75,76,77,78],"145":57,"14\uc758":76,"15":[24,32,51,58,66,68,69,76,77],"150":[24,85],"15\uc758":76,"16":[15,22,23,29,32,38,49,59,65,68,76],"16711680":59,"16bit":38,"17":[63,68,76],"170":[42,57,58,66],"17\uc5d0\uc11c\uc758":76,"18":[24,58,63,66,68,76],"187":[58,66],"19":[68,76],"192":84,"1920":[23,59],"19\ub294":76,"19\uc5d0\uc11c":76,"1\uac1c":78,"1\uac1c\uc758":76,"1\uacfc":77,"1\uc778":75,"1\uc778\uc9c0":81,"1\uc904\uc9dc\ub9ac":76,"1\ucc28\uc6d0":81,"1\ucd08\uc5d0":77,"1d":[42,73],"1s":62,"1x1":37,"2":[1,9,15,17,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33,35,36,37,38,39,40,41,42,43,44,45,47,50,51,52,54,55,56,57,58,61,63,65,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,83,84],"20":[22,24,32,45,56,65,68,71,72,73,76,79,80,81,84],"200":[24,63],"2000":[16,63],"20000":37,"2001":63,"2004":18,"204":42,"20500":37,"20\uc77c":79,"20\uc904\uc9dc\ub9ac":76,"21":[37,63],"210":24,"22":49,"220":[24,67,68,69,70,75,76,77,78],"22000":49,"22050":38,"225":24,"23":63,"235":[58,66],"238":[42,58,66],"2380":23,"24":[17,18,22,24,28,31,42,51,52,56,63,65],"240":[63,68,69,70,71,72,73,76,77,78,79,80,81],"24x24":22,"25":[56,58,66],"250":[24,85],"255":[1,20,24,28,29,30,35,42,43,50,51,56,57,58,59,65,68,69,70,71,72,73,76,77,78,79,80,81,84,85],"256":[23,37,51],"260":24,"27":37,"270":[72,73,80,81],"28":84,"299":42,"2\uac1c\ub97c":80,"2\uac1c\uc758":78,"2\ucc28\ub235":81,"2\ucc28\uc6d0":81,"2d":[16,35,42,43,48,52,63,64,65,68,73,76],"2d\uc6a9":76,"2pre":36,"2s":62,"2x2":65,"3":[1,17,18,20,22,23,24,28,30,31,32,33,36,37,38,39,42,43,44,47,50,51,61,62,63,64,65,67,68,69,70,71,73,76,77,78,79,81,83,84],"30":[22,24,29,30,38,45,53,57,63,71,84],"300":24,"3072":38,"30\uc73c\ub85c":79,"315":29,"32":[1,15,17,18,29,31,35,38,51,52,56,59,65,68,69,70,71,72,73,76,77,78,79,80,81],"320":[63,68,69,70,71,72,73,76,77,78,79,80,81],"325":[72,73,80,81],"32767":47,"32768":47,"32x32":23,"33":65,"35":[74,84],"359":29,"35\ub144":82,"36":[29,85],"360":[20,29,32,47,58,66],"390":29,"3\uac1c\uc758":[76,79],"3d":[23,26,43,52,63,65,67],"3f":32,"3rd":63,"3x3":65,"4":[1,4,9,17,20,24,28,29,32,33,36,37,38,39,42,47,51,56,57,58,59,60,61,62,65,66,68,69,70,71,72,73,76,77,78,79,80,81,83,84,86,89],"40":[22,24,54,56,62,63,71,72,73,79,80,81,84],"400":[22,23,24,57],"4096":[37,38],"42":24,"425":[72,73,80,81],"4321":44,"44100":38,"45":[29,72,73,80,81],"47":89,"480":[18,26,39,48,57,58,59,62,66,68,69,70,71,72,73,76,77,78,79,80,81,89],"480\uc73c\ub85c":76,"4\uac1c\uc758":[76,79],"4k":23,"4th":65,"5":[14,20,23,24,25,29,32,33,35,36,37,38,39,40,42,44,46,49,50,57,58,61,62,63,65,66,68,69,70,71,72,73,76,77,78,79,80,81,83,89],"50":[22,24,26,57,65,73,81,84,85],"500":32,"500m":37,"512":38,"55":56,"56":24,"587":42,"5\uac00":77,"5\uac1c\uc758":76,"5\uc5d0":78,"5x5":[73,81],"6":[24,26,32,33,38,44,50,61,62,65,68,69,70,71,73,76,77,78,79,81,83],"60":[22,24,37,38,39,58,66,69,71,72,73,77,79,80,81,89],"600":[22,59,62],"60\uc774\ub77c\ub294":77,"63":20,"64":[20,29,56,58,66],"640":[18,26,39,48,57,59,62,68,69,70,71,72,73,76,77,78,79,80,81,89],"640x480":[23,62,65],"65":[37,56],"65280":59,"6\uc744":79,"6x":84,"7":[23,32,33,43,44,63,65,68,69,70,71,76,77,78,79,83],"70":24,"700":[23,32],"72":29,"720":29,"75":[22,24,69,77],"7\uc5d0\uc11c":79,"7\uc758":76,"8":[15,17,18,20,22,23,24,26,28,29,30,31,32,33,35,38,42,43,44,46,49,50,51,52,54,56,59,62,63,65,68,69,70,76,77,78,83,89],"80":[24,50,58,66],"800":59,"8191":37,"8192":37,"8\uc758":76,"8bit":38,"9":[14,16,17,18,20,23,25,26,29,30,32,33,35,36,37,38,40,42,43,44,45,46,47,51,52,56,57,65,68,69,70,76,77,78],"90":[24,35,38,56,57,58,66,89],"97":33,"9\uc758":76,"\uac00":[76,77,81],"\uac00\ub2a5":80,"\uac00\ub3c5\uc131\uc744":76,"\uac00\ubcf4\uc790":78,"\uac00\uc18d":77,"\uac00\uc7a5":[76,79,82],"\uac00\uc815\ud558\uba74":76,"\uac00\uc815\ud574":75,"\uac00\uc9c0\uace0":[75,78,81],"\uac00\uc9c0\uae30":76,"\uac00\uc9c0\ub294":76,"\uac00\uc9c0\ubbc0\ub85c":[76,79],"\uac00\uc9c4\ub2e4":[76,80],"\uac00\uc9c4\ub2e4\ub294":75,"\uac00\uc9c8":82,"\uac01\uac01":79,"\uac01\uac01\uc758":79,"\uac04\ub2e8\ud558\ub2e4":81,"\uac10\uc18c\uc2dc\ud0a4\ub294":80,"\uac10\uc18c\ud55c\ub2e4":81,"\uac12":79,"\uac12\ub9cc\uc774":79,"\uac12\uc740":[76,79],"\uac12\uc744":[76,79,80],"\uac12\uc774":79,"\uac12\uc774\uace0":79,"\uac16\ub294":[81,82],"\uac19\ub2e4":[75,76,82],"\uac19\uc544":[77,81],"\uac19\uc740":[76,77,82],"\uac19\uc74c":81,"\uac19\uc774":[76,79],"\uac1c\ub150\uc740":82,"\uac1c\ub150\uc744":77,"\uac1c\ub150\uc774\ub2e4":82,"\uac1c\ubc1c\uc790\uac00":75,"\uac1c\uc120\uc758":81,"\uac1c\uc218\ub97c":81,"\uac1c\uc218\ub9cc\ud07c":79,"\uac1d\uccb4":[76,78],"\uac1d\uccb4\uc5d0":76,"\uac1d\uccb4\uc758":76,"\uac70\uc758":[75,76],"\uac71\uc815\ud558\uc9c0":82,"\uac78\ub9ac\ub294":76,"\uac80\uc740":[79,81],"\uac80\uc740\ube14\ub85d":16,"\uac83":[75,76,78],"\uac83\uacfc":[80,82],"\uac83\ub4e4\uc774":81,"\uac83\ub4e4\uc774\ub2e4":76,"\uac83\ubcf4\ub2e4":79,"\uac83\uc5d0":[75,77,78],"\uac83\uc5d0\ub9cc":75,"\uac83\uc740":[76,77,78,79,80,82],"\uac83\uc744":79,"\uac83\uc774":[75,76,79,80],"\uac83\uc774\uae30":78,"\uac83\uc774\ub2e4":[75,76,77,78,79,80,81,82],"\uac83\uc778\ub2e4":80,"\uac83\ucc98\ub7fc":[77,80],"\uac8c\uc784":[75,76,77,78,81,82],"\uac8c\uc784\ub3c4":[75,82],"\uac8c\uc784\ub9cc\uc758":82,"\uac8c\uc784\uc5d0\uc11c\uc758":79,"\uac8c\uc784\uc5d0\uc120":77,"\uac8c\uc784\uc5d4\uc9c4":75,"\uac8c\uc784\uc5d4\uc9c4\uc774\ub098":75,"\uac8c\uc784\uc740":[75,78,81],"\uac8c\uc784\uc744":[75,78,82],"\uac8c\uc784\uc758":[75,78],"\uac8c\uc784\uc774":[75,77,78,80,81,82],"\uac8c\uc784\uc774\ub098":82,"\uac8c\uc784\uc774\ub2e4":81,"\uac8c\uc784\uc774\ub77c\uace0":78,"\uac8c\uc784\uc774\ubbc0\ub85c":76,"\uac8c\uc784\ud310":83,"\uac8c\uc784\ud310\uc740":81,"\uac8c\uc784\ud310\uc744":81,"\uacaa\uc5b4":82,"\uacb0\uacfc":[76,77,78],"\uacb0\uacfc\uac00":77,"\uacb0\uacfc\ub294":[78,81],"\uacb0\uacfc\ub97c":77,"\uacb0\uacfc\ubb3c\ub4e4\uc744":76,"\uacb0\uacfc\ubb3c\uc740":76,"\uacb0\ub860\uc774":82,"\uacb0\uc815\ud560":76,"\uacbd\uc6b0":[76,78,79,80],"\uacbd\uc6b0\ub97c":78,"\uacbd\uc6b0\uc758":82,"\uacbd\ud5d8\uc774":78,"\uacc4\uc0b0\ub9cc":76,"\uacc4\uc0b0\uc744":80,"\uacc4\uc0b0\ud558\uae30":77,"\uacc4\uc0b0\ud574\uc57c":81,"\uacc4\uc18d":[75,76,78],"\uace0":81,"\uace0\uae09":75,"\uace0\ub824\ub418\uc5c8\uc744":82,"\uace0\ub824\ub418\uc9c0":77,"\uace0\ub824\ud558\uc5ec":76,"\uace0\ub974\ub294":81,"\uace0\uc815":77,"\uace0\uc815\ub418\uc5b4":[76,79],"\uace0\uc815\ub41c":76,"\uace0\uc815\ub420":77,"\uace0\uc815\uc2dc\ucf1c":77,"\uace0\uc815\uc2dc\ud0a4\ub294":77,"\uace0\uc815\uc2dc\ud0a8\ub2e4":76,"\uace0\uc815\ud558\ub294":77,"\uacf5\uac04":76,"\uacf5\uac04\uc0c1\uc5d0\uc11c\uc758":75,"\uacf5\uac04\uc744":[76,80],"\uacf5\uc774\ub098":77,"\uacfc":[76,80],"\uad00\ub828":75,"\uad6c\uc131":76,"\uad6c\uc131\ub41c\ub2e4":75,"\uad6c\uc131\ud560":75,"\uad6c\uc2dd\uc774\uace0":75,"\uad6c\uc5ed\uc744":76,"\uad6c\uc5ed\uc758":76,"\uad6c\uccb4\uc801\uc778":[78,80],"\uad6c\ud604\ud55c":[81,82],"\uad6c\ud604\ud55c\ub2e4\uba74":81,"\uad6c\ud604\ud560":82,"\uaddc\uce59":[78,82],"\uaddc\uce59\uc740":81,"\uaddc\uce59\uc744":[81,82],"\uaddc\uce59\uc774":82,"\uadf8":[75,76,77,79,80,81],"\uadf8\uac83\uc740":79,"\uadf8\uac83\uc774":[78,82],"\uadf8\uac83\uc774\ub2e4":76,"\uadf8\ub2e4\uc9c0":76,"\uadf8\ub798\uc11c":[75,76,77],"\uadf8\ub798\ud53d":75,"\uadf8\ub798\ud53d\uc744":75,"\uadf8\ub7ec\ub098":[77,78,82],"\uadf8\ub7ec\uba74":[75,77,81],"\uadf8\ub7ec\ubbc0\ub85c":[76,77,80,82],"\uadf8\ub7f0\uac00":78,"\uadf8\ub807\ub2e4\uba74":[76,77],"\uadf8\ub807\uc9c0":80,"\uadf8\ub824\uc9c0\uace0":76,"\uadf8\ub824\uc9c0\ub294":76,"\uadf8\ub824\uc9c4\ub2e4":81,"\uadf8\ub9ac\uace0":[75,76,77],"\uadf8\ub9ac\uae30":75,"\uadf8\ub9ac\ub294":[76,79],"\uadf8\ub9b0\ub2e4":[79,80],"\uadf9\uc18c\uc218\ub9cc\uc744":82,"\uae30\ub2a5":77,"\uae30\ub2a5\uc744":[76,77],"\uae30\ub85d\ud574\uc57c":80,"\uae30\ubc18":76,"\uae30\ubc18\uc73c\ub85c":76,"\uae30\ubc18\ud558\uc600\uae30":75,"\uae30\uc874\uc758":82,"\uae38\uc774\ub97c":76,"\uae4c\uba39\uc5b4\uc120":76,"\uae5c\ube61\uac70\ub9ac\ub294":75,"\uaf64":76,"\ub049\uaca8":75,"\ub05d\ub09c":76,"\ub05d\uc774":82,"\ub098":81,"\ub098\uac8c":82,"\ub098\ub220\uc9c8":76,"\ub098\ub294":78,"\ub098\uba74":76,"\ub098\uc544\uc84c\ub2e4":79,"\ub098\uc911\uc5d0":[76,77,78],"\ub098\ud0c0\ub0b8\ub2e4":80,"\ub09c\ub2e4":82,"\ub09c\uc218":82,"\ub09c\uc218\uac00":82,"\ub09c\uc218\uae4c\uc9c0":82,"\ub0ab\ub2e4":75,"\ub0b4\ubd80":[76,78],"\ub0b4\ubd80\ub97c":80,"\ub0b4\ubd80\uc5d0\uc11c":80,"\ub0b4\ubd80\uc600\ub2e4\uba74":80,"\ub0b4\uc5d0\uc11c":[77,81,82],"\ub0b4\uc6a9":76,"\ub0b4\uc6a9\uacfc":76,"\ub0b4\uc6a9\uc740":80,"\ub108\ubb34":77,"\ub118\uac8c":82,"\ub123\ub294\ub2e4\uba74":81,"\ub123\uc73c\uba74":81,"\ub124\ubc88\uc9f8":79,"\ub192\ub2e4\ub294":75,"\ub192\uc774\uae30":76,"\ub204\ub974\ub294":77,"\ub204\ub974\uba74":78,"\ub208\uc0ac\ud0dc":82,"\ub208\uc0ac\ud0dc\ub97c":82,"\ub20c\ub7ec":79,"\ub20c\ub824\uc788\ub294":78,"\ub20c\ub838\ub2e4":78,"\ub20c\ub9ac\uc9c0":78,"\ub20c\ub9b0":78,"\ub294":76,"\ub2a5\ub825\uc774\ub2e4":82,"\ub2e4\ub8e8\uaca0\ub2e4":78,"\ub2e4\ub8e8\uae30":78,"\ub2e4\ub974\uac8c":78,"\ub2e4\ub974\ub2e4":77,"\ub2e4\ub974\uc9c0":79,"\ub2e4\ub978":[76,78,82],"\ub2e4\uc2dc":79,"\ub2e4\uc591\uc131":78,"\ub2e4\uc591\ud788":81,"\ub2e4\uc6e0\ub2e4":82,"\ub2e4\uc74c":[76,79,80,81],"\ub2e4\uc911":77,"\ub2e4\ud589\ud788":75,"\ub2e8":77,"\ub2e8\uacc4\ub85c":78,"\ub2e8\uacc4\ub97c":76,"\ub2e8\uacc4\uc5d0\uc11c\uc758":78,"\ub2e8\uc0c9":76,"\ub2e8\uc21c\ud558\uae30":81,"\ub2e8\uc21c\ud558\ub2e4":[79,80],"\ub2e8\uc21c\ud558\uc9c0\ub9cc":81,"\ub2e8\uc21c\ud788":[78,81],"\ub2e8\uc5b4\ub294":78,"\ub2e8\uc810\uc740":77,"\ub2e8\uc810\uc774":75,"\ub2ec\ub77c\uc9c0\ubbc0\ub85c":77,"\ub2ec\ub77c\uc9c4\ub2e4":81,"\ub2ec\ub77c\uc9c8":78,"\ub2f4\uc558\ub294\ub370":79,"\ub2f9\uc5f0\ud55c":76,"\ub300\ub2e8\ud788":[81,82],"\ub300\ub85c":81,"\ub300\ubcf4\uac8c":75,"\ub300\uc0c1\uc5d0":82,"\ub300\uccb4\ud558\ub294\uac00":76,"\ub300\ud55c":76,"\ub354":[75,78,79,82],"\ub370":76,"\ub370\uc5d0\ub9cc":80,"\ub370\uc774\ud130":[78,81],"\ub370\uc774\ud130\uac00":76,"\ub370\uc774\ud130\ub4e4\uc744":79,"\ub370\uc774\ud130\ub97c":79,"\ub3c4":[76,78],"\ub3c4\uc6c0":78,"\ub3c4\uc6c0\uc774":78,"\ub3c4\uc911":76,"\ub3c4\ud615":75,"\ub3c4\ud615\uc744":79,"\ub3d9\uae30\ubd80\uc5ec":78,"\ub3d9\uc2dc\uc5d0":75,"\ub3d9\uc77c\ud55c":[76,79,80],"\ub3d9\uc77c\ud574\uc57c":80,"\ub3d9\uc791\ud558\ub3c4\ub85d":78,"\ub3d9\uce58\uad00\uacc4\ub77c\ub294":75,"\ub418\uae30":78,"\ub418\ub3cc\uc544\uac00\uc57c":76,"\ub418\uc5b4\uc57c\ub9cc":77,"\ub418\uc5c8\ub294\uc9c0":78,"\ub418\uc9c0":79,"\ub41c":[78,80],"\ub41c\ub2e4":[75,76,77,78,79,80,81,82],"\ub41c\ub2e4\uba74":82,"\ub420":[75,77,79],"\ub450":[79,80,81,82],"\ub450\uaed8":79,"\ub450\uaed8\ub9cc":80,"\ub450\ub294":[79,80],"\ub450\ub294\ub370":76,"\ub450\uba74":77,"\ub450\ubc88\uc9f8":[78,79],"\ub450\uc5c8\ub2e4":76,"\ub458":75,"\ub458\uc9f8":[75,80],"\ub4a4\uc5d0":78,"\ub4b7\ubd80\ubd84\uc5d0":77,"\ub4e4\uba74":79,"\ub4e4\uc5b4\uc11c":76,"\ub4e4\uc744":80,"\ub4f1":[75,78],"\ub4f1\uc740":82,"\ub4f1\uc758":75,"\ub514\ub809\ud1a0\ub9ac\uc5d0":76,"\ub514\uc2a4\ud50c\ub808\uc774":75,"\ub514\uc790\uc778\ud560":79,"\ub51c\ub808\ub9c8\uac00":75,"\ub51c\ub808\ub9c8\ub97c":75,"\ub51c\ub808\uc774":77,"\ub530\ub77c":[77,81],"\ub530\uc62c":79,"\ub530\uc838\uc11c":79,"\ub54c":[76,77,79,81,82],"\ub54c\ub9c8\ub2e4":79,"\ub54c\ub9cc":76,"\ub54c\ubb38\uc5d0":[75,76,77,78,81],"\ub54c\ubb38\uc774\ub2e4":[76,77,78,80,81],"\ub54c\uc758":79,"\ub610\ub294":[75,79,82],"\ub610\ud55c":[77,81],"\ub611\uac19\uc740":78,"\ub73b\uc774\ub2e4":78,"\ub77c\uace0":[78,82],"\ub77c\ub294":[76,82],"\ub77c\uc774\ube0c\ub7ec\ub9ac\uc774\uae30":75,"\ub77c\uc774\ube0c\ub7ec\ub9ac\uc774\ub2e4":75,"\ub80c\ub354\ub9c1":79,"\ub85c\uc9c1\uc740":79,"\ub85c\uc9c1\uc744":[76,78],"\ub85c\uc9c1\uc774":77,"\ub8e8\ud2b82":77,"\ub97c":[76,77,78,80],"\ub9c8\ub77c":82,"\ub9c8\uc6b0\uc2a4":[75,78,80],"\ub9c8\uc6b0\uc2a4\uac00up":80,"\ub9c8\uc9c0\ub9c9\uc5d0":76,"\ub9c8\uc9c0\ub9c9\uc73c\ub85c":[78,79],"\ub9c8\ucc2c\uac00\uc9c0\uc774\ub2e4":82,"\ub9cc":75,"\ub9cc\ub4dc\ub294":[75,80,82],"\ub9cc\ub4e0":75,"\ub9cc\ub4e0\ub2e4\uace0":75,"\ub9cc\ub4e4":[75,79,82],"\ub9cc\ub4e4\uace0":81,"\ub9cc\ub4e4\uc5b4":[79,81],"\ub9cc\ub4e4\uc5b4\uc11c":82,"\ub9cc\ub4e4\uc5b4\uc57c":80,"\ub9cc\ub4e4\uc5b4\uc9c4":81,"\ub9cc\ub4e4\uc5b4\uc9c4\ub2e4\uba74":82,"\ub9cc\ub4e4\uc5c8\ub2e4":79,"\ub9cc\uc57d":[76,79,80,82],"\ub9cc\uc744":[76,79],"\ub9ce\ub2e4":81,"\ub9ce\uc73c\ubbc0\ub85c":77,"\ub9ce\uc740":81,"\ub9d0\uc774\ub2e4":76,"\ub9d0\ud558\ub294":78,"\ub9d0\ud55c":76,"\ub9d0\ud588\ub2e4":82,"\ub9d0\ud588\ub4ef":76,"\ub9de\ub294\uac00":78,"\ub9de\uc744":76,"\ub9e4\uac1c":79,"\ub9e4\uc6b0":[78,82],"\uba39\ud788\ub294":76,"\uba3c\uc800":[78,79],"\uba54\ubaa8\ub9ac":75,"\uba64\ubc84":76,"\uba85\ub839\uc5b4\uac00":78,"\uba87":77,"\uba87\uba87":[76,78],"\ubaa8\ub2c8\ud130":76,"\ubaa8\ub450":[75,76],"\ubaa8\ub4c8\ub4e4\uc744":76,"\ubaa8\ub4e0":[75,76,78,81,82],"\ubaa9\ub85d\uc740":78,"\ubaa9\ud45c\uac00":75,"\ubab8\uc758":78,"\ubb34\uc5b8\uac00\ub97c":[76,78],"\ubb34\uc5c7\uc744":77,"\ubb34\uc5c7\uc774\ub4e0\uc9c0":82,"\ubb34\uc5c7\uc778\uac00":[77,79,82],"\ubb34\uc5c7\uc778\uc9c0\ub294":79,"\ubb34\uc791\uc704\ub85c":81,"\ubb34\ud55c":76,"\ubb36\uc744":80,"\ubb38\uad6c\uc774\ub2e4":76,"\ubb38\uc790\uc5f4\uc740":76,"\ubb38\uc790\uc5f4\uc774\ub2e4":76,"\ubb38\uc7a5\ub4e4":76,"\ubb38\uc81c\uac00":[76,77],"\ubb38\uc81c\ub97c":81,"\ubb3c\ub860":[75,76,77,78,79],"\ubb54\uac00":80,"\ubbf8\uce58\uac8c":82,"\ubc0f":78,"\ubc14\uafb8\uace0":77,"\ubc14\uafb8\ub294":77,"\ubc14\uafb8\ub294\uac00":79,"\ubc14\uafb8\uba74":81,"\ubc14\uafbc":78,"\ubc14\uafc0":77,"\ubc14\uafd4":79,"\ubc14\ub00c\ub294\uac00":77,"\ubc14\ub00c\ub294\uc9c0\ub97c":77,"\ubc14\ub294":79,"\ubc14\ub85c":[77,82],"\ubc18\ub4dc\uc2dc":[77,78],"\ubc18\ubcf5\ubb38":76,"\ubc18\uc601":78,"\ubc18\ud544\uc218\uc801\uc73c\ub85c":76,"\ubc18\ud658":76,"\ubc18\ud658\ud55c\ub2e4":[76,81],"\ubc1c\uc0dd":76,"\ubc1c\uc0dd\ud558\uba74":76,"\ubc1c\uc0dd\ud55c":76,"\ubc1c\uc804\ub41c":75,"\ubc1c\ud718\ub41c":82,"\ubc29\ubc95":78,"\ubc29\ubc95\uc740":[78,79],"\ubc29\ubc95\uc744":[77,78],"\ubc29\ubc95\uc774\ub2e4":79,"\ubc29\uc2dd":75,"\ubc29\ud5a5\uc73c\ub85c":78,"\ubc29\ud5a5\ud0a4\ub97c":78,"\ubc30\uc5f4\uacfc":81,"\ubc30\uc5f4\uc5d0\uc11c":81,"\ubc30\uc5f4\uc740":81,"\ubc30\uc5f4\uc744":[76,81],"\ubc30\uc5f4\uc774":81,"\ubc30\uc5f4\ucc98\ub7fc":81,"\ubc30\uc6b0\uace0":[78,82],"\ubc30\uc6b0\ub294":[75,76],"\ubc30\uc6b4\ub2e4":78,"\ubc30\ud2c0\uc2ed":75,"\ubc84\ud2bc":81,"\ubc84\ud2bc\ub4e4":83,"\ubc84\ud2bc\ub4e4\uc740":80,"\ubc84\ud2bc\ub4e4\uc744":80,"\ubc84\ud2bc\uc744":[77,80,81],"\ubc84\ud2bc\uc758":80,"\ubc88":77,"\ubc94\uc704\uac00":80,"\ubc95\uc744":81,"\ubcc0\uacbd\ud558\uba74\uc11c":79,"\ubcc0\uc218":[76,79,80],"\ubcc0\uc218\uac00":[76,77,79,80],"\ubcc0\uc218\ub294":[76,79],"\ubcc0\uc218\ub3c4":80,"\ubcc0\uc218\ub4e4\uc744":80,"\ubcc0\uc218\ub4e4\uc774":76,"\ubcc0\uc218\ub85c":[79,80],"\ubcc0\uc218\ub97c":[76,77,79,80],"\ubcc0\uc218\uc640":78,"\ubcc0\uc218\uc758":79,"\ubcc0\uc218\uc774\uace0":79,"\ubcc0\uc218\uc774\ub2e4":79,"\ubcc0\uc704\uac00":77,"\ubcc0\uc704\ub294":77,"\ubcc0\uc704\ub9cc":77,"\ubcc0\ud55c\ub2e4\uba74":79,"\ubcc0\ud560":79,"\ubcf4\uace0":75,"\ubcf4\ub2e4":77,"\ubcf4\uba74":[77,80],"\ubcf4\uc544\ub77c":[78,79,82],"\ubcf4\uc774\ub294":80,"\ubcf4\uc774\uc9c4":81,"\ubcf4\uc778\ub2e4":77,"\ubcf4\uc778\ub2e4\ub294":[75,77],"\ubcf4\uc77c":77,"\ubcf4\uc790":[75,82],"\ubcf4\ud1b5":75,"\ubcf5\uc18c\uc218\uc88c\ud45c\ub97c":75,"\ubcf5\uc7a1\ub3c4\ub294":77,"\ubcf5\uc7a1\ub3c4\ub97c":77,"\ubcf5\uc7a1\ud558\ub2e4":76,"\ubcf5\uc7a1\ud55c":75,"\ubcf8\uaca9\uc801\uc73c\ub85c":79,"\ubcfc\ub9cc":75,"\ubd80":83,"\ubd80\ubd84\uc5d0\uc11c":78,"\ubd80\ubd84\uc73c\ub85c":76,"\ubd80\ubd84\uc758":81,"\ubd80\uc5ec\ud560":82,"\ubd84\uc11d\ud558\uc9c0":77,"\ubd88\uacfc\ud558\ub2e4":78,"\ubd88\uacfc\ud558\ubbc0\ub85c":77,"\ubd88\ub9b4":78,"\ubd88\uc5f0\uc18d\uc801":79,"\ube14\ub85d":81,"\ube14\ub85d\uc744":81,"\ube14\ub85d\uc758":81,"\ube44\uad50\ud558\uc5ec":78,"\ube44\ud45c\uc900":75,"\ube44\ud558\uba74":76,"\ube48\ub3c4\uc5d0":77,"\ube60\ub978":75,"\ube60\ub97c\uae4c":77,"\ube60\uc9c0\uba74":75,"\ube68\uac04":[76,79,81],"\ube68\uac04\ube14\ub85d":16,"\ube68\ub9ac":75,"\ubfcc\uc694\ubfcc\uc694":75,"\uc0ac\uae30\uac00":80,"\uc0ac\ub78c\ub4e4\uc774":82,"\uc0ac\ub78c\uc774":82,"\uc0ac\uc2e4":81,"\uc0ac\uc6a9\ub418\uc5c8\uae30":80,"\uc0ac\uc6a9\ub418\uc5c8\uc9c0\ub9cc":80,"\uc0ac\uc6a9\ub41c":79,"\uc0ac\uc6a9\uc790\uac00":[76,80],"\uc0ac\uc6a9\ud558\uae30":76,"\uc0ac\uc6a9\ud558\ub294":76,"\uc0ac\uc6a9\ud558\uc5ec":76,"\uc0ac\uc6a9\ud560":76,"\uc0ac\uc774\uc5d0\ub294":75,"\uc0ac\uc774\uc758":75,"\uc0ac\uc9c4":75,"\uc0b4\ud3b4\ubcf4\uc790":76,"\uc0bd\uc785\ud558\uba74":76,"\uc0c1\uc138\ud558\uac8c":79,"\uc0c1\uc218":80,"\uc0c1\uc218\ub4e4\uc744":76,"\uc0c1\ud0dc":78,"\uc0c1\ud0dc\ub97c":75,"\uc0c1\ud638\uc791\uc6a9\uc774":78,"\uc0c8\ub85c\uc6b4":[79,81,82],"\uc0c9":[75,76,79],"\uc0c9\uc0c1":[76,79],"\uc0c9\uc0c1\uacfc":76,"\uc0c9\uc0c1\uc740":[76,81],"\uc0c9\uc0c1\uc744":[76,81],"\uc0c9\uc0c1\uc758":81,"\uc0c9\uc774":76,"\uc0dd\uac01\uc77c":80,"\uc0dd\uac01\ud574":82,"\uc0dd\uac01\ud574\ubcf4\uba74":78,"\uc0dd\uac01\ud574\ubd10\ub77c":78,"\uc0dd\uacbc\ub2e4":78,"\uc0dd\uae38":76,"\uc0dd\uc131\ud558\uace0":76,"\uc11c\ub85c":76,"\uc120\uc5b8":76,"\uc120\uc5b8\ub418\uc5b4\uc57c":76,"\uc120\ud0dd\uc801\uc73c\ub85c":75,"\uc120\ud0dd\uc801\uc778":77,"\uc120\ud0dd\uc9c0\ub294":81,"\uc120\ud589\ub418\uc5b4\uc57c":79,"\uc124\uba85\uc774":76,"\uc124\uba85\uc774\uc5c8\ub2e4":76,"\uc124\uba85\ud558\ub294":79,"\uc124\uba85\ud560":81,"\uc124\uc815":75,"\uc131\ubd84":76,"\uc131\ubd84\uc774":76,"\uc138\uace0":81,"\uc138\ud305":78,"\uc148\uc774\ub2e4":76,"\uc18c\uac1c":83,"\uc18c\ub9ac":[75,78],"\uc18c\uc124":82,"\uc18c\uc2a4":[75,76,77,78],"\uc18c\uc2a4\ucf54\ub4dc":76,"\uc18c\uc2a4\ucf54\ub4dc\uac00":76,"\uc18c\uc2a4\ucf54\ub4dc\ub294":76,"\uc18c\uc2a4\ucf54\ub4dc\ub97c":[75,76],"\uc18c\uc2a4\ucf54\ub4dc\uc5d0":76,"\uc18c\uc2a4\ucf54\ub4dc\uc640":75,"\uc18c\uc2a4\ucf54\ub4dc\uc758":76,"\uc18c\uc2a4\ud30c\uc77c\uc5d0":75,"\uc18c\uc2a4\ud30c\uc77c\uc740":75,"\uc18d":76,"\uc18d\ub3c4\ub97c":77,"\uc18d\ub3c4\uc5d0":77,"\uc18d\ub3c4\uc774\ub77c\ub294":77,"\uc18d\uc5d0\ub294":77,"\uc190\uac00\ub77d":78,"\uc190\uc744":75,"\uc218":[75,76,77,78,79,80,81,82],"\uc218\uac00":82,"\uc218\ub294":[77,82],"\uc218\ub3c4":82,"\uc218\ub97c":81,"\uc218\ub9ce\uc740":75,"\uc218\uc815\ud558\ub294":76,"\uc218\uc815\ud55c\ub2e4\uba74":76,"\uc218\uc900":75,"\uc218\ud589\ub418\uc5b4\uc57c":76,"\uc218\ud589\ud55c\ub2e4":76,"\uc21c\ucc28\uc801\uc73c\ub85c":76,"\uc26c\uc6b4":79,"\uc27d\uac8c":[77,79],"\uc27d\ub2e4":[77,78,80],"\uc2a4\ud06c\ub9b0":76,"\uc2b5\ub4dd\ud560":82,"\uc2dc\uac01\uc801":81,"\uc2dc\uac01\ud654":[78,79],"\uc2dc\uac04":[77,78,81],"\uc2dc\uac04\ubcf4\ub2e4":82,"\uc2dc\uac04\uc21c\uc73c\ub85c":76,"\uc2dc\uac04\uc740":77,"\uc2dc\uac04\uc744":[77,82],"\uc2dc\uac04\uc774":[76,82],"\uc2dc\uac04\uc774\ub2e4":82,"\uc2dc\ub3c4\ud574":75,"\uc2dc\uc2a4\ud15c\uc744":78,"\uc2dc\uc2a4\ud15c\uc774":76,"\uc2dc\uc791\ub418\uae30":77,"\uc2dc\uc791\ub420":77,"\uc2dc\uc791\ud558\ub294":77,"\uc2dc\ud589":82,"\uc2dd\uc758":75,"\uc2e0\uacbd":80,"\uc2e4\uc81c\ub85c":76,"\uc2e4\ud589":[76,77,78,81],"\uc2e4\ud589\ub418\uac70\ub098":75,"\uc2e4\ud589\ub418\ub294":[75,77],"\uc2e4\ud589\ub418\uba74":76,"\uc2e4\ud589\ub418\uc57c":77,"\uc2e4\ud589\ub418\uc5b4\uc57c":76,"\uc2e4\ud589\ub418\uc9c0":76,"\uc2e4\ud589\ub41c\ub2e4":76,"\uc2e4\ud589\ub41c\ub2e4\ub294":75,"\uc2e4\ud589\ub428":75,"\uc2e4\ud589\ud558\ub294":75,"\uc2eb\ub2e4\uba74":80,"\uc2ec\ud654":78,"\uc2ec\ud654\ub41c":78,"\uc2f6\ub2e4\uba74":75,"\uc2f6\uc744":76,"\uc368\uc57c":80,"\uc4f0\uba74":76,"\uc4f8":75,"\uc544\ub2c8\ub2e4":78,"\uc544\ub2c8\ub77c":77,"\uc544\ub2c8\ubbc0\ub85c":77,"\uc544\ub2c8\uc9c0\ub9cc":78,"\uc544\ub2cc":[75,76,77,79,80,81],"\uc544\ub2cc\uc9c0\ub97c":78,"\uc544\ub798\ub97c":79,"\uc544\ub798\uc640":79,"\uc544\ub798\ucabd\uc774":76,"\uc544\ub9c8\ub3c4":78,"\uc544\ubb34":82,"\uc544\ubb34\ub798\ub3c4":75,"\uc544\uc2a4\ud0a4\uc544\ud2b8\ub97c":75,"\uc544\uc774\ub514\uc5b4\ub294":79,"\uc544\uc774\ub514\uc5b4\ub97c":79,"\uc544\uc774\ub514\uc5b4\uc640":79,"\uc544\uc774\ub514\uc5b4\ucc98\ub7fc":80,"\uc544\uc9c1":[79,80],"\uc544\uc9c1\ub3c4":[77,80],"\uc548\ub418\ub294":77,"\uc548\ub41c\ub2e4":76,"\uc54a\ub294":[76,77],"\uc54a\ub294\ub2e4":[77,78,79,81],"\uc54a\ub2e4":79,"\uc54a\ub2e4\uba74":80,"\uc54a\uc558\uc9c0\ub9cc":78,"\uc54a\uc73c\uba74":76,"\uc54a\uc744":[76,77],"\uc54c":[76,80,81],"\uc54c\uace0":[77,78],"\uc54c\uace0\ub9ac\uc998\uc73c\ub85c":75,"\uc54c\uace0\ub9ac\uc998\uc758":78,"\uc54c\uace0\ub9ac\uc998\uc774":78,"\uc54c\ub809\uc138\uc774":82,"\uc54c\uc544\ub0b4\uae30":80,"\uc54c\uc544\ub0bc":[76,77],"\uc54c\uc544\uc57c":78,"\uc54c\uc558\ub2e4":77,"\uc54c\uce74\ub178\uc774\ub4dc\uc758":77,"\uc55e\ubd80\ubd84\uc5d0":77,"\uc55e\uc11c":76,"\uc55e\uc11c\uc11c":76,"\uc55e\uc5d0":78,"\uc560\ub2c8\uba54\uc774\uc158":[75,77],"\uc57d\uac04":78,"\uc57d\uac04\uc758":76,"\uc5b4\ub5a4":[76,82],"\uc5b4\ub5a4\uac00":79,"\uc5b4\ub5a8\uae4c":[76,80],"\uc5b4\ub5bb\uac8c":[76,77,79,80,81],"\uc5b4\ub835\uc9c0":76,"\uc5b4\uca0c\ub4e0":78,"\uc5b4\ucc0c\ub410\ub4e0":76,"\uc5b8\uae09\ud558\uaca0\ub2e4":76,"\uc5b8\uae09\ud55c":81,"\uc5b8\uc5b4\uc758":76,"\uc5bc\ub9c8\ub098":77,"\uc5bc\ub9cc\ud07c\uc758":82,"\uc5c5\ub370\uc774\ud2b8":77,"\uc5c5\ub370\uc774\ud2b8\uac00":76,"\uc5c5\ub370\uc774\ud2b8\ub418\uac70\ub098":76,"\uc5c5\ub370\uc774\ud2b8\ub418\uac8c":77,"\uc5c5\ub370\uc774\ud2b8\ub418\uc5c8\ub294\uc9c0\ub97c":77,"\uc5c5\ub370\uc774\ud2b8\ub41c\ub2e4":78,"\uc5c5\ub370\uc774\ud2b8\ud558\ub294":[77,78,80],"\uc5c6\uace0":[78,80],"\uc5c6\uae30":[76,77,78],"\uc5c6\ub294":[75,76,82],"\uc5c6\ub2e4":[77,78,81],"\uc5c6\uc73c\ubbc0\ub85c":[77,80],"\uc5c6\uc774":[76,78],"\uc5d0":76,"\uc5d0\uc11c":82,"\uc5d0\uc120":76,"\uc5d0\ud544\ub85c\uadf8":83,"\uc5d4\uc9c4":75,"\uc5d4\uc9c4\uc5d0\ub3c4":75,"\uc5d4\uc9c4\uc740":75,"\uc5d4\uc9c4\uc744":75,"\uc5d4\uc9c4\uc758":75,"\uc5d4\ud130":75,"\uc5ec\uae30\uc11c":77,"\uc5ec\uae30\uc5d0":76,"\uc5ec\uae30\uc5d0\uc11c":82,"\uc5ec\ub7ec":75,"\uc5ec\ub7ec\uac00\uc9c0":76,"\uc5ec\uc804\ud788":79,"\uc5ec\uc9c0\uac00":81,"\uc5f0\uacb0\uc2dc\ud0a4\uba74\uc11c":82,"\uc5f0\uacb0\uc810\uc774":75,"\uc601\uc5ed":80,"\uc601\uc5ed\uacfc":80,"\uc601\uc5ed\uc744":80,"\uc601\uc5ed\uc774":80,"\uc601\ud5a5\uc744":82,"\uc601\ud654":82,"\uc608\ub97c":[76,79],"\uc608\uc2dc":75,"\uc608\uc2dc\uc774\ub2e4":82,"\uc608\uc678\uc801\uc73c\ub85c":76,"\uc608\uc81c\uc778":76,"\uc608\uce21\ub418\uae30":77,"\uc624\uac8c":76,"\uc624\uac8c\ub054":76,"\uc624\ub2f5\uc774\ub77c\uba74":81,"\uc624\ub2f5\uc77c":81,"\uc624\ub798":76,"\uc624\ub978\ucabd\uc774":76,"\uc624\ube0c\uc81d\ud2b8\uac04":78,"\uc624\ube0c\uc81d\ud2b8\uc758":77,"\uc624\uc9c1":[79,80],"\uc640":[76,77,78,80,82],"\uc640\uc57c":77,"\uc644\ubcbd\ud788":82,"\uc644\uc131\ub418\uc5c8\ub2e4":78,"\uc644\uc804\ud55c":80,"\uc644\uc804\ud788":78,"\uc65c":78,"\uc65c\ub098\ud558\uba74":76,"\uc65c\ub0d0\uba74":78,"\uc65c\ub0d0\ud558\uba74":[77,78],"\uc678\ubd80":75,"\uc678\uc758":76,"\uc694\uc18c":[78,81],"\uc694\uc18c\ub97c":76,"\uc694\uc57d\ud558\uc790\uba74":75,"\uc6a9":80,"\uc6a9\ub3c4\uac00":79,"\uc6a9\uc774\ub2e4":81,"\uc6b0":80,"\uc6b0\ub9ac\uac00":77,"\uc6b0\ub9ac\ub294":[77,78,81,82],"\uc6b0\ub9ac\uc758":82,"\uc6b0\uc120":[76,77,78,79,81],"\uc6c0\uc9c1\uc774\uac8c":77,"\uc6c0\uc9c1\uc774\ub294":77,"\uc6c0\uc9c1\uc778\ub2e4":[77,78],"\uc6c0\uc9c1\uc778\ub2e4\ub294":78,"\uc6c0\uc9c1\uc77c\uae4c":77,"\uc6d0\ub9ac\ub97c":76,"\uc704":79,"\uc704\uce58":[76,79],"\uc704\uce58\uac00":77,"\uc704\uce58\ub97c":76,"\uc704\uce58\uc5d0\uc11c\uc758":80,"\uc704\ud55c":[75,76,80,81],"\uc704\ud574":[76,78,82],"\uc704\ud574\uc11c\ub294":78,"\uc704\ud574\uc120":76,"\uc708\ub3c4\uc6b0":76,"\uc708\ub3c4\uc6b0\uc758":77,"\uc720\ub2c8\ud2f0":75,"\uc720\uc6a9\ud55c":76,"\uc73c\ub85c":[75,76],"\uc740":77,"\uc744":[77,78,81],"\uc74c\uc545":82,"\uc758":75,"\uc758\ubbf8\ub97c":80,"\uc758\ubbf8\ud558\uac8c":[77,80],"\uc758\ubbf8\ud558\uace0":78,"\uc758\ubbf8\ud558\uc9c0\ub294":78,"\uc758\ubbf8\ud55c\ub2e4":[76,77,78],"\uc774":[75,76,77,78,79,80,81,82],"\uc774\uac83\ub4e4\uc740":79,"\uc774\uac83\uc740":[76,77,81],"\uc774\uac83\uc774":[75,76,82],"\uc774\ub294":[77,78],"\uc774\ub2e4":76,"\uc774\ub3d9":83,"\uc774\ub780":75,"\uc774\ub7f0":[75,78],"\uc774\ub807\uac8c":75,"\uc774\ub8e8\uc5b4\uc9c4\ub2e4":[76,79],"\uc774\ub8e8\uc5b4\uc9d0\uc5d0":78,"\uc774\ub97c":77,"\uc774\ub984":78,"\uc774\ub984\uc73c\ub85c\ub294":78,"\uc774\ub984\uc744":78,"\uc774\ub984\uc758":76,"\uc774\ubbf8":82,"\uc774\ubbf8\uc9c0":[77,78,81],"\uc774\ubca4\ud2b8\uac00":[76,78],"\uc774\ubca4\ud2b8\ub4e4\uc740":76,"\uc774\ubca4\ud2b8\ub4e4\uc744":76,"\uc774\ubca4\ud2b8\ub4e4\uc758":76,"\uc774\ubca4\ud2b8\ub97c":[76,78,80],"\uc774\ubca4\ud2b8\uc801":75,"\uc774\ubcc4\uc744":76,"\uc774\uc0c1":[75,77],"\uc774\uc0c1\uc758":78,"\uc774\uc5d0":76,"\uc774\uc6a9\ud558\uba74":77,"\uc774\uc6a9\ud55c":75,"\uc774\uc6a9\ud560":78,"\uc774\uc720\ub294":80,"\uc774\uc720\uc774\ub2e4":[75,78,82],"\uc774\uc804":[77,78],"\uc774\uc804\uacfc":79,"\uc774\uc804\ubd80\ud130":78,"\uc774\uc804\uc5d0\ub294":78,"\uc774\uc804\uc758":[76,78,80],"\uc774\uc81c":[77,78,80,81,82],"\uc774\uc81c\ub294":79,"\uc774\uc820":77,"\uc774\ud574\ud558\ub294":76,"\uc774\ud574\ud560":[78,79],"\uc774\ud574\ud588\ub2e4\uba74":76,"\uc774\ud6c4":76,"\uc774\ud6c4\uc5d0":76,"\uc778\uc790\ub97c":78,"\uc778\ud130\ud398\uc774\uc2a4":78,"\uc778\ud130\ud398\uc774\uc2a4\ub97c":81,"\uc77c\ubc18\uc801\uc73c\ub85c":76,"\uc77c\ubd80":[76,77,78],"\uc77c\ubd80\ubd84":78,"\uc77c\ubd80\uc774\uae30":75,"\uc77c\uc5b4\ub0ac\ub294\uc9c0":80,"\uc77c\uc73c\ud0a4\ub294":82,"\uc77c\uc885\uc758":77,"\uc77c\uce58\ud558\uc9c0":76,"\uc784\ub9c8\ub204\uc5d8":82,"\uc784\uc740":77,"\uc785\ub825":[75,76,77,80],"\uc785\ub825\ubcf4\ub2e4":82,"\uc785\ub825\uc2dc\ud0a4\ub294":82,"\uc785\ub825\uc740":[75,80],"\uc785\ub825\uc744":[78,80],"\uc785\ub825\uc774":[77,78],"\uc785\ub825\uc774\ub098":77,"\uc785\ub825\uc774\ub780":80,"\uc785\ub825\ud558\ub294":78,"\uc785\ubb38\uc7a5\ubcbd\uc774":75,"\uc788\uac8c":[75,76],"\uc788\uace0":79,"\uc788\uae30":78,"\uc788\ub290\ub0d0":78,"\uc788\ub294":[75,76,80,81,82],"\uc788\ub294\ub370":79,"\uc788\ub2e4":[75,76,77,78,79,80,81,82],"\uc788\ub2e4\uace0":76,"\uc788\ub3c4\ub85d":79,"\uc788\uc5b4\uc57c":77,"\uc788\uc73c\uba74":75,"\uc788\uc744\uae4c":[75,76],"\uc788\uc74c":80,"\uc788\uc74c\uc744":[77,78,80],"\uc790\ub3d9\uc801\uc73c\ub85c":[76,77],"\uc790\uc8fc":77,"\uc791\ub3d9":76,"\uc791\ub3d9\ud558\uc9c0":77,"\uc791\uc131\ub418\uc5b4\uc57c":76,"\uc791\uc131\uc740":81,"\uc791\uc131\ud558\ub294":75,"\uc791\uc131\ud55c":75,"\uc791\uc5c5\uc774":76,"\uc791\uc740":[79,80],"\uc7a5":77,"\uc7a5\uc774":77,"\uc7a5\uc810\ub3c4":75,"\uc7a5\uc810\uc740":75,"\uc7a5\uc810\uc744":75,"\uc800\uae09":75,"\uc800\uc7a5\ud574":76,"\uc801\uc6a9\ub418\uc5b4":80,"\uc801\uc808\ud55c":[76,77,78,80],"\uc801\uc808\ud788":76,"\uc804\uc138\uacc4":82,"\uc804\uc5ed":76,"\uc804\uccb4":[76,81],"\uc804\uccb4\ub97c":79,"\uc804\ud600":78,"\uc808\ucc28\uc801\uc73c\ub85c":75,"\uc808\ucc28\uc801\uc774":75,"\uc810\uc218\ub3c4":78,"\uc810\uc740":80,"\uc811\uadfc\uc131\uc774":75,"\uc811\uadfc\ud560":75,"\uc815\ub2f5\uc774\uac70\ub098":81,"\uc815\ub2f5\uc774\ub77c\uba74":81,"\uc815\ub82c\ub41c\ub2e4":76,"\uc815\ub9ac\ub97c":77,"\uc815\ubcf4\ub4e4\uc740":76,"\uc815\ubcf4\ub97c":76,"\uc815\uc0ac\uac01\ud615":80,"\uc815\uc0ac\uac01\ud615\uc744":80,"\uc815\uc218":[79,81],"\uc815\uc2e0\uc5c6\uc774":77,"\uc815\uc758":78,"\uc815\uc911\uc559\uc5d0":76,"\uc815\uc911\uc559\uc73c\ub85c":76,"\uc815\uc911\uc559\uc740":76,"\uc815\uc911\uc559\uc744":76,"\uc815\uc9c0\ub41c":77,"\uc815\ud558\uace0":76,"\uc815\ud558\ub294":79,"\uc815\ud55c\ub2e4":76,"\uc815\ud560":[76,77],"\uc815\ud574\uc57c":76,"\uc815\ud574\uc838\uc57c":76,"\uc815\ud655\ud788\ub294":76,"\uc81c\uacf5\ud558\uae30":75,"\uc81c\uc57d\uc870\uac74":78,"\uc81c\uc678\ud654\uba74":75,"\uc81c\uc791":75,"\uc81c\ud55c\uc744":81,"\uc870\uac74\ubb38\uc774":76,"\uc870\uac74\uc774":76,"\uc870\uc808\ud558\uac8c":79,"\uc870\uc885":83,"\uc874\uc7ac\ud558\uace0":80,"\uc874\uc7ac\ud558\uae30":77,"\uc874\uc7ac\ud568\uc744":80,"\uc885\ub8cc":77,"\uc885\ub8cc\ub418\uac8c":76,"\uc885\ub8cc\ub418\uace0":78,"\uc885\ub8cc\ub418\uc5b4\uc57c":76,"\uc885\ub8cc\ub41c":76,"\uc885\ub8cc\ud558\uace0":76,"\uc885\ub8cc\ud558\ub294":77,"\uc885\ub958\uc758":76,"\uc88b\ub2e4\ub294":75,"\uc88b\uc740":[75,80],"\uc88b\uc744":79,"\uc88c\ud45c":76,"\uc88c\ud45c\ub97c":[78,79],"\uc88c\ud45c\uc5d0":77,"\uc8fc\ub294":75,"\uc8fc\ub85c":76,"\uc8fc\ubaa9\ud574\ub77c":78,"\uc8fc\uc5b4\uc9c4":76,"\uc904\ub4e4\uc740":78,"\uc911":[75,77],"\uc911\uc694\ud55c":82,"\uc990\uae38":78,"\uc99d\uac00\uc2dc\ud0a4\uac70\ub098":80,"\uc99d\uac00\ud558\uace0":81,"\uc9c0\uae08\uae4c\uc9c0":78,"\uc9c0\uae08\uc740":78,"\uc9c0\ub294":80,"\uc9c0\uc2dd\ub9cc\uc73c\ub85c":82,"\uc9c0\uc2dd\ubcf4\ub2e4":82,"\uc9c0\uc2dd\uc5d0":82,"\uc9c0\uc2dd\uc744":82,"\uc9c0\uc5d0":81,"\uc9c0\uc6b0\ub294":75,"\uc9c0\uc810\uc744":80,"\uc9c1\uad00\uc801\uc73c\ub85c":78,"\uc9c1\uad00\uc801\uc778":78,"\uc9c1\uc0ac\uac01\ud615":76,"\uc9c1\uc0ac\uac01\ud615\ub4e4\uc5d0":79,"\uc9c1\uc0ac\uac01\ud615\ub4e4\uc744":79,"\uc9c1\uc0ac\uac01\ud615\uc744":79,"\uc9c1\uc811":79,"\uc9c4\uc9dc":78,"\uc9c4\ud589\ub420":76,"\uc9c8":81,"\uc9c8\ub9b0\ub2e4\uba74":75,"\uc9d1\uc911\ud558\uba74":75,"\uc9dc\uc99d\ub0a0":81,"\ucc28\uc774\uc810\uc774":78,"\ucc28\uc774\uc810\uc774\ub2e4":78,"\ucc29\uc624\ub97c":82,"\ucc38\uace0":[76,77,78,79,80,81],"\ucc3d\uc758\uc801\uc778":82,"\ucc3e\uc544\ub0b4\uba74":77,"\ucc3e\uc744":79,"\ucc44\ub85c":78,"\ucc44\uc6b0\ub294":76,"\ucc98\ub9ac":[75,76,78],"\ucc98\ub9ac\uac00":[76,77],"\ucc98\ub9ac\ub294":75,"\ucc98\ub9ac\ub97c":79,"\ucc98\ub9ac\ub9cc\uc774":80,"\ucc98\ub9ac\uc758":76,"\ucc98\ub9ac\ud558\uace0":76,"\ucc98\ub9ac\ud558\ub294":80,"\ucc98\ub9ac\ud558\ub294\uc9c0\ub294":77,"\ucc98\ub9ac\ud558\ub824\uba74":81,"\ucc98\ub9ac\ud560":76,"\ucc9c\uc7ac\uc131\uc774\ub780":82,"\uccab\ubc88\uc9f8":79,"\uccab\uc9f8":[75,80],"\uccab\uc9f8\ub294":78,"\uccab\uc9f8\ub85c":76,"\uccb4\ud06c\ud558\ub294":76,"\ucd08\uae30\ud654\ub418\uac70\ub098":76,"\ucd08\uae30\ud654\ub41c\ub2e4":76,"\ucd08\uae30\ud654\ub428\uc744":77,"\ucd08\ub85d":76,"\ucd1d":79,"\ucd5c\ub300":79,"\ucd5c\ub300\uac12\uc774":79,"\ucd5c\ub300\ud55c":75,"\ucd5c\uc18c":76,"\ucd94\uac00":77,"\ucd94\uac00\ub418\uba74":81,"\ucd94\uac00\ub418\uc5c8\uace0":77,"\ucd94\uac00\ub418\uc5c8\ub2e4":[77,80],"\ucd94\uac00\ub41c":76,"\ucd94\uac00\ub41c\ub2e4":78,"\ucd94\uac00\uc801\uc73c\ub85c":78,"\ucd94\uac00\uc801\uc778":[76,77,78,79],"\ucd94\uac00\ud558\uac70\ub098":76,"\ucd94\uac00\ud558\ub294":[76,78],"\ucd94\uac00\ud558\ub824":81,"\ucd94\uac00\ud574\ubcf4\uc790":78,"\ucd94\uac00\ud574\uc57c":77,"\ucd9c\ub825":[75,78,79,81,83],"\ucd9c\ub825\ub418\uac8c":76,"\ucd9c\ub825\ub418\ub294":76,"\ucd9c\ub825\ub420":79,"\ucd9c\ub825\uc6a9\uc774\ub2e4":80,"\ucd9c\ub825\uc73c\ub85c":75,"\ucd9c\ub825\uc740":[75,78],"\ucd9c\ub825\uc744":[76,77,80],"\ucd9c\ub825\uc758":78,"\ucd9c\ub825\uc774":82,"\ucd9c\ub825\ud558\uae30":76,"\ucd9c\ub825\ud558\ub294":[76,78,79,81],"\ucd9c\ub825\ud55c\ub2e4":81,"\ucd9c\ub825\ud574\uc57c":81,"\ucda9\ub3cc":75,"\ucda9\ubd84\ud788":79,"\uce58\uace4":76,"\uce5c\uc219\ud55c":76,"\uce60\ud558\uae30":75,"\uce78\ud2b8\ub294":82,"\uce94\ubc84\uc2a4":[76,79],"\uce94\ubc84\uc2a4\ub97c":76,"\uce94\ubc84\uc2a4\uc5d0":76,"\uce94\ubc84\uc2a4\uc758":76,"\ucea1\uc158\uc5d0":76,"\ucee4\uc9c0\uac8c":82,"\ucee8\ud150\uce20":78,"\ucef4\ud4e8\ud130\ub294":82,"\ucef4\ud4e8\ud130\ub9c8\ub2e4":77,"\ucef4\ud4e8\ud130\uc5d0\uac8c":82,"\ucf54\ub4dc":[76,77,78,79,80,81],"\ucf54\ub4dc\uac00":76,"\ucf54\ub4dc\ub97c":75,"\ucf54\ub4dc\uc640":76,"\ucf54\ub529\ud558\uac8c":75,"\ucf54\ub529\ud574":75,"\ucf58\uc194":75,"\ucf58\uc194\uc5d0\uc11c":75,"\ud06c\uac8c":[79,81],"\ud06c\uace0":76,"\ud06c\uae30":76,"\ud06c\uae30\uac00":76,"\ud06c\uae30\ub97c":[76,81],"\ud06c\uae30\uc640":76,"\ud06c\ub2e4\ub294":82,"\ud06c\uba74":77,"\ud070":[75,78,79,80],"\ud074\uae4c":82,"\ud074\ub9ad":80,"\ud074\ub9ad\uc774":80,"\ud074\ub9ad\ud588\ub2e4":80,"\ud07c\uc744":76,"\ud0a4":78,"\ud0a4\ub294":78,"\ud0a4\ub4e4\ub3c4":78,"\ud0a4\ub97c":78,"\ud0a4\ubcf4\ub4dc":[75,78,79],"\ud0a4\ubcf4\ub4dc\uac00down\ub41c":80,"\ud0a4\ubcf4\ub4dc\uc5d0":78,"\ud0a4\uc758":78,"\ud0c4\ucc3d\uc5d0\uc11c":79,"\ud14c\ub450\ub9ac\ub97c":[79,81],"\ud14c\ud2b8\ub9ac\uc2a4\ub97c":82,"\ud14d\uc2a4\ud2b8":[76,83],"\ud14d\uc2a4\ud2b8\uac00":[76,79],"\ud14d\uc2a4\ud2b8\ub294":76,"\ud14d\uc2a4\ud2b8\ub97c":[76,77,79],"\ud14d\uc2a4\ud2b8\uc758":[76,77],"\ud14d\uc2a4\ud2b8\uc774\ub2e4":79,"\ud1b5\ud574":80,"\ud22c\uc790\ud588\uc744\uae4c":82,"\ud234\uc774":75,"\ud29c\ud1a0\ub9ac\uc5bc":[16,81],"\ud29c\ud1a0\ub9ac\uc5bc\uc740":82,"\ud2b8\ub9ac\uac70":78,"\ud2b8\ub9ac\uac70\ub418\uba74":76,"\ud2b9\uc131":[76,81],"\ud2b9\uc131\uc774":82,"\ud2b9\uc131\uc774\ub2e4":82,"\ud2b9\uc774\ud55c":80,"\ud2b9\uc815":[76,77,80],"\ud2b9\uc815\ud55c":80,"\ud30c\uc774\uac8c\uc784":[76,81],"\ud30c\uc774\uac8c\uc784\uc740":[75,76],"\ud30c\uc774\uac8c\uc784\uc744":75,"\ud30c\uc774\uac8c\uc784\uc758":[75,76,77,82],"\ud30c\uc774\uac8c\uc784\uc774":[75,76],"\ud30c\uc774\uc36c\uc5d0":75,"\ud30c\uc774\uc36c\uc758":[75,76],"\ud30c\uc77c":75,"\ud30c\uc77c\ub85c":81,"\ud30c\uc77c\uc744":[75,76],"\ud30c\uc77c\uc774\ub098":75,"\ud30c\uc9c0\ud2b8\ub178\ud504\uac00":82,"\ud310\ub2e8\ud558\ub294":78,"\ud310\uc815":80,"\ud3ec\ud568":82,"\ud3ed\ub113\uc740":82,"\ud3f0\ud2b8":76,"\ud3f0\ud2b8\ub97c":76,"\ud3f0\ud2b8\uc640":76,"\ud479":75,"\ud48d\uc131\ud558\uac8c":78,"\ud504\ub85c\uadf8\ub798\uba38\uac00":75,"\ud504\ub85c\uadf8\ub798\uba38\ub294":75,"\ud504\ub85c\uadf8\ub798\ubc0d":76,"\ud504\ub85c\uadf8\ub798\ubc0d\uacfc":82,"\ud504\ub85c\uadf8\ub798\ubc0d\uc740":82,"\ud504\ub85c\uadf8\ub798\ubc0d\uc758":82,"\ud504\ub85c\uadf8\ub7a8":[76,77],"\ud504\ub85c\uadf8\ub7a8\uacfc":75,"\ud504\ub85c\uadf8\ub7a8\uc5d0":81,"\ud504\ub85c\uadf8\ub7a8\uc5d0\uc120":78,"\ud504\ub85c\uadf8\ub7a8\uc740":[81,82],"\ud504\ub85c\uadf8\ub7a8\uc744":[76,77,79,82],"\ud504\ub85c\uadf8\ub7a8\uc758":[75,76,78],"\ud504\ub85c\uadf8\ub7a8\uc774":79,"\ud504\ub85c\uc81d\ud2b8":77,"\ud504\ub85c\uc81d\ud2b8\uac00":[76,78],"\ud504\ub85c\uc81d\ud2b8\ub294":[76,77,78],"\ud504\ub85c\uc81d\ud2b8\ub85c":76,"\ud504\ub85c\uc81d\ud2b8\uc5d0\uc11c":76,"\ud504\ub85c\uc81d\ud2b8\uc640":78,"\ud504\ub85c\uc81d\ud2b8\uc740":75,"\ud504\ub85c\uc81d\ud2b8\uc758":[76,77,78],"\ud504\ub85c\uc81d\ud2b8\uc774\uba70":76,"\ud504\ub864\ub85c\uadf8":83,"\ud504\ub864\ub85c\uadf8\uc5d0\uc11c":81,"\ud504\ub9b0\ud2b8":80,"\ud50c\ub808\uc774":[78,82],"\ud53c\ud0c0\uace0\ub77c\uc2a4":77,"\ud544\uc218\uc870\uac74\uc774":78,"\ud544\uc218\uc870\uac74\uc774\uae30":78,"\ud544\uc694":[75,76,81],"\ud544\uc694\ub85c":76,"\ud544\uc694\ud558\uac8c":80,"\ud544\uc694\ud558\ub2e4":[76,78],"\ud544\uc694\ud560":77,"\ud558\uaca0\ub2e4":79,"\ud558\uace0":81,"\ud558\uae30":[76,78],"\ud558\uae30\ub9cc":79,"\ud558\ub098":75,"\ud558\ub098\ub85c":80,"\ud558\ub098\ub9cc":81,"\ud558\ub098\uc758":[75,76,77,79,82],"\ud558\ub098\uc774\ub2e4":77,"\ud558\ub294":[76,77,80],"\ud558\ub294\ub370":80,"\ud558\ub294\uc9c0":76,"\ud558\ub2e4":75,"\ud558\uba74":[76,77,79],"\ud558\uc580":79,"\ud558\uc580\uc0c9":76,"\ud558\uc600\ub2e4":79,"\ud558\uc9c0\ub9cc":[75,76,77,79,80,82],"\ud55c":[77,80,82],"\ud55c\uad6d\uc5b4":16,"\ud55c\ub2e4":[76,77,78,79,80,81],"\ud55c\ubc88\ub9cc":76,"\ud55c\ubc88\ucbe4\uc740":75,"\ud560":[76,77,79,82],"\ud560\uae4c":79,"\ud560\ub2f9\ub41c":76,"\ud568\uc218":[76,77],"\ud568\uc218\uac00":[76,77],"\ud568\uc218\ub294":[76,77,80,81],"\ud568\uc218\ub4e4\uacfc":75,"\ud568\uc218\ub4e4\uc740":[75,76],"\ud568\uc218\ub4e4\uc744":[75,76],"\ud568\uc218\ub4e4\uc774":75,"\ud568\uc218\ub85c":75,"\ud568\uc218\ub97c":[76,79],"\ud568\uc218\ubcf4\ub2e4":77,"\ud568\uc218\uc5d0\uc120":79,"\ud568\uc218\uc640":[76,77],"\ud568\uc218\uc758":76,"\ud568\uc218\uc774\uae30":76,"\ud568\uc218\uc774\ub2e4":77,"\ud568\uc218\ud654":78,"\ud568\uc218\ud654\ub97c":79,"\ud56d\uc0c1":[75,76,78,80],"\ud574":75,"\ud574\uacb0\ud560":75,"\ud574\ub2f9":78,"\ud574\ub2f9\ub418\ub294":77,"\ud574\uc11c":81,"\ud574\uc57c":[76,79],"\ud5f7\uac08\ub9ac\uba74":76,"\ud604\uc7ac":79,"\ud615\uc2dd\uc5d0":76,"\ud615\uc2dd\uc744":76,"\ud615\uc2dd\uc774":76,"\ud638\ucd9c\ub418\ub294\ub370":76,"\ud638\ucd9c\ub418\uba74":76,"\ud638\ucd9c\ub418\uc5b4\uc57c":76,"\ud638\ucd9c\ub41c\ub2e4":76,"\ud638\ud658\uc131":75,"\ud654\ub824\ud55c":76,"\ud654\uba74":[76,79],"\ud654\uba74\uacfc":76,"\ud654\uba74\ubcf4\ub2e4\ub294":77,"\ud654\uba74\ubcf4\ud638\uae30\ucc98\ub7fc":77,"\ud654\uba74\uc744":[75,77],"\ud654\uba74\uc758":76,"\ud655\uc2e4\ud558\ub2e4":77,"\ud655\uc778\ud558\ub294":[75,79],"\ud655\uc778\ud558\ub77c":80,"\ud655\uc778\ud558\uba74":[79,80],"\ud655\uc778\ud560":[77,78,79],"\ud655\uc778\ud574\uc57c":78,"\ud655\uc815\ub41c\ub2e4\uba74":76,"\ud658\uacbd":75,"\ud658\uacbd\uacfc":75,"\ud658\uacbd\uc5d0\uc11c":75,"\ud658\uacbd\uc5d0\uc11c\uc758":75,"\ud658\uacbd\uc6a9":75,"\ud658\uacbd\uc740":75,"\ud65c\ub3d9\uc774\ub2e4":82,"\ud65c\uc131\ud654\ub418\uba74":80,"\ud65c\uc6a9\ud558\uace0":82,"\ud65c\uc6a9\ud55c":75,"\ud65c\uc6a9\ud574":75,"\ud69f\uc218\ub97c":77,"\ud6a8\uacfc\uac00":[80,82],"\ud6a8\uacfc\ub97c":81,"\ud6a8\uacfc\uc74c\uc744":81,"\ud6c4":[75,78],"\ud6e8\uc52c":79,"\ud765\ubbf8\ub85c\uc6b4":82,"always\ubb38":[76,77],"always\ubb38\uacfc":79,"always\ubb38\uc5d0":[76,77],"always\ubb38\uc5d0\uc11c":76,"always\ubb38\uc758":77,"always\ubb38\uc774":77,"b\u00e9zier":30,"b\uac12":76,"blit\uc774":76,"blit\ud568\uc218\ub294":76,"boolean":[25,28,32,33,39,56,64],"break":[18,30,33,46,54,62,88],"byte":[10,15,17,18,20,22,23,28,29,31,37,38,42,43,44,46,51],"c\ub85c":75,"case":[16,18,20,23,24,28,29,31,33,37,38,40,43,44,51,57,58,64,68,70,72,73,74,84,85,87,88],"catch":[44,64,89],"center\ub77c\ub294":76,"char":[1,7,10,28,29,51],"class":[0,16,17,19,20,26,29,31,32,35,37,38,45,51,57,61,62,66,84,86,89],"collidepoint\ub97c":80,"const":[1,7,10,70],"cui\uac00":75,"cui\uace0":75,"cui\ud658\uacbd\uc5d0\uc11c\ub9cc":76,"default":[1,15,18,20,22,23,24,25,26,28,29,31,33,35,37,38,40,43,44,45,48,50,51,53,54,56,58,59,63],"do":[9,16,18,19,20,22,23,24,25,26,27,29,32,35,41,42,44,45,50,51,56,57,58,59,60,61,63,64,65,67,68,69,74,85,86,87,88,89],"drawbuttons\uc5d0":80,"drawhp\ub77c\ub294":79,"else\ubb38\uc740":77,"event\ubb38":[76,78],"event\ubb38\uc5d0":80,"event\ubb38\uc5d0\uc11c":79,"event\ubb38\uc744":79,"event\ubb38\uc774":78,"export":[0,11,20,38,42,43,51],"fill\ud568\uc218\ub098":76,"final":[22,26,28,29,42,44,51,58,61,62,71,84,85,86,89],"float":[1,17,19,20,24,29,30,32,35,36,38,40,45,48,50,54,56,65],"fps\uac00":77,"fps\uac12\uc774":77,"fps\ub294":77,"fps\ub300\ub85c":77,"function":[0,1,8,9,10,13,16,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33,35,37,38,39,40,41,43,44,45,46,47,48,49,50,51,52,53,54,56,57,58,60,61,63,64,66,67,68,69,70,72,73,84,85,87,88,89],"g\uac12":76,"gui\uac00":80,"gui\ub97c":76,"gui\uc5d0\uc11c\uc758":80,"gui\uc774\ubbc0\ub85c":76,"gui\uc774\uc9c0\ub9cc":81,"gui\uc784\uc744":76,"gui\ud658\uacbd\uc5d0\uc11c":76,"header\uc5d0\uc120":76,"header\uc758":78,"hp\ub294":[79,81],"hp\ub97c":[79,80],"hp\ubc14":83,"hp\uc744":79,"hp\uc758":79,"import":[1,11,16,18,22,24,25,26,27,28,29,30,32,34,36,38,39,44,49,52,53,59,61,62,63,64,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84,85,86,89],"import\ud558\ub294":76,"in\ubb38\uc744":76,"initial\ubb38":76,"initial\ubb38\uc5d0":76,"initial\ubb38\uc758":77,"input\ud568\uc218\ub97c":76,"input\ud568\uc218\uc640\ub294":76,"int":[1,2,3,4,5,6,7,8,9,10,12,13,17,18,20,23,24,25,28,29,30,32,33,35,36,37,41,42,44,45,47,48,50,51,55,56,71,72,73,79,80,81],"it\uc744":81,"k_\uc2dc\ub9ac\uc988\uc774\ub2e4":78,"kewdown\uc740":78,"key\ub294":78,"keydown\uac00":80,"keyup\uc774\ub77c\ub294":78,"l_f4\ub4f1\uc774":78,"locals\ub85c\ubd80\ud130":78,"long":[7,25,27,29,35,38,40,44,50,53,63,64,84,88],"main\ud568\uc218\ub97c":79,"main\ud568\uc218\uc5d0":79,"mousebuttonup\uc774":80,"mytext\uac1d\uccb4\uc758":76,"mytext\ub77c\ub294":76,"mytextarea\ub294":76,"mytextarea\ub77c\ub294":76,"mytextfont\uac1d\uccb4\uc758":76,"mytextfont\ub77c\ub294":76,"name\uc5d0\uc11c":78,"new":[2,3,4,5,6,7,8,9,12,13,14,17,18,20,21,22,23,25,26,28,29,30,31,32,33,35,36,37,38,39,40,42,43,44,45,46,47,48,49,50,51,52,54,55,56,58,59,61,62,63,64,65,69,71,72,73,74,84,85,86,87,89],"null":[1,2,3,4,5,6,7,8,9,10,12,15,28],"play\ub77c\ub294":78,"play\ud55c\ub2e4":78,"pos\ub294":80,"print\ud568\uc218\ub098":76,"public":[26,86,89],"quit\uac19\uc740":76,"quit\ub77c\ub294":76,"r\uac12":76,"return":[1,2,3,4,5,6,7,8,9,10,12,13,14,15,17,18,19,20,22,23,24,25,27,28,29,30,31,32,33,35,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,62,63,64,65,66,68,71,72,73,79,80,81,84,85,86,87,88,89],"short":[25,63,65,84],"statement\uc5d0":77,"statement\uc5d0\uc11c":77,"static":[47,48,50,69],"super":[26,35,48,64],"switch":[22,23,29,44,50,59,89],"sys\ub294":76,"throw":[40,62,64],"tick\ud568\uc218\ub294":77,"true":[2,3,4,5,6,7,8,10,12,13,14,17,18,19,20,22,23,24,25,26,27,28,29,31,32,33,35,36,37,38,39,40,41,44,45,46,47,50,51,53,56,57,58,60,64,66,68,69,70,71,72,73,76,77,78,79,80,81,89],"try":[25,27,29,32,44,51,58,61,62,63,64,65,67,84,85,86,89],"ttf\ud30c\uc77c\ub85c":76,"ttf\ud655\uc7a5\uc790\ub97c":76,"update\ud568\uc218\uac00":76,"void":[1,9,13],"while":[0,17,19,22,24,25,28,30,31,32,38,39,40,42,43,44,49,50,51,54,57,62,63,64,65,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84,85,87,89],"world\uac00":[77,78],"world\ub294":77,"world\uc758":77,"x\uac12\uacfc":80,"x\uc88c\ud45c\uac00":76,"y\uac12\uc744":80,"y\uc131\ubd84\uc744":76,"y\uc88c\ud45c\uac00":76,A:[1,5,8,9,12,13,15,16,17,18,20,22,23,24,25,26,29,30,32,33,35,38,39,40,42,43,45,46,49,50,51,53,54,56,58,63,64,85,86,89],AND:[18,33],ANDing:84,AS:18,And:[22,32,58,62,66,68,69,71,74,84,85,89],As:[24,29,35,38,39,44,51,52,56,57,58,64,65,67,68,84,85,86,88,89],At:[26,31,63,64,65],BE:18,BUT:18,BY:18,Be:[22,23,24,28,44,65],Being:63,But:[26,39,43,51,58,62,64,65,68,69,71,72,74,85,87,88],By:[23,25,29,31,35,39,43,44,51,53,54,56,57,61,62,64,85,86],FOR:18,For:[1,17,18,20,22,23,24,25,26,27,28,29,30,31,32,33,35,36,37,38,40,42,43,44,45,46,47,48,49,50,51,53,56,57,60,61,62,63,64,65,67,68,71,84,85,86,88],IF:18,IN:[18,27],IS:[18,27],If:[6,10,13,17,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,56,58,59,60,61,62,63,64,65,67,68,69,71,72,73,74,84,85,87,88,89],In:[17,18,22,23,27,29,30,31,32,33,36,37,39,40,43,44,51,54,57,58,59,61,62,63,64,65,68,70,72,84,85,86,87,88,89],Is:[37,50,63],It:[2,13,16,17,18,19,20,23,25,26,28,29,31,32,33,36,37,38,40,42,43,44,47,50,51,53,54,56,57,58,59,60,61,63,64,65,66,68,69,72,73,84,86,87,88,89],Its:34,NO:18,NOT:[18,37,40,56],No:[1,3,6,7,9,12,33,44,45,50,51,67,70],Not:[23,25,41,51,60,63,64,65,69,70],OF:18,ON:18,OR:[18,29,35],ORed:38,ORing:33,Of:[57,69,70,71],On:[1,2,3,4,5,6,7,8,9,10,18,23,25,26,37,40,44,46,50,51,56,63,66,84],One:[11,19,32,62,63,65,84],Or:[26,44,64,74],SUCH:18,THE:18,TO:[18,32],That:[29,56,58,62,63,64,67,68,69,70,71,73,74,84],The:[1,2,3,4,5,6,7,8,9,10,12,13,15,16,17,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,59,60,61,63,65,66,68,71,84,87,88],Then:[11,22,24,58,62,64,65,68,71,73,84,85,86,88,89],There:[18,19,20,22,23,24,25,26,27,28,30,32,33,37,39,45,46,50,51,57,58,59,60,62,64,65,69,70,72,73,85],These:[20,22,23,24,26,29,32,37,39,44,45,47,48,50,51,52,53,56,58,59,62,64,65,84,85,87],To:[22,23,25,28,30,33,35,37,38,39,40,41,42,43,47,50,54,57,58,65,87,88],Will:[3,5,6,7,12,32,38,54],With:[26,37,51,62,63,65,84,85,87,88],_:33,__copy__:35,__dict__:25,__file__:[26,58,66],__init__:[32,45,50,57,58,62,64,66,86,87,88,89],__main__:[66,71,72,73,79,80,81,85,89],__name__:[66,71,72,73,79,80,81,85,89],__new__:[29,45],__tags__:53,_camera:18,_default_lay:50,_freetyp:[0,11],_index:1,_layer:50,_pixels_address:51,_pygam:11,_sdl2:48,_spin:[58,66],_sprite__g:64,_spritegroup:64,_tag:53,_test:53,_time_threshold:50,_use_upd:50,_walk:[58,66],a0:37,a6f89747b551:44,a_mask:35,aa:[20,30,65],aaa:65,aacircl:30,aaellips:30,aalib:23,aalin:24,aapolygon:[24,30],aatrigon:30,abandon:18,abil:[44,58,63],abl:[31,42,58,63,84,89],abnorm:89,abort:37,about:[16,18,19,23,26,32,36,37,39,42,44,48,50,51,55,58,59,61,62,63,64,65,67,68,70,71,72,73,74,84,85,87,88],abov:[15,18,19,22,23,24,29,32,40,41,42,43,45,48,57,58,62,64,65,74,84,87],absent:23,absolut:[19,20,29,32,37,40,51,84],abspath:[58,66],abstractgroup:50,acceler:[23,24,30,41,48,51,56,63,69,84],accept:[15,24,26,28,29,30,31,38,39,45,50,51,52,62],access:[9,10,16,17,19,24,25,26,28,29,32,35,37,38,39,41,43,44,46,50,51,59,64,65,67,84],accord:[43,69],accordingli:51,account:[32,33,38,40,42,68,84],accur:[39,40,54],achiev:[62,86],acolor:20,acquir:[10,51,52],across:[22,23,58,62,65,66,84,87,88,89],act:[58,63,70,84],action:[25,32,63,65,88],activ:[23,38,39,40,49,51,52,55,72,74],activeev:[23,25],actual:[5,12,18,19,22,23,28,30,32,37,38,40,41,43,45,50,51,54,56,58,59,62,63,64,65,73,84,85,88],ad:[11,23,24,25,31,32,35,38,39,40,42,43,47,50,54,56,58,62,64,65,68,69,70,72,73,84,87,89],add:[23,29,48,50,57,58,61,62,63,64,65,68,69,70,89],add_intern:64,add_map:47,addit:[22,23,24,25,26,32,33,36,37,44,46,48,50,51],addition:[23,24,47],address:[17,51,84,86],adequ:72,adjac:[24,30],adjust:[9,20,23,28,29,37,71,89],admit:84,adopt:[48,61],advanc:[16,28,29,47,50,51,58,62,63,67,70],advancedinputoutput1:[72,80],advancedinputoutput2:[72,80],advancedinputoutput3:[72,80],advancedinputoutput4:[72,80],advancedinputoutput5:[72,80],advancedoutputalpha1:[73,81],advancedoutputalpha2:[73,81],advancedoutputalpha3:[73,81],advancedoutputprocess1:[71,79],advancedoutputprocess2:[71,79],advancedoutputprocess3:[71,79],advancedoutputprocess4:[71,79],advancedoutputprocess5:[71,79],advancedoutputprocess6:[71,79],advancemam:56,advantag:[59,63,64,67,84,87],advic:[63,84],advis:[18,22,23],ae:28,affect:[12,23,24,29,38,42,44,45,50,51,52,65,74],afraid:65,after:[17,19,23,24,29,31,32,33,37,38,40,47,49,50,51,57,58,59,62,63,65,68,69,70,84,89],again:[18,33,40,44,50,51,54,59,61,62,64,65,84,85,88,89],against:[29,45,56,57,64],ago:63,agp:65,ahead:[24,32],ai:[84,86,89],aid:29,aim:61,alexei:74,algorithm:[24,35,44,56,67,70],alia:[46,50],alias:[16,23,28,29,85],aliceblu:21,alien:[26,64],align:[29,35,45,84],aliv:[17,50,64],all:[16,17,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33,35,36,37,38,39,40,41,42,44,45,47,48,50,51,52,53,56,57,59,60,61,63,64,65,67,68,84,85,86,87,88],all_my_sprites_list:84,allblack:65,alloc:[31,38,68],allot:53,allow:[16,18,20,22,23,25,27,28,29,31,32,36,38,42,44,46,50,51,56,57,58,59,64,65,87,89],allowedchang:38,allsprit:[58,66],almost:[16,58,61,63,64,65,67,86],alon:[26,84],along:[24,25,26,29,37,45,53,63,64,65,66,74,84,87],alpha:[1,20,23,24,26,28,29,30,31,35,43,44,48,51,52,56,63,65,86],alreadi:[10,19,23,25,29,32,37,38,40,45,47,50,57,62,63,64,65,88],alsa:37,also:[11,13,15,16,17,19,20,22,23,25,26,28,29,30,31,33,35,36,37,38,39,40,42,44,45,47,50,51,52,53,54,56,57,58,59,60,61,62,63,64,65,68,69,72,73,84,85,86,87,88,89],alt:33,alter:[35,39,56],altern:[19,23,24,26,28,29,30,45],altgr:33,although:[58,68,86],alwai:[18,23,25,26,28,29,30,31,32,33,35,39,41,44,45,47,49,50,51,54,56,58,59,60,62,63,64,65,68,69,70,71,77,86,87,89],ambigu:38,among:18,amongst:16,amount:[23,25,28,29,32,39,54,55,56,58,63],ampersand:33,amplitud:49,an:[1,2,4,5,6,7,8,10,11,12,13,14,15,16,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,63,64,65,67,69,84,85,86,87,88,89],an_id:37,analog:[32,42,47],andal:29,andmask:[22,39],android:33,angl:[24,29,30,35,36,48,56,57,87,89],angle_to:36,angular:87,ani:[1,10,16,17,18,19,21,22,23,24,25,26,27,28,29,30,31,32,35,37,38,40,41,42,43,44,45,47,48,50,51,52,54,56,57,58,59,60,61,62,63,64,65,67,68,74,84,85,86,87,88],anim:[16,26,31,50,56,62,63,64,67],anisotrop:44,annoi:[16,61,73],anoth:[11,20,23,24,26,28,29,30,32,33,35,36,39,40,42,43,45,46,47,50,51,62,63,64,65,73,74,84,86,89],ansi:37,ansi_not:37,answer:[63,84],anti:[16,23,29,85],antialia:28,antialias:[24,28,29,30,56,58],anticip:[44,69],antiquewhit:21,antiquewhite1:21,antiquewhite2:21,antiquewhite3:21,antiquewhite4:21,anyon:64,anyth:[19,23,27,44,50,51,58,62,63,64,65,74,84],anywai:[65,70,84,85],anywher:[13,62],apart:38,api:[16,18,23,30,37,46,47,48,57],app:[23,26,44,57],appear:[16,23,25,54,62,63,64,70,84],append:[27,57,62,64,69,73,81,84],appli:[20,24,26,29,35,36,37,51,55,56,65,84],applic:[0,17,23,25,26,27,33,34,37,38,46,51,84,88],appreci:84,approach:61,appropri:[23,25,39,58,59,64,69,88],approxim:[32,35,51,57],aptitud:74,aqua:21,aquamarin:21,aquamarine1:21,aquamarine2:21,aquamarine3:21,aquamarine4:21,ar:[1,9,10,11,13,15,16,17,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33,34,35,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,56,57,58,59,60,61,63,64,65,66,67,68,70,71,72,73,74,85,86,87,88,89],arang:65,arbitrari:[50,56,62],arbitrarili:23,arc:[24,30],arcad:[63,84],architectur:56,archiv:[28,29,84],area:[12,23,24,26,28,29,32,35,44,45,48,50,51,56,57,58,62,63,64,66,68,72,84,85,87,88,89],aren:[58,62,84],arg:[26,50,53],argb:31,argb_premult:31,argument:[1,2,4,10,12,16,17,18,19,20,22,23,24,25,26,28,29,30,31,32,33,35,36,38,39,40,41,43,44,45,47,48,50,51,53,54,56,58,59,62,64,84,85],aris:18,arithmet:[20,42,65],arkanoid:69,around:[23,24,26,32,36,39,42,45,48,54,57,58,59,62,63,65,84,85,86,89],arrai:[1,2,4,16,20,22,26,29,33,38,42,49,51,62,63,65,72,73,80],arrang:[65,68],array2d:[52,65],array3d:[52,65],array_alpha:[52,65],array_blu:52,array_colorkei:[43,52,65],array_green:52,array_r:52,array_to_surfac:43,arraydemo:[16,26,65],arraytyp:[26,49,52],arrayxd:65,arriv:84,arrow:[22,26,33,70],art:[67,74],articl:[62,63],as_joystick:47,as_polar:36,as_spher:36,ascend:29,ascent:[28,29],ascii:[15,22,33,52,67],asid:67,ask:[23,28,29,57,58,59,62,63,84],aspect:[44,45],assembl:[33,63],assertequ:56,assertnotequ:56,assign:[20,25,29,32,42,45,47,50,53,58,62,65,88],assist:51,associ:[3,8,29,48,55],assum:[1,10,12,20,28,29,37,39,45,57,61,64,86,88],asterisk:33,astonish:84,astyp:65,asurf:31,asyncblit:51,asynchron:51,attach:[10,23,26,47,57],attack:63,attempt:[18,28,29,37,51,58,60,65],attent:[63,70],attibut:50,attract:70,attribut:[6,23,25,27,28,29,30,32,33,34,35,36,39,44,45,50,51,53,54,58,64,85,87,88,89],attributeerror:[29,32,51,64],audio:[3,26,37,38,44,46,49,63],audio_allow_any_chang:38,audio_allow_channels_chang:38,audio_allow_format_chang:38,audio_allow_frequency_chang:38,audiodevicead:25,audiodeviceremov:25,author:[18,57,58,59,60,62,63,64,65,84],autom:84,automat:[13,19,23,28,29,30,31,32,33,34,37,38,44,46,50,51,58,60,65,68,69],avail:[0,1,3,10,18,20,22,23,26,27,28,29,30,31,37,38,41,44,46,49,51,52,53,55,56,58,59,60,62,63,64,65,84],avalanch:74,averag:[28,29,53,54,56,57,65,84],average_color:[56,57],average_surfac:[56,57],avid:84,avoid:[19,23,33,36,38,42,53,65,89],awai:[64,71,89],awar:[23,25,28,44,65],awhil:19,awkward:[62,84],ax:[23,29,32,47,87],axi:[24,25,29,32,36,39,42,47,48,49,52,56,85,87],axis_numb:32,azimuth:36,azur:21,azure1:21,azure2:21,azure3:21,azure4:21,b0:47,b3:47,b:[20,26,32,33,42,43,46,47,51,56,65],b_black:[73,81],b_height:[73,81],b_red:[73,81],b_width:[73,81],bach:40,back:[19,28,29,32,33,37,38,50,57,58,59,66,68,88,89],backend:[18,23,43,44,56,59],backgound:66,background:[24,26,28,29,38,50,57,61,64,66,84,85,87,89],backslash:33,backslashreplac:44,backspac:33,backward:[23,25,29,38,54],backyard:63,bad:84,bagic:[68,69,70,76,77,78],baker:63,ball:[25,32,61,63,67,68,69,70,71,72,73,75,76,77,78,79,80,81,85,86,88],ball_numb:32,ballrect:[63,67,68,69,70,71,72,73,75,76,77,78,79,80,81],ballsprit:89,banner:[16,26,58,66],bar:[71,79],barrier:67,base:[0,11,17,18,24,25,26,28,29,35,48,50,57,58,62,64,65,66,67,68,87,89],baselin:[28,29],basic:[16,18,20,23,26,31,46,58,61,62,63,64,65,76,84,86,87,88,89],bat:61,battleship:[67,75],bayer:18,bb:20,bdf:29,beam:22,bear:[28,29,39],beauti:62,becam:25,becaus:[24,27,29,36,37,51,58,61,64,65,67,68,69,70,72,73,84,85,86,87,88,89],becom:[23,25,29,38,40,49,51,52,62,63,64,65,68,73],been:[19,20,22,23,24,25,29,32,36,38,39,40,44,46,47,50,51,59,60,62,63,64,84,88,89],befor:[10,17,18,19,22,23,27,28,29,32,33,35,37,38,39,40,44,46,50,51,53,54,57,58,59,60,61,62,63,64,65,68,69,70,71,84,87,88],begin:[16,17,18,26,38,40,45,56,62,63,65,69,87],beginn:65,behalf:17,behavior:[39,50],behaviour:[23,39,44,46,89],behind:[16,23,50,87,88,89],beig:21,being:[9,18,23,24,25,31,32,33,35,37,38,39,40,42,46,63,64,69,84,88],believ:84,belong:[50,58,64,85],below:[18,20,23,24,26,27,32,37,44,45,47,50,57,62,71],bend:37,benefit:[62,64],beo:84,besid:[19,26,65],best:[13,18,23,25,26,35,38,42,43,51,52,59,62,63,64,65,72,84,86],bet:59,better:[23,28,30,37,39,40,51,56,62,63,64,65,71,84,85],between:[1,4,20,23,24,25,28,29,32,33,35,36,37,38,40,42,43,44,45,46,47,48,49,50,51,52,53,54,55,57,64,65,67,70,84],bezier:30,bg:57,bgcolor:29,bgd:50,bgr:[31,51,65],bid:58,big:[17,18,44,50,57,62,64,65,70,71,72],bigger:[16,23,58,73],biggest:[23,59],bilinear:56,bin:[66,85,86,87],binari:[16,18,20,22,41],bind:[37,59],bisqu:21,bisque1:21,bisque2:21,bisque3:21,bisque4:21,bit:[1,15,16,17,18,22,23,26,28,29,30,31,32,35,38,40,42,43,49,50,51,52,56,57,58,59,61,62,64,65,87,89],bitblt:62,bitmap:[22,29,31,56,62],bitmap_1:22,bitmap_2:22,bitmask:[22,33,35,50,51],bitsiz:[23,35,59],bitstream:[28,29],bitstreamverasan:28,bitwis:[23,33,35],bl:89,bla:31,black:[21,22,24,26,29,32,35,42,51,57,58,63,65,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84],blade:63,blanchedalmond:21,blank:[28,57,62,84,85],blanket:[43,51],blend:[20,24,26,29,44,48,51],blend_add:51,blend_alpha_sdl2:51,blend_fil:26,blend_max:51,blend_min:51,blend_mod:48,blend_mult:51,blend_premultipli:[20,51],blend_rgb_add:51,blend_rgb_max:51,blend_rgb_min:51,blend_rgb_mult:51,blend_rgb_sub:51,blend_rgba_add:51,blend_rgba_max:51,blend_rgba_min:51,blend_rgba_mult:51,blend_rgba_sub:51,blend_sub:51,blend_xxx:26,blendmod:50,blink:67,blit:[12,20,23,26,28,29,30,32,43,48,50,51,52,56,57,58,61,63,64,65,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84,87,88,89],blit_arrai:[43,52,65],blit_blend:26,blit_hw:[23,59],blit_hw_a:[23,59],blit_hw_cc:[23,59],blit_sequ:51,blit_sw:[23,59],blit_sw_a:[23,59],blit_sw_cc:[23,59],blitter:[44,51,62],blitzbas:26,blob:[56,57],block:[17,18,25,35,40,50,51,57,58,73,84],block_list:50,blocks_hit_list:50,bloodi:63,blt:62,blue1:21,blue2:21,blue3:21,blue4:21,blue:[1,18,20,21,23,24,28,31,42,51,52,56,57,65,68,71,72,73,79,80,81,85,87],blueviolet:21,bluish:65,bmp:[31,46,62,63],board:[73,81],bodi:70,bold:[28,29],bomb:64,bonu:62,bool:[17,18,19,23,24,25,27,28,29,31,32,33,35,36,37,38,39,40,44,45,46,47,48,50,51,56],boom:64,boom_sound:64,border:[23,24,30,39,45,48],border_bottom_left_radiu:24,border_bottom_right_radiu:24,border_radiu:24,border_top_left_radiu:24,border_top_right_radiu:24,borderless:48,bore:[67,86],borrow:[1,63,86],both:[19,23,24,28,29,30,31,32,33,35,37,38,39,42,51,56,57,62,63,64,65,67,71,74,84,87,89],bother:[58,61,86],bottom:[23,24,26,28,29,30,31,35,45,50,63,67,68,69,70,71,72,73,75,76,77,78,79,80,81,89],bottomleft:[45,89],bottomright:[45,89],bounc:[26,36,56,63,89],bound:[22,24,29,35,50,51],boundari:[24,29],box:[24,29,30,32,33,57,64,88],br:89,bracket:[33,87],breakag:42,breakdown:63,brief:[19,26,44,61,62],briefli:85,bright:[18,48,57],brighten:23,brightmap:65,bring:[50,63],broadcast:[42,65],broken:[39,44],broken_x:22,brought:56,brown1:21,brown2:21,brown3:21,brown4:21,brown:21,bu:[65,84],buffer:[1,2,18,20,23,31,37,38,43,46,51,58,63,64,84],buffer_s:37,bufferproxi:[0,16,17,51],buffers:[37,38],bug:[20,44,56,63,89],build:[44,64,65,85,89],built:[15,18,29,31,44,47,85],builtin:[18,28,64],bullet:[64,84],bump:84,bumper:32,bunch:[57,64],bundl:[28,29],burlywood1:21,burlywood2:21,burlywood3:21,burlywood4:21,burlywood:21,busi:[18,19,38,54,62],button1:39,button2:39,button3:39,button4:39,button5:39,button:[24,25,26,27,32,33,39,47,58,61,62,69,73,80,84,85,88],bx:47,bye:68,bypass:44,byte_data:46,bytecod:63,byteord:17,bytes:[17,23,35,51,59],bytestr:38,c:[11,16,17,18,20,26,30,33,43,44,51,60,63,65,67,75],c_api:0,cach:29,cache_s:29,cadetblu:21,cadetblue1:21,cadetblue2:21,cadetblue3:21,cadetblue4:21,cadillac:64,calcnewpo:[87,89],calcul:[24,29,35,36,40,42,50,68,69,72,73,87,88],calibr:57,call:[1,10,13,17,18,19,22,23,24,25,26,27,28,29,30,31,32,33,35,36,37,38,39,40,41,44,45,46,47,48,50,51,53,54,57,58,59,60,61,62,63,64,65,66,68,69,70,84,85,86,87,88,89],callabl:[17,25,44,50],callback:[1,2,17,50],caller:37,calling_mask:35,cam:57,came:[26,31],camera:[16,26,44],camlist:57,can:[1,9,14,15,16,17,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,49,50,51,52,53,54,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,84,85,86,87,88,89],candid:[13,33],cannot:[15,18,23,25,28,30,38,40,45,48,50,51,52,54,62,63,64,69,84,86,89],canva:[68,71],cap:33,capabl:[23,59,63,86,87],capslock:33,caption:[23,68],captur:[16,18,26,31],capword:25,card:[23,38,65],care:[27,38,58,65,72,85],caret:33,carri:89,castl:63,categor:64,caught:63,caus:[2,18,20,25,28,35,40,42,56,58,64,65,66,68,84,88],caveat:23,cc:57,ccolor:57,cd:[3,19],cdrom:[0,63],cdrom_tag:53,cdrom_test:53,ceil:63,center:[24,26,30,32,35,44,45,48,50,51,57,66,68,69,70,71,72,73,76,77,78,79,80,81,85],centeri:45,centerx:[45,58,66,85],centr:44,centroid:[35,57],certain:[20,25,33,36,57,58,61,67,68,69,70,71,72,84],certainli:[62,65],cff:29,challeng:63,chanc:[38,65,84],chang:[16,18,20,23,24,25,26,28,29,30,31,32,33,35,36,37,38,39,40,42,44,45,46,47,48,49,50,51,52,54,56,57,58,59,61,63,64,65,68,69,70,71,73,84,87,88,89],change_color:56,change_lay:50,channel:[8,20,31,37,38,40,65,84],channelnum:8,char_bit:35,charact:[15,17,23,28,29,33,43,44,52,62,84,88],character:36,characterist:[20,74],charset:46,chart:65,chartreus:21,chartreuse1:21,chartreuse2:21,chartreuse3:21,chartreuse4:21,chase:64,chaser:64,chatroom:62,cheap:[50,64],check:[3,4,5,6,7,8,12,18,23,25,26,28,32,35,38,39,40,42,44,46,47,49,50,52,57,58,60,62,63,64,67,68,70,71,72,84,85,86,87,88,89],checkout:44,chew:54,chief:86,child:51,chimp:[16,26,61,64,86],chimpanze:16,chocol:21,chocolate1:21,chocolate2:21,chocolate3:21,chocolate4:21,choic:[18,23,38,57],choos:[18,22,23,26,59,61,65,73,84],chop:56,chord:84,chore:84,chose:73,chosen:[18,23,29],chromin:18,chunk:[8,17,89],circl:[22,24,26,30,32,50,57],circular:64,circumst:89,claim:18,clamp:[26,45],clamp_ip:45,clariti:35,clark:84,classless:[86,87],classmethod:48,claus:89,clean:[39,42,58,60,62,63,64],cleaner:[62,63],cleanli:[60,62,63,64,89],cleanup:42,clear:[16,24,25,32,33,35,38,43,48,50,51,62,63,64,67,75,84],clear_callback:50,clearer:60,clench:[58,66],click:[22,24,26,32,33,39,69,72,84,85],clip:[24,26,45,50,51,62],clipboard:[16,26],cliplin:45,clipped_lin:45,clist:57,clock:[22,24,32,39,54,58,66,69,70,71,72,73,77,78,79,80,81,89],clockwis:[29,30,36,56,87],clone:20,close:[10,18,22,23,24,25,26,29,32,37,40,42,47,56,57,62,65,85,86],close_to_play:64,close_to_player2:64,close_to_player3:64,closest:[23,37,38,59],cmy:20,co:[87,89],cocoa:23,code:[6,15,16,17,18,22,23,24,25,26,27,28,29,30,32,33,35,39,42,43,44,45,46,50,51,56,57,58,62,63,64,65,67,68,69,70,71,72,73,84,85,86,87,88,89],codec:44,codepoint:28,coercion:65,col:30,collect:[13,23,51,60],collid:[35,45,50,58,64,66,87,89],collide_circl:50,collide_circle_ratio:50,collide_mask:[35,50],collide_rect:50,collide_rect_ratio:50,collided_cal:50,collidedict:45,collidedictal:45,collidelist:45,collidelistal:45,collidepoint:[45,72,73,80,81,84,89],colliderect:[45,50,58,66,89],colliding_sprit:50,collis:[26,35,36,45,50,57,67,89],colon:33,color:[0,1,11,16,22,23,24,28,29,30,31,32,35,42,43,48,50,51,52,56,57,58,59,62,63,65,67,68,71,72,73,80,81,84,85],color_valu:20,colordict:21,colorkei:[23,26,28,29,31,43,51,52,56,58,63,65,66],colormap:[26,43,52],colorspac:18,colour:[20,44],column:[35,42,65,73,81],com:56,combin:[23,29,33,45,51,56,63,64,84,89],come:[10,25,26,28,29,37,44,57,62,63,64,65,66,84,87,88,89],comfort:[16,87],comma:[28,29,33,37,65],command:[24,25,26,32,53,65,67,68,69,70],commend:65,comment:[26,32,61,64,66,87,89],commerci:[16,63],commit:[33,63],common:[23,28,29,32,47,50,56,60,61,62,63,84],commun:[25,48,84],comp:84,compani:63,compar:[33,35,42,44,50,56,63,68,84],comparison:[20,25,26,42,65,70,74],compat:[23,25,28,29,31,38,48,50,54,67,86],compens:63,compil:[14,16,19,22,25,29,38,41,44],complement:36,complet:[24,33,38,40,45,50,51,52,63,64,84,89],complex:[38,58,63,64,67,69,84,86,87,88],complic:[68,84],compon:[20,35,36,43,51,65,68],composit:33,compositor:44,compound:46,compound_text:46,compress:[40,51],comput:[16,18,19,26,28,31,32,38,54,58,62,63,64,69,74,84],concept:[16,61,62,63,65,69,74],concern:[64,74],conclud:63,conclus:74,condit:[18,22,38,68,89],confid:84,configur:[16,23,29,39,65],confin:48,confus:[24,62,68,84],connect:[24,26,30,35,47,61,62,74,86],connected_compon:[35,57],consequ:86,consequenti:18,consid:[23,24,29,35,38,40,44,45,50,51,56,84,89],consider:51,consist:[19,24,25,27,38,46,61,65,85,86],consol:[26,44,53,67],constant:[16,22,25,29,33,38,39,44,46,47,54,57,60,68,72],constantli:84,constrain:[24,39,70],construct:[36,45,62],constructor:[29,32,50,58,64],consum:[1,54,65,84],contact:[57,58,59,60,62,63,64,65],contain:[0,7,9,10,16,19,22,23,24,25,28,29,31,32,33,34,35,37,38,39,43,45,46,47,50,51,53,55,58,59,62,63,64,66,84,86,88,89],content:[23,34,41,42,46,58,59,68,70],context:[10,23,42,48],contigu:[17,24,51],continu:[35,38,44,50,51,63,85],contol:47,contract:[18,56],contrast:[39,70,87],contribut:64,contributor:18,control:[3,5,18,22,25,26,28,29,32,33,34,38,41,44,50,51,52,53,54,56,58,59,60,61,63,69,70,78,84,86],controller_axis_lefti:47,controller_axis_leftx:47,controller_axis_righti:47,controller_axis_rightx:47,controller_axis_triggerleft:47,controller_axis_triggerright:47,controller_button_a:47,controller_button_b:47,controller_button_back:47,controller_button_dpad_down:47,controller_button_dpad_left:47,controller_button_dpad_right:47,controller_button_dpad_up:47,controller_button_guid:47,controller_button_i:47,controller_button_leftshould:47,controller_button_leftstick:47,controller_button_rightshould:47,controller_button_rightstick:47,controller_button_start:47,controller_button_x:47,controlleraxismot:47,controllerbuttondown:47,controllerbuttonup:47,controllerdevicead:[25,47],controllerdeviceremap:[25,47],controllerdeviceremov:[25,47],controllertouchpaddown:47,controllertouchpadmot:47,controllertouchpadup:47,convei:22,conveni:[36,44,50,53,62,63],convent:47,convers:[1,18,20,35,42,52,84],convert:[1,18,20,22,24,29,31,37,38,40,43,45,49,51,52,58,59,62,65,66,85,86,89],convert_alpha:[26,31,51,86,89],convolut:[35,65],convolv:35,cool:84,cooper:19,coord:57,coordin:[9,22,24,29,30,32,35,36,39,50,51,56,85,89],copi:[17,22,26,31,35,36,38,42,45,46,48,49,50,51,52,56,58,62,63,64,65,84,85],copyright:18,coral1:21,coral2:21,coral3:21,coral4:21,coral:21,cord:26,coremidi:37,corner:[24,29,30,35,39,42,44,50,51,56,57,58,62,84,89],cornflowerblu:21,cornsilk1:21,cornsilk2:21,cornsilk3:21,cornsilk4:21,cornsilk:21,correct:[18,22,28,41,45,56,62,65,68,73],correct_gamma:20,correctli:[37,38,56,57,58,62,65,84],correspond:[29,33,35,37,42,51,53,68,84,89],cost:84,could:[22,25,33,41,49,50,52,56,57,58,61,62,64,65,84,85,86,87],couldn:[86,89],count:[17,19,32,35,38,42,56,57,69,73],counterclockwis:[24,29,36,56],coupl:[32,58,62,64,65],courier:29,cours:[57,69,70,71,85,86,87,89],cover:[16,24,44,45,51,56,57,59,62,74,85],coverag:24,cpu:[24,54,67,75,84],cram:84,crash:[41,64],crate:87,creat:[1,2,6,7,16,17,19,20,21,22,23,25,26,28,29,31,32,33,35,38,39,41,42,43,45,47,48,49,50,51,52,54,56,57,59,63,64,65,66,74,84,85,86,87,88,89],create_graphics_screen:62,create_screen:62,creation:[29,32,47,49,50,52,62],creativ:74,crect:57,crimson:21,critic:84,critter:[58,66],crop:[45,56],cross:[32,36,58,63,65,84,86],crossbar:26,crossbon:22,crossfad:65,crosshair:22,crt:23,crucial:84,crude:[26,58,62],cryptic:64,cube:26,cui:[67,68,73,81],current:[14,18,19,22,23,25,26,27,28,29,32,35,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,53,56,58,59,63,64,67,68,69,71,84,87,88,89],current_h:[23,59],current_w:[23,59],currrent:23,cursor:[16,26,39,58,63,84],cursor_arg:22,cursor_index:22,cursorfil:22,curv:30,custom:[16,23,25,26,38,50,63],custom_typ:25,customis:86,cut:[38,46],cutout:62,cx1:45,cx2:45,cy1:45,cy2:45,cyan1:21,cyan2:21,cyan3:21,cyan4:21,cyan:21,d:[32,33,51,62,84,85,87],da:61,dai:[63,64],damag:18,dark:[58,63],darkblu:21,darkcyan:21,darken:23,darkgoldenrod1:21,darkgoldenrod2:21,darkgoldenrod3:21,darkgoldenrod4:21,darkgoldenrod:21,darkgrai:21,darkgreen:21,darkgrei:21,darkkhaki:21,darkmagenta:21,darkolivegreen1:21,darkolivegreen2:21,darkolivegreen3:21,darkolivegreen4:21,darkolivegreen:21,darkorang:21,darkorange1:21,darkorange2:21,darkorange3:21,darkorange4:21,darkorchid1:21,darkorchid2:21,darkorchid3:21,darkorchid4:21,darkorchid:21,darkr:21,darksalmon:21,darkseagreen1:21,darkseagreen2:21,darkseagreen3:21,darkseagreen4:21,darkseagreen:21,darkslateblu:21,darkslategrai:21,darkslategray1:21,darkslategray2:21,darkslategray3:21,darkslategray4:21,darkslategrei:21,darkturquois:21,darkviolet:21,data1:37,data2:37,data3:37,data:[0,2,16,17,18,19,22,26,31,35,37,38,39,40,41,43,46,51,56,58,62,63,65,66,68,70,71,72,73,84,86,89],data_dir:[58,66],datatyp:65,david:84,dead:27,deal:[33,44,65,68,84,88],dealloc:32,dealt:[25,27,88],death:63,debat:84,debug:[25,56,88],decapit:63,decept:72,decid:[25,27,35,58,61,64,68],decim:24,declar:[9,65],decod:[22,29,33,46,63],decor:85,decreas:[38,72],decrement:10,dedic:64,deeppink1:21,deeppink2:21,deeppink3:21,deeppink4:21,deeppink:21,deepskyblu:21,deepskyblue1:21,deepskyblue2:21,deepskyblue3:21,deepskyblue4:21,def:[29,32,35,39,50,56,57,58,62,64,66,71,72,73,79,80,81,85,86,87,88,89],default_id:37,default_lay:50,defin:[1,2,4,7,8,9,11,12,24,25,28,29,32,34,44,46,50,58,61,84,85,88],definit:[46,60,64,65,70],deflat:89,degre:[29,30,35,36,52,56,58,87,89],del:65,delai:[26,33,37,54,62,69,84],delet:[25,33,62,64,84],deliv:37,demo:[26,58,65],demonstr:[16,26,58,65],denot:[40,45,54],depend:[15,23,25,28,29,31,35,38,40,42,43,46,49,58,63,66,69,71,84],deprec:[23,25,26,27,29,32,36,49,50,52],deprecationwarn:[49,52],depth:[18,23,35,42,48,51,52,56,57,58,59,62],deriv:[26,44,50,58,64],descend:29,descent:[28,29],describ:[1,17,22,23,37,39,45,57,59,86],descript:[1,18,22,25,29,33,34,44,46,62,64],design:[17,50,61,62,63,64,68,71,88],desir:[18,51,56,58,59,84],desktop:[23,48,59],desper:62,dest:[29,35,48,51,56,65],dest_rect:56,dest_siz:56,dest_surf:56,dest_surfac:56,destin:[18,28,29,30,35,42,50,51,56,62,63,85],destroi:[1,31,48,64],destruct:[56,58],destsurfac:18,detail:[16,23,24,29,34,35,36,37,41,50,51,56,57,61,71,84],detect:[23,26,35,36,42,44,45,50,57],determin:[19,20,22,23,24,28,29,31,33,36,37,40,41,50,51,56,59,64,65,68,69,72,87],dev13:25,dev3:[25,54],dev7:39,dev8:24,dev:[18,57],develop:[23,39,44,48,53,63,67,86],devic:[16,18,19,25,26,32,33,37,39,47,55,57,59,63,84],device_id:[26,37],device_index:25,devicenam:38,dga2:84,dga:23,diagon:[35,56],diagram:[87,88],diamond:22,dict:[1,6,17,20,23,25,35,45,47,51,53,55],dictionari:[1,6,23,25,45,47,50,53,64,84],did:[18,24,32,62,63,64],didn:[84,85],diff:65,differ:[18,19,20,22,23,26,27,28,29,30,32,33,35,38,40,42,44,48,50,51,56,57,58,59,60,62,63,64,65,68,69,70,84,85,87,88],difficult:[37,61,63],digit:[20,32],dilemma:67,dimens:[17,18,23,24,26,28,29,30,35,36,42,43,45,50,51,52,56,58,65,89],dimension:[20,24,29,30,35,36,42,62,65],dimgrai:21,dimgrei:21,direct:[18,23,24,26,29,30,32,36,39,43,47,51,58,65,70,87,89],directfb:23,directli:[15,17,22,24,25,28,29,31,33,42,43,46,49,51,52,53,62,64,65,67,84],directmedia:63,directori:[23,28,29,53,58,62,67,68,86],directx:[23,37,63],dirti:[50,64],dirty_rect:84,dirtysprit:50,disabl:[23,25,29,33,44,47,51,54,58,66],disable_advanced_featur:44,disadvantag:[59,84],disallow:23,disappear:[18,30,46],disc:19,discard:54,disclaim:18,disconnect:61,discontinu:[17,51,67],discourag:27,discov:[63,84],discret:71,discuss:[64,84],disk:[50,84],displac:69,displai:[0,1,16,22,24,25,26,30,32,33,34,36,38,39,41,44,46,48,50,51,53,57,62,63,64,65,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84,85,87,88,89],display_index:48,distanc:[36,42,56],distance_squared_to:36,distance_to:36,distil:84,distort:23,distribut:[16,18,53,58],dive:68,divers:61,divid:[33,61],divis:[20,22],dizzi:[58,66],doc:[23,27,48,50,51,70,78],document:[18,34,38,44,51,57,59,61,63,64,65,84,86,87],dodgerblu:21,dodgerblue1:21,dodgerblue2:21,dodgerblue3:21,dodgerblue4:21,doe:[4,5,8,13,19,22,23,24,25,26,28,29,30,32,33,35,37,38,40,41,43,44,45,46,47,50,51,54,56,57,58,62,64,65,68,84,86,88],doesn:[18,23,26,28,29,44,51,58,62,64,72,73,84,86,87,88,89],dokil:[50,64],dokill1:[50,64],dokill2:[50,64],dollar:33,domain:26,don:[18,24,26,29,32,50,54,56,57,58,61,62,63,64,65,68,70,74,85,86,87,89],done:[24,28,29,32,40,58,62,63,65,68,70,71,84,87],doreturn:51,dot:[29,36],doubl:[22,23,56,58,63,65,84],doublebuf:[23,84],doubler:56,down:[23,29,32,33,39,44,47,51,57,59,62,63,65,68,69,71,72,84,88],download:[63,65,89],dozen:84,dpad:47,dpi:29,drastic:85,draw:[16,20,23,28,29,31,32,35,48,50,51,57,62,63,64,66,67,68,71,72,73,79,80,81,84,85,89],draw_blend_mod:48,draw_bottom_left:24,draw_bottom_right:24,draw_circle_part:24,draw_color:48,draw_lin:48,draw_point:48,draw_rect:48,draw_top_left:24,draw_top_right:24,drawback:84,drawboard:[73,81],drawbutton:[72,73,80,81],drawhp:[71,72,73,79,80,81],drawn:[23,24,30,32,35,50,51,58,62,63,64,68,85],drawplain:58,dream:67,drew:62,drift:32,drive:[3,19],driven:[23,50,67],driver:[23,37,44,59,84],drivernam:44,drop:[25,29,38],dropbegin:25,dropcomplet:25,dropfil:25,dropout:38,droptext:25,dstobj:12,dstrect:[12,48],dualshock:47,due:[20,23,36,51],dull:84,dummi:[58,64,88],dump:53,dungeon:63,duplic:[50,51],durat:[32,47],dure:[18,23,29,30,33,40,42,52,65],dvd:[19,69,77],dx:[25,35,51,87,89],dy:[25,35,51,87,89],dynam:69,e:[6,20,23,24,28,30,31,32,33,35,36,37,38,44,45,50,57,61,85,87,88],each:[17,18,19,20,23,24,25,26,27,28,29,30,32,35,36,38,39,42,46,49,50,51,52,53,56,57,58,60,61,62,63,64,65,71,84,85,87,88,89],earli:[16,48,63,84],earlier:[26,40,43],easi:[26,48,59,60,61,62,63,64,65,70,84,88,89],easier:[45,50,59,60,62,87],easiest:[26,47,62,71,85],easili:[22,44,57,58,60,62,64,65,69,74,84,87],east:22,eat:64,echo:26,eclass:10,eclecti:57,ed:[51,64],edg:[24,28,39,45,56,89],edit:[33,47],editbox:84,editor:[33,84],effect:[16,23,25,26,28,32,40,44,46,47,50,51,56,57,58,62,63,64,65,73,84,86],effici:[16,23,25,28,50,62,64],effort:74,eg:[26,29,31],eight:26,either:[15,17,19,22,23,29,31,32,38,39,45,50,51,56,58,59,89],eject:19,element:[4,17,20,29,36,37,42,43,49,51,62,64,65],elementari:87,elementwis:36,elif:[32,39,58,66,69,70,71,72,73,77,78,79,80,81,88,89],ellips:[16,24,30],ellipt:[24,30],els:[1,9,32,33,43,44,45,46,58,59,64,66,69,84,86,89],elsewher:1,emb:23,embed:[23,29],emit:39,emoji:28,empti:[6,19,23,25,27,28,29,32,35,44,45,46,50,53,59,64],emul:[23,28,39,59],enabl:[23,25,28,29,33,44,47,48,63,67],encapsul:88,enclos:[24,50,68],encod:[10,15,22,28,29,40,44,46,51],encode_file_path:44,encode_str:44,encount:35,end:[19,24,25,30,31,33,38,40,44,45,50,58,61,62,63,66,69,74,84,85,88],end_index:65,end_po:24,endcap:[24,30],endev:[38,40],endian:[17,44],endpoint:[24,30,45],enemi:64,engin:[24,63,67,84],enhanc:[16,28,29],enjoy:70,enlarg:29,enough:[29,50,57,58,60,62,63,64,65,67,71,84],ensur:[25,27,33,38,63,84,85,86],enter:[25,28,33,39,48,58,67],entir:[16,19,23,24,35,38,48,50,51,62,63,64,68,69,70,72,84],entri:[17,33,51,84],enumer:18,env:[66,86],env_var:44,environ:[23,25,28,37,44,46,63,67,68,86,87],equal:[14,17,20,22,24,25,29,33,35,36,51,67,73],equat:[35,69],equip:65,equival:[17,29,35,37,42,43],eras:[32,35,50,58,62,63,64,84],err:[86,89],errno:37,error:[1,2,3,7,10,12,20,23,25,26,29,31,33,37,43,44,46,53,56,58,60,64,65,74,84,86,89],error_msg:44,errorstr:44,es:23,esc:26,escap:[15,29,33,58,89],especi:[25,29,44,64,65,84,86],essenti:65,etc:[31,32,37,42,45,61,65,67,84],etyp:44,euclidean:[36,42],euro:33,eval:53,evalu:58,even:[15,18,19,23,24,26,28,29,32,40,42,44,54,57,62,63,64,65,67,68,72,84],event:[0,16,18,22,23,24,26,32,33,34,37,38,39,40,47,54,57,61,62,63,66,67,69,71,72,73,75,76,77,78,79,80,81,89],event_nam:25,eventlist:[25,26],eventtyp:[6,25],eventu:[13,23,25],ever:[37,40,59],everi:[16,18,19,22,25,26,33,35,36,38,40,44,50,51,52,54,56,59,61,63,64,65,67,68,69,70,71,74,84,85,86,88],everyth:[25,43,44,62,63,64,65,66,67,68,73,84,85,89],evil:84,evolv:26,ex:[39,70],exact:[20,22,23,24,31,32,39,57,59,72,73],exactli:[37,42,45,51,58,62,63,64,65,68,84],examin:16,exampl:[11,16,17,20,22,23,24,25,27,28,29,30,31,32,33,35,37,38,39,40,44,45,46,47,49,50,51,53,56,57,60,61,62,63,64,67,68,70,71,74,84,85,86,87,88],exce:51,exceedingli:29,excel:[58,62,63],except:[1,3,4,5,6,7,8,9,10,12,15,20,22,23,24,25,28,29,31,32,33,37,38,44,45,46,51,56,60,61,65,69,86,89],exchang:42,excit:[58,62,63,65],exclaim:33,exclud:[17,25,51,53],exclus:[37,51],execut:[39,53,66,67,68,69,70,71,73],exemplari:18,exist:[18,19,22,23,24,25,28,29,32,37,47,48,50,51,64],exit:[23,24,32,37,44,48,62,63,67,68,69,70,71,72,73,75,76,77,78,79,80,81,85,86,89],exmapl:67,expand:[56,61],expans:56,expect:[20,27,37,38,39,43,53,57,62],expens:65,experi:[25,63,64,70],experiment:[18,23,30,36,44,46,48,57],expir:53,explain:[58,62,64,68,71,73,86,87,89],explan:[26,36,60,64,66,68,70,84],explanatori:58,explicit:[23,39,43],explicitli:[18,23,29,30,42,54,58,60],explor:63,explos:64,expos:[2,11,29,43,51],express:[18,20],extend:[17,24,31,44,50],extens:[1,2,3,4,5,7,8,9,10,12,13,16,31,56,63],extern:[22,25,49,52,67],extra:[22,29,38,45,50,51,58,59,62,63,64,65,70,89],extract:[42,56,58],extrem:[26,58,65],extsion:6,ey:63,f10:33,f11:33,f12:33,f13:33,f14:33,f15:33,f1:33,f2:33,f3:33,f4:33,f5:33,f6:33,f7:33,f8:33,f9:33,f:[1,17,18,33,84],face:16,fact:[30,64,84],factor:[26,29,65],fade:[26,38,40,65],fade_m:[38,40],fadeout:[38,40],fail:[23,25,27,28,29,44,53,58,60],failur:[1,2,4,5,6,8,9,53],fairli:[50,60,63,84,86,87],fake:[26,28,53],fall:[28,29,50],fals:[2,3,5,6,7,12,13,17,18,19,22,23,24,25,26,28,29,31,32,35,36,37,38,39,40,45,46,47,48,50,53,56,57,58,66,89],famili:28,familiar:[62,63,64,84,85,88],fantast:62,far:[20,36,58,62,71,84,87,88,89],farther:[58,62],fast:[32,35,42,51,52,56,58,62,63,64,65,69,84],faster:[31,36,44,50,52,56,58,64,65,67,84],fastest:[23,51,58,63],fastev:27,fastrendergroup:26,fault:84,favorit:84,favour:27,fbcon:23,featur:[16,23,26,27,28,29,35,44,50,51,59,64,65,87],fed:18,feed:89,feedback:23,feel:[26,62,64,84],felt:63,fetch:50,fever:[58,66],few:[22,28,54,62,63,64,65,74,84,86],ffff:15,fgcolor:29,field:[5,9,13,17,32,37],fighter:63,figur:62,file:[0,2,3,4,5,6,7,8,9,10,11,12,13,14,16,22,23,25,26,28,29,31,38,40,44,49,53,58,61,63,65,67,68,73,84,86],file_path:26,filenam:[7,22,25,28,29,31,38,40,62,86],fileobj:[31,40],filesystem:15,fill:[6,9,10,22,23,24,25,26,29,30,32,35,39,43,48,50,51,56,57,58,62,63,64,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84,85,89],fill_rect:48,filled_:30,filled_circl:30,filled_ellips:30,filled_polygon:30,filled_trigon:30,filter:[16,25,35,56,65],fin:26,find:[16,18,19,23,24,25,26,28,32,35,36,38,50,51,56,57,58,59,62,63,64,65,69,71,84,87,89],find_channel:38,fine:[38,51,59,64,84],finer:57,finger:[55,70,86],finger_id:25,fingerdown:25,fingermot:25,fingerup:25,finish:[13,33,38,40,51,60,61,62,63,65],finit:35,fire:[65,84],firebrick1:21,firebrick2:21,firebrick3:21,firebrick4:21,firebrick:21,firmer:[61,63],first:[4,17,19,24,26,28,29,30,31,32,33,35,37,38,40,42,43,45,49,50,51,52,54,57,58,59,60,61,63,64,65,68,69,70,71,72,73,84,85,87,88,89],firstli:70,fist:[16,58,66],fist_offset:[58,66],fit:[18,23,29,38,45,51,85],five:[38,39,40],fix:[25,29,51,56,63,65,68,69,71,89],fixed_s:29,fixed_width:29,flag:[1,17,20,23,24,26,28,29,32,34,35,43,50,51,58,59,64,84],flame:65,flash:16,flavor:84,flexibl:[16,60,64,86,87],flickeri:84,flip:[18,22,23,24,25,31,32,35,39,42,45,48,50,56,57,58,63,65,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84,85,89],flip_i:56,flip_x:56,flipi:48,flipx:48,flood:[73,81],floor:20,floralwhit:21,flourish:70,flush:[31,37],fly:[45,84,85,88],fnt:29,focu:[23,25,33,39,48,57,67],folder:58,folk:62,follow:[17,18,22,24,25,26,29,30,31,32,33,35,36,37,38,40,45,46,47,49,50,52,58,61,63,64,65,66,67,84],font:[7,16,26,32,44,58,60,63,66,68,69,70,71,72,73,76,77,78,79,80,81,84,85],font_index:[7,29],fonti:26,foo:84,fool:[63,65],forbidden:10,forc:[23,26,38,44,63],forcibl:38,forego:25,foreground:29,foreign:62,forestgreen:21,forev:62,forget:[32,64,87],form:[18,22,25,30,37,51,85],formal:62,format:[18,20,22,23,24,29,30,31,32,35,37,38,40,41,42,43,44,45,49,51,52,56,58,59,62,63,65,68,84,85],formula:[42,44,51,87],forth:58,fortun:[26,62,65],forward:33,found:[16,20,26,28,29,34,35,37,45,49,50,51,52,58,59,62,65,70,85,88],four:[4,19,22,23,24,29,45,52,70,89],fourth:[22,71],fout:26,fp:[46,50,69,77,84],fpsclock:[69,70,71,72,73,77,78,79,80,81],fraction:29,frame:[18,23,25,27,32,44,50,54,57,58,62,63,64,69,77,84,85,88,89],framebuff:23,framer:[16,18,54,57,58,84],framework:[26,63],free:[10,26,40,62,64],freedom:63,freetyp:[7,16,26,28,29,44],freetype2:29,freetype_misc:[26,29],frequenc:[37,38],frequency_to_midi:37,frequent:[32,62,64,69],friendli:[24,68],friendlier:63,frill:64,from:[0,4,6,7,9,10,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,42,43,44,45,46,47,48,49,50,51,52,53,56,57,58,60,61,63,64,65,67,68,69,70,71,72,73,76,77,78,79,80,81,84,85,86,87,88,89],from_display_modul:48,from_joystick:47,from_polar:36,from_spher:36,from_surfac:[35,48,50],from_threshold:[35,57],from_window:48,frombuff:31,fromstr:31,front:50,frozen:53,ftfont:[28,29],fuchsia:21,full:[23,25,26,27,28,29,31,32,38,39,40,42,50,51,56,57,58,59,62,63,64,66,70,85,86,89],fulli:[20,23,33,45,48,50,51,52,58,65,84],fullnam:[58,66,86,89],fullscreen:[23,34,48,50,59,84],fullscreen_desktop:48,fun:[26,57,62,63,65],fundament:61,funni:64,further:46,furthermor:[68,70,71],futur:[18,19,23,27,29,32,37,38,41,46,64],g:[20,23,24,26,28,30,31,33,36,37,42,43,44,45,50,51,56,87,88],gain:[23,25,29,57,84],gainsboro:21,game:[16,18,22,23,24,25,26,27,32,39,44,47,51,54,57,59,60,62,64,66,67,68,69,70,71,72,73,74,84,86,88,89],gameobject:62,gamepad:[25,47],gameplai:[33,64],gamma:[20,23,48],gap:[17,51],garbag:[13,51],gather:59,gaussian:65,gener:[1,16,23,25,26,31,32,33,36,37,39,40,42,47,51,52,56,57,58,63,64,65,68,73,86,89],generateboard:[73,81],geniu:74,geometri:[67,71],get:[2,16,18,19,20,22,23,24,25,26,27,28,29,31,32,33,35,37,38,39,40,42,43,44,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,62,63,64,65,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,85,86,87,88,89],get_abs_offset:51,get_abs_par:51,get_act:23,get_al:19,get_allow_screensav:23,get_alpha:[51,86,89],get_and_flip:57,get_arraytyp:[49,52],get_asc:28,get_at:[35,51,56,58,65,66,84],get_at_map:[20,51],get_axi:[32,47],get_backend:18,get_bal:32,get_bits:51,get_block:25,get_bold:28,get_bottom_lay:50,get_bounding_rect:[35,51],get_buff:[2,17,51],get_busi:[19,38,40],get_button:[32,47],get_bytes:[42,51],get_cache_s:29,get_capt:23,get_clip:[50,51],get_colorkei:51,get_control:[18,57],get_count:[19,32,37,47],get_curr:19,get_cursor:39,get_default_font:[28,29],get_default_input_id:37,get_default_output_id:37,get_default_resolut:29,get_desc:28,get_desktop_s:23,get_devic:55,get_device_info:37,get_driv:[23,59],get_empti:19,get_endev:[38,40],get_error:[29,44],get_eventst:47,get_extend:31,get_fing:55,get_flag:51,get_focus:[23,33,39],get_font:28,get_fp:54,get_grab:25,get_guid:32,get_hardwar:41,get_hat:32,get_height:[28,51],get_id:[19,32],get_imag:[18,57],get_init:[19,23,27,28,29,32,37,38,44,46,47,49,58,60,66],get_instance_id:32,get_ital:28,get_layer_of_sprit:50,get_length:38,get_lines:28,get_lock:51,get_loss:51,get_map:47,get_mask:51,get_metr:29,get_mod:33,get_nam:[19,32],get_num_channel:38,get_num_devic:55,get_num_displai:23,get_num_fing:55,get_numax:32,get_numbal:32,get_numbutton:32,get_numhat:32,get_numtrack:19,get_offset:51,get_palett:51,get_palette_at:51,get_par:51,get_paus:19,get_pitch:51,get_po:[39,40,58,66,84],get_power_level:32,get_press:[33,39,84],get_queu:38,get_raw:[18,38],get_rawtim:54,get_rect:[29,35,48,50,51,56,58,62,63,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,85,86,87,88,89],get_rel:39,get_repeat:33,get_sdl_byteord:44,get_sdl_image_vers:31,get_sdl_mixer_vers:38,get_sdl_vers:[23,44],get_shift:51,get_siz:[18,29,35,42,51,58,66,85,89],get_sized_ascend:29,get_sized_descend:29,get_sized_glyph_height:29,get_sized_height:29,get_smoothscale_backend:56,get_sound:38,get_sprit:50,get_sprites_at:50,get_sprites_from_lay:50,get_surfac:[23,58,66,87,88,89],get_tick:54,get_tim:54,get_top_lay:50,get_top_sprit:50,get_track_audio:19,get_track_length:19,get_track_start:19,get_typ:46,get_underlin:28,get_vers:29,get_view:[17,51],get_viewport:48,get_vis:39,get_volum:[38,40],get_width:[51,58,66],get_window_s:23,get_wm_info:23,getbufferproc:2,getch:[67,75],getfilesystemencod:[15,44],getopt:[86,89],gfxdraw:[11,16,24,30],gg:20,ggi:23,ghost:64,ghostwhit:21,gif:[31,63,71,72,73,79,80,81,84],gil:[10,30],github:[44,46,56],give:[17,22,23,29,32,37,40,42,50,51,58,59,60,61,65,74,84,85,86,87],given:[9,14,17,20,22,23,24,25,28,29,30,32,35,36,37,38,39,44,45,46,47,50,51,52,54,55,56,58,59,64,68,70,73,84],gl:23,gl_accelerated_visu:23,gl_accum_alpha_s:23,gl_accum_blue_s:23,gl_accum_green_s:23,gl_accum_red_s:23,gl_alpha_s:23,gl_buffer_s:23,gl_context_flag:23,gl_context_major_vers:23,gl_context_minor_vers:23,gl_context_profile_:23,gl_context_profile_compat:23,gl_context_profile_cor:23,gl_context_profile_mask:23,gl_context_release_behavior:23,gl_depth_siz:23,gl_framebuffer_srgb_cap:23,gl_get_attribut:23,gl_multisamplebuff:23,gl_multisamplesampl:23,gl_set_attribut:23,gl_share_with_current_context:23,gl_stencil_s:23,gl_stereo:23,glcube:26,glitch:89,global:[53,60,68,86,89],glsl:36,glue:89,glyph:[28,29],gnu:[86,89],go:[20,22,24,32,36,37,51,53,57,58,59,60,61,64,65,66,68,70,74,84,85,86,88,89],goal:63,goe:[58,62,64,68,89],gold1:21,gold2:21,gold3:21,gold4:21,gold:21,golden:59,goldenrod1:21,goldenrod2:21,goldenrod3:21,goldenrod4:21,goldenrod:21,gone:[62,89],good:[18,22,23,26,28,38,44,51,58,61,62,63,64,65,67,68,84,85,86,87,89],goodluck:26,got:[25,40,57,62,64,84],gotten:62,grab:[25,33,39,48,64,89],grace:89,gradient:[26,35,65],grahic:23,grai:[21,29,71,72,73,79,80,81],graphic:[23,26,56,58,59,62,63,64,65,67,68,84],grasp:[61,89],grave:33,gray0:21,gray100:21,gray10:21,gray11:21,gray12:21,gray13:21,gray14:21,gray15:21,gray16:21,gray17:21,gray18:21,gray19:21,gray1:21,gray20:21,gray21:21,gray22:21,gray23:21,gray24:21,gray25:21,gray26:21,gray27:21,gray28:21,gray29:21,gray2:21,gray30:21,gray31:21,gray32:21,gray33:21,gray34:21,gray35:21,gray36:21,gray37:21,gray38:21,gray39:21,gray3:21,gray40:21,gray41:21,gray42:21,gray43:21,gray44:21,gray45:21,gray46:21,gray47:21,gray48:21,gray49:21,gray4:21,gray50:21,gray51:21,gray52:21,gray53:21,gray54:21,gray55:21,gray56:21,gray57:21,gray58:21,gray59:21,gray5:21,gray60:21,gray61:21,gray62:21,gray63:21,gray64:21,gray65:21,gray66:21,gray67:21,gray68:21,gray69:21,gray6:21,gray70:21,gray71:21,gray72:21,gray73:21,gray74:21,gray75:21,gray76:21,gray77:21,gray78:21,gray79:21,gray7:21,gray80:21,gray81:21,gray82:21,gray83:21,gray84:21,gray85:21,gray86:21,gray87:21,gray88:21,gray89:21,gray8:21,gray90:21,gray91:21,gray92:21,gray93:21,gray94:21,gray95:21,gray96:21,gray97:21,gray98:21,gray99:21,gray9:21,great:[23,57,63,65,84],greater:[17,24,28,29,33,35,37,40,51,74],green1:21,green2:21,green3:21,green4:21,green:[1,18,20,21,23,24,42,51,52,57,58,65,68,69,70,71,72,73,76,77,78,79,80,81,85],greenyellow:21,grei:[21,58],grey0:21,grey100:21,grey10:21,grey11:21,grey12:21,grey13:21,grey14:21,grey15:21,grey16:21,grey17:21,grey18:21,grey19:21,grey1:21,grey20:21,grey21:21,grey22:21,grey23:21,grey24:21,grey25:21,grey26:21,grey27:21,grey28:21,grey29:21,grey2:21,grey30:21,grey31:21,grey32:21,grey33:21,grey34:21,grey35:21,grey36:21,grey37:21,grey38:21,grey39:21,grey3:21,grey40:21,grey41:21,grey42:21,grey43:21,grey44:21,grey45:21,grey46:21,grey47:21,grey48:21,grey49:21,grey4:21,grey50:21,grey51:21,grey52:21,grey53:21,grey54:21,grey55:21,grey56:21,grey57:21,grey58:21,grey59:21,grey5:21,grey60:21,grey61:21,grey62:21,grey63:21,grey64:21,grey65:21,grey66:21,grey67:21,grey68:21,grey69:21,grey6:21,grey70:21,grey71:21,grey72:21,grey73:21,grey74:21,grey75:21,grey76:21,grey77:21,grey78:21,grey79:21,grey7:21,grey80:21,grey81:21,grey82:21,grey83:21,grey84:21,grey85:21,grey86:21,grey87:21,grey88:21,grey89:21,grey8:21,grey90:21,grey91:21,grey92:21,grey93:21,grey94:21,grey95:21,grey96:21,grey97:21,grey98:21,grey99:21,grey9:21,greyscal:56,grid:29,ground:62,group1:[50,64],group2:[50,64],group:[26,35,50,58,63,86],group_list:50,groupcollid:[50,64,87],groupmulti:64,groupsingl:[50,64],grow:[24,45,84],guarante:[18,23,25,38,46,53],guess:[38,84],gui:[63,67,71,72,73,75,79],guid:[16,32,57,85],gun:71,h:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,20,25,26,30,33,42,43,45,51,56],ha:[1,2,11,16,17,18,19,22,23,24,25,26,27,28,29,31,32,33,35,36,38,39,40,42,43,44,45,46,47,49,50,51,52,53,54,56,57,58,59,60,62,63,64,65,67,68,69,70,71,72,73,84,86,87,89],habit:87,had:[51,63,64,84],hadn:84,half:[26,50,63,84],hand:[20,22,42,43,58,60,62,84,87],handi:[26,61,86,87,88,89],handili:89,handl:[10,15,16,23,25,28,29,32,33,38,43,44,50,56,59,61,63,64,65,66,70,87,89],handler:[25,27],hang:[32,84],happen:[19,24,58,60,63,64,84,85,88,89],hard:[62,63,65,68],hardcod:26,harder:[61,65],hardest:64,hardwar:[22,23,24,30,32,37,38,41,51,63,64,65],harmless:23,hasattr:28,hash:33,hashabl:45,hasn:29,hat:[25,32,47],hat_numb:32,have:[1,4,9,11,18,19,20,22,23,24,25,26,27,28,29,30,32,33,35,36,38,40,41,42,43,44,45,47,50,51,52,53,54,56,57,58,59,60,61,62,63,64,65,67,68,69,70,72,73,84,85,86,87,88,89],haven:84,he:[58,84,85],headach:84,header:[0,1,2,3,4,5,6,7,8,9,10,12,13,14,68,70,76],headless:26,headless_no_windows_need:26,heavili:25,hei:84,height:[9,18,22,23,24,26,28,29,31,32,35,41,42,45,48,50,51,56,59,62,63,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84],held:[33,88],hello:[68,69,70,76,77,78,85],help:[16,22,25,26,28,32,33,37,38,39,48,50,51,53,54,58,59,61,64,65,70,86,87,88],helper:63,henc:29,here:[18,23,25,26,34,35,39,41,44,50,51,58,59,60,64,65,66,68,70,84,85,86,87,88,89],hex:20,hflip:[18,57],hi:[58,62],hidden:[23,25,39],hide:[33,39,44,48,58],high:[0,23,26,50,67,69,84],high_frequ:[32,47],higher:[16,23,37,47,50,52,59,63,64],highest:44,highgui:44,highli:[27,51],him:[58,62],hint:[23,84],hit:[25,26,58,61,84,85,87,88],hitbox:[58,66],hkey_local_machin:37,hline:30,hmm:62,hold:[1,25,28,32,33,50,56,64,65,70],holdov:64,home:33,honeydew1:21,honeydew2:21,honeydew3:21,honeydew4:21,honeydew:21,hook:50,hoonwhitecatr:[68,69,70,71,72,73,76,77,78,79,80,81],hope:64,hopefulli:[62,65,87],horizont:[18,24,25,26,29,30,39,56,58,65],horizontal_advance_i:29,horizontal_advance_x:29,hot:25,hotpink1:21,hotpink2:21,hotpink3:21,hotpink4:21,hotpink:21,hotplug:32,hotspot:[22,39],hour:84,how:[15,16,19,20,23,24,26,29,31,32,33,35,36,38,40,44,46,50,51,54,56,58,61,63,64,65,68,69,70,71,72,73,74,84,87,88,89],howev:[13,18,29,34,42,44,45,47,50,56,67,68,69,70,74,84],hp:[70,71,72,73,78,79,80,81],hsl:20,hsla:20,hsv:[18,20,57],hsva:20,html:[20,70,78],http:[39,56,70,78,86,89],hue:18,human:[63,74,86],humung:63,hundr:63,husano896:39,hw:[23,59],hwaccel:51,hwsurfac:[23,51,65,84],hx:47,i1:20,i1i2i3:20,i2:20,i3:20,i686:56,i:[1,5,16,17,18,22,24,26,27,32,33,35,36,38,45,57,61,63,64,65,68,70,71,72,73,79,80,81,84,85,86,87,88,89],iceberg:64,icon:[23,48],iconifi:23,icontitl:23,id3:40,id:[3,19,23,25,32,33,37,38,48,55],idea:[23,51,57,59,61,63,65,70,71,72,73,86,87],ident:[25,42,72],identif:37,identifi:[3,25,32,33,44,46,57],idiom:[58,84],idl:[24,25,27,32,38,40],idx:50,ie:[31,65,84],ignor:[25,29,35,37,38,40,51,53,84],illeg:45,illus:62,illustr:[62,65,87],im:33,imag:[12,13,16,18,20,22,23,26,28,29,30,41,46,48,50,52,56,58,59,61,63,64,65,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84,85,86,87,88,89],image_fil:26,imagefil:26,imagin:[62,85,89],imgsurfac:65,immanuel:74,immedi:[23,25,32,37,38,58],immut:20,implement:[10,11,13,17,18,20,23,26,29,37,42,43,44,50,61,63,64,73,74,84,89],impli:[18,29],implicitli:[23,51],import_pygame_bas:[1,11],importantli:62,importerror:[65,86,89],impos:[33,38],imprecis:84,impress:63,improperli:41,improv:[24,28,40,58,73,84],inact:[29,38],inadequ:84,incas:31,inch:29,incident:18,inclin:36,includ:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,16,18,22,23,26,28,29,30,31,32,34,37,44,45,50,51,53,54,56,58,61,63,64,65,67,70,74,84,86,87],inclus:[1,4,20,25,29,38],incom:16,incomplet:53,incorrect:43,increas:[23,29,38,50,68,72,74,84],incred:[74,84],increment:[11,56,65],inde:4,indefinit:[38,40],indent:[32,61],independ:[58,86],index:[1,7,16,18,19,23,29,32,33,42,43,44,45,47,48,49,50,51,52,55,62,65,84],indexerror:[30,35,37,51],indexexcept:17,indexoutofbound:50,indianr:21,indianred1:21,indianred2:21,indianred3:21,indianred4:21,indic:[12,23,24,25,30,35,37,39,40,42,45,46,49,50,52,53,65],indigo:21,indirect:18,individu:[16,19,29,35,44,51,53,58,84],ineffici:58,inequ:25,infinit:[58,63,68],inflat:[29,45,58,66,84,89],inflate_ip:45,influenc:23,info:[5,23,37,59,86],inform:[6,14,16,17,18,19,23,28,32,33,36,37,39,47,51,52,53,55,59,62,64,65,68],inherit:[50,51,64,86,87],init:[1,18,19,22,23,24,27,28,29,32,37,38,39,44,46,47,53,54,58,59,62,63,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,85,89],initi:[16,18,19,23,24,25,27,28,29,32,33,34,37,38,44,46,47,49,50,51,54,57,59,63,64,66,68,69,77,87],initialis:[32,44,47,61,85,88,89],innat:74,inner:72,input:[16,18,23,25,26,32,33,39,48,51,53,56,57,61,63,66,67,68,69,72,73,74,78,84,87],input_onli:48,inputimag:26,insensit:[43,51],insert:[33,69,73],insid:[22,24,26,31,44,45,50,51,57,58,63,65,71,72,89],insight:84,inspir:16,instal:[16,18,26,58,65,84],instanc:[2,3,4,5,6,7,8,9,12,13,17,19,25,26,29,30,32,35,38,42,45,50,51,58,61,64,85,87,88],instance_id:[25,32],instead:[9,15,20,22,23,24,25,26,28,29,32,33,36,38,42,44,50,51,53,56,62,64,65,69,84,87],instruct:56,instrument:37,instrument_id:37,int32:65,int8:65,int_valu:51,integ:[1,9,14,17,19,20,23,24,26,29,30,31,32,33,37,38,39,40,42,43,44,45,47,49,50,51,52,53,54,55,65,71,73],integr:18,intend:[43,50,51],interact:[6,16,26,33,34,42,47,50,53,63,65,70,87],interest:[25,46,63,67,74,84],interf:37,interfac:[1,17,20,29,33,37,38,42,43,47,51,57,63,70,73],interior:56,intern:[0,13,23,25,27,38,44,46,51,58,68,70,84,89],interpol:[20,30,36],interpret:[15,26,29,44,61,84],interrupt:18,intersect:[35,45,50,64,67],interv:33,intial:[58,66],intimid:65,intric:63,intro_bal:63,introduc:[23,25,43,61,62,65,87,89],introduct:[16,60,67,75],introspect:43,intuit:70,invalid:[1,23,38,45,47,56],invalu:87,inverse_set:56,invert:[29,35,36,42],invis:85,invok:[17,29,88],involv:[16,26,29,51,64,84,87,89],inward:24,ip:45,irc:84,is_control:47,is_norm:36,iscaptur:25,ish:24,isn:[19,27,48,57,61,62,64,69,71,84,88],isol:[51,57],issu:[23,62,63],ital:[28,29],item:[29,30,42,43,50,62,64],items:42,iter:[28,29,42,50,64,85,88,89],its:[2,10,13,17,18,23,24,25,29,30,32,35,36,37,38,42,44,45,46,48,50,51,58,59,61,62,63,64,68,69,70,84,85,86,87,88,89],itself:[13,18,28,29,36,42,43,44,48,51,58,61,62,63,64,87,88,89],ivori:21,ivory1:21,ivory2:21,ivory3:21,ivory4:21,iyuv_overlai:41,j:[33,35,73,81],jaggi:56,jid:32,jitter:32,job:[63,64],joi:25,join:[31,45,58,66,86,89],joint:24,journal:84,joyaxismot:[25,32],joyballmot:[25,32],joybuttondown:[25,32],joybuttonup:[25,32],joydevicead:[25,32],joydeviceremov:[25,32],joyhatmot:[25,32],joystick:[16,25,26,47,63,84,85,88],joystick_count:32,jp:18,jpeg:[31,84],jpg:[31,63],jumbl:84,jump:[39,62,63,65,84],just:[24,26,29,30,32,35,38,40,41,50,51,52,53,56,57,58,59,60,63,64,65,67,68,69,70,71,73,84,85,87,88,89],k:[33,36],k_0:33,k_1:33,k_2:33,k_3:33,k_4:33,k_5:33,k_6:33,k_7:33,k_8:[33,70,78],k_9:33,k_:[33,34,70],k_a:[33,70,78,89],k_ac_back:33,k_ampersand:33,k_asterisk:33,k_at:33,k_b:33,k_backquot:33,k_backslash:33,k_backspac:33,k_break:33,k_c:33,k_capslock:33,k_caret:33,k_clear:33,k_colon:33,k_comma:33,k_d:33,k_delet:[33,70,78],k_dollar:33,k_down:[33,70,71,72,73,78,79,80,81,88,89],k_e:33,k_end:33,k_equal:33,k_escap:[22,33,57,58,66],k_euro:33,k_exclaim:33,k_f10:33,k_f11:33,k_f12:33,k_f13:33,k_f14:33,k_f15:33,k_f1:33,k_f2:33,k_f3:33,k_f4:[33,70],k_f5:33,k_f6:33,k_f7:33,k_f8:33,k_f9:33,k_f:[33,84],k_g:33,k_greater:33,k_h:33,k_hash:33,k_help:33,k_home:33,k_i:33,k_insert:33,k_j:33,k_k:33,k_kp0:33,k_kp1:33,k_kp2:33,k_kp3:33,k_kp4:33,k_kp5:33,k_kp6:33,k_kp7:33,k_kp8:33,k_kp9:33,k_kp_divid:33,k_kp_enter:33,k_kp_equal:33,k_kp_minu:33,k_kp_multipli:33,k_kp_period:33,k_kp_plu:33,k_l:[33,70,78],k_lalt:33,k_lctrl:[33,70,78],k_left:[33,70,78],k_leftbracket:33,k_leftparen:33,k_less:33,k_lmeta:33,k_lshift:33,k_lsuper:33,k_m:33,k_menu:33,k_minu:33,k_mode:33,k_n:33,k_numlock:33,k_o:33,k_p:33,k_pagedown:33,k_pageup:33,k_paus:33,k_period:33,k_plu:33,k_power:33,k_print:33,k_q:33,k_question:33,k_quot:33,k_quotedbl:33,k_r:33,k_ralt:33,k_rctrl:33,k_return:33,k_right:[33,70,78],k_rightbracket:33,k_rightparen:33,k_rmeta:33,k_rshift:33,k_rsuper:33,k_scrollock:33,k_semicolon:33,k_slash:33,k_space:33,k_sysreq:33,k_t:[33,84],k_tab:33,k_u:33,k_underscor:33,k_up:[33,70,71,72,73,78,79,80,81,88,89],k_v:33,k_w:33,k_x:33,k_y:33,k_z:[33,89],kanji:29,kant:74,kde:44,keep:[13,17,25,32,50,54,56,57,58,59,60,61,62,63,64,84,88],kei:[16,17,20,22,23,25,26,33,34,35,45,51,55,57,58,61,63,64,66,70,71,72,73,74,78,79,80,81,84,88,89],kern:[28,29],kewdown:78,key_cod:33,key_rect:45,keyboard:[16,25,26,34,39,62,63,67,70,84,85],keycod:33,keydown:[22,25,33,34,57,58,62,66,70,71,72,73,78,79,80,81,88,89],keypad:33,keypress:84,keyup:[25,33,34,70,88,89],keyword:[16,18,24,25,26,35,38,44,48,51,53,56],khaki1:21,khaki2:21,khaki3:21,khaki4:21,khaki:21,khz:49,kick:61,kill:[50,53,64],kind:[37,43,51,61,65,67,84],kmod_alt:33,kmod_cap:33,kmod_ctrl:33,kmod_lalt:33,kmod_lctrl:33,kmod_lmeta:33,kmod_lshift:33,kmod_meta:33,kmod_mod:33,kmod_non:33,kmod_num:33,kmod_ralt:33,kmod_rctrl:33,kmod_rmeta:33,kmod_rshift:33,kmod_shift:33,know:[18,28,31,33,46,57,58,62,64,65,67,68,69,70,73,87,88,89],knowledg:[74,84],known:[33,84],korean:16,kwarg:[35,48,50,51],kwd:53,l:[32,33],l_margin:[73,81],lack:23,laggi:38,laid:[29,61],landscap:62,lang:84,languag:[26,28,33,62,63,84],lantinga:63,laplacian:56,larg:[16,29,43,45,51,61,64,65,87],larger:[23,38,51,56,58,65,67],largest:[35,57,59,63,65],last:[24,25,29,30,32,50,51,52,54,58,62,63,64,65,68,84],lastli:[22,50,58,59,62,64,65],late:84,latenc:[37,38,84],later:[18,23,30,37,38,42,46,50,57,58,59,60,62,63,64,65,68,86,89],latest:[29,70],latin1:[28,29],lavend:21,lavenderblush1:21,lavenderblush2:21,lavenderblush3:21,lavenderblush4:21,lavenderblush:21,lawngreen:21,layer1:50,layer1_nr:50,layer2:50,layer2_nr:50,layer:[50,63,64],layer_nr:50,layereddirti:50,layeredupd:50,layout:[17,28,29,43,52,88],lbm:31,leak:62,learn:[26,51,59,62,63,65,67,68,69,70,73,74,84],learnt:89,least:[14,24,30,35,43,51,55,61,65,67,70,84],leav:[24,29,51,65],left:[20,23,24,25,29,32,33,35,38,39,44,45,47,50,51,57,58,62,63,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84,85,86,87,88,89],leftclick:26,leftmost:47,legaci:[27,67,75],lemonchiffon1:21,lemonchiffon2:21,lemonchiffon3:21,lemonchiffon4:21,lemonchiffon:21,len:[17,20,22,24,30,50,64,65],length:[1,4,9,17,19,20,23,24,25,30,32,33,36,38,42,47,51,58,68,87],length_squar:36,leonidovich:74,lerp:[20,36],less:[24,25,27,28,33,35,37,38,54,55,56,67,85],lesson:84,let:[10,20,21,26,44,51,58,59,61,63,65,69,70,71,84,88],letter:[19,28,51],level:[0,16,17,20,23,28,37,38,40,41,51,53,56,63,64,65,67,70],lgpl:16,li:84,liabil:18,liabl:18,lib:26,librari:[18,24,26,29,30,31,32,37,38,44,47,59,62,63,67],libsdl:39,licens:[16,86,89],lie:[30,45],life:[57,59],lifetim:[13,42,52,65],lightblu:21,lightblue1:21,lightblue2:21,lightblue3:21,lightblue4:21,lightcor:21,lightcyan1:21,lightcyan2:21,lightcyan3:21,lightcyan4:21,lightcyan:21,lightgoldenrod1:21,lightgoldenrod2:21,lightgoldenrod3:21,lightgoldenrod4:21,lightgoldenrod:21,lightgoldenrodyellow:21,lightgrai:21,lightgreen:21,lightgrei:21,lightpink1:21,lightpink2:21,lightpink3:21,lightpink4:21,lightpink:21,lightsalmon1:21,lightsalmon2:21,lightsalmon3:21,lightsalmon4:21,lightsalmon:21,lightseagreen:21,lightskyblu:21,lightskyblue1:21,lightskyblue2:21,lightskyblue3:21,lightskyblue4:21,lightslateblu:21,lightslategrai:21,lightslategrei:21,lightsteelblu:21,lightsteelblue1:21,lightsteelblue2:21,lightsteelblue3:21,lightsteelblue4:21,lightweight:[50,84],lightyellow1:21,lightyellow2:21,lightyellow3:21,lightyellow4:21,lightyellow:21,like:[1,10,16,18,20,22,23,24,26,27,29,31,32,33,34,35,36,38,39,40,42,44,47,50,51,56,57,58,59,60,61,62,63,64,65,68,69,70,72,73,74,84,85,86,87,88,89],lime:21,limegreen:21,limit:[18,19,23,24,25,28,29,31,32,38,40,51,52,53,54,60,63,64,65,73,84],line:[16,24,26,28,30,31,32,45,48,53,60,61,62,63,64,65,66,68,69,70,84,87,89],line_height:32,line_spac:29,linear:[20,23,36,50,65],linearli:51,linen:21,link:38,linux:[18,23,37,40,44,57,63,84],liquid:[26,62],list:[16,18,19,20,22,23,24,25,26,27,28,29,30,32,33,34,35,37,41,44,45,46,50,51,53,58,59,64,65,68,70,84],list_camera:[18,57],list_mod:[23,59],listen:39,littl:[17,22,26,44,50,54,58,59,61,62,64,65,68,84,87,88],live:[16,26,65],ll:[22,58,61,62,63,64,65,84,85,87,88,89],load:[8,10,16,18,22,26,30,31,40,50,59,61,62,63,65,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84,87,89],load_background_imag:62,load_bas:31,load_extend:31,load_imag:[58,66],load_player_imag:62,load_png:[86,87,88,89],load_sound:[58,66,86],load_xbm:22,local:[9,16,33,34,38,39,44,57,58,60,61,68,69,70,71,72,73,76,77,78,79,80,81,85,86,89],locat:[26,34,35,39,41,58,68,69,70,71,72,73,84],lock:[13,17,24,25,27,33,42,43,50,51,52,84],lockobj:13,logger:26,logic:[48,58,61,63,65,68,69,70,71,84,86],logical_s:48,logo:23,loki:63,longer:[19,32,38,47,87,88],longest:38,look:[22,24,28,36,37,44,46,52,56,57,58,62,63,64,65,68,69,70,72,84,85,86,87,88,89],lookout:26,lookup:[23,25,28,50,58,65],loop:[24,25,32,38,40,54,57,61,62,63,64,66,68,84,86,87,88,89],lose:[19,23,33,56,84],loss:[18,23,58,59],lost:[25,40,46,62],lostsprit:64,lot:[26,32,51,54,56,58,59,61,62,63,64,65,67,73,84,85,87,89],loud:38,love:84,low:[32,63,67],low_frequ:[32,47],lower:[19,23,32,37,38,41,52,84],lowercas:28,lowest:37,lowli:84,ls:18,lt:32,luck:65,luckili:84,luma:18,m:[20,26,33,53,58,65,84],mac:[18,23,26,37,40,44,46,63,84],machin:[26,56,64,65,84],maco:22,macosx:25,macro:[3,4,5,6,7,8,9,12,14],made:[3,6,7,12,16,23,25,49,62,71,73,74,84,87],magazin:[16,71],magenta1:21,magenta2:21,magenta3:21,magenta4:21,magenta:21,magic:87,magnifi:26,magnitud:36,magnitude_squar:36,mai:[1,2,18,19,20,22,23,25,27,28,29,30,31,32,33,37,38,40,43,44,45,46,51,53,57,59,62,63,64,65,84],mail:[62,84],main:[18,24,25,26,27,32,39,41,46,50,53,57,61,62,64,65,66,71,72,73,79,80,81,85,86,87,88,89],main_dir:[58,66],mainli:[28,51,62,64,65],maintain:[28,44,50,61],major:[14,23,31,38,44,63],make:[0,16,20,22,24,25,26,27,31,38,42,44,45,50,51,52,54,56,57,58,59,60,63,64,65,67,68,70,71,72,73,74,84,85,86,87,88,89],make_sound:[38,49],make_surfac:[42,43,52],maker:[67,74],malform:29,man:67,manag:[16,19,25,32,38,42,50,51,59,63,64],mani:[19,23,24,25,28,29,33,38,39,40,44,45,50,51,54,56,58,59,62,63,84],manipul:[16,31,42,45,51,63,65,84,87],manner:[59,87],manual:[19,28,29,41,44,51,57,64,84],map:[17,20,24,32,42,43,47,51,52,59,65],map_arrai:[43,52],map_rgb:[20,24,42,51,52],mapped_int:51,margin:[26,68,71,72,73,80,81],mario:88,mark:[33,42,57,63],maroon1:21,maroon2:21,maroon3:21,maroon4:21,maroon:21,mask:[22,23,26,29,42,50,51,59,84],maskfil:22,mass:35,master:[56,65,67],match:[17,23,28,29,32,33,37,38,42,43,51,52,56,58,59,64,65,68],match_font:28,materi:18,math:[24,30,35,36,86,87,89],mathemat:[51,61,65],matter:[31,51,62,64,84,87],max:[24,32,35,57,71],max_i:29,max_x:29,maxhp:[71,72,73,79,80,81],maxi:28,maxim:[25,48],maximum:[23,28,29,84],maxtim:38,maxx:28,mayb:[62,64,70,84,86],me:[59,63,65],mean:[20,22,23,24,29,32,33,36,37,38,39,40,43,47,48,50,56,57,58,59,62,63,64,68,69,70,71,72,84,88],meant:[44,48,64,84],measur:[24,37,84,87],mechanim:67,mechanin:75,mediev:63,medium:32,mediumaquamarin:21,mediumblu:21,mediumorchid1:21,mediumorchid2:21,mediumorchid3:21,mediumorchid4:21,mediumorchid:21,mediumpurpl:21,mediumpurple1:21,mediumpurple2:21,mediumpurple3:21,mediumpurple4:21,mediumseagreen:21,mediumslateblu:21,mediumspringgreen:21,mediumturquois:21,mediumvioletr:21,meet:[45,84],megabyt:23,member:[25,50,59,64,68,84],membership:[50,64],memori:[17,23,24,29,38,51,52,62,67,84],mental:74,mention:[54,58,64,68,70,84],menu:[23,33,61],merchant:18,mercuri:44,mere:[37,84],merg:64,merrili:89,messag:[25,27,37,44,53,58,86,89],messi:64,met:[18,22],meta:33,method:[9,10,12,15,16,17,19,20,22,23,24,25,26,28,29,30,31,32,35,36,38,39,40,42,44,45,46,49,50,51,52,54,58,59,61,62,63,64,65,71,73,84,85,86,87,89],metric:[28,29],mice:39,micro:44,microsoft:23,midbottom:45,middl:[39,47,57,62,65],midi:[25,26],midi_ev:37,midi_event_list:37,midi_not:37,midi_output:37,midi_to_ansi_not:37,midi_to_frequ:37,midiexcept:37,midiin:[25,37],midiout:[25,37],midis2ev:37,midisport:37,midleft:[45,88,89],midnightblu:21,midright:[45,88,89],midtop:45,might:[20,23,25,26,29,44,46,60,61,62,64,65,84,86,87,89],mighti:62,migrationguid:39,milli:54,millisecond:[25,33,37,38,40,50,54,63,84],mime:46,mimic:29,min:[24,57],min_alpha:51,min_i:29,min_x:29,mind:[39,54,60,65],minhp:73,mini:28,miniatur:32,minim:[23,25,48,64],minimum:[23,24,28,30,31,35,51],minor:[14,31,38,44,63],mintcream:21,minu:33,minx:28,mirror:[23,58],miss:[58,66,84],missingmodul:[49,52],mistyros:21,mistyrose1:21,mistyrose2:21,mistyrose3:21,mistyrose4:21,misunderstand:84,miter:24,mix:[28,38,51,63,65,84],mix_chunk:8,mix_setmusicposit:40,mixer:[0,16,26,38,44,49,58,66],mizuno:18,mmsystem:37,mmx:[26,56],moccasin:21,mod:[25,33,34,40,67],mod_:34,modal:48,mode:[16,20,23,24,25,26,28,29,30,33,38,39,44,46,48,50,51,53,58,63,65],mode_ok:[23,59],model:51,modif:[13,18,51,86],modifi:[29,30,33,34,37,39,45,48,49,50,51,64,65,85],modnam:1,modul:[0,1,2,3,4,5,6,7,8,9,10,12,13,16,17,21,26,34,41,42,48,51,53,59,60,61,62,65,66,68,87,89],modulu:20,moment:[46,49,84,87],momma:62,monitor:[23,34,59,63,68],monkei:[58,63,66],mono:[29,38,49],monochrom:29,monster:64,month:63,moon:84,more:[16,18,19,20,23,24,25,26,28,29,30,31,32,35,36,37,38,39,42,43,44,47,50,51,54,57,58,59,60,61,62,63,64,70,71,73,74,85,86,87,88,89],most:[19,23,24,25,26,28,29,31,38,39,40,44,45,50,51,54,57,59,60,61,63,64,65,74,84,85],mostli:70,motion:[32,39,48,63,87,89],motiv:70,mous:[16,22,23,25,26,32,46,48,58,61,62,63,66,67,70,72,84,85,88],mousebuttondown:[22,25,27,39,58,66,84],mousebuttonup:[25,39,58,66,72,73,80,81,84],mousemot:[25,39],mousewheel:[25,39],movabl:[88,89],move:[16,25,26,39,44,45,50,51,56,58,61,63,65,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84,85,87,88,89],move_and_draw_all_game_object:62,move_ip:[45,58,66],move_to_back:50,move_to_front:50,movedown:[70,78,88,89],moveit:[26,62],movement:[32,39,50,58,87,88],movepo:[88,89],moveright:[69,70,77,78],moveup:[69,77,88,89],movi:74,mozart:40,mp3:40,ms:[32,37,39,47],msg:37,msmf:18,much:[18,24,26,28,31,54,56,58,59,60,61,62,63,65,67,68,71,73,74,84,85,87,89],multi_thread:53,multicolor:26,multidimension:65,multigestur:25,multimedia:[33,63,84],multipl:[1,7,18,19,22,23,24,25,26,28,32,33,36,38,41,44,50,51,56,57,61,63,64,65,69],multipli:[20,24,29,33,36,42,48,56,65],multisampl:23,multithread:27,music:[8,16,26,37,38,40,63,74,86],must:[1,2,4,17,18,19,20,22,23,24,25,27,28,29,30,31,32,35,36,37,38,41,42,43,44,45,46,47,49,50,51,52,53,56,58,59,60,63,64,65,68,72],mustlock:51,mutabl:25,mute:38,my:[26,32,61,62,63,65,84,86,89],my_appl:44,my_data_typ:46,mygroup:64,myscreen:[68,69,70,71,72,73,76,77,78,79,80,81],mysprit:64,mysurf:51,mytext:[68,69,70,71,72,73,76,77,78,79,80,81],mytextarea:[68,69,70,71,72,73,76,77,78,79,80,81],mytextfont:[68,69,70,71,72,73,76,77,78,79,80,81],n:[28,33,38,65],name:[1,10,18,19,20,23,25,26,28,29,32,33,37,44,45,47,50,51,53,58,59,61,62,63,64,65,66,68,70,86,88,89],name_forindex:47,name_of_environment_vari:44,namehint:[31,40],namespac:[34,58,60],nano:31,nasti:86,nativ:[16,18,22,44,57,84],natur:[40,65,74,84,86],navajowhit:21,navajowhite1:21,navajowhite2:21,navajowhite3:21,navajowhite4:21,navi:21,navyblu:21,ndim:42,nearest:[24,38],nearli:[64,67],neater:88,necessari:[23,25,27,29,38,51,60,61,64,68,84,85,87,88,89],necessarili:63,need:[11,16,18,19,22,23,25,26,27,28,31,32,33,35,42,44,45,46,50,51,53,57,58,59,60,62,63,64,65,66,67,68,69,70,71,72,73,85,86,87,88,89],needless:[68,71,73,84],needn:[26,61,89],neg:[9,10,17,25,29,35,36,38,39,40,42,45,51,56,65,89],neglig:18,neither:[50,69,70],nest:51,net:[86,89],network:[61,86],never:[29,32,38,39,40,51,54,57,63,65,84],new_height:26,new_lay:50,new_mask:35,new_width:26,newarrai:42,newbi:16,newcom:84,newer:[23,40],newest:68,newli:[20,35],newlin:28,newpo:[58,66,87,88,89],newrect:64,newtonian:63,next:[18,27,29,30,35,36,38,41,46,58,64,68,73,85,88,89],nice:[58,61,62,65,87],nirav:57,node:44,noevent:[25,27,38,40,84],nofram:23,nois:[32,35,57],nomin:29,non:[17,19,23,24,26,29,31,33,41,42,44,50,51,56,58,64,84,86],none:[17,18,19,20,23,24,25,26,27,28,29,30,31,32,33,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,54,56,58,60,65,66,85,86,87,89],nonesound:[58,66],nonetheless:26,nonetyp:[30,35,50],nonlinear:51,nonzero:[35,45],nor:[50,70],normal:[9,12,19,20,28,29,35,36,44,45,50,51,53,55,58,64,65,71,87,89],normalize_ip:36,north:22,northeast:22,northwest:22,nosubprocess:53,notabl:[23,40,87],notat:39,notdef:29,note1:35,note2:35,note:[18,19,20,23,24,25,26,27,29,31,32,33,35,36,37,38,39,40,42,44,45,47,54,56,57,58,59,60,62,64,66,84,86,87,89],note_off:37,note_on:37,noteworthi:63,noth:[19,23,24,30,32,50,58,59,63,64,84,85,86],notic:[18,36,45,62,68,69,70,72,84,87,88,89],notifi:64,notimplementederror:[33,40],novel:74,now:[26,27,28,29,32,33,35,37,38,43,44,46,56,57,58,61,62,63,64,65,67,68,69,70,71,72,73,74,84,85,87,89],nowadai:63,nrp:57,num:[33,72,73,80,81],num_button:39,num_devic:37,num_ev:37,num_fing:25,num_threshold_pixel:56,num_track:19,number:[1,8,11,17,18,19,20,23,24,25,26,28,29,30,31,32,33,35,36,37,38,40,42,44,47,49,50,51,52,53,54,55,56,62,64,65,69,73,74,84],numbit:35,numer:[36,38],numev:[25,38],numfail:44,numlock:33,numpass:44,numpi:[1,16,26,42,43,49,51,52,63],o:[7,22,33,62],obj:[1,2,4,5,8,9,10,44],object:[1,2,4,5,6,7,9,10,12,13,16,18,19,21,22,23,24,25,26,27,28,29,30,31,32,35,38,39,40,43,44,46,47,48,49,52,54,56,57,59,61,62,63,64,65,66,68,69,70,86,89],obliqu:29,obscur:[61,84],obsolet:[23,44,51],obtain:[29,37],obviou:61,obvious:[64,85],occasion:64,occupi:85,occur:[29,33,37,38,42,68],octob:63,odd:[24,65,89],ofcod:89,off:[18,24,25,26,29,32,37,38,40,45,56,58,61,62,64,84,89],offcourt:89,offer:[22,23,25,47,57],offici:62,offset:[17,24,26,28,29,30,35,37,40,42,45,50,51,58],often:[19,31,36,51,61,63,65,69,84,86],ogg:[38,40],oh:89,ok:[65,84,85,87],okai:[69,72],old:[23,39,44,50,51,54,58,62,64,74,84,88],older:[27,32,40,44,64],oldest:68,oldlac:21,oliv:21,olivedrab1:21,olivedrab2:21,olivedrab3:21,olivedrab4:21,olivedrab:21,omit:[29,37,42,53],onc:[18,19,23,25,28,29,31,32,33,35,37,38,40,42,44,47,51,53,54,58,60,63,64,65,84,85,86,87,89],one:[17,18,20,22,23,24,25,26,27,28,29,30,31,32,33,35,38,39,40,42,43,44,45,46,47,49,50,51,52,54,56,57,58,59,60,61,62,63,64,65,67,68,69,70,71,73,84,85,86,87,88,89],ones:[29,40,51,60,64,87,88],onli:[3,17,18,19,20,23,24,25,28,29,31,32,34,35,37,38,39,40,42,43,44,45,46,47,48,49,50,51,52,53,54,56,57,58,59,60,61,62,63,64,65,67,68,72,73,74,84,85,86,87,89],ons:63,onscreen:23,onto:[12,20,27,28,29,30,35,36,50,51,58,62,63,65,68,84,85,87],ooo:84,opac:[48,84],opaqu:[20,26,29,35,43,48,51,52,65,84],open:[1,7,10,16,18,19,23,25,32,33,37,44,46,47,57,58,63,85,86],opencv:[18,44,57],opengl:[23,26],opentyp:29,oper:[15,20,22,23,24,25,27,33,36,42,44,45,48,50,51,52,56,64,65,85],operand:65,oppos:29,optim:[23,26,28,51,56,64,65],optimis:84,option:[1,17,18,20,23,24,26,28,29,30,31,32,35,37,38,39,40,43,44,50,51,53,54,56,57,58,60,62,65,84],orang:21,orange1:21,orange2:21,orange3:21,orange4:21,orangered1:21,orangered2:21,orangered3:21,orangered4:21,orchid1:21,orchid2:21,orchid3:21,orchid4:21,orchid:21,order:[1,18,23,28,29,33,37,38,40,42,44,50,51,53,54,58,62,65,68,84,89],orderedupd:50,ordinari:64,org:[39,58,59,60,62,63,64,65,70,78],organ:[16,50,64,84],organis:61,orient:[29,35,62],origin:[10,20,22,23,24,26,29,31,32,35,42,45,47,48,50,51,56,58,62,63,64,65,66],original_color:56,original_dest_color:56,orthogon:35,os:[10,18,23,26,31,32,37,44,46,58,66,84,86,89],oss:37,osx:[23,63],other:[0,18,19,20,23,24,25,26,27,28,29,30,31,32,33,35,36,38,40,42,43,44,45,46,48,49,50,51,52,53,54,56,57,58,61,62,63,64,68,70,71,84,85,86,87,88,89],otherarrai:42,othermask:35,othersurfac:35,otherwis:[1,2,6,10,13,17,18,22,23,24,26,29,31,35,36,37,38,39,43,45,46,50,51,52,56,62,72,73,89],ouput:[68,76],our:[58,62,63,65,66,74,85],out:[18,24,29,32,35,37,38,40,57,58,59,61,62,64,65,84,85,86,87,88,89],outdat:67,outer:72,outgo:37,outlin:[24,29,35,57],outpng:26,output:[18,25,26,28,32,35,56,67,69,70,73,74,84,88],outputimag:26,outsid:[24,28,30,33,35,39,45,51,56,58,63,68],over:[22,23,29,35,38,40,42,44,47,50,57,60,62,63,64,65,66,84,86],overal:65,overboard:86,overcom:67,overflow:65,overhead:[51,64,84],overlai:64,overlap:[35,45,50,62,64,84,87,89],overlap_area:35,overlap_mask:35,overlin:29,overrid:[18,29,35,44,50,51,63,84],overridden:[23,29,35,38,45],overwrit:[17,24,26,32,47],overwritten:[24,32,47,51],own:[13,22,25,26,27,37,38,46,48,59,61,63,65,84,86],own_data_typ:46,owner:13,ownership:46,p1:48,p2:48,p:[31,33,43],pac:64,pack:[23,51,52,59],packag:[16,26,28,29,30,31,49,52,58,60,63,65],pacman:64,pad:[29,32,56],page:[33,39,46,65],pai:70,pain:84,painless:86,paint:[50,85],pair:[13,23,24,28,29,31,32,45,51],pajitnov:74,palegoldenrod:21,palegreen1:21,palegreen2:21,palegreen3:21,palegreen4:21,palegreen:21,palett:[23,28,31,35,51,52,56],palette_color:[35,56],paleturquois:21,paleturquoise1:21,paleturquoise2:21,paleturquoise3:21,paleturquoise4:21,palevioletr:21,palevioletred1:21,palevioletred2:21,palevioletred3:21,palevioletred4:21,panic:84,papayawhip:21,paper:84,parallax:84,param:24,paramet:[18,20,23,24,25,26,29,30,31,33,35,36,37,38,39,40,44,45,46,51,55,56,57,70,71],parametr:36,parent:[2,13,17,48,50,51],parenthesi:33,pars:[84,87],part:[23,24,25,29,30,35,51,53,56,62,63,64,65,68,69,70,72,86],parti:[18,63],partial:[23,24,37,51,84],particular:[18,29,40,42,49,50,53,54,59,84],particularli:37,pass:[9,10,15,17,18,19,20,22,23,24,25,26,28,29,31,32,35,37,38,39,40,41,42,44,46,50,51,53,54,56,58,62,63,64,66,86],past:[24,46,58,63,84],patch:[14,26,31,38,44,63],patel:57,path:[7,10,16,25,26,28,29,31,36,38,44,53,57,58,66,86,89],pathlib:[28,29,31,38],pathlib_path:38,pathnam:[38,58,86],pattern:[29,40],paus:[19,26,33,38,40,54,86],pbm:[31,46],pc:[17,37],pcf:29,pci:65,pcx:31,peachpuff1:21,peachpuff2:21,peachpuff3:21,peachpuff4:21,peachpuff:21,peek:25,pellet:64,penalti:[51,59,64],pend:37,peopl:[16,58,61,62,63,84],per:[16,24,25,29,30,31,32,35,49,50,51,52,53,54,58,59,63,65,69,77,84,88,89],perfect:35,perfectli:84,perform:[12,23,25,26,28,29,30,35,36,38,42,50,51,52,56,57,59,64,65,84,85,88],perhap:[62,64,84,86],period:[33,40],permiss:23,permit:[15,18,29],person:[62,63,88],perspect:[26,63],peru:21,pete:[58,59,60,62,63,64,65,84],pfr:29,pg:[22,58,66],pg_buffer:[1,2],pg_encodefilepath:10,pg_encodestr:10,pg_floatfromobj:1,pg_floatfromobjindex:1,pg_getdefaultwindow:1,pg_getdefaultwindowsurfac:1,pg_intfromobj:1,pg_intfromobjindex:1,pg_major_vers:14,pg_minor_vers:14,pg_mod_autoinit:1,pg_mod_autoquit:1,pg_patch_vers:14,pg_registerquit:1,pg_rgbafromobj:[1,11],pg_setdefaultwindow:1,pg_setdefaultwindowsurfac:1,pg_twofloatsfromobj:1,pg_twointsfromobj:1,pg_uintfromobj:1,pg_uintfromobjindex:1,pg_version_atleast:14,pg_versionnum:14,pg_view_p:1,pgbuffer_asarrayinterfac:1,pgbuffer_asarraystruct:1,pgbuffer_releas:1,pgbufproxy_check:2,pgbufproxy_getpar:2,pgbufproxy_new:2,pgbufproxy_trip:2,pgbufproxy_typ:2,pgcd_asid:3,pgcd_check:3,pgcd_new:3,pgcd_type:3,pgcdobject:3,pgchannel_asint:8,pgchannel_check:8,pgchannel_new:8,pgchannel_typ:8,pgchannelobject:8,pgcolor_check:4,pgcolor_new:4,pgcolor_newlength:4,pgcolor_typ:4,pgdict_asbuff:1,pgevent_check:6,pgevent_filluserev:6,pgevent_new2:6,pgevent_new:6,pgevent_typ:6,pgeventobject:6,pgexc_buffererror:1,pgexc_sdlerror:1,pgfont_check:7,pgfont_is_al:7,pgfont_new:7,pgfont_typ:7,pgfontobject:7,pglifetimelock_check:13,pglifetimelock_typ:13,pglifetimelockobject:13,pgm:31,pgobject_getbuff:1,pgrect_asrect:9,pgrect_fromobject:9,pgrect_new4:9,pgrect_new:9,pgrect_norm:9,pgrect_typ:9,pgrectobject:9,pgrwops_fromfileobject:10,pgrwops_fromobject:10,pgrwops_getfileextens:10,pgrwops_isfileobject:10,pgrwops_releaseobject:10,pgsound_aschunk:8,pgsound_check:8,pgsound_new:8,pgsound_typ:8,pgsoundobject:8,pgsurface_assurfac:12,pgsurface_blit:12,pgsurface_check:12,pgsurface_lock:13,pgsurface_lockbi:13,pgsurface_locklifetim:13,pgsurface_new:12,pgsurface_prep:13,pgsurface_typ:12,pgsurface_unlock:13,pgsurface_unlockbi:13,pgsurface_unprep:13,pgsurfaceobject:[1,12,13],pgvidinfo_asvidinfo:5,pgvidinfo_check:5,pgvidinfo_new:5,pgvidinfo_typ:5,pgvidinfoobject:5,pgyam:[0,5],phase:[69,70],phi:36,photo:44,photograph:56,physic:[17,23,32,61,63,86,88,89],pi:[24,89],pick:[23,44,56,59,62,64],pictur:[31,63],pie:30,piec:[29,84],pile:26,pinch:25,pink1:21,pink2:21,pink3:21,pink4:21,pink:21,pipe:23,pitch:[37,51,62],pitch_bend:37,pixel2d:65,pixel3d:65,pixel:[16,17,18,20,22,23,24,26,28,29,30,31,35,41,45,48,51,56,58,59,63,65,85,88,89],pixel_arrai:42,pixelarrai:[16,26,42,51],pixelcopi:[26,42,43,52],pixelformat:18,pixels2d:[52,65],pixels3d:[52,65],pixels_alpha:[52,65],pixels_blu:52,pixels_green:52,pixels_r:52,pixels_within_threshold:56,place:[1,23,25,27,29,34,36,37,39,42,44,45,46,50,51,52,53,58,62,63,64,65,68,84,87,88],placehold:44,placement:44,plai:[8,16,19,23,26,32,37,40,47,58,62,63,64,66,70,74,84,86,89],plain:46,plan:[51,63],plane:[41,51],plant:65,platform:[16,18,23,24,25,30,33,35,37,38,41,44,46,53,54,57,58,59,63,84,86,88],playabl:49,playback:[19,26,38,40,63],player1:[61,89],player2:89,player:[26,50,58,61,62,64,68,70,73,74,84,88,89],playerimag:62,playerpo:62,playersprit:89,playmu:26,playstat:32,pleas:[23,44,84],plenti:61,plot:61,plu:[28,29,33,37,44,64],plug:[25,32],plum1:21,plum2:21,plum3:21,plum4:21,plum:21,pm_recommended_input_devic:37,pm_recommended_output_devic:37,pmdeviceid:37,png:[26,31,58,63,65,66,67,68,69,70,75,76,77,78,84,86,87,88,89],pnm:31,po:[25,27,35,40,50,58,62,66,72,73,80,81],point:[15,17,19,20,22,24,26,28,29,30,35,36,37,45,48,50,56,57,62,63,64,65,67,72,84,89],pointer:[9,12,58,84],polar:36,polish:[22,63],poll:[25,27,37,84],polygon:[24,30],pong:[61,86,89],poor:61,poorli:61,pop:44,popular:[26,32,66],port:[18,26,37,44,48],portabl:[33,37,63],portion:[12,23,45,48,51,56,63,64],portmidi:37,posit:[1,9,17,19,22,23,24,25,26,28,29,30,32,33,35,38,39,40,44,45,48,50,51,53,55,57,58,62,63,64,66,68,69,84,85,87,88,89],possibl:[18,23,28,29,31,32,50,51,57,58,61,63,65,67,68],post:[25,27,38,47,54],potenti:[31,64,84,88],powderblu:21,power:[18,32,33,38,64,74],ppem:29,ppm:[31,46],pr:39,practic:[84,86],pre:[20,29],pre_init:38,prealloc:51,prebuilt:16,preced:[35,68],precis:[23,38,51,65,84],predecessor:[65,84],predefin:[25,46],predomin:43,prefer:[23,30,31,33],prefix:58,prematur:84,premul_alpha:20,prepar:[26,40,66],present:[44,48,60,63,64],preserv:[20,44,45,51],preset:[22,38],press:[26,32,33,39,47,57,58,62,70,71,84],pressur:55,pretend:62,pretti:[59,62,64,65,84,85,88,89],prevar:84,prevent:[25,89],prevent_display_stretch:23,previou:[1,23,29,38,39,48,50,54,56,58,62,64,65,69,70,72,73,85,89],previoulsi:40,previous:[18,20,25,28,29,31,38,40,44,59,85],primari:39,primarili:[29,44,48],prime:48,primer:65,primit:30,principl:[88,89],print:[25,28,32,33,36,39,44,45,46,57,58,59,62,66,68,70,71,72,73,76,84,86,89],printboard:[73,81],printf:[67,75],prior:23,prioriti:18,privat:[51,58],probabl:[26,62,64,68,84,85],problem:[43,44,58,61,69,84,86],procedur:[67,68],process:[18,25,26,27,32,46,52,53,54,60,62,67,68,70,72,73,77,84],processor:[54,56],procur:18,produc:[29,84],product:[36,61],profil:[23,84],profit:18,program:[16,19,23,25,27,32,33,37,38,41,44,45,53,54,58,61,62,63,64,65,66,67,68,69,70,71,73,74,84,85,86,87,88],programm:[63,64,84,86,87],programmat:44,progress:43,project:[26,36,61,63,67,68,69,70,71,72,73,76,77,78,79,80,81,84,86,87,89],prolog:73,promis:[58,62],prompt:[44,63,65],proper:[29,33,38,39,64,65],properli:[10,16,25,39,53,58,62,64,65,84],properti:[17,25,29,39,50,52],propos:63,protect:[26,58],protocol:[2,16,43,51],proud:62,provid:[16,18,20,23,26,27,28,29,33,35,36,38,41,42,44,45,50,51,53,54,56,57,58,67,84,86,87],proxi:[2,17],ps4:32,ps:[26,32],pseudo:87,pt:56,pull:[18,58,66],pummel:[58,66],pump:[25,27,32,88,89],punch:[58,63,66],punch_sound:[58,66],punchabl:58,punctuat:28,pure:[44,51],purpl:21,purple1:21,purple2:21,purple3:21,purple4:21,purpos:[1,18,48,57,61],push:[33,71,88],pushabl:32,put:[32,46,54,60,61,63,64,66,68,85,86,87],puyopuyo:[67,75],pxarrai:42,py:[16,23,26,44,46,53,56,61,62,63,65],py_buff:[1,17],pybuf:1,pybuffer_releaseproc:1,pycdio:19,pygam:[2,11,15,21,68,69,70,71,72,73,74,75,76,77,78,79,80,81,86,87,89],pygame_blend_add:12,pygame_blend_alpha_sdl2:[12,44],pygame_blend_max:12,pygame_blend_min:12,pygame_blend_mult:12,pygame_blend_premultipli:12,pygame_blend_rgba_add:12,pygame_blend_rgba_max:12,pygame_blend_rgba_min:12,pygame_blend_rgba_mult:12,pygame_blend_rgba_sub:12,pygame_blend_sub:12,pygame_bufferproxi:2,pygame_camera:44,pygame_displai:44,pygame_force_scal:44,pygame_freetyp:[7,28,44],pygame_hide_support_prompt:44,pygame_mix:8,pygameapi_base_numslot:11,pygamevers:44,pyobject:[1,2,3,4,5,6,7,8,9,10,12,13],pyopengl:[26,31,63],pypi:42,pyportmidi:37,pysdl:[63,84],pythagorean:[36,69],python26:26,python2:26,python3:18,python:[1,2,3,4,5,6,7,8,9,10,12,13,15,16,17,18,19,22,26,28,29,31,38,43,44,45,50,51,53,58,60,61,62,64,66,67,68,85,86,87],pytypeobject:[2,3,4,5,8,9,12,13],pyunicode_asencodedstr:[10,44],q:33,qce:18,quadrant:24,quadruplet:[24,30],quake3:63,qualiti:[26,44,58,63],quaternion:67,queri:[23,37,46,59],query_imag:[18,57],question:[33,62,84],queu:[25,38,40],queue:[6,18,23,32,33,34,37,38,39,40,47,54,58,63,84,88],quick:[25,26,32,51,53,60,64,65,84,88],quicker:[50,51,56,64],quickest:51,quickli:[31,58,59,62,63,64,65,84],quietli:25,quit:[1,19,22,23,24,25,26,28,29,32,37,38,39,44,47,51,53,57,58,62,63,65,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,85,88,89],quiz:73,quot:33,quotedbl:33,r:[9,20,26,30,32,33,36,42,43,51,56,64,65,71,72,73,79,80,81],r_margin:[72,73,80,81],radial:[36,65],radian:[24,30,36,87,89],radii:[24,30],radiu:[24,30,50],radom:74,rais:[1,2,3,4,5,6,7,8,9,10,15,17,20,22,23,24,25,26,28,29,30,31,33,35,36,37,38,40,43,44,45,46,48,49,50,51,52,56,57,60,65,86,89],ramp:23,ran:85,rand:89,randint:[73,81,89],random:[53,61,73,74,81,86,89],randomli:73,rang:[20,23,24,25,28,29,32,35,36,37,38,42,44,47,50,57,62,63,65,68,71,72,73,79,80,81],rank:84,rapid:32,rapidli:[33,62],rare:[44,51,84],rate:[38,40,50,69,84],rather:[28,29,30,33,44,50,54,56,69,85,87],ratio:[45,50],raw:[17,31,42,43,51,52,65],rb:46,re:[22,26,29,44,56,59,61,62,64,71,85,87,88],reach:63,read:[10,17,20,25,26,29,37,39,46,48,50,51,61,62,65,84],readabl:[20,38,68,86],readi:[18,22,32,48,53,57,58,62,63],readlin:22,readm:16,readonli:50,real:[25,28,29,37,38,51,57,59,62,64,70,84],realist:[86,89],realiti:59,realiz:[63,84],realli:[23,41,56,58,59,62,63,64,65,70,85,87,88],realtim:[51,63,65],reason:[23,27,28,29,38,39,56,57,61,62,64,84,87],rebel:63,rebind:47,recalcul:29,recap:61,receiv:[23,27,32,33,39,47,84],recent:[58,63,64,65],reciev:23,recogn:[17,25,29,43,45,56],recogniz:31,recommend:[23,25,27,28,50,51],recommended_input_devic:37,recommended_output_devic:37,recompil:89,record:[18,29,52,53,72,84],recreat:[26,50,53],rect1:45,rect2:45,rect:[0,16,24,29,30,33,35,41,45,48,50,51,56,57,58,62,63,64,66,71,72,73,79,80,81,86,87,88,89],rect_area_pt:56,rect_list:50,rect_sequ:45,rectangl:[9,16,23,24,26,28,29,30,33,45,48,50,51,56,64,68,84,85,87,89],rectangle_list:23,rectangular:[9,29,30,35,42,48,50,51,62,63,71,84],rectstyl:84,red1:21,red2:21,red3:21,red4:21,red:[1,18,20,21,23,24,31,42,50,51,52,65,68,69,70,71,72,73,76,77,78,79,80,81,85],redimg:65,redistribut:18,redraw:[41,62],redrawn:[23,41],reduc:[29,38,64,88],reentrant:53,ref:[70,78],refcount:10,refer:[1,13,17,23,24,31,33,35,42,46,47,49,51,52,57,58,59,62,63,64,65,68,69,70,71,72,73,84,88],referenc:[52,58,64,65],reflect:36,reflect_ip:36,regard:[24,68],regardless:[28,44],region:[31,51,56,86],regist:[1,44,46,87],register_quit:44,registri:37,regular:[16,23,24,28,40,41,50,51,56,64],regularli:32,reinit:[88,89],reiniti:38,reinitialis:32,rel:[25,32,37,39,40,41,48,50,61,86],relat:[1,23,29,34,39,43,47,50,84],relationship:50,relative_mous:48,releas:[1,13,17,18,23,29,30,32,33,37,39,42,44,46,51,58,63,84,86,88,89],release_buff:1,relev:[29,84],reli:[9,88],reliabl:[18,23,37,84],remain:[20,40,45,51,52,85],remap:[42,47],rememb:[25,39,50,51,59,61,63,64,65,68,73,84,86,87],remind:68,remov:[13,17,18,25,27,28,32,36,48,50,56,58,64,89],remove_intern:64,remove_sprites_of_lay:50,renam:47,render:[16,23,24,26,32,41,48,50,58,63,66,68,69,70,71,72,73,76,77,78,79,80,81,84,85,87,88],render_raw:29,render_raw_to:29,render_to:29,renderclear:[50,64],renderplain:[50,58,64,66,89],renderupd:[26,50,64],renderupdatesdraw:64,repaint:[25,27,50],repaint_rect:50,repcolor:42,repeat:[23,33,35,38,40,44,61],repeatedli:[50,51,54,56,58],replac:[1,23,27,29,38,42,43,44,51,52,54,62,65,68],report:[26,32,44,56,84],repositori:[44,84],repr:44,repres:[1,12,13,14,16,17,19,20,22,23,24,25,29,31,32,33,35,38,39,40,41,44,45,47,48,52,54,56,58,62,63,64,65,84,87],represent:[1,4,9,16,21,24,30,42,56,58],reproduc:18,request:[1,23,26,28,29,35,38,49,51,52,59],requir:[17,18,23,25,26,28,31,33,35,36,37,38,44,45,46,47,50,51,55,56,59,61,62,63,64,65,68,70,84,85,86,88],resampl:38,rescal:26,resembl:[26,43,52],reserv:[25,37,38],reset:[29,32,37,38,40,50,58,89],resist:84,resiz:[16,23,25,26,35,45,48,56,58,85],resolut:[23,29,41,51,54,56,58,59],resolv:[46,68,87],resourc:[26,38,40,44,59,61,66,87],respect:[1,22,23,24,33,35,36,46,50,51],respond:[25,27,62],respons:53,rest:[19,25,27,57,58,62,63,65,84],restart:[40,86],restor:[23,25,48],restrict:51,result:[20,24,28,29,35,36,37,40,42,51,53,56,58,62,63,64,65,68,69,70,73,76,84,89],resultscreen:[69,70,77,78],resum:[19,38,40],retail:63,retain:[18,51],retrac:23,retriev:[14,36,38,46,84,88],reus:[18,86],reusabl:86,rev:44,revers:[1,58,63,65,89],revis:[44,61,63],reward:[58,63],rewind:40,rewound:26,rgb:[18,20,23,24,28,30,31,41,43,51,57,58,63,65,84,85],rgba:[1,4,20,23,24,30,31,51],rgba_premult:31,rgbarrai:65,rgbx:31,rich:58,rid:57,ridicul:61,right:[20,23,24,25,29,30,32,33,35,38,42,44,45,47,50,51,58,62,63,64,65,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84,87,88,89],rle:51,rleaccel:[51,58,66],rleaccelok:51,road:62,roll:[32,39,64],root:[36,53,84],rosybrown1:21,rosybrown2:21,rosybrown3:21,rosybrown4:21,rosybrown:21,rotat:[25,26,29,36,48,50,56,58,63,66],rotate_i:36,rotate_ip:36,rotate_ip_rad:36,rotate_rad:36,rotate_rad_ip:36,rotate_x:36,rotate_x_ip:36,rotate_x_ip_rad:36,rotate_x_rad:36,rotate_x_rad_ip:36,rotate_y_ip:36,rotate_y_ip_rad:36,rotate_y_rad:36,rotate_y_rad_ip:36,rotate_z:36,rotate_z_ip:36,rotate_z_ip_rad:36,rotate_z_rad:36,rotate_z_rad_ip:36,rotozoom:56,round:[20,24,37,38,88],routin:[1,18,25,28,29,51,56,58,59,68],row1:65,row2:65,row:[35,42,51,65],royalblu:21,royalblue1:21,royalblue2:21,royalblue3:21,royalblue4:21,rr:20,rrggbb:20,rrggbbaa:20,rt:32,rudder:32,rudimentari:26,ruin:65,rule:[59,70,73,74,89],rumbl:[32,47],run:[23,25,26,31,32,38,44,53,54,56,58,59,62,63,64,65,66,67,84,85,89],run_speed_test:26,run_test:53,run_tests__test:53,rundown:26,runner:53,runtim:[23,38,54,56,63],runtimeerror:[29,44],rw:10,rwobject:0,rx:30,ry:30,s:[9,12,13,15,17,20,22,23,24,25,26,28,29,31,33,35,36,37,38,39,40,41,42,43,44,45,46,47,48,50,51,54,58,59,61,63,64,65,67,68,69,70,71,74,84,85,86,87,88,89],saddlebrown:21,safe:[19,23,25,28,29,32,37,38,42,44,47,50,51,57,60],sai:[51,61,62,64,68,84],said:[24,61,68,70,74,84,85],sake:85,salmon1:21,salmon2:21,salmon3:21,salmon4:21,salmon:21,sam:63,same:[10,18,19,20,22,23,24,25,28,29,30,31,32,33,35,36,38,39,42,43,44,45,47,50,51,52,54,56,57,58,59,62,63,64,65,67,68,70,71,72,73,84,85,89],sampl:[16,20,38,40,56,57,62,64,65,88],san:29,sandybrown:21,satisfactori:86,satisfi:23,satur:18,sauf:35,save:[16,18,31,61,63,84],save_extend:31,saw:[57,58,62],scalabl:29,scalar:[36,58],scale2x:56,scale:[18,23,24,26,29,31,35,36,44,48,50,56,58,63,65,66],scale_to_length:36,scaledown:65,scaler:26,scaletest:26,scaleup:65,scan:19,scancod:[25,33],scanf:[67,75],scanlin:62,scant:26,scene:57,school:39,scipi:65,scope:[42,65],score:[26,50,61,70,89],scoreboard:61,scoreup:61,scrap:[16,46],scrap_bmp:46,scrap_clipboard:[26,46],scrap_pbm:46,scrap_ppm:46,scrap_select:46,scrap_text:46,scratch:64,scratchi:38,screen:[1,5,16,22,24,25,26,28,31,32,33,34,39,44,45,46,48,50,51,57,58,59,61,63,64,65,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84,85,87,88,89],screen_dim:26,screen_height:23,screen_rect:50,screen_width:23,screensav:[23,44,69],screenshot:58,script:[29,60,63,66],scroll:[25,26,39,51,62,63,64,84],scrollabl:26,scroller:84,scrollock:33,sdl1:[19,23,41,51],sdl2:[25,32,38,39,44,47,51,55],sdl:[1,3,6,8,10,12,13,23,25,26,27,32,33,38,41,43,44,47,48,56,59,63,84],sdl_audiodriv:44,sdl_delai:54,sdl_event:6,sdl_gfx:30,sdl_hint_video_allow_screensav:23,sdl_imag:[31,63],sdl_mixer:[38,40],sdl_rect:[9,12],sdl_rwop:10,sdl_surfac:12,sdl_ttf:[28,29,44],sdl_video:51,sdl_video_allow_screensav:44,sdl_video_cent:44,sdl_video_window_po:44,sdl_video_x11_net_wm_bypass_compositor:44,sdl_videodriv:[23,44],sdl_videoinfo:5,sdl_window:1,sdl_windowid:23,sdlerror:40,sdlversion:44,seagreen1:21,seagreen2:21,seagreen3:21,seagreen4:21,seagreen:21,search:[16,28,29,35,45,50,56],search_color:56,search_surf:56,seashel:21,seashell1:21,seashell2:21,seashell3:21,seashell4:21,second:[17,19,20,22,24,26,30,32,36,38,40,42,49,50,53,54,58,60,62,63,65,69,70,71,72,77,84,88,89],secondari:84,section:[19,51,58,61,62,64,65,67,68,86,89],secur:86,see:[18,19,20,23,24,26,28,29,30,31,32,33,35,36,37,38,39,43,44,45,47,50,51,52,56,57,58,60,61,62,63,64,65,84,85,87,88,89],seed:[53,65],seek:10,seem:[31,46,61,62,63,64,68,72,73,84,85,87],seemingli:61,seen:[23,61,65,88,89],segment:[24,30],select:[18,23,29,33,35,37,38,40,44,46,53,59,67,69,73,84],self:[20,32,35,36,50,51,56,57,58,62,64,66,87,88,89],sell:62,semi:[26,84],semicolon:33,semiton:37,send:[25,37,38,40,89],sens:[62,87,88,89],sensit:84,sent:[23,25,32,33,38,40],separ:[18,22,26,28,29,37,38,44,50,51,52,53,56,57,61,62,64,65,72,84,86],sequenc:[1,9,15,22,23,24,25,29,30,33,35,37,39,42,45,50,51,56,59,63,64,84,88],sequenti:24,seri:[37,63,70],serv:[27,63],server:[26,39],servic:18,session:53,set:[1,7,17,18,20,22,23,24,25,28,29,31,32,33,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,54,56,58,60,62,65,67,68,70,71,72,73,84,85,86,87,88,89],set_allow:25,set_allow_screensav:23,set_alpha:[43,51],set_at:[35,51,65,84],set_behavior:56,set_block:[25,84],set_bold:28,set_capt:[22,23,24,32,58,66,68,69,70,71,72,73,76,77,78,79,80,81,85,89],set_clip:[50,51],set_color:56,set_colorkei:[43,51,58,66,84],set_control:[18,57],set_cursor:[22,39],set_default_resolut:29,set_endev:[38,40],set_error:44,set_eventst:47,set_fullscreen:48,set_gamma:23,set_gamma_ramp:23,set_grab:[25,33,39],set_icon:[23,48],set_instru:37,set_ital:28,set_length:20,set_loc:41,set_map:47,set_mask:51,set_mod:[1,22,23,24,32,33,34,39,44,46,48,51,57,58,59,62,63,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84,85,89],set_modal_for:48,set_num_channel:38,set_palett:[23,51],set_palette_at:51,set_po:[39,40],set_repeat:33,set_reserv:38,set_shift:51,set_smoothscale_backend:56,set_text_input_rect:33,set_tim:54,set_timing_threshold:50,set_timing_treshold:50,set_underlin:28,set_viewport:48,set_vis:[39,58,66],set_volum:[38,40],set_window:48,setcolor:35,setsurfac:35,settabl:44,setup:[22,26],sever:[16,22,23,24,26,29,38,45,50,54,59,60,62,63,64,65,84,85,89],sf:42,sfnt:29,sg:22,shade:24,shall:18,shallow:35,shape:[16,17,42,43,51,63,65,72,84],share:[16,25,28,31,32,33,38,46,48,51,52,54],sharp:24,she:85,shell:26,shift:[23,26,33,35,42,44,51,59,65],shinner:[58,59,60,62,63,64,65,84],shoot:63,shortcut:64,shorter:[23,58,65],shortest:36,shot:64,should:[18,19,22,23,25,26,28,29,30,31,32,33,35,36,37,38,42,44,45,47,50,51,54,56,58,59,61,62,63,64,65,68,69,84,85,86,87,89],shoulder:47,shouldn:88,show:[22,23,26,29,33,39,41,48,53,56,57,58,59,62,65,88,89],show_output:53,showcas:[26,84],shown:[23,25,33,41,57,62,87],shrink:[45,84,89],shrinkag:56,shrunk:51,shtml:[86,89],shut:[23,29,32,44,69],shutdown:[8,63],side:[23,24,42,45,47,58,61,63,87,88],sienna1:21,sienna2:21,sienna3:21,sienna4:21,sienna:21,sign:[17,33,37,38,39,44],signal:[25,40,85],signific:51,silenc:53,silent:[23,60,84],silver:21,similar:[29,31,32,42,49,50,51,54,58,62,64,65,85,86,88,89],simpl:[16,22,23,24,25,26,32,42,50,51,56,57,58,60,61,62,63,64,65,66,67,69,71,72,73,74,84,85,86,89],simpler:[62,63,64],simplest:[57,71],simpli:[22,25,37,41,44,50,57,58,59,62,63,65,67,84,85,87,89],simul:[58,67],simultan:[38,67],sin:[87,89],sinc:[19,23,25,31,32,36,38,39,44,48,50,51,52,54,57,58,59,60,62,63,64,65,84],singl:[17,20,22,23,24,25,28,29,30,32,33,38,40,41,42,43,45,50,51,52,53,58,60,61,62,63,64,65,67,68,69,70,71,73,85],sit:84,site:26,situat:[23,51,58,64,65],six:[38,40,61,63],sizabl:84,size:[9,17,18,22,23,24,25,26,28,29,31,35,38,39,41,42,43,45,48,50,51,52,56,57,58,59,61,62,63,65,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84,85],sizeabl:23,sizeal:22,sizenesw:22,sizenws:22,sizeof:35,sizer_x_str:22,sizer_xy_str:22,sizer_y_str:22,skew:28,skip:[23,35,38,58],skyblu:21,skyblue1:21,skyblue2:21,skyblue3:21,skyblue4:21,sl:22,slash:[22,33],slateblu:21,slateblue1:21,slateblue2:21,slateblue3:21,slateblue4:21,slategrai:21,slategray1:21,slategray2:21,slategray3:21,slategray4:21,slategrei:21,sleep:[25,54],slerp:36,slice:[36,42,43,65,84],slight:[58,64],slightli:[20,25,26,39,40,51,54,58,64,84,85],slope:24,sloppi:26,slot:0,slow:[23,48,51,57,59,62,65,84,85],slower:[24,50,51,54,62,84],slowest:[44,51,85],small:[18,22,23,28,29,32,39,44,45,58,62,63,65,71,72,85,87],smaller:[18,23,35,38,45,51,71,72,84],smallest:[23,51,59],smart:[62,64],smooth:[28,58,84],smoother:62,smoothli:[56,62,84],smoothscal:[26,56],sn9c101:18,snapshot:57,sndarrai:[16,26,38,49,63],snow1:21,snow2:21,snow3:21,snow4:21,snow:21,so:[11,17,18,22,23,24,26,28,29,30,31,32,33,36,38,42,43,44,45,50,51,52,53,56,58,59,61,63,64,65,67,68,69,70,71,72,74,84,85,86,87,88,89],socket:[86,89],soften:65,softwar:[16,18,23,24,30,37,41,50,51,58,63,84],solarwolf:[63,84],solid:[24,28,30,50,51,52,56,65],solut:[84,85],solv:[38,61,67],some:[16,18,22,23,24,25,27,28,29,30,31,32,34,36,37,38,39,42,44,45,46,50,56,57,58,59,60,61,63,64,65,67,68,69,70,72,84,85,86,87,88,89],someimag:26,someth:[18,24,26,32,39,56,57,59,62,63,64,65,68,69,70,84,85],sometim:[22,23,27,44,64,84],somewhat:[26,64],somewher:[64,68],sonix:18,soon:[40,44,64,88],sophist:[86,87],sorri:[57,59],sort:[23,25,26,27,50,58,59,62,64,84,89],sound:[8,16,26,40,58,61,63,64,66,67,70,73,84,86],sound_array_demo:26,sour:48,sourc:[16,18,26,31,37,38,42,43,50,51,56,58,61,62,63,64,67,68,69,70,84,86,89],source_rect:50,sourcecod:[68,69,70,76,77,78],south:22,southeast:22,southwest:22,space:[20,28,29,31,33,37,42,62],sparingli:48,speak:[85,86],speaker:38,special:[18,22,23,25,33,35,38,43,50,56,58,59,62,64,65,68,84,85],special_flag:[48,50,51],specif:[23,25,28,29,33,35,38,43,46,50,51,52,57,58,59,64,65,68,70,71,72,84],specifi:[14,18,21,23,28,29,31,32,35,37,38,40,46,47,50,56,59,65,84,89],sped:24,speed:[25,26,29,44,54,62,63,64,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84,85,87,88,89],spend:84,spent:[63,74,84],spheric:36,spin:[26,58,66,88,89],spite:50,split:[22,29,58,63,64,66,84],sport:63,spot:84,spread:84,spring:56,springgreen1:21,springgreen2:21,springgreen3:21,springgreen4:21,springgreen:21,sprite1:50,sprite2:50,sprite:[16,26,35,50,61,66,84,88,89],sprite_dict:50,sprite_list:50,spritecollid:[50,64,87],spritecollideani:50,spritedict:64,sprites_click:84,sqrt:[36,69],squar:[24,32,36,72],src:65,src_c:[0,11,14],srcalpha:[35,43,51,56],srccolorkei:51,srcobj:12,srcrect:[12,48],sse:[26,56],stabl:43,stack:25,stage:57,stai:[61,65,70],stand:26,standard:[1,22,25,27,41,43,44,46,50,57,58,59,61,63,64,65,68],star:26,starfield:[26,84],start:[1,17,18,19,24,25,26,29,30,32,33,35,38,39,40,42,44,45,47,50,51,57,58,59,61,62,63,64,65,66,67,69,74,84,85,86,88,89],start_angl:[24,30],start_index:65,start_po:24,start_text_input:33,startup:[8,38],state:[23,25,26,29,31,32,33,37,38,39,46,47,48,50,51,58,64,66,67,84,88,89],statement:[68,69,70,71,72,89],stationari:64,statu:[26,32,37,70],stderr:53,stdin:65,stdout:53,steelblu:21,steelblue1:21,steelblue2:21,steelblue3:21,steelblue4:21,steep:24,stencil:23,step:[16,30,32,42,58,65,68,70,73,84,88],stereo:[23,38,49],stick:[32,47,62,65,84],still:[23,31,38,39,43,46,47,48,51,57,58,61,62,63,64,65,71,72,73,84,85,88,89],stop:[1,18,19,24,30,32,33,38,39,40,44,47,54,57,62,64,84,88,89],stop_angl:[24,30],stop_rumbl:[32,47],stop_text_input:33,store:[9,22,23,25,29,30,35,50,51,52,58,62,64,68],str:[17,18,20,29,32,35,37,44,47,49,52,71,72,73,79,80,81],straight:[24,30,62,63,65,86],straighten:62,straightforward:[62,63],strang:[23,63],strateg:84,strategi:84,stream:[16,37,38,48,63],strength:[29,32,47],stress:63,stretch:[23,26,28,29],strict:[18,61],strictli:[30,85],stride:[17,42],strike:29,string:[10,15,17,18,19,20,22,23,25,28,29,31,32,33,37,38,41,44,46,48,49,51,52,53,56,68,84,86,87],strip:51,stripe:65,stroke:24,strong:29,strongli:[23,50],struct:[1,3,5,6,7,8,10,17,29,42,43,51,52],structur:[8,11,43,85,87,88],stuck:62,studi:[65,87],studio:63,stuff:[46,57,61,62,65],style:[25,26,29,32,42,63,86],style_default:29,style_norm:29,style_obliqu:29,style_strong:29,style_underlin:29,style_wid:29,sub:[50,84],subarrai:42,subclass:[2,3,4,5,6,7,8,12,13,17,20,35,45,50,51],subdirectori:[26,58],subgroup:67,subject:[23,44],submask:35,submit:84,submodul:[44,53],subpackag:53,subprocess:53,subprocess_ignor:53,subscript:[36,42],subsect:62,subsequ:57,subset:[22,23,84],substanti:84,substitut:[18,22],substr:37,subsubsurfac:51,subsurfac:[13,51,56],subtract:89,subview:42,succe:[18,23],succeed:18,success:[1,2,6,9,10,12,23,44,84],successfulli:[32,47],sudden:63,sufac:42,suffix:45,suggest:[42,58,84],suit:[27,51,59],suitabl:[23,28,29,46,63,68,86],sum:[24,74],summari:64,summer:63,suppli:[18,35,37,38,57,58,65,85],support:[1,7,17,18,19,20,22,23,24,25,26,28,29,31,32,33,35,36,37,38,39,40,41,42,43,44,47,48,49,50,51,52,54,56,57,58,59,63,84,87],suppos:[56,84],sure:[11,50,54,57,58,63,64,65,69,70,84,89],surf:[22,26,29,30,42,50,51,56],surfac:[0,1,2,11,13,16,18,20,22,23,24,26,28,29,30,31,35,36,39,41,43,46,48,50,51,57,58,59,62,63,64,66,85,89],surface_dest:50,surface_to_arrai:43,surfarrai:[16,17,26,43,49,51,52,63,84],surfdemo_show:65,surflock:0,surfobj:13,surpris:[62,63],surrog:[15,29],surround:[56,85],suspend:84,svg:31,svgalib:23,swap:[23,31,42,45],swatch:20,swig:63,switch_lay:50,swizzl:36,swsurfac:[51,84],sy:[15,44,53,62,63,67,68,69,70,71,72,73,75,76,77,78,79,80,81,86,89],symbol:33,sync:[23,25],synchron:37,synonym:25,syntax:[65,84],syntaxerror:44,synthes:37,sysfont:[28,29],sysrq:33,system:[15,16,18,19,22,23,25,26,27,28,29,32,33,36,37,39,40,44,48,49,51,52,53,59,68,70,84,85,88],system_cursor_arrow:22,system_cursor_crosshair:22,system_cursor_hand:22,system_cursor_ibeam:22,system_cursor_no:22,system_cursor_sizeal:22,system_cursor_sizen:22,system_cursor_sizenesw:22,system_cursor_sizenws:22,system_cursor_sizew:22,system_cursor_wait:22,system_cursor_waitarrow:22,systemexit:[86,89],t:[18,19,23,24,26,27,28,29,32,33,36,40,44,46,48,49,50,51,52,54,56,57,58,61,62,63,64,65,68,69,70,71,72,73,74,85,86,87,88,89],ta:61,tab:33,tabl:[23,43],tag:[40,53],taka:18,takafumi:18,take:[15,22,24,25,26,29,31,32,33,35,36,37,38,40,42,45,50,51,53,56,57,58,59,63,64,65,68,84,85,86,88,89],taken:[4,21,23,26,27,38,39,87],talk:62,tan1:21,tan2:21,tan3:21,tan4:21,tan:21,tango:29,target:[29,42,43,45,48,50,58,64,66],target_textur:48,task:[59,86],tau:24,teach:62,teal:21,technic:41,techniqu:[50,84],tell:[10,38,39,44,58,59,62,64,84,88],temp:9,temporari:[56,65],temporarili:[19,24,33,38,40,51,52],tempt:84,temptat:84,ten:54,tenni:[88,89],term:[62,64,85],termin:[1,37,44,58,68],terminolog:[39,84],terrain1:62,terrain2:62,test:[16,19,25,26,28,29,31,32,33,36,38,39,41,44,45,47,50,51,56,58,59,60,65],test_threshold_dest_surf_not_chang:56,test_util:56,testin:37,testout:37,testsprit:26,tetri:74,text:[25,26,28,29,33,46,66,68,69,70,71,84,85,87],textbitmap:32,textedit:[25,33],textinput:[25,33],textmarker_str:22,textpo:[58,66,85],textprint:32,textstr:32,textur:[30,48],textured_polygon:30,textureorimag:48,tga:[31,63],than:[16,18,19,23,24,25,26,28,29,30,31,32,33,35,36,37,38,40,44,45,47,50,51,52,54,55,56,57,58,59,60,62,63,64,65,69,70,74,85,86,87,88,89],thank:88,the_arg:12,the_dirty_rectangl:84,thei:[1,11,18,19,22,23,24,25,26,28,29,32,35,36,38,39,44,45,46,47,50,51,56,58,59,62,63,64,65,68,69,71,72,86,87,88,89],them:[16,22,24,25,26,27,31,33,34,35,38,42,44,49,50,51,52,57,58,59,62,63,65,71,84,85,86,87,88,89],themselv:[51,61,64,85],theorem:36,theori:18,therefor:[24,30,35,50,64,84,87],theta:[35,36],thi:[1,2,3,4,5,6,7,9,10,11,12,13,16,17,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,72,73,74,84,85,86,87,88,89],thick:[24,28],thickarrow_str:22,thin:58,thing:[19,25,27,40,44,57,58,59,60,61,62,63,64,65,85,87],think:[18,23,62,64,65,70,74,84,89],third:[17,18,22,30,36,62,63,65,71,85],third_surfac:56,thirteen:16,thistl:21,thistle1:21,thistle2:21,thistle3:21,thistle4:21,thorough:89,those:[16,18,22,23,24,25,26,28,29,39,42,43,50,57,61,62,64,65,84,86,87,88,89],though:[18,23,30,37,38,43,53,61,65,85,86,87,88,89],thought:84,thousand:49,thread:[10,18,25,26,27,28,30,38,39,50,53,57],three:[36,38,44,51,52,64,65,68,84,85,88],threshold:[35,42,50,56],threshold_behavior_from_search_color:56,threshold_color:56,throttl:32,through:[2,18,25,27,29,35,37,38,44,50,51,58,61,62,63,64,74,84,85,88],throughout:34,thrown:[56,89],thru:63,thu:[36,42,87],thumbnail:26,ti:40,tick:[22,24,32,39,54,58,66,69,71,72,73,77,79,80,81,89],tick_busy_loop:54,tie:[57,72],tif:31,tiff:[31,46],tile:62,time:[14,16,18,19,22,23,24,25,26,28,29,32,34,37,38,39,40,44,48,49,50,51,53,56,57,58,59,61,62,63,64,65,66,67,68,69,70,71,72,73,74,77,78,79,80,81,84,85,86,87,89],time_m:50,time_out:53,time_proc:37,timeout:25,timer:[37,54],timer_resolut:[34,54],timestamp:37,tini:[23,84],tip:[16,64,84],titl:[23,48,58,63,68],tl:89,to_surfac:[35,48],todo:64,togeth:[33,38,56,61,63,65,86],toggl:[22,47],toggle_fullscreen:23,toler:32,tom:[86,89],tomato1:21,tomato2:21,tomato3:21,tomato4:21,tomato:21,tomchanc:[86,89],tompong:[61,89],tone:37,too:[25,27,29,42,45,50,51,53,58,62,65,67,68,69,73,84,85],took:63,tool:[26,64,67,87],top:[16,23,24,26,28,29,31,35,38,39,45,50,51,62,63,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84,85,86,89],topic:16,topleft:[35,42,45,50,56,58,62,66,89],toplevel:38,topmost:50,topright:[45,89],tort:18,tortur:84,tostr:31,total:[38,43,44,53,62,68,86],touch:[25,32,84],touch_id:25,touchid:55,toward:[23,61,63],tp:[67,75],tprint:32,tr:89,traceback:[65,86],track:[16,19,50,54,57,62,64,84],trackbal:[25,47],tradition:22,trail:[53,63],train:84,trait:[68,74],transfer:[16,46,56,61,65],transform:[16,18,29,57,58,62,63,65,66],transform_test:56,translat:[9,15,26,29,33,42],transluc:84,transmiss:37,transpar:[23,24,26,28,29,31,35,43,48,51,52,56,58,62,63,84,86],transpos:42,travel:89,treat:[23,29,32,52,65],tree:57,trend:63,tri:[44,62,63,84,86],tri_left:22,tri_right:22,trial:[74,84],triangl:[24,26,30,32],trick:89,tricki:[64,65,84],trickier:65,trigger:[32,33,39,40,47,68,70],trigon:30,trigonometri:87,triplet:[23,24,30,58],truetyp:[16,28,58,63],truncat:[24,30,38,45,65],truth:64,ttf:[28,29,68,69,70,71,72,73,76,77,78,79,80,81],tune:[29,64],tupl:[9,17,19,20,22,23,24,28,29,30,31,32,35,36,37,38,39,42,44,45,47,49,50,51,52,53,62,65,84],turn:[29,37,56,58,62,64,66,84],turquois:21,turquoise1:21,turquoise2:21,turquoise3:21,turquoise4:21,turtl:68,tutori:[26,61,63,66,73,74,85,89],tweak:64,twice:[50,56,65],twitch:84,two:[1,16,18,19,22,23,24,25,26,28,29,30,32,33,35,36,37,38,42,43,45,47,49,50,53,54,56,58,62,63,64,65,70,71,72,73,84,85,87],tx:30,ty:30,type1:29,type42:29,type:[1,2,3,4,5,6,7,8,9,10,12,13,15,16,17,20,22,23,24,25,27,28,29,30,31,32,33,34,35,37,38,39,40,41,42,44,45,46,47,49,50,51,52,54,56,57,58,59,62,63,65,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84,85,87,88,89],typeerror:[24,28,43,45,50],typelist:25,typestr:17,typic:[18,23,37,51,58],u0001:28,u4:17,u:[15,17,33,41],u_margin:[73,81],uc:[15,28,29],ucs4:29,ucs_4:28,uffff:[15,28],ufo:63,ufunc:65,ugh:84,ui:26,uint32:1,uint8:[1,4],uint:65,uklinux:[86,89],ultim:74,unabl:[31,46,64],unaccept:84,unalt:[44,84],unari:20,unavail:[23,28,58,84],unchang:[15,20,23,29],uncommit:44,uncommon:58,uncompress:[31,38],undefin:[29,65],under:[16,37,39,40,63,84,86,89],underli:[29,32,37,44],underlin:[28,29,40],underline_adjust:29,underneath:65,underscor:[33,58],understand:[16,41,59,61,62,63,64,65,68,69,70,71,84,85,86,88,89],understood:71,undesir:24,unencod:44,unfamiliar:[62,84],unfil:[30,35],unfilt:56,unfortun:[53,84],unicod:[15,25,28,29,33,38,44,46,51],unicode_escap:44,unicodeencodeerror:[29,44],unicodeerror:28,unind:32,uniniti:[18,19,23,28,32,37,38,44,47],union:[45,64,84],union_ip:45,unional:45,unionall_ip:45,uniqu:[32,48,50,51,62,67,72,74],unit:[28,29,44,51],uniti:[67,75],unix:[22,23,63,84],unknown:[23,25,28,32],unless:[7,19,23,29,31,41,46,51,54,56,58,62,64,68,69,84,87,88],unlik:[38,43,51,65,88],unload:40,unlock:[24,51,84],unmap:43,unmap_rgb:[20,24,43,51,52],unmodifi:18,unnorm:67,unnot:33,unpack:[20,39],unpaus:[19,38,40],unplay:[23,63],unpredict:29,unpunch:[58,66],unreal:[63,67,75],unrealist:89,unrecogn:[28,31],unrel:23,unscal:29,unset:[29,35,51,89],unsetcolor:35,unsetsurfac:35,unsign:[1,17,20,35,38,51,65],unspecifi:29,unstructur:51,unsupport:[18,40],until:[18,23,24,25,27,32,35,37,40,47,51,54,57,62,64,66,84,85,88],untransform:29,unus:[31,38],unwieldi:84,up:[18,22,23,24,25,27,32,33,37,38,39,40,42,44,47,50,51,58,60,62,64,65,71,72,73,80,81,84,85,86,87,88],updat:[12,20,23,24,25,32,36,41,44,45,47,48,50,54,59,60,61,62,63,64,66,68,69,70,71,72,73,76,77,78,79,80,81,84,85,87,88,89],update_rect:26,upon:89,upper:[25,29,32,51,57],us:[0,1,9,10,11,14,15,16,17,19,20,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,53,54,56,58,59,61,62,63,64,65,66,67,68,71,72,85,86,87,88,89],usabl:[20,31,57],usag:[23,27,37,51,53],usb:37,use_alpha:26,use_arraytyp:[49,52],use_bitmap_strik:29,use_fastrendergroup:26,use_stat:26,use_valu:45,user:[6,16,18,23,24,25,27,32,33,37,44,46,51,53,58,61,62,63,64,65,67,72,84,85,87],userev:[25,38],userevent_dropfil:25,userrect:84,usr:[26,28,66,85,86,87],usual:[23,25,28,29,32,38,44,50,51,58,59,60,62,63,64,65,70,84,86],utf8_str:46,utf:[15,29,46],util:[63,74,84],uxxxxxxxx:[15,29],uyvy_overlai:41,v1:44,v2:[1,40],v3:17,v4l2:[18,57],v:[17,20,33,36,41],val1:1,val2:1,val:[1,65],valid:[17,23,38,39,41,51,57,64],valu:[1,4,9,10,17,18,19,20,22,23,24,25,26,28,29,30,31,32,33,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,56,58,59,62,64,65,68,69,71,72,84,85,88,89],value_to_set:44,valueerror:[17,22,24,26,29,30,33,35,36,43,46,49,51,52,57,65],vanish:84,vari:71,variabl:[17,22,23,28,37,40,44,57,58,63,64,65,69,70,71,74,89],variant:22,varieti:[25,63,70,84],variou:[1,16,22,25,26,34,84,89],ve:[24,32,58,61,62,63,64,65,84,85,87,88,89],vec:36,vector2:[24,30,35,36,45],vector3:36,vector:[24,30,35,61,89],vectorelementwiseproxi:36,veloc:[37,69],ver:44,vera:[28,29],veri:[18,23,26,37,54,58,60,62,63,64,65,70,84,87,88,89],verifi:23,vernum:44,versatil:[47,56],version:[0,12,17,23,25,26,27,29,30,31,32,38,40,43,45,47,50,56,57,58,60,61,62,63,64,84,86,89],vertic:[18,23,24,26,29,30,31,39,42,56,58,65],vflip:[18,57],vgl:23,vgrade:[26,65],via:[18,23,29,35,57],vidcaptur:44,video0:[18,57],video:[23,25,26,32,44,48,51,57,59,64,84],video_mem:[23,59],videocaptur:[18,57],videoexpos:[23,25],videoinfo:[23,59],videores:[23,25],vidinfo:[23,59],view:[1,2,16,42,51],view_p:1,violet:21,violetr:21,violetred1:21,violetred2:21,violetred3:21,violetred4:21,virtual:[23,26,37,39,45],visibl:[17,22,23,39,41,50,58,59,62,63],vision:[16,18],visit:63,vista:23,visual:[70,71,72,73],visualis:87,vline:30,volatil:51,volum:[16,38,40,63],vsync:[23,48],w:[9,25,26,30,33,35,36,42,43,45,56],wa:[10,16,19,20,22,23,24,25,26,27,31,32,33,35,37,38,39,40,42,43,44,47,54,57,58,62,63,64,65,68,70,73,84,86,88],wai:[18,23,24,25,26,28,29,31,32,33,38,39,43,44,47,48,50,53,58,60,61,62,63,64,65,71,85,87,88,89],wait:[22,23,25,27,32,37,39,54,58,84],waitarrow:22,walk:[58,66],wall:[36,57,89],want:[18,20,23,25,27,31,32,33,36,44,50,51,54,56,57,58,59,61,62,63,64,65,67,68,84,85,86,87,88,89],wargam:84,warn:[44,48,58,66],warranti:18,warrior:63,was_init:29,wasn:63,wast:[84,87],watch:[16,57,61,85],wav:[38,40,46,58,66],wave:49,wayland:[22,23],we:[22,24,26,32,56,57,58,60,62,63,64,65,67,68,69,70,71,72,73,74,84,85,86,87,88,89],weak:[13,17,84],web:[26,66],webcam:18,webp:31,websit:63,week:63,weight:[42,65],weird:33,welcom:44,well:[1,2,13,22,24,27,30,31,33,39,42,44,47,51,56,61,62,63,64,65,84,89],were:[1,11,23,25,28,33,50,53,62,63,64,69,84,86,89],west:22,what:[16,20,22,23,24,26,28,32,38,39,44,46,50,57,58,59,60,61,63,64,65,68,69,71,74,85,86,88,89],whatev:[50,57,58,61,64,84],wheat1:21,wheat2:21,wheat3:21,wheat4:21,wheat:21,wheel:39,when:[13,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,37,38,39,40,41,42,44,45,46,49,50,51,52,53,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,73,74,84,85,87,88,89],whenev:[23,39,44,65],where:[11,16,17,19,20,22,23,24,25,26,29,30,33,35,36,38,39,40,41,42,44,46,47,50,51,53,56,57,58,62,64,65,68,84,85,88,89],wherea:[23,87],wherev:65,whether:[18,23,25,26,28,29,35,38,39,45,46,48,56,61,71,72,84,85],which:[1,13,15,17,18,20,22,23,24,25,26,28,29,31,32,33,35,36,37,38,39,40,42,44,45,46,47,49,50,51,52,53,54,56,58,59,60,61,62,63,64,65,67,68,69,70,71,72,73,74,85,86,87,88,89],whiff:[58,66],whiff_sound:[58,66],whilst:23,white:[21,22,24,32,35,42,57,58,68,69,70,71,72,73,76,77,78,79,80,81,85],whitesmok:21,whitespac:61,who:[16,48,61,62,64,84,89],whole:[23,24,37,44,62,84,87],whoop:62,whose:[24,55],why:[44,63,70,74,87],wide:[24,28,29,35,44,62,63],wider:18,widget:26,width:[9,18,22,23,24,26,28,29,31,32,35,41,42,45,48,50,51,56,59,62,63,67,68,69,70,71,72,73,75,76,77,78,79,80,81,84],wiki:39,wikipedia:36,win32:37,win:[1,58,66,73],windib:23,window:[1,5,16,18,25,26,27,29,32,33,34,37,39,44,46,48,51,58,59,62,63,68,69,84,85,88],window_surfac:23,windowclos:25,windowent:25,windowev:23,windowevent_minim:23,windowexpos:25,windowfocusgain:25,windowfocuslost:25,windowhidden:25,windowhittest:25,windowleav:25,windowmaxim:25,windowminim:25,windowmov:25,windowpos_cent:48,windowpos_undefin:48,windowres:25,windowrestor:25,windowshown:25,windowsizechang:25,windowtakefocu:25,wire:32,wireless:32,wisdom:65,wise:[29,65],wish:86,within:[13,17,22,29,33,35,44,50,51,56,68,74,84],without:[18,22,23,24,29,38,42,45,48,50,51,52,58,59,62,63,64,65,69,70,72,88,89],wm:[23,59],won:[40,50,58,61,62,64,65,84,86,87,88],wonder:[57,84],word:[29,46,54,62,64,88],word_wrap:29,wordwrap:28,work:[18,19,20,22,23,24,25,26,28,29,30,31,32,34,35,37,38,42,43,46,50,51,52,53,56,57,58,59,61,62,63,64,65,68,69,85,87,89],world:[57,68,69,70,74,76,77,78,84],worri:[26,48,50,64,65,74,84],wors:[58,84],worst:61,worth:54,would:[17,22,24,25,28,35,36,38,44,50,51,56,57,58,60,61,62,63,64,65,84,85,87,88,89],wow:68,wrap:[2,5,10,17,22,30,42,51,63],wrapper:[10,84],wrestl:26,writabl:17,write:[1,10,17,26,37,51,61,63,67,84,86,87],write_short:37,write_sys_ex:37,written:[16,24,60,61,63,64,84,86,87],wrong:[38,65,84],wrote:84,www:[70,78,86,89],x00:[15,28],x10:37,x11:[23,25,37,39,44,46,48],x12:37,x13:37,x1:[24,30,45],x2:[24,30,45],x360:32,x3:[24,30],x4:84,x7d:37,x86:56,x:[2,3,5,6,7,8,9,12,13,22,23,24,25,26,28,29,30,32,33,35,36,37,39,42,44,45,46,47,48,49,50,51,52,55,58,59,62,68,69,70,72,73,76,77,78,80,81,84,85,87,89],x_offset:35,x_scale:48,xbm:22,xbox:[32,47],xf0:37,xf7:37,xfade:65,xor:22,xormask:[22,39],xpm:31,xx:22,xxx:22,xxxx:22,xxxx_test:53,xxxxx:22,xy:[36,89],y1:[24,30,45],y2:[24,30,45],y3:[24,30],y:[9,20,22,23,24,25,28,29,30,32,33,35,36,39,41,42,44,45,47,48,49,50,51,52,55,58,62,66,68,69,70,72,73,77,78,80,81,84,85,87,88,89],y_offset:35,y_scale:48,ye:[65,67,85],yeah:71,year:[63,74,84],yellow1:21,yellow2:21,yellow3:21,yellow4:21,yellow:21,yellowgreen:21,yet:[29,48,65,84,88],you:[11,16,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,36,37,38,39,40,41,42,44,46,50,51,54,56,57,58,59,60,61,63,64,65,67,68,71,72,74,85,86,87,88,89],your:[16,18,19,22,23,25,26,27,28,30,31,33,37,38,44,46,54,56,57,58,59,60,61,63,65,67,70,85,86,87,88,89],yourself:[28,50,58,63,65,86,87],yup:84,yuv:[18,41,57],yuy2_overlai:41,yv12_overlai:41,yvyu_overlai:41,z:[33,36,87,89],zero:[19,20,24,28,29,36,37,38,59,64,65,89],zine:63,zip:84,zoom:26},titles:["pygame C API","High level API exported by pygame.base","Class BufferProxy API exported by pgyame.bufferproxy","API exported by pygame.cdrom","Class Color API exported by pygame.color","API exported by pygame.display","API exported by pygame.event","API exported by pygame._freetype","API exported by pygame.mixer","Class Rect API exported by pygame.rect","API exported by pygame.rwobject","Slots and c_api - Making functions and data available from other modules","Class Surface API exported by pygame.surface","API exported by pygame.surflock","API exported by pygame.version","File Path Function Arguments","Pygame Front Page","pygame.BufferProxy","pygame.camera","pygame.cdrom","pygame.Color","Named Colors","pygame.cursors","pygame.display","pygame.draw","pygame.event","pygame.examples","pygame.fastevent","pygame.font","pygame.freetype","pygame.gfxdraw","pygame.image","pygame.joystick","pygame.key","pygame.locals","pygame.mask","pygame.math","pygame.midi","pygame.mixer","pygame.mouse","pygame.mixer.music","pygame.Overlay","pygame.PixelArray","pygame.pixelcopy","pygame","pygame.Rect","pygame.scrap","pygame._sdl2.controller","pygame.sdl2_video","pygame.sndarray","pygame.sprite","pygame.Surface","pygame.surfarray","pygame.tests","pygame.time","pygame._sdl2.touch","pygame.transform","Pygame Tutorials - Camera Module Introduction","Pygame Tutorials - Line By Line Chimp Example","Pygame Tutorials - Setting Display Modes","Pygame Tutorials - Import and Initialize","Making Games With Pygame","Pygame Tutorials - Help! How Do I Move An Image?","Pygame Intro","Pygame Tutorials - Sprite Module Introduction","Pygame Tutorials - Surfarray Introduction","pygame/examples/chimp.py","Author: Youngwook Kim (Korean)","Author: Youngwook Kim (Korean)","Author: Youngwook Kim (Korean)","Author: Youngwook Kim (Korean)","Author: Youngwook Kim (Korean)","Author: Youngwook Kim (Korean)","Author: Youngwook Kim (Korean)","Author: Youngwook Kim (Korean)","Author: Youngwook Kim (Korean)","Author: Youngwook Kim (Korean)","Author: Youngwook Kim (Korean)","Author: Youngwook Kim (Korean)","Author: Youngwook Kim (Korean)","Author: Youngwook Kim (Korean)","Author: Youngwook Kim (Korean)","Author: Youngwook Kim (Korean)","\ud55c\uad6d\uc5b4 \ud29c\ud1a0\ub9ac\uc5bc","A Newbie Guide to pygame","Revision: Pygame fundamentals","Kicking things off","Game object classes","User-controllable objects","Putting it all together"],titleterms:{"1":[61,85,86,87,88,89],"2":[62,85,86,87,89],"3":[85,86,88,89],"4":[85,87],"5":[85,88],"6":89,"\uadf8\ub9ac\uace0":[79,80,81],"\uae30\ubc18\uacfc":76,"\uae30\ubc18\uc73c\ub85c\uc758":76,"\uae30\ubcf8":76,"\uae30\ucd08":[76,77,78],"\ub354":81,"\ubc84\ud2bc":80,"\uc0c8\ub85c\uc6b4":78,"\uc2ec\ud654":[79,80],"\uc5d0\ud544\ub85c\uadf8":82,"\uc65c":75,"\uc6c0\uc9c1\uc774\uae30":77,"\uc704\ud55c":77,"\uc774\ubca4\ud2b8":[76,78],"\uc785\ub825":78,"\uc785\ub825\uc740":78,"\uc785\ubb38":76,"\uc870\uac74":77,"\uc870\uae08":81,"\ucc98\ub9ac":[77,79],"\ucd9c\ub825":[76,80],"\ud29c\ud1a0\ub9ac\uc5bc":83,"\ud30c\uc774\uac8c\uc784":75,"\ud504\ub864\ub85c\uadf8":75,"\ud558\ud544":75,"\ud55c\uad6d\uc5b4":83,"\ud568\uc218\ud654":79,"\ud615\uc2dd\uacfc":76,"\ud654\uba74\uc774":77,"class":[2,4,9,12,36,50,58,64,87,88],"do":[62,84],"export":[1,2,3,4,5,6,7,8,9,10,12,13,14,17],"function":[11,15,59,62,65,71,86],"import":[57,58,60,65],"new":70,"while":58,A:[61,62,84,87,88],AND:63,By:58,Into:68,It:62,NO:84,On:[58,62],The:[58,62,64,85,86,89],There:84,To:62,With:61,_freetyp:7,_sdl2:[47,55],access:[42,49,52],advanc:[64,65,71,72],all:[58,62,89],alpha:[73,84],an:[17,62],anim:[69,84],api:[0,1,2,3,4,5,6,7,8,9,10,12,13,14],ar:[62,84],argument:15,arrai:[17,43,52],audio:[19,40],author:[67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82],avail:11,back:62,background:[58,62],ball:[87,89],base:1,basic:[50,57,59,68,69,70,85],bat:[88,89],blit:[62,85],bother:84,buffer:17,bufferproxi:2,bufferproxypygam:17,button:72,c:[0,1,2,3,4,5,6,7,8,9,10,12,13],c_api:11,camera:[18,57],camerapygam:18,captur:57,cdrom:[3,19],cdrompygam:19,center:58,chang:62,chimp:[58,66],clipboard:46,close:63,code:61,collis:[64,84],color:[4,20,21],colorkei:84,colorpygam:20,colorspac:57,com:[67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82],comfort:84,common:64,comput:[29,57],connect:57,constant:34,contact:[67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82],contain:44,content:61,control:[19,23,40,47,57,88],controllerpygam:47,convert:84,coordin:[45,62],copi:43,creat:[58,62],cursor:22,cursorspygam:22,da:85,data:[11,49,52],decid:59,definit:62,detect:[64,84],direct:42,dirti:84,displai:[5,23,58,59],displaypygam:23,distract:84,divers:[87,88],document:16,don:84,draw:[24,30,58],drawpygam:24,driven:68,entir:58,epilog:74,event:[6,25,27,58,68,70,84,85,88],eventpygam:25,everyth:58,exampl:[26,58,59,65,66],examplesmodul:26,extend:64,fasteventpygam:27,file:15,finish:[58,89],first:[62,86],font:[28,29],fontpygam:28,freetypeenhanc:29,friend:84,from:[11,62],front:16,fundament:85,game:[50,58,61,63,85,87],gamepad:32,gener:43,get:84,gfxdrawpygam:30,gmail:[67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82],go:62,graduat:65,graphic:41,group:64,gui:[68,76],guid:84,handl:[58,62,86],hardwar:84,help:62,here:62,hero:62,high:1,histori:[63,64],hit:89,how:[59,62],i:62,imag:[31,35,51,57,62],imagepygam:31,inform:44,init:[57,60],initi:[58,60],input:[37,55,58,62,70],interact:[25,27,32,37],interfac:52,intro:63,introduct:[57,58,59,61,63,64,65],issu:84,joystick:32,joystickpygam:32,just:62,keyboard:33,keypygam:33,kick:86,kim:[67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82],know:84,korean:[67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82],lesson:64,let:[62,89],level:[1,44],line:[58,86],list:[57,62],live:57,load:[28,29,38,58,86],localspygam:34,lock:65,loop:[58,85],main:58,make:[11,61,62],manag:84,mani:64,map:62,mask:[35,57],maskpygam:35,mathpygam:36,midi:37,midipygam:37,mix:64,mixer:[8,40],mixerpygam:38,mode:59,modul:[11,18,19,22,23,24,25,27,28,29,30,31,32,33,35,36,37,38,39,40,43,44,46,47,49,50,52,54,55,56,57,58,63,64,86],monitor:54,more:[65,84],mous:39,mousepygam:39,move:62,movement:62,multipl:62,musicpygam:40,mysteri:62,name:21,need:84,newbi:84,next:62,note:61,numer:65,numpi:65,object:[17,20,41,42,45,50,51,58,85,87,88],off:86,other:[11,65],output:[37,68,72],over:58,overlai:41,overlaypygam:41,overview:63,own:[62,64],packag:[44,53],page:16,part:84,path:15,perfect:84,pgyam:2,physic:87,pixel:[42,43,52,62,84],pixelarraypygam:42,pixelcopypygam:43,plai:38,plu:73,prepar:58,problem:64,process:[69,71],product:89,program:26,prolog:67,protocol:17,put:[58,62,89],py:[14,66],pygam:[0,1,3,4,5,6,7,8,9,10,12,13,14,16,17,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,84,85,88],pygameth:44,python:[63,65,84],pythoni:84,queue:[25,27],quit:60,re:84,realli:84,recogn:84,rect:[9,84],rectangular:45,rectpygam:45,refer:16,render:[28,29,64],repres:51,represent:20,resourc:[22,58,86],revis:85,rule:84,rumia0601:[67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82],rwobject:10,s:62,sampl:49,scene:58,scrappygam:46,screen:[23,62],sdl2_video:48,set:[59,69],setup:58,shape:[24,30],side:[84,89],simpl:[87,88],singl:57,six:84,slot:11,smooth:62,sndarraypygam:49,so:62,some:62,sound:[38,49],sprite:[58,64,87],spritepygam:50,src_c:[1,2,3,4,5,6,7,8,9,10,12,13],src_py:14,step:62,store:45,stream:[40,57],style:61,subsystem:84,suit:53,support:46,surfac:[12,17,42,52,56,65,84],surfacepygam:51,surfarrai:65,surfarraypygam:52,surflock:13,t:84,ta:85,tabl:61,take:62,tast:63,templat:68,test:53,testspygam:53,text:58,than:84,thei:84,them:64,thing:[84,86],threshold:57,through:17,time:54,timepygam:54,togeth:[62,64,89],top:44,touch:55,touchpygam:55,trackbal:32,transfer:31,transform:56,transformpygam:56,transpar:65,troubl:84,tutori:[16,57,58,59,60,62,64,65],type:64,unit:53,updat:58,us:[18,52,57,84],user:88,vector:[36,87],version:[14,44],versionsmal:44,video:41,vision:57,vs:84,wai:84,what:[62,84],which:84,why:67,window:23,work:[33,39,47,55,84],worth:84,you:[62,84],youngwook:[67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82],your:[62,64,84]}}) \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/tut/CameraIntro.html b/venv/Lib/site-packages/pygame/docs/generated/tut/CameraIntro.html new file mode 100644 index 0000000..400dc61 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/tut/CameraIntro.html @@ -0,0 +1,378 @@ + + + + + + + + + Pygame Tutorials - Camera Module Introduction — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

Camera Module Introduction

+
+
Author
+

by Nirav Patel

+
+
Contact
+

nrp@eclecti.cc

+
+
+

Pygame 1.9 comes with support for interfacing cameras, allowing you to capture +still images, watch live streams, and do some simple computer vision. This +tutorial will cover all of those use cases, providing code samples you can base +your app or game on. You can refer to the reference documentation +for the full API.

+
+

Note

+

As of Pygame 1.9, the camera module offers native support for cameras +that use v4l2 on Linux. There is support for other platforms via Videocapture +or OpenCV, but this guide will focus on the native module. Most of the code +will be valid for other platforms, but certain things like controls will not +work. The module is also marked as EXPERIMENTAL, meaning the API could +change in subsequent versions.

+
+
+

Import and Init

+
import pygame
+import pygame.camera
+from pygame.locals import *
+
+pygame.init()
+pygame.camera.init()
+
+
+

As the camera module is optional, it needs to be imported and initialized +manually as shown above.

+
+
+

Capturing a Single Image

+

Now we will go over the simplest case of opening a camera and capturing a frame +as a surface. In the below example, we assume that there is a camera at +/dev/video0 on the computer, and initialize it with a size of 640 by 480. +The surface called image is whatever the camera was seeing when get_image() was +called.

+
cam = pygame.camera.Camera("/dev/video0",(640,480))
+cam.start()
+image = cam.get_image()
+
+
+
+

Listing Connected Cameras

+

You may be wondering, what if we don't know the exact path of the camera? +We can ask the module to provide a list of cameras attached to the +computer and initialize the first camera in the list.

+
camlist = pygame.camera.list_cameras()
+if camlist:
+    cam = pygame.camera.Camera(camlist[0],(640,480))
+
+
+
+
+

Using Camera Controls

+

Most cameras support controls like flipping the image and changing brightness. +set_controls() and get_controls() can be used at any point after using start().

+
cam.set_controls(hflip = True, vflip = False)
+print camera.get_controls()
+
+
+
+
+
+

Capturing a Live Stream

+

The rest of this tutorial will be based around capturing a live stream of +images. For this, we will be using the class below. As described, it will +simply blit a constant stream of camera frames to the screen, effectively +showing live video. It is basically what you would expect, looping get_image(), +blitting to the display surface, and flipping it. For performance reasons, +we will be supplying the camera with the same surface to use each time.

+
class Capture(object):
+    def __init__(self):
+        self.size = (640,480)
+        # create a display surface. standard pygame stuff
+        self.display = pygame.display.set_mode(self.size, 0)
+
+        # this is the same as what we saw before
+        self.clist = pygame.camera.list_cameras()
+        if not self.clist:
+            raise ValueError("Sorry, no cameras detected.")
+        self.cam = pygame.camera.Camera(self.clist[0], self.size)
+        self.cam.start()
+
+        # create a surface to capture to.  for performance purposes
+        # bit depth is the same as that of the display surface.
+        self.snapshot = pygame.surface.Surface(self.size, 0, self.display)
+
+    def get_and_flip(self):
+        # if you don't want to tie the framerate to the camera, you can check
+        # if the camera has an image ready.  note that while this works
+        # on most cameras, some will never return true.
+        if self.cam.query_image():
+            self.snapshot = self.cam.get_image(self.snapshot)
+
+        # blit it to the display surface.  simple!
+        self.display.blit(self.snapshot, (0,0))
+        pygame.display.flip()
+
+    def main(self):
+        going = True
+        while going:
+            events = pygame.event.get()
+            for e in events:
+                if e.type == QUIT or (e.type == KEYDOWN and e.key == K_ESCAPE):
+                    # close the camera safely
+                    self.cam.stop()
+                    going = False
+
+            self.get_and_flip()
+
+
+

Since get_image() is a blocking call that could take quite a bit of time on a +slow camera, this example uses query_image() to see if the camera is ready. +This allows you to separate the framerate of your game from that of your camera. +It is also possible to have the camera capturing images in a separate thread, +for approximately the same performance gain, if you find that your camera does +not support the query_image() function correctly.

+
+
+

Basic Computer Vision

+

By using the camera, transform, and mask modules, pygame can do some basic +computer vision.

+
+

Colorspaces

+

When initializing a camera, colorspace is an optional parameter, with 'RGB', +'YUV', and 'HSV' as the possible choices. YUV and HSV are both generally more +useful for computer vision than RGB, and allow you to more easily threshold by +color, something we will look at later in the tutorial.

+
self.cam = pygame.camera.Camera(self.clist[0], self.size, "RGB")
+
+
+../_images/camera_rgb.jpg +
self.cam = pygame.camera.Camera(self.clist[0], self.size, "YUV")
+
+
+../_images/camera_yuv.jpg +
self.cam = pygame.camera.Camera(self.clist[0], self.size, "HSV")
+
+
+../_images/camera_hsv.jpg +
+
+

Thresholding

+

Using the threshold() function from the transform module, one can do simple +green screen like effects, or isolate specifically colored objects in a scene. +In the below example, we threshold out just the green tree and make the rest +of the image black. Check the reference documentation for details on the +threshold function.

+
self.thresholded = pygame.surface.Surface(self.size, 0, self.display)
+self.snapshot = self.cam.get_image(self.snapshot)
+pygame.transform.threshold(self.thresholded,self.snapshot,(0,255,0),(90,170,170),(0,0,0),2)
+
+
+../_images/camera_thresholded.jpg +

Of course, this is only useful if you already know the exact color of the object +you are looking for. To get around this and make thresholding usable in the +real world, we need to add a calibration stage where we identify the color of an +object and use it to threshold against. We will be using the average_color() +function of the transform module to do this. Below is an example calibration +function that you could loop until an event like a key press, and an image of +what it would look like. The color inside the box will be the one that is +used for the threshold. Note that we are using the HSV colorspace in the below +images.

+
def calibrate(self):
+    # capture the image
+    self.snapshot = self.cam.get_image(self.snapshot)
+    # blit it to the display surface
+    self.display.blit(self.snapshot, (0,0))
+    # make a rect in the middle of the screen
+    crect = pygame.draw.rect(self.display, (255,0,0), (145,105,30,30), 4)
+    # get the average color of the area inside the rect
+    self.ccolor = pygame.transform.average_color(self.snapshot, crect)
+    # fill the upper left corner with that color
+    self.display.fill(self.ccolor, (0,0,50,50))
+    pygame.display.flip()
+
+
+../_images/camera_average.jpg +
pygame.transform.threshold(self.thresholded,self.snapshot,self.ccolor,(30,30,30),(0,0,0),2)
+
+
+../_images/camera_thresh.jpg +

You can use the same idea to do a simple green screen/blue screen, by first +getting a background image and then thresholding against it. The below example +just has the camera pointed at a blank white wall in HSV colorspace.

+
def calibrate(self):
+    # capture a bunch of background images
+    bg = []
+    for i in range(0,5):
+      bg.append(self.cam.get_image(self.background))
+    # average them down to one to get rid of some noise
+    pygame.transform.average_surfaces(bg,self.background)
+    # blit it to the display surface
+    self.display.blit(self.background, (0,0))
+    pygame.display.flip()
+
+
+../_images/camera_background.jpg +
pygame.transform.threshold(self.thresholded,self.snapshot,(0,255,0),(30,30,30),(0,0,0),1,self.background)
+
+
+../_images/camera_green.jpg +
+
+

Using the Mask Module

+

The stuff above is great if you just want to display images, but with the +mask module, you can also use a camera as an +input device for a game. For example, going back to the example of +thresholding out a specific object, we can find the position of that object and +use it to control an on screen object.

+
def get_and_flip(self):
+    self.snapshot = self.cam.get_image(self.snapshot)
+    # threshold against the color we got before
+    mask = pygame.mask.from_threshold(self.snapshot, self.ccolor, (30, 30, 30))
+    self.display.blit(self.snapshot,(0,0))
+    # keep only the largest blob of that color
+    connected = mask.connected_component()
+    # make sure the blob is big enough that it isn't just noise
+    if mask.count() > 100:
+        # find the center of the blob
+        coord = mask.centroid()
+        # draw a circle with size variable on the size of the blob
+        pygame.draw.circle(self.display, (0,255,0), coord, max(min(50,mask.count()/400),5))
+    pygame.display.flip()
+
+
+../_images/camera_mask.jpg +

This is just the most basic example. You can track multiple different colored +blobs, find the outlines of objects, have collision detection between real life +and in game objects, get the angle of an object to allow for even finer control, +and more. Have fun!

+
+
+
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/tut/ChimpLineByLine.html b/venv/Lib/site-packages/pygame/docs/generated/tut/ChimpLineByLine.html new file mode 100644 index 0000000..6f1e21f --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/tut/ChimpLineByLine.html @@ -0,0 +1,597 @@ + + + + + + + + + Pygame Tutorials - Line By Line Chimp Example — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

Line By Line Chimp

+
+
Author
+

Pete Shinners

+
+
Contact
+

pete@shinners.org

+
+
+
+
+
+

Introduction

+

In the pygame examples there is a simple example named "chimp". +This example simulates a punchable monkey moving around the screen with +promises of riches and reward. The example itself is very simple, and a +bit thin on error-checking code. This example program demonstrates many of +pygame's abilities, like creating a window, loading images and sounds, +rendering text, and basic event and mouse handling.

+

The program and images can be found inside the standard source distribution +of pygame. You can run it by running python -m pygame.examples.chimp in +your terminal.

+

This tutorial will go through the code block by block. Explaining how +the code works. There will also be mention of how the code could be improved +and what error checking could help out.

+

This is an excellent tutorial for people getting their first look at +the pygame code. Once pygame is fully installed, you can find +and run the chimp demo for yourself in the examples directory.

+
+

(no, this is not a banner ad, it's the screenshot)

+chimp game banner +

Full Source

+
+
+
+

Import Modules

+

This is the code that imports all the needed modules into your program. +It also checks for the availability of some of the optional pygame modules.

+
# Import Modules
+import os
+import pygame as pg
+
+if not pg.font:
+    print("Warning, fonts disabled")
+if not pg.mixer:
+    print("Warning, sound disabled")
+
+main_dir = os.path.split(os.path.abspath(__file__))[0]
+data_dir = os.path.join(main_dir, "data")
+
+
+

First, we import the standard "os" python module. This allow +us to do things like create platform independent file paths.

+

In the next line, we import the pygame package. In our case, we import +pygame as pg, so that all of the functionality of pygame is able to +be referenced from the namespace pg.

+

Some pygame modules are optional, and if they aren't found, +they evaluate to False. Because of that, we decide to print +a nice warning message if the font or +mixer modules in pygame are not available. +(Although they will only be unavailable in very uncommon situations).

+

Lastly, we prepare two paths for the rest of the code to use. +main_dir uses the os.path module and the __file__ variable provided +by Python to locate the game's python file, and extract the folder from +that path. It then prepares the variable data_dir to tell the +loading functions exactly where to look.

+
+
+

Loading Resources

+

Here we have two functions we can use to load images and sounds. We will +look at each function individually in this section.

+
def load_image(name, colorkey=None, scale=1):
+    fullname = os.path.join(data_dir, name)
+    image = pg.image.load(fullname)
+
+    size = image.get_size()
+    size = (size[0] * scale, size[1] * scale)
+    image = pg.transform.scale(image, size)
+
+    image = image.convert()
+    if colorkey is not None:
+        if colorkey == -1:
+            colorkey = image.get_at((0, 0))
+        image.set_colorkey(colorkey, pg.RLEACCEL)
+    return image, image.get_rect()
+
+
+

This function takes the name of an image to load. It also optionally +takes an argument it can use to set a colorkey for the image, and an argument +to scale the image. A colorkey is used in graphics to represent a color of the +image that is transparent.

+

The first thing this function does is create a full pathname to the file. +In this example all the resources are in a "data" subdirectory. By using +the os.path.join function, a pathname will be created that works for whatever +platform the game is running on.

+

Next we load the image using the pygame.image.load()load new image from a file (or file-like object) function. +After the image is loaded, we make an important +call to the convert() function. This makes a new copy of a Surface and converts +its color format and depth to match the display. This means blitting the +image to the screen will happen as quickly as possible.

+

We then scale the image, using the pygame.transform.scale()resize to new resolution function. +This function takes a Surface and the size it should be scaled to. To scale +by a scalar, we can get the size and scale the x and y by the scalar.

+

Last, we set the colorkey for the image. If the user supplied an argument +for the colorkey argument we use that value as the colorkey for the image. +This would usually just be a color RGB value, like (255, 255, 255) for +white. You can also pass a value of -1 as the colorkey. In this case the +function will lookup the color at the topleft pixel of the image, and use +that color for the colorkey.

+
def load_sound(name):
+    class NoneSound:
+        def play(self):
+            pass
+
+    if not pg.mixer or not pg.mixer.get_init():
+        return NoneSound()
+
+    fullname = os.path.join(data_dir, name)
+    sound = pg.mixer.Sound(fullname)
+
+    return sound
+
+
+

Next is the function to load a sound file. The first thing this function +does is check to see if the pygame.mixerpygame module for loading and playing sounds module was imported correctly. +If not, it returns a small class instance that has a dummy play method. +This will act enough like a normal Sound object for this game to run without +any extra error checking.

+

This function is similar to the image loading function, but handles some +different problems. First we create a full path to the sound image, and +load the sound file. Then we simply return the loaded Sound object.

+
+
+

Game Object Classes

+

Here we create two classes to represent the objects in our game. Almost +all the logic for the game goes into these two classes. We will look over +them one at a time here.

+
class Fist(pg.sprite.Sprite):
+    """moves a clenched fist on the screen, following the mouse"""
+
+    def __init__(self):
+        pg.sprite.Sprite.__init__(self)  # call Sprite initializer
+        self.image, self.rect = load_image("fist.png", -1)
+        self.fist_offset = (-235, -80)
+        self.punching = False
+
+    def update(self):
+        """move the fist based on the mouse position"""
+        pos = pg.mouse.get_pos()
+        self.rect.topleft = pos
+        self.rect.move_ip(self.fist_offset)
+        if self.punching:
+            self.rect.move_ip(15, 25)
+
+    def punch(self, target):
+        """returns true if the fist collides with the target"""
+        if not self.punching:
+            self.punching = True
+            hitbox = self.rect.inflate(-5, -5)
+            return hitbox.colliderect(target.rect)
+
+    def unpunch(self):
+        """called to pull the fist back"""
+        self.punching = False
+
+
+

Here we create a class to represent the players fist. It is derived from +the Sprite class included in the pygame.spritepygame module with basic game object classes module. The __init__ function +is called when new instances of this class are created. The first thing +we do is be sure to call the __init__ function for our base class. This +allows the Sprite's __init__ function to prepare our object for use as a +sprite. This game uses one of the sprite drawing Group classes. These classes +can draw sprites that have an "image" and "rect" attribute. By simply changing +these two attributes, the renderer will draw the current image at the current +position.

+

All sprites have an update() method. This function is typically called +once per frame. It is where you should put code that moves and updates +the variables for the sprite. The update() method for the fist moves the +fist to the location of the mouse pointer. It also offsets the fist position +slightly if the fist is in the "punching" state.

+

The following two functions punch() and unpunch() change the punching +state for the fist. The punch() method also returns a true value if the fist +is colliding with the given target sprite.

+
class Chimp(pg.sprite.Sprite):
+    """moves a monkey critter across the screen. it can spin the
+    monkey when it is punched."""
+
+    def __init__(self):
+        pg.sprite.Sprite.__init__(self)  # call Sprite intializer
+        self.image, self.rect = load_image("chimp.png", -1, 4)
+        screen = pg.display.get_surface()
+        self.area = screen.get_rect()
+        self.rect.topleft = 10, 90
+        self.move = 18
+        self.dizzy = False
+
+    def update(self):
+        """walk or spin, depending on the monkeys state"""
+        if self.dizzy:
+            self._spin()
+        else:
+            self._walk()
+
+    def _walk(self):
+        """move the monkey across the screen, and turn at the ends"""
+        newpos = self.rect.move((self.move, 0))
+        if not self.area.contains(newpos):
+            if self.rect.left < self.area.left or self.rect.right > self.area.right:
+                self.move = -self.move
+                newpos = self.rect.move((self.move, 0))
+                self.image = pg.transform.flip(self.image, True, False)
+        self.rect = newpos
+
+    def _spin(self):
+        """spin the monkey image"""
+        center = self.rect.center
+        self.dizzy = self.dizzy + 12
+        if self.dizzy >= 360:
+            self.dizzy = False
+            self.image = self.original
+        else:
+            rotate = pg.transform.rotate
+            self.image = rotate(self.original, self.dizzy)
+        self.rect = self.image.get_rect(center=center)
+
+    def punched(self):
+        """this will cause the monkey to start spinning"""
+        if not self.dizzy:
+            self.dizzy = True
+            self.original = self.image
+
+
+

The Chimp class is doing a little more work than the fist, but nothing +more complex. This class will move the chimp back and forth across the +screen. When the monkey is punched, he will spin around to exciting effect. +This class is also derived from the base Sprite +class, and is initialized the same as the fist. While initializing, the class +also sets the attribute "area" to be the size of the display screen.

+

The update function for the chimp simply looks at the current "dizzy" +state, which is true when the monkey is spinning from a punch. It calls either +the _spin or _walk method. These functions are prefixed with an underscore. +This is just a standard python idiom which suggests these methods should +only be used by the Chimp class. We could go so far as to give them a double +underscore, which would tell python to really try to make them private +methods, but we don't need such protection. :)

+

The _walk method creates a new position for the monkey by moving the current +rect by a given offset. If this new position crosses outside the display +area of the screen, it reverses the movement offset. It also mirrors the +image using the pygame.transform.flip()flip vertically and horizontally function. This is a crude effect +that makes the monkey look like he's turning the direction he is moving.

+

The _spin method is called when the monkey is currently "dizzy". The dizzy +attribute is used to store the current amount of rotation. When the monkey +has rotated all the way around (360 degrees) it resets the monkey image +back to the original, non-rotated version. Before calling the +pygame.transform.rotate()rotate an image function, you'll see the code makes a local +reference to the function simply named "rotate". There is no need to do that +for this example, it is just done here to keep the following line's length a +little shorter. Note that when calling the rotate function, we are always +rotating from the original monkey image. When rotating, there is a slight loss +of quality. Repeatedly rotating the same image and the quality would get worse +each time. Also, when rotating an image, the size of the image will actually +change. This is because the corners of the image will be rotated out, making +the image bigger. We make sure the center of the new image matches the center +of the old image, so it rotates without moving.

+

The last method is punched() which tells the sprite to enter its dizzy +state. This will cause the image to start spinning. It also makes a copy +of the current image named "original".

+
+
+

Initialize Everything

+

Before we can do much with pygame, we need to make sure its modules +are initialized. In this case we will also open a simple graphics window. +Now we are in the main() function of the program, which actually runs everything.

+
pg.init()
+screen = pg.display.set_mode((1280, 480), pg.SCALED)
+pg.display.set_caption("Monkey Fever")
+pg.mouse.set_visible(False)
+
+
+

The first line to initialize pygame takes care of a bit of +work for us. It checks through the imported pygame modules and attempts +to initialize each one of them. It is possible to go back and check if modules +failed to initialize, but we won't bother here. It is also possible to +take a lot more control and initialize each specific module by hand. That +type of control is generally not needed, but is available if you desire.

+

Next we set up the display graphics mode. Note that the pygame.displaypygame module to control the display window and screen +module is used to control all the display settings. In this case we are +asking for a 1280 by 480 window, with the SCALED display flag. +This automatically scales up the window for displays much larger than the +window.

+

Last we set the window title and turn off the mouse cursor for our +window. Very basic to do, and now we have a small black window ready to +do our bidding. Usually the cursor defaults to visible, so there is no need +to really set the state unless we want to hide it.

+
+
+

Create The Background

+

Our program is going to have text message in the background. It would +be nice for us to create a single surface to represent the background and +repeatedly use that. The first step is to create the surface.

+
background = pg.Surface(screen.get_size())
+background = background.convert()
+background.fill((170, 238, 187))
+
+
+

This creates a new surface for us that is the same size as the display +window. Note the extra call to convert() after creating the Surface. The +convert with no arguments will make sure our background is the same format +as the display window, which will give us the fastest results.

+

We also fill the entire background with a certain green color. The fill() +function usually takes an RGB triplet as arguments, but supports many +input formats. See the pygame.Colorpygame object for color representations for all the color formats.

+
+
+

Put Text On The Background, Centered

+

Now that we have a background surface, lets get the text rendered to it. We +only do this if we see the pygame.fontpygame module for loading and rendering fonts module has imported properly. +If not, we just skip this section.

+
if pg.font:
+    font = pg.font.Font(None, 64)
+    text = font.render("Pummel The Chimp, And Win $$$", True, (10, 10, 10))
+    textpos = text.get_rect(centerx=background.get_width() / 2, y=10)
+    background.blit(text, textpos)
+
+
+

As you see, there are a couple steps to getting this done. First we +must create the font object and render it into a new surface. We then find +the center of that new surface and blit (paste) it onto the background.

+

The font is created with the font module's Font() constructor. Usually +you will pass the name of a TrueType font file to this function, but we +can also pass None, which will use a default font. The Font constructor +also needs to know the size of font we want to create.

+

We then render that font into a new surface. The render function creates +a new surface that is the appropriate size for our text. In this case +we are also telling render to create antialiased text (for a nice smooth +look) and to use a dark grey color.

+

Next we need to find the centered position of the text on our display. +We create a "Rect" object from the text dimensions, which allows us to +easily assign it to the screen center.

+

Finally we blit (blit is like a copy or paste) the text onto the background +image.

+
+
+

Display The Background While Setup Finishes

+

We still have a black window on the screen. Lets show our background +while we wait for the other resources to load.

+
screen.blit(background, (0, 0))
+pygame.display.flip()
+
+
+

This will blit our entire background onto the display window. The +blit is self explanatory, but what about this flip routine?

+

In pygame, changes to the display surface are not immediately visible. +Normally, a display must be updated in areas that have changed for them +to be visible to the user. In this case the flip() function works nicely +because it simply handles the entire window area.

+
+
+

Prepare Game Object

+

Here we create all the objects that the game is going to need.

+
whiff_sound = load_sound("whiff.wav")
+punch_sound = load_sound("punch.wav")
+chimp = Chimp()
+fist = Fist()
+allsprites = pg.sprite.RenderPlain((chimp, fist))
+clock = pg.time.Clock()
+
+
+

First we load two sound effects using the load_sound function we defined +above. Then we create an instance of each of our sprite classes. And lastly +we create a sprite Group which will contain all +our sprites.

+

We actually use a special sprite group named RenderPlain. This sprite group can draw all the sprites it +contains to the screen. It is called RenderPlain because there are actually +more advanced Render groups. But for our game, we just need simple drawing. We +create the group named "allsprites" by passing a list with all the sprites that +should belong in the group. We could later on add or remove sprites from this +group, but in this game we won't need to.

+

The clock object we create will be used to help control our game's framerate. +we will use it in the main loop of our game to make sure it doesn't run too fast.

+
+
+

Main Loop

+

Nothing much here, just an infinite loop.

+
going = True
+while going:
+    clock.tick(60)
+
+
+

All games run in some sort of loop. The usual order of things is to +check on the state of the computer and user input, move and update the +state of all the objects, and then draw them to the screen. You'll see +that this example is no different.

+

We also make a call to our clock object, which will make sure our game +doesn't run faster than 60 frames per second.

+
+
+

Handle All Input Events

+

This is an extremely simple case of working the event queue.

+
for event in pg.event.get():
+    if event.type == pg.QUIT:
+        going = False
+    elif event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE:
+        going = False
+    elif event.type == pg.MOUSEBUTTONDOWN:
+        if fist.punch(chimp):
+            punch_sound.play()  # punch
+            chimp.punched()
+        else:
+            whiff_sound.play()  # miss
+    elif event.type == pg.MOUSEBUTTONUP:
+        fist.unpunch()
+
+
+

First we get all the available Events from pygame and loop through each +of them. The first two tests see if the user has quit our game, or pressed +the escape key. In these cases we just set going to False, allowing +us out of the infinite loop.

+

Next we just check to see if the mouse button was pressed or released. +If the button was pressed, we ask the fist object if it has collided with +the chimp. We play the appropriate sound effect, and if the monkey was hit, +we tell him to start spinning (by calling his punched() method).

+
+
+

Update the Sprites

+
allsprites.update()
+
+
+

Sprite groups have an update() method, which simply calls the update method +for all the sprites it contains. Each of the objects will move around, depending +on which state they are in. This is where the chimp will move one step side +to side, or spin a little farther if he was recently punched.

+
+
+

Draw The Entire Scene

+

Now that all the objects are in the right place, time to draw them.

+
screen.blit(background, (0, 0))
+allsprites.draw(screen)
+pygame.display.flip()
+
+
+

The first blit call will draw the background onto the entire screen. This +erases everything we saw from the previous frame (slightly inefficient, but +good enough for this game). Next we call the draw() method of the sprite +container. Since this sprite container is really an instance of the "DrawPlain" +sprite group, it knows how to draw our sprites. Lastly, we flip() the contents +of pygame's software double buffer to the screen. This makes everything we've +drawn visible all at once.

+
+
+

Game Over

+

User has quit, time to clean up.

+
pg.quit()
+
+
+

Cleaning up the running game in pygame is extremely simple. +Since all variables are automatically destructed, we don't really have to do +anything, but calling pg.quit() explicitly cleans up pygame's internals.

+
+
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/tut/DisplayModes.html b/venv/Lib/site-packages/pygame/docs/generated/tut/DisplayModes.html new file mode 100644 index 0000000..b0d7d82 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/tut/DisplayModes.html @@ -0,0 +1,314 @@ + + + + + + + + + Pygame Tutorials - Setting Display Modes — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

Setting Display Modes

+
+
Author
+

Pete Shinners

+
+
Contact
+

pete@shinners.org

+
+
+
+

Introduction

+

Setting the display mode in pygame creates a visible image surface +on the monitor. +This surface can either cover the full screen, or be windowed +on platforms that support a window manager. +The display surface is nothing more than a standard pygame surface object. +There are special functions needed in the pygame.displaypygame module to control the display window and screen +module to keep the image surface contents updated on the monitor.

+

Setting the display mode in pygame is an easier task than with most +graphic libraries. +The advantage is if your display mode is not available, +pygame will emulate the display mode that you asked for. +Pygame will select a display resolution and color depth that best matches +the settings you have requested, +then allow you to access the display with the format you have requested. +In reality, since the pygame.displaypygame module to control the display window and screen module is +a binding around the SDL library, SDL is really doing all this work.

+

There are advantages and disadvantages to setting the display mode in this +manner. +The advantage is that if your game requires a specific display mode, +your game will run on platforms that do not support your requirements. +It also makes life easier when you're getting something started, +it is always easy to go back later and make the mode selection a little more +particular. +The disadvantage is that what you request is not always what you will get. +There is also a performance penalty when the display mode must be emulated. +This tutorial will help you understand the different methods for querying +the platforms display capabilities, and setting the display mode for your game.

+
+
+

Setting Basics

+

The first thing to learn about is how to actually set the current display mode. +The display mode may be set at any time after the pygame.displaypygame module to control the display window and screen +module has been initialized. +If you have previously set the display mode, +setting it again will change the current mode. +Setting the display mode is handled with the function +pygame.display.set_mode((width, height), flags, depth)Initialize a window or screen for display. +The only required argument in this function is a sequence containing +the width and height of the new display mode. +The depth flag is the requested bits per pixel for the surface. +If the given depth is 8, pygame will create a color-mapped surface. +When given a higher bit depth, pygame will use a packed color mode. +Much more information about depths and color modes can be found in the +documentation for the display and surface modules. +The default value for depth is 0. +When given an argument of 0, pygame will select the best bit depth to use, +usually the same as the system's current bit depth. +The flags argument lets you control extra features for the display mode. +Again, more information about this is found in the pygame reference documents.

+
+
+

How to Decide

+

So how do you select a display mode that is going to work best with your +graphic resources and the platform your game is running on? +There are several methods for gathering information about the display device. +All of these methods must be called after the display module has been +initialized, but you likely want to call them before setting the display mode. +First, pygame.display.Info()Create a video display information object +will return a special object type of VidInfo, +which can tell you a lot about the graphics driver capabilities. +The function +pygame.display.list_modes(depth, flags)Get list of available fullscreen modes +can be used to find the supported graphic modes by the system. +pygame.display.mode_ok((width, height), flags, depth)Pick the best color depth for a display mode takes the same arguments as +set_mode(), +but returns the closest matching bit depth to the one you request. +Lastly, pygame.display.get_driver()Get the name of the pygame display backend +will return the name of the graphics driver selected by pygame.

+

Just remember the golden rule. +Pygame will work with pretty much any display mode you request. +Some display modes will need to be emulated, +which will slow your game down, +since pygame will need to convert every update you make to the +"real" display mode. The best bet is to always let pygame +choose the best bit depth, +and convert all your graphic resources to that format when they are loaded. +You let pygame choose its bit depth by calling +set_mode() +with no depth argument or a depth of 0, +or you can call +mode_ok() +to find a closest matching bit depth to what you need.

+

When your display mode is windowed, +you usually must match the same bit depth as the desktop. +When you are fullscreen, some platforms can switch to any bit depth that +best suits your needs. +You can find the depth of the current desktop if you get a VidInfo object +before ever setting your display mode.

+

After setting the display mode, +you can find out information about its settings by getting a VidInfo object, +or by calling any of the Surface.get* methods on the display surface.

+
+
+

Functions

+

These are the routines you can use to determine the most appropriate +display mode. +You can find more information about these functions in the display module +documentation.

+
+

pygame.display.mode_ok(size, flags, depth)Pick the best color depth for a display mode

+
+

This function takes the exact same arguments as pygame.display.set_mode(). +It returns the best available bit depth for the mode you have described. +If this returns zero, +then the desired display mode is not available without emulation.

+
+

pygame.display.list_modes(depth, flags)Get list of available fullscreen modes

+
+

Returns a list of supported display modes with the requested +depth and flags. +An empty list is returned when there are no modes. +The flags argument defaults to FULLSCREEN. +If you specify your own flags without FULLSCREEN, +you will likely get a return value of -1. +This means that any display size is fine, since the display will be windowed. +Note that the listed modes are sorted largest to smallest.

+
+

pygame.display.Info()Create a video display information object

+
+

This function returns an object with many members describing +the display device. +Printing the VidInfo object will quickly show you all the +members and values for this object.

+
>>> import pygame.display
+>>> pygame.display.init()
+>>> info = pygame.display.Info()
+>>> print(info)
+<VideoInfo(hw = 0, wm = 1,video_mem = 0
+        blit_hw = 0, blit_hw_CC = 0, blit_hw_A = 0,
+        blit_sw = 0, blit_sw_CC = 0, blit_sw_A = 0,
+        bitsize  = 32, bytesize = 4,
+        masks =  (16711680, 65280, 255, 0),
+        shifts = (16, 8, 0, 0),
+        losses =  (0, 0, 0, 8),
+        current_w = 1920, current_h = 1080
+>
+
+
+
+
+

You can test all these flags as simply members of the VidInfo object.

+
+
+

Examples

+

Here are some examples of different methods to init the graphics display. +They should help you get an idea of how to go about setting your display mode.

+
>>> #give me the best depth with a 640 x 480 windowed display
+>>> pygame.display.set_mode((640, 480))
+
+>>> #give me the biggest 16-bit display available
+>>> modes = pygame.display.list_modes(16)
+>>> if not modes:
+...     print('16-bit not supported')
+... else:
+...     print('Found Resolution:', modes[0])
+...     pygame.display.set_mode(modes[0], FULLSCREEN, 16)
+
+>>> #need an 8-bit surface, nothing else will do
+>>> if pygame.display.mode_ok((800, 600), 0, 8) != 8:
+...     print('Can only work with an 8-bit display, sorry')
+... else:
+...     pygame.display.set_mode((800, 600), 0, 8)
+
+
+
+
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/tut/ImportInit.html b/venv/Lib/site-packages/pygame/docs/generated/tut/ImportInit.html new file mode 100644 index 0000000..2b11c40 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/tut/ImportInit.html @@ -0,0 +1,197 @@ + + + + + + + + + Pygame Tutorials - Import and Initialize — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

Import and Initialize

+
+
Author
+

Pete Shinners

+
+
Contact
+

pete@shinners.org

+
+
+

Getting pygame imported and initialized is a very simple process. It is also +flexible enough to give you control over what is happening. Pygame is a +collection of different modules in a single python package. Some of the +modules are written in C, and some are written in python. Some modules +are also optional, and might not always be present.

+

This is just a quick introduction on what is going on when you import pygame. +For a clearer explanation definitely see the pygame examples.

+
+

Import

+

First we must import the pygame package. Since pygame version 1.4 this +has been updated to be much easier. Most games will import all of pygame like this.

+
import pygame
+from pygame.locals import *
+
+
+

The first line here is the only necessary one. It imports all the available pygame +modules into the pygame package. The second line is optional, and puts a limited +set of constants and functions into the global namespace of your script.

+

An important thing to keep in mind is that several pygame modules are optional. +For example, one of these is the font module. When you "import pygame", pygame +will check to see if the font module is available. If the font module is available +it will be imported as "pygame.font". If the module is not available, "pygame.font" +will be set to None. This makes it fairly easy to later on test if the font module is available.

+
+
+

Init

+

Before you can do much with pygame, you will need to initialize it. The most common +way to do this is just make one call.

+
pygame.init()
+
+
+

This will attempt to initialize all the pygame modules for you. Not all pygame modules +need to be initialized, but this will automatically initialize the ones that do. You can +also easily initialize each pygame module by hand. For example to only initialize the +font module you would just call.

+
pygame.font.init()
+
+
+

Note that if there is an error when you initialize with "pygame.init()", it will silently fail. +When hand initializing modules like this, any errors will raise an exception. Any +modules that must be initialized also have a "get_init()" function, which will return true +if the module has been initialized.

+

It is safe to call the init() function for any module more than once.

+
+
+

Quit

+

Modules that are initialized also usually have a quit() function that will clean up. +There is no need to explicitly call these, as pygame will cleanly quit all the +initialized modules when python finishes.

+
+
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/tut/MakeGames.html b/venv/Lib/site-packages/pygame/docs/generated/tut/MakeGames.html new file mode 100644 index 0000000..b9f6ed9 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/tut/MakeGames.html @@ -0,0 +1,237 @@ + + + + + + + + + Making Games With Pygame — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

Making Games With Pygame

+
+
+
+

Table of Contents

+

1. Introduction

+
+
+

2. Revision: Pygame fundamentals

+
+
+

3. Kicking things off

+
+
+

4. Game object classes

+
+
+

5. User-controllable objects

+
+
+

6. Putting it all together

+
+
+
+
+

1. Introduction

+

First of all, I will assume you have read the Line By Line Chimp +tutorial, which introduces the basics of Python and pygame. Give it a read before reading this +tutorial, as I won't bother repeating what that tutorial says (or at least not in as much detail). This tutorial is aimed at those +who understand how to make a ridiculously simple little "game", and who would like to make a relatively simple game like Pong. +It introduces you to some concepts of game design, some simple mathematics to work out ball physics, and some ways to keep your +game easy to maintain and expand.

+

All the code in this tutorial works toward implementing TomPong, +a game I've written. By the end of the tutorial, you should not only have a firmer grasp of pygame, but +you should also understand how TomPong works, and how to make your own version.

+

Now, for a brief recap of the basics of pygame. A common method of organising the code for a game is to divide it into the following +six sections:

+
+
    +
  • Load modules which are required in the game. Standard stuff, except that you should +remember to import the pygame local names as well as the pygame module itself

  • +
  • Resource handling classes; define some classes to handle your most basic resources, +which will be loading images and sounds, as well as connecting and disconnecting to and from networks, loading save game +files, and any other resources you might have.

  • +
  • Game object classes; define the classes for your game object. In the pong example, +these will be one for the player's bat (which you can initialise multiple times, one for each player in the game), and one +for the ball (which can again have multiple instances). If you're going to have a nice in-game menu, it's also a good idea to make a +menu class.

  • +
  • Any other game functions; define other necessary functions, such as scoreboards, menu +handling, etc. Any code that you could put into the main game logic, but that would make understanding said logic harder, should +be put into its own function. So as plotting a scoreboard isn't game logic, it should be moved into a function.

  • +
  • Initialise the game, including the pygame objects themselves, the background, the game +objects (initialising instances of the classes) and any other little bits of code you might want to add in.

  • +
  • The main loop, into which you put any input handling (i.e. watching for users hitting +keys/mouse buttons), the code for updating the game objects, and finally for updating the screen.

  • +
+
+

Every game you make will have some or all of those sections, possibly with more of your own. For the purposes of this tutorial, I will +write about how TomPong is laid out, and the ideas I write about can be transferred to almost any kind of game you might make. I will +also assume that you want to keep all of the code in a single file, but if you're making a reasonably large game, it's often a good +idea to source certain sections into module files. Putting the game object classes into a file called objects.py, for +example, can help you keep game logic separate from game objects. If you have a lot of resource handling code, it can also be handy +to put that into resources.py. You can then from objects,resources import * to import all of the +classes and functions.

+
+
+

1.1. A note on coding styles

+

The first thing to remember when approaching any programming project is to decide on a coding style, and stay consistent. Python +solves a lot of the problems because of its strict interpretation of whitespace and indentation, but you can still choose the size +of your indentations, whether you put each module import on a new line, how you comment code, etc. You'll see how I do all of this +in the code examples; you needn't use my style, but whatever style you adopt, use it all the way through the program code. Also try +to document all of your classes, and comment on any bits of code that seem obscure, though don't start commenting the obvious. I've +seen plenty of people do the following:

+
player1.score += scoreup        # Add scoreup to player1 score
+
+
+

The worst code is poorly laid out, with seemingly random changes in style, and poor documentation. Poor code is not only annoying +for other people, but it also makes it difficult for you to maintain.

+
+
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/tut/MoveIt.html b/venv/Lib/site-packages/pygame/docs/generated/tut/MoveIt.html new file mode 100644 index 0000000..67469fa --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/tut/MoveIt.html @@ -0,0 +1,539 @@ + + + + + + + + + Pygame Tutorials - Help! How Do I Move An Image? — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

Help! How Do I Move An Image?

+
+
Author
+

Pete Shinners

+
+
Contact
+

pete@shinners.org

+
+
+

Many people new to programming and graphics have a hard time figuring +out how to make an image move around the screen. Without understanding +all the concepts, it can be very confusing. You're not the first person +to be stuck here, I'll do my best to take things step by step. We'll even +try to end with methods of keeping your animations efficient.

+

Note that we won't be teaching you to program with python in this article, +just introduce you to some of the basics with pygame.

+
+

Just Pixels On The Screen

+

Pygame has a display Surface. This is basically an image that is visible +on the screen, and the image is made up of pixels. The main way you change +these pixels is by calling the blit() function. This copies the pixels +from one image onto another.

+

This is the first thing to understand. When you blit an image onto the +screen, you are simply changing the color of the pixels on the screen. +Pixels aren't added or moved, we just change the colors of the pixels already +on the screen. These images you blit to the screen are also Surfaces in +pygame, but they are in no way connected to the display Surface. When they +are blitted to the screen they are copied into the display, but you still +have a unique copy of the original.

+

With this brief description. Perhaps you can already understand what +is needed to "move" an image. We don't actually move anything at all. We +simply blit the image in a new position. But before we draw the image in +the new position, we'll need to "erase" the old one. Otherwise the image +will be visible in two places on the screen. By rapidly erasing the image +and redrawing it in a new place, we achieve the "illusion" of movement.

+

Through the rest of this tutorial we will break this process down into +simpler steps. Even explaining the best ways to have multiple images moving +around the screen. You probably already have questions. Like, how do we +"erase" the image before drawing it in a new position? Perhaps you're still +totally lost? Well hopefully the rest of this tutorial can straighten things +out for you.

+
+
+

Let's Go Back A Step

+

Perhaps the concept of pixels and images is still a little foreign to +you? Well good news, for the next few sections we are going to use code that +does everything we want, it just doesn't use pixels. We're going to create +a small python list of 6 numbers, and imagine it represents some fantastic +graphics we could see on the screen. It might actually be surprising how +closely this represents exactly what we'll later be doing with real graphics.

+

So let's begin by creating our screen list and fill it with a beautiful +landscape of 1s and 2s.

+
>>> screen = [1, 1, 2, 2, 2, 1]
+>>> print screen
+[1, 1, 2, 2, 2, 1]
+
+
+

Now we've created our background. It's not going to be very exciting +unless we also draw a player on the screen. We'll create a mighty hero +that looks like the number 8. Let's stick him near the middle of the map +and see what it looks like.

+
>>> screen[3] = 8
+>>> print screen
+[1, 1, 2, 8, 2, 1]
+
+
+

This might have been as far as you've gotten if you jumped right in doing +some graphics programming with pygame. You've got some nice looking stuff +on the screen, but it cannot move anywhere. Perhaps now that our screen +is just a list of numbers, it's easier to see how to move him?

+
+
+

Making The Hero Move

+

Before we can start moving the character. We need to keep track of some +sort of position for him. In the last section when we drew him, we just picked +an arbitrary position. Let's do it a little more officially this time.

+
>>> playerpos = 3
+>>> screen[playerpos] = 8
+>>> print screen
+[1, 1, 2, 8, 2, 1]
+
+
+

Now it is pretty easy to move him to a new position. We simply change +the value of playerpos, and draw him on the screen again.

+
>>> playerpos = playerpos - 1
+>>> screen[playerpos] = 8
+>>> print screen
+[1, 1, 8, 8, 2, 1]
+
+
+

Whoops. Now we can see two heroes. One in the old position, and one +in his new position. This is exactly the reason we need to "erase" the hero +in his old position before we draw him in the new position. To erase him, +we need to change that value in the list back to what it was before the hero +was there. That means we need to keep track of the values on the screen before +the hero replaced them. There's several way you could do this, but the easiest +is usually to keep a separate copy of the screen background. This means +we need to make some changes to our little game.

+
+
+

Creating A Map

+

What we want to do is create a separate list we will call our background. +We will create the background so it looks like our original screen did, +with 1s and 2s. Then we will copy each item from the background to the screen. +After that we can finally draw our hero back onto the screen.

+
>>> background = [1, 1, 2, 2, 2, 1]
+>>> screen = [0]*6                         #a new blank screen
+>>> for i in range(6):
+...     screen[i] = background[i]
+>>> print screen
+[1, 1, 2, 2, 2, 1]
+>>> playerpos = 3
+>>> screen[playerpos] = 8
+>>> print screen
+[1, 1, 2, 8, 2, 1]
+
+
+

It may seem like a lot of extra work. We're no farther off than we were +before the last time we tried to make him move. But this time we have the +extra information we need to move him properly.

+
+
+

Making The Hero Move (Take 2)

+

This time it will be easy to move the hero around. First we will erase +the hero from his old position. We do this by copying the correct value +from the background onto the screen. Then we will draw the character in his +new position on the screen

+
>>> print screen
+[1, 1, 2, 8, 2, 1]
+>>> screen[playerpos] = background[playerpos]
+>>> playerpos = playerpos - 1
+>>> screen[playerpos] = 8
+>>> print screen
+[1, 1, 8, 2, 2, 1]
+
+
+

There it is. The hero has moved one space to the left. We can use this +same code to move him to the left again.

+
>>> screen[playerpos] = background[playerpos]
+>>> playerpos = playerpos - 1
+>>> screen[playerpos] = 8
+>>> print screen
+[1, 8, 2, 2, 2, 1]
+
+
+

Excellent! This isn't exactly what you'd call smooth animation. But with +a couple small changes, we'll make this work directly with graphics on +the screen.

+
+
+

Definition: "blit"

+

In the next sections we will transform our program from using lists to +using real graphics on the screen. When displaying the graphics we will +use the term blit frequently. If you are new to doing graphics +work, you are probably unfamiliar with this common term.

+

BLIT: Basically, blit means to copy graphics from one image +to another. A more formal definition is to copy an array of data +to a bitmapped array destination. You can think of blit as just +"assigning" pixels. Much like setting values in our screen-list +above, blitting assigns the color of pixels in our image.

+

Other graphics libraries will use the word bitblt, or just blt, +but they are talking about the same thing. It is basically copying +memory from one place to another. Actually, it is a bit more advanced than +straight copying of memory, since it needs to handle things like pixel +formats, clipping, and scanline pitches. Advanced blitters can also +handle things like transparency and other special effects.

+
+
+

Going From The List To The Screen

+

To take the code we see in the above to examples and make them work with +pygame is very straightforward. We'll pretend we have loaded some pretty +graphics and named them "terrain1", "terrain2", and "hero". Where before +we assigned numbers to a list, we now blit graphics to the screen. Another +big change, instead of using positions as a single index (0 through 5), we +now need a two dimensional coordinate. We'll pretend each of the graphics +in our game is 10 pixels wide.

+
>>> background = [terrain1, terrain1, terrain2, terrain2, terrain2, terrain1]
+>>> screen = create_graphics_screen()
+>>> for i in range(6):
+...     screen.blit(background[i], (i*10, 0))
+>>> playerpos = 3
+>>> screen.blit(playerimage, (playerpos*10, 0))
+
+
+

Hmm, that code should seem very familiar, and hopefully more importantly; +the code above should make a little sense. Hopefully my illustration of setting +simple values in a list shows the similarity of setting pixels on the screen +(with blit). The only part that's really extra work is converting the player position +into coordinates on the screen. For now we just use a crude (playerpos*10, 0) , +but we can certainly do better than that. Now let's move the player +image over a space. This code should have no surprises.

+
>>> screen.blit(background[playerpos], (playerpos*10, 0))
+>>> playerpos = playerpos - 1
+>>> screen.blit(playerimage, (playerpos*10, 0))
+
+
+

There you have it. With this code we've shown how to display a simple background +with a hero's image on it. Then we've properly moved that hero one space +to the left. So where do we go from here? Well for one the code is still +a little awkward. First thing we'll want to do is find a cleaner way to represent +the background and player position. Then perhaps a bit of smoother, real +animation.

+
+
+

Screen Coordinates

+

To position an object on the screen, we need to tell the blit() function +where to put the image. In pygame we always pass positions as an (X,Y) coordinate. +This represents the number of pixels to the right, and the number of pixels +down to place the image. The top-left corner of a Surface is coordinate (0, +0). Moving to the right a little would be (10, 0), and then moving down just +as much would be (10, 10). When blitting, the position argument represents +where the topleft corner of the source should be placed on the destination.

+

Pygame comes with a convenient container for these coordinates, it is a +Rect. The Rect basically represents a rectangular area in these coordinates. +It has topleft corner and a size. The Rect comes with a lot of convenient +methods which help you move and position them. In our next examples we will +represent the positions of our objects with the Rects.

+

Also know that many functions in pygame expect Rect arguments. All of these +functions can also accept a simple tuple of 4 elements (left, top, width, +height). You aren't always required to use these Rect objects, but you will +mainly want to. Also, the blit() function can accept a Rect as its position +argument, it simply uses the topleft corner of the Rect as the real position.

+
+
+

Changing The Background

+

In all our previous sections, we've been storing the background as a list +of different types of ground. That is a good way to create a tile-based game, +but we want smooth scrolling. To make that a little easier, we're going to +change the background into a single image that covers the whole screen. This +way, when we want to "erase" our objects (before redrawing them) we only need +to blit the section of the erased background onto the screen.

+

By passing an optional third Rect argument to blit, we tell blit to only +use that subsection of the source image. You'll see that in use below as we +erase the player image.

+

Also note, now when we finish drawing to the screen, we call pygame.display.update() +which will show everything we've drawn onto the screen.

+
+
+

Smooth Movement

+

To make something appear to move smoothly, we only want to move it a couple +pixels at a time. Here is the code to make an object move smoothly across +the screen. Based on what we already now know, this should look pretty simple.

+
>>> screen = create_screen()
+>>> player = load_player_image()
+>>> background = load_background_image()
+>>> screen.blit(background, (0, 0))        #draw the background
+>>> position = player.get_rect()
+>>> screen.blit(player, position)          #draw the player
+>>> pygame.display.update()                #and show it all
+>>> for x in range(100):                   #animate 100 frames
+...     screen.blit(background, position, position) #erase
+...     position = position.move(2, 0)     #move player
+...     screen.blit(player, position)      #draw new player
+...     pygame.display.update()            #and show it all
+...     pygame.time.delay(100)             #stop the program for 1/10 second
+
+
+

There you have it. This is all the code that is needed to smoothly animate +an object across the screen. We can even use a pretty background character. +Another benefit of doing the background this way, the image for the player +can have transparency or cutout sections and it will still draw correctly +over the background (a free bonus).

+

We also throw in a call to pygame.time.delay() at the end of our loop above. +This slows down our program a little, otherwise it might run so fast you might +not see it.

+
+
+

So, What Next?

+

Well there we have it. Hopefully this article has done everything it promised +to do. But, at this point the code really isn't ready for the next best-selling +game. How do we easily have multiple moving objects? What exactly are those +mysterious functions like load_player_image()? We also need a way to get simple +user input, and loop for more than 100 frames. We'll take the example we +have here, and turn it into an object oriented creation that would make momma +proud.

+
+
+

First, The Mystery Functions

+

Full information on these types of functions can be found in other tutorials +and reference. The pygame.image module has a load() function which will do +what we want. The lines to load the images should become this.

+
>>> player = pygame.image.load('player.bmp').convert()
+>>> background = pygame.image.load('liquid.bmp').convert()
+
+
+

We can see that's pretty simple, the load function just takes a filename +and returns a new Surface with the loaded image. After loading we make a call +to the Surface method, convert(). Convert returns us a new Surface of the +image, but now converted to the same pixel format as our display. Since the +images will be the same format at the screen, they will blit very quickly. +If we did not convert, the blit() function is slower, since it has to convert +from one type of pixel to another as it goes.

+

You may also have noticed that both the load() and convert() return new +Surfaces. This means we're really creating two Surfaces on each of these +lines. In other programming languages, this results in a memory leak (not +a good thing). Fortunately Python is smart enough to handle this, and pygame +will properly clean up the Surface we end up not using.

+

The other mystery function we saw in the above example was create_screen(). +In pygame it is simple to create a new window for graphics. The code to create +a 640x480 surface is below. By passing no other arguments, pygame will just +pick the best color depth and pixel format for us.

+
>>> screen = pygame.display.set_mode((640, 480))
+
+
+
+
+

Handling Some Input

+

We desperately need to change the main loop to look for any user input, (like +when the user closes the window). We need to add "event handling" to our +program. All graphical programs use this Event Based design. The program +gets events like "keyboard pressed" or "mouse moved" from the computer. Then +the program responds to the different events. Here's what the code should +look like. Instead of looping for 100 frames, we'll keep looping until the +user asks us to stop.

+
>>> while 1:
+...     for event in pygame.event.get():
+...         if event.type in (QUIT, KEYDOWN):
+...             sys.exit()
+...     move_and_draw_all_game_objects()
+
+
+

What this code simply does is, first loop forever, then check if there are +any events from the user. We exit the program if the user presses the keyboard +or the close button on the window. After we've checked all the events we +move and draw our game objects. (We'll also erase them before they move, +too)

+
+
+

Moving Multiple Images

+

Here's the part where we're really going to change things around. Let's +say we want 10 different images moving around on the screen. A good way to +handle this is to use python's classes. We'll create a class that represents +our game object. This object will have a function to move itself, and then +we can create as many as we like. The functions to draw and move the object +need to work in a way where they only move one frame (or one step) at a time. +Here's the python code to create our class.

+
>>> class GameObject:
+...     def __init__(self, image, height, speed):
+...         self.speed = speed
+...         self.image = image
+...         self.pos = image.get_rect().move(0, height)
+...     def move(self):
+...         self.pos = self.pos.move(0, self.speed)
+...         if self.pos.right > 600:
+...             self.pos.left = 0
+
+
+

So we have two functions in our class. The init function constructs our object. +It positions the object and sets its speed. The move method moves the object +one step. If it's gone too far, it moves the object back to the left.

+
+
+

Putting It All Together

+

Now with our new object class, we can put together the entire game. Here +is what the main function for our program will look like.

+
>>> screen = pygame.display.set_mode((640, 480))
+>>> player = pygame.image.load('player.bmp').convert()
+>>> background = pygame.image.load('background.bmp').convert()
+>>> screen.blit(background, (0, 0))
+>>> objects = []
+>>> for x in range(10):                    #create 10 objects</i>
+...     o = GameObject(player, x*40, x)
+...     objects.append(o)
+>>> while 1:
+...     for event in pygame.event.get():
+...         if event.type in (QUIT, KEYDOWN):
+...             sys.exit()
+...     for o in objects:
+...         screen.blit(background, o.pos, o.pos)
+...     for o in objects:
+...         o.move()
+...         screen.blit(o.image, o.pos)
+...     pygame.display.update()
+...     pygame.time.delay(100)
+
+
+

And there it is. This is the code we need to animate 10 objects on the screen. +The only point that might need explaining is the two loops we use to clear +all the objects and draw all the objects. In order to do things properly, +we need to erase all the objects before drawing any of them. In our sample +here it may not matter, but when objects are overlapping, using two loops +like this becomes important.

+
+
+

You Are On Your Own From Here

+

So what would be next on your road to learning? Well first playing around +with this example a bit. The full running version of this example is available +in the pygame examples directory. It is the example named +moveit.py . +Take a look at the code and play with it, run it, learn it.

+

Things you may want to work on is maybe having more than one type of object. +Finding a way to cleanly "delete" objects when you don't want to show them +any more. Also updating the display.update() call to pass a list of the areas +on-screen that have changed.

+

There are also other tutorials and examples in pygame that cover these +issues. So when you're ready to keep learning, keep on reading. :-)

+

Lastly, you can feel free to come to the pygame mailing list or chatroom +with any questions on this stuff. There's always folks on hand who can help +you out with this sort of business.

+

Lastly, have fun, that's what games are for!

+
+
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/tut/PygameIntro.html b/venv/Lib/site-packages/pygame/docs/generated/tut/PygameIntro.html new file mode 100644 index 0000000..0331936 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/tut/PygameIntro.html @@ -0,0 +1,418 @@ + + + + + + + + + Pygame Intro — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

Python Pygame Introduction

+
+
Author
+

Pete Shinners

+
+
Contact
+

pete@shinners.org

+
+
+

This article is an introduction to the pygame library +for Python programmers. +The original version appeared in the Py Zine, +volume 1 issue 3. This version contains minor revisions, to +create an all-around better article. Pygame is a Python extension +library that wraps the SDL library +and its helpers.

+
+

HISTORY

+

Pygame started in the summer of 2000. Being a C programmer of many +years, I discovered both Python and SDL at about the same time. You are +already familiar with Python, which was at version 1.5.2. You may need +an introduction to SDL, which is the Simple DirectMedia Layer. +Created by Sam Lantinga, SDL is a cross-platform C library for +controlling multimedia, comparable to DirectX. It has been used for +hundreds of commercial and open source games. I was impressed at how clean +and straightforward both projects were and it wasn't long before I +realized mixing Python and SDL was an interesting proposal.

+

I discovered a small project already under-way with exactly the same +idea, PySDL. Created by Mark Baker, PySDL was a straightforward +implementation of SDL as a Python extension. The interface was cleaner +than a generic SWIG wrapping, but I felt it forced a "C style" of code. +The sudden death of PySDL prompted me to take on a new project of my +own.

+

I wanted to put together a project that really took advantage of +Python. My goal was to make it easy to do the simple things, and +straightforward to do the difficult things. Pygame was started in +October, 2000. Six months later pygame version 1.0 was released.

+
+
+

TASTE

+

I find the best way to understand a new library is to jump straight +into an example. In the early days of pygame, I created a bouncing ball +animation with 7 lines of code. Let's take a look at a friendlier +version of that same thing. This should be simple enough to follow +along, and a complete breakdown follows.

+../_images/intro_ball.gif +
 1import sys, pygame
+ 2pygame.init()
+ 3
+ 4size = width, height = 320, 240
+ 5speed = [2, 2]
+ 6black = 0, 0, 0
+ 7
+ 8screen = pygame.display.set_mode(size)
+ 9
+10ball = pygame.image.load("intro_ball.gif")
+11ballrect = ball.get_rect()
+12
+13while 1:
+14    for event in pygame.event.get():
+15        if event.type == pygame.QUIT: sys.exit()
+16
+17    ballrect = ballrect.move(speed)
+18    if ballrect.left < 0 or ballrect.right > width:
+19        speed[0] = -speed[0]
+20    if ballrect.top < 0 or ballrect.bottom > height:
+21        speed[1] = -speed[1]
+22
+23    screen.fill(black)
+24    screen.blit(ball, ballrect)
+25    pygame.display.flip()
+
+
+

This is as simple as you can get for a bouncing animation. +First we see importing and initializing pygame is nothing noteworthy. +The import pygame imports the package with all the available +pygame modules. +The call to pygame.init() initializes each of these modules.

+

On line 8 we create a +graphical window with the call to pygame.display.set_mode(). +Pygame and SDL make this easy by defaulting to the best graphics modes +for the graphics hardware. You can override the mode and SDL will +compensate for anything the hardware cannot do. Pygame represents +images as Surface objects. +The display.set_mode() function creates a new Surface +object that represents the actual displayed graphics. Any drawing you +do to this Surface will become visible on the monitor.

+

At line 10 we load +our ball image. Pygame supports a variety of image formats through the +SDL_image library, including BMP, JPG, PNG, TGA, and GIF. +The pygame.image.load() function +returns us a Surface with the ball data. The Surface will keep any +colorkey or alpha transparency from the file. After loading the ball +image we create a variable named ballrect. Pygame comes with a +convenient utility object type named Rect, +which represents a rectangular area. Later, in the animation part of +the code, we will see what the Rect objects can do.

+

At this point, line 13, +our program is initialized and ready to run. Inside an infinite loop we +check for user input, move the ball, and then draw the ball. If you are +familiar with GUI programming, you have had experience with events and +event loops. In pygame this is no different, +we check if a QUIT event has happened. If so we +simply exit the program, pygame will ensure everything is cleanly +shutdown.

+

It is time to update our position for the ball. +Lines 17 moves the ballrect variable by the current speed. +Lines 18 thru 21 reverse the speed if the ball has moved outside the screen. +Not exactly Newtonian physics, but it is all we need.

+

On line 23 we erase +the screen by filling it with a black RGB color. If you have never +worked with animations this may seem strange. You may be asking "Why do +we need to erase anything, why don't we just move the ball on the +screen?" That is not quite the way computer animation works. Animation +is nothing more than a series of single images, which when displayed in +sequence do a very good job of fooling the human eye into seeing +motion. The screen is just a single image that the user sees. If we did +not take the time to erase the ball from the screen, we would actually +see a "trail" of the ball as we continuously draw the ball in its new +positions.

+

On line 24 we draw the ball image onto the screen. +Drawing of images is handled by the +Surface.blit() method. +A blit basically means copying pixel colors from one image to another. +We pass the blit method a source Surface +to copy from, and a position to place the source onto the destination.

+

The last thing we need to do is actually update the visible display. +Pygame manages the display with a double buffer. When we are finished +drawing we call the pygame.display.flip()Update the full display Surface to the screen method. +This makes everything we have drawn on the screen Surface +become visible. This buffering makes sure we only see completely drawn +frames on the screen. Without it, the user would see the half completed +parts of the screen as they are being created.

+

That concludes this short introduction to pygame. Pygame also has +modules to do things like input handling for the keyboard, mouse, and +joystick. It can mix audio and decode streaming music. +With the Surfaces you can draw simple +shapes, rotate and scale the picture, and even manipulate the pixels of +an image in realtime as numpy arrays. +Pygame also has the ability to act as a +cross platform display layer for PyOpenGL. Most of the pygame modules +are written in C, few are actually done in Python.

+

The pygame website has full reference documentation for every pygame +function and tutorials for all ranges of users. The pygame source comes +with many examples of things like monkey punching and UFO shooting.

+
+
+

PYTHON AND GAMING

+

"Is Python suitable for gaming?" The answer is, "It depends on the +game."

+

Python is actually quite capable at running games. It will likely even +surprise you how much is possible in under 30 milliseconds. Still, it +is not hard to reach the ceiling once your game begins to get more +complex. Any game running in realtime will be making full use of the +computer.

+../_images/intro_blade.jpg +

Over the past several years there has been an interesting trend in game development, +the move towards higher level languages. Usually a game is split into +two major parts. The game engine, which must be as fast as possible, +and the game logic, which makes the engine actually do something. It +wasn't long ago when the engine of a game was written in assembly, with +portions written in C. Nowadays, C has moved to the game engine, while +often the game itself is written in higher level scripting languages. +Games like Quake3 and Unreal run these scripts as portable bytecode.

+

In early 2001, developer Rebel Act Studios finished their game, +Severance: Blade of Darkness. Using their own custom 3D engine, the +rest of the game is written with Python. The game is a bloody action +3rd person perspective fighter. You control medieval warriors into +intricate decapitating combination attacks while exploring dungeons and +castles. You can download third party add-ons for this game, and find +they are nothing more than Python source files.

+

More recently, Python has been used in a variety of games like Freedom +Force, and Humungous' Backyard Sports Series.

+../_images/intro_freedom.jpg +

Pygame and SDL serve as an excellent C engine for 2D games. +Games will still find the largest part of their runtime is spent +inside SDL handling the graphics. +SDL can take advantage of graphics hardware acceleration. +Enabling this can change a game from running around 40 frames per +second to over 200 frames per second. When you see your Python game +running at 200 frames per second, you realize that Python and games can +work together.

+

It is impressive how well both Python and SDL work on multiple +platforms. For example, in May of 2001 I released my own full pygame +project, SolarWolf, an arcade style action game. One thing that has +surprised me is that one year later there has been no need for any +patches, bug fixes, or updates. The game was developed entirely on +windows, but runs on Linux, Mac OSX, and many Unixes without any extra +work on my end.

+

Still, there are very clear limitations. The best way to manage +hardware accelerated graphics is not always the way to get fastest +results from software rendering. Hardware support is not available on +all platforms. When a game gets more complex, it often must commit to +one or the other. SDL has some other design limitations, things like +full screen scrolling graphics can quickly bring your game down to +unplayable speeds. While SDL is not suitable for all types of games, +remember companies like Loki have used SDL to run a wide variety of +retail quality titles.

+

Pygame is fairly low-level when it comes to writing games. You'll +quickly find yourself needing to wrap common functions into your own +game environment. The great thing about this is there is nothing inside +pygame to get in your way. Your program is in full control of +everything. The side effect of that is you will find yourself borrowing +a lot of code to get a more advanced framework put together. You'll +need a better understanding of what you are doing.

+
+
+

CLOSING

+

Developing games is very rewarding, there is something exciting about +being able to see and interact with the code you've written. Pygame +currently has almost 30 other projects using it. Several of them are +ready to play now. You may be surprised to visit the pygame website, +and see what other users have been able to do with Python.

+

One thing that has caught my attention is the amount of people coming +to Python for the first time to try game development. I can see why +games are a draw for new programmers, but it can be difficult since +creating games requires a firmer understanding of the language. I've +tried to support this group of users by writing many examples and +pygame tutorials for people new to these concepts.

+

In the end, my advice is to keep it simple. I cannot stress this +enough. If you are planning to create your first game, there is a +lot to learn. Even a simpler game will challenge your designs, and +complex games don't necessarily mean fun games. When you understand +Python, you can use pygame to create a simple game in only one or two +weeks. From there you'll need a surprising amount of time to add +the polish to make that into a full presentable game.

+
+

Pygame Modules Overview

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

cdrom

playback

cursors

load cursor images, includes standard cursors

display

control the display window or screen

draw

draw simple shapes onto a Surface

event

manage events and the event queue

font

create and render TrueType fonts

image

save and load images

joystick

manage joystick devices

key

manage the keyboard

mouse

manage the mouse

sndarray

manipulate sounds with numpy

surfarray

manipulate images with numpy

time

control timing

transform

scale, rotate, and flip images

+
+
+
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/tut/SpriteIntro.html b/venv/Lib/site-packages/pygame/docs/generated/tut/SpriteIntro.html new file mode 100644 index 0000000..b691185 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/tut/SpriteIntro.html @@ -0,0 +1,498 @@ + + + + + + + + + Pygame Tutorials - Sprite Module Introduction — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

Sprite Module Introduction

+
+
Author
+

Pete Shinners

+
+
Contact
+

pete@shinners.org

+
+
+

Pygame version 1.3 comes with a new module, pygame.sprite. This module is +written in Python and includes some higher-level classes to manage your game +objects. By using this module to its full potential, you can easily manage and +draw your game objects. The sprite classes are very optimized, so it's likely +your game will run faster with the sprite module than without.

+

The sprite module is also meant to be very generic. It turns out you can use it +with nearly any type of gameplay. All this flexibility comes with a slight +penalty, it needs a little understanding to properly use it. The +reference documentation for the sprite module can keep +you running, but you'll probably need a bit more explanation of how to use +pygame.sprite in your own game.

+

Several of the pygame examples (like "chimp" and "aliens") have been updated to +use the sprite module. You may want to look into those first to see what this +sprite module is all about. The chimp module even has its own line-by-line +tutorial, which may help get more an understanding of programming with python +and pygame.

+

Note that this introduction will assume you have a bit of experience +programming with python, and are somewhat familiar with the different parts of +creating a simple game. In this tutorial the word "reference" is occasionally +used. This represents a python variable. Variables in python are references, +so you can have several variables all pointing to the same object.

+
+

History Lesson

+

The term "sprite" is a holdover from older computer and game machines. These +older boxes were unable to draw and erase normal graphics fast enough for them +to work as games. These machines had special hardware to handle game like +objects that needed to animate very quickly. These objects were called +"sprites" and had special limitations, but could be drawn and updated very +fast. They usually existed in special overlay buffers in the video. These days +computers have become generally fast enough to handle sprite like objects +without dedicated hardware. The term sprite is still used to represent just +about anything in a 2D game that is animated.

+
+
+

The Classes

+

The sprite module comes with two main classes. The first is Sprite, which should be used as a base class for all your game +objects. This class doesn't really do anything on its own, it just includes +several functions to help manage the game object. The other type of class is +Group. The Group class is a container for +different Sprite objects. There are actually several different types of +group classes. Some of the Groups can draw all the elements they contain, +for example.

+

This is all there really is to it. We'll start with a description of what each +type of class does, and then discuss the proper ways to use these two classes.

+
+
+

The Sprite Class

+

As mentioned before, the Sprite class is designed to be a base class for all +your game objects. You cannot really use it on its own, as it only has several +methods to help it work with the different Group classes. The sprite keeps +track of which groups it belongs to. +The class constructor (__init__ method) takes an argument of a +Group (or list of Groups) the Sprite instance should belong to. +You can also change the Group membership for the Sprite with the +add() and +remove() methods. +There is also a groups() method, +which returns a list of the current groups containing the sprite.

+

When using the your Sprite classes it's best to think of them as "valid" or +"alive" when they are belonging to one or more Groups. When you remove the +instance from all groups pygame will clean up the object. (Unless you have your +own references to the instance somewhere else.) The kill() method removes the sprite from all groups it +belongs to. This will cleanly delete the sprite object. If you've put some +little games together, you'll know sometimes cleanly deleting a game object can +be tricky. The sprite also comes with an alive() method, which returns true if it is still a +member of any groups.

+
+
+

The Group Class

+

The Group class is just a simple container. Similar to the sprite, it has +an add() and remove() method which can change which sprites belong to +the group. You also can pass a sprite or list of sprites to the constructor +(__init__() method) to create a Group instance that contains some +initial sprites.

+

The Group has a few other methods like empty() to remove all sprites from the group and +copy() which will return a copy of the group +with all the same members. Also the has() +method will quickly check if the Group contains a sprite or list of +sprites.

+

The other function you will use frequently is the sprites() method. This returns an object that can be +looped on to access every sprite the group contains. Currently this is just a +list of the sprites, but in later version of python this will likely use +iterators for better performance.

+

As a shortcut, the Group also has an update() method, which will call an update() method on +every sprite in the group. Passing the same arguments to each one. Usually in a +game you need some function that updates the state of a game object. It's very +easy to call your own methods using the Group.sprites() method, but this is +a shortcut that's used enough to be included. Also note that the base +Sprite class has a "dummy" update() method that takes any sort of +arguments and does nothing.

+

Lastly, the Group has a couple other methods that allow you to use it with +the builtin len() function, getting the number of sprites it contains, and +the "truth" operator, which allows you to do "if mygroup:" to check if the +group has any sprites.

+
+
+

Mixing Them Together

+

At this point the two classes seem pretty basic. Not doing a lot more than you +can do with a simple list and your own class of game objects. But there are +some big advantages to using the Sprite and Group together. A sprite +can belong to as many groups as you want. Remember as soon as it belongs to no +groups, it will usually be cleared up (unless you have other "non-group" +references to that object).

+

The first big thing is a fast simple way to categorize sprites. For example, +say we had a Pacman-like game. We could make separate groups for the different +types of objects in the game. Ghosts, Pac, and Pellets. When Pac eats a power +pellet, we can change the state for all ghost objects by effecting everything +in the Ghost group. This is quicker and simpler than looping through a list +of all the game objects and checking which ones are ghosts.

+

Adding and removing groups and sprites from each other is a very fast +operation, quicker than using lists to store everything. Therefore you can very +efficiently change group memberships. Groups can be used to work like simple +attributes for each game object. Instead of tracking some attribute like +"close_to_player" for a bunch of enemy objects, you could add them to a +separate group. Then when you need to access all the enemies that are near the +player, you already have a list of them, instead of going through a list of all +the enemies, checking for the "close_to_player" flag. Later on your game could +add multiple players, and instead of adding more "close_to_player2", +"close_to_player3" attributes, you can easily add them to different groups or +each player.

+

Another important benefit of using the Sprites and Groups is that the groups +cleanly handle the deleting (or killing) of game objects. In a game where many +objects are referencing other objects, sometimes deleting an object can be the +hardest part, since it can't go away until it is not referenced by anyone. Say +we have an object that is "chasing" another object. The chaser can keep a +simple Group that references the object (or objects) it is chasing. If the +object being chased happens to be destroyed, we don't need to worry about +notifying the chaser to stop chasing. The chaser can see for itself that its +group is now empty, and perhaps find a new target.

+

Again, the thing to remember is that adding and removing sprites from groups is +a very cheap/fast operation. You may be best off by adding many groups to +contain and organize your game objects. Some could even be empty for large +portions of the game, there isn't any penalties for managing your game like +this.

+
+
+

The Many Group Types

+

The above examples and reasons to use Sprites and Groups are only a tip +of the iceberg. Another advantage is that the sprite module comes with several +different types of Groups. These groups all work just like a regular old +Group, but they also have added functionality (or slightly different +functionality). Here's a list of the Group classes included with the +sprite module.

+
+

Group

+
+

This is the standard "no frills" group mainly explained above. Most of the +other Groups are derived from this one, but not all.

+
+

GroupSingle

+
+

This works exactly like the regular Group class, but it only contains +the most recently added sprite. Therefore when you add a sprite to this group, +it "forgets" about any previous sprites it had. Therefore it always contains +only one or zero sprites.

+
+

RenderPlain

+
+

This is a standard group derived from Group. It has a draw() method +that draws all the sprites it contains to the screen (or any Surface). For +this to work, it requires all sprites it contains to have a "image" and "rect" +attributes. It uses these to know what to blit, and where to blit it.

+
+

RenderClear

+
+

This is derived from the RenderPlain group, and adds a method named +clear(). This will erase the previous position of all drawn sprites. It +uses a background image to fill in the areas where the sprite were. It is smart +enough to handle deleted sprites and properly clear them from the screen when +the clear() method is called.

+
+

RenderUpdates

+
+

This is the Cadillac of rendering Groups. It is inherited from +RenderClear, but changes the draw() method to also return a list of +pygame Rects, which represent all the areas on screen that have been +changed.

+
+
+

That is the list of different groups available We'll discuss more about these +rendering groups in the next section. There's nothing stopping you from +creating your own Group classes as well. They are just python code, so you can +inherit from one of these and add/change whatever you want. In the future I +hope we can add a couple more Groups to this list. A GroupMulti which +is like the GroupSingle, but can hold up to a given number of sprites (in +some sort of circular buffer?). Also a super-render group that can clear the +position of the old sprites without needing a background image to do it (by +grabbing a copy of the screen before blitting). Who knows really, but in the +future we can add more useful classes to this list.

+
+
+

The Rendering Groups

+

From above we can see there are three different rendering groups. We could +probably just get away with the RenderUpdates one, but it adds overhead not +really needed for something like a scrolling game. So we have a couple tools +here, pick the right one for the right job.

+

For a scrolling type game, where the background completely changes every frame, +we obviously don't need to worry about python's update rectangles in the call +to display.update(). You should definitely go with the RenderPlain +group here to manage your rendering.

+

For games where the background is more stationary, you definitely don't want +pygame updating the entire screen (since it doesn't need to). This type of game +usually involves erasing the old position of each object, then drawing it in a +new place for each frame. This way we are only changing what is necessary. +Most of the time you will just want to use the RenderUpdates class here. +Since you will also want to pass this list of changes to the +display.update() function.

+

The RenderUpdates class also does a good job at minimizing overlapping +areas in the list of updated rectangles. If the previous position and current +position of an object overlap, it will merge them into a single rectangle. +Combined with the fact that it properly handles deleted objects, this is +one powerful Group class. If you've written a game that manages the changed +rectangles for the objects in a game, you know this the cause for a lot of +messy code in your game. Especially once you start to throw in objects that can +be deleted at any time. All this work is reduced to a clear() and +draw() method with this monster class. Plus with the overlap checking, it +is likely faster than when you did it manually.

+

Also note that there's nothing stopping you from mixing and matching these +render groups in your game. You should definitely use multiple rendering groups +when you want to do layering with your sprites. Also if the screen is split +into multiple sections, perhaps each section of the screen should use an +appropriate render group?

+
+
+

Collision Detection

+

The sprite module also comes with two very generic collision detection +functions. For more complex games, these really won't work for you, but you +can easily grab the source code for them, and modify them as needed.

+

Here's a summary of what they are, and what they do.

+
+

spritecollide(sprite, group, dokill) -> list

+
+

This checks for collisions between a single sprite and the sprites in a group. +It requires a "rect" attribute for all the sprites used. It returns a list of +all the sprites that overlap with the first sprite. The "dokill" argument is a +boolean argument. If it is true, the function will call the kill() method +on all the sprites. This means the last reference to each sprite is probably in +the returned list. Once the list goes away so do the sprites. A quick example +of using this in a loop

+
>>> for bomb in sprite.spritecollide(player, bombs, 1):
+...     boom_sound.play()
+...     Explosion(bomb, 0)
+
+
+

This finds all the sprites in the "bomb" group that collide with the player. +Because of the "dokill" argument it deletes all the crashed bombs. For each +bomb that did collide, it plays a "boom" sound effect, and creates a new +Explosion where the bomb was. (Note, the Explosion class here knows to +add each instance to the appropriate class, so we don't need to store it in a +variable, that last line might feel a little "funny" to you python programmers.

+
+

groupcollide(group1, group2, dokill1, dokill2) -> dictionary

+
+

This is similar to the spritecollide function, but a little more complex. +It checks for collisions for all the sprites in one group, to the sprites in +another. There is a dokill argument for the sprites in each list. When +dokill1 is true, the colliding sprites in group1 will be kill()``ed. +When ``dokill2 is true, we get the same results for group2. The +dictionary it returns works like this; each key in the dictionary is a sprite +from group1 that had a collision. The value for that key is a list of the +sprites that it collided with. Perhaps another quick code sample explains it +best

+
>>> for alien in sprite.groupcollide(aliens, shots, 1, 1).keys()
+...     boom_sound.play()
+...     Explosion(alien, 0)
+...     kills += 1
+
+
+

This code checks for the collisions between player bullets and all the aliens +they might intersect. In this case we only loop over the dictionary keys, but +we could loop over the values() or items() if we wanted to do something +to the specific shots that collided with aliens. If we did loop over the +values() we would be looping through lists that contain sprites. The same +sprite may even appear more than once in these different loops, since the same +"shot" could have collided against multiple "aliens".

+
+
+

Those are the basic collision functions that come with pygame. It should be +easy to roll your own that perhaps use something different than the "rect" +attribute. Or maybe try to fine-tweak your code a little more by directly +effecting the collision object, instead of building a list of the collision? +The code in the sprite collision functions is very optimized, but you could +speed it up slightly by taking out some functionality you don't need.

+
+
+

Common Problems

+

Currently there is one main problem that catches new users. When you derive +your new sprite class with the Sprite base, you must call the +Sprite.__init__() method from your own class __init__() method. If you +forget to call the Sprite.__init__() method, you get a cryptic error, like +this

+
AttributeError: 'mysprite' instance has no attribute '_Sprite__g'
+
+
+
+
+

Extending Your Own Classes (Advanced)

+

Because of speed concerns, the current Group classes try to only do exactly +what they need, and not handle a lot of general situations. If you decide you +need extra features, you may want to create your own Group class.

+

The Sprite and Group classes were designed to be extended, so feel free +to create your own Group classes to do specialized things. The best place +to start is probably the actual python source code for the sprite module. +Looking at the current Sprite groups should be enough example on how to +create your own.

+

For example, here is the source code for a rendering Group that calls a +render() method for each sprite, instead of just blitting an "image" +variable from it. Since we want it to also handle updated areas, we will start +with a copy of the original RenderUpdates group, here is the code:

+
class RenderUpdatesDraw(RenderClear):
+    """call sprite.draw(screen) to render sprites"""
+    def draw(self, surface):
+        dirty = self.lostsprites
+        self.lostsprites = []
+        for s, r in self.spritedict.items():
+            newrect = s.draw(screen) #Here's the big change
+            if r is 0:
+                dirty.append(newrect)
+            else:
+                dirty.append(newrect.union(r))
+            self.spritedict[s] = newrect
+        return dirty
+
+
+

Following is more information on how you could create your own Sprite and +Group objects from scratch.

+

The Sprite objects only "require" two methods. "add_internal()" and +"remove_internal()". These are called by the Group classes when they are +removing a sprite from themselves. The add_internal() and +remove_internal() have a single argument which is a group. Your Sprite +will need some way to also keep track of the Groups it belongs to. You will +likely want to try to match the other methods and arguments to the real +Sprite class, but if you're not going to use those methods, you sure don't +need them.

+

It is almost the same requirements for creating your own Group. In fact, if +you look at the source you'll see the GroupSingle isn't derived from the +Group class, it just implements the same methods so you can't really tell +the difference. Again you need an "add_internal()" and "remove_internal()" +method that the sprites call when they want to belong or remove themselves from +the group. The add_internal() and remove_internal() have a single +argument which is a sprite. The only other requirement for the Group +classes is they have a dummy attribute named "_spritegroup". It doesn't matter +what the value is, as long as the attribute is present. The Sprite classes can +look for this attribute to determine the difference between a "group" and any +ordinary python container. (This is important, because several sprite methods +can take an argument of a single group, or a sequence of groups. Since they +both look similar, this is the most flexible way to "see" the difference.)

+

You should go through the code for the sprite module. While the code is a bit +"tuned", it's got enough comments to help you follow along. There's even a +TODO section in the source if you feel like contributing.

+
+
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/tut/SurfarrayIntro.html b/venv/Lib/site-packages/pygame/docs/generated/tut/SurfarrayIntro.html new file mode 100644 index 0000000..9bc37f4 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/tut/SurfarrayIntro.html @@ -0,0 +1,661 @@ + + + + + + + + + Pygame Tutorials - Surfarray Introduction — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

Surfarray Introduction

+
+
Author
+

Pete Shinners

+
+
Contact
+

pete@shinners.org

+
+
+
+

Introduction

+

This tutorial will attempt to introduce users to both NumPy and the pygame +surfarray module. To beginners, the code that uses surfarray can be quite +intimidating. But actually there are only a few concepts to understand and +you will be up and running. Using the surfarray module, it becomes possible +to perform pixel level operations from straight python code. The performance +can become quite close to the level of doing the code in C.

+

You may just want to jump down to the "Examples" section to get an +idea of what is possible with this module, then start at the beginning here +to work your way up.

+

Now I won't try to fool you into thinking everything is very easy. To get +more advanced effects by modifying pixel values is very tricky. Just mastering +Numeric Python (SciPy's original array package was Numeric, the predecessor of NumPy) +takes a lot of learning. In this tutorial I'll be sticking with +the basics and using a lot of examples in an attempt to plant seeds of wisdom. +After finishing the tutorial you should have a basic handle on how the surfarray +works.

+
+
+

Numeric Python

+

If you do not have the python NumPy package installed, +you will need to do that now. +You can download the package from the +NumPy Downloads Page +To make sure NumPy is working for you, +you should get something like this from the interactive python prompt.

+
>>> from numpy import *                    #import numeric
+>>> a = array((1,2,3,4,5))                 #create an array
+>>> a                                      #display the array
+array([1, 2, 3, 4, 5])
+>>> a[2]                                   #index into the array
+3
+>>> a*2                                    #new array with twiced values
+array([ 2,  4,  6,  8, 10])
+
+
+

As you can see, the NumPy module gives us a new data type, the array. +This object holds an array of fixed size, and all values inside are of the same +type. The arrays can also be multidimensional, which is how we will use them +with images. There's a bit more to it than this, but it is enough to get us +started.

+

If you look at the last command above, you'll see that mathematical operations +on NumPy arrays apply to all values in the array. This is called "element-wise +operations". These arrays can also be sliced like normal lists. The slicing +syntax is the same as used on standard python objects. +(so study up if you need to :] ). +Here are some more examples of working with arrays.

+
>>> len(a)                                 #get array size
+5
+>>> a[2:]                                  #elements 2 and up
+array([3, 4, 5])
+>>> a[:-2]                                 #all except last 2
+array([1, 2, 3])
+>>> a[2:] + a[:-2]                         #add first and last
+array([4, 6, 8])
+>>> array((1,2,3)) + array((3,4))          #add arrays of wrong sizes
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+ValueError: operands could not be broadcast together with shapes (3,) (2,)
+
+
+

We get an error on the last commend, because we try add together two arrays +that are different sizes. In order for two arrays two operate with each other, +including comparisons and assignment, they must have the same dimensions. It is +very important to know that the new arrays created from slicing the original all +reference the same values. So changing the values in a slice also changes the +original values. It is important how this is done.

+
>>> a                                      #show our starting array
+array([1, 2, 3, 4, 5])
+>>> aa = a[1:3]                            #slice middle 2 elements
+>>> aa                                     #show the slice
+array([2, 3])
+>>> aa[1] = 13                             #chance value in slice
+>>> a                                      #show change in original
+array([ 1, 2, 13,  4,  5])
+>>> aaa = array(a)                         #make copy of array
+>>> aaa                                    #show copy
+array([ 1, 2, 13,  4,  5])
+>>> aaa[1:4] = 0                           #set middle values to 0
+>>> aaa                                    #show copy
+array([1, 0, 0, 0, 5])
+>>> a                                      #show original again
+array([ 1, 2, 13,  4,  5])
+
+
+

Now we will look at small arrays with two +dimensions. Don't be too worried, getting started it is the same as having a +two dimensional tuple (a tuple inside a tuple). Let's get started with +two dimensional arrays.

+
>>> row1 = (1,2,3)                         #create a tuple of vals
+>>> row2 = (3,4,5)                         #another tuple
+>>> (row1,row2)                            #show as a 2D tuple
+((1, 2, 3), (3, 4, 5))
+>>> b = array((row1, row2))                #create a 2D array
+>>> b                                      #show the array
+array([[1, 2, 3],
+       [3, 4, 5]])
+>>> array(((1,2),(3,4),(5,6)))             #show a new 2D array
+array([[1, 2],
+       [3, 4],
+       [5, 6]])
+
+
+

Now with this two +dimensional array (from now on as "2D") we can index specific values +and do slicing on both dimensions. Simply using a comma to separate the indices +allows us to lookup/slice in multiple dimensions. Just using ":" as an +index (or not supplying enough indices) gives us all the values in +that dimension. Let's see how this works.

+
>>> b                                      #show our array from above
+array([[1, 2, 3],
+       [3, 4, 5]])
+>>> b[0,1]                                 #index a single value
+2
+>>> b[1,:]                                 #slice second row
+array([3, 4, 5])
+>>> b[1]                                   #slice second row (same as above)
+array([3, 4, 5])
+>>> b[:,2]                                 #slice last column
+array([3, 5])
+>>> b[:,:2]                                #slice into a 2x2 array
+array([[1, 2],
+       [3, 4]])
+
+
+

Ok, stay with me here, this is about as hard as it gets. When using NumPy +there is one more feature to slicing. Slicing arrays also allow you to specify +a slice increment. The syntax for a slice with increment is +start_index : end_index : increment.

+
>>> c = arange(10)                         #like range, but makes an array
+>>> c                                      #show the array
+array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
+>>> c[1:6:2]                               #slice odd values from 1 to 6
+array([1, 3, 5])
+>>> c[4::4]                                #slice every 4th val starting at 4
+array([4, 8])
+>>> c[8:1:-1]                              #slice 1 to 8, reversed
+array([8, 7, 6, 5, 4, 3, 2])
+
+
+

Well that is it. There's enough information there to get you started using +NumPy with the surfarray module. There's certainly a lot more to NumPy, but +this is only an introduction. Besides, we want to get on to the fun stuff, +correct?

+
+
+

Import Surfarray

+

In order to use the surfarray module we need to import it. Since both surfarray +and NumPy are optional components for pygame, it is nice to make sure they +import correctly before using them. In these examples I'm going to import +NumPy into a variable named N. This will let you know which functions +I'm using are from the NumPy package. +(and is a lot shorter than typing NumPy before each function)

+
try:
+    import numpy as N
+    import pygame.surfarray as surfarray
+except ImportError:
+    raise ImportError, "NumPy and Surfarray are required."
+
+
+
+
+

Surfarray Introduction

+

There are two main types of functions in surfarray. One set of functions for +creating an array that is a copy of a surface pixel data. The other functions +create a referenced copy of the array pixel data, so that changes to the array +directly affect the original surface. There are other functions that allow you +to access any per-pixel alpha values as arrays along with a few other helpful +functions. We will look at these other functions later on.

+

When working with these surface arrays, there are two ways of representing the +pixel values. First, they can be represented as mapped integers. This type of +array is a simple 2D array with a single integer representing the surface's +mapped color value. This type of array is good for moving parts of an image +around. The other type of array uses three RGB values to represent each pixel +color. This type of array makes it extremely simple to do types of effects that +change the color of each pixel. This type of array is also a little trickier to +deal with, since it is essentially a 3D numeric array. Still, once you get your +mind into the right mode, it is not much harder than using the normal 2D arrays.

+

The NumPy module uses a machine's natural number types to represent the data +values, so a NumPy array can consist of integers that are 8-bits, 16-bits, and 32-bits. +(the arrays can also use other types like floats and doubles, but for our image +manipulation we mainly need to worry about the integer types). +Because of this limitation of integer sizes, you must take a little extra care +that the type of arrays that reference pixel data can be properly mapped to a +proper type of data. The functions create these arrays from surfaces are:

+
+
+surfarray.pixels2d(surface)
+

Creates a 2D array (integer pixel values) that reference the original surface data. +This will work for all surface formats except 24-bit.

+
+ +
+
+surfarray.array2d(surface)
+

Creates a 2D array (integer pixel values) that is copied from any type of surface.

+
+ +
+
+surfarray.pixels3d(surface)
+

Creates a 3D array (RGB pixel values) that reference the original surface data. +This will only work on 24-bit and 32-bit surfaces that have RGB or BGR formatting.

+
+ +
+
+surfarray.array3d(surface)
+

Creates a 3D array (RGB pixel values) that is copied from any type of surface.

+
+ +

Here is a small chart that might better illustrate what types of functions +should be used on which surfaces. As you can see, both the arrayXD functions +will work with any type of surface.

+ +++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

32-bit

24-bit

16-bit

8-bit(c-map)

pixel2d

yes

yes

yes

array2d

yes

yes

yes

yes

pixel3d

yes

yes

array3d

yes

yes

yes

yes

+
+
+

Examples

+

With this information, we are equipped to start trying things with surface +arrays. The following are short little demonstrations that create a NumPy +array and display them in pygame. These different tests are found in the +arraydemo.py example. There is a simple function named surfdemo_show +that displays an array on the screen.

+
+
+allblack +
allblack = N.zeros((128, 128))
+surfdemo_show(allblack, 'allblack')
+
+
+

Our first example creates an all black array. Whenever you need +to create a new numeric array of a specific size, it is best to use the +zeros function. Here we create a 2D array of all zeros and display +it.

+
+
+
+
+striped +
striped = N.zeros((128, 128, 3))
+striped[:] = (255, 0, 0)
+striped[:,::3] = (0, 255, 255)
+surfdemo_show(striped, 'striped')
+
+
+

Here we are dealing with a 3D array. We start by creating an all red image. +Then we slice out every third row and assign it to a blue/green color. As you +can see, we can treat the 3D arrays almost exactly the same as 2D arrays, just +be sure to assign them 3 values instead of a single mapped integer.

+
+
+
+
+rgbarray +
imgsurface = pygame.image.load('surfarray.png')
+rgbarray = surfarray.array3d(imgsurface)
+surfdemo_show(rgbarray, 'rgbarray')
+
+
+

Here we load an image with the image module, then convert it to a 3D +array of integer RGB color elements. An RGB copy of a surface always +has the colors arranged as a[r,c,0] for the red component, +a[r,c,1] for the green component, and a[r,c,2] for blue. This can then +be used without caring how the pixels of the actual surface are configured, +unlike a 2D array which is a copy of the mapped +(raw) surface pixels. We will use this image in the rest of the samples.

+
+
+
+
+flipped +
flipped = rgbarray[:,::-1]
+surfdemo_show(flipped, 'flipped')
+
+
+

Here we flip the image vertically. All we need to do is take the original +image array and slice it using a negative increment.

+
+
+
+
+scaledown +
scaledown = rgbarray[::2,::2]
+surfdemo_show(scaledown, 'scaledown')
+
+
+

Based on the last example, scaling an image down is pretty logical. We just +slice out all the pixels using an increment of 2 vertically and horizontally.

+
+
+
+
+scaleup +
shape = rgbarray.shape
+scaleup = N.zeros((shape[0]*2, shape[1]*2, shape[2]))
+scaleup[::2,::2,:] = rgbarray
+scaleup[1::2,::2,:] = rgbarray
+scaleup[:,1::2] = scaleup[:,::2]
+surfdemo_show(scaleup, 'scaleup')
+
+
+

Scaling the image up is a little more work, but is similar to the previous +scaling down, we do it all with slicing. First we create an array that is +double the size of our original. First we copy the original array into every +other pixel of the new array. Then we do it again for every other pixel doing +the odd columns. At this point we have the image scaled properly going across, +but every other row is black, so we simply need to copy each row to the one +underneath it. Then we have an image doubled in size.

+
+
+
+
+redimg +
redimg = N.array(rgbarray)
+redimg[:,:,1:] = 0
+surfdemo_show(redimg, 'redimg')
+
+
+

Now we are using 3D arrays to change the colors. Here we +set all the values in green and blue to zero. +This leaves us with just the red channel.

+
+
+
+
+soften +
factor = N.array((8,), N.int32)
+soften = N.array(rgbarray, N.int32)
+soften[1:,:]  += rgbarray[:-1,:] * factor
+soften[:-1,:] += rgbarray[1:,:] * factor
+soften[:,1:]  += rgbarray[:,:-1] * factor
+soften[:,:-1] += rgbarray[:,1:] * factor
+soften //= 33
+surfdemo_show(soften, 'soften')
+
+
+

Here we perform a 3x3 convolution filter that will soften our image. +It looks like a lot of steps here, but what we are doing is shifting +the image 1 pixel in each direction and adding them all together (with some +multiplication for weighting). Then average all the values. It's no Gaussian, +but it's fast. One point with NumPy arrays, the precision of arithmetic +operations is determined by the array with the largest data type. +So if factor was not declared as a 1 element array of type numpy.int32, +the multiplications would be performed using numpy.int8, the 8 bit integer +type of each rgbarray element. This will cause value truncation. The soften +array must also be declared to have a larger integer size than rgbarray to +avoid truncation.

+
+
+
+
+xfade +
src = N.array(rgbarray)
+dest = N.zeros(rgbarray.shape)
+dest[:] = 20, 50, 100
+diff = (dest - src) * 0.50
+xfade = src + diff.astype(N.uint)
+surfdemo_show(xfade, 'xfade')
+
+
+

Lastly, we are cross fading between the original image and a solid bluish +image. Not exciting, but the dest image could be anything, and changing the 0.50 +multiplier will let you choose any step in a linear crossfade between two images.

+
+
+
+
+

Hopefully by this point you are starting to see how surfarray can be used to +perform special effects and transformations that are only possible at the pixel +level. At the very least, you can use the surfarray to do a lot of Surface.set_at() +Surface.get_at() type operations very quickly. But don't think you are finished +yet, there is still much to learn.

+
+
+

Surface Locking

+

Like the rest of pygame, surfarray will lock any Surfaces it needs to +automatically when accessing pixel data. There is one extra thing to be aware +of though. When creating the pixel arrays, the original surface will +be locked during the lifetime of that pixel array. This is important to remember. +Be sure to "del" the pixel array or let it go out of scope +(ie, when the function returns, etc).

+

Also be aware that you really don't want to be doing much (if any) +direct pixel access on hardware surfaces (HWSURFACE). This is because +the actual surface data lives on the graphics card, and transferring pixel +changes over the PCI/AGP bus is not fast.

+
+
+

Transparency

+

The surfarray module has several methods for accessing a Surface's alpha/colorkey +values. None of the alpha functions are affected by overall transparency of a +Surface, just the pixel alpha values. Here's the list of those functions.

+
+
+surfarray.pixels_alpha(surface)
+

Creates a 2D array (integer pixel values) that references the original +surface alpha data. +This will only work on 32-bit images with an 8-bit alpha component.

+
+ +
+
+surfarray.array_alpha(surface)
+

Creates a 2D array (integer pixel values) that is copied from any +type of surface. +If the surface has no alpha values, +the array will be fully opaque values (255).

+
+ +
+
+surfarray.array_colorkey(surface)
+

Creates a 2D array (integer pixel values) that is set to transparent +(0) wherever that pixel color matches the Surface colorkey.

+
+ +
+
+

Other Surfarray Functions

+

There are only a few other functions available in surfarray. You can get a better +list with more documentation on the +surfarray reference page. +There is one very useful function though.

+
+
+surfarray.blit_array(surface, array)
+

This will transfer any type of 2D or 3D surface array onto a Surface +of the same dimensions. +This surfarray blit will generally be faster than assigning an array to a +referenced pixel array. +Still, it should not be as fast as normal Surface blitting, +since those are very optimized.

+
+ +
+
+

More Advanced NumPy

+

There's a couple last things you should know about NumPy arrays. When dealing +with very large arrays, like the kind that are 640x480 big, there are some extra +things you should be careful about. Mainly, while using the operators like + and +* on the arrays makes them easy to use, it is also very expensive on big arrays. +These operators must make new temporary copies of the array, that are then +usually copied into another array. This can get very time consuming. Fortunately, +all the NumPy operators come with special functions that can perform the +operation "in place". For example, you would want to replace +screen[:] = screen + brightmap with the much faster +add(screen, brightmap, screen). +Anyway, you'll want to read up on the NumPy UFunc +documentation for more about this. +It is important when dealing with the arrays.

+

Another thing to be aware of when working with NumPy arrays is the datatype +of the array. Some of the arrays (especially the mapped pixel type) often return +arrays with an unsigned 8-bit value. These arrays will easily overflow if you are +not careful. NumPy will use the same coercion that you find in C programs, so +mixing an operation with 8-bit numbers and 32-bit numbers will give a result as +32-bit numbers. You can convert the datatype of an array, but definitely be +aware of what types of arrays you have, if NumPy gets in a situation where +precision would be ruined, it will raise an exception.

+

Lastly, be aware that when assigning values into the 3D arrays, they must be +between 0 and 255, or you will get some undefined truncating.

+
+
+

Graduation

+

Well there you have it. My quick primer on Numeric Python and surfarray. +Hopefully now you see what is possible, and even if you never use them for +yourself, you do not have to be afraid when you see code that does. Look into +the vgrade example for more numeric array action. There are also some "flame" +demos floating around that use surfarray to create a realtime fire effect.

+

Best of all, try some things on your own. Take it slow at first and build up, +I've seen some great things with surfarray already like radial gradients and +more. Good Luck.

+
+
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/tut/chimp.py.html b/venv/Lib/site-packages/pygame/docs/generated/tut/chimp.py.html new file mode 100644 index 0000000..3d2925f --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/tut/chimp.py.html @@ -0,0 +1,342 @@ + + + + + + + + + pygame/examples/chimp.py — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
#!/usr/bin/env python
+""" pygame.examples.chimp
+
+This simple example is used for the line-by-line tutorial
+that comes with pygame. It is based on a 'popular' web banner.
+Note there are comments here, but for the full explanation,
+follow along in the tutorial.
+"""
+
+
+# Import Modules
+import os
+import pygame as pg
+
+if not pg.font:
+    print("Warning, fonts disabled")
+if not pg.mixer:
+    print("Warning, sound disabled")
+
+main_dir = os.path.split(os.path.abspath(__file__))[0]
+data_dir = os.path.join(main_dir, "data")
+
+
+# functions to create our resources
+def load_image(name, colorkey=None, scale=1):
+    fullname = os.path.join(data_dir, name)
+    image = pg.image.load(fullname)
+    image = image.convert()
+
+    size = image.get_size()
+    size = (size[0] * scale, size[1] * scale)
+    image = pg.transform.scale(image, size)
+
+    if colorkey is not None:
+        if colorkey == -1:
+            colorkey = image.get_at((0, 0))
+        image.set_colorkey(colorkey, pg.RLEACCEL)
+    return image, image.get_rect()
+
+
+def load_sound(name):
+    class NoneSound:
+        def play(self):
+            pass
+
+    if not pg.mixer or not pg.mixer.get_init():
+        return NoneSound()
+
+    fullname = os.path.join(data_dir, name)
+    sound = pg.mixer.Sound(fullname)
+
+    return sound
+
+
+# classes for our game objects
+class Fist(pg.sprite.Sprite):
+    """moves a clenched fist on the screen, following the mouse"""
+
+    def __init__(self):
+        pg.sprite.Sprite.__init__(self)  # call Sprite initializer
+        self.image, self.rect = load_image("fist.png", -1)
+        self.fist_offset = (-235, -80)
+        self.punching = False
+
+    def update(self):
+        """move the fist based on the mouse position"""
+        pos = pg.mouse.get_pos()
+        self.rect.topleft = pos
+        self.rect.move_ip(self.fist_offset)
+        if self.punching:
+            self.rect.move_ip(15, 25)
+
+    def punch(self, target):
+        """returns true if the fist collides with the target"""
+        if not self.punching:
+            self.punching = True
+            hitbox = self.rect.inflate(-5, -5)
+            return hitbox.colliderect(target.rect)
+
+    def unpunch(self):
+        """called to pull the fist back"""
+        self.punching = False
+
+
+class Chimp(pg.sprite.Sprite):
+    """moves a monkey critter across the screen. it can spin the
+    monkey when it is punched."""
+
+    def __init__(self):
+        pg.sprite.Sprite.__init__(self)  # call Sprite intializer
+        self.image, self.rect = load_image("chimp.png", -1, 4)
+        screen = pg.display.get_surface()
+        self.area = screen.get_rect()
+        self.rect.topleft = 10, 90
+        self.move = 18
+        self.dizzy = False
+
+    def update(self):
+        """walk or spin, depending on the monkeys state"""
+        if self.dizzy:
+            self._spin()
+        else:
+            self._walk()
+
+    def _walk(self):
+        """move the monkey across the screen, and turn at the ends"""
+        newpos = self.rect.move((self.move, 0))
+        if not self.area.contains(newpos):
+            if self.rect.left < self.area.left or self.rect.right > self.area.right:
+                self.move = -self.move
+                newpos = self.rect.move((self.move, 0))
+                self.image = pg.transform.flip(self.image, True, False)
+        self.rect = newpos
+
+    def _spin(self):
+        """spin the monkey image"""
+        center = self.rect.center
+        self.dizzy = self.dizzy + 12
+        if self.dizzy >= 360:
+            self.dizzy = False
+            self.image = self.original
+        else:
+            rotate = pg.transform.rotate
+            self.image = rotate(self.original, self.dizzy)
+        self.rect = self.image.get_rect(center=center)
+
+    def punched(self):
+        """this will cause the monkey to start spinning"""
+        if not self.dizzy:
+            self.dizzy = True
+            self.original = self.image
+
+
+def main():
+    """this function is called when the program starts.
+    it initializes everything it needs, then runs in
+    a loop until the function returns."""
+    # Initialize Everything
+    pg.init()
+    screen = pg.display.set_mode((1280, 480), pg.SCALED)
+    pg.display.set_caption("Monkey Fever")
+    pg.mouse.set_visible(False)
+
+    # Create The Backgound
+    background = pg.Surface(screen.get_size())
+    background = background.convert()
+    background.fill((170, 238, 187))
+
+    # Put Text On The Background, Centered
+    if pg.font:
+        font = pg.font.Font(None, 64)
+        text = font.render("Pummel The Chimp, And Win $$$", True, (10, 10, 10))
+        textpos = text.get_rect(centerx=background.get_width() / 2, y=10)
+        background.blit(text, textpos)
+
+    # Display The Background
+    screen.blit(background, (0, 0))
+    pg.display.flip()
+
+    # Prepare Game Objects
+    whiff_sound = load_sound("whiff.wav")
+    punch_sound = load_sound("punch.wav")
+    chimp = Chimp()
+    fist = Fist()
+    allsprites = pg.sprite.RenderPlain((chimp, fist))
+    clock = pg.time.Clock()
+
+    # Main Loop
+    going = True
+    while going:
+        clock.tick(60)
+
+        # Handle Input Events
+        for event in pg.event.get():
+            if event.type == pg.QUIT:
+                going = False
+            elif event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE:
+                going = False
+            elif event.type == pg.MOUSEBUTTONDOWN:
+                if fist.punch(chimp):
+                    punch_sound.play()  # punch
+                    chimp.punched()
+                else:
+                    whiff_sound.play()  # miss
+            elif event.type == pg.MOUSEBUTTONUP:
+                fist.unpunch()
+
+        allsprites.update()
+
+        # Draw Everything
+        screen.blit(background, (0, 0))
+        allsprites.draw(screen)
+        pg.display.flip()
+
+    pg.quit()
+
+
+# Game Over
+
+
+# this calls the 'main' function when this script is executed
+if __name__ == "__main__":
+    main()
+
+
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/tut/newbieguide.html b/venv/Lib/site-packages/pygame/docs/generated/tut/newbieguide.html new file mode 100644 index 0000000..b5e36a6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/tut/newbieguide.html @@ -0,0 +1,475 @@ + + + + + + + + + A Newbie Guide to pygame — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

A Newbie Guide to pygame

+

or Things I learned by trial and error so you don't have to,

+

or How I learned to stop worrying and love the blit.

+

Pygame is a python wrapper for SDL, written by Pete Shinners. What this +means is that, using pygame, you can write games or other multimedia +applications in Python that will run unaltered on any of SDL's supported +platforms (Windows, Unix, Mac, BeOS and others).

+

Pygame may be easy to learn, but the world of graphics programming can be +pretty confusing to the newcomer. I wrote this to try to distill the practical +knowledge I've gained over the past year or so of working with pygame, and its +predecessor, PySDL. I've tried to rank these suggestions in order of +importance, but how relevant any particular hint is will depend on your own +background and the details of your project.

+
+

Get comfortable working in Python.

+

The most important thing is to feel confident using python. Learning something +as potentially complicated as graphics programming will be a real chore if +you're also unfamiliar with the language you're using. Write a few sizable +non-graphical programs in python -- parse some text files, write a guessing +game or a journal-entry program or something. Get comfortable with string and +list manipulation -- know how to split, slice and combine strings and lists. +Know how import works -- try writing a program that is spread across +several source files. Write your own functions, and practice manipulating +numbers and characters; know how to convert between the two. Get to the point +where the syntax for using lists and dictionaries is second-nature -- you don't +want to have to run to the documentation every time you need to slice a list or +sort a set of keys. Resist the temptation to run to a mailing list, +comp.lang.python, or IRC when you run into trouble. Instead, fire up the +interpreter and play with the problem for a few hours. Print out the Python +2.0 Quick Reference and keep it by your computer.

+

This may sound incredibly dull, but the confidence you'll gain through your +familiarity with python will work wonders when it comes time to write your +game. The time you spend making python code second-nature will be nothing +compared to the time you'll save when you're writing real code.

+
+
+

Recognize which parts of pygame you really need.

+

Looking at the jumble of classes at the top of the pygame Documentation index +may be confusing. The important thing is to realize that you can do a great +deal with only a tiny subset of functions. Many classes you'll probably never +use -- in a year, I haven't touched the Channel, Joystick, cursors, +Userrect, surfarray or version functions.

+
+
+

Know what a surface is.

+

The most important part of pygame is the surface. Just think of a surface as a +blank piece of paper. You can do a lot of things with a surface -- you can +draw lines on it, fill parts of it with color, copy images to and from it, and +set or read individual pixel colors on it. A surface can be any size (within +reason) and you can have as many of them as you like (again, within reason). +One surface is special -- the one you create with +pygame.display.set_mode(). This 'display surface' represents the screen; +whatever you do to it will appear on the user's screen. You can only have one +of these -- that's an SDL limitation, not a pygame one.

+

So how do you create surfaces? As mentioned above, you create the special +'display surface' with pygame.display.set_mode(). You can create a surface +that contains an image by using image.load(), or you can make a surface +that contains text with font.render(). You can even create a surface that +contains nothing at all with Surface().

+

Most of the surface functions are not critical. Just learn blit(), +fill(), set_at() and get_at(), and you'll be fine.

+
+
+

Use surface.convert().

+

When I first read the documentation for surface.convert(), I didn't think +it was something I had to worry about. 'I only use PNGs, therefore everything I +do will be in the same format. So I don't need convert()';. It turns out I +was very, very wrong.

+

The 'format' that convert() refers to isn't the file format (ie PNG, +JPEG, GIF), it's what's called the 'pixel format'. This refers to the +particular way that a surface records individual colors in a specific pixel. +If the surface format isn't the same as the display format, SDL will have to +convert it on-the-fly for every blit -- a fairly time-consuming process. Don't +worry too much about the explanation; just note that convert() is necessary +if you want to get any kind of speed out of your blits.

+

How do you use convert? Just call it after creating a surface with the +image.load() function. Instead of just doing:

+
surface = pygame.image.load('foo.png')
+
+
+

Do:

+
surface = pygame.image.load('foo.png').convert()
+
+
+

It's that easy. You just need to call it once per surface, when you load an +image off the disk. You'll be pleased with the results; I see about a 6x +increase in blitting speed by calling convert().

+

The only times you don't want to use convert() is when you really need to +have absolute control over an image's internal format -- say you were writing +an image conversion program or something, and you needed to ensure that the +output file had the same pixel format as the input file. If you're writing a +game, you need speed. Use convert().

+
+
+

Dirty rect animation.

+

The most common cause of inadequate frame rates in pygame programs results from +misunderstanding the pygame.display.update() function. With pygame, merely +drawing something to the display surface doesn't cause it to appear on the +screen -- you need to call pygame.display.update(). There are three ways +of calling this function:

+
+
    +
  • pygame.display.update() -- This updates the whole window (or the whole screen for fullscreen displays).

  • +
  • pygame.display.flip() -- This does the same thing, and will also do the right thing if you're using double-buffered hardware acceleration, which you're not, so on to...

  • +
  • pygame.display.update(a rectangle or some list of rectangles) -- This updates just the rectangular areas of the screen you specify.

  • +
+
+

Most people new to graphics programming use the first option -- they update the +whole screen every frame. The problem is that this is unacceptably slow for +most people. Calling update() takes 35 milliseconds on my machine, which +doesn't sound like much, until you realize that 1000 / 35 = 28 frames per +second maximum. And that's with no game logic, no blits, no input, no AI, +nothing. I'm just sitting there updating the screen, and 28 fps is my maximum +framerate. Ugh.

+

The solution is called 'dirty rect animation'. Instead of updating the whole +screen every frame, only the parts that changed since the last frame are +updated. I do this by keeping track of those rectangles in a list, then +calling update(the_dirty_rectangles) at the end of the frame. In detail +for a moving sprite, I:

+
+
    +
  • Blit a piece of the background over the sprite's current location, erasing it.

  • +
  • Append the sprite's current location rectangle to a list called dirty_rects.

  • +
  • Move the sprite.

  • +
  • Draw the sprite at its new location.

  • +
  • Append the sprite's new location to my dirty_rects list.

  • +
  • Call display.update(dirty_rects)

  • +
+
+

The difference in speed is astonishing. Consider that SolarWolf has dozens of +constantly moving sprites updating smoothly, and still has enough time left +over to display a parallax starfield in the background, and update that too.

+

There are two cases where this technique just won't work. The first is where +the whole window or screen really is being updated every frame -- think of a +smooth-scrolling engine like an overhead real-time strategy game or a +side-scroller. So what do you do in this case? Well, the short answer is -- +don't write this kind of game in pygame. The long answer is to scroll in steps +of several pixels at a time; don't try to make scrolling perfectly smooth. +Your player will appreciate a game that scrolls quickly, and won't notice the +background jumping along too much.

+

A final note -- not every game requires high framerates. A strategic wargame +could easily get by on just a few updates per second -- in this case, the added +complexity of dirty rect animation may not be necessary.

+
+
+

There is NO rule six.

+
+
+

Hardware surfaces are more trouble than they're worth.

+

Especially in pygame 2, because HWSURFACE now does nothing

+

If you've been looking at the various flags you can use with +pygame.display.set_mode(), you may have thought like this: Hey, +HWSURFACE! Well, I want that -- who doesn't like hardware acceleration. Ooo... +DOUBLEBUF; well, that sounds fast, I guess I want that too!. It's not +your fault; we've been trained by years of 3-d gaming to believe that hardware +acceleration is good, and software rendering is slow.

+

Unfortunately, hardware rendering comes with a long list of drawbacks:

+
+
    +
  • It only works on some platforms. Windows machines can usually get hardware surfaces if you ask for them. Most other platforms can't. Linux, for example, may be able to provide a hardware surface if X4 is installed, if DGA2 is working properly, and if the moons are aligned correctly. If a hardware surface is unavailable, SDL will silently give you a software surface instead.

  • +
  • It only works fullscreen.

  • +
  • It complicates per-pixel access. If you have a hardware surface, you need to Lock the surface before writing or reading individual pixel values on it. If you don't, Bad Things Happen. Then you need to quickly Unlock the surface again, before the OS gets all confused and starts to panic. Most of this process is automated for you in pygame, but it's something else to take into account.

  • +
  • You lose the mouse pointer. If you specify HWSURFACE (and actually get it), your pointer will usually just vanish (or worse, hang around in a half-there, half-not flickery state). You'll need to create a sprite to act as a manual mouse pointer, and you'll need to worry about pointer acceleration and sensitivity. What a pain.

  • +
  • It might be slower anyway. Many drivers are not accelerated for the types of drawing that we do, and since everything has to be blitted across the video bus (unless you can cram your source surface into video memory as well), it might end up being slower than software access anyway.

  • +
+
+

Hardware rendering has its place. It works pretty reliably under Windows, so +if you're not interested in cross-platform performance, it may provide you with +a substantial speed increase. However, it comes at a cost -- increased +headaches and complexity. It's best to stick with good old reliable +SWSURFACE until you're sure you know what you're doing.

+
+
+

Don't get distracted by side issues.

+

Sometimes, new game programmers spend too much time worrying about issues that +aren't really critical to their game's success. The desire to get secondary +issues 'right' is understandable, but early in the process of creating a game, +you cannot even know what the important questions are, let alone what answers +you should choose. The result can be a lot of needless prevarication.

+

For example, consider the question of how to organize your graphics files. +Should each frame have its own graphics file, or each sprite? Perhaps all the +graphics should be zipped up into one archive? A great deal of time has been +wasted on a lot of projects, asking these questions on mailing lists, debating +the answers, profiling, etc, etc. This is a secondary issue; any time spent +discussing it should have been spent coding the actual game.

+

The insight here is that it is far better to have a 'pretty good' solution that +was actually implemented, than a perfect solution that you never got around to +writing.

+
+
+

Rects are your friends.

+

Pete Shinners' wrapper may have cool alpha effects and fast blitting speeds, +but I have to admit my favorite part of pygame is the lowly Rect class. A +rect is simply a rectangle -- defined only by the position of its top left +corner, its width, and its height. Many pygame functions take rects as +arguments, and they also take 'rectstyles', a sequence that has the same values +as a rect. So if I need a rectangle that defines the area between 10, 20 and +40, 50, I can do any of the following:

+
rect = pygame.Rect(10, 20, 30, 30)
+rect = pygame.Rect((10, 20, 30, 30))
+rect = pygame.Rect((10, 20), (30, 30))
+rect = (10, 20, 30, 30)
+rect = ((10, 20, 30, 30))
+
+
+

If you use any of the first three versions, however, you get access to Rect's +utility functions. These include functions to move, shrink and inflate rects, +find the union of two rects, and a variety of collision-detection functions.

+

For example, suppose I'd like to get a list of all the sprites that contain a +point (x, y) -- maybe the player clicked there, or maybe that's the current +location of a bullet. It's simple if each sprite has a .rect member -- I just +do:

+
sprites_clicked = [sprite for sprite in all_my_sprites_list if sprite.rect.collidepoint(x, y)]
+
+
+

Rects have no other relation to surfaces or graphics functions, other than the +fact that you can use them as arguments. You can also use them in places that +have nothing to do with graphics, but still need to be defined as rectangles. +Every project I discover a few new places to use rects where I never thought +I'd need them.

+
+
+

Don't bother with pixel-perfect collision detection.

+

So you've got your sprites moving around, and you need to know whether or not they're bumping into one another. It's tempting to write something like the following:

+
+
    +
  • Check to see if the rects are in collision. If they aren't, ignore them.

  • +
  • For each pixel in the overlapping area, see if the corresponding pixels from both sprites are opaque. If so, there's a collision.

  • +
+
+

There are other ways to do this, with ANDing sprite masks and so on, but any +way you do it in pygame, it's probably going to be too slow. For most games, +it's probably better just to do 'sub-rect collision' -- create a rect for each +sprite that's a little smaller than the actual image, and use that for +collisions instead. It will be much faster, and in most cases the player won't +notice the imprecision.

+
+
+

Managing the event subsystem.

+

Pygame's event system is kind of tricky. There are actually two different ways +to find out what an input device (keyboard, mouse or joystick) is doing.

+

The first is by directly checking the state of the device. You do this by +calling, say, pygame.mouse.get_pos() or pygame.key.get_pressed(). +This will tell you the state of that device at the moment you call the +function.

+

The second method uses the SDL event queue. This queue is a list of events -- +events are added to the list as they're detected, and they're deleted from the +queue as they're read off.

+

There are advantages and disadvantages to each system. State-checking (system +1) gives you precision -- you know exactly when a given input was made -- if +mouse.get_pressed([0]) is 1, that means that the left mouse button is +down right at this moment. The event queue merely reports that the +mouse was down at some time in the past; if you check the queue fairly often, +that can be ok, but if you're delayed from checking it by other code, input +latency can grow. Another advantage of the state-checking system is that it +detects "chording" easily; that is, several states at the same time. If you +want to know whether the t and f keys are down at the same time, just +check:

+
if (key.get_pressed[K_t] and key.get_pressed[K_f]):
+    print "Yup!"
+
+
+

In the queue system, however, each keypress arrives in the queue as a +completely separate event, so you'd need to remember that the t key was +down, and hadn't come up yet, while checking for the f key. A little more +complicated.

+

The state system has one great weakness, however. It only reports what the +state of the device is at the moment it's called; if the user hits a mouse +button then releases it just before a call to mouse.get_pressed(), the +mouse button will return 0 -- get_pressed() missed the mouse button press +completely. The two events, MOUSEBUTTONDOWN and MOUSEBUTTONUP, will +still be sitting in the event queue, however, waiting to be retrieved and +processed.

+

The lesson is: choose the system that meets your requirements. If you don't +have much going on in your loop -- say you're just sitting in a while 1 +loop, waiting for input, use get_pressed() or another state function; the +latency will be lower. On the other hand, if every keypress is crucial, but +latency isn't as important -- say your user is typing something in an editbox, +use the event queue. Some keypresses may be slightly late, but at least you'll +get them all.

+

A note about event.poll() vs. wait() -- poll() may seem better, +since it doesn't block your program from doing anything while it's waiting for +input -- wait() suspends the program until an event is received. +However, poll() will consume 100% of available CPU time while it runs, +and it will fill the event queue with NOEVENTS. Use set_blocked() to +select just those event types you're interested in -- your queue will be much +more manageable.

+
+
+

Colorkey vs. Alpha.

+

There's a lot of confusion around these two techniques, and much of it comes from the terminology used.

+

'Colorkey blitting' involves telling pygame that all pixels of a certain color +in a certain image are transparent instead of whatever color they happen to be. +These transparent pixels are not blitted when the rest of the image is blitted, +and so don't obscure the background. This is how we make sprites that aren't +rectangular in shape. Simply call surface.set_colorkey(color), where +color is an RGB tuple -- say (0,0,0). This would make every pixel in the source +image transparent instead of black.

+

'Alpha' is different, and it comes in two flavors. 'Image alpha' applies to the +whole image, and is probably what you want. Properly known as 'translucency', +alpha causes each pixel in the source image to be only partially opaque. +For example, if you set a surface's alpha to 192 and then blitted it onto a +background, 3/4 of each pixel's color would come from the source image, and 1/4 +from the background. Alpha is measured from 255 to 0, where 0 is completely +transparent, and 255 is completely opaque. Note that colorkey and alpha +blitting can be combined -- this produces an image that is fully transparent in +some spots, and semi-transparent in others.

+

'Per-pixel alpha' is the other flavor of alpha, and it's more complicated. +Basically, each pixel in the source image has its own alpha value, from 0 to +255. Each pixel, therefore, can have a different opacity when blitted onto a +background. This type of alpha can't be mixed with colorkey blitting, +and it overrides per-image alpha. Per-pixel alpha is rarely used in +games, and to use it you have to save your source image in a graphic +editor with a special alpha channel. It's complicated -- don't use it +yet.

+
+
+

Do things the pythony way.

+

A final note (this isn't the least important one; it just comes at the end). +Pygame is a pretty lightweight wrapper around SDL, which is in turn a pretty +lightweight wrapper around your native OS graphics calls. Chances are pretty +good that if your code is still slow, and you've done the things I've mentioned +above, then the problem lies in the way you're addressing your data in python. +Certain idioms are just going to be slow in python no matter what you do. +Luckily, python is a very clear language -- if a piece of code looks awkward or +unwieldy, chances are its speed can be improved, too. Read over Python +Performance Tips for some great advice on how you can improve the speed of +your code. That said, premature optimisation is the root of all evil; if it's +just not fast enough, don't torture the code trying to make it faster. Some +things are just not meant to be :)

+

There you go. Now you know practically everything I know about using pygame. +Now, go write that game!

+
+

David Clark is an avid pygame user and the editor of the Pygame Code +Repository, a showcase for community-submitted python game code. He is also +the author of Twitch, an entirely average pygame arcade game.

+
+
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/tut/tom_games2.html b/venv/Lib/site-packages/pygame/docs/generated/tut/tom_games2.html new file mode 100644 index 0000000..5d54038 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/tut/tom_games2.html @@ -0,0 +1,240 @@ + + + + + + + + + Revision: Pygame fundamentals — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

2. Revision: Pygame fundamentals

+
+

2.1. The basic Pygame game

+

For the sake of revision, and to ensure that you are familiar with the basic structure of a Pygame program, I'll briefly run through +a basic Pygame program, which will display no more than a window with some text in it, that should, by the end, look something like +this (though of course the window decoration will probably be different on your system):

+../_images/tom_basic.png +

The full code for this example looks like this:

+
#!/usr/bin/python
+
+import pygame
+from pygame.locals import *
+
+def main():
+    # Initialise screen
+    pygame.init()
+    screen = pygame.display.set_mode((150, 50))
+    pygame.display.set_caption('Basic Pygame program')
+
+    # Fill background
+    background = pygame.Surface(screen.get_size())
+    background = background.convert()
+    background.fill((250, 250, 250))
+
+    # Display some text
+    font = pygame.font.Font(None, 36)
+    text = font.render("Hello There", 1, (10, 10, 10))
+    textpos = text.get_rect()
+    textpos.centerx = background.get_rect().centerx
+    background.blit(text, textpos)
+
+    # Blit everything to the screen
+    screen.blit(background, (0, 0))
+    pygame.display.flip()
+
+    # Event loop
+    while 1:
+        for event in pygame.event.get():
+            if event.type == QUIT:
+                return
+
+        screen.blit(background, (0, 0))
+        pygame.display.flip()
+
+
+if __name__ == '__main__': main()
+
+
+
+
+

2.2. Basic Pygame objects

+

As you can see, the code consists of three main objects: the screen, the background, and the text. Each of these objects is created +by first calling an instance of an in-built Pygame object, and then modifying it to fit our needs. The screen is a slightly special +case, because we still modify the display through Pygame calls, rather than calling methods belonging to the screen object. But for +all other Pygame objects, we first create the object as a copy of a Pygame object, giving it some attributes, and build our game +objects from them.

+

With the background, we first create a Pygame Surface object, and make it the size of the screen. We then perform the convert() +operation to convert the Surface to a single pixel format. This is more obviously necessary when we have several images and surfaces, +all of different pixel formats, which makes rendering them quite slow. By converting all the surfaces, we can drastically speed up +rendering times. Finally, we fill the background surface with white (255, 255, 255). These values are RGB (Red Green +Blue), and can be worked out from any good paint program.

+

With the text, we require more than one object. First, we create a font object, which defines which font to use, and the size of the +font. Then we create a text object, by using the render method that belongs to our font object, supplying three arguments: +the text to be rendered, whether or not it should be anti-aliased (1=yes, 0=no), and the color of the text (again in RGB format). Next +we create a third text object, which gets the rectangle for the text. The easiest way to understand this is to imagine drawing a +rectangle that will surround all of the text; you can then use this rectangle to get/set the position of the text on the screen. So +in this example we get the rectangle, set its centerx attribute to be the centerx attribute of the +background (so the text's center will be the same as the background's center, i.e. the text will be centered on the screen on the x +axis). We could also set the y coordinate, but it's not any different so I left the text at the top of the screen. As the screen is +small anyway, it didn't seem necessary.

+
+
+

2.3. Blitting

+

Now we have created our game objects, we need to actually render them. If we didn't and we ran the program, we'd just see a +blank window, and the objects would remain invisible. The term used for rendering objects is blitting, which is where +you copy the pixels belonging to said object onto the destination object. So to render the background object, you blit it onto the +screen. In this example, to make things simple, we blit the text onto the background (so the background will now have a copy of the +text on it), and then blit the background onto the screen.

+

Blitting is one of the slowest operations in any game, so you need to be careful not to blit too much onto the screen in every frame. +If you have a background image, and a ball flying around the screen, then you could blit the background and then the ball in every +frame, which would cover up the ball's previous position and render the new ball, but this would be pretty slow. A better solution is +to blit the background onto the area that the ball previously occupied, which can be found by the ball's previous rectangle, and then +blitting the ball, so that you are only blitting two small areas.

+
+
+

2.4. The event loop

+

Once you've set the game up, you need to put it into a loop so that it will continuously run until the user signals that he/she wants +to exit. So you start an open while loop, and then for each iteration of the loop, which will be each frame of the game, +update the game. The first thing is to check for any Pygame events, which will be the user hitting the keyboard, clicking a mouse +button, moving a joystick, resizing the window, or trying to close it. In this case, we simply want to watch out for for user trying +to quit the game by closing the window, in which case the game should return, which will end the while loop. +Then we simply need to re-blit the background, and flip (update) the display to have everything drawn. OK, as nothing moves or happens +in this example, we don't strictly speaking need to re-blit the background in every iteration, but I put it in because when things are +moving around on the screen, you will need to do all your blitting here.

+
+
+

2.5. Ta-da!

+

And that's it - your most basic Pygame game! All games will take a form similar to this, but with lots more code for the actual game +functions themselves, which are more to do your with programming, and less guided in structure by the workings of Pygame. This is what +this tutorial is really about, and will now go onto.

+
+
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/tut/tom_games3.html b/venv/Lib/site-packages/pygame/docs/generated/tut/tom_games3.html new file mode 100644 index 0000000..a17fb21 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/tut/tom_games3.html @@ -0,0 +1,220 @@ + + + + + + + + + Kicking things off — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

3. Kicking things off

+

The first sections of code are relatively simple, and, once written, can usually be reused in every game you consequently make. They +will do all of the boring, generic tasks like loading modules, loading images, opening networking connections, playing music, and so +on. They will also include some simple but effective error handling, and any customisation you wish to provide on top of functions +provided by modules like sys and pygame.

+
+

3.1. The first lines, and loading modules

+

First off, you need to start off your game and load up your modules. It's always a good idea to set a few things straight at the top of +the main source file, such as the name of the file, what it contains, the license it is under, and any other helpful info you might +want to give those will will be looking at it. Then you can load modules, with some error checking so that Python doesn't print out +a nasty traceback, which non-programmers won't understand. The code is fairly simple, so I won't bother explaining any of it:

+
#!/usr/bin/env python
+#
+# Tom's Pong
+# A simple pong game with realistic physics and AI
+# http://www.tomchance.uklinux.net/projects/pong.shtml
+#
+# Released under the GNU General Public License
+
+VERSION = "0.4"
+
+try:
+    import sys
+    import random
+    import math
+    import os
+    import getopt
+    import pygame
+    from socket import *
+    from pygame.locals import *
+except ImportError, err:
+    print "couldn't load module. %s" % (err)
+    sys.exit(2)
+
+
+
+
+

3.2. Resource handling functions

+

In the Line By Line Chimp example, the first code to be written was for loading images and sounds. As these +were totally independent of any game logic or game objects, they were written as separate functions, and were written first so +that later code could make use of them. I generally put all my code of this nature first, in their own, classless functions; these +will, generally speaking, be resource handling functions. You can of course create classes for these, so that you can group them +together, and maybe have an object with which you can control all of your resources. As with any good programming environment, it's up +to you to develop your own best practice and style.

+

It's always a good idea to write your own resource handling functions, +because although Pygame has methods for opening images and sounds, and other modules will have their methods of opening other +resources, those methods can take up more than one line, they can require consistent modification by yourself, and they often don't +provide satisfactory error handling. Writing resource handling functions gives you sophisticated, reusable code, and gives you more +control over your resources. Take this example of an image loading function:

+
def load_png(name):
+    """ Load image and return image object"""
+    fullname = os.path.join('data', name)
+    try:
+        image = pygame.image.load(fullname)
+        if image.get_alpha() is None:
+            image = image.convert()
+        else:
+            image = image.convert_alpha()
+    except pygame.error, message:
+        print 'Cannot load image:', fullname
+        raise SystemExit, message
+    return image, image.get_rect()
+
+
+

Here we make a more sophisticated image loading function than the one provided by pygame.image.load()load new image from a file (or file-like object). Note that +the first line of the function is a documentation string describing what the function does, and what object(s) it returns. The +function assumes that all of your images are in a directory called data, and so it takes the filename and creates the full pathname, +for example data/ball.png, using the os module to ensure cross-platform compatibility. Then it +tries to load the image, and convert any alpha regions so you can achieve transparency, and it returns a more human-readable error +if there's a problem. Finally it returns the image object, and its rect.

+

You can make similar functions for loading any other resources, such as loading sounds. You can also make resource handling classes, +to give you more flexibility with more complex resources. For example, you could make a music class, with an __init__ +function that loads the sound (perhaps borrowing from a load_sound() function), a function to pause the music, and a +function to restart. Another handy resource handling class is for network connections. Functions to open sockets, pass data with +suitable security and error checking, close sockets, finger addresses, and other network tasks, can make writing a game with network +capabilities relatively painless.

+

Remember the chief task of these functions/classes is to ensure that by the time you get around to writing game object classes, +and the main loop, there's almost nothing left to do. Class inheritance can make these basic classes especially handy. Don't go +overboard though; functions which will only be used by one class should be written as part of that class, not as a global +function.

+
+
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/tut/tom_games4.html b/venv/Lib/site-packages/pygame/docs/generated/tut/tom_games4.html new file mode 100644 index 0000000..0504256 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/tut/tom_games4.html @@ -0,0 +1,249 @@ + + + + + + + + + Game object classes — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

4. Game object classes

+

Once you've loaded your modules, and written your resource handling functions, you'll want to get on to writing some game objects. +The way this is done is fairly simple, though it can seem complex at first. You write a class for each type of object in the game, +and then create an instance of those classes for the objects. You can then use those classes' methods to manipulate the objects, +giving objects some motion and interactive capabilities. So your game, in pseudo-code, will look like this:

+
#!/usr/bin/python
+
+# [load modules here]
+
+# [resource handling functions here]
+
+class Ball:
+    # [ball functions (methods) here]
+    # [e.g. a function to calculate new position]
+    # [and a function to check if it hits the side]
+
+def main:
+    # [initiate game environment here]
+
+    # [create new object as instance of ball class]
+    ball = Ball()
+
+    while 1:
+        # [check for user input]
+
+        # [call ball's update function]
+        ball.update()
+
+
+

This is, of course, a very simple example, and you'd need to put in all the code, instead of those little bracketed comments. But +you should get the basic idea. You crate a class, into which you put all the functions for a ball, including __init__, +which would create all the ball's attributes, and update, which would move the ball to its new position, before blitting +it onto the screen in this position.

+

You can then create more classes for all of your other game objects, and then create instances of them so that you can handle them +easily in the main function and the main program loop. Contrast this with initiating the ball in the main +function, and then having lots of classless functions to manipulate a set ball object, and you'll hopefully see why using classes is +an advantage: It allows you to put all of the code for each object in one place; it makes using objects easier; it makes adding new +objects, and manipulating them, more flexible. Rather than adding more code for each new ball object, you could simply create new +instances of the Ball class for each new ball object. Magic!

+
+

4.1. A simple ball class

+

Here is a simple class with the functions necessary for creating a ball object that will, if the update function is called +in the main loop, move across the screen:

+
class Ball(pygame.sprite.Sprite):
+    """A ball that will move across the screen
+    Returns: ball object
+    Functions: update, calcnewpos
+    Attributes: area, vector"""
+
+    def __init__(self, vector):
+        pygame.sprite.Sprite.__init__(self)
+        self.image, self.rect = load_png('ball.png')
+        screen = pygame.display.get_surface()
+        self.area = screen.get_rect()
+        self.vector = vector
+
+    def update(self):
+        newpos = self.calcnewpos(self.rect,self.vector)
+        self.rect = newpos
+
+    def calcnewpos(self,rect,vector):
+        (angle,z) = vector
+        (dx,dy) = (z*math.cos(angle),z*math.sin(angle))
+        return rect.move(dx,dy)
+
+
+

Here we have the Ball class, with an __init__ function that sets the ball up, an update +function that changes the ball's rectangle to be in the new position, and a calcnewpos function to calculate the ball's +new position based on its current position, and the vector by which it is moving. I'll explain the physics in a moment. The one other +thing to note is the documentation string, which is a little bit longer this time, and explains the basics of the class. These strings +are handy not only to yourself and other programmers looking at the code, but also for tools to parse your code and document it. They +won't make much of a difference in small programs, but with large ones they're invaluable, so it's a good habit to get into.

+
+

4.1.1. Diversion 1: Sprites

+

The other reason for creating a class for each object is sprites. Each image you render in your game will be a sprite object, and so +to begin with, the class for each object should inherit the Sprite class. +This is a really nice feature of Python - class +inheritance. Now the Ball class has all of the functions that come with the Sprite class, and any object +instances of the Ball class will be registered by Pygame as sprites. Whereas with text and the background, which don't +move, it's OK to blit the object onto the background, Pygame handles sprite objects in a different manner, which you'll see when we +look at the whole program's code.

+

Basically, you create both a ball object, and a sprite object for that ball, and you then call the ball's update function on the +sprite object, thus updating the sprite. Sprites also give you sophisticated ways of determining if two objects have collided. +Normally you might just check in the main loop to see if their rectangles overlap, but that would involve a lot of code, which would +be a waste because the Sprite class provides two functions (spritecollide and groupcollide) +to do this for you.

+
+
+

4.1.2. Diversion 2: Vector physics

+

Other than the structure of the Ball class, the notable thing about this code is the vector physics, used to calculate +the ball's movement. With any game involving angular movement, you won't get very far unless you're comfortable with trigonometry, so +I'll just introduce the basics you need to know to make sense of the calcnewpos function.

+

To begin with, you'll notice that the ball has an attribute vector, which is made up of angle and z. +The angle is measured in radians, and will give you the direction in which the ball is moving. Z is the speed at which the ball +moves. So by using this vector, we can determine the direction and speed of the ball, and therefore how much it will move on the x and +y axes:

+../_images/tom_radians.png +

The diagram above illustrates the basic maths behind vectors. In the left hand diagram, you can see the ball's projected movement +represented by the blue line. The length of that line (z) represents its speed, and the angle is the direction in which +it will move. The angle for the ball's movement will always be taken from the x axis on the right, and it is measured clockwise from +that line, as shown in the diagram.

+

From the angle and speed of the ball, we can then work out how much it has moved along the x and y axes. We need to do this because +Pygame doesn't support vectors itself, and we can only move the ball by moving its rectangle along the two axes. So we need to +resolve the angle and speed into its movement on the x axis (dx) and on the y axis (dy). This is a simple matter of +trigonometry, and can be done with the formulae shown in the diagram.

+

If you've studied elementary trigonometry before, none of this should be news to you. But just in case you're forgetful, here are some +useful formulae to remember, that will help you visualise the angles (I find it easier to visualise angles in degrees than in radians!)

+../_images/tom_formulae.png +
+
+
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/tut/tom_games5.html b/venv/Lib/site-packages/pygame/docs/generated/tut/tom_games5.html new file mode 100644 index 0000000..97f8f87 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/tut/tom_games5.html @@ -0,0 +1,238 @@ + + + + + + + + + User-controllable objects — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

5. User-controllable objects

+

So far you can create a Pygame window, and render a ball that will fly across the screen. The next step is to make some bats which +the user can control. This is potentially far more simple than the ball, because it requires no physics (unless your user-controlled +object will move in ways more complex than up and down, e.g. a platform character like Mario, in which case you'll need more physics). +User-controllable objects are pretty easy to create, thanks to Pygame's event queue system, as you'll see.

+
+

5.1. A simple bat class

+

The principle behind the bat class is similar to that of the ball class. You need an __init__ function to initialise the +ball (so you can create object instances for each bat), an update function to perform per-frame changes on the bat before +it is blitted the bat to the screen, and the functions that will define what this class will actually do. Here's some sample code:

+
class Bat(pygame.sprite.Sprite):
+    """Movable tennis 'bat' with which one hits the ball
+    Returns: bat object
+    Functions: reinit, update, moveup, movedown
+    Attributes: which, speed"""
+
+    def __init__(self, side):
+        pygame.sprite.Sprite.__init__(self)
+        self.image, self.rect = load_png('bat.png')
+        screen = pygame.display.get_surface()
+        self.area = screen.get_rect()
+        self.side = side
+        self.speed = 10
+        self.state = "still"
+        self.reinit()
+
+    def reinit(self):
+        self.state = "still"
+        self.movepos = [0,0]
+        if self.side == "left":
+            self.rect.midleft = self.area.midleft
+        elif self.side == "right":
+            self.rect.midright = self.area.midright
+
+    def update(self):
+        newpos = self.rect.move(self.movepos)
+        if self.area.contains(newpos):
+            self.rect = newpos
+        pygame.event.pump()
+
+    def moveup(self):
+        self.movepos[1] = self.movepos[1] - (self.speed)
+        self.state = "moveup"
+
+    def movedown(self):
+        self.movepos[1] = self.movepos[1] + (self.speed)
+        self.state = "movedown"
+
+
+

As you can see, this class is very similar to the ball class in its structure. But there are differences in what each function does. +First of all, there is a reinit function, which is used when a round ends, and the bat needs to be set back in its starting place, +with any attributes set back to their necessary values. Next, the way in which the bat is moved is a little more complex than with the +ball, because here its movement is simple (up/down), but it relies on the user telling it to move, unlike the ball which just keeps +moving in every frame. To make sense of how the ball moves, it is helpful to look at a quick diagram to show the sequence of events:

+../_images/tom_event-flowchart.png +

What happens here is that the person controlling the bat pushes down on the key that moves the bat up. For each iteration of the main +game loop (for every frame), if the key is still held down, then the state attribute of that bat object will be set to +"moving", and the moveup function will be called, causing the ball's y position to be reduced by the value of the +speed attribute (in this example, 10). In other words, so long as the key is held down, the bat will move up the screen +by 10 pixels per frame. The state attribute isn't used here yet, but it's useful to know if you're dealing with spin, or +would like some useful debugging output.

+

As soon as the player lets go of that key, the second set of boxes is invoked, and the state attribute of the bat object +will be set back to "still", and the movepos attribute will be set back to [0,0], meaning that when the update function is called, it won't move the bat any more. So when the player lets go of the key, the bat stops moving. Simple!

+
+

5.1.1. Diversion 3: Pygame events

+

So how do we know when the player is pushing keys down, and then releasing them? With the Pygame event queue system, dummy! It's a +really easy system to use and understand, so this shouldn't take long :) You've already seen the event queue in action in the basic +Pygame program, where it was used to check if the user was quitting the application. The code for moving the bat is about as simple +as that:

+
for event in pygame.event.get():
+    if event.type == QUIT:
+        return
+    elif event.type == KEYDOWN:
+        if event.key == K_UP:
+            player.moveup()
+        if event.key == K_DOWN:
+            player.movedown()
+    elif event.type == KEYUP:
+        if event.key == K_UP or event.key == K_DOWN:
+            player.movepos = [0,0]
+            player.state = "still"
+
+
+

Here assume that you've already created an instance of a bat, and called the object player. You can see the familiar +layout of the for structure, which iterates through each event found in the Pygame event queue, which is retrieved with +the event.get() function. As the user hits keys, pushes mouse buttons and moves the joystick about, those actions are +pumped into the Pygame event queue, and left there until dealt with. So in each iteration of the main game loop, you go through +these events, checking if they're ones you want to deal with, and then dealing with them appropriately. The event.pump() +function that was in the Bat.update function is then called in every iteration to pump out old events, and keep the queue +current.

+

First we check if the user is quitting the program, and quit it if they are. Then we check if any keys are being pushed down, and if +they are, we check if they're the designated keys for moving the bat up and down. If they are, then we call the appropriate moving +function, and set the player state appropriately (though the states moveup and movedown and changed in the moveup() and +movedown() functions, which makes for neater code, and doesn't break encapsulation, which means that you +assign attributes to the object itself, without referring to the name of the instance of that object). Notice here we have three +states: still, moveup, and movedown. Again, these come in handy if you want to debug or calculate spin. We also check if any keys have +been "let go" (i.e. are no longer being held down), and again if they're the right keys, we stop the bat from moving.

+
+
+
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/docs/generated/tut/tom_games6.html b/venv/Lib/site-packages/pygame/docs/generated/tut/tom_games6.html new file mode 100644 index 0000000..3ab1389 --- /dev/null +++ b/venv/Lib/site-packages/pygame/docs/generated/tut/tom_games6.html @@ -0,0 +1,436 @@ + + + + + + + + + Putting it all together — pygame v2.1.2 documentation + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+ +
+
+ +
+
+

6. Putting it all together

+

So far you've learnt all the basics necessary to build a simple game. You should understand how to create Pygame objects, how Pygame +displays objects, how it handles events, and how you can use physics to introduce some motion into your game. Now I'll just show how +you can take all those chunks of code and put them together into a working game. What we need first is to let the ball hit the sides +of the screen, and for the bat to be able to hit the ball, otherwise there's not going to be much game play involved. We do this +using Pygame's collision methods.

+
+

6.1. Let the ball hit sides

+

The basics principle behind making it bounce of the sides is easy to grasp. You grab the coordinates of the four corners of the ball, +and check to see if they correspond with the x or y coordinate of the edge of the screen. So if the top right and top left corners both +have a y coordinate of zero, you know that the ball is currently on the top edge of the screen. We do all this in the update function, +after we've worked out the new position of the ball.

+
if not self.area.contains(newpos):
+      tl = not self.area.collidepoint(newpos.topleft)
+      tr = not self.area.collidepoint(newpos.topright)
+      bl = not self.area.collidepoint(newpos.bottomleft)
+      br = not self.area.collidepoint(newpos.bottomright)
+      if tr and tl or (br and bl):
+              angle = -angle
+      if tl and bl:
+              self.offcourt(player=2)
+      if tr and br:
+              self.offcourt(player=1)
+
+self.vector = (angle,z)
+
+
+

Here we check to see if the area +contains the new position of the ball (it always should, so we needn't have an else clause, +though in other circumstances you might want to consider it. We then check if the coordinates for the four corners +are colliding with the area's edges, and create objects for each result. If they are, the objects will have a value of 1, +or True. If they don't, then the value will be None, or False. We then see if it has hit the top or bottom, and if it +has we change the ball's direction. Handily, using radians we can do this by simply reversing its positive/negative value. +We also check to see if the ball has gone off the sides, and if it has we call the offcourt function. +This, in my game, resets the ball, adds 1 point to the score of the player specified when calling the function, and displays the new score.

+

Finally, we recompile the vector based on the new angle. And that is it. The ball will now merrily bounce off the walls and go +offcourt with good grace.

+
+
+

6.2. Let the ball hit bats

+

Making the ball hit the bats is very similar to making it hit the sides of the screen. We still use the collide method, but this time +we check to see if the rectangles for the ball and either bat collide. In this code I've also put in some extra code to avoid various +glitches. You'll find that you'll have to put all sorts of extra code in to avoid glitches and bugs, so it's good to get used to seeing +it.

+
else:
+    # Deflate the rectangles so you can't catch a ball behind the bat
+    player1.rect.inflate(-3, -3)
+    player2.rect.inflate(-3, -3)
+
+    # Do ball and bat collide?
+    # Note I put in an odd rule that sets self.hit to 1 when they collide, and unsets it in the next
+    # iteration. this is to stop odd ball behaviour where it finds a collision *inside* the
+    # bat, the ball reverses, and is still inside the bat, so bounces around inside.
+    # This way, the ball can always escape and bounce away cleanly
+    if self.rect.colliderect(player1.rect) == 1 and not self.hit:
+        angle = math.pi - angle
+        self.hit = not self.hit
+    elif self.rect.colliderect(player2.rect) == 1 and not self.hit:
+        angle = math.pi - angle
+        self.hit = not self.hit
+    elif self.hit:
+        self.hit = not self.hit
+self.vector = (angle,z)
+
+
+

We start this section with an else statement, because this carries on from the previous chunk of code to check if the ball +hits the sides. It makes sense that if it doesn't hit the sides, it might hit a bat, so we carry on the conditional statement. The +first glitch to fix is to shrink the players' rectangles by 3 pixels in both dimensions, to stop the bat catching a ball that goes +behind them (if you imagine you just move the bat so that as the ball travels behind it, the rectangles overlap, and so normally the +ball would then have been "hit" - this prevents that).

+

Next we check if the rectangles collide, with one more glitch fix. Notice that I've commented on these odd bits of code - it's always +good to explain bits of code that are abnormal, both for others who look at your code, and so you understand it when you come back to +it. The without the fix, the ball might hit a corner of the bat, change direction, and one frame later still find itself inside the +bat. Then it would again think it has been hit, and change its direction. This can happen several times, making the ball's motion +completely unrealistic. So we have a variable, self.hit, which we set to True when it has been hit, and False one frame +later. When we check if the rectangles have collided, we also check if self.hit is True/False, to stop internal bouncing.

+

The important code here is pretty easy to understand. All rectangles have a colliderect +function, into which you feed the rectangle of another object, which returns True if the rectangles do overlap, and False if not. +If they do, we can change the direction by subtracting the current angle from pi (again, a handy trick you can do with radians, +which will adjust the angle by 90 degrees and send it off in the right direction; you might find at this point that a thorough +understanding of radians is in order!). Just to finish the glitch checking, we switch self.hit back to False if it's the frame +after they were hit.

+

We also then recompile the vector. You would of course want to remove the same line in the previous chunk of code, so that you only do +this once after the if-else conditional statement. And that's it! The combined code will now allow the ball to hit sides and bats.

+
+
+

6.3. The Finished product

+

The final product, with all the bits of code thrown together, as well as some other bits ofcode to glue it all together, will look +like this:

+
#
+# Tom's Pong
+# A simple pong game with realistic physics and AI
+# http://www.tomchance.uklinux.net/projects/pong.shtml
+#
+# Released under the GNU General Public License
+
+VERSION = "0.4"
+
+try:
+    import sys
+    import random
+    import math
+    import os
+    import getopt
+    import pygame
+    from socket import *
+    from pygame.locals import *
+except ImportError, err:
+    print "couldn't load module. %s" % (err)
+    sys.exit(2)
+
+def load_png(name):
+    """ Load image and return image object"""
+    fullname = os.path.join('data', name)
+    try:
+        image = pygame.image.load(fullname)
+        if image.get_alpha is None:
+            image = image.convert()
+        else:
+            image = image.convert_alpha()
+    except pygame.error, message:
+        print 'Cannot load image:', fullname
+        raise SystemExit, message
+    return image, image.get_rect()
+
+class Ball(pygame.sprite.Sprite):
+    """A ball that will move across the screen
+    Returns: ball object
+    Functions: update, calcnewpos
+    Attributes: area, vector"""
+
+    def __init__(self, (xy), vector):
+        pygame.sprite.Sprite.__init__(self)
+        self.image, self.rect = load_png('ball.png')
+        screen = pygame.display.get_surface()
+        self.area = screen.get_rect()
+        self.vector = vector
+        self.hit = 0
+
+    def update(self):
+        newpos = self.calcnewpos(self.rect,self.vector)
+        self.rect = newpos
+        (angle,z) = self.vector
+
+        if not self.area.contains(newpos):
+            tl = not self.area.collidepoint(newpos.topleft)
+            tr = not self.area.collidepoint(newpos.topright)
+            bl = not self.area.collidepoint(newpos.bottomleft)
+            br = not self.area.collidepoint(newpos.bottomright)
+            if tr and tl or (br and bl):
+                angle = -angle
+            if tl and bl:
+                #self.offcourt()
+                angle = math.pi - angle
+            if tr and br:
+                angle = math.pi - angle
+                #self.offcourt()
+        else:
+            # Deflate the rectangles so you can't catch a ball behind the bat
+            player1.rect.inflate(-3, -3)
+            player2.rect.inflate(-3, -3)
+
+            # Do ball and bat collide?
+            # Note I put in an odd rule that sets self.hit to 1 when they collide, and unsets it in the next
+            # iteration. this is to stop odd ball behaviour where it finds a collision *inside* the
+            # bat, the ball reverses, and is still inside the bat, so bounces around inside.
+            # This way, the ball can always escape and bounce away cleanly
+            if self.rect.colliderect(player1.rect) == 1 and not self.hit:
+                angle = math.pi - angle
+                self.hit = not self.hit
+            elif self.rect.colliderect(player2.rect) == 1 and not self.hit:
+                angle = math.pi - angle
+                self.hit = not self.hit
+            elif self.hit:
+                self.hit = not self.hit
+        self.vector = (angle,z)
+
+    def calcnewpos(self,rect,vector):
+        (angle,z) = vector
+        (dx,dy) = (z*math.cos(angle),z*math.sin(angle))
+        return rect.move(dx,dy)
+
+class Bat(pygame.sprite.Sprite):
+    """Movable tennis 'bat' with which one hits the ball
+    Returns: bat object
+    Functions: reinit, update, moveup, movedown
+    Attributes: which, speed"""
+
+    def __init__(self, side):
+        pygame.sprite.Sprite.__init__(self)
+        self.image, self.rect = load_png('bat.png')
+        screen = pygame.display.get_surface()
+        self.area = screen.get_rect()
+        self.side = side
+        self.speed = 10
+        self.state = "still"
+        self.reinit()
+
+    def reinit(self):
+        self.state = "still"
+        self.movepos = [0,0]
+        if self.side == "left":
+            self.rect.midleft = self.area.midleft
+        elif self.side == "right":
+            self.rect.midright = self.area.midright
+
+    def update(self):
+        newpos = self.rect.move(self.movepos)
+        if self.area.contains(newpos):
+            self.rect = newpos
+        pygame.event.pump()
+
+    def moveup(self):
+        self.movepos[1] = self.movepos[1] - (self.speed)
+        self.state = "moveup"
+
+    def movedown(self):
+        self.movepos[1] = self.movepos[1] + (self.speed)
+        self.state = "movedown"
+
+
+def main():
+    # Initialise screen
+    pygame.init()
+    screen = pygame.display.set_mode((640, 480))
+    pygame.display.set_caption('Basic Pong')
+
+    # Fill background
+    background = pygame.Surface(screen.get_size())
+    background = background.convert()
+    background.fill((0, 0, 0))
+
+    # Initialise players
+    global player1
+    global player2
+    player1 = Bat("left")
+    player2 = Bat("right")
+
+    # Initialise ball
+    speed = 13
+    rand = ((0.1 * (random.randint(5,8))))
+    ball = Ball((0,0),(0.47,speed))
+
+    # Initialise sprites
+    playersprites = pygame.sprite.RenderPlain((player1, player2))
+    ballsprite = pygame.sprite.RenderPlain(ball)
+
+    # Blit everything to the screen
+    screen.blit(background, (0, 0))
+    pygame.display.flip()
+
+    # Initialise clock
+    clock = pygame.time.Clock()
+
+    # Event loop
+    while 1:
+        # Make sure game doesn't run at more than 60 frames per second
+        clock.tick(60)
+
+        for event in pygame.event.get():
+            if event.type == QUIT:
+                return
+            elif event.type == KEYDOWN:
+                if event.key == K_a:
+                    player1.moveup()
+                if event.key == K_z:
+                    player1.movedown()
+                if event.key == K_UP:
+                    player2.moveup()
+                if event.key == K_DOWN:
+                    player2.movedown()
+            elif event.type == KEYUP:
+                if event.key == K_a or event.key == K_z:
+                    player1.movepos = [0,0]
+                    player1.state = "still"
+                if event.key == K_UP or event.key == K_DOWN:
+                    player2.movepos = [0,0]
+                    player2.state = "still"
+
+        screen.blit(background, ball.rect, ball.rect)
+        screen.blit(background, player1.rect, player1.rect)
+        screen.blit(background, player2.rect, player2.rect)
+        ballsprite.update()
+        playersprites.update()
+        ballsprite.draw(screen)
+        playersprites.draw(screen)
+        pygame.display.flip()
+
+
+if __name__ == '__main__': main()
+
+
+

As well as showing you the final product, I'll point you back to TomPong, upon which all of this is based. Download it, have a look +at the source code, and you'll see a full implementation of pong using all of the code you've seen in this tutorial, as well as lots of +other code I've added in various versions, such as some extra physics for spinning, and various other bug and glitch fixes.

+

Oh, find TomPong at http://www.tomchance.uklinux.net/projects/pong.shtml.

+
+
+
+ + +

+
+Edit on GitHub +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/draw.pyi b/venv/Lib/site-packages/pygame/draw.pyi new file mode 100644 index 0000000..8a24089 --- /dev/null +++ b/venv/Lib/site-packages/pygame/draw.pyi @@ -0,0 +1,74 @@ +from typing import Optional, Sequence + +from pygame.rect import Rect +from pygame.surface import Surface + +from ._common import _ColorValue, _Coordinate, _RectValue + +def rect( + surface: Surface, + color: _ColorValue, + rect: _RectValue, + width: int = 0, + border_radius: int = -1, + border_top_left_radius: int = -1, + border_top_right_radius: int = -1, + border_bottom_left_radius: int = -1, + border_bottom_right_radius: int = -1, +) -> Rect: ... +def polygon( + surface: Surface, + color: _ColorValue, + points: Sequence[_Coordinate], + width: int = 0, +) -> Rect: ... +def circle( + surface: Surface, + color: _ColorValue, + center: _Coordinate, + radius: float, + width: int = 0, + draw_top_right: Optional[bool] = None, + draw_top_left: Optional[bool] = None, + draw_bottom_left: Optional[bool] = None, + draw_bottom_right: Optional[bool] = None, +) -> Rect: ... +def ellipse( + surface: Surface, color: _ColorValue, rect: _RectValue, width: int = 0 +) -> Rect: ... +def arc( + surface: Surface, + color: _ColorValue, + rect: _RectValue, + start_angle: float, + stop_angle: float, + width: int = 1, +) -> Rect: ... +def line( + surface: Surface, + color: _ColorValue, + start_pos: _Coordinate, + end_pos: _Coordinate, + width: int = 1, +) -> Rect: ... +def lines( + surface: Surface, + color: _ColorValue, + closed: bool, + points: Sequence[_Coordinate], + width: int = 1, +) -> Rect: ... +def aaline( + surface: Surface, + color: _ColorValue, + start_pos: _Coordinate, + end_pos: _Coordinate, + blend: int = 1, +) -> Rect: ... +def aalines( + surface: Surface, + color: _ColorValue, + closed: bool, + points: Sequence[_Coordinate], + blend: int = 1, +) -> Rect: ... diff --git a/venv/Lib/site-packages/pygame/draw_py.py b/venv/Lib/site-packages/pygame/draw_py.py new file mode 100644 index 0000000..edd1c0c --- /dev/null +++ b/venv/Lib/site-packages/pygame/draw_py.py @@ -0,0 +1,564 @@ +# -*- coding: utf-8 -*- +"""Pygame Drawing algorithms written in Python. (Work in Progress) + +Implement Pygame's Drawing Algorithms in a Python version for testing +and debugging. +""" + +from collections import namedtuple +from math import floor, ceil + + +# H E L P E R F U N C T I O N S # + +# fractional part of x + + +def frac(value): + """return fractional part of x""" + return value - floor(value) + + +def inv_frac(value): + """return inverse fractional part of x""" + return 1 - (value - floor(value)) # eg, 1 - frac(x) + + +BoundingBox = namedtuple("BoundingBox", ["left", "top", "right", "bottom"]) +Point = namedtuple("Point", ["x", "y"]) + + +# L O W L E V E L D R A W F U N C T I O N S # +# (They are too low-level to be translated into python, right?) + + +def set_at(surf, in_x, in_y, color): + """Set the color of a pixel in a surface""" + surf.set_at((in_x, in_y), color) + + +def draw_pixel(surf, pos, color, bright, blend=True): + """draw one blended pixel with given brightness.""" + try: + other_col = surf.get_at(pos) if blend else (0, 0, 0, 0) + except IndexError: # pixel outside the surface + return + new_color = tuple( + (bright * col + (1 - bright) * pix) for col, pix in zip(color, other_col) + ) + # FIXME what should happen if only one, color or surf_col, has alpha? + surf.set_at(pos, new_color) + + +def _drawhorzline(surf, color, x_from, in_y, x_to): + if x_from == x_to: + surf.set_at((x_from, in_y), color) + return + + start, end = (x_from, x_to) if x_from <= x_to else (x_to, x_from) + for line_x in range(start, end + 1): + surf.set_at((line_x, in_y), color) + + +def _drawvertline(surf, color, in_x, y_from, y_to): + if y_from == y_to: + surf.set_at((in_x, y_from), color) + return + + start, end = (y_from, y_to) if y_from <= y_to else (y_to, y_from) + for line_y in range(start, end + 1): + surf.set_at((in_x, line_y), color) + + +# I N T E R N A L D R A W L I N E F U N C T I O N S # + + +def _clip_and_draw_horizline(surf, color, x_from, in_y, x_to): + """draw clipped horizontal line.""" + # check Y inside surf + clip = surf.get_clip() + if in_y < clip.y or in_y >= clip.y + clip.h: + return + + x_from = max(x_from, clip.x) + x_to = min(x_to, clip.x + clip.w - 1) + + # check any x inside surf + if x_to < clip.x or x_from >= clip.x + clip.w: + return + + _drawhorzline(surf, color, x_from, in_y, x_to) + + +def _clip_and_draw_vertline(surf, color, in_x, y_from, y_to): + """draw clipped vertical line.""" + # check X inside surf + clip = surf.get_clip() + + if in_x < clip.x or in_x >= clip.x + clip.w: + return + + y_from = max(y_from, clip.y) + y_to = min(y_to, clip.y + clip.h - 1) + + # check any y inside surf + if y_to < clip.y or y_from >= clip.y + clip.h: + return + + _drawvertline(surf, color, in_x, y_from, y_to) + + +# These constants xxx_EDGE are "outside-the-bounding-box"-flags +LEFT_EDGE = 0x1 +RIGHT_EDGE = 0x2 +BOTTOM_EDGE = 0x4 +TOP_EDGE = 0x8 + + +def encode(pos, b_box): + """returns a code that defines position with respect to a bounding box""" + # we use the fact that python interprets booleans (the inequalities) + # as 0/1, and then multiply them with the xxx_EDGE flags + return ( + (pos[0] < b_box.left) * LEFT_EDGE + + (pos[0] > b_box.right) * RIGHT_EDGE + + (pos[1] < b_box.top) * TOP_EDGE + + (pos[1] > b_box.bottom) * BOTTOM_EDGE + ) + + +def clip_line(line, b_box, use_float=False): + """Algorithm to calculate the clipped line. + + We calculate the coordinates of the part of the line segment within the + bounding box (defined by left, top, right, bottom). The we write + the coordinates of the line segment into "line", much like the C-algorithm. + With `use_float` True, clip_line is usable for float-clipping. + + Returns: true if the line segment cuts the bounding box (false otherwise) + """ + + def inside(code): + return not code + + def accept(code_a, code_b): + return not (code_a or code_b) + + def reject(code_a, code_b): + return code_a and code_b + + assert isinstance(line, list) + x_1, y_1, x_2, y_2 = line + dtype = float if use_float else int + + while True: + # the coordinates are progressively modified with the codes, + # until they are either rejected or correspond to the final result. + code1 = encode((x_1, y_1), b_box) + code2 = encode((x_2, y_2), b_box) + + if accept(code1, code2): + # write coordinates into "line" ! + line[:] = x_1, y_1, x_2, y_2 + return True + if reject(code1, code2): + return False + + # We operate on the (x_1, y_1) point, + # and swap if it is inside the bbox: + if inside(code1): + x_1, x_2 = x_2, x_1 + y_1, y_2 = y_2, y_1 + code1, code2 = code2, code1 + slope = (y_2 - y_1) / float(x_2 - x_1) if (x_2 != x_1) else 1.0 + # Each case, if true, means that we are outside the border: + # calculate x_1 and y_1 to be the "first point" inside the bbox... + if code1 & LEFT_EDGE: + y_1 += dtype((b_box.left - x_1) * slope) + x_1 = b_box.left + elif code1 & RIGHT_EDGE: + y_1 += dtype((b_box.right - x_1) * slope) + x_1 = b_box.right + elif code1 & BOTTOM_EDGE: + if x_2 != x_1: + x_1 += dtype((b_box.bottom - y_1) / slope) + y_1 = b_box.bottom + elif code1 & TOP_EDGE: + if x_2 != x_1: + x_1 += dtype((b_box.top - y_1) / slope) + y_1 = b_box.top + + +def _draw_line(surf, color, start, end): + """draw a non-horizontal line (without anti-aliasing).""" + # Variant of https://en.wikipedia.org/wiki/Bresenham's_line_algorithm + # + # This strongly differs from craw.c implementation, because we use a + # "slope" variable (instead of delta_x and delta_y) and a "error" variable. + # And we can not do pointer-arithmetic with "BytesPerPixel", like in + # the C-algorithm. + if start.x == end.x: + # This case should not happen... + raise ValueError + + slope = abs((end.y - start.y) / (end.x - start.x)) + error = 0.0 + + if slope < 1: + # Here, it's a rather horizontal line + + # 1. check in which octants we are & set init values + if end.x < start.x: + start.x, end.x = end.x, start.x + start.y, end.y = end.y, start.y + line_y = start.y + dy_sign = 1 if (start.y < end.y) else -1 + + # 2. step along x coordinate + for line_x in range(start.x, end.x + 1): + set_at(surf, line_x, line_y, color) + error += slope + if error >= 0.5: + line_y += dy_sign + error -= 1 + else: + # Case of a rather vertical line + + # 1. check in which octants we are & set init values + if start.y > end.y: + start.x, end.x = end.x, start.x + start.y, end.y = end.y, start.y + line_x = start.x + slope = 1 / slope + dx_sign = 1 if (start.x < end.x) else -1 + + # 2. step along y coordinate + for line_y in range(start.y, end.y + 1): + set_at(surf, line_x, line_y, color) + error += slope + if error >= 0.5: + line_x += dx_sign + error -= 1 + + +def _draw_aaline(surf, color, start, end, blend): + """draw an anti-aliased line. + + The algorithm yields identical results with _draw_line for horizontal, + vertical or diagonal lines, and results changes smoothly when changing + any of the endpoint coordinates. + + Note that this yields strange results for very short lines, eg + a line from (0, 0) to (0, 1) will draw 2 pixels, and a line from + (0, 0) to (0, 1.1) will blend 10 % on the pixel (0, 2). + """ + # The different requirements that we have on an antialiasing algorithm + # implies to make some compromises: + # 1. We want smooth evolution wrt to the 4 endpoint coordinates + # (this means also that we want a smooth evolution when the angle + # passes +/- 45° + # 2. We want the same behavior when swapping the endpoints + # 3. We want understandable results for the endpoint values + # (eg we want to avoid half-integer values to draw a simple plain + # horizontal or vertical line between two integer l endpoints) + # + # This implies to somehow make the line artificially 1 pixel longer + # and to draw a full pixel when we have the endpoints are identical. + d_x = end.x - start.x + d_y = end.y - start.y + + if d_x == 0 and d_y == 0: + # For smoothness reasons, we could also do some blending here, + # but it seems overshoot... + set_at(surf, int(start.x), int(start.y), color) + return + + if start.x > end.x or start.y > end.y: + start.x, end.x = end.x, start.x + start.y, end.y = end.y, start.y + d_x = -d_x + d_y = -d_y + + if abs(d_x) >= abs(d_y): + slope = d_y / d_x + + def draw_two_pixel(in_x, float_y, factor): + flr_y = floor(float_y) + draw_pixel(surf, (in_x, flr_y), color, factor * inv_frac(float_y), blend) + draw_pixel(surf, (in_x, flr_y + 1), color, factor * frac(float_y), blend) + + _draw_aaline_dx(d_x, slope, end, start, draw_two_pixel) + else: + slope = d_x / d_y + + def draw_two_pixel(float_x, in_y, factor): + fl_x = floor(float_x) + draw_pixel(surf, (fl_x, in_y), color, factor * inv_frac(float_x), blend) + draw_pixel(surf, (fl_x + 1, in_y), color, factor * frac(float_x), blend) + + _draw_aaline_dy(d_y, slope, end, start, draw_two_pixel) + + +def _draw_aaline_dy(d_y, slope, end, start, draw_two_pixel): + g_y = ceil(start.y) + g_x = start.x + (g_y - start.y) * slope + # 1. Draw start of the segment + if start.y < g_y: + draw_two_pixel(g_x - slope, floor(start.y), inv_frac(start.y)) + # 2. Draw end of the segment + rest = frac(end.y) + s_y = ceil(end.y) + if rest > 0: + s_x = start.x + slope * (d_y + 1 - rest) + draw_two_pixel(s_x, s_y, rest) + else: + s_y += 1 + # 3. loop for other points + for line_y in range(g_y, s_y): + line_x = g_x + slope * (line_y - g_y) + draw_two_pixel(line_x, line_y, 1) + + +def _draw_aaline_dx(d_x, slope, end, start, draw_two_pixel): + # A and G are respectively left and right to the "from" point, but + # with integer-x-coordinate, (and only if from_x is not integer). + # Hence they appear in following order on the line in general case: + # A from-pt G . . . to-pt S + # |------*-------|--- . . . ---|-----*------|- + g_x = ceil(start.x) + g_y = start.y + (g_x - start.x) * slope + # 1. Draw start of the segment if we have a non-integer-part + if start.x < g_x: + # this corresponds to the point "A" + draw_two_pixel(floor(start.x), g_y - slope, inv_frac(start.x)) + # 2. Draw end of the segment: we add one pixel for homogeneity reasons + rest = frac(end.x) + s_x = ceil(end.x) + if rest > 0: + # Again we draw only if we have a non-integer-part + s_y = start.y + slope * (d_x + 1 - rest) + draw_two_pixel(s_x, s_y, rest) + else: + s_x += 1 + # 3. loop for other points + for line_x in range(g_x, s_x): + line_y = g_y + slope * (line_x - g_x) + draw_two_pixel(line_x, line_y, 1) + + +# C L I P A N D D R A W L I N E F U N C T I O N S # + + +def _clip_and_draw_line(surf, rect, color, pts): + """clip the line into the rectangle and draw if needed. + + Returns true if anything has been drawn, else false.""" + # "pts" is a list with the four coordinates of the two endpoints + # of the line to be drawn : pts = x1, y1, x2, y2. + # The data format is like that to stay closer to the C-algorithm. + if not clip_line( + pts, BoundingBox(rect.x, rect.y, rect.x + rect.w - 1, rect.y + rect.h - 1) + ): + # The line segment defined by "pts" is not crossing the rectangle + return 0 + if pts[1] == pts[3]: # eg y1 == y2 + _drawhorzline(surf, color, pts[0], pts[1], pts[2]) + elif pts[0] == pts[2]: # eg x1 == x2 + _drawvertline(surf, color, pts[0], pts[1], pts[3]) + else: + _draw_line(surf, color, Point(pts[0], pts[1]), Point(pts[2], pts[3])) + return 1 + + +def _clip_and_draw_line_width(surf, rect, color, line, width): + yinc = xinc = 0 + if abs(line[0] - line[2]) > abs(line[1] - line[3]): + yinc = 1 + else: + xinc = 1 + newpts = line[:] + if _clip_and_draw_line(surf, rect, color, newpts): + anydrawn = 1 + frame = newpts[:] + else: + anydrawn = 0 + frame = [10000, 10000, -10000, -10000] + + for loop in range(1, width // 2 + 1): + newpts[0] = line[0] + xinc * loop + newpts[1] = line[1] + yinc * loop + newpts[2] = line[2] + xinc * loop + newpts[3] = line[3] + yinc * loop + if _clip_and_draw_line(surf, rect, color, newpts): + anydrawn = 1 + frame[0] = min(newpts[0], frame[0]) + frame[1] = min(newpts[1], frame[1]) + frame[2] = max(newpts[2], frame[2]) + frame[3] = max(newpts[3], frame[3]) + + if loop * 2 < width: + newpts[0] = line[0] - xinc * loop + newpts[1] = line[1] - yinc * loop + newpts[2] = line[2] - xinc * loop + newpts[3] = line[3] - yinc * loop + if _clip_and_draw_line(surf, rect, color, newpts): + anydrawn = 1 + frame[0] = min(newpts[0], frame[0]) + frame[1] = min(newpts[1], frame[1]) + frame[2] = max(newpts[2], frame[2]) + frame[3] = max(newpts[3], frame[3]) + + return anydrawn + + +def _clip_and_draw_aaline(surf, rect, color, line, blend): + """draw anti-aliased line between two endpoints.""" + if not clip_line( + line, + BoundingBox(rect.x - 1, rect.y - 1, rect.x + rect.w, rect.y + rect.h), + use_float=True, + ): + return # TODO Rect(rect.x, rect.y, 0, 0) + _draw_aaline(surf, color, Point(line[0], line[1]), Point(line[2], line[3]), blend) + return # TODO Rect(-- affected area --) + + +# D R A W L I N E F U N C T I O N S # + + +def draw_aaline(surf, color, from_point, to_point, blend=True): + """draw anti-aliased line between two endpoints.""" + line = [from_point[0], from_point[1], to_point[0], to_point[1]] + return _clip_and_draw_aaline(surf, surf.get_clip(), color, line, blend) + + +def draw_line(surf, color, from_point, to_point, width=1): + """draw anti-aliased line between two endpoints.""" + line = [from_point[0], from_point[1], to_point[0], to_point[1]] + return _clip_and_draw_line_width(surf, surf.get_clip(), color, line, width) + + +# M U L T I L I N E F U N C T I O N S # + + +def _multi_lines( + surf, + color, + closed, # pylint: disable=too-many-arguments + points, + width=1, + blend=False, + aaline=False, +): + """draw several lines, either anti-aliased or not.""" + # The code for anti-aliased or not is almost identical, so it's factorized + if len(points) <= 2: + raise TypeError + line = [0] * 4 # store x1, y1 & x2, y2 of the lines to be drawn + + xlist = [pt[0] for pt in points] + ylist = [pt[1] for pt in points] + line[0] = xlist[0] + line[1] = ylist[0] + b_box = BoundingBox(left=xlist[0], right=xlist[0], top=ylist[0], bottom=ylist[0]) + + for line_x, line_y in points[1:]: + b_box.left = min(b_box.left, line_x) + b_box.right = max(b_box.right, line_x) + b_box.top = min(b_box.top, line_y) + b_box.bottom = max(b_box.bottom, line_y) + + rect = surf.get_clip() + for loop in range(1, len(points)): + + line[0] = xlist[loop - 1] + line[1] = ylist[loop - 1] + line[2] = xlist[loop] + line[3] = ylist[loop] + if aaline: + _clip_and_draw_aaline(surf, rect, color, line, blend) + else: + _clip_and_draw_line_width(surf, rect, color, line, width) + + if closed: + line[0] = xlist[len(points) - 1] + line[1] = ylist[len(points) - 1] + line[2] = xlist[0] + line[3] = ylist[0] + if aaline: + _clip_and_draw_aaline(surf, rect, color, line, blend) + else: + _clip_and_draw_line_width(surf, rect, color, line, width) + + # TODO Rect(...) + + +def draw_lines(surf, color, closed, points, width=1): + """draw several lines connected through the points.""" + return _multi_lines(surf, color, closed, points, width, aaline=False) + + +def draw_aalines(surf, color, closed, points, blend=True): + """draw several anti-aliased lines connected through the points.""" + return _multi_lines(surf, color, closed, points, blend=blend, aaline=True) + + +def draw_polygon(surface, color, points, width): + """Draw a polygon""" + if width: + draw_lines(surface, color, 1, points, width) + return # TODO Rect(...) + num_points = len(points) + point_x = [x for x, y in points] + point_y = [y for x, y in points] + + miny = min(point_y) + maxy = max(point_y) + + if miny == maxy: + minx = min(point_x) + maxx = max(point_x) + _clip_and_draw_horizline(surface, color, minx, miny, maxx) + return # TODO Rect(...) + + for y_coord in range(miny, maxy + 1): + x_intersect = [] + for i in range(num_points): + _draw_polygon_inner_loop(i, point_x, point_y, y_coord, x_intersect) + + x_intersect.sort() + for i in range(0, len(x_intersect), 2): + _clip_and_draw_horizline( + surface, color, x_intersect[i], y_coord, x_intersect[i + 1] + ) + + # special case : horizontal border lines + for i in range(num_points): + i_prev = i - 1 if i else num_points - 1 + if miny < point_y[i] == point_y[i_prev] < maxy: + _clip_and_draw_horizline( + surface, color, point_x[i], point_y[i], point_x[i_prev] + ) + + return # TODO Rect(...) + + +def _draw_polygon_inner_loop(index, point_x, point_y, y_coord, x_intersect): + i_prev = index - 1 if index else len(point_x) - 1 + + y_1 = point_y[i_prev] + y_2 = point_y[index] + + if y_1 < y_2: + x_1 = point_x[i_prev] + x_2 = point_x[index] + elif y_1 > y_2: + y_2 = point_y[i_prev] + y_1 = point_y[index] + x_2 = point_x[i_prev] + x_1 = point_x[index] + else: # special case handled below + return + + if (y_2 > y_coord >= y_1) or ((y_coord == max(point_y)) and (y_coord <= y_2)): + x_intersect.append((y_coord - y_1) * (x_2 - x_1) // (y_2 - y_1) + x_1) diff --git a/venv/Lib/site-packages/pygame/event.pyi b/venv/Lib/site-packages/pygame/event.pyi new file mode 100644 index 0000000..85d7a5d --- /dev/null +++ b/venv/Lib/site-packages/pygame/event.pyi @@ -0,0 +1,32 @@ +from typing import Any, Dict, List, Optional, SupportsInt, Tuple, Union, overload + +class Event: + type: int + __dict__: Dict[str, Any] + __hash__: None # type: ignore + @overload + def __init__(self, type: int, dict: Dict[str, Any]) -> None: ... + @overload + def __init__(self, type: int, **attributes: Any) -> None: ... + def __getattr__(self, name: str) -> Any: ... + +_EventTypes = Union[SupportsInt, Tuple[SupportsInt, ...], List[SupportsInt]] + +def pump() -> None: ... +def get( + eventtype: Optional[_EventTypes] = None, + pump: Any = True, + exclude: Optional[_EventTypes] = None, +) -> List[Event]: ... +def poll() -> Event: ... +def wait(timeout: int = 0) -> Event: ... +def peek(eventtype: Optional[_EventTypes] = None, pump: Any = True) -> bool: ... +def clear(eventtype: Optional[_EventTypes] = None, pump: Any = True) -> None: ... +def event_name(type: int) -> str: ... +def set_blocked(type: Optional[_EventTypes]) -> None: ... +def set_allowed(type: Optional[_EventTypes]) -> None: ... +def get_blocked(type: _EventTypes) -> bool: ... +def set_grab(grab: bool) -> None: ... +def get_grab() -> bool: ... +def post(event: Event) -> bool: ... +def custom_type() -> int: ... diff --git a/venv/Lib/site-packages/pygame/examples/README.rst b/venv/Lib/site-packages/pygame/examples/README.rst new file mode 100644 index 0000000..a319922 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/README.rst @@ -0,0 +1,142 @@ +These examples should help get you started with pygame. Here is a +brief rundown of what you get. The source code for all examples +is in the public domain. Feel free to use for your own projects. + +aliens.py + This started off as a port of the SDL demonstration, Aliens. + Now it has evolved into something sort of resembling fun. + This demonstrates a lot of different uses of sprites and + optimized blitting. Also transparancy, colorkeys, fonts, sound, + music, joystick, and more. (PS, my high score is 117! goodluck) + +arraydemo.py + Another example filled with various surfarray effects. + It requires the surfarray and image modules to be installed. + This little demo can also make a good starting point for any of + your own tests with surfarray + +audiocapture.py + Record sound from a microphone, and play back the recorded sound. + +blend_fill.py + BLEND_ing colors in different ways with Surface.fill(). + +blit_blends.py + BLEND_ing colors Surface.blit(). + +camera.py + Basic image capturing and display using pygame.camera + +cursors.py + Make custom cursors :) + +dropevent.py + Drag and drop files. Using the following events. + DROPBEGIN, DROPCOMPLETE, DROPTEXT, DROPFILE + +eventlist.py + Learn about pygame events and input. + Watch the events fly by. Click the mouse, and see the mouse + event come up. Press a keyboard key, and see the key up event. + +font_viewer.py + Display all available fonts in a scrolling window. + +fonty.py + Super quick, super simple application demonstrating + the different ways to render fonts with the font module + +freetype_misc.py + FreeType is a world famous font project. + +glcube.py + Using PyOpenGL and Pygame, this creates a spinning 3D multicolored cube. + +headless_no_windows_needed.py + For using pygame in scripts. + +liquid.py + This example was created in a quick comparison with the + BlitzBasic gaming language. Nonetheless, it demonstrates a quick + 8-bit setup (with colormap). + +mask.py + Single bit pixel manipulation. Fast for collision detection, + and also good for computer vision. + +midi.py + For connecting pygame to musical equipment. + +moveit.py + A very simple example of moving stuff. + +music_drop_fade.py + Fade in and play music from a list while observing + several events. Uses fade_ms added in pygame2, as well as set_endevent, + set_volume, drag and drop events, and the scrap module. + +overlay.py + An old way of displaying video content. + +pixelarray.py + Process whole arrays of pixels at a time. + Like numpy, but for pixels, and also built into pygame. + +playmus.py + Simple music playing example. + +prevent_display_stretching.py + A windows specific example. + +scaletest.py + Showing how to scale Surfaces. + +scrap_clipboard.py + A simple demonstration example for the clipboard support. + +setmodescale.py + SCALED allows you to work in 320x200 and have it show up big. + It handles mouse scaling and selection of a good sized window depending + on the display. + +sound.py + Extremely basic testing of the mixer module. Load a + sound and play it. All from the command shell, no graphics. + +sound_array_demos.py + Echo, delay and other array based processing of sounds. + +sprite_texture.py + Shows how to use hardware Image Textures with pygame.sprite. + +stars.py + A simple starfield example. You can change the center of + perspective by leftclicking the mouse on the screen. + +testsprite.py + More of a test example. If you're interested in how to use sprites, + then check out the aliens.py example instead. + +textinput.py + A little "console" where you can write in text. + Shows how to use the TEXTEDITING and TEXTINPUT events. + +vgrade.py + Demonstrates creating a vertical gradient with + Numpy. The app will create a new gradient every half + second and report the time needed to create and display the + image. If you're not prepared to start working with the + Numpy arrays, don't worry about the source for this one :] + +video.py + It explores some new video APIs in pygame 2. + Including multiple windows, Textures, and such. + +data/ + Directory with the resources for the examples. + +There's LOTS of examples on the pygame website, and on places like github. + +We're always on the lookout for more examples and/or example +requests. Code like this is probably the best way to start +getting involved with Python gaming. diff --git a/venv/Lib/site-packages/pygame/examples/__init__.py b/venv/Lib/site-packages/pygame/examples/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/pygame/examples/aacircle.py b/venv/Lib/site-packages/pygame/examples/aacircle.py new file mode 100644 index 0000000..de3733d --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/aacircle.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +"""Proof of concept gfxdraw example""" + +import pygame +import pygame.gfxdraw + + +def main(): + pygame.init() + screen = pygame.display.set_mode((500, 500)) + screen.fill((255, 0, 0)) + s = pygame.Surface(screen.get_size(), pygame.SRCALPHA, 32) + pygame.draw.line(s, (0, 0, 0), (250, 250), (250 + 200, 250)) + + width = 1 + for a_radius in range(width): + radius = 200 + pygame.gfxdraw.aacircle(s, 250, 250, radius - a_radius, (0, 0, 0)) + + screen.blit(s, (0, 0)) + + pygame.draw.circle(screen, "green", (50, 100), 10) + pygame.draw.circle(screen, "black", (50, 100), 10, 1) + + pygame.display.flip() + try: + while 1: + event = pygame.event.wait() + if event.type == pygame.QUIT: + break + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_ESCAPE or event.unicode == "q": + break + pygame.display.flip() + finally: + pygame.quit() + + +if __name__ == "__main__": + main() diff --git a/venv/Lib/site-packages/pygame/examples/aliens.py b/venv/Lib/site-packages/pygame/examples/aliens.py new file mode 100644 index 0000000..9fecb3f --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/aliens.py @@ -0,0 +1,401 @@ +#!/usr/bin/env python +""" pygame.examples.aliens + +Shows a mini game where you have to defend against aliens. + +What does it show you about pygame? + +* pg.sprite, the difference between Sprite and Group. +* dirty rectangle optimization for processing for speed. +* music with pg.mixer.music, including fadeout +* sound effects with pg.Sound +* event processing, keyboard handling, QUIT handling. +* a main loop frame limited with a game clock from pg.time.Clock +* fullscreen switching. + + +Controls +-------- + +* Left and right arrows to move. +* Space bar to shoot +* f key to toggle between fullscreen. + +""" + +import random +import os + +# import basic pygame modules +import pygame as pg + +# see if we can load more than standard BMP +if not pg.image.get_extended(): + raise SystemExit("Sorry, extended image module required") + + +# game constants +MAX_SHOTS = 2 # most player bullets onscreen +ALIEN_ODDS = 22 # chances a new alien appears +BOMB_ODDS = 60 # chances a new bomb will drop +ALIEN_RELOAD = 12 # frames between new aliens +SCREENRECT = pg.Rect(0, 0, 640, 480) +SCORE = 0 + +main_dir = os.path.split(os.path.abspath(__file__))[0] + + +def load_image(file): + """loads an image, prepares it for play""" + file = os.path.join(main_dir, "data", file) + try: + surface = pg.image.load(file) + except pg.error: + raise SystemExit('Could not load image "%s" %s' % (file, pg.get_error())) + return surface.convert() + + +def load_sound(file): + """because pygame can be be compiled without mixer.""" + if not pg.mixer: + return None + file = os.path.join(main_dir, "data", file) + try: + sound = pg.mixer.Sound(file) + return sound + except pg.error: + print("Warning, unable to load, %s" % file) + return None + + +# Each type of game object gets an init and an update function. +# The update function is called once per frame, and it is when each object should +# change its current position and state. +# +# The Player object actually gets a "move" function instead of update, +# since it is passed extra information about the keyboard. + + +class Player(pg.sprite.Sprite): + """Representing the player as a moon buggy type car.""" + + speed = 10 + bounce = 24 + gun_offset = -11 + images = [] + + def __init__(self): + pg.sprite.Sprite.__init__(self, self.containers) + self.image = self.images[0] + self.rect = self.image.get_rect(midbottom=SCREENRECT.midbottom) + self.reloading = 0 + self.origtop = self.rect.top + self.facing = -1 + + def move(self, direction): + if direction: + self.facing = direction + self.rect.move_ip(direction * self.speed, 0) + self.rect = self.rect.clamp(SCREENRECT) + if direction < 0: + self.image = self.images[0] + elif direction > 0: + self.image = self.images[1] + self.rect.top = self.origtop - (self.rect.left // self.bounce % 2) + + def gunpos(self): + pos = self.facing * self.gun_offset + self.rect.centerx + return pos, self.rect.top + + +class Alien(pg.sprite.Sprite): + """An alien space ship. That slowly moves down the screen.""" + + speed = 13 + animcycle = 12 + images = [] + + def __init__(self): + pg.sprite.Sprite.__init__(self, self.containers) + self.image = self.images[0] + self.rect = self.image.get_rect() + self.facing = random.choice((-1, 1)) * Alien.speed + self.frame = 0 + if self.facing < 0: + self.rect.right = SCREENRECT.right + + def update(self): + self.rect.move_ip(self.facing, 0) + if not SCREENRECT.contains(self.rect): + self.facing = -self.facing + self.rect.top = self.rect.bottom + 1 + self.rect = self.rect.clamp(SCREENRECT) + self.frame = self.frame + 1 + self.image = self.images[self.frame // self.animcycle % 3] + + +class Explosion(pg.sprite.Sprite): + """An explosion. Hopefully the Alien and not the player!""" + + defaultlife = 12 + animcycle = 3 + images = [] + + def __init__(self, actor): + pg.sprite.Sprite.__init__(self, self.containers) + self.image = self.images[0] + self.rect = self.image.get_rect(center=actor.rect.center) + self.life = self.defaultlife + + def update(self): + """called every time around the game loop. + + Show the explosion surface for 'defaultlife'. + Every game tick(update), we decrease the 'life'. + + Also we animate the explosion. + """ + self.life = self.life - 1 + self.image = self.images[self.life // self.animcycle % 2] + if self.life <= 0: + self.kill() + + +class Shot(pg.sprite.Sprite): + """a bullet the Player sprite fires.""" + + speed = -11 + images = [] + + def __init__(self, pos): + pg.sprite.Sprite.__init__(self, self.containers) + self.image = self.images[0] + self.rect = self.image.get_rect(midbottom=pos) + + def update(self): + """called every time around the game loop. + + Every tick we move the shot upwards. + """ + self.rect.move_ip(0, self.speed) + if self.rect.top <= 0: + self.kill() + + +class Bomb(pg.sprite.Sprite): + """A bomb the aliens drop.""" + + speed = 9 + images = [] + + def __init__(self, alien): + pg.sprite.Sprite.__init__(self, self.containers) + self.image = self.images[0] + self.rect = self.image.get_rect(midbottom=alien.rect.move(0, 5).midbottom) + + def update(self): + """called every time around the game loop. + + Every frame we move the sprite 'rect' down. + When it reaches the bottom we: + + - make an explosion. + - remove the Bomb. + """ + self.rect.move_ip(0, self.speed) + if self.rect.bottom >= 470: + Explosion(self) + self.kill() + + +class Score(pg.sprite.Sprite): + """to keep track of the score.""" + + def __init__(self): + pg.sprite.Sprite.__init__(self) + self.font = pg.font.Font(None, 20) + self.font.set_italic(1) + self.color = "white" + self.lastscore = -1 + self.update() + self.rect = self.image.get_rect().move(10, 450) + + def update(self): + """We only update the score in update() when it has changed.""" + if SCORE != self.lastscore: + self.lastscore = SCORE + msg = "Score: %d" % SCORE + self.image = self.font.render(msg, 0, self.color) + + +def main(winstyle=0): + # Initialize pygame + if pg.get_sdl_version()[0] == 2: + pg.mixer.pre_init(44100, 32, 2, 1024) + pg.init() + if pg.mixer and not pg.mixer.get_init(): + print("Warning, no sound") + pg.mixer = None + + fullscreen = False + # Set the display mode + winstyle = 0 # |FULLSCREEN + bestdepth = pg.display.mode_ok(SCREENRECT.size, winstyle, 32) + screen = pg.display.set_mode(SCREENRECT.size, winstyle, bestdepth) + + # Load images, assign to sprite classes + # (do this before the classes are used, after screen setup) + img = load_image("player1.gif") + Player.images = [img, pg.transform.flip(img, 1, 0)] + img = load_image("explosion1.gif") + Explosion.images = [img, pg.transform.flip(img, 1, 1)] + Alien.images = [load_image(im) for im in ("alien1.gif", "alien2.gif", "alien3.gif")] + Bomb.images = [load_image("bomb.gif")] + Shot.images = [load_image("shot.gif")] + + # decorate the game window + icon = pg.transform.scale(Alien.images[0], (32, 32)) + pg.display.set_icon(icon) + pg.display.set_caption("Pygame Aliens") + pg.mouse.set_visible(0) + + # create the background, tile the bgd image + bgdtile = load_image("background.gif") + background = pg.Surface(SCREENRECT.size) + for x in range(0, SCREENRECT.width, bgdtile.get_width()): + background.blit(bgdtile, (x, 0)) + screen.blit(background, (0, 0)) + pg.display.flip() + + # load the sound effects + boom_sound = load_sound("boom.wav") + shoot_sound = load_sound("car_door.wav") + if pg.mixer: + music = os.path.join(main_dir, "data", "house_lo.wav") + pg.mixer.music.load(music) + pg.mixer.music.play(-1) + + # Initialize Game Groups + aliens = pg.sprite.Group() + shots = pg.sprite.Group() + bombs = pg.sprite.Group() + all = pg.sprite.RenderUpdates() + lastalien = pg.sprite.GroupSingle() + + # assign default groups to each sprite class + Player.containers = all + Alien.containers = aliens, all, lastalien + Shot.containers = shots, all + Bomb.containers = bombs, all + Explosion.containers = all + Score.containers = all + + # Create Some Starting Values + global score + alienreload = ALIEN_RELOAD + clock = pg.time.Clock() + + # initialize our starting sprites + global SCORE + player = Player() + Alien() # note, this 'lives' because it goes into a sprite group + if pg.font: + all.add(Score()) + + # Run our main loop whilst the player is alive. + while player.alive(): + + # get input + for event in pg.event.get(): + if event.type == pg.QUIT: + return + if event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE: + return + elif event.type == pg.KEYDOWN: + if event.key == pg.K_f: + if not fullscreen: + print("Changing to FULLSCREEN") + screen_backup = screen.copy() + screen = pg.display.set_mode( + SCREENRECT.size, winstyle | pg.FULLSCREEN, bestdepth + ) + screen.blit(screen_backup, (0, 0)) + else: + print("Changing to windowed mode") + screen_backup = screen.copy() + screen = pg.display.set_mode( + SCREENRECT.size, winstyle, bestdepth + ) + screen.blit(screen_backup, (0, 0)) + pg.display.flip() + fullscreen = not fullscreen + + keystate = pg.key.get_pressed() + + # clear/erase the last drawn sprites + all.clear(screen, background) + + # update all the sprites + all.update() + + # handle player input + direction = keystate[pg.K_RIGHT] - keystate[pg.K_LEFT] + player.move(direction) + firing = keystate[pg.K_SPACE] + if not player.reloading and firing and len(shots) < MAX_SHOTS: + Shot(player.gunpos()) + if pg.mixer: + shoot_sound.play() + player.reloading = firing + + # Create new alien + if alienreload: + alienreload = alienreload - 1 + elif not int(random.random() * ALIEN_ODDS): + Alien() + alienreload = ALIEN_RELOAD + + # Drop bombs + if lastalien and not int(random.random() * BOMB_ODDS): + Bomb(lastalien.sprite) + + # Detect collisions between aliens and players. + for alien in pg.sprite.spritecollide(player, aliens, 1): + if pg.mixer: + boom_sound.play() + Explosion(alien) + Explosion(player) + SCORE = SCORE + 1 + player.kill() + + # See if shots hit the aliens. + for alien in pg.sprite.groupcollide(aliens, shots, 1, 1).keys(): + if pg.mixer: + boom_sound.play() + Explosion(alien) + SCORE = SCORE + 1 + + # See if alien boms hit the player. + for bomb in pg.sprite.spritecollide(player, bombs, 1): + if pg.mixer: + boom_sound.play() + Explosion(player) + Explosion(bomb) + player.kill() + + # draw the scene + dirty = all.draw(screen) + pg.display.update(dirty) + + # cap the framerate at 40fps. Also called 40HZ or 40 times per second. + clock.tick(40) + + if pg.mixer: + pg.mixer.music.fadeout(1000) + pg.time.wait(1000) + + +# call the "main" function if running this script +if __name__ == "__main__": + main() + pg.quit() diff --git a/venv/Lib/site-packages/pygame/examples/arraydemo.py b/venv/Lib/site-packages/pygame/examples/arraydemo.py new file mode 100644 index 0000000..c35f376 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/arraydemo.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python +""" pygame.examples.arraydemo + +Welcome to the arraydemo! + +Use the numpy array package to manipulate pixels. + +This demo will show you a few things: + +* scale up, scale down, flip, +* cross fade +* soften +* put stripes on it! + +""" + + +import os + +import pygame as pg +from pygame import surfarray + +main_dir = os.path.split(os.path.abspath(__file__))[0] + + +def surfdemo_show(array_img, name): + "displays a surface, waits for user to continue" + screen = pg.display.set_mode(array_img.shape[:2], 0, 32) + surfarray.blit_array(screen, array_img) + pg.display.flip() + pg.display.set_caption(name) + while 1: + e = pg.event.wait() + if e.type == pg.MOUSEBUTTONDOWN: + break + elif e.type == pg.KEYDOWN and e.key == pg.K_s: + # pg.image.save(screen, name+'.bmp') + # s = pg.Surface(screen.get_size(), 0, 32) + # s = s.convert_alpha() + # s.fill((0,0,0,255)) + # s.blit(screen, (0,0)) + # s.fill((222,0,0,50), (0,0,40,40)) + # pg.image.save_extended(s, name+'.png') + # pg.image.save(s, name+'.png') + # pg.image.save(screen, name+'_screen.png') + # pg.image.save(s, name+'.tga') + pg.image.save(screen, name + ".png") + elif e.type == pg.QUIT: + pg.quit() + raise SystemExit() + + +def main(): + """show various surfarray effects""" + import numpy as N + from numpy import int32, uint8, uint + + pg.init() + print("Using %s" % surfarray.get_arraytype().capitalize()) + print("Press the mouse button to advance image.") + print('Press the "s" key to save the current image.') + + # allblack + allblack = N.zeros((128, 128), int32) + surfdemo_show(allblack, "allblack") + + # striped + # the element type is required for N.zeros in numpy else + # an array of float is returned. + striped = N.zeros((128, 128, 3), int32) + striped[:] = (255, 0, 0) + striped[:, ::3] = (0, 255, 255) + surfdemo_show(striped, "striped") + + # rgbarray + imagename = os.path.join(main_dir, "data", "arraydemo.bmp") + imgsurface = pg.image.load(imagename) + rgbarray = surfarray.array3d(imgsurface) + surfdemo_show(rgbarray, "rgbarray") + + # flipped + flipped = rgbarray[:, ::-1] + surfdemo_show(flipped, "flipped") + + # scaledown + scaledown = rgbarray[::2, ::2] + surfdemo_show(scaledown, "scaledown") + + # scaleup + # the element type is required for N.zeros in numpy else + # an #array of floats is returned. + shape = rgbarray.shape + scaleup = N.zeros((shape[0] * 2, shape[1] * 2, shape[2]), int32) + scaleup[::2, ::2, :] = rgbarray + scaleup[1::2, ::2, :] = rgbarray + scaleup[:, 1::2] = scaleup[:, ::2] + surfdemo_show(scaleup, "scaleup") + + # redimg + redimg = N.array(rgbarray) + redimg[:, :, 1:] = 0 + surfdemo_show(redimg, "redimg") + + # soften + # having factor as an array forces integer upgrade during multiplication + # of rgbarray, even for numpy. + factor = N.array((8,), int32) + soften = N.array(rgbarray, int32) + soften[1:, :] += rgbarray[:-1, :] * factor + soften[:-1, :] += rgbarray[1:, :] * factor + soften[:, 1:] += rgbarray[:, :-1] * factor + soften[:, :-1] += rgbarray[:, 1:] * factor + soften //= 33 + surfdemo_show(soften, "soften") + + # crossfade (50%) + src = N.array(rgbarray) + dest = N.zeros(rgbarray.shape) # dest is float64 by default. + dest[:] = 20, 50, 100 + diff = (dest - src) * 0.50 + xfade = src + diff.astype(uint) + surfdemo_show(xfade, "xfade") + + # alldone + pg.quit() + + +if __name__ == "__main__": + main() diff --git a/venv/Lib/site-packages/pygame/examples/audiocapture.py b/venv/Lib/site-packages/pygame/examples/audiocapture.py new file mode 100644 index 0000000..aa50fcf --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/audiocapture.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +""" pygame.examples.audiocapture + +A pygame 2 experiment. + +* record sound from a microphone +* play back the recorded sound +""" +import pygame as pg +import time + +from pygame._sdl2 import ( + get_audio_device_names, + AudioDevice, + AUDIO_F32, + AUDIO_ALLOW_FORMAT_CHANGE, +) +from pygame._sdl2.mixer import set_post_mix + + +pg.mixer.pre_init(44100, 32, 2, 512) +pg.init() + +# init_subsystem(INIT_AUDIO) +names = get_audio_device_names(True) +print(names) + +sounds = [] +sound_chunks = [] + + +def callback(audiodevice, audiomemoryview): + """This is called in the sound thread. + + Note, that the frequency and such you request may not be what you get. + """ + # print(type(audiomemoryview), len(audiomemoryview)) + # print(audiodevice) + sound_chunks.append(bytes(audiomemoryview)) + + +def postmix_callback(postmix, audiomemoryview): + """This is called in the sound thread. + + At the end of mixing we get this data. + """ + print(type(audiomemoryview), len(audiomemoryview)) + print(postmix) + + +set_post_mix(postmix_callback) + +audio = AudioDevice( + devicename=names[0], + iscapture=True, + frequency=44100, + audioformat=AUDIO_F32, + numchannels=2, + chunksize=512, + allowed_changes=AUDIO_ALLOW_FORMAT_CHANGE, + callback=callback, +) +# start recording. +audio.pause(0) + +print(audio) + +print("recording with '%s'" % names[0]) +time.sleep(5) + + +print("Turning data into a pg.mixer.Sound") +sound = pg.mixer.Sound(buffer=b"".join(sound_chunks)) + +print("playing back recorded sound") +sound.play() +time.sleep(5) +pg.quit() diff --git a/venv/Lib/site-packages/pygame/examples/blend_fill.py b/venv/Lib/site-packages/pygame/examples/blend_fill.py new file mode 100644 index 0000000..301888b --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/blend_fill.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python +""" pygame.examples.blend_fill + +BLEND_ing colors in different ways with Surface.fill(). + +Keyboard Controls: + +* Press R, G, B to increase the color channel values, +* 1-9 to set the step range for the increment, +* A - ADD, S- SUB, M- MULT, - MIN, + MAX to change the blend modes + +""" +import os +import pygame as pg +from pygame import K_1, K_2, K_3, K_4, K_5, K_6, K_7, K_8, K_9 + + +def usage(): + print("Press R, G, B to increase the color channel values,") + print("1-9 to set the step range for the increment,") + print("A - ADD, S- SUB, M- MULT, - MIN, + MAX") + print(" to change the blend modes") + + +main_dir = os.path.split(os.path.abspath(__file__))[0] +data_dir = os.path.join(main_dir, "data") + + +def main(): + color = [0, 0, 0] + changed = False + blendtype = 0 + step = 5 + + pg.init() + screen = pg.display.set_mode((640, 480), 0, 32) + screen.fill((100, 100, 100)) + + image = pg.image.load(os.path.join(data_dir, "liquid.bmp")).convert() + blendimage = pg.image.load(os.path.join(data_dir, "liquid.bmp")).convert() + screen.blit(image, (10, 10)) + screen.blit(blendimage, (200, 10)) + + pg.display.flip() + pg.key.set_repeat(500, 30) + usage() + + going = True + while going: + for event in pg.event.get(): + if event.type == pg.QUIT: + going = False + + if event.type == pg.KEYDOWN: + usage() + + if event.key == pg.K_ESCAPE: + going = False + + if event.key == pg.K_r: + color[0] += step + if color[0] > 255: + color[0] = 0 + changed = True + + elif event.key == pg.K_g: + color[1] += step + if color[1] > 255: + color[1] = 0 + changed = True + + elif event.key == pg.K_b: + color[2] += step + if color[2] > 255: + color[2] = 0 + changed = True + + elif event.key == pg.K_a: + blendtype = pg.BLEND_ADD + changed = True + elif event.key == pg.K_s: + blendtype = pg.BLEND_SUB + changed = True + elif event.key == pg.K_m: + blendtype = pg.BLEND_MULT + changed = True + elif event.key == pg.K_PLUS: + blendtype = pg.BLEND_MAX + changed = True + elif event.key == pg.K_MINUS: + blendtype = pg.BLEND_MIN + changed = True + + elif event.key in (K_1, K_2, K_3, K_4, K_5, K_6, K_7, K_8, K_9): + step = int(event.unicode) + + if changed: + screen.fill((100, 100, 100)) + screen.blit(image, (10, 10)) + blendimage.blit(image, (0, 0)) + # blendimage.fill (color, (0, 0, 20, 20), blendtype) + blendimage.fill(color, None, blendtype) + screen.blit(blendimage, (200, 10)) + print( + "Color: %s, Pixel (0,0): %s" + % (tuple(color), [blendimage.get_at((0, 0))]) + ) + changed = False + pg.display.flip() + + pg.quit() + + +if __name__ == "__main__": + main() diff --git a/venv/Lib/site-packages/pygame/examples/blit_blends.py b/venv/Lib/site-packages/pygame/examples/blit_blends.py new file mode 100644 index 0000000..8bc8978 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/blit_blends.py @@ -0,0 +1,198 @@ +#!/usr/bin/env python +""" pygame.examples.blit_blends + +Blending colors in different ways with different blend modes. + +It also shows some tricks with the surfarray. +Including how to do additive blending. + + +Keyboard Controls +----------------- + +* R, G, B - add a bit of Red, Green, or Blue. +* A - Add blend mode +* S - Subtractive blend mode +* M - Multiply blend mode +* = key BLEND_MAX blend mode. +* - key BLEND_MIN blend mode. +* 1, 2, 3, 4 - use different images. + +""" +import os +import pygame as pg +import time + +main_dir = os.path.split(os.path.abspath(__file__))[0] +data_dir = os.path.join(main_dir, "data") + +try: + import pygame.surfarray + import numpy +except ImportError: + print("no surfarray for you! install numpy") + + +def main(): + pg.init() + pg.mixer.quit() # remove ALSA underflow messages for Debian squeeze + screen = pg.display.set_mode((640, 480)) + + im1 = pg.Surface(screen.get_size()) + # im1= im1.convert() + im1.fill((100, 0, 0)) + + im2 = pg.Surface(screen.get_size()) + im2.fill((0, 50, 0)) + # we make a srcalpha copy of it. + # im3= im2.convert(SRCALPHA) + im3 = im2 + im3.set_alpha(127) + + images = {} + images[pg.K_1] = im2 + images[pg.K_2] = pg.image.load(os.path.join(data_dir, "chimp.png")) + images[pg.K_3] = pg.image.load(os.path.join(data_dir, "alien3.gif")) + images[pg.K_4] = pg.image.load(os.path.join(data_dir, "liquid.bmp")) + img_to_blit = im2.convert() + iaa = img_to_blit.convert_alpha() + + blits = {} + blits[pg.K_a] = pg.BLEND_ADD + blits[pg.K_s] = pg.BLEND_SUB + blits[pg.K_m] = pg.BLEND_MULT + blits[pg.K_EQUALS] = pg.BLEND_MAX + blits[pg.K_MINUS] = pg.BLEND_MIN + + blitsn = {} + blitsn[pg.K_a] = "BLEND_ADD" + blitsn[pg.K_s] = "BLEND_SUB" + blitsn[pg.K_m] = "BLEND_MULT" + blitsn[pg.K_EQUALS] = "BLEND_MAX" + blitsn[pg.K_MINUS] = "BLEND_MIN" + + screen.blit(im1, (0, 0)) + pg.display.flip() + clock = pg.time.Clock() + print("one pixel is:%s:" % [im1.get_at((0, 0))]) + + going = True + while going: + clock.tick(60) + + for event in pg.event.get(): + if event.type == pg.QUIT: + going = False + if event.type == pg.KEYDOWN: + usage() + + if event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE: + going = False + + elif event.type == pg.KEYDOWN and event.key in images.keys(): + img_to_blit = images[event.key] + iaa = img_to_blit.convert_alpha() + + elif event.type == pg.KEYDOWN and event.key in blits.keys(): + t1 = time.time() + # blits is a dict keyed with key -> blit flag. eg BLEND_ADD. + im1.blit(img_to_blit, (0, 0), None, blits[event.key]) + t2 = time.time() + print("one pixel is:%s:" % [im1.get_at((0, 0))]) + print("time to do:%s:" % (t2 - t1)) + + elif event.type == pg.KEYDOWN and event.key in [pg.K_t]: + + for bkey in blits.keys(): + t1 = time.time() + + for x in range(300): + im1.blit(img_to_blit, (0, 0), None, blits[bkey]) + + t2 = time.time() + + # show which key we're doing... + onedoing = blitsn[bkey] + print("time to do :%s: is :%s:" % (onedoing, t2 - t1)) + + elif event.type == pg.KEYDOWN and event.key in [pg.K_o]: + t1 = time.time() + # blits is a dict keyed with key -> blit flag. eg BLEND_ADD. + im1.blit(iaa, (0, 0)) + t2 = time.time() + print("one pixel is:%s:" % [im1.get_at((0, 0))]) + print("time to do:%s:" % (t2 - t1)) + + elif event.type == pg.KEYDOWN and event.key == pg.K_SPACE: + # this additive blend without clamp two surfaces. + # im1.set_alpha(127) + # im1.blit(im1, (0,0)) + # im1.set_alpha(255) + t1 = time.time() + + im1p = pygame.surfarray.pixels2d(im1) + im2p = pygame.surfarray.pixels2d(im2) + im1p += im2p + del im1p + del im2p + t2 = time.time() + print("one pixel is:%s:" % [im1.get_at((0, 0))]) + print("time to do:%s:" % (t2 - t1)) + + elif event.type == pg.KEYDOWN and event.key in [pg.K_z]: + t1 = time.time() + im1p = pygame.surfarray.pixels3d(im1) + im2p = pygame.surfarray.pixels3d(im2) + im1p16 = im1p.astype(numpy.uint16) + im2p16 = im1p.astype(numpy.uint16) + im1p16 += im2p16 + im1p16 = numpy.minimum(im1p16, 255) + pygame.surfarray.blit_array(im1, im1p16) + + del im1p + del im2p + t2 = time.time() + print("one pixel is:%s:" % [im1.get_at((0, 0))]) + print("time to do:%s:" % (t2 - t1)) + + elif event.type == pg.KEYDOWN and event.key in [pg.K_r, pg.K_g, pg.K_b]: + # this adds one to each pixel. + colmap = {} + colmap[pg.K_r] = 0x10000 + colmap[pg.K_g] = 0x00100 + colmap[pg.K_b] = 0x00001 + im1p = pygame.surfarray.pixels2d(im1) + im1p += colmap[event.key] + del im1p + print("one pixel is:%s:" % [im1.get_at((0, 0))]) + + elif event.type == pg.KEYDOWN and event.key == pg.K_p: + print("one pixel is:%s:" % [im1.get_at((0, 0))]) + + elif event.type == pg.KEYDOWN and event.key == pg.K_f: + # this additive blend without clamp two surfaces. + + t1 = time.time() + im1.set_alpha(127) + im1.blit(im2, (0, 0)) + im1.set_alpha(255) + + t2 = time.time() + print("one pixel is:%s:" % [im1.get_at((0, 0))]) + print("time to do:%s:" % (t2 - t1)) + + screen.blit(im1, (0, 0)) + pg.display.flip() + + pg.quit() + + +def usage(): + print("press keys 1-5 to change image to blit.") + print("A - ADD, S- SUB, M- MULT, - MIN, + MAX") + print("T - timing test for special blend modes.") + + +if __name__ == "__main__": + usage() + main() diff --git a/venv/Lib/site-packages/pygame/examples/camera.py b/venv/Lib/site-packages/pygame/examples/camera.py new file mode 100644 index 0000000..34fc46e --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/camera.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +""" pygame.examples.camera + +Basic image capturing and display using pygame.camera + +Keyboard controls +----------------- + +- 0, start camera 0. +- 1, start camera 1. +- 9, start camera 9. +- 10, start camera... wait a minute! There's not 10 key! +""" +import pygame as pg +import pygame.camera + + +class VideoCapturePlayer(object): + + size = (640, 480) + + def __init__(self, **argd): + self.__dict__.update(**argd) + super(VideoCapturePlayer, self).__init__(**argd) + + # create a display surface. standard pygame stuff + self.display = pg.display.set_mode(self.size) + self.init_cams(0) + + def init_cams(self, which_cam_idx): + + # gets a list of available cameras. + self.clist = pygame.camera.list_cameras() + print(self.clist) + + if not self.clist: + raise ValueError("Sorry, no cameras detected.") + + try: + cam_id = self.clist[which_cam_idx] + except IndexError: + cam_id = self.clist[0] + + # creates the camera of the specified size and in RGB colorspace + self.camera = pygame.camera.Camera(cam_id, self.size, "RGB") + + # starts the camera + self.camera.start() + + self.clock = pg.time.Clock() + + # create a surface to capture to. for performance purposes, you want the + # bit depth to be the same as that of the display surface. + self.snapshot = pg.surface.Surface(self.size, 0, self.display) + + def get_and_flip(self): + # if you don't want to tie the framerate to the camera, you can check and + # see if the camera has an image ready. note that while this works + # on most cameras, some will never return true. + + self.snapshot = self.camera.get_image(self.display) + + # if 0 and self.camera.query_image(): + # # capture an image + + # self.snapshot = self.camera.get_image(self.snapshot) + + # if 0: + # self.snapshot = self.camera.get_image(self.snapshot) + # # self.snapshot = self.camera.get_image() + + # # blit it to the display surface. simple! + # self.display.blit(self.snapshot, (0, 0)) + # else: + + # self.snapshot = self.camera.get_image(self.display) + # # self.display.blit(self.snapshot, (0,0)) + + pg.display.flip() + + def main(self): + going = True + while going: + events = pg.event.get() + for e in events: + if e.type == pg.QUIT or (e.type == pg.KEYDOWN and e.key == pg.K_ESCAPE): + going = False + if e.type == pg.KEYDOWN: + if e.key in range(pg.K_0, pg.K_0 + 10): + self.init_cams(e.key - pg.K_0) + + self.get_and_flip() + self.clock.tick() + pygame.display.set_caption(f"CAMERA! ({self.clock.get_fps():.2f} FPS)") + + +def main(): + pg.init() + pygame.camera.init() + VideoCapturePlayer().main() + pg.quit() + + +if __name__ == "__main__": + main() diff --git a/venv/Lib/site-packages/pygame/examples/chimp.py b/venv/Lib/site-packages/pygame/examples/chimp.py new file mode 100644 index 0000000..4612be5 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/chimp.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python +""" pygame.examples.chimp + +This simple example is used for the line-by-line tutorial +that comes with pygame. It is based on a 'popular' web banner. +Note there are comments here, but for the full explanation, +follow along in the tutorial. +""" + + +# Import Modules +import os +import pygame as pg + +if not pg.font: + print("Warning, fonts disabled") +if not pg.mixer: + print("Warning, sound disabled") + +main_dir = os.path.split(os.path.abspath(__file__))[0] +data_dir = os.path.join(main_dir, "data") + + +# functions to create our resources +def load_image(name, colorkey=None, scale=1): + fullname = os.path.join(data_dir, name) + image = pg.image.load(fullname) + image = image.convert() + + size = image.get_size() + size = (size[0] * scale, size[1] * scale) + image = pg.transform.scale(image, size) + + if colorkey is not None: + if colorkey == -1: + colorkey = image.get_at((0, 0)) + image.set_colorkey(colorkey, pg.RLEACCEL) + return image, image.get_rect() + + +def load_sound(name): + class NoneSound: + def play(self): + pass + + if not pg.mixer or not pg.mixer.get_init(): + return NoneSound() + + fullname = os.path.join(data_dir, name) + sound = pg.mixer.Sound(fullname) + + return sound + + +# classes for our game objects +class Fist(pg.sprite.Sprite): + """moves a clenched fist on the screen, following the mouse""" + + def __init__(self): + pg.sprite.Sprite.__init__(self) # call Sprite initializer + self.image, self.rect = load_image("fist.png", -1) + self.fist_offset = (-235, -80) + self.punching = False + + def update(self): + """move the fist based on the mouse position""" + pos = pg.mouse.get_pos() + self.rect.topleft = pos + self.rect.move_ip(self.fist_offset) + if self.punching: + self.rect.move_ip(15, 25) + + def punch(self, target): + """returns true if the fist collides with the target""" + if not self.punching: + self.punching = True + hitbox = self.rect.inflate(-5, -5) + return hitbox.colliderect(target.rect) + + def unpunch(self): + """called to pull the fist back""" + self.punching = False + + +class Chimp(pg.sprite.Sprite): + """moves a monkey critter across the screen. it can spin the + monkey when it is punched.""" + + def __init__(self): + pg.sprite.Sprite.__init__(self) # call Sprite intializer + self.image, self.rect = load_image("chimp.png", -1, 4) + screen = pg.display.get_surface() + self.area = screen.get_rect() + self.rect.topleft = 10, 90 + self.move = 18 + self.dizzy = False + + def update(self): + """walk or spin, depending on the monkeys state""" + if self.dizzy: + self._spin() + else: + self._walk() + + def _walk(self): + """move the monkey across the screen, and turn at the ends""" + newpos = self.rect.move((self.move, 0)) + if not self.area.contains(newpos): + if self.rect.left < self.area.left or self.rect.right > self.area.right: + self.move = -self.move + newpos = self.rect.move((self.move, 0)) + self.image = pg.transform.flip(self.image, True, False) + self.rect = newpos + + def _spin(self): + """spin the monkey image""" + center = self.rect.center + self.dizzy = self.dizzy + 12 + if self.dizzy >= 360: + self.dizzy = False + self.image = self.original + else: + rotate = pg.transform.rotate + self.image = rotate(self.original, self.dizzy) + self.rect = self.image.get_rect(center=center) + + def punched(self): + """this will cause the monkey to start spinning""" + if not self.dizzy: + self.dizzy = True + self.original = self.image + + +def main(): + """this function is called when the program starts. + it initializes everything it needs, then runs in + a loop until the function returns.""" + # Initialize Everything + pg.init() + screen = pg.display.set_mode((1280, 480), pg.SCALED) + pg.display.set_caption("Monkey Fever") + pg.mouse.set_visible(False) + + # Create The Backgound + background = pg.Surface(screen.get_size()) + background = background.convert() + background.fill((170, 238, 187)) + + # Put Text On The Background, Centered + if pg.font: + font = pg.font.Font(None, 64) + text = font.render("Pummel The Chimp, And Win $$$", True, (10, 10, 10)) + textpos = text.get_rect(centerx=background.get_width() / 2, y=10) + background.blit(text, textpos) + + # Display The Background + screen.blit(background, (0, 0)) + pg.display.flip() + + # Prepare Game Objects + whiff_sound = load_sound("whiff.wav") + punch_sound = load_sound("punch.wav") + chimp = Chimp() + fist = Fist() + allsprites = pg.sprite.RenderPlain((chimp, fist)) + clock = pg.time.Clock() + + # Main Loop + going = True + while going: + clock.tick(60) + + # Handle Input Events + for event in pg.event.get(): + if event.type == pg.QUIT: + going = False + elif event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE: + going = False + elif event.type == pg.MOUSEBUTTONDOWN: + if fist.punch(chimp): + punch_sound.play() # punch + chimp.punched() + else: + whiff_sound.play() # miss + elif event.type == pg.MOUSEBUTTONUP: + fist.unpunch() + + allsprites.update() + + # Draw Everything + screen.blit(background, (0, 0)) + allsprites.draw(screen) + pg.display.flip() + + pg.quit() + + +# Game Over + + +# this calls the 'main' function when this script is executed +if __name__ == "__main__": + main() diff --git a/venv/Lib/site-packages/pygame/examples/cursors.py b/venv/Lib/site-packages/pygame/examples/cursors.py new file mode 100644 index 0000000..09e5d1f --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/cursors.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +""" pygame.examples.cursors + +Click a mouse button (if you have one!) and the cursor changes. + +""" +import pygame as pg + + +arrow = ( + "xX ", + "X.X ", + "X..X ", + "X...X ", + "X....X ", + "X.....X ", + "X......X ", + "X.......X ", + "X........X ", + "X.........X ", + "X......XXXXX ", + "X...X..X ", + "X..XX..X ", + "X.X XX..X ", + "XX X..X ", + "X X..X ", + " X..X ", + " X..X ", + " X..X ", + " XX ", + " ", + " ", + " ", + " ", +) + + +no = ( + " ", + " ", + " XXXXXX ", + " XX......XX ", + " X..........X ", + " X....XXXX....X ", + " X...XX XX...X ", + " X.....X X...X ", + " X..X...X X..X ", + " X...XX...X X...X ", + " X..X X...X X..X ", + " X..X X...X X..X ", + " X..X X.,.X X..X ", + " X..X X...X X..X ", + " X...X X...XX...X ", + " X..X X...X..X ", + " X...X X.....X ", + " X...XX X...X ", + " X....XXXXX...X ", + " X..........X ", + " XX......XX ", + " XXXXXX ", + " ", + " ", +) + + +def TestCursor(arrow): + hotspot = None + for y, line in enumerate(arrow): + for x, char in enumerate(line): + if char in ["x", ",", "O"]: + hotspot = x, y + break + if hotspot is not None: + break + if hotspot is None: + raise Exception("No hotspot specified for cursor '%s'!" % arrow) + s2 = [] + for line in arrow: + s2.append(line.replace("x", "X").replace(",", ".").replace("O", "o")) + cursor, mask = pg.cursors.compile(s2, "X", ".", "o") + size = len(arrow[0]), len(arrow) + pg.mouse.set_cursor(size, hotspot, cursor, mask) + + +def main(): + pg.init() + pg.font.init() + font = pg.font.Font(None, 24) + bg = pg.display.set_mode((800, 600), 0, 24) + bg.fill((255, 255, 255)) + bg.blit(font.render("Click to advance", 1, (0, 0, 0)), (0, 0)) + pg.display.update() + for cursor in [no, arrow]: + TestCursor(cursor) + going = True + while going: + pg.event.pump() + for e in pg.event.get(): + if e.type == pg.MOUSEBUTTONDOWN: + going = False + pg.quit() + + +if __name__ == "__main__": + main() diff --git a/venv/Lib/site-packages/pygame/examples/data/BGR.png b/venv/Lib/site-packages/pygame/examples/data/BGR.png new file mode 100644 index 0000000..f5dba74 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/BGR.png differ diff --git a/venv/Lib/site-packages/pygame/examples/data/alien1.gif b/venv/Lib/site-packages/pygame/examples/data/alien1.gif new file mode 100644 index 0000000..c4497e0 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/alien1.gif differ diff --git a/venv/Lib/site-packages/pygame/examples/data/alien1.jpg b/venv/Lib/site-packages/pygame/examples/data/alien1.jpg new file mode 100644 index 0000000..6d110a4 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/alien1.jpg differ diff --git a/venv/Lib/site-packages/pygame/examples/data/alien1.png b/venv/Lib/site-packages/pygame/examples/data/alien1.png new file mode 100644 index 0000000..471d6a4 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/alien1.png differ diff --git a/venv/Lib/site-packages/pygame/examples/data/alien2.gif b/venv/Lib/site-packages/pygame/examples/data/alien2.gif new file mode 100644 index 0000000..8df05a3 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/alien2.gif differ diff --git a/venv/Lib/site-packages/pygame/examples/data/alien2.png b/venv/Lib/site-packages/pygame/examples/data/alien2.png new file mode 100644 index 0000000..aef5ace Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/alien2.png differ diff --git a/venv/Lib/site-packages/pygame/examples/data/alien3.gif b/venv/Lib/site-packages/pygame/examples/data/alien3.gif new file mode 100644 index 0000000..5305d41 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/alien3.gif differ diff --git a/venv/Lib/site-packages/pygame/examples/data/alien3.png b/venv/Lib/site-packages/pygame/examples/data/alien3.png new file mode 100644 index 0000000..90d0f7c Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/alien3.png differ diff --git a/venv/Lib/site-packages/pygame/examples/data/arraydemo.bmp b/venv/Lib/site-packages/pygame/examples/data/arraydemo.bmp new file mode 100644 index 0000000..ad96338 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/arraydemo.bmp differ diff --git a/venv/Lib/site-packages/pygame/examples/data/asprite.bmp b/venv/Lib/site-packages/pygame/examples/data/asprite.bmp new file mode 100644 index 0000000..cc96356 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/asprite.bmp differ diff --git a/venv/Lib/site-packages/pygame/examples/data/background.gif b/venv/Lib/site-packages/pygame/examples/data/background.gif new file mode 100644 index 0000000..5041ce6 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/background.gif differ diff --git a/venv/Lib/site-packages/pygame/examples/data/black.ppm b/venv/Lib/site-packages/pygame/examples/data/black.ppm new file mode 100644 index 0000000..698a52c --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/data/black.ppm @@ -0,0 +1,3076 @@ +P3 +# Created by GIMP version 2.10.20 PNM plug-in +32 32 +255 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 diff --git a/venv/Lib/site-packages/pygame/examples/data/blue.gif b/venv/Lib/site-packages/pygame/examples/data/blue.gif new file mode 100644 index 0000000..98c6fd6 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/blue.gif differ diff --git a/venv/Lib/site-packages/pygame/examples/data/blue.mpg b/venv/Lib/site-packages/pygame/examples/data/blue.mpg new file mode 100644 index 0000000..60dceca Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/blue.mpg differ diff --git a/venv/Lib/site-packages/pygame/examples/data/bomb.gif b/venv/Lib/site-packages/pygame/examples/data/bomb.gif new file mode 100644 index 0000000..f885cbb Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/bomb.gif differ diff --git a/venv/Lib/site-packages/pygame/examples/data/boom.wav b/venv/Lib/site-packages/pygame/examples/data/boom.wav new file mode 100644 index 0000000..f19126a Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/boom.wav differ diff --git a/venv/Lib/site-packages/pygame/examples/data/brick.png b/venv/Lib/site-packages/pygame/examples/data/brick.png new file mode 100644 index 0000000..cfe37a3 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/brick.png differ diff --git a/venv/Lib/site-packages/pygame/examples/data/car_door.wav b/venv/Lib/site-packages/pygame/examples/data/car_door.wav new file mode 100644 index 0000000..60acf9e Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/car_door.wav differ diff --git a/venv/Lib/site-packages/pygame/examples/data/chimp.png b/venv/Lib/site-packages/pygame/examples/data/chimp.png new file mode 100644 index 0000000..9bf37b1 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/chimp.png differ diff --git a/venv/Lib/site-packages/pygame/examples/data/city.png b/venv/Lib/site-packages/pygame/examples/data/city.png new file mode 100644 index 0000000..202da5c Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/city.png differ diff --git a/venv/Lib/site-packages/pygame/examples/data/crimson.pnm b/venv/Lib/site-packages/pygame/examples/data/crimson.pnm new file mode 100644 index 0000000..28501e9 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/data/crimson.pnm @@ -0,0 +1,5 @@ +P6 +# CREATOR: GIMP PNM Filter Version 1.1 +32 32 +255 +<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< \ No newline at end of file diff --git a/venv/Lib/site-packages/pygame/examples/data/danger.gif b/venv/Lib/site-packages/pygame/examples/data/danger.gif new file mode 100644 index 0000000..106d69c Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/danger.gif differ diff --git a/venv/Lib/site-packages/pygame/examples/data/explosion1.gif b/venv/Lib/site-packages/pygame/examples/data/explosion1.gif new file mode 100644 index 0000000..fabec16 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/explosion1.gif differ diff --git a/venv/Lib/site-packages/pygame/examples/data/fist.png b/venv/Lib/site-packages/pygame/examples/data/fist.png new file mode 100644 index 0000000..9097629 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/fist.png differ diff --git a/venv/Lib/site-packages/pygame/examples/data/green.pcx b/venv/Lib/site-packages/pygame/examples/data/green.pcx new file mode 100644 index 0000000..c0aea8d Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/green.pcx differ diff --git a/venv/Lib/site-packages/pygame/examples/data/grey.pgm b/venv/Lib/site-packages/pygame/examples/data/grey.pgm new file mode 100644 index 0000000..b181a5d --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/data/grey.pgm @@ -0,0 +1,1028 @@ +P2 +# Created by GIMP version 2.10.20 PNM plug-in +32 32 +255 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 +120 diff --git a/venv/Lib/site-packages/pygame/examples/data/house_lo.mp3 b/venv/Lib/site-packages/pygame/examples/data/house_lo.mp3 new file mode 100644 index 0000000..4c26994 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/house_lo.mp3 differ diff --git a/venv/Lib/site-packages/pygame/examples/data/house_lo.ogg b/venv/Lib/site-packages/pygame/examples/data/house_lo.ogg new file mode 100644 index 0000000..e050848 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/house_lo.ogg differ diff --git a/venv/Lib/site-packages/pygame/examples/data/house_lo.wav b/venv/Lib/site-packages/pygame/examples/data/house_lo.wav new file mode 100644 index 0000000..68a96b8 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/house_lo.wav differ diff --git a/venv/Lib/site-packages/pygame/examples/data/laplacian.png b/venv/Lib/site-packages/pygame/examples/data/laplacian.png new file mode 100644 index 0000000..8d064f5 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/laplacian.png differ diff --git a/venv/Lib/site-packages/pygame/examples/data/liquid.bmp b/venv/Lib/site-packages/pygame/examples/data/liquid.bmp new file mode 100644 index 0000000..c4f12eb Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/liquid.bmp differ diff --git a/venv/Lib/site-packages/pygame/examples/data/midikeys.png b/venv/Lib/site-packages/pygame/examples/data/midikeys.png new file mode 100644 index 0000000..74ecb86 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/midikeys.png differ diff --git a/venv/Lib/site-packages/pygame/examples/data/player1.gif b/venv/Lib/site-packages/pygame/examples/data/player1.gif new file mode 100644 index 0000000..6c4eda7 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/player1.gif differ diff --git a/venv/Lib/site-packages/pygame/examples/data/punch.wav b/venv/Lib/site-packages/pygame/examples/data/punch.wav new file mode 100644 index 0000000..aa3f56c Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/punch.wav differ diff --git a/venv/Lib/site-packages/pygame/examples/data/purple.xpm b/venv/Lib/site-packages/pygame/examples/data/purple.xpm new file mode 100644 index 0000000..7798cc1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/data/purple.xpm @@ -0,0 +1,36 @@ +/* XPM */ +static char * C:\Users\Kristof\Documents\purple_xpm[] = { +"32 32 1 1", +" c #FF00FF", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/venv/Lib/site-packages/pygame/examples/data/red.jpg b/venv/Lib/site-packages/pygame/examples/data/red.jpg new file mode 100644 index 0000000..11a9aa0 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/red.jpg differ diff --git a/venv/Lib/site-packages/pygame/examples/data/sans.ttf b/venv/Lib/site-packages/pygame/examples/data/sans.ttf new file mode 100644 index 0000000..09fac2f Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/sans.ttf differ diff --git a/venv/Lib/site-packages/pygame/examples/data/scarlet.webp b/venv/Lib/site-packages/pygame/examples/data/scarlet.webp new file mode 100644 index 0000000..cd0a15c Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/scarlet.webp differ diff --git a/venv/Lib/site-packages/pygame/examples/data/secosmic_lo.wav b/venv/Lib/site-packages/pygame/examples/data/secosmic_lo.wav new file mode 100644 index 0000000..867f802 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/secosmic_lo.wav differ diff --git a/venv/Lib/site-packages/pygame/examples/data/shot.gif b/venv/Lib/site-packages/pygame/examples/data/shot.gif new file mode 100644 index 0000000..18de528 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/shot.gif differ diff --git a/venv/Lib/site-packages/pygame/examples/data/static.png b/venv/Lib/site-packages/pygame/examples/data/static.png new file mode 100644 index 0000000..fb3b057 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/static.png differ diff --git a/venv/Lib/site-packages/pygame/examples/data/teal.svg b/venv/Lib/site-packages/pygame/examples/data/teal.svg new file mode 100644 index 0000000..85f4149 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/data/teal.svg @@ -0,0 +1,9 @@ + + teal + + + Layer 1 + + + + diff --git a/venv/Lib/site-packages/pygame/examples/data/turquoise.tif b/venv/Lib/site-packages/pygame/examples/data/turquoise.tif new file mode 100644 index 0000000..39b3620 Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/turquoise.tif differ diff --git a/venv/Lib/site-packages/pygame/examples/data/whiff.wav b/venv/Lib/site-packages/pygame/examples/data/whiff.wav new file mode 100644 index 0000000..3954efa Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/whiff.wav differ diff --git a/venv/Lib/site-packages/pygame/examples/data/yellow.tga b/venv/Lib/site-packages/pygame/examples/data/yellow.tga new file mode 100644 index 0000000..d0124fe Binary files /dev/null and b/venv/Lib/site-packages/pygame/examples/data/yellow.tga differ diff --git a/venv/Lib/site-packages/pygame/examples/dropevent.py b/venv/Lib/site-packages/pygame/examples/dropevent.py new file mode 100644 index 0000000..e812558 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/dropevent.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +""" pygame.examples.dropfile + +Drag and drop an image on here. + +Uses these events: + +* DROPBEGIN +* DROPCOMPLETE +* DROPTEXT +* DROPFILE +""" +import pygame as pg + +if pg.get_sdl_version() < (2, 0, 0): + raise Exception("This example requires SDL2.") + +pg.init() + + +def main(): + + Running = True + surf = pg.display.set_mode((640, 480)) + font = pg.font.SysFont("Arial", 24) + clock = pg.time.Clock() + + spr_file_text = font.render("Feed me some file or image!", 1, (255, 255, 255)) + spr_file_text_rect = spr_file_text.get_rect() + spr_file_text_rect.center = surf.get_rect().center + + spr_file_image = None + spr_file_image_rect = None + + while Running: + for ev in pg.event.get(): + if ev.type == pg.QUIT: + Running = False + elif ev.type == pg.DROPBEGIN: + print(ev) + print("File drop begin!") + elif ev.type == pg.DROPCOMPLETE: + print(ev) + print("File drop complete!") + elif ev.type == pg.DROPTEXT: + print(ev) + spr_file_text = font.render(ev.text, 1, (255, 255, 255)) + spr_file_text_rect = spr_file_text.get_rect() + spr_file_text_rect.center = surf.get_rect().center + elif ev.type == pg.DROPFILE: + print(ev) + spr_file_text = font.render(ev.file, 1, (255, 255, 255)) + spr_file_text_rect = spr_file_text.get_rect() + spr_file_text_rect.center = surf.get_rect().center + + # Try to open the file if it's an image + filetype = ev.file[-3:] + if filetype in ["png", "bmp", "jpg"]: + spr_file_image = pg.image.load(ev.file).convert() + spr_file_image.set_alpha(127) + spr_file_image_rect = spr_file_image.get_rect() + spr_file_image_rect.center = surf.get_rect().center + + surf.fill((0, 0, 0)) + surf.blit(spr_file_text, spr_file_text_rect) + if spr_file_image: + surf.blit(spr_file_image, spr_file_image_rect) + + pg.display.flip() + clock.tick(30) + + pg.quit() + + +if __name__ == "__main__": + main() diff --git a/venv/Lib/site-packages/pygame/examples/eventlist.py b/venv/Lib/site-packages/pygame/examples/eventlist.py new file mode 100644 index 0000000..b329586 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/eventlist.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python +""" pygame.examples.eventlist + +Learn about pygame events and input. + +At the top of the screen are the state of several device values, +and a scrolling list of events are displayed on the bottom. + +""" + +usage = """ +Mouse Controls +============== + +- 1st button on mouse (left click) to toggle events 'grabed'. +- 3rd button on mouse (right click) to toggle mouse visible. +- The window can be resized. +- Mouse the mouse around to see mouse events. +- If events grabbed and mouse invisible show virtual mouse coords. + + +Keyboard Joystick Controls +========================== + +- press keys up an down to see events. +- you can see joystick events if any are plugged in. +- press "c" to toggle events generated by controllers. +""" + +import pygame as pg + +try: + import pygame._sdl2.controller + + pygame._sdl2.controller.init() + SDL2 = True +except ImportError: + SDL2 = False + +img_on_off = [] +font = None +last_key = None + +# these are a running counter of mouse.get_rel() calls. +virtual_x = 0 +virtual_y = 0 + + +def showtext(win, pos, text, color, bgcolor): + textimg = font.render(text, 1, color, bgcolor) + win.blit(textimg, pos) + return pos[0] + textimg.get_width() + 5, pos[1] + + +def drawstatus(win): + global virtual_x, virtual_y + bgcolor = 50, 50, 50 + win.fill(bgcolor, (0, 0, 640, 120)) + win.blit(font.render("Status Area", 1, (155, 155, 155), bgcolor), (2, 2)) + + pos = showtext(win, (10, 30), "Mouse Focus", (255, 255, 255), bgcolor) + win.blit(img_on_off[pg.mouse.get_focused()], pos) + + pos = showtext( + win, (pos[0] + 50, pos[1]), "Mouse visible", (255, 255, 255), bgcolor + ) + win.blit(img_on_off[pg.mouse.get_visible()], pos) + + pos = showtext(win, (330, 30), "Keyboard Focus", (255, 255, 255), bgcolor) + win.blit(img_on_off[pg.key.get_focused()], pos) + + pos = showtext(win, (10, 60), "Mouse Position(rel)", (255, 255, 255), bgcolor) + rel = pg.mouse.get_rel() + virtual_x += rel[0] + virtual_y += rel[1] + + mouse_data = tuple(list(pg.mouse.get_pos()) + list(rel)) + p = "%s, %s (%s, %s)" % mouse_data + showtext(win, pos, p, bgcolor, (255, 255, 55)) + + pos = showtext(win, (330, 60), "Last Keypress", (255, 255, 255), bgcolor) + if last_key: + p = "%d, %s" % (last_key, pg.key.name(last_key)) + else: + p = "None" + showtext(win, pos, p, bgcolor, (255, 255, 55)) + + pos = showtext(win, (10, 90), "Input Grabbed", (255, 255, 255), bgcolor) + win.blit(img_on_off[pg.event.get_grab()], pos) + + is_virtual_mouse = pg.event.get_grab() and not pg.mouse.get_visible() + pos = showtext(win, (330, 90), "Virtual Mouse", (255, 255, 255), bgcolor) + win.blit(img_on_off[is_virtual_mouse], pos) + if is_virtual_mouse: + p = "%s, %s" % (virtual_x, virtual_y) + showtext(win, (pos[0] + 50, pos[1]), p, bgcolor, (255, 255, 55)) + + +def drawhistory(win, history): + img = font.render("Event History Area", 1, (155, 155, 155), (0, 0, 0)) + win.blit(img, (2, 132)) + ypos = 450 + h = list(history) + h.reverse() + for line in h: + r = win.blit(line, (10, ypos)) + win.fill(0, (r.right, r.top, 620, r.height)) + ypos -= font.get_height() + + +def draw_usage_in_history(history, text): + lines = text.split("\n") + for line in lines: + if line == "" or "===" in line: + continue + img = font.render(line, 1, (50, 200, 50), (0, 0, 0)) + history.append(img) + + +def main(): + pg.init() + print(usage) + + win = pg.display.set_mode((640, 480), pg.RESIZABLE) + pg.display.set_caption("Mouse Focus Workout. h key for help") + + global font + font = pg.font.Font(None, 26) + + global img_on_off + img_on_off.append(font.render("Off", 1, (0, 0, 0), (255, 50, 50))) + img_on_off.append(font.render("On", 1, (0, 0, 0), (50, 255, 50))) + + # stores surfaces of text representing what has gone through the event queue + history = [] + + # let's turn on the joysticks just so we can play with em + for x in range(pg.joystick.get_count()): + if SDL2 and pg._sdl2.controller.is_controller(x): + c = pg._sdl2.controller.Controller(x) + txt = "Enabled controller: " + c.name + else: + j = pg.joystick.Joystick(x) + txt = "Enabled joystick: " + j.get_name() + + img = font.render(txt, 1, (50, 200, 50), (0, 0, 0)) + history.append(img) + if not pg.joystick.get_count(): + img = font.render("No Joysticks to Initialize", 1, (50, 200, 50), (0, 0, 0)) + history.append(img) + + going = True + while going: + for e in pg.event.get(): + if e.type == pg.KEYDOWN: + if e.key == pg.K_ESCAPE: + going = False + else: + global last_key + last_key = e.key + if e.key == pg.K_h: + draw_usage_in_history(history, usage) + if SDL2 and e.key == pg.K_c: + current_state = pg._sdl2.controller.get_eventstate() + pg._sdl2.controller.set_eventstate(not current_state) + + if e.type == pg.MOUSEBUTTONDOWN and e.button == 1: + pg.event.set_grab(not pg.event.get_grab()) + + if e.type == pg.MOUSEBUTTONDOWN and e.button == 3: + pg.mouse.set_visible(not pg.mouse.get_visible()) + + if e.type != pg.MOUSEMOTION: + txt = "%s: %s" % (pg.event.event_name(e.type), e.dict) + img = font.render(txt, 1, (50, 200, 50), (0, 0, 0)) + history.append(img) + history = history[-13:] + + if e.type == pg.VIDEORESIZE: + win = pg.display.set_mode(e.size, pg.RESIZABLE) + + if e.type == pg.QUIT: + going = False + + drawstatus(win) + drawhistory(win, history) + + pg.display.flip() + pg.time.wait(10) + + pg.quit() + raise SystemExit + + +if __name__ == "__main__": + main() diff --git a/venv/Lib/site-packages/pygame/examples/font_viewer.py b/venv/Lib/site-packages/pygame/examples/font_viewer.py new file mode 100644 index 0000000..7170fd4 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/font_viewer.py @@ -0,0 +1,279 @@ +#!/usr/bin/env python +""" pygame.examples.font_viewer +Scroll through your system fonts from a list of surfaces or one huge buffer. + +This example exhibits: +* iterate over available fonts using font.get_fonts and font.SysFont() +* click and drag using mouse input +* scrolling with the scroll wheel +* save a surface to disk +* work with a very large surface +* simple mouse and keyboard scroll speed acceleration + +By default this example uses the fonts returned by pygame.font.get_fonts() +and opens them using pygame.font.SysFont(). +Alternatively, you may pass a path to the command line. The TTF files found +in that directory will be used instead. + +Mouse Controls: +* Use the mouse wheel or click and drag to scroll + +Keyboard Controls: +* Press up or down to scroll +* Press escape to exit +""" +import sys +import os + +import pygame as pg + +use_big_surface = False # draw into large buffer and save png file + + +class FontViewer: + """ + This example is encapsulated by the fontviewer class + It initializes the pygame window, handles input, and draws itself + to the screen. + """ + + KEY_SCROLL_SPEED = 10 + MOUSE_SCROLL_SPEED = 50 + + def __init__(self, **dparams): + pg.init() + self.font_dir = dparams.get("folder", None) + + # create a window that uses 80 percent of the screen + info = pg.display.Info() + w = info.current_w + h = info.current_h + pg.display.set_mode((int(w * 0.8), int(h * 0.8))) + self.font_size = h // 20 + + self.clock = pg.time.Clock() + self.y_offset = 0 + self.grabbed = False + self.render_fonts("&N abcDEF789") + + if use_big_surface or "big" in sys.argv: + self.render_surface() + self.display_surface() + self.save_png() + else: + self.display_fonts() + + def get_font_list(self): + """ + Generate a font list using font.get_fonts() for system fonts or + from a path from the command line. + """ + path = "" + if len(sys.argv) > 1 and os.path.exists(sys.argv[1]): + path = os.path.join(sys.argv[1], "") + fonts = [] + if os.path.exists(path): + # this list comprehension could replace the following loop + # fonts = [f in os.listdir(path) if f.endswith('.ttf')] + for font in os.listdir(path): + if font.endswith(".ttf"): + fonts.append(font) + return fonts or pg.font.get_fonts(), path + + def render_fonts(self, text="A display of font &N", **dparams): + """ + Build a list that includes a surface and the running total of their + height for each font in the font list. Store the largest width and + other variables for later use. + """ + font_size = dparams.get("size", 0) or self.font_size + color = dparams.get("color", (255, 255, 255)) + self.back_color = dparams.get("back_color", (0, 0, 0)) + + fonts, path = self.get_font_list() + font_surfaces = [] + total_height = 0 + max_width = 0 + + load_font = pg.font.Font if path else pg.font.SysFont + + # display instructions at the top of the display + font = pg.font.SysFont(pg.font.get_default_font(), font_size) + lines = ( + "Use the scroll wheel or click and drag", + "to scroll up and down", + "Foreign fonts might render incorrectly", + "Here are your {} fonts".format(len(fonts)), + "", + ) + for line in lines: + surf = font.render(line, 1, color, self.back_color) + font_surfaces.append((surf, total_height)) + total_height += surf.get_height() + max_width = max(max_width, surf.get_width()) + + # render all the fonts and store them with the total height + for name in sorted(fonts): + try: + font = load_font(path + name, font_size) + except IOError: + continue + line = text.replace("&N", name) + try: + surf = font.render(line, 1, color, self.back_color) + except pg.error as e: + print(e) + break + + max_width = max(max_width, surf.get_width()) + font_surfaces.append((surf, total_height)) + total_height += surf.get_height() + + # store variables for later usage + self.total_height = total_height + self.max_width = max_width + self.font_surfaces = font_surfaces + self.max_y = total_height - pg.display.get_surface().get_height() + + def display_fonts(self): + """ + Display the visible fonts based on the y_offset value(updated in + handle_events) and the height of the pygame window. + """ + display = pg.display.get_surface() + clock = pg.time.Clock() + center = display.get_width() // 2 + + while True: + # draw visible surfaces + display.fill(self.back_color) + for surface, top in self.font_surfaces: + bottom = top + surface.get_height() + if ( + bottom >= self.y_offset + and top <= self.y_offset + display.get_height() + ): + x = center - surface.get_width() // 2 + display.blit(surface, (x, top - self.y_offset)) + # get input and update the screen + if not self.handle_events(): + break + pg.display.flip() + clock.tick(30) + + def render_surface(self): + """ + Note: this method uses twice the memory and is only called if + big_surface is set to true or big is added to the command line. + + Optionally generates one large buffer to draw all the font surfaces + into. This is necessary to save the display to a png file and may + be useful for testing large surfaces. + """ + + large_surface = pg.surface.Surface( + (self.max_width, self.total_height) + ).convert() + large_surface.fill(self.back_color) + print("scrolling surface created") + + # display the surface size and memory usage + byte_size = large_surface.get_bytesize() + total_size = byte_size * (self.max_width * self.total_height) + print( + "Surface Size = {}x{} @ {}bpp: {:,.3f}mb".format( + self.max_width, self.total_height, byte_size, total_size / 1000000.0 + ) + ) + + y = 0 + center = int(self.max_width / 2) + for surface, top in self.font_surfaces: + w = surface.get_width() + x = center - int(w / 2) + large_surface.blit(surface, (x, y)) + y += surface.get_height() + self.max_y = large_surface.get_height() - pg.display.get_surface().get_height() + self.surface = large_surface + + def display_surface(self, time=10): + """ + Display the large surface created by the render_surface method. Scrolls + based on the y_offset value(set in handle_events) and the height of the + pygame window. + """ + screen = pg.display.get_surface() + + # Create a Rect equal to size of screen. Then we can just change its + # top attribute to draw the desired part of the rendered font surface + # to the display surface + rect = pg.rect.Rect( + 0, + 0, + self.surface.get_width(), + min(self.surface.get_height(), screen.get_height()), + ) + + x = int((screen.get_width() - self.surface.get_width()) / 2) + going = True + while going: + if not self.handle_events(): + going = False + screen.fill(self.back_color) + rect.top = self.y_offset + screen.blit(self.surface, (x, 0), rect) + pg.display.flip() + self.clock.tick(20) + + def save_png(self, name="font_viewer.png"): + pg.image.save(self.surface, name) + file_size = os.path.getsize(name) // 1024 + print("font surface saved to {}\nsize: {:,}Kb".format(name, file_size)) + + def handle_events(self): + """ + This method handles user input. It returns False when it receives + a pygame.QUIT event or the user presses escape. The y_offset is + changed based on mouse and keyboard input. display_fonts() and + display_surface() use the y_offset to scroll display. + """ + events = pg.event.get() + for e in events: + if e.type == pg.QUIT: + return False + elif e.type == pg.KEYDOWN: + if e.key == pg.K_ESCAPE: + return False + elif e.type == pg.MOUSEWHEEL: + self.y_offset += e.y * self.MOUSE_SCROLL_SPEED * -1 + elif e.type == pg.MOUSEBUTTONDOWN: + # enter dragging mode on mouse down + self.grabbed = True + pg.event.set_grab(True) + elif e.type == pg.MOUSEBUTTONUP: + # exit drag mode on mouse up + self.grabbed = False + pg.event.set_grab(False) + + # allow simple accelerated scrolling with the keyboard + keys = pg.key.get_pressed() + if keys[pg.K_UP]: + self.key_held += 1 + self.y_offset -= int(self.KEY_SCROLL_SPEED * (self.key_held // 10)) + elif keys[pg.K_DOWN]: + self.key_held += 1 + self.y_offset += int(self.KEY_SCROLL_SPEED * (self.key_held // 10)) + else: + self.key_held = 20 + + # set the y_offset for scrolling and keep it between 0 and max_y + y = pg.mouse.get_rel()[1] + if y and self.grabbed: + self.y_offset -= y + + self.y_offset = min((max(self.y_offset, 0), self.max_y)) + return True + + +viewer = FontViewer() +pg.quit() diff --git a/venv/Lib/site-packages/pygame/examples/fonty.py b/venv/Lib/site-packages/pygame/examples/fonty.py new file mode 100644 index 0000000..3eed676 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/fonty.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python +""" pygame.examples.fonty + +Here we load a .TTF True Type font file, and display it in +a basic pygame window. + +Demonstrating several Font object attributes. + +- basic window, event, and font management. +""" +import pygame as pg + +def main(): + # initialize + pg.init() + resolution = 400, 200 + screen = pg.display.set_mode(resolution) + + ## pg.mouse.set_cursor(*pg.cursors.diamond) + + fg = 250, 240, 230 + bg = 5, 5, 5 + wincolor = 40, 40, 90 + + # fill background + screen.fill(wincolor) + + # load font, prepare values + font = pg.font.Font(None, 80) + text = "Fonty" + size = font.size(text) + + # no AA, no transparancy, normal + ren = font.render(text, 0, fg, bg) + screen.blit(ren, (10, 10)) + + # no AA, transparancy, underline + font.set_underline(1) + ren = font.render(text, 0, fg) + screen.blit(ren, (10, 40 + size[1])) + font.set_underline(0) + + a_sys_font = pg.font.SysFont("Arial", 60) + + # AA, no transparancy, bold + a_sys_font.set_bold(1) + ren = a_sys_font.render(text, 1, fg, bg) + screen.blit(ren, (30 + size[0], 10)) + a_sys_font.set_bold(0) + + # AA, transparancy, italic + a_sys_font.set_italic(1) + ren = a_sys_font.render(text, 1, fg) + screen.blit(ren, (30 + size[0], 40 + size[1])) + a_sys_font.set_italic(0) + + # Get some metrics. + print("Font metrics for 'Fonty': %s" % a_sys_font.metrics(text)) + ch = "\u3060" + msg = "Font metrics for '%s': %s" % (ch, a_sys_font.metrics(ch)) + print(msg) + + ## #some_japanese_unicode = u"\u304b\u3070\u306b" + ##some_japanese_unicode = unicode_('%c%c%c') % (0x304b, 0x3070, 0x306b) + + # AA, transparancy, italic + ##ren = a_sys_font.render(some_japanese_unicode, 1, fg) + ##screen.blit(ren, (30 + size[0], 40 + size[1])) + + # show the surface and await user quit + pg.display.flip() + while True: + # use event.wait to keep from polling 100% cpu + if pg.event.wait().type in (pg.QUIT, pg.KEYDOWN, pg.MOUSEBUTTONDOWN): + break + pg.quit() + + +if __name__ == "__main__": + main() diff --git a/venv/Lib/site-packages/pygame/examples/freetype_misc.py b/venv/Lib/site-packages/pygame/examples/freetype_misc.py new file mode 100644 index 0000000..d07c422 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/freetype_misc.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python +""" pygame.examples.freetype_misc + + +Miscellaneous (or misc) means: + "consisting of a mixture of various things that are not + usually connected with each other" + Adjective + + +All those words you read on computers, magazines, books, and such over the years? +Probably a lot of them were constructed with... + +The FreeType Project: a free, high-quality and portable Font engine. +https://freetype.org + +Next time you're reading something. Think of them. + + +Herein lies a *BOLD* demo consisting of a mixture of various things. + + Not only is it a *BOLD* demo, it's an + italics demo, + a rotated demo, + it's a blend, + and is sized to go nicely with a cup of tea*. + + * also goes well with coffee. + +Enjoy! +""" +import os +import pygame as pg +import pygame.freetype as freetype + + +def run(): + pg.init() + + fontdir = os.path.dirname(os.path.abspath(__file__)) + font = freetype.Font(os.path.join(fontdir, "data", "sans.ttf")) + + screen = pg.display.set_mode((800, 600)) + screen.fill("gray") + + font.underline_adjustment = 0.5 + font.pad = True + font.render_to( + screen, + (32, 32), + "Hello World", + "red3", + "dimgray", + size=64, + style=freetype.STYLE_UNDERLINE | freetype.STYLE_OBLIQUE, + ) + font.pad = False + + font.render_to( + screen, + (32, 128), + "abcdefghijklm", + "dimgray", + "green3", + size=64, + ) + + font.vertical = True + font.render_to(screen, (32, 200), "Vertical?", "blue3", None, size=32) + font.vertical = False + + font.render_to(screen, (64, 190), "Let's spin!", "red3", None, size=48, rotation=55) + + font.render_to( + screen, (160, 290), "All around!", "green3", None, size=48, rotation=-55 + ) + + font.render_to(screen, (250, 220), "and BLEND", (255, 0, 0, 128), None, size=64) + + font.render_to(screen, (265, 237), "or BLAND!", (0, 0xCC, 28, 128), None, size=64) + + # Some pinwheels + font.origin = True + for angle in range(0, 360, 45): + font.render_to(screen, (150, 420), ")", "black", size=48, rotation=angle) + font.vertical = True + for angle in range(15, 375, 30): + font.render_to(screen, (600, 400), "|^*", "orange", size=48, rotation=angle) + font.vertical = False + font.origin = False + + utext = "I \u2665 Unicode" + font.render_to(screen, (298, 320), utext, (0, 0xCC, 0xDD), None, size=64) + + utext = "\u2665" + font.render_to(screen, (480, 32), utext, "gray", "red3", size=148) + + font.render_to( + screen, + (380, 380), + "...yes, this is an SDL surface", + "black", + None, + size=24, + style=freetype.STYLE_STRONG, + ) + + font.origin = True + r = font.render_to( + screen, + (100, 530), + "stretch", + "red3", + None, + size=(24, 24), + style=freetype.STYLE_NORMAL, + ) + font.render_to( + screen, + (100 + r.width, 530), + " VERTICAL", + "red3", + None, + size=(24, 48), + style=freetype.STYLE_NORMAL, + ) + + r = font.render_to( + screen, + (100, 580), + "stretch", + "blue3", + None, + size=(24, 24), + style=freetype.STYLE_NORMAL, + ) + font.render_to( + screen, + (100 + r.width, 580), + " HORIZONTAL", + "blue3", + None, + size=(48, 24), + style=freetype.STYLE_NORMAL, + ) + + pg.display.flip() + + while 1: + if pg.event.wait().type in (pg.QUIT, pg.KEYDOWN, pg.MOUSEBUTTONDOWN): + break + + pg.quit() + + +if __name__ == "__main__": + run() diff --git a/venv/Lib/site-packages/pygame/examples/glcube.py b/venv/Lib/site-packages/pygame/examples/glcube.py new file mode 100644 index 0000000..9d85c24 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/glcube.py @@ -0,0 +1,591 @@ +#!/usr/bin/env python +""" pygame.examples.glcube + +Draw a cube on the screen. + + + +Amazing. + +Every frame we orbit the camera around a small amount +creating the illusion of a spinning object. + +First we setup some points of a multicolored cube. Then we then go through +a semi-unoptimized loop to draw the cube points onto the screen. + +OpenGL does all the hard work for us. :] + + +Keyboard Controls +----------------- + +* ESCAPE key to quit +* f key to toggle fullscreen. + +""" +import math +import ctypes + +import pygame as pg + +try: + import OpenGL.GL as GL + import OpenGL.GLU as GLU +except ImportError: + print("pyopengl missing. The GLCUBE example requires: pyopengl numpy") + raise SystemExit + +try: + from numpy import array, dot, eye, zeros, float32, uint32 +except ImportError: + print("numpy missing. The GLCUBE example requires: pyopengl numpy") + raise SystemExit + + +# do we want to use the 'modern' OpenGL API or the old one? +# This example shows you how to do both. +USE_MODERN_GL = True + +# Some simple data for a colored cube here we have the 3D point position +# and color for each corner. A list of indices describes each face, and a +# list of indices describes each edge. + +CUBE_POINTS = ( + (0.5, -0.5, -0.5), + (0.5, 0.5, -0.5), + (-0.5, 0.5, -0.5), + (-0.5, -0.5, -0.5), + (0.5, -0.5, 0.5), + (0.5, 0.5, 0.5), + (-0.5, -0.5, 0.5), + (-0.5, 0.5, 0.5), +) + +# colors are 0-1 floating values +CUBE_COLORS = ( + (1, 0, 0), + (1, 1, 0), + (0, 1, 0), + (0, 0, 0), + (1, 0, 1), + (1, 1, 1), + (0, 0, 1), + (0, 1, 1), +) + +CUBE_QUAD_VERTS = ( + (0, 1, 2, 3), + (3, 2, 7, 6), + (6, 7, 5, 4), + (4, 5, 1, 0), + (1, 5, 7, 2), + (4, 0, 3, 6), +) + +CUBE_EDGES = ( + (0, 1), + (0, 3), + (0, 4), + (2, 1), + (2, 3), + (2, 7), + (6, 3), + (6, 4), + (6, 7), + (5, 1), + (5, 4), + (5, 7), +) + + +def translate(matrix, x=0.0, y=0.0, z=0.0): + """ + Translate (move) a matrix in the x, y and z axes. + + :param matrix: Matrix to translate. + :param x: direction and magnitude to translate in x axis. Defaults to 0. + :param y: direction and magnitude to translate in y axis. Defaults to 0. + :param z: direction and magnitude to translate in z axis. Defaults to 0. + :return: The translated matrix. + """ + translation_matrix = array( + [ + [1.0, 0.0, 0.0, x], + [0.0, 1.0, 0.0, y], + [0.0, 0.0, 1.0, z], + [0.0, 0.0, 0.0, 1.0], + ], + dtype=matrix.dtype, + ).T + matrix[...] = dot(matrix, translation_matrix) + return matrix + + +def frustum(left, right, bottom, top, znear, zfar): + """ + Build a perspective matrix from the clipping planes, or camera 'frustrum' + volume. + + :param left: left position of the near clipping plane. + :param right: right position of the near clipping plane. + :param bottom: bottom position of the near clipping plane. + :param top: top position of the near clipping plane. + :param znear: z depth of the near clipping plane. + :param zfar: z depth of the far clipping plane. + + :return: A perspective matrix. + """ + perspective_matrix = zeros((4, 4), dtype=float32) + perspective_matrix[0, 0] = +2.0 * znear / (right - left) + perspective_matrix[2, 0] = (right + left) / (right - left) + perspective_matrix[1, 1] = +2.0 * znear / (top - bottom) + perspective_matrix[3, 1] = (top + bottom) / (top - bottom) + perspective_matrix[2, 2] = -(zfar + znear) / (zfar - znear) + perspective_matrix[3, 2] = -2.0 * znear * zfar / (zfar - znear) + perspective_matrix[2, 3] = -1.0 + return perspective_matrix + + +def perspective(fovy, aspect, znear, zfar): + """ + Build a perspective matrix from field of view, aspect ratio and depth + planes. + + :param fovy: the field of view angle in the y axis. + :param aspect: aspect ratio of our view port. + :param znear: z depth of the near clipping plane. + :param zfar: z depth of the far clipping plane. + + :return: A perspective matrix. + """ + h = math.tan(fovy / 360.0 * math.pi) * znear + w = h * aspect + return frustum(-w, w, -h, h, znear, zfar) + + +def rotate(matrix, angle, x, y, z): + """ + Rotate a matrix around an axis. + + :param matrix: The matrix to rotate. + :param angle: The angle to rotate by. + :param x: x of axis to rotate around. + :param y: y of axis to rotate around. + :param z: z of axis to rotate around. + + :return: The rotated matrix + """ + angle = math.pi * angle / 180 + c, s = math.cos(angle), math.sin(angle) + n = math.sqrt(x * x + y * y + z * z) + x, y, z = x / n, y / n, z / n + cx, cy, cz = (1 - c) * x, (1 - c) * y, (1 - c) * z + rotation_matrix = array( + [ + [cx * x + c, cy * x - z * s, cz * x + y * s, 0], + [cx * y + z * s, cy * y + c, cz * y - x * s, 0], + [cx * z - y * s, cy * z + x * s, cz * z + c, 0], + [0, 0, 0, 1], + ], + dtype=matrix.dtype, + ).T + matrix[...] = dot(matrix, rotation_matrix) + return matrix + + +class Rotation: + """ + Data class that stores rotation angles in three axes. + """ + + def __init__(self): + self.theta = 20 + self.phi = 40 + self.psi = 25 + + +def drawcube_old(): + """ + Draw the cube using the old open GL methods pre 3.2 core context. + """ + allpoints = list(zip(CUBE_POINTS, CUBE_COLORS)) + + GL.glBegin(GL.GL_QUADS) + for face in CUBE_QUAD_VERTS: + for vert in face: + pos, color = allpoints[vert] + GL.glColor3fv(color) + GL.glVertex3fv(pos) + GL.glEnd() + + GL.glColor3f(1.0, 1.0, 1.0) + GL.glBegin(GL.GL_LINES) + for line in CUBE_EDGES: + for vert in line: + pos, color = allpoints[vert] + GL.glVertex3fv(pos) + + GL.glEnd() + + +def init_gl_stuff_old(): + """ + Initialise open GL, prior to core context 3.2 + """ + GL.glEnable(GL.GL_DEPTH_TEST) # use our zbuffer + + # setup the camera + GL.glMatrixMode(GL.GL_PROJECTION) + GL.glLoadIdentity() + GLU.gluPerspective(45.0, 640 / 480.0, 0.1, 100.0) # setup lens + GL.glTranslatef(0.0, 0.0, -3.0) # move back + GL.glRotatef(25, 1, 0, 0) # orbit higher + + +def init_gl_modern(display_size): + """ + Initialise open GL in the 'modern' open GL style for open GL versions + greater than 3.1. + + :param display_size: Size of the window/viewport. + """ + + # Create shaders + # -------------------------------------- + vertex_code = """ + + #version 150 + uniform mat4 model; + uniform mat4 view; + uniform mat4 projection; + + uniform vec4 colour_mul; + uniform vec4 colour_add; + + in vec4 vertex_colour; // vertex colour in + in vec3 vertex_position; + + out vec4 vertex_color_out; // vertex colour out + void main() + { + vertex_color_out = (colour_mul * vertex_colour) + colour_add; + gl_Position = projection * view * model * vec4(vertex_position, 1.0); + } + + """ + + fragment_code = """ + #version 150 + in vec4 vertex_color_out; // vertex colour from vertex shader + out vec4 fragColor; + void main() + { + fragColor = vertex_color_out; + } + """ + + program = GL.glCreateProgram() + vertex = GL.glCreateShader(GL.GL_VERTEX_SHADER) + fragment = GL.glCreateShader(GL.GL_FRAGMENT_SHADER) + GL.glShaderSource(vertex, vertex_code) + GL.glCompileShader(vertex) + + # this logs issues the shader compiler finds. + log = GL.glGetShaderInfoLog(vertex) + if isinstance(log, bytes): + log = log.decode() + for line in log.split("\n"): + print(line) + + GL.glAttachShader(program, vertex) + GL.glShaderSource(fragment, fragment_code) + GL.glCompileShader(fragment) + + # this logs issues the shader compiler finds. + log = GL.glGetShaderInfoLog(fragment) + if isinstance(log, bytes): + log = log.decode() + for line in log.split("\n"): + print(line) + + GL.glAttachShader(program, fragment) + GL.glValidateProgram(program) + GL.glLinkProgram(program) + + GL.glDetachShader(program, vertex) + GL.glDetachShader(program, fragment) + GL.glUseProgram(program) + + # Create vertex buffers and shader constants + # ------------------------------------------ + + # Cube Data + vertices = zeros( + 8, [("vertex_position", float32, 3), ("vertex_colour", float32, 4)] + ) + + vertices["vertex_position"] = [ + [1, 1, 1], + [-1, 1, 1], + [-1, -1, 1], + [1, -1, 1], + [1, -1, -1], + [1, 1, -1], + [-1, 1, -1], + [-1, -1, -1], + ] + + vertices["vertex_colour"] = [ + [0, 1, 1, 1], + [0, 0, 1, 1], + [0, 0, 0, 1], + [0, 1, 0, 1], + [1, 1, 0, 1], + [1, 1, 1, 1], + [1, 0, 1, 1], + [1, 0, 0, 1], + ] + + filled_cube_indices = array( + [ + 0, + 1, + 2, + 0, + 2, + 3, + 0, + 3, + 4, + 0, + 4, + 5, + 0, + 5, + 6, + 0, + 6, + 1, + 1, + 6, + 7, + 1, + 7, + 2, + 7, + 4, + 3, + 7, + 3, + 2, + 4, + 7, + 6, + 4, + 6, + 5, + ], + dtype=uint32, + ) + + outline_cube_indices = array( + [0, 1, 1, 2, 2, 3, 3, 0, 4, 7, 7, 6, 6, 5, 5, 4, 0, 5, 1, 6, 2, 7, 3, 4], + dtype=uint32, + ) + + shader_data = {"buffer": {}, "constants": {}} + + GL.glBindVertexArray(GL.glGenVertexArrays(1)) # Have to do this first + + shader_data["buffer"]["vertices"] = GL.glGenBuffers(1) + GL.glBindBuffer(GL.GL_ARRAY_BUFFER, shader_data["buffer"]["vertices"]) + GL.glBufferData(GL.GL_ARRAY_BUFFER, vertices.nbytes, vertices, GL.GL_DYNAMIC_DRAW) + + stride = vertices.strides[0] + offset = ctypes.c_void_p(0) + + loc = GL.glGetAttribLocation(program, "vertex_position") + GL.glEnableVertexAttribArray(loc) + GL.glVertexAttribPointer(loc, 3, GL.GL_FLOAT, False, stride, offset) + + offset = ctypes.c_void_p(vertices.dtype["vertex_position"].itemsize) + + loc = GL.glGetAttribLocation(program, "vertex_colour") + GL.glEnableVertexAttribArray(loc) + GL.glVertexAttribPointer(loc, 4, GL.GL_FLOAT, False, stride, offset) + + shader_data["buffer"]["filled"] = GL.glGenBuffers(1) + GL.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, shader_data["buffer"]["filled"]) + GL.glBufferData( + GL.GL_ELEMENT_ARRAY_BUFFER, + filled_cube_indices.nbytes, + filled_cube_indices, + GL.GL_STATIC_DRAW, + ) + + shader_data["buffer"]["outline"] = GL.glGenBuffers(1) + GL.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, shader_data["buffer"]["outline"]) + GL.glBufferData( + GL.GL_ELEMENT_ARRAY_BUFFER, + outline_cube_indices.nbytes, + outline_cube_indices, + GL.GL_STATIC_DRAW, + ) + + shader_data["constants"]["model"] = GL.glGetUniformLocation(program, "model") + GL.glUniformMatrix4fv(shader_data["constants"]["model"], 1, False, eye(4)) + + shader_data["constants"]["view"] = GL.glGetUniformLocation(program, "view") + view = translate(eye(4), z=-6) + GL.glUniformMatrix4fv(shader_data["constants"]["view"], 1, False, view) + + shader_data["constants"]["projection"] = GL.glGetUniformLocation( + program, "projection" + ) + GL.glUniformMatrix4fv(shader_data["constants"]["projection"], 1, False, eye(4)) + + # This colour is multiplied with the base vertex colour in producing + # the final output + shader_data["constants"]["colour_mul"] = GL.glGetUniformLocation( + program, "colour_mul" + ) + GL.glUniform4f(shader_data["constants"]["colour_mul"], 1, 1, 1, 1) + + # This colour is added on to the base vertex colour in producing + # the final output + shader_data["constants"]["colour_add"] = GL.glGetUniformLocation( + program, "colour_add" + ) + GL.glUniform4f(shader_data["constants"]["colour_add"], 0, 0, 0, 0) + + # Set GL drawing data + # ------------------- + GL.glClearColor(0, 0, 0, 0) + GL.glPolygonOffset(1, 1) + GL.glEnable(GL.GL_LINE_SMOOTH) + GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA) + GL.glDepthFunc(GL.GL_LESS) + GL.glHint(GL.GL_LINE_SMOOTH_HINT, GL.GL_NICEST) + GL.glLineWidth(1.0) + + projection = perspective(45.0, display_size[0] / float(display_size[1]), 2.0, 100.0) + GL.glUniformMatrix4fv(shader_data["constants"]["projection"], 1, False, projection) + + return shader_data, filled_cube_indices, outline_cube_indices + + +def draw_cube_modern(shader_data, filled_cube_indices, outline_cube_indices, rotation): + """ + Draw a cube in the 'modern' Open GL style, for post 3.1 versions of + open GL. + + :param shader_data: compile vertex & pixel shader data for drawing a cube. + :param filled_cube_indices: the indices to draw the 'filled' cube. + :param outline_cube_indices: the indices to draw the 'outline' cube. + :param rotation: the current rotations to apply. + """ + + GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) + + # Filled cube + GL.glDisable(GL.GL_BLEND) + GL.glEnable(GL.GL_DEPTH_TEST) + GL.glEnable(GL.GL_POLYGON_OFFSET_FILL) + GL.glUniform4f(shader_data["constants"]["colour_mul"], 1, 1, 1, 1) + GL.glUniform4f(shader_data["constants"]["colour_add"], 0, 0, 0, 0.0) + GL.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, shader_data["buffer"]["filled"]) + GL.glDrawElements( + GL.GL_TRIANGLES, len(filled_cube_indices), GL.GL_UNSIGNED_INT, None + ) + + # Outlined cube + GL.glDisable(GL.GL_POLYGON_OFFSET_FILL) + GL.glEnable(GL.GL_BLEND) + GL.glUniform4f(shader_data["constants"]["colour_mul"], 0, 0, 0, 0.0) + GL.glUniform4f(shader_data["constants"]["colour_add"], 1, 1, 1, 1.0) + GL.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, shader_data["buffer"]["outline"]) + GL.glDrawElements(GL.GL_LINES, len(outline_cube_indices), GL.GL_UNSIGNED_INT, None) + + # Rotate cube + # rotation.theta += 1.0 # degrees + rotation.phi += 1.0 # degrees + # rotation.psi += 1.0 # degrees + model = eye(4, dtype=float32) + # rotate(model, rotation.theta, 0, 0, 1) + rotate(model, rotation.phi, 0, 1, 0) + rotate(model, rotation.psi, 1, 0, 0) + GL.glUniformMatrix4fv(shader_data["constants"]["model"], 1, False, model) + + +def main(): + """run the demo""" + + # initialize pygame and setup an opengl display + pg.init() + + gl_version = (3, 0) # GL Version number (Major, Minor) + if USE_MODERN_GL: + gl_version = (3, 2) # GL Version number (Major, Minor) + + # By setting these attributes we can choose which Open GL Profile + # to use, profiles greater than 3.2 use a different rendering path + pg.display.gl_set_attribute(pg.GL_CONTEXT_MAJOR_VERSION, gl_version[0]) + pg.display.gl_set_attribute(pg.GL_CONTEXT_MINOR_VERSION, gl_version[1]) + pg.display.gl_set_attribute( + pg.GL_CONTEXT_PROFILE_MASK, pg.GL_CONTEXT_PROFILE_CORE + ) + + fullscreen = False # start in windowed mode + + display_size = (640, 480) + pg.display.set_mode(display_size, pg.OPENGL | pg.DOUBLEBUF | pg.RESIZABLE) + + if USE_MODERN_GL: + gpu, f_indices, o_indices = init_gl_modern(display_size) + rotation = Rotation() + else: + init_gl_stuff_old() + + going = True + while going: + # check for quit'n events + events = pg.event.get() + for event in events: + if event.type == pg.QUIT or ( + event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE + ): + going = False + + elif event.type == pg.KEYDOWN and event.key == pg.K_f: + if not fullscreen: + print("Changing to FULLSCREEN") + pg.display.set_mode( + (640, 480), pg.OPENGL | pg.DOUBLEBUF | pg.FULLSCREEN + ) + else: + print("Changing to windowed mode") + pg.display.set_mode((640, 480), pg.OPENGL | pg.DOUBLEBUF) + fullscreen = not fullscreen + if gl_version[0] >= 4 or (gl_version[0] == 3 and gl_version[1] >= 2): + gpu, f_indices, o_indices = init_gl_modern(display_size) + rotation = Rotation() + else: + init_gl_stuff_old() + + if USE_MODERN_GL: + draw_cube_modern(gpu, f_indices, o_indices, rotation) + else: + # clear screen and move camera + GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) + # orbit camera around by 1 degree + GL.glRotatef(1, 0, 1, 0) + drawcube_old() + + pg.display.flip() + pg.time.wait(10) + + pg.quit() + + +if __name__ == "__main__": + main() diff --git a/venv/Lib/site-packages/pygame/examples/headless_no_windows_needed.py b/venv/Lib/site-packages/pygame/examples/headless_no_windows_needed.py new file mode 100644 index 0000000..a74057c --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/headless_no_windows_needed.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +""" pygame.examples.headless_no_windows_needed + +How to use pygame with no windowing system, like on headless servers. + +Thumbnail generation with scaling is an example of what you can do with pygame. +NOTE: the pygame scale function uses mmx/sse if available, and can be run + in multiple threads. +""" +useage = """-scale inputimage outputimage new_width new_height +eg. -scale in.png out.png 50 50 + +""" + +import os +import sys + +# set SDL to use the dummy NULL video driver, +# so it doesn't need a windowing system. +os.environ["SDL_VIDEODRIVER"] = "dummy" + +import pygame as pg + +# Some platforms need to init the display for some parts of pg. +pg.display.init() +screen = pg.display.set_mode((1, 1)) + + +def scaleit(fin, fout, w, h): + i = pg.image.load(fin) + + if hasattr(pg.transform, "smoothscale"): + scaled_image = pg.transform.smoothscale(i, (w, h)) + else: + scaled_image = pg.transform.scale(i, (w, h)) + pg.image.save(scaled_image, fout) + + +def main(fin, fout, w, h): + """smoothscale image file named fin as fout with new size (w,h)""" + scaleit(fin, fout, w, h) + + +if __name__ == "__main__": + if "-scale" in sys.argv: + fin, fout, w, h = sys.argv[2:] + w, h = map(int, [w, h]) + main(fin, fout, w, h) + else: + print(useage) diff --git a/venv/Lib/site-packages/pygame/examples/joystick.py b/venv/Lib/site-packages/pygame/examples/joystick.py new file mode 100644 index 0000000..44cc7b8 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/joystick.py @@ -0,0 +1,149 @@ +import pygame + +pygame.init() + +# This is a simple class that will help us print to the screen. +# It has nothing to do with the joysticks, just outputting the +# information. +class TextPrint(object): + def __init__(self): + self.reset() + self.font = pygame.font.Font(None, 20) + + def tprint(self, screen, text): + text_bitmap = self.font.render(text, True, "black") + screen.blit(text_bitmap, (self.x, self.y)) + self.y += self.line_height + + def reset(self): + self.x = 10 + self.y = 10 + self.line_height = 15 + + def indent(self): + self.x += 10 + + def unindent(self): + self.x -= 10 + + +def main(): + # Set the width and height of the screen (width, height), and name the window. + screen = pygame.display.set_mode((500, 700)) + pygame.display.set_caption("Joystick example") + + clock = pygame.time.Clock() + + # Get ready to print. + text_print = TextPrint() + + # This dict can be left as-is, since pygame will generate a + # pygame.JOYDEVICEADDED event for every joystick connected + # at the start of the program. + joysticks = {} + + done = False + while not done: + # Event processing step. + # Possible joystick events: JOYAXISMOTION, JOYBALLMOTION, JOYBUTTONDOWN, + # JOYBUTTONUP, JOYHATMOTION, JOYDEVICEADDED, JOYDEVICEREMOVED + for event in pygame.event.get(): + if event.type == pygame.QUIT: + done = True # Flag that we are done so we exit this loop. + + if event.type == pygame.JOYBUTTONDOWN: + print("Joystick button pressed.") + if event.button == 0: + joystick = joysticks[event.instance_id] + if joystick.rumble(0, 0.7, 500): + print( + "Rumble effect played on joystick {}".format( + event.instance_id + ) + ) + + if event.type == pygame.JOYBUTTONUP: + print("Joystick button released.") + + # Handle hotplugging + if event.type == pygame.JOYDEVICEADDED: + # This event will be generated when the program starts for every + # joystick, filling up the list without needing to create them manually. + joy = pygame.joystick.Joystick(event.device_index) + joysticks[joy.get_instance_id()] = joy + print("Joystick {} connencted".format(joy.get_instance_id())) + + if event.type == pygame.JOYDEVICEREMOVED: + del joysticks[event.instance_id] + print("Joystick {} disconnected".format(event.instance_id)) + + # Drawing step + # First, clear the screen to white. Don't put other drawing commands + # above this, or they will be erased with this command. + screen.fill("white") + text_print.reset() + + text_print.tprint(screen, "Number of joysticks: {}".format(len(joysticks))) + text_print.indent() + + # For each joystick: + for joystick in joysticks.values(): + jid = joystick.get_instance_id() + text_print.tprint(screen, "Joystick {}".format(jid)) + text_print.indent() + + # Get the name from the OS for the joystick. + name = joystick.get_name() + text_print.tprint(screen, "Joystick name: {}".format(name)) + + guid = joystick.get_guid() + text_print.tprint(screen, "GUID: {}".format(guid)) + + power_level = joystick.get_power_level() + text_print.tprint(screen, "Joystick's power level: {}".format(power_level)) + + # Usually axis run in pairs, up/down for one, and left/right for + # the other. Triggers count as axes. + axes = joystick.get_numaxes() + text_print.tprint(screen, "Number of axes: {}".format(axes)) + text_print.indent() + + for i in range(axes): + axis = joystick.get_axis(i) + text_print.tprint(screen, "Axis {} value: {:>6.3f}".format(i, axis)) + text_print.unindent() + + buttons = joystick.get_numbuttons() + text_print.tprint(screen, "Number of buttons: {}".format(buttons)) + text_print.indent() + + for i in range(buttons): + button = joystick.get_button(i) + text_print.tprint(screen, "Button {:>2} value: {}".format(i, button)) + text_print.unindent() + + hats = joystick.get_numhats() + text_print.tprint(screen, "Number of hats: {}".format(hats)) + text_print.indent() + + # Hat position. All or nothing for direction, not a float like + # get_axis(). Position is a tuple of int values (x, y). + for i in range(hats): + hat = joystick.get_hat(i) + text_print.tprint(screen, "Hat {} value: {}".format(i, str(hat))) + text_print.unindent() + + text_print.unindent() + + # Go ahead and update the screen with what we've drawn. + pygame.display.flip() + + # Limit to 30 frames per second. + clock.tick(30) + + +if __name__ == "__main__": + main() + # If you forget this line, the program will 'hang' + # on exit if running from IDLE. + pygame.quit() diff --git a/venv/Lib/site-packages/pygame/examples/liquid.py b/venv/Lib/site-packages/pygame/examples/liquid.py new file mode 100644 index 0000000..d55ba9c --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/liquid.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +""" pygame.examples.liquid + +This example demonstrates a simplish water effect of an +image. It attempts to create a hardware display surface that +can use pageflipping for faster updates. Note that the colormap +from the loaded GIF image is copied to the colormap for the +display surface. + +This is based on the demo named F2KWarp by Brad Graham of Freedom2000 +done in BlitzBasic. I was just translating the BlitzBasic code to +pygame to compare the results. I didn't bother porting the text and +sound stuff, that's an easy enough challenge for the reader :] +""" + +import pygame as pg +import os +from math import sin +import time + +main_dir = os.path.split(os.path.abspath(__file__))[0] + + +def main(): + # initialize and setup screen + pg.init() + screen = pg.display.set_mode((640, 480), pg.HWSURFACE | pg.DOUBLEBUF) + + # load image and quadruple + imagename = os.path.join(main_dir, "data", "liquid.bmp") + bitmap = pg.image.load(imagename) + bitmap = pg.transform.scale2x(bitmap) + bitmap = pg.transform.scale2x(bitmap) + + # get the image and screen in the same format + if screen.get_bitsize() == 8: + screen.set_palette(bitmap.get_palette()) + else: + bitmap = bitmap.convert() + + # prep some variables + anim = 0.0 + + # mainloop + xblocks = range(0, 640, 20) + yblocks = range(0, 480, 20) + stopevents = pg.QUIT, pg.KEYDOWN, pg.MOUSEBUTTONDOWN + while 1: + for e in pg.event.get(): + if e.type in stopevents: + return + + anim = anim + 0.02 + for x in xblocks: + xpos = (x + (sin(anim + x * 0.01) * 15)) + 20 + for y in yblocks: + ypos = (y + (sin(anim + y * 0.01) * 15)) + 20 + screen.blit(bitmap, (x, y), (xpos, ypos, 20, 20)) + + pg.display.flip() + time.sleep(0.01) + + +if __name__ == "__main__": + main() + pg.quit() + + +"""BTW, here is the code from the BlitzBasic example this was derived +from. i've snipped the sound and text stuff out. +----------------------------------------------------------------- +; Brad@freedom2000.com + +; Load a bmp pic (800x600) and slice it into 1600 squares +Graphics 640,480 +SetBuffer BackBuffer() +bitmap$="f2kwarp.bmp" +pic=LoadAnimImage(bitmap$,20,15,0,1600) + +; use SIN to move all 1600 squares around to give liquid effect +Repeat +f=0:w=w+10:If w=360 Then w=0 +For y=0 To 599 Step 15 +For x = 0 To 799 Step 20 +f=f+1:If f=1600 Then f=0 +DrawBlock pic,(x+(Sin(w+x)*40))/1.7+80,(y+(Sin(w+y)*40))/1.7+60,f +Next:Next:Flip:Cls +Until KeyDown(1) +""" diff --git a/venv/Lib/site-packages/pygame/examples/mask.py b/venv/Lib/site-packages/pygame/examples/mask.py new file mode 100644 index 0000000..dae3b2b --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/mask.py @@ -0,0 +1,212 @@ +#!/usr/bin/env python +""" pygame.examples.mask + +A pygame.mask collision detection production. + + + + +Brought + + to + you + by + + the + +pixels + 0000000000000 + and + 111111 + + +This is 32 bits: + 11111111111111111111111111111111 + +There are 32 or 64 bits in a computer 'word'. +Rather than using one word for a pixel, +the mask module represents 32 or 64 pixels in one word. +As you can imagine, this makes things fast, and saves memory. + +Compute intensive things like collision detection, +and computer vision benefit greatly from this. + + +This module can also be run as a stand-alone program, excepting +one or more image file names as command line arguments. +""" + +import sys +import os +import random + +import pygame as pg + + +def maskFromSurface(surface, threshold=127): + return pg.mask.from_surface(surface, threshold) + + +def vadd(x, y): + return [x[0] + y[0], x[1] + y[1]] + + +def vsub(x, y): + return [x[0] - y[0], x[1] - y[1]] + + +def vdot(x, y): + return x[0] * y[0] + x[1] * y[1] + + +class Sprite: + def __init__(self, surface, mask=None): + self.surface = surface + if mask: + self.mask = mask + else: + self.mask = maskFromSurface(self.surface) + self.setPos([0, 0]) + self.setVelocity([0, 0]) + + def setPos(self, pos): + self.pos = [pos[0], pos[1]] + + def setVelocity(self, vel): + self.vel = [vel[0], vel[1]] + + def move(self, dr): + self.pos = vadd(self.pos, dr) + + def kick(self, impulse): + self.vel[0] += impulse[0] + self.vel[1] += impulse[1] + + def collide(self, s): + """Test if the sprites are colliding and + resolve the collision in this case.""" + offset = [int(x) for x in vsub(s.pos, self.pos)] + overlap = self.mask.overlap_area(s.mask, offset) + if overlap == 0: + return + """Calculate collision normal""" + nx = self.mask.overlap_area( + s.mask, (offset[0] + 1, offset[1]) + ) - self.mask.overlap_area(s.mask, (offset[0] - 1, offset[1])) + ny = self.mask.overlap_area( + s.mask, (offset[0], offset[1] + 1) + ) - self.mask.overlap_area(s.mask, (offset[0], offset[1] - 1)) + if nx == 0 and ny == 0: + """One sprite is inside another""" + return + n = [nx, ny] + dv = vsub(s.vel, self.vel) + J = vdot(dv, n) / (2 * vdot(n, n)) + if J > 0: + """Can scale up to 2*J here to get bouncy collisions""" + J *= 1.9 + self.kick([nx * J, ny * J]) + s.kick([-J * nx, -J * ny]) + return + + # """Separate the sprites""" + # c1 = -overlap/vdot(n,n) + # c2 = -c1/2 + # self.move([c2*nx,c2*ny]) + # s.move([(c1+c2)*nx,(c1+c2)*ny]) + + def update(self, dt): + self.pos[0] += dt * self.vel[0] + self.pos[1] += dt * self.vel[1] + + +def main(*args): + """Display multiple images bounce off each other using collision detection + + Positional arguments: + one or more image file names. + + This pg.masks demo will display multiple moving sprites bouncing + off each other. More than one sprite image can be provided. + """ + + if len(args) == 0: + raise ValueError("Require at least one image file name: non given") + print("Press any key to quit") + pg.init() + screen = pg.display.set_mode((640, 480)) + images = [] + masks = [] + for impath in args: + images.append(pg.image.load(impath).convert_alpha()) + masks.append(maskFromSurface(images[-1])) + + numtimes = 10 + import time + + t1 = time.time() + for x in range(numtimes): + unused_mask = maskFromSurface(images[-1]) + t2 = time.time() + + print("python maskFromSurface :%s" % (t2 - t1)) + + t1 = time.time() + for x in range(numtimes): + unused_mask = pg.mask.from_surface(images[-1]) + t2 = time.time() + + print("C pg.mask.from_surface :%s" % (t2 - t1)) + + sprites = [] + for i in range(20): + j = i % len(images) + s = Sprite(images[j], masks[j]) + s.setPos( + ( + random.uniform(0, screen.get_width()), + random.uniform(0, screen.get_height()), + ) + ) + s.setVelocity((random.uniform(-5, 5), random.uniform(-5, 5))) + sprites.append(s) + pg.time.set_timer(pg.USEREVENT, 33) + while 1: + event = pg.event.wait() + if event.type == pg.QUIT: + return + elif event.type == pg.USEREVENT: + + # Do both mechanics and screen update + screen.fill((240, 220, 100)) + for i, sprite in enumerate(sprites): + for j in range(i + 1, len(sprites)): + sprite.collide(sprites[j]) + for s in sprites: + s.update(1) + if s.pos[0] < -s.surface.get_width() - 3: + s.pos[0] = screen.get_width() + elif s.pos[0] > screen.get_width() + 3: + s.pos[0] = -s.surface.get_width() + if s.pos[1] < -s.surface.get_height() - 3: + s.pos[1] = screen.get_height() + elif s.pos[1] > screen.get_height() + 3: + s.pos[1] = -s.surface.get_height() + screen.blit(s.surface, s.pos) + pg.display.update() + elif event.type == pg.KEYDOWN: + return + + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Usage: mask.py [ ...]") + print("Let many copies of IMAGE(s) bounce against each other") + print("Press any key to quit") + main_dir = os.path.split(os.path.abspath(__file__))[0] + imagename = os.path.join(main_dir, "data", "chimp.png") + main(imagename) + + else: + main(*sys.argv[1:]) + pg.quit() diff --git a/venv/Lib/site-packages/pygame/examples/midi.py b/venv/Lib/site-packages/pygame/examples/midi.py new file mode 100644 index 0000000..3e184ef --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/midi.py @@ -0,0 +1,877 @@ +#!/usr/bin/env python +""" pygame.examples.midi + +midi input, and a separate example of midi output. + +By default it runs the output example. + +python -m pygame.examples.midi --output +python -m pygame.examples.midi --input +python -m pygame.examples.midi --input +""" + +import sys +import os + +import pygame as pg +import pygame.midi + +# black and white piano keys use b/w color values directly +BACKGROUNDCOLOR = "slategray" + + +def print_device_info(): + pygame.midi.init() + _print_device_info() + pygame.midi.quit() + + +def _print_device_info(): + for i in range(pygame.midi.get_count()): + r = pygame.midi.get_device_info(i) + (interf, name, input, output, opened) = r + + in_out = "" + if input: + in_out = "(input)" + if output: + in_out = "(output)" + + print( + "%2i: interface :%s:, name :%s:, opened :%s: %s" + % (i, interf, name, opened, in_out) + ) + + +def input_main(device_id=None): + pg.init() + + pygame.midi.init() + + _print_device_info() + + if device_id is None: + input_id = pygame.midi.get_default_input_id() + else: + input_id = device_id + + print("using input_id :%s:" % input_id) + i = pygame.midi.Input(input_id) + + pg.display.set_mode((1, 1)) + + going = True + while going: + events = pygame.event.get() + for e in events: + if e.type in [pg.QUIT]: + going = False + if e.type in [pg.KEYDOWN]: + going = False + if e.type in [pygame.midi.MIDIIN]: + print(e) + + if i.poll(): + midi_events = i.read(10) + # convert them into pygame events. + midi_evs = pygame.midi.midis2events(midi_events, i.device_id) + + for m_e in midi_evs: + pygame.event.post(m_e) + + del i + pygame.midi.quit() + + +def output_main(device_id=None): + """Execute a musical keyboard example for the Church Organ instrument + + This is a piano keyboard example, with a two octave keyboard, starting at + note F3. Left mouse down over a key starts a note, left up stops it. The + notes are also mapped to the computer keyboard keys, assuming an American + English PC keyboard (sorry everyone else, but I don't know if I can map to + absolute key position instead of value.) The white keys are on the second + row, TAB to BACKSLASH, starting with note F3. The black keys map to the top + row, '1' to BACKSPACE, starting with F#3. 'r' is middle C. Close the + window or press ESCAPE to quit the program. Key velocity (note + amplitude) varies vertically on the keyboard image, with minimum velocity + at the top of a key and maximum velocity at bottom. + + Default Midi output, no device_id given, is to the default output device + for the computer. + + """ + + # A note to new pygamers: + # + # All the midi module stuff is in this function. It is unnecessary to + # understand how the keyboard display works to appreciate how midi + # messages are sent. + + # The keyboard is drawn by a Keyboard instance. This instance maps Midi + # notes to musical keyboard keys. A regions surface maps window position + # to (Midi note, velocity) pairs. A key_mapping dictionary does the same + # for computer keyboard keys. Midi sound is controlled with direct method + # calls to a pygame.midi.Output instance. + # + # Things to consider when using pygame.midi: + # + # 1) Initialize the midi module with a to pygame.midi.init(). + # 2) Create a midi.Output instance for the desired output device port. + # 3) Select instruments with set_instrument() method calls. + # 4) Play notes with note_on() and note_off() method calls. + # 5) Call pygame.midi.Quit() when finished. Though the midi module tries + # to ensure that midi is properly shut down, it is best to do it + # explicitly. A try/finally statement is the safest way to do this. + # + + # GRAND_PIANO = 0 + CHURCH_ORGAN = 19 + + instrument = CHURCH_ORGAN + # instrument = GRAND_PIANO + start_note = 53 # F3 (white key note), start_note != 0 + n_notes = 24 # Two octaves (14 white keys) + + key_mapping = make_key_mapping( + [ + pg.K_TAB, + pg.K_1, + pg.K_q, + pg.K_2, + pg.K_w, + pg.K_3, + pg.K_e, + pg.K_r, + pg.K_5, + pg.K_t, + pg.K_6, + pg.K_y, + pg.K_u, + pg.K_8, + pg.K_i, + pg.K_9, + pg.K_o, + pg.K_0, + pg.K_p, + pg.K_LEFTBRACKET, + pg.K_EQUALS, + pg.K_RIGHTBRACKET, + pg.K_BACKSPACE, + pg.K_BACKSLASH, + ], + start_note, + ) + + pg.init() + pygame.midi.init() + + _print_device_info() + + if device_id is None: + port = pygame.midi.get_default_output_id() + else: + port = device_id + + print("using output_id :%s:" % port) + + midi_out = pygame.midi.Output(port, 0) + try: + midi_out.set_instrument(instrument) + keyboard = Keyboard(start_note, n_notes) + + screen = pg.display.set_mode(keyboard.rect.size) + screen.fill(BACKGROUNDCOLOR) + pg.display.flip() + + background = pg.Surface(screen.get_size()) + background.fill(BACKGROUNDCOLOR) + dirty_rects = [] + keyboard.draw(screen, background, dirty_rects) + pg.display.update(dirty_rects) + + regions = pg.Surface(screen.get_size()) # initial color (0,0,0) + keyboard.map_regions(regions) + + pg.event.set_blocked(pg.MOUSEMOTION) + mouse_note = 0 + on_notes = set() + while 1: + e = pg.event.wait() + if e.type == pg.MOUSEBUTTONDOWN: + mouse_note, velocity, __, __ = regions.get_at(e.pos) + if mouse_note and mouse_note not in on_notes: + keyboard.key_down(mouse_note) + midi_out.note_on(mouse_note, velocity) + on_notes.add(mouse_note) + else: + mouse_note = 0 + elif e.type == pg.MOUSEBUTTONUP: + if mouse_note: + midi_out.note_off(mouse_note) + keyboard.key_up(mouse_note) + on_notes.remove(mouse_note) + mouse_note = 0 + elif e.type == pg.QUIT: + break + elif e.type == pg.KEYDOWN: + if e.key == pg.K_ESCAPE: + break + try: + note, velocity = key_mapping[e.key] + except KeyError: + pass + else: + if note not in on_notes: + keyboard.key_down(note) + midi_out.note_on(note, velocity) + on_notes.add(note) + elif e.type == pg.KEYUP: + try: + note, __ = key_mapping[e.key] + except KeyError: + pass + else: + if note in on_notes and note != mouse_note: + keyboard.key_up(note) + midi_out.note_off(note, 0) + on_notes.remove(note) + + dirty_rects = [] + keyboard.draw(screen, background, dirty_rects) + pg.display.update(dirty_rects) + finally: + del midi_out + pygame.midi.quit() + + +def make_key_mapping(keys, start_note): + """Return a dictionary of (note, velocity) by computer keyboard key code""" + mapping = {} + for i, key in enumerate(keys): + mapping[key] = (start_note + i, 127) + return mapping + + +class NullKey(object): + """A dummy key that ignores events passed to it by other keys + + A NullKey instance is the left key instance used by default + for the left most keyboard key. + + """ + + def _right_white_down(self): + pass + + def _right_white_up(self): + pass + + def _right_black_down(self): + pass + + def _right_black_up(self): + pass + + +null_key = NullKey() + + +def key_class(updates, image_strip, image_rects, is_white_key=True): + """Return a keyboard key widget class + + Arguments: + updates - a set into which a key instance adds itself if it needs + redrawing. + image_strip - The surface containing the images of all key states. + image_rects - A list of Rects giving the regions within image_strip that + are relevant to this key class. + is_white_key (default True) - Set false if this is a black key. + + This function automates the creation of a key widget class for the + three basic key types. A key has two basic states, up or down ( + depressed). Corresponding up and down images are drawn for each + of these two states. But to give the illusion of depth, a key + may have shadows cast upon it by the adjacent keys to its right. + These shadows change depending on the up/down state of the key and + its neighbors. So a key may support multiple images and states + depending on the shadows. A key type is determined by the length + of image_rects and the value of is_white. + + """ + + # Naming convention: Variables used by the Key class as part of a + # closure start with 'c_'. + + # State logic and shadows: + # + # A key may cast a shadow upon the key to its left. A black key casts a + # shadow on an adjacent white key. The shadow changes depending of whether + # the black or white key is depressed. A white key casts a shadow on the + # white key to its left if it is up and the left key is down. Therefore + # a keys state, and image it will draw, is determined entirely by its + # itself and the key immediately adjacent to it on the right. A white key + # is always assumed to have an adjacent white key. + # + # There can be up to eight key states, representing all permutations + # of the three fundamental states of self up/down, adjacent white + # right up/down, adjacent black up/down. + # + down_state_none = 0 + down_state_self = 1 + down_state_white = down_state_self << 1 + down_state_self_white = down_state_self | down_state_white + down_state_black = down_state_white << 1 + down_state_self_black = down_state_self | down_state_black + down_state_white_black = down_state_white | down_state_black + down_state_all = down_state_self | down_state_white_black + + # Some values used in the class. + # + c_down_state_initial = down_state_none + c_down_state_rect_initial = image_rects[0] + c_updates = updates + c_image_strip = image_strip + c_width, c_height = image_rects[0].size + + # A key propagates its up/down state change to the adjacent white key on + # the left by calling the adjacent key's _right_black_down or + # _right_white_down method. + # + if is_white_key: + key_color = "white" + else: + key_color = "black" + c_notify_down_method = "_right_%s_down" % key_color + c_notify_up_method = "_right_%s_up" % key_color + + # Images: + # + # A black key only needs two images, for the up and down states. Its + # appearance is unaffected by the adjacent keys to its right, which cast no + # shadows upon it. + # + # A white key with a no adjacent black to its right only needs three + # images, for self up, self down, and both self and adjacent white down. + # + # A white key with both a black and white key to its right needs six + # images: self up, self up and adjacent black down, self down, self and + # adjacent white down, self and adjacent black down, and all three down. + # + # Each 'c_event' dictionary maps the current key state to a new key state, + # along with corresponding image, for the related event. If no redrawing + # is required for the state change then the image rect is simply None. + # + c_event_down = {down_state_none: (down_state_self, image_rects[1])} + c_event_up = {down_state_self: (down_state_none, image_rects[0])} + c_event_right_white_down = { + down_state_none: (down_state_none, None), + down_state_self: (down_state_self, None), + } + c_event_right_white_up = c_event_right_white_down.copy() + c_event_right_black_down = c_event_right_white_down.copy() + c_event_right_black_up = c_event_right_white_down.copy() + if len(image_rects) > 2: + c_event_down[down_state_white] = (down_state_self_white, image_rects[2]) + c_event_up[down_state_self_white] = (down_state_white, image_rects[0]) + c_event_right_white_down[down_state_none] = (down_state_white, None) + c_event_right_white_down[down_state_self] = ( + down_state_self_white, + image_rects[2], + ) + c_event_right_white_up[down_state_white] = (down_state_none, None) + c_event_right_white_up[down_state_self_white] = ( + down_state_self, + image_rects[1], + ) + c_event_right_black_down[down_state_white] = (down_state_white, None) + c_event_right_black_down[down_state_self_white] = (down_state_self_white, None) + c_event_right_black_up[down_state_white] = (down_state_white, None) + c_event_right_black_up[down_state_self_white] = (down_state_self_white, None) + if len(image_rects) > 3: + c_event_down[down_state_black] = (down_state_self_black, image_rects[4]) + c_event_down[down_state_white_black] = (down_state_all, image_rects[5]) + c_event_up[down_state_self_black] = (down_state_black, image_rects[3]) + c_event_up[down_state_all] = (down_state_white_black, image_rects[3]) + c_event_right_white_down[down_state_black] = (down_state_white_black, None) + c_event_right_white_down[down_state_self_black] = ( + down_state_all, + image_rects[5], + ) + c_event_right_white_up[down_state_white_black] = (down_state_black, None) + c_event_right_white_up[down_state_all] = (down_state_self_black, image_rects[4]) + c_event_right_black_down[down_state_none] = (down_state_black, image_rects[3]) + c_event_right_black_down[down_state_self] = ( + down_state_self_black, + image_rects[4], + ) + c_event_right_black_down[down_state_white] = ( + down_state_white_black, + image_rects[3], + ) + c_event_right_black_down[down_state_self_white] = ( + down_state_all, + image_rects[5], + ) + c_event_right_black_up[down_state_black] = (down_state_none, image_rects[0]) + c_event_right_black_up[down_state_self_black] = ( + down_state_self, + image_rects[1], + ) + c_event_right_black_up[down_state_white_black] = ( + down_state_white, + image_rects[0], + ) + c_event_right_black_up[down_state_all] = (down_state_self_white, image_rects[2]) + + class Key(object): + """A key widget, maintains key state and draws the key's image + + Constructor arguments: + ident - A unique key identifier. Any immutable type suitable as a key. + posn - The location of the key on the display surface. + key_left - Optional, the adjacent white key to the left. Changes in + up and down state are propagated to that key. + + A key has an associated position and state. Related to state is the + image drawn. State changes are managed with method calls, one method + per event type. The up and down event methods are public. Other + internal methods are for passing on state changes to the key_left + key instance. + + """ + + is_white = is_white_key + + def __init__(self, ident, posn, key_left=None): + """Return a new Key instance + + The initial state is up, with all adjacent keys to the right also + up. + + """ + if key_left is None: + key_left = null_key + rect = pg.Rect(posn[0], posn[1], c_width, c_height) + self.rect = rect + self._state = c_down_state_initial + self._source_rect = c_down_state_rect_initial + self._ident = ident + self._hash = hash(ident) + self._notify_down = getattr(key_left, c_notify_down_method) + self._notify_up = getattr(key_left, c_notify_up_method) + self._key_left = key_left + self._background_rect = pg.Rect(rect.left, rect.bottom - 10, c_width, 10) + c_updates.add(self) + + def down(self): + """Signal that this key has been depressed (is down)""" + + self._state, source_rect = c_event_down[self._state] + if source_rect is not None: + self._source_rect = source_rect + c_updates.add(self) + self._notify_down() + + def up(self): + """Signal that this key has been released (is up)""" + + self._state, source_rect = c_event_up[self._state] + if source_rect is not None: + self._source_rect = source_rect + c_updates.add(self) + self._notify_up() + + def _right_white_down(self): + """Signal that the adjacent white key has been depressed + + This method is for internal propagation of events between + key instances. + + """ + + self._state, source_rect = c_event_right_white_down[self._state] + if source_rect is not None: + self._source_rect = source_rect + c_updates.add(self) + + def _right_white_up(self): + """Signal that the adjacent white key has been released + + This method is for internal propagation of events between + key instances. + + """ + + self._state, source_rect = c_event_right_white_up[self._state] + if source_rect is not None: + self._source_rect = source_rect + c_updates.add(self) + + def _right_black_down(self): + """Signal that the adjacent black key has been depressed + + This method is for internal propagation of events between + key instances. + + """ + + self._state, source_rect = c_event_right_black_down[self._state] + if source_rect is not None: + self._source_rect = source_rect + c_updates.add(self) + + def _right_black_up(self): + """Signal that the adjacent black key has been released + + This method is for internal propagation of events between + key instances. + + """ + + self._state, source_rect = c_event_right_black_up[self._state] + if source_rect is not None: + self._source_rect = source_rect + c_updates.add(self) + + def __eq__(self, other): + """True if same identifiers""" + + return self._ident == other._ident + + def __hash__(self): + """Return the immutable hash value""" + + return self._hash + + def __str__(self): + """Return the key's identifier and position as a string""" + + return "" % (self._ident, self.rect.top, self.rect.left) + + def draw(self, surf, background, dirty_rects): + """Redraw the key on the surface surf + + The background is redrawn. The altered region is added to the + dirty_rects list. + + """ + + surf.blit(background, self._background_rect, self._background_rect) + surf.blit(c_image_strip, self.rect, self._source_rect) + dirty_rects.append(self.rect) + + return Key + + +def key_images(): + """Return a keyboard keys image strip and a mapping of image locations + + The return tuple is a surface and a dictionary of rects mapped to key + type. + + This function encapsulates the constants relevant to the keyboard image + file. There are five key types. One is the black key. The other four + white keys are determined by the proximity of the black keys. The plain + white key has no black key adjacent to it. A white-left and white-right + key has a black key to the left or right of it respectively. A white-center + key has a black key on both sides. A key may have up to six related + images depending on the state of adjacent keys to its right. + + """ + + my_dir = os.path.split(os.path.abspath(__file__))[0] + strip_file = os.path.join(my_dir, "data", "midikeys.png") + white_key_width = 42 + white_key_height = 160 + black_key_width = 22 + black_key_height = 94 + strip = pg.image.load(strip_file) + names = [ + "black none", + "black self", + "white none", + "white self", + "white self-white", + "white-left none", + "white-left self", + "white-left black", + "white-left self-black", + "white-left self-white", + "white-left all", + "white-center none", + "white-center self", + "white-center black", + "white-center self-black", + "white-center self-white", + "white-center all", + "white-right none", + "white-right self", + "white-right self-white", + ] + rects = {} + for i in range(2): + rects[names[i]] = pg.Rect( + i * white_key_width, 0, black_key_width, black_key_height + ) + for i in range(2, len(names)): + rects[names[i]] = pg.Rect( + i * white_key_width, 0, white_key_width, white_key_height + ) + return strip, rects + + +class Keyboard(object): + """Musical keyboard widget + + Constructor arguments: + start_note: midi note value of the starting note on the keyboard. + n_notes: number of notes (keys) on the keyboard. + + A Keyboard instance draws the musical keyboard and maintains the state of + all the keyboard keys. Individual keys can be in a down (depressed) or + up (released) state. + + """ + + _image_strip, _rects = key_images() + + white_key_width, white_key_height = _rects["white none"].size + black_key_width, black_key_height = _rects["black none"].size + + _updates = set() + + # There are five key classes, representing key shape: + # black key (BlackKey), plain white key (WhiteKey), white key to the left + # of a black key (WhiteKeyLeft), white key between two black keys + # (WhiteKeyCenter), and white key to the right of a black key + # (WhiteKeyRight). + BlackKey = key_class( + _updates, _image_strip, [_rects["black none"], _rects["black self"]], False + ) + WhiteKey = key_class( + _updates, + _image_strip, + [_rects["white none"], _rects["white self"], _rects["white self-white"]], + ) + WhiteKeyLeft = key_class( + _updates, + _image_strip, + [ + _rects["white-left none"], + _rects["white-left self"], + _rects["white-left self-white"], + _rects["white-left black"], + _rects["white-left self-black"], + _rects["white-left all"], + ], + ) + WhiteKeyCenter = key_class( + _updates, + _image_strip, + [ + _rects["white-center none"], + _rects["white-center self"], + _rects["white-center self-white"], + _rects["white-center black"], + _rects["white-center self-black"], + _rects["white-center all"], + ], + ) + WhiteKeyRight = key_class( + _updates, + _image_strip, + [ + _rects["white-right none"], + _rects["white-right self"], + _rects["white-right self-white"], + ], + ) + + def __init__(self, start_note, n_notes): + """Return a new Keyboard instance with n_note keys""" + + self._start_note = start_note + self._end_note = start_note + n_notes - 1 + self._add_keys() + + def _add_keys(self): + """Populate the keyboard with key instances + + Set the _keys and rect attributes. + + """ + + # Keys are entered in a list, where index is Midi note. Since there are + # only 128 possible Midi notes the list length is managable. Unassigned + # note positions should never be accessed, so are set None to ensure + # the bug is quickly detected. + # + key_map = [None] * 128 + + start_note = self._start_note + end_note = self._end_note + black_offset = self.black_key_width // 2 + prev_white_key = None + x = y = 0 + if is_white_key(start_note): + is_prev_white = True + else: + x += black_offset + is_prev_white = False + for note in range(start_note, end_note + 1): + ident = note # For now notes uniquely identify keyboard keys. + if is_white_key(note): + if is_prev_white: + if note == end_note or is_white_key(note + 1): + key = self.WhiteKey(ident, (x, y), prev_white_key) + else: + key = self.WhiteKeyLeft(ident, (x, y), prev_white_key) + else: + if note == end_note or is_white_key(note + 1): + key = self.WhiteKeyRight(ident, (x, y), prev_white_key) + else: + key = self.WhiteKeyCenter(ident, (x, y), prev_white_key) + is_prev_white = True + x += self.white_key_width + prev_white_key = key + else: + key = self.BlackKey(ident, (x - black_offset, y), prev_white_key) + is_prev_white = False + key_map[note] = key + self._keys = key_map + + kb_width = key_map[self._end_note].rect.right + kb_height = self.white_key_height + self.rect = pg.Rect(0, 0, kb_width, kb_height) + + def map_regions(self, regions): + """Draw the key regions onto surface regions. + + Regions must have at least 3 byte pixels. Each pixel of the keyboard + rectangle is set to the color (note, velocity, 0). The regions surface + must be at least as large as (0, 0, self.rect.left, self.rect.bottom) + + """ + + # First draw the white key regions. Then add the overlapping + # black key regions. + # + cutoff = self.black_key_height + black_keys = [] + for note in range(self._start_note, self._end_note + 1): + key = self._keys[note] + if key.is_white: + fill_region(regions, note, key.rect, cutoff) + else: + black_keys.append((note, key)) + for note, key in black_keys: + fill_region(regions, note, key.rect, cutoff) + + def draw(self, surf, background, dirty_rects): + """Redraw all altered keyboard keys""" + + changed_keys = self._updates + while changed_keys: + changed_keys.pop().draw(surf, background, dirty_rects) + + def key_down(self, note): + """Signal a key down event for note""" + + self._keys[note].down() + + def key_up(self, note): + """Signal a key up event for note""" + + self._keys[note].up() + + +def fill_region(regions, note, rect, cutoff): + """Fill the region defined by rect with a (note, velocity, 0) color + + The velocity varies from a small value at the top of the region to + 127 at the bottom. The vertical region 0 to cutoff is split into + three parts, with velocities 42, 84 and 127. Everything below cutoff + has velocity 127. + + """ + + x, y, width, height = rect + if cutoff is None: + cutoff = height + delta_height = cutoff // 3 + regions.fill((note, 42, 0), (x, y, width, delta_height)) + regions.fill((note, 84, 0), (x, y + delta_height, width, delta_height)) + regions.fill( + (note, 127, 0), (x, y + 2 * delta_height, width, height - 2 * delta_height) + ) + + +def is_white_key(note): + """True if note is represented by a white key""" + + key_pattern = [ + True, + False, + True, + True, + False, + True, + False, + True, + True, + False, + True, + False, + ] + return key_pattern[(note - 21) % len(key_pattern)] + + +def usage(): + print("--input [device_id] : Midi message logger") + print("--output [device_id] : Midi piano keyboard") + print("--list : list available midi devices") + + +def main(mode="output", device_id=None): + """Run a Midi example + + Arguments: + mode - if 'output' run a midi keyboard output example + 'input' run a midi event logger input example + 'list' list available midi devices + (default 'output') + device_id - midi device number; if None then use the default midi input or + output device for the system + + """ + + if mode == "input": + input_main(device_id) + elif mode == "output": + output_main(device_id) + elif mode == "list": + print_device_info() + else: + raise ValueError("Unknown mode option '%s'" % mode) + + +if __name__ == "__main__": + + try: + device_id = int(sys.argv[-1]) + except ValueError: + device_id = None + + if "--input" in sys.argv or "-i" in sys.argv: + + input_main(device_id) + + elif "--output" in sys.argv or "-o" in sys.argv: + output_main(device_id) + elif "--list" in sys.argv or "-l" in sys.argv: + print_device_info() + else: + usage() + + pg.quit() diff --git a/venv/Lib/site-packages/pygame/examples/moveit.py b/venv/Lib/site-packages/pygame/examples/moveit.py new file mode 100644 index 0000000..b902ce5 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/moveit.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python +""" pygame.examples.moveit + +This is the full and final example from the Pygame Tutorial, +"How Do I Make It Move". It creates 10 objects and animates +them on the screen. + +Note it's a bit scant on error checking, but it's easy to read. :] +Fortunately, this is python, and we needn't wrestle with a pile of +error codes. +""" +import os +import pygame as pg + +main_dir = os.path.split(os.path.abspath(__file__))[0] + +# our game object class +class GameObject: + def __init__(self, image, height, speed): + self.speed = speed + self.image = image + self.pos = image.get_rect().move(0, height) + + def move(self): + self.pos = self.pos.move(self.speed, 0) + if self.pos.right > 600: + self.pos.left = 0 + + +# quick function to load an image +def load_image(name): + path = os.path.join(main_dir, "data", name) + return pg.image.load(path).convert() + + +# here's the full code +def main(): + pg.init() + screen = pg.display.set_mode((640, 480)) + + player = load_image("player1.gif") + background = load_image("liquid.bmp") + + # scale the background image so that it fills the window and + # successfully overwrites the old sprite position. + background = pg.transform.scale2x(background) + background = pg.transform.scale2x(background) + + screen.blit(background, (0, 0)) + + objects = [] + for x in range(10): + o = GameObject(player, x * 40, x) + objects.append(o) + + while 1: + for event in pg.event.get(): + if event.type in (pg.QUIT, pg.KEYDOWN): + return + + for o in objects: + screen.blit(background, o.pos, o.pos) + for o in objects: + o.move() + screen.blit(o.image, o.pos) + + pg.display.update() + + +if __name__ == "__main__": + main() + pg.quit() diff --git a/venv/Lib/site-packages/pygame/examples/music_drop_fade.py b/venv/Lib/site-packages/pygame/examples/music_drop_fade.py new file mode 100644 index 0000000..9d83546 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/music_drop_fade.py @@ -0,0 +1,249 @@ +#!/usr/bin/env python +""" pygame.examples.music_drop_fade +Fade in and play music from a list while observing several events + +Adds music files to a playlist whenever played by one of the following methods +Music files passed from the commandline are played +Music files and filenames are played when drag and dropped onto the pygame window +Polls the clipboard and plays music files if it finds one there + +Keyboard Controls: +* Press space or enter to pause music playback +* Press up or down to change the music volume +* Press left or right to seek 5 seconds into the track +* Press escape to quit +* Press any other button to skip to the next music file in the list +""" + +import pygame as pg +import os, sys + +VOLUME_CHANGE_AMOUNT = 0.02 # how fast should up and down arrows change the volume? + + +def add_file(filename): + """ + This function will check if filename exists and is a music file + If it is the file will be added to a list of music files(even if already there) + Type checking is by the extension of the file, not by its contents + We can only discover if the file is valid when we mixer.music.load() it later + + It looks in the file directory and its data subdirectory + """ + if filename.rpartition(".")[2].lower() not in music_file_types: + print("{} not added to file list".format(filename)) + print("only these files types are allowed: ", music_file_types) + return False + elif os.path.exists(filename): + music_file_list.append(filename) + elif os.path.exists(os.path.join(main_dir, filename)): + music_file_list.append(os.path.join(main_dir, filename)) + elif os.path.exists(os.path.join(data_dir, filename)): + music_file_list.append(os.path.join(data_dir, filename)) + else: + print("file not found") + return False + print("{} added to file list".format(filename)) + return True + + +def play_file(filename): + """ + This function will call add_file and play it if successful + The music will fade in during the first 4 seconds + set_endevent is used to post a MUSIC_DONE event when the song finishes + The main loop will call play_next() when the MUSIC_DONE event is received + """ + global starting_pos + + if add_file(filename): + try: # we must do this in case the file is not a valid audio file + pg.mixer.music.load(music_file_list[-1]) + except pg.error as e: + print(e) # print description such as 'Not an Ogg Vorbis audio stream' + if filename in music_file_list: + music_file_list.remove(filename) + print("{} removed from file list".format(filename)) + return + pg.mixer.music.play(fade_ms=4000) + pg.mixer.music.set_volume(volume) + + if filename.rpartition(".")[2].lower() in music_can_seek: + print("file supports seeking") + starting_pos = 0 + else: + print("file does not support seeking") + starting_pos = -1 + pg.mixer.music.set_endevent(MUSIC_DONE) + + +def play_next(): + """ + This function will play the next song in music_file_list + It uses pop(0) to get the next song and then appends it to the end of the list + The song will fade in during the first 4 seconds + """ + + global starting_pos + if len(music_file_list) > 1: + nxt = music_file_list.pop(0) + + try: + pg.mixer.music.load(nxt) + except pg.error as e: + print(e) + print("{} removed from file list".format(nxt)) + + music_file_list.append(nxt) + print("starting next song: ", nxt) + else: + nxt = music_file_list[0] + pg.mixer.music.play(fade_ms=4000) + pg.mixer.music.set_volume(volume) + pg.mixer.music.set_endevent(MUSIC_DONE) + + if nxt.rpartition(".")[2].lower() in music_can_seek: + starting_pos = 0 + else: + starting_pos = -1 + + +def draw_text_line(text, y=0): + """ + Draws a line of text onto the display surface + The text will be centered horizontally at the given y postition + The text's height is added to y and returned to the caller + """ + screen = pg.display.get_surface() + surf = font.render(text, 1, (255, 255, 255)) + y += surf.get_height() + x = (screen.get_width() - surf.get_width()) / 2 + screen.blit(surf, (x, y)) + return y + + +def change_music_postion(amount): + """ + Changes current playback postition by amount seconds. + This only works with OGG and MP3 files. + music.get_pos() returns how many milliseconds the song has played, not + the current postion in the file. We must track the starting postion + ourselves. music.set_pos() will set the position in seconds. + """ + global starting_pos + + if starting_pos >= 0: # will be -1 unless play_file() was OGG or MP3 + played_for = pg.mixer.music.get_pos() / 1000.0 + old_pos = starting_pos + played_for + starting_pos = old_pos + amount + pg.mixer.music.play(start=starting_pos) + print("jumped from {} to {}".format(old_pos, starting_pos)) + + +MUSIC_DONE = pg.event.custom_type() # event to be set as mixer.music.set_endevent() +main_dir = os.path.split(os.path.abspath(__file__))[0] +data_dir = os.path.join(main_dir, "data") + +starting_pos = 0 # needed to fast forward and rewind +volume = 0.75 +music_file_list = [] +music_file_types = ("mp3", "ogg", "mid", "mod", "it", "xm", "wav") +music_can_seek = ("mp3", "ogg", "mod", "it", "xm") + + +def main(): + global font # this will be used by the draw_text_line function + global volume, starting_pos + running = True + paused = False + + # we will be polling for key up and key down events + # users should be able to change the volume by holding the up and down arrows + # the change_volume variable will be set by key down events and cleared by key up events + change_volume = 0 + + pg.init() + pg.display.set_mode((640, 480)) + font = pg.font.SysFont("Arial", 24) + clock = pg.time.Clock() + + pg.scrap.init() + pg.SCRAP_TEXT = pg.scrap.get_types()[0] # TODO remove when scrap module is fixed + clipped = pg.scrap.get(pg.SCRAP_TEXT).decode("UTF-8") + # store the current text from the clipboard TODO remove decode + + # add the command line arguments to the music_file_list + for arg in sys.argv[1:]: + add_file(arg) + play_file("house_lo.ogg") # play default music included with pygame + + # draw instructions on screen + y = draw_text_line("Drop music files or path names onto this window", 20) + y = draw_text_line("Copy file names into the clipboard", y) + y = draw_text_line("Or feed them from the command line", y) + y = draw_text_line("If it's music it will play!", y) + y = draw_text_line("SPACE to pause or UP/DOWN to change volume", y) + y = draw_text_line("LEFT and RIGHT will skip around the track", y) + draw_text_line("Other keys will start the next track", y) + + """ + This is the main loop + It will respond to drag and drop, clipboard changes, and key presses + """ + while running: + for ev in pg.event.get(): + if ev.type == pg.QUIT: + running = False + elif ev.type == pg.DROPTEXT: + play_file(ev.text) + elif ev.type == pg.DROPFILE: + play_file(ev.file) + elif ev.type == MUSIC_DONE: + play_next() + elif ev.type == pg.KEYDOWN: + if ev.key == pg.K_ESCAPE: + running = False # exit loop + elif ev.key in (pg.K_SPACE, pg.K_RETURN): + if paused: + pg.mixer.music.unpause() + paused = False + else: + pg.mixer.music.pause() + paused = True + elif ev.key == pg.K_UP: + change_volume = VOLUME_CHANGE_AMOUNT + elif ev.key == pg.K_DOWN: + change_volume = -VOLUME_CHANGE_AMOUNT + elif ev.key == pg.K_RIGHT: + change_music_postion(+5) + elif ev.key == pg.K_LEFT: + change_music_postion(-5) + + else: + play_next() + + elif ev.type == pg.KEYUP: + if ev.key in (pg.K_UP, pg.K_DOWN): + change_volume = 0 + + # is the user holding up or down? + if change_volume: + volume += change_volume + volume = min(max(0, volume), 1) # volume should be between 0 and 1 + pg.mixer.music.set_volume(volume) + print("volume:", volume) + + # TODO remove decode when SDL2 scrap is fixed + new_text = pg.scrap.get(pg.SCRAP_TEXT).decode("UTF-8") + if new_text != clipped: # has the clipboard changed? + clipped = new_text + play_file(clipped) # try to play the file if it has + + pg.display.flip() + clock.tick(9) # keep CPU use down by updating screen less often + + pg.quit() + + +if __name__ == "__main__": + main() diff --git a/venv/Lib/site-packages/pygame/examples/pixelarray.py b/venv/Lib/site-packages/pygame/examples/pixelarray.py new file mode 100644 index 0000000..9961091 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/pixelarray.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python +""" pygame.examples.pixelarray + +PixelArray does array processing of pixels. +Sort of like another array processor called 'numpy' - But for pixels. + + Flip it, + stripe it, + rotate it. + +Controls +-------- + +To see different effects - press a key or click a mouse. +""" +import os +import pygame as pg + + +main_dir = os.path.split(os.path.abspath(__file__))[0] +data_dir = os.path.join(main_dir, "data") + + +def show(image): + screen = pg.display.get_surface() + screen.fill((255, 255, 255)) + screen.blit(image, (0, 0)) + pg.display.flip() + while 1: + event = pg.event.wait() + if event.type == pg.QUIT: + pg.quit() + raise SystemExit + if event.type in [pg.MOUSEBUTTONDOWN, pg.KEYDOWN]: + break + + +def main(): + pg.init() + + pg.display.set_mode((255, 255)) + surface = pg.Surface((255, 255)) + + pg.display.flip() + + # Create the PixelArray. + ar = pg.PixelArray(surface) + + # Do some easy gradient effect. + for y in range(255): + r, g, b = y, y, y + ar[:, y] = (r, g, b) + del ar + show(surface) + + # We have made some gradient effect, now flip it. + ar = pg.PixelArray(surface) + ar[:] = ar[:, ::-1] + del ar + show(surface) + + # Every second column will be made blue + ar = pg.PixelArray(surface) + ar[::2] = (0, 0, 255) + del ar + show(surface) + + # Every second row will be made green + ar = pg.PixelArray(surface) + ar[:, ::2] = (0, 255, 0) + del ar + show(surface) + + # Manipulate the image. Flip it around the y axis. + surface = pg.image.load(os.path.join(data_dir, "arraydemo.bmp")) + ar = pg.PixelArray(surface) + ar[:] = ar[:, ::-1] + del ar + show(surface) + + # Flip the image around the x axis. + ar = pg.PixelArray(surface) + ar[:] = ar[::-1, :] + del ar + show(surface) + + # Every second column will be made white. + ar = pg.PixelArray(surface) + ar[::2] = (255, 255, 255) + del ar + show(surface) + + # Flip the image around both axes, restoring its original layout. + ar = pg.PixelArray(surface) + ar[:] = ar[::-1, ::-1] + del ar + show(surface) + + # Rotate 90 degrees clockwise. + w, h = surface.get_size() + surface2 = pg.Surface((h, w), surface.get_flags(), surface) + ar = pg.PixelArray(surface) + ar2 = pg.PixelArray(surface2) + ar2[...] = ar.transpose()[::-1, :] + del ar, ar2 + show(surface2) + + # Scale it by throwing each second pixel away. + surface = pg.image.load(os.path.join(data_dir, "arraydemo.bmp")) + ar = pg.PixelArray(surface) + sf2 = ar[::2, ::2].make_surface() + del ar + show(sf2) + + # Replace anything looking like the blue color from the text. + ar = pg.PixelArray(surface) + ar.replace((60, 60, 255), (0, 255, 0), 0.06) + del ar + show(surface) + + # Extract anything which might be somewhat black. + surface = pg.image.load(os.path.join(data_dir, "arraydemo.bmp")) + ar = pg.PixelArray(surface) + ar2 = ar.extract((0, 0, 0), 0.07) + sf2 = ar2.surface + del ar, ar2 + show(sf2) + + # Compare two images. + surface = pg.image.load(os.path.join(data_dir, "alien1.gif")) + surface2 = pg.image.load(os.path.join(data_dir, "alien2.gif")) + ar1 = pg.PixelArray(surface) + ar2 = pg.PixelArray(surface2) + ar3 = ar1.compare(ar2, 0.07) + sf3 = ar3.surface + del ar1, ar2, ar3 + show(sf3) + + +if __name__ == "__main__": + main() + pg.quit() diff --git a/venv/Lib/site-packages/pygame/examples/playmus.py b/venv/Lib/site-packages/pygame/examples/playmus.py new file mode 100644 index 0000000..dac2f64 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/playmus.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python +""" pygame.examples.playmus + +A simple music player. + + Use pygame.mixer.music to play an audio file. + +A window is created to handle keyboard events for playback commands. + + +Keyboard Controls +----------------- + +space - play/pause toggle +r - rewind +f - fade out +q - stop + +""" +import sys + +import pygame as pg +import pygame.freetype + + +class Window(object): + """The application's Pygame window + + A Window instance manages the creation of and drawing to a + window. It is a singleton class. Only one instance can exist. + + """ + + instance = None + + def __new__(cls, *args, **kwds): + """Return an open Pygame window""" + + if Window.instance is not None: + return Window.instance + self = object.__new__(cls) + pg.display.init() + self.screen = pg.display.set_mode((600, 400)) + Window.instance = self + return self + + def __init__(self, title): + pg.display.set_caption(title) + self.text_color = (254, 231, 21, 255) + self.background_color = (16, 24, 32, 255) + self.screen.fill(self.background_color) + pg.display.flip() + + pygame.freetype.init() + self.font = pygame.freetype.Font(None, 20) + self.font.origin = True + self.ascender = int(self.font.get_sized_ascender() * 1.5) + self.descender = int(self.font.get_sized_descender() * 1.5) + self.line_height = self.ascender - self.descender + + self.write_lines( + "\nPress 'q' or 'ESCAPE' or close this window to quit\n" + "Press 'SPACE' to play / pause\n" + "Press 'r' to rewind to the beginning (restart)\n" + "Press 'f' to fade music out over 5 seconds\n\n" + "Window will quit automatically when music ends\n", + 0, + ) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() + return False + + def close(self): + pg.display.quit() + Window.instance = None + + def write_lines(self, text, line=0): + w, h = self.screen.get_size() + line_height = self.line_height + nlines = h // line_height + if line < 0: + line = nlines + line + for i, text_line in enumerate(text.split("\n"), line): + y = i * line_height + self.ascender + # Clear the line first. + self.screen.fill( + self.background_color, (0, i * line_height, w, line_height) + ) + # Write new text. + self.font.render_to(self.screen, (15, y), text_line, self.text_color) + pg.display.flip() + + +def show_usage_message(): + print("Usage: python playmus.py ") + print(" python -m pygame.examples.playmus ") + + +def main(file_path): + """Play an audio file with pg.mixer.music""" + + with Window(file_path) as win: + win.write_lines("Loading ...", -1) + pg.mixer.init(frequency=44100) + try: + paused = False + pg.mixer.music.load(file_path) + + # Make sure the event loop ticks over at least every 0.5 seconds. + pg.time.set_timer(pg.USEREVENT, 500) + + pg.mixer.music.play() + win.write_lines("Playing ...\n", -1) + + while pg.mixer.music.get_busy() or paused: + e = pg.event.wait() + if e.type == pg.KEYDOWN: + key = e.key + if key == pg.K_SPACE: + if paused: + pg.mixer.music.unpause() + paused = False + win.write_lines("Playing ...\n", -1) + else: + pg.mixer.music.pause() + paused = True + win.write_lines("Paused ...\n", -1) + elif key == pg.K_r: + if file_path[-3:].lower() in ("ogg", "mp3", "mod"): + status = "Rewound." + pg.mixer.music.rewind() + else: + status = "Restarted." + pg.mixer.music.play() + if paused: + pg.mixer.music.pause() + win.write_lines(status, -1) + elif key == pg.K_f: + win.write_lines("Fading out ...\n", -1) + pg.mixer.music.fadeout(5000) + # when finished get_busy() will return False. + elif key in [pg.K_q, pg.K_ESCAPE]: + paused = False + pg.mixer.music.stop() + # get_busy() will now return False. + elif e.type == pg.QUIT: + paused = False + pg.mixer.music.stop() + # get_busy() will now return False. + pg.time.set_timer(pg.USEREVENT, 0) + finally: + pg.mixer.quit() + pg.quit() + + +if __name__ == "__main__": + # Check the only command line argument, a file path + if len(sys.argv) != 2: + show_usage_message() + else: + main(sys.argv[1]) diff --git a/venv/Lib/site-packages/pygame/examples/prevent_display_stretching.py b/venv/Lib/site-packages/pygame/examples/prevent_display_stretching.py new file mode 100644 index 0000000..363df81 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/prevent_display_stretching.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python +""" pygame.examples.prevent_display_stretching + +Prevent display stretching on Windows. + +On some computers, the display environment can be configured to stretch +all windows so that they will not appear too small on the screen for +the user. This configuration is especially common on high-DPI displays. +pygame graphics appear distorted when automatically stretched by the +display environment. This script demonstrates a technique for preventing +this stretching and distortion. + +Limitations: +This script makes an API call that is only available on Windows (versions +Vista and newer). + +""" + +# Ensure that the computer is running Windows Vista or newer +import os +import sys + +# game constants +TEXTCOLOR = "green" +BACKGROUNDCOLOR = "black" +AXISCOLOR = "white" + +if os.name != "nt" or sys.getwindowsversion()[0] < 6: + raise NotImplementedError("this script requires Windows Vista or newer") + +import pygame as pg + +import ctypes + +# Determine whether or not the user would like to prevent stretching +if os.path.basename(sys.executable) == "pythonw.exe": + selection = "y" +else: + selection = None + while selection not in ("y", "n"): + selection = input("Prevent stretching? (y/n): ").strip().lower() + +if selection == "y": + msg = "Stretching is prevented." +else: + msg = "Stretching is not prevented." + +# Prevent stretching +if selection == "y": + user32 = ctypes.windll.user32 + user32.SetProcessDPIAware() + +# Show screen +pg.display.init() +RESOLUTION = (350, 350) +screen = pg.display.set_mode(RESOLUTION) + +# Render message onto a surface +pg.font.init() +font = pg.font.Font(None, 36) +msg_surf = font.render(msg, 1, TEXTCOLOR) +res_surf = font.render("Intended resolution: %ix%i" % RESOLUTION, 1, TEXTCOLOR) + +# Control loop +running = True +clock = pg.time.Clock() +counter = 0 +while running: + + for event in pg.event.get(): + if event.type == pg.QUIT: + running = False + + screen.fill(BACKGROUNDCOLOR) + + # Draw lines which will be blurry if the window is stretched + # or clear if the window is not stretched. + pg.draw.line(screen, AXISCOLOR, (0, counter), (RESOLUTION[0] - 1, counter)) + pg.draw.line(screen, AXISCOLOR, (counter, 0), (counter, RESOLUTION[1] - 1)) + + # Blit message onto screen surface + msg_blit_rect = screen.blit(msg_surf, (0, 0)) + screen.blit(res_surf, (0, msg_blit_rect.bottom)) + + clock.tick(10) + + pg.display.flip() + + counter += 1 + if counter == RESOLUTION[0]: + counter = 0 + +pg.quit() diff --git a/venv/Lib/site-packages/pygame/examples/resizing_new.py b/venv/Lib/site-packages/pygame/examples/resizing_new.py new file mode 100644 index 0000000..cda01f2 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/resizing_new.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +import pygame as pg + +pg.init() + +RES = (160, 120) +FPS = 30 +clock = pg.time.Clock() + +screen = pg.display.set_mode(RES, pg.RESIZABLE) +pg.display._set_autoresize(False) + +# MAIN LOOP + +done = False + +i = 0 +j = 0 + +while not done: + for event in pg.event.get(): + if event.type == pg.KEYDOWN and event.key == pg.K_q: + done = True + if event.type == pg.QUIT: + done = True + # if event.type==pg.WINDOWRESIZED: + # screen=pg.display.get_surface() + if event.type == pg.VIDEORESIZE: + screen = pg.display.get_surface() + i += 1 + i = i % screen.get_width() + j += i % 2 + j = j % screen.get_height() + + screen.fill((255, 0, 255)) + pg.draw.circle(screen, (0, 0, 0), (100, 100), 20) + pg.draw.circle(screen, (0, 0, 200), (0, 0), 10) + pg.draw.circle(screen, (200, 0, 0), (160, 120), 30) + pg.draw.line(screen, (250, 250, 0), (0, 120), (160, 0)) + pg.draw.circle(screen, (255, 255, 255), (i, j), 5) + + pg.display.flip() + clock.tick(FPS) +pg.quit() diff --git a/venv/Lib/site-packages/pygame/examples/scaletest.py b/venv/Lib/site-packages/pygame/examples/scaletest.py new file mode 100644 index 0000000..6d7b964 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/scaletest.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python +""" pygame.examples.scaletest + +Shows an interactive image scaler. + +""" +import sys +import time +import pygame as pg + + +def main(imagefile, convert_alpha=False, run_speed_test=False): + """show an interactive image scaler + + Args: + imagefile - name of source image (required) + convert_alpha - use convert_alpha() on the surf (default False) + run_speed_test - (default False) + """ + + # initialize display + pg.display.init() + # load background image + background = pg.image.load(imagefile) + + if run_speed_test: + if convert_alpha: + # convert_alpha() requires the display mode to be set + pg.display.set_mode((1, 1)) + background = background.convert_alpha() + + SpeedTest(background) + return + + # start fullscreen mode + screen = pg.display.set_mode((1024, 768), pg.FULLSCREEN) + if convert_alpha: + background = background.convert_alpha() + + # turn off the mouse pointer + pg.mouse.set_visible(0) + # main loop + bRunning = True + bUp = False + bDown = False + bLeft = False + bRight = False + cursize = [background.get_width(), background.get_height()] + while bRunning: + image = pg.transform.smoothscale(background, cursize) + imgpos = image.get_rect(centerx=512, centery=384) + screen.fill((255, 255, 255)) + screen.blit(image, imgpos) + pg.display.flip() + for event in pg.event.get(): + if event.type == pg.QUIT or ( + event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE + ): + bRunning = False + if event.type == pg.KEYDOWN: + if event.key == pg.K_UP: + bUp = True + if event.key == pg.K_DOWN: + bDown = True + if event.key == pg.K_LEFT: + bLeft = True + if event.key == pg.K_RIGHT: + bRight = True + if event.type == pg.KEYUP: + if event.key == pg.K_UP: + bUp = False + if event.key == pg.K_DOWN: + bDown = False + if event.key == pg.K_LEFT: + bLeft = False + if event.key == pg.K_RIGHT: + bRight = False + if bUp: + cursize[1] -= 2 + if cursize[1] < 1: + cursize[1] = 1 + if bDown: + cursize[1] += 2 + if bLeft: + cursize[0] -= 2 + if cursize[0] < 1: + cursize[0] = 1 + if bRight: + cursize[0] += 2 + pg.quit() + + +def SpeedTest(image): + print("\nImage Scaling Speed Test - Image Size %s\n" % str(image.get_size())) + + imgsize = [image.get_width(), image.get_height()] + duration = 0.0 + for i in range(128): + shrinkx = (imgsize[0] * i) // 128 + shrinky = (imgsize[1] * i) // 128 + start = time.time() + tempimg = pg.transform.smoothscale(image, (shrinkx, shrinky)) + duration += time.time() - start + del tempimg + + print( + "Average transform.smoothscale shrink time: %.4f ms." % (duration / 128 * 1000) + ) + + duration = 0.0 + for i in range(128): + expandx = (imgsize[0] * (i + 129)) // 128 + expandy = (imgsize[1] * (i + 129)) // 128 + start = time.time() + tempimg = pg.transform.smoothscale(image, (expandx, expandy)) + duration += time.time() - start + del tempimg + + print( + "Average transform.smoothscale expand time: %.4f ms." % (duration / 128 * 1000) + ) + + duration = 0.0 + for i in range(128): + shrinkx = (imgsize[0] * i) // 128 + shrinky = (imgsize[1] * i) // 128 + start = time.time() + tempimg = pg.transform.scale(image, (shrinkx, shrinky)) + duration += time.time() - start + del tempimg + + print("Average transform.scale shrink time: %.4f ms." % (duration / 128 * 1000)) + + duration = 0.0 + for i in range(128): + expandx = (imgsize[0] * (i + 129)) // 128 + expandy = (imgsize[1] * (i + 129)) // 128 + start = time.time() + tempimg = pg.transform.scale(image, (expandx, expandy)) + duration += time.time() - start + del tempimg + + print("Average transform.scale expand time: %.4f ms." % (duration / 128 * 1000)) + + +if __name__ == "__main__": + # check input parameters + if len(sys.argv) < 2: + print("\nUsage: %s imagefile [-t] [-convert_alpha]" % sys.argv[0]) + print(" imagefile image filename (required)") + print(" -t run speed test") + print(" -convert_alpha use convert_alpha() on the image's " "surface\n") + else: + main( + sys.argv[1], + convert_alpha="-convert_alpha" in sys.argv, + run_speed_test="-t" in sys.argv, + ) diff --git a/venv/Lib/site-packages/pygame/examples/scrap_clipboard.py b/venv/Lib/site-packages/pygame/examples/scrap_clipboard.py new file mode 100644 index 0000000..5978a42 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/scrap_clipboard.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +""" pygame.examples.scrap_clipboard + +Demonstrates the clipboard capabilities of pygame. + +Copy/paste! + + +Keyboard Controls +----------------- + +g - get and print types in clipboard. If, image blit to screen. +p - place some text into clipboard +a - print types available in the clipboard +i - put image into the clipboard +""" +import os + +import pygame as pg +import pygame.scrap as scrap + +from io import BytesIO + + +def usage(): + print("Press the 'g' key to get all of the current clipboard data") + print("Press the 'p' key to put a string into the clipboard") + print("Press the 'a' key to get a list of the currently available types") + print("Press the 'i' key to put an image into the clipboard") + + +main_dir = os.path.split(os.path.abspath(__file__))[0] + +pg.init() +screen = pg.display.set_mode((200, 200)) +c = pg.time.Clock() +going = True + +# Initialize the scrap module and use the clipboard mode. +scrap.init() +scrap.set_mode(pg.SCRAP_CLIPBOARD) + +usage() + +while going: + for e in pg.event.get(): + if e.type == pg.QUIT or (e.type == pg.KEYDOWN and e.key == pg.K_ESCAPE): + going = False + + elif e.type == pg.KEYDOWN and e.key == pg.K_g: + # This means to look for data. + print("Getting the different clipboard data..") + for t in scrap.get_types(): + r = scrap.get(t) + if r and len(r) > 500: + print("Type %s : (large %i byte buffer)" % (t, len(r))) + elif r is None: + print("Type %s : None" % (t,)) + else: + print("Type %s : '%s'" % (t, r.decode("ascii", "ignore"))) + if "image" in t: + namehint = t.split("/")[1] + if namehint in ["bmp", "png", "jpg"]: + f = BytesIO(r) + loaded_surf = pg.image.load(f, "." + namehint) + screen.blit(loaded_surf, (0, 0)) + + elif e.type == pg.KEYDOWN and e.key == pg.K_p: + # Place some text into the selection. + print("Placing clipboard text.") + scrap.put(pg.SCRAP_TEXT, b"Hello. This is a message from scrap.") + + elif e.type == pg.KEYDOWN and e.key == pg.K_a: + # Get all available types. + print("Getting the available types from the clipboard.") + types = scrap.get_types() + print(types) + if len(types) > 0: + print("Contains %s: %s" % (types[0], scrap.contains(types[0]))) + print("Contains _INVALID_: ", scrap.contains("_INVALID_")) + + elif e.type == pg.KEYDOWN and e.key == pg.K_i: + print("Putting image into the clipboard.") + scrap.set_mode(pg.SCRAP_CLIPBOARD) + fp = open(os.path.join(main_dir, "data", "liquid.bmp"), "rb") + buf = fp.read() + scrap.put("image/bmp", buf) + fp.close() + + elif e.type in (pg.KEYDOWN, pg.MOUSEBUTTONDOWN): + usage() + pg.display.flip() + c.tick(40) +pg.quit() diff --git a/venv/Lib/site-packages/pygame/examples/scroll.py b/venv/Lib/site-packages/pygame/examples/scroll.py new file mode 100644 index 0000000..48b7417 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/scroll.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python +""" pygame.examples.scroll + +An zoomed image viewer that demonstrates Surface.scroll + +This example shows a scrollable image that has a zoom factor of eight. +It uses the Surface.scroll function to shift the image on the display +surface. A clip rectangle protects a margin area. If called as a function, +the example accepts an optional image file path. If run as a program +it takes an optional file path command line argument. If no file +is provided a default image file is used. + +When running click on a black triangle to move one pixel in the direction +the triangle points. Or use the arrow keys. Close the window or press ESC +to quit. +""" +import sys +import os + +import pygame as pg +from pygame.transform import scale + +main_dir = os.path.dirname(os.path.abspath(__file__)) + +# game constants +DIR_UP = 1 +DIR_DOWN = 2 +DIR_LEFT = 3 +DIR_RIGHT = 4 + +zoom_factor = 8 + + +def draw_arrow(surf, color, posn, direction): + x, y = posn + if direction == DIR_UP: + pointlist = ((x - 29, y + 30), (x + 30, y + 30), (x + 1, y - 29), (x, y - 29)) + elif direction == DIR_DOWN: + pointlist = ((x - 29, y - 29), (x + 30, y - 29), (x + 1, y + 30), (x, y + 30)) + elif direction == DIR_LEFT: + pointlist = ((x + 30, y - 29), (x + 30, y + 30), (x - 29, y + 1), (x - 29, y)) + else: + pointlist = ((x - 29, y - 29), (x - 29, y + 30), (x + 30, y + 1), (x + 30, y)) + pg.draw.polygon(surf, color, pointlist) + + +def add_arrow_button(screen, regions, posn, direction): + draw_arrow(screen, "black", posn, direction) + draw_arrow(regions, (direction, 0, 0), posn, direction) + + +def scroll_view(screen, image, direction, view_rect): + src_rect = None + zoom_view_rect = screen.get_clip() + image_w, image_h = image.get_size() + if direction == DIR_UP: + if view_rect.top > 0: + screen.scroll(dy=zoom_factor) + view_rect.move_ip(0, -1) + src_rect = view_rect.copy() + src_rect.h = 1 + dst_rect = zoom_view_rect.copy() + dst_rect.h = zoom_factor + elif direction == DIR_DOWN: + if view_rect.bottom < image_h: + screen.scroll(dy=-zoom_factor) + view_rect.move_ip(0, 1) + src_rect = view_rect.copy() + src_rect.h = 1 + src_rect.bottom = view_rect.bottom + dst_rect = zoom_view_rect.copy() + dst_rect.h = zoom_factor + dst_rect.bottom = zoom_view_rect.bottom + elif direction == DIR_LEFT: + if view_rect.left > 0: + screen.scroll(dx=zoom_factor) + view_rect.move_ip(-1, 0) + src_rect = view_rect.copy() + src_rect.w = 1 + dst_rect = zoom_view_rect.copy() + dst_rect.w = zoom_factor + elif direction == DIR_RIGHT: + if view_rect.right < image_w: + screen.scroll(dx=-zoom_factor) + view_rect.move_ip(1, 0) + src_rect = view_rect.copy() + src_rect.w = 1 + src_rect.right = view_rect.right + dst_rect = zoom_view_rect.copy() + dst_rect.w = zoom_factor + dst_rect.right = zoom_view_rect.right + if src_rect is not None: + scale(image.subsurface(src_rect), dst_rect.size, screen.subsurface(dst_rect)) + pg.display.update(zoom_view_rect) + + +def main(image_file=None): + if image_file is None: + image_file = os.path.join(main_dir, "data", "arraydemo.bmp") + margin = 80 + view_size = (30, 20) + zoom_view_size = (view_size[0] * zoom_factor, view_size[1] * zoom_factor) + win_size = (zoom_view_size[0] + 2 * margin, zoom_view_size[1] + 2 * margin) + background_color = pg.Color("beige") + + pg.init() + + # set up key repeating so we can hold down the key to scroll. + old_k_delay, old_k_interval = pg.key.get_repeat() + pg.key.set_repeat(500, 30) + + try: + screen = pg.display.set_mode(win_size) + screen.fill(background_color) + pg.display.flip() + + image = pg.image.load(image_file).convert() + image_w, image_h = image.get_size() + + if image_w < view_size[0] or image_h < view_size[1]: + print("The source image is too small for this example.") + print("A %i by %i or larger image is required." % zoom_view_size) + return + + regions = pg.Surface(win_size, 0, 24) + add_arrow_button(screen, regions, (40, win_size[1] // 2), DIR_LEFT) + add_arrow_button( + screen, regions, (win_size[0] - 40, win_size[1] // 2), DIR_RIGHT + ) + add_arrow_button(screen, regions, (win_size[0] // 2, 40), DIR_UP) + add_arrow_button( + screen, regions, (win_size[0] // 2, win_size[1] - 40), DIR_DOWN + ) + pg.display.flip() + + screen.set_clip((margin, margin, zoom_view_size[0], zoom_view_size[1])) + + view_rect = pg.Rect(0, 0, view_size[0], view_size[1]) + + scale( + image.subsurface(view_rect), + zoom_view_size, + screen.subsurface(screen.get_clip()), + ) + pg.display.flip() + + # the direction we will scroll in. + direction = None + + clock = pg.time.Clock() + clock.tick() + + going = True + while going: + # wait for events before doing anything. + # events = [pg.event.wait()] + pg.event.get() + events = pg.event.get() + + for e in events: + if e.type == pg.KEYDOWN: + if e.key == pg.K_ESCAPE: + going = False + elif e.key == pg.K_DOWN: + scroll_view(screen, image, DIR_DOWN, view_rect) + elif e.key == pg.K_UP: + scroll_view(screen, image, DIR_UP, view_rect) + elif e.key == pg.K_LEFT: + scroll_view(screen, image, DIR_LEFT, view_rect) + elif e.key == pg.K_RIGHT: + scroll_view(screen, image, DIR_RIGHT, view_rect) + elif e.type == pg.QUIT: + going = False + elif e.type == pg.MOUSEBUTTONDOWN: + direction = regions.get_at(e.pos)[0] + elif e.type == pg.MOUSEBUTTONUP: + direction = None + + if direction: + scroll_view(screen, image, direction, view_rect) + clock.tick(30) + + finally: + pg.key.set_repeat(old_k_delay, old_k_interval) + pg.quit() + + +if __name__ == "__main__": + if len(sys.argv) > 1: + image_file = sys.argv[1] + else: + image_file = None + main(image_file) diff --git a/venv/Lib/site-packages/pygame/examples/setmodescale.py b/venv/Lib/site-packages/pygame/examples/setmodescale.py new file mode 100644 index 0000000..3f427d2 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/setmodescale.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +""" pygame.examples.setmodescale + +On high resolution displays(4k, 1080p) and tiny graphics games (640x480) +show up very small so that they are unplayable. SCALED scales up the window +for you. The game thinks it's a 640x480 window, but really it can be bigger. +Mouse events are scaled for you, so your game doesn't need to do it. + +Passing SCALED to pygame.display.set_mode means the resolution depends +on desktop size and the graphics are scaled. +""" + +import pygame as pg + +pg.init() + +RES = (160, 120) +FPS = 30 +clock = pg.time.Clock() + +print("desktops", pg.display.get_desktop_sizes()) +screen = pg.display.set_mode(RES, pg.SCALED | pg.RESIZABLE) + +# MAIN LOOP + +done = False + +i = 0 +j = 0 + +r_name, r_flags = pg.display._get_renderer_info() +print("renderer:", r_name, "flags:", bin(r_flags)) +for flag, name in [ + (1, "software"), + (2, "accelerated"), + (4, "VSync"), + (8, "render to texture"), +]: + if flag & r_flags: + print(name) + +while not done: + for event in pg.event.get(): + if event.type == pg.KEYDOWN and event.key == pg.K_q: + done = True + if event.type == pg.QUIT: + done = True + if event.type == pg.KEYDOWN and event.key == pg.K_f: + pg.display.toggle_fullscreen() + if event.type == pg.VIDEORESIZE: + pg.display._resize_event(event) + + i += 1 + i = i % screen.get_width() + j += i % 2 + j = j % screen.get_height() + + screen.fill((255, 0, 255)) + pg.draw.circle(screen, (0, 0, 0), (100, 100), 20) + pg.draw.circle(screen, (0, 0, 200), (0, 0), 10) + pg.draw.circle(screen, (200, 0, 0), (160, 120), 30) + pg.draw.line(screen, (250, 250, 0), (0, 120), (160, 0)) + pg.draw.circle(screen, (255, 255, 255), (i, j), 5) + + pg.display.flip() + clock.tick(FPS) +pg.quit() diff --git a/venv/Lib/site-packages/pygame/examples/sound.py b/venv/Lib/site-packages/pygame/examples/sound.py new file mode 100644 index 0000000..c5a23b9 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/sound.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +""" pygame.examples.sound + +Playing a soundfile and waiting for it to finish. You'll need the +pygame.mixer module for this to work. Note how in this simple example +we don't even bother loading all of the pygame package. +Just pick the mixer for sound and time for the delay function. + +Optional command line argument: audio file name +""" +import os +import sys +import pygame as pg + +main_dir = os.path.split(os.path.abspath(__file__))[0] + + +def main(file_path=None): + """Play an audio file as a buffered sound sample + + :param str file_path: audio file (default data/secosmic_low.wav) + """ + # choose a desired audio format + pg.mixer.init(11025) # raises exception on fail + + # load the sound + sound = pg.mixer.Sound(file_path) + + # start playing + print("Playing Sound...") + channel = sound.play() + + # poll until finished + while channel.get_busy(): # still playing + print(" ...still going...") + pg.time.wait(1000) + print("...Finished") + pg.quit() + + +if __name__ == "__main__": + if len(sys.argv) > 1: + main(sys.argv[1]) + else: + main(os.path.join(main_dir, "data", "secosmic_lo.wav")) diff --git a/venv/Lib/site-packages/pygame/examples/sound_array_demos.py b/venv/Lib/site-packages/pygame/examples/sound_array_demos.py new file mode 100644 index 0000000..1a2b49d --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/sound_array_demos.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python +""" pygame.examples.sound_array_demos + +Creates an echo effect on any Sound object. + +Uses sndarray and numpy to create offset faded copies of the +original sound. Currently it just uses hardcoded values for the +number of echos and the delay. Easy for you to recreate as +needed. + +version 2. changes: +- Should work with different sample rates now. +- put into a function. +- Uses numpy by default, but falls back on Numeric. +""" +import os +import pygame as pg +from numpy import zeros, int32, int16 +import time + + +# pg.mixer.init(44100, -16, 0) +pg.mixer.init() +# pg.mixer.init(11025, -16, 0) +# pg.mixer.init(11025) + + +def make_echo(sound, samples_per_second, mydebug=True): + """returns a sound which is echoed of the last one.""" + + echo_length = 3.5 + + a1 = pg.sndarray.array(sound) + if mydebug: + print("SHAPE1: %s" % (a1.shape,)) + + length = a1.shape[0] + + # myarr = zeros(length+12000) + myarr = zeros(a1.shape, int32) + + if len(a1.shape) > 1: + # mult = a1.shape[1] + size = (a1.shape[0] + int(echo_length * a1.shape[0]), a1.shape[1]) + # size = (a1.shape[0] + int(a1.shape[0] + (echo_length * 3000)), a1.shape[1]) + else: + # mult = 1 + size = (a1.shape[0] + int(echo_length * a1.shape[0]),) + # size = (a1.shape[0] + int(a1.shape[0] + (echo_length * 3000)),) + + if mydebug: + print(int(echo_length * a1.shape[0])) + myarr = zeros(size, int32) + + if mydebug: + print("size %s" % (size,)) + print(myarr.shape) + myarr[:length] = a1 + # print (myarr[3000:length+3000]) + # print (a1 >> 1) + # print ("a1.shape %s" % (a1.shape,)) + # c = myarr[3000:length+(3000*mult)] + # print ("c.shape %s" % (c.shape,)) + + incr = int(samples_per_second / echo_length) + gap = length + + myarr[incr : gap + incr] += a1 >> 1 + myarr[incr * 2 : gap + (incr * 2)] += a1 >> 2 + myarr[incr * 3 : gap + (incr * 3)] += a1 >> 3 + myarr[incr * 4 : gap + (incr * 4)] += a1 >> 4 + + if mydebug: + print("SHAPE2: %s" % (myarr.shape,)) + + sound2 = pg.sndarray.make_sound(myarr.astype(int16)) + + return sound2 + + +def slow_down_sound(sound, rate): + """returns a sound which is a slowed down version of the original. + rate - at which the sound should be slowed down. eg. 0.5 would be half speed. + """ + + raise NotImplementedError() + # grow_rate = 1 / rate + # make it 1/rate times longer. + # a1 = pg.sndarray.array(sound) + # surf = pg.surfarray.make_surface(a1) + # print (a1.shape[0] * grow_rate) + # scaled_surf = pg.transform.scale(surf, (int(a1.shape[0] * grow_rate), a1.shape[1])) + # print (scaled_surf) + # print (surf) + + # a2 = a1 * rate + # print (a1.shape) + # print (a2.shape) + # print (a2) + # sound2 = pg.sndarray.make_sound(a2.astype(int16)) + # return sound2 + + +def sound_from_pos(sound, start_pos, samples_per_second=None, inplace=1): + """returns a sound which begins at the start_pos. + start_pos - in seconds from the begining. + samples_per_second - + """ + + # see if we want to reuse the sound data or not. + if inplace: + a1 = pg.sndarray.samples(sound) + else: + a1 = pg.sndarray.array(sound) + + # see if samples per second has been given. If not, query the pg.mixer. + # eg. it might be set to 22050 + if samples_per_second is None: + samples_per_second = pg.mixer.get_init()[0] + + # figure out the start position in terms of samples. + start_pos_in_samples = int(start_pos * samples_per_second) + + # cut the beginning off the sound at the start position. + a2 = a1[start_pos_in_samples:] + + # make the Sound instance from the array. + sound2 = pg.sndarray.make_sound(a2) + + return sound2 + + +def main(): + """play various sndarray effects""" + + main_dir = os.path.split(os.path.abspath(__file__))[0] + print("mixer.get_init %s" % (pg.mixer.get_init(),)) + + samples_per_second = pg.mixer.get_init()[0] + + print(("-" * 30) + "\n") + print("loading sound") + sound = pg.mixer.Sound(os.path.join(main_dir, "data", "car_door.wav")) + + print("-" * 30) + print("start positions") + print("-" * 30) + + start_pos = 0.1 + sound2 = sound_from_pos(sound, start_pos, samples_per_second) + + print("sound.get_length %s" % (sound.get_length(),)) + print("sound2.get_length %s" % (sound2.get_length(),)) + sound2.play() + while pg.mixer.get_busy(): + pg.time.wait(200) + + print("waiting 2 seconds") + pg.time.wait(2000) + print("playing original sound") + + sound.play() + while pg.mixer.get_busy(): + pg.time.wait(200) + + print("waiting 2 seconds") + pg.time.wait(2000) + + # if 0: + # #TODO: this is broken. + # print (("-" * 30) + "\n") + # print ("Slow down the original sound.") + # rate = 0.2 + # slowed_sound = slow_down_sound(sound, rate) + # slowed_sound.play() + # while pg.mixer.get_busy(): + # pg.time.wait(200) + + print("-" * 30) + print("echoing") + print("-" * 30) + + t1 = time.time() + sound2 = make_echo(sound, samples_per_second) + print("time to make echo %i" % (time.time() - t1,)) + + print("original sound") + sound.play() + while pg.mixer.get_busy(): + pg.time.wait(200) + + print("echoed sound") + sound2.play() + while pg.mixer.get_busy(): + pg.time.wait(200) + + sound = pg.mixer.Sound(os.path.join(main_dir, "data", "secosmic_lo.wav")) + + t1 = time.time() + sound3 = make_echo(sound, samples_per_second) + print("time to make echo %i" % (time.time() - t1,)) + + print("original sound") + sound.play() + while pg.mixer.get_busy(): + pg.time.wait(200) + + print("echoed sound") + sound3.play() + while pg.mixer.get_busy(): + pg.time.wait(200) + + pg.quit() + + +if __name__ == "__main__": + main() diff --git a/venv/Lib/site-packages/pygame/examples/sprite_texture.py b/venv/Lib/site-packages/pygame/examples/sprite_texture.py new file mode 100644 index 0000000..79d8cf5 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/sprite_texture.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +""" pygame.examples.sprite_texture + +Experimental! Uses APIs which may disapear in the next release (_sdl2 is private). + + +Hardware accelerated Image objects with pygame.sprite. + +_sdl2.video.Image is a backwards compatible way with to use Texture with +pygame.sprite groups. +""" +import os +import pygame as pg + +if pg.get_sdl_version()[0] < 2: + raise SystemExit("This example requires pygame 2 and SDL2.") +from pygame._sdl2 import Window, Texture, Image, Renderer + + +data_dir = os.path.join(os.path.split(os.path.abspath(__file__))[0], "data") + + +def load_img(file): + return pg.image.load(os.path.join(data_dir, file)) + + +pg.display.init() +pg.key.set_repeat(10, 10) + +win = Window("asdf", resizable=True) +renderer = Renderer(win) +tex = Texture.from_surface(renderer, load_img("alien1.gif")) + + +class Something(pg.sprite.Sprite): + def __init__(self, img): + pg.sprite.Sprite.__init__(self) + + self.rect = img.get_rect() + self.image = img + + self.rect.w *= 5 + self.rect.h *= 5 + + img.origin = self.rect.w / 2, self.rect.h / 2 + + +sprite = Something(Image(tex, (0, 0, tex.width / 2, tex.height / 2))) +sprite.rect.x = 250 +sprite.rect.y = 50 + +# sprite2 = Something(Image(sprite.image)) +sprite2 = Something(Image(tex)) +sprite2.rect.x = 250 +sprite2.rect.y = 250 +sprite2.rect.w /= 2 +sprite2.rect.h /= 2 + +group = pg.sprite.Group() +group.add(sprite2) +group.add(sprite) + +import math + +t = 0 +running = True +clock = pg.time.Clock() +renderer.draw_color = (255, 0, 0, 255) + +while running: + for event in pg.event.get(): + if event.type == pg.QUIT: + running = False + elif event.type == pg.KEYDOWN: + if event.key == pg.K_ESCAPE: + running = False + elif event.key == pg.K_LEFT: + sprite.rect.x -= 5 + elif event.key == pg.K_RIGHT: + sprite.rect.x += 5 + elif event.key == pg.K_DOWN: + sprite.rect.y += 5 + elif event.key == pg.K_UP: + sprite.rect.y -= 5 + + renderer.clear() + t += 1 + + img = sprite.image + img.angle += 1 + img.flipX = t % 50 < 25 + img.flipY = t % 100 < 50 + img.color[0] = int(255.0 * (0.5 + math.sin(0.5 * t + 10.0) / 2.0)) + img.alpha = int(255.0 * (0.5 + math.sin(0.1 * t) / 2.0)) + # img.draw(dstrect=(x, y, 5 * img.srcrect['w'], 5 * img.srcrect['h'])) + + group.draw(renderer) + + renderer.present() + + clock.tick(60) + win.title = str("FPS: {}".format(clock.get_fps())) + +pg.quit() diff --git a/venv/Lib/site-packages/pygame/examples/stars.py b/venv/Lib/site-packages/pygame/examples/stars.py new file mode 100644 index 0000000..1bd2ac6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/stars.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python +""" pg.examples.stars + + We are all in the gutter, + but some of us are looking at the stars. + -- Oscar Wilde + +A simple starfield example. Note you can move the 'center' of +the starfield by leftclicking in the window. This example show +the basics of creating a window, simple pixel plotting, and input +event management. +""" +import random +import math +import pygame as pg + +# constants +WINSIZE = [640, 480] +WINCENTER = [320, 240] +NUMSTARS = 150 + + +def init_star(): + "creates new star values" + dir = random.randrange(100000) + velmult = random.random() * 0.6 + 0.4 + vel = [math.sin(dir) * velmult, math.cos(dir) * velmult] + return vel, WINCENTER[:] + + +def initialize_stars(): + "creates a new starfield" + stars = [] + for x in range(NUMSTARS): + star = init_star() + vel, pos = star + steps = random.randint(0, WINCENTER[0]) + pos[0] = pos[0] + (vel[0] * steps) + pos[1] = pos[1] + (vel[1] * steps) + vel[0] = vel[0] * (steps * 0.09) + vel[1] = vel[1] * (steps * 0.09) + stars.append(star) + move_stars(stars) + return stars + + +def draw_stars(surface, stars, color): + "used to draw (and clear) the stars" + for vel, pos in stars: + pos = (int(pos[0]), int(pos[1])) + surface.set_at(pos, color) + + +def move_stars(stars): + "animate the star values" + for vel, pos in stars: + pos[0] = pos[0] + vel[0] + pos[1] = pos[1] + vel[1] + if not 0 <= pos[0] <= WINSIZE[0] or not 0 <= pos[1] <= WINSIZE[1]: + vel[:], pos[:] = init_star() + else: + vel[0] = vel[0] * 1.05 + vel[1] = vel[1] * 1.05 + + +def main(): + "This is the starfield code" + # create our starfield + random.seed() + stars = initialize_stars() + clock = pg.time.Clock() + # initialize and prepare screen + pg.init() + screen = pg.display.set_mode(WINSIZE) + pg.display.set_caption("pygame Stars Example") + white = 255, 240, 200 + black = 20, 20, 40 + screen.fill(black) + + # main game loop + done = 0 + while not done: + draw_stars(screen, stars, black) + move_stars(stars) + draw_stars(screen, stars, white) + pg.display.update() + for e in pg.event.get(): + if e.type == pg.QUIT or (e.type == pg.KEYUP and e.key == pg.K_ESCAPE): + done = 1 + break + elif e.type == pg.MOUSEBUTTONDOWN and e.button == 1: + WINCENTER[:] = list(e.pos) + clock.tick(50) + pg.quit() + + +# if python says run, then we should run +if __name__ == "__main__": + main() + + # I prefer the time of insects to the time of stars. + # + # -- Wisława Szymborska diff --git a/venv/Lib/site-packages/pygame/examples/testsprite.py b/venv/Lib/site-packages/pygame/examples/testsprite.py new file mode 100644 index 0000000..825fb9e --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/testsprite.py @@ -0,0 +1,261 @@ +#!/usr/bin/env python +""" pg.examples.testsprite + +Like the testsprite.c that comes with libsdl, this pygame version shows +lots of sprites moving around. + +It is an abomination of ugly code, and mostly used for testing. + + +See pg.examples.aliens for some prettyier code. +""" +import sys +import os + +from random import randint +from time import time + +import pygame as pg + + +if "-psyco" in sys.argv: + try: + import psyco + + psyco.full() + except Exception: + print("No psyco for you! psyco failed to import and run.") + +main_dir = os.path.split(os.path.abspath(__file__))[0] +data_dir = os.path.join(main_dir, "data") + + +# use this to use update rects or not. +# If the screen is mostly full, then update rects are not useful. +update_rects = True +if "-update_rects" in sys.argv: + update_rects = True +if "-noupdate_rects" in sys.argv: + update_rects = False + +use_static = False +if "-static" in sys.argv: + use_static = True + + +use_layered_dirty = False +if "-layered_dirty" in sys.argv: + update_rects = True + use_layered_dirty = True + + +flags = 0 +if "-flip" in sys.argv: + flags ^= pg.DOUBLEBUF + +if "-fullscreen" in sys.argv: + flags ^= pg.FULLSCREEN + +if "-sw" in sys.argv: + flags ^= pg.SWSURFACE + +use_rle = True + +if "-hw" in sys.argv: + flags ^= pg.HWSURFACE + use_rle = False + +if "-scaled" in sys.argv: + flags ^= pg.SCALED + +screen_dims = [640, 480] + +if "-height" in sys.argv: + i = sys.argv.index("-height") + screen_dims[1] = int(sys.argv[i + 1]) + +if "-width" in sys.argv: + i = sys.argv.index("-width") + screen_dims[0] = int(sys.argv[i + 1]) + +if "-alpha" in sys.argv: + use_alpha = True +else: + use_alpha = False + +print(screen_dims) + + +##class Thingy(pg.sprite.Sprite): +## images = None +## def __init__(self): +## pg.sprite.Sprite.__init__(self) +## self.image = Thingy.images[0] +## self.rect = self.image.get_rect() +## self.rect.x = randint(0, screen_dims[0]) +## self.rect.y = randint(0, screen_dims[1]) +## #self.vel = [randint(-10, 10), randint(-10, 10)] +## self.vel = [randint(-1, 1), randint(-1, 1)] +## +## def move(self): +## for i in [0, 1]: +## nv = self.rect[i] + self.vel[i] +## if nv >= screen_dims[i] or nv < 0: +## self.vel[i] = -self.vel[i] +## nv = self.rect[i] + self.vel[i] +## self.rect[i] = nv + + +class Thingy(pg.sprite.DirtySprite): + images = None + + def __init__(self): + ## pg.sprite.Sprite.__init__(self) + pg.sprite.DirtySprite.__init__(self) + self.image = Thingy.images[0] + self.rect = self.image.get_rect() + self.rect.x = randint(0, screen_dims[0]) + self.rect.y = randint(0, screen_dims[1]) + # self.vel = [randint(-10, 10), randint(-10, 10)] + self.vel = [randint(-1, 1), randint(-1, 1)] + self.dirty = 2 + + def update(self): + for i in [0, 1]: + nv = self.rect[i] + self.vel[i] + if nv >= screen_dims[i] or nv < 0: + self.vel[i] = -self.vel[i] + nv = self.rect[i] + self.vel[i] + self.rect[i] = nv + + +class Static(pg.sprite.DirtySprite): + images = None + + def __init__(self): + pg.sprite.DirtySprite.__init__(self) + self.image = Static.images[0] + self.rect = self.image.get_rect() + self.rect.x = randint(0, 3 * screen_dims[0] / 4) + self.rect.y = randint(0, 3 * screen_dims[1] / 4) + + +def main( + update_rects=True, + use_static=False, + use_layered_dirty=False, + screen_dims=[640, 480], + use_alpha=False, + flags=0, +): + """Show lots of sprites moving around + + Optional keyword arguments: + update_rects - use the RenderUpdate sprite group class (default True) + use_static - include non-moving images (default False) + use_layered_dirty - Use the FastRenderGroup sprite group (default False) + screen_dims - Pygame window dimensions (default [640, 480]) + use_alpha - use alpha blending (default False) + flags - additional display mode flags (default no additional flags) + + """ + + if use_layered_dirty: + update_rects = True + + pg.init() # needed to initialise time module for get_ticks() + pg.display.init() + + # if "-fast" in sys.argv: + + screen = pg.display.set_mode(screen_dims, flags, vsync="-vsync" in sys.argv) + + # this is mainly for GP2X, so it can quit. + pg.joystick.init() + num_joysticks = pg.joystick.get_count() + if num_joysticks > 0: + stick = pg.joystick.Joystick(0) + stick.init() # now we will receive events for the joystick + + screen.fill([0, 0, 0]) + pg.display.flip() + sprite_surface = pg.image.load(os.path.join(data_dir, "asprite.bmp")) + sprite_surface2 = pg.image.load(os.path.join(data_dir, "static.png")) + + if use_rle: + sprite_surface.set_colorkey([0xFF, 0xFF, 0xFF], pg.SRCCOLORKEY | pg.RLEACCEL) + sprite_surface2.set_colorkey([0xFF, 0xFF, 0xFF], pg.SRCCOLORKEY | pg.RLEACCEL) + else: + sprite_surface.set_colorkey([0xFF, 0xFF, 0xFF], pg.SRCCOLORKEY) + sprite_surface2.set_colorkey([0xFF, 0xFF, 0xFF], pg.SRCCOLORKEY) + + if use_alpha: + sprite_surface = sprite_surface.convert_alpha() + sprite_surface2 = sprite_surface2.convert_alpha() + else: + sprite_surface = sprite_surface.convert() + sprite_surface2 = sprite_surface2.convert() + + Thingy.images = [sprite_surface] + if use_static: + Static.images = [sprite_surface2] + + if len(sys.argv) > 1: + try: + numsprites = int(sys.argv[-1]) + except Exception: + numsprites = 100 + else: + numsprites = 100 + sprites = None + if use_layered_dirty: + ## sprites = pg.sprite.FastRenderGroup() + sprites = pg.sprite.LayeredDirty() + else: + if update_rects: + sprites = pg.sprite.RenderUpdates() + else: + sprites = pg.sprite.Group() + + for i in range(0, numsprites): + if use_static and i % 2 == 0: + sprites.add(Static()) + sprites.add(Thingy()) + + frames = 0 + start = time() + + background = pg.Surface(screen.get_size()) + background = background.convert() + background.fill([0, 0, 0]) + + going = True + while going: + if not update_rects: + screen.fill([0, 0, 0]) + + ## for sprite in sprites: + ## sprite.move() + + if update_rects: + sprites.clear(screen, background) + sprites.update() + + rects = sprites.draw(screen) + if update_rects: + pg.display.update(rects) + else: + pg.display.flip() + + for event in pg.event.get(): + if event.type in [pg.QUIT, pg.KEYDOWN, pg.QUIT, pg.JOYBUTTONDOWN]: + going = False + + frames += 1 + end = time() + print("FPS: %f" % (frames / ((end - start)))) + pg.quit() + + +if __name__ == "__main__": + main(update_rects, use_static, use_layered_dirty, screen_dims, use_alpha, flags) diff --git a/venv/Lib/site-packages/pygame/examples/textinput.py b/venv/Lib/site-packages/pygame/examples/textinput.py new file mode 100644 index 0000000..4e241d1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/textinput.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python +""" pg.examples.textinput + +A little "console" where you can write in text. + +Shows how to use the TEXTEDITING and TEXTINPUT events. +""" +import sys +import pygame as pg +import pygame.freetype as freetype + +# Version check +if pg.get_sdl_version() < (2, 0, 0): + raise Exception("This example requires pygame 2.") + +###CONSTS +# Set to true or add 'showevent' in argv to see IME and KEYDOWN events +PRINT_EVENT = False +# frames per second, the general speed of the program +FPS = 50 +# size of window +WINDOWWIDTH, WINDOWHEIGHT = 640, 480 +BGCOLOR = (0, 0, 0) + +# position of chatlist and chatbox +CHATLIST_POS = pg.Rect(0, 20, WINDOWWIDTH, 400) +CHATBOX_POS = pg.Rect(0, 440, WINDOWWIDTH, 40) +CHATLIST_MAXSIZE = 20 + +TEXTCOLOR = (0, 255, 0) + +# Add fontname for each language, otherwise some text can't be correctly displayed. +FONTNAMES = [ + "notosanscjktcregular", + "notosansmonocjktcregular", + "notosansregular,", + "microsoftjhengheimicrosoftjhengheiuilight", + "microsoftyaheimicrosoftyaheiuilight", + "msgothicmsuigothicmspgothic", + "msmincho", + "Arial", +] + +# Initalize +pg.init() +Screen = pg.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT)) +pg.display.set_caption("TextInput example") +FPSClock = pg.time.Clock() + +# Freetype +# "The font name can be a comma separated list of font names to search for." +FONTNAMES = ",".join(str(x) for x in FONTNAMES) +Font = freetype.SysFont(FONTNAMES, 24) +FontSmall = freetype.SysFont(FONTNAMES, 16) +print("Using font: " + Font.name) + +# Main loop process +def main(): + global BGCOLOR, PRINT_EVENT, CHATBOX_POS, CHATLIST_POS, CHATLIST_MAXSIZE + global FPSClock, Font, Screen + + """ + https://wiki.libsdl.org/SDL_HINT_IME_INTERNAL_EDITING + https://wiki.libsdl.org/Tutorials/TextInput + Candidate list not showing due to SDL2 problem ;w; + """ + pg.key.start_text_input() + input_rect = pg.Rect(80, 80, 320, 40) + pg.key.set_text_input_rect(input_rect) + + _IMEEditing = False + _IMEText = "" + _IMETextPos = 0 + _IMEEditingText = "" + _IMEEditingPos = 0 + ChatList = [] + + while True: + for event in pg.event.get(): + if event.type == pg.QUIT: + pg.quit() + return + + elif event.type == pg.KEYDOWN: + if PRINT_EVENT: + print(event) + + if _IMEEditing: + if len(_IMEEditingText) == 0: + _IMEEditing = False + continue + + if event.key == pg.K_BACKSPACE: + if len(_IMEText) > 0 and _IMETextPos > 0: + _IMEText = ( + _IMEText[0 : _IMETextPos - 1] + _IMEText[_IMETextPos:] + ) + _IMETextPos = max(0, _IMETextPos - 1) + + elif event.key == pg.K_DELETE: + _IMEText = _IMEText[0:_IMETextPos] + _IMEText[_IMETextPos + 1 :] + elif event.key == pg.K_LEFT: + _IMETextPos = max(0, _IMETextPos - 1) + elif event.key == pg.K_RIGHT: + _IMETextPos = min(len(_IMEText), _IMETextPos + 1) + # Handle ENTER key + elif event.key in [pg.K_RETURN, pg.K_KP_ENTER]: + # Block if we have no text to append + if len(_IMEText) == 0: + continue + + # Append chat list + ChatList.append(_IMEText) + if len(ChatList) > CHATLIST_MAXSIZE: + ChatList.pop(0) + _IMEText = "" + _IMETextPos = 0 + + elif event.type == pg.TEXTEDITING: + if PRINT_EVENT: + print(event) + _IMEEditing = True + _IMEEditingText = event.text + _IMEEditingPos = event.start + + elif event.type == pg.TEXTINPUT: + if PRINT_EVENT: + print(event) + _IMEEditing = False + _IMEEditingText = "" + _IMEText = _IMEText[0:_IMETextPos] + event.text + _IMEText[_IMETextPos:] + _IMETextPos += len(event.text) + + # Screen updates + Screen.fill(BGCOLOR) + + # Chat List updates + chat_height = CHATLIST_POS.height / CHATLIST_MAXSIZE + for i, chat in enumerate(ChatList): + FontSmall.render_to( + Screen, + (CHATLIST_POS.x, CHATLIST_POS.y + i * chat_height), + chat, + TEXTCOLOR, + ) + + # Chat box updates + start_pos = CHATBOX_POS.copy() + ime_textL = ">" + _IMEText[0:_IMETextPos] + ime_textM = ( + _IMEEditingText[0:_IMEEditingPos] + "|" + _IMEEditingText[_IMEEditingPos:] + ) + ime_textR = _IMEText[_IMETextPos:] + + rect_textL = Font.render_to(Screen, start_pos, ime_textL, TEXTCOLOR) + start_pos.x += rect_textL.width + + # Editing texts should be underlined + rect_textM = Font.render_to( + Screen, start_pos, ime_textM, TEXTCOLOR, None, freetype.STYLE_UNDERLINE + ) + start_pos.x += rect_textM.width + Font.render_to(Screen, start_pos, ime_textR, TEXTCOLOR) + + pg.display.update() + + FPSClock.tick(FPS) + + +if __name__ == "__main__": + if "showevent" in sys.argv: + PRINT_EVENT = True + + main() diff --git a/venv/Lib/site-packages/pygame/examples/vgrade.py b/venv/Lib/site-packages/pygame/examples/vgrade.py new file mode 100644 index 0000000..9618c45 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/vgrade.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python +""" pg.examples.vgrade + +This example demonstrates creating an image with numpy +python, and displaying that through SDL. You can look at the +method of importing numpy and pg.surfarray. This method +will fail 'gracefully' if it is not available. +I've tried mixing in a lot of comments where the code might +not be self explanatory, nonetheless it may still seem a bit +strange. Learning to use numpy for images like this takes a +bit of learning, but the payoff is extremely fast image +manipulation in python. + +For Pygame 1.9.2 and up, this example also showcases a new feature +of surfarray.blit_surface: array broadcasting. If a source array +has either a width or height of 1, the array is repeatedly blitted +to the surface along that dimension to fill the surface. In fact, +a (1, 1) or (1, 1, 3) array results in a simple surface color fill. + +Just so you know how this breaks down. For each sampling of +time, 30% goes to each creating the gradient and blitting the +array. The final 40% goes to flipping/updating the display surface + +The window will have no border decorations. + +The code also demonstrates use of the timer events. +""" + + +import os +import pygame as pg + +try: + import numpy as np + import numpy.random as np_random +except ImportError: + raise SystemExit("This example requires numpy and the pygame surfarray module") + +timer = 0 + + +def stopwatch(message=None): + "simple routine to time python code" + global timer + if not message: + timer = pg.time.get_ticks() + return + now = pg.time.get_ticks() + runtime = (now - timer) / 1000.0 + 0.001 + print("%s %s %s" % (message, runtime, ("seconds\t(%.2ffps)" % (1.0 / runtime)))) + timer = now + + +def VertGradientColumn(surf, topcolor, bottomcolor): + "creates a new 3d vertical gradient array" + topcolor = np.array(topcolor, copy=False) + bottomcolor = np.array(bottomcolor, copy=False) + diff = bottomcolor - topcolor + width, height = surf.get_size() + # create array from 0.0 to 1.0 triplets + column = np.arange(height, dtype="float") / height + column = np.repeat(column[:, np.newaxis], [3], 1) + # create a single column of gradient + column = topcolor + (diff * column).astype("int") + # make the column a 3d image column by adding X + column = column.astype("uint8")[np.newaxis, :, :] + # 3d array into 2d array + return pg.surfarray.map_array(surf, column) + + +def DisplayGradient(surf): + "choose random colors and show them" + stopwatch() + colors = np_random.randint(0, 255, (2, 3)) + column = VertGradientColumn(surf, colors[0], colors[1]) + pg.surfarray.blit_array(surf, column) + pg.display.flip() + stopwatch("Gradient:") + + +def main(): + pg.init() + pg.mixer.quit() # remove ALSA underflow messages for Debian squeeze + size = 600, 400 + os.environ["SDL_VIDEO_CENTERED"] = "1" + screen = pg.display.set_mode(size, pg.NOFRAME, 0) + + pg.event.set_blocked(pg.MOUSEMOTION) # keep our queue cleaner + pg.time.set_timer(pg.USEREVENT, 500) + + while 1: + event = pg.event.wait() + if event.type in (pg.QUIT, pg.KEYDOWN, pg.MOUSEBUTTONDOWN): + break + elif event.type == pg.USEREVENT: + DisplayGradient(screen) + + pg.quit() + + +if __name__ == "__main__": + main() diff --git a/venv/Lib/site-packages/pygame/examples/video.py b/venv/Lib/site-packages/pygame/examples/video.py new file mode 100644 index 0000000..3d4b9f1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/examples/video.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python +""" pg.examples.video + +Experimental! + +* dialog message boxes with messagebox. +* multiple windows with Window +* driver selection +* Renderer, Texture, and Image classes +* Drawing lines, rects, and such onto Renderers. +""" +import os +import pygame as pg + +if pg.get_sdl_version()[0] < 2: + raise SystemExit( + "This example requires pygame 2 and SDL2. _sdl2 is experimental and will change." + ) +from pygame._sdl2 import Window, Texture, Image, Renderer, get_drivers, messagebox + +data_dir = os.path.join(os.path.split(os.path.abspath(__file__))[0], "data") + + +def load_img(file): + return pg.image.load(os.path.join(data_dir, file)) + + +pg.display.init() +pg.key.set_repeat(1000, 10) + +for driver in get_drivers(): + print(driver) + +import random + +answer = messagebox( + "I will open two windows! Continue?", + "Hello!", + info=True, + buttons=("Yes", "No", "Chance"), + return_button=0, + escape_button=1, +) +if answer == 1 or (answer == 2 and random.random() < 0.5): + import sys + + sys.exit(0) + +win = Window("asdf", resizable=True) +renderer = Renderer(win) +tex = Texture.from_surface(renderer, load_img("alien1.gif")) + +running = True + +x, y = 250, 50 +clock = pg.time.Clock() + +backgrounds = [(255, 0, 0, 255), (0, 255, 0, 255), (0, 0, 255, 255)] +bg_index = 0 + +renderer.draw_color = backgrounds[bg_index] + +win2 = Window("2nd window", size=(256, 256), always_on_top=True) +win2.opacity = 0.5 +win2.set_icon(load_img("bomb.gif")) +renderer2 = Renderer(win2) +tex2 = Texture.from_surface(renderer2, load_img("asprite.bmp")) +renderer2.clear() +tex2.draw() +renderer2.present() +del tex2 + +full = 0 + +tex = Image(tex) + + +surf = pg.Surface((64, 64)) +streamtex = Texture(renderer, (64, 64), streaming=True) +tex_update_interval = 1000 +next_tex_update = pg.time.get_ticks() + + +while running: + for event in pg.event.get(): + if event.type == pg.QUIT: + running = False + elif getattr(event, "window", None) == win2: + if ( + event.type == pg.KEYDOWN + and event.key == pg.K_ESCAPE + or event.type == pg.WINDOWCLOSE + ): + win2.destroy() + elif event.type == pg.KEYDOWN: + if event.key == pg.K_ESCAPE: + running = False + elif event.key == pg.K_LEFT: + x -= 5 + elif event.key == pg.K_RIGHT: + x += 5 + elif event.key == pg.K_DOWN: + y += 5 + elif event.key == pg.K_UP: + y -= 5 + elif event.key == pg.K_f: + if full == 0: + win.set_fullscreen(True) + full = 1 + else: + win.set_windowed() + full = 0 + elif event.key == pg.K_s: + readsurf = renderer.to_surface() + pg.image.save(readsurf, "test.png") + + elif event.key == pg.K_SPACE: + bg_index = (bg_index + 1) % len(backgrounds) + renderer.draw_color = backgrounds[bg_index] + + renderer.clear() + + # update texture + curtime = pg.time.get_ticks() + if curtime >= next_tex_update: + for x_ in range(streamtex.width // 4): + for y_ in range(streamtex.height // 4): + newcol = ( + random.randint(0, 255), + random.randint(0, 255), + random.randint(0, 255), + 255, + ) + area = (4 * x_, 4 * y_, 4, 4) + surf.fill(newcol, area) + streamtex.update(surf) + next_tex_update = curtime + tex_update_interval + streamtex.draw(dstrect=pg.Rect(64, 128, 64, 64)) + + tex.draw(dstrect=(x, y)) + + # TODO: should these be? + # - line instead of draw_line + # - point instead of draw_point + # - rect(rect, width=1)->draw 1 pixel, instead of draw_rect + # - rect(rect, width=0)->filled ? , instead of fill_rect + # + # TODO: should these work with pg.draw.line(renderer, ...) functions? + renderer.draw_color = (255, 255, 255, 255) + renderer.draw_line((0, 0), (64, 64)) + renderer.draw_line((64, 64), (128, 0)) + renderer.draw_point((72, 32)) + renderer.draw_rect(pg.Rect(0, 64, 64, 64)) + renderer.fill_rect(pg.Rect(0, 128, 64, 64)) + renderer.draw_color = backgrounds[bg_index] + + renderer.present() + + clock.tick(60) + win.title = str("FPS: {}".format(clock.get_fps())) + +pg.quit() diff --git a/venv/Lib/site-packages/pygame/fastevent.py b/venv/Lib/site-packages/pygame/fastevent.py new file mode 100644 index 0000000..e102fc4 --- /dev/null +++ b/venv/Lib/site-packages/pygame/fastevent.py @@ -0,0 +1,88 @@ +""" +A compatibility shim for pygame.fastevent based on pygame.event. +This module was deprecated in pygame 2.2, and is scheduled for removal in a +future pygame version. If you are using pygame.fastevent, please migrate to +using regular pygame.event module +""" + +import pygame.event +import pygame.display +from pygame import error, register_quit +from pygame.event import Event + +_ft_init = False + + +def _ft_init_check(): + """ + Raises error if module is not init + """ + if not _ft_init: + raise error("fastevent system not initialized") + + +def _quit_hook(): + """ + Hook that gets run to quit module + """ + global _ft_init + _ft_init = False + + +def init(): + """init() -> None + initialize pygame.fastevent + """ + global _ft_init + if not pygame.display.get_init(): + raise error("video system not initialized") + + register_quit(_quit_hook) + _ft_init = True + + +def get_init(): + """get_init() -> bool + returns True if the fastevent module is currently initialized + """ + return _ft_init + + +def pump(): + """pump() -> None + internally process pygame event handlers + """ + _ft_init_check() + pygame.event.pump() + + +def wait(): + """wait() -> Event + wait for an event + """ + _ft_init_check() + return pygame.event.wait() + + +def poll(): + """poll() -> Event + get an available event + """ + _ft_init_check() + return pygame.event.poll() + + +def get(): + """get() -> list of Events + get all events from the queue + """ + _ft_init_check() + return pygame.event.get() + + +def post(event: Event): + """post(Event) -> None + place an event on the queue + """ + _ft_init_check() + pygame.event.post(event) diff --git a/venv/Lib/site-packages/pygame/fastevent.pyi b/venv/Lib/site-packages/pygame/fastevent.pyi new file mode 100644 index 0000000..9ef2e26 --- /dev/null +++ b/venv/Lib/site-packages/pygame/fastevent.pyi @@ -0,0 +1,11 @@ +from typing import List + +from pygame.event import Event + +def init() -> None: ... +def get_init() -> bool: ... +def pump() -> None: ... +def wait() -> Event: ... +def pool() -> Event: ... +def get() -> List[Event]: ... +def post(event: Event) -> None: ... diff --git a/venv/Lib/site-packages/pygame/font.pyi b/venv/Lib/site-packages/pygame/font.pyi new file mode 100644 index 0000000..9002ed7 --- /dev/null +++ b/venv/Lib/site-packages/pygame/font.pyi @@ -0,0 +1,50 @@ +from typing import Hashable, Iterable, List, Optional, Tuple, Union + +from pygame.surface import Surface + +from ._common import _ColorValue, _FileArg + +def init() -> None: ... +def quit() -> None: ... +def get_init() -> bool: ... +def get_default_font() -> str: ... +def get_fonts() -> List[str]: ... +def match_font( + name: Union[str, bytes, Iterable[Union[str, bytes]]], + bold: Hashable = False, + italic: Hashable = False, +) -> str: ... +def SysFont( + name: Union[str, bytes, Iterable[Union[str, bytes]]], + size: int, + bold: Hashable = False, + italic: Hashable = False, +) -> Font: ... + +class Font(object): + + bold: bool + italic: bool + underline: bool + def __init__(self, name: Optional[_FileArg], size: int) -> None: ... + def render( + self, + text: Union[str, bytes], + antialias: bool, + color: _ColorValue, + background: Optional[_ColorValue] = None, + ) -> Surface: ... + def size(self, text: Union[str, bytes]) -> Tuple[int, int]: ... + def set_underline(self, value: bool) -> None: ... + def get_underline(self) -> bool: ... + def set_bold(self, value: bool) -> None: ... + def get_bold(self) -> bool: ... + def set_italic(self, value: bool) -> None: ... + def metrics( + self, text: Union[str, bytes] + ) -> List[Tuple[int, int, int, int, int]]: ... + def get_italic(self) -> bool: ... + def get_linesize(self) -> int: ... + def get_height(self) -> int: ... + def get_ascent(self) -> int: ... + def get_descent(self) -> int: ... diff --git a/venv/Lib/site-packages/pygame/freesansbold.ttf b/venv/Lib/site-packages/pygame/freesansbold.ttf new file mode 100644 index 0000000..a98562f Binary files /dev/null and b/venv/Lib/site-packages/pygame/freesansbold.ttf differ diff --git a/venv/Lib/site-packages/pygame/freetype.py b/venv/Lib/site-packages/pygame/freetype.py new file mode 100644 index 0000000..c1b5f59 --- /dev/null +++ b/venv/Lib/site-packages/pygame/freetype.py @@ -0,0 +1,78 @@ +"""Enhanced Pygame module for loading and rendering computer fonts""" + +from pygame._freetype import ( + Font, + STYLE_NORMAL, + STYLE_OBLIQUE, + STYLE_STRONG, + STYLE_UNDERLINE, + STYLE_WIDE, + STYLE_DEFAULT, + init, + quit, + get_init, + was_init, + get_cache_size, + get_default_font, + get_default_resolution, + get_error, + get_version, + set_default_resolution, +) +from pygame.sysfont import match_font, get_fonts, SysFont as _SysFont + +__all__ = [ + "Font", + "STYLE_NORMAL", + "STYLE_OBLIQUE", + "STYLE_STRONG", + "STYLE_UNDERLINE", + "STYLE_WIDE", + "STYLE_DEFAULT", + "init", + "quit", + "get_init", + "was_init", + "get_cache_size", + "get_default_font", + "get_default_resolution", + "get_error", + "get_version", + "set_default_resolution", + "match_font", + "get_fonts", +] + + +def SysFont(name, size, bold=0, italic=0, constructor=None): + """pygame.ftfont.SysFont(name, size, bold=False, italic=False, constructor=None) -> Font + Create a pygame Font from system font resources. + + This will search the system fonts for the given font + name. You can also enable bold or italic styles, and + the appropriate system font will be selected if available. + + This will always return a valid Font object, and will + fallback on the builtin pygame font if the given font + is not found. + + Name can also be an iterable of font names, a string of + comma-separated font names, or a bytes of comma-separated + font names, in which case the set of names will be searched + in order. Pygame uses a small set of common font aliases. If the + specific font you ask for is not available, a reasonable + alternative may be used. + + If optional constructor is provided, it must be a function with + signature constructor(fontpath, size, bold, italic) which returns + a Font instance. If None, a pygame.freetype.Font object is created. + """ + if constructor is None: + + def constructor(fontpath, size, bold, italic): + font = Font(fontpath, size) + font.strong = bold + font.oblique = italic + return font + + return _SysFont(name, size, bold, italic, constructor) diff --git a/venv/Lib/site-packages/pygame/freetype.pyi b/venv/Lib/site-packages/pygame/freetype.pyi new file mode 100644 index 0000000..dd77f55 --- /dev/null +++ b/venv/Lib/site-packages/pygame/freetype.pyi @@ -0,0 +1,122 @@ +from typing import Any, Iterable, List, Optional, Text, Tuple, Union + +from pygame.color import Color +from pygame.font import Font +from pygame.rect import Rect +from pygame.surface import Surface + +from ._common import _ColorValue, _FileArg, _CanBeRect + +def get_error() -> str: ... +def get_version() -> Tuple[int, int, int]: ... +def init(cache_size: int = 64, resolution: int = 72) -> None: ... +def quit() -> None: ... +def get_init() -> bool: ... +def was_init() -> bool: ... +def get_cache_size() -> int: ... +def get_default_resolution() -> int: ... +def set_default_resolution(resolution: int) -> None: ... +def SysFont( + name: Union[str, bytes, Iterable[Union[str, bytes]]], + size: int, + bold: int = False, + italic: int = False, +) -> Font: ... +def get_default_font() -> str: ... + +STYLE_NORMAL: int +STYLE_UNDERLINE: int +STYLE_OBLIQUE: int +STYLE_STRONG: int +STYLE_WIDE: int +STYLE_DEFAULT: int + +class Font: + name: str + path: Text + size: Union[float, Tuple[float, float]] + height: int + ascender: int + descender: int + style: int + underline: bool + strong: bool + oblique: bool + wide: bool + strength: float + underline_adjustment: float + fixed_width: bool + fixed_sizes: int + scalable: bool + use_bitmap_strikes: bool + antialiased: bool + kerning: bool + vertical: bool + rotation: int + fgcolor: Color + bgcolor: Color + origin: bool + pad: bool + ucs4: bool + resolution: int + def __init__( + self, + file: Optional[_FileArg], + size: float = 0, + font_index: int = 0, + resolution: int = 0, + ucs4: int = False, + ) -> None: ... + def get_rect( + self, + text: str, + style: int = STYLE_DEFAULT, + rotation: int = 0, + size: float = 0, + ) -> Rect: ... + def get_metrics( + self, text: str, size: float = 0 + ) -> List[Tuple[int, int, int, int, float, float]]: ... + def get_sized_ascender(self, size: float) -> int: ... + def get_sized_descender(self, size: float) -> int: ... + def get_sized_height(self, size: float) -> int: ... + def get_sized_glyph_height(self, size: float) -> int: ... + def get_sizes(self) -> List[Tuple[int, int, int, float, float]]: ... + def render( + self, + text: str, + fgcolor: Optional[_ColorValue] = None, + bgcolor: Optional[_ColorValue] = None, + style: int = STYLE_DEFAULT, + rotation: int = 0, + size: float = 0, + ) -> Tuple[Surface, Rect]: ... + def render_to( + self, + surf: Surface, + dest: _CanBeRect, + text: str, + fgcolor: Optional[_ColorValue] = None, + bgcolor: Optional[_ColorValue] = None, + style: int = STYLE_DEFAULT, + rotation: int = 0, + size: float = 0, + ) -> Rect: ... + def render_raw( + self, + text: str, + style: int = STYLE_DEFAULT, + rotation: int = 0, + size: float = 0, + invert: bool = False, + ) -> Tuple[bytes, Tuple[int, int]]: ... + def render_raw_to( + self, + array: Any, + text: str, + dest: Optional[_CanBeRect] = None, + style: int = STYLE_DEFAULT, + rotation: int = 0, + size: float = 0, + invert: bool = False, + ) -> Rect: ... diff --git a/venv/Lib/site-packages/pygame/ftfont.py b/venv/Lib/site-packages/pygame/ftfont.py new file mode 100644 index 0000000..e648ede --- /dev/null +++ b/venv/Lib/site-packages/pygame/ftfont.py @@ -0,0 +1,203 @@ +"""pygame module for loading and rendering fonts (freetype alternative)""" + +__all__ = [ + "Font", + "init", + "quit", + "get_default_font", + "get_init", + "SysFont", + "match_font", + "get_fonts", +] + +from pygame._freetype import init, Font as _Font, get_default_resolution +from pygame._freetype import quit, get_default_font, get_init as _get_init +from pygame._freetype import __PYGAMEinit__ +from pygame.sysfont import match_font, get_fonts, SysFont as _SysFont +from pygame import encode_file_path + + +class Font(_Font): + """Font(filename, size) -> Font + Font(object, size) -> Font + create a new Font object from a file (freetype alternative) + + This Font type differs from font.Font in that it can render glyphs + for Unicode code points in the supplementary planes (> 0xFFFF). + """ + + __encode_file_path = staticmethod(encode_file_path) + __get_default_resolution = staticmethod(get_default_resolution) + __default_font = encode_file_path(get_default_font()) + + __unull = "\x00" + __bnull = b"\x00" + + def __init__(self, file, size=-1): + size = max(size, 1) + if isinstance(file, str): + try: + bfile = self.__encode_file_path(file, ValueError) + except ValueError: + bfile = "" + else: + bfile = file + if isinstance(bfile, bytes) and bfile == self.__default_font: + file = None + if file is None: + resolution = int(self.__get_default_resolution() * 0.6875) + if resolution == 0: + resolution = 1 + else: + resolution = 0 + super(Font, self).__init__(file, size=size, resolution=resolution) + self.strength = 1.0 / 12.0 + self.kerning = False + self.origin = True + self.pad = True + self.ucs4 = True + self.underline_adjustment = 1.0 + + def render(self, text, antialias, color, background=None): + """render(text, antialias, color, background=None) -> Surface + draw text on a new Surface""" + + if text is None: + text = "" + if isinstance(text, str) and self.__unull in text: + raise ValueError("A null character was found in the text") + if isinstance(text, bytes) and self.__bnull in text: + raise ValueError("A null character was found in the text") + save_antialiased = ( + self.antialiased # pylint: disable = access-member-before-definition + ) + self.antialiased = bool(antialias) + try: + s, _ = super(Font, self).render(text, color, background) + return s + finally: + self.antialiased = save_antialiased + + def set_bold(self, value): + """set_bold(bool) -> None + enable fake rendering of bold text""" + + self.wide = bool(value) + + def get_bold(self): + """get_bold() -> bool + check if text will be rendered bold""" + + return self.wide + + bold = property(get_bold, set_bold) + + def set_italic(self, value): + """set_italic(bool) -> None + enable fake rendering of italic text""" + + self.oblique = bool(value) + + def get_italic(self): + """get_italic() -> bool + check if the text will be rendered italic""" + + return self.oblique + + italic = property(get_italic, set_italic) + + def set_underline(self, value): + """set_underline(bool) -> None + control if text is rendered with an underline""" + + self.underline = bool(value) + + def get_underline(self): + """set_bold(bool) -> None + enable fake rendering of bold text""" + + return self.underline + + def metrics(self, text): + """metrics(text) -> list + Gets the metrics for each character in the passed string.""" + + return self.get_metrics(text) + + def get_ascent(self): + """get_ascent() -> int + get the ascent of the font""" + + return self.get_sized_ascender() + + def get_descent(self): + """get_descent() -> int + get the descent of the font""" + + return self.get_sized_descender() + + def get_height(self): + """get_height() -> int + get the height of the font""" + + return self.get_sized_ascender() - self.get_sized_descender() + 1 + + def get_linesize(self): + """get_linesize() -> int + get the line space of the font text""" + + return self.get_sized_height() + + def size(self, text): + """size(text) -> (width, height) + determine the amount of space needed to render text""" + + return self.get_rect(text).size + + +FontType = Font + + +def get_init(): + """get_init() -> bool + true if the font module is initialized""" + + return _get_init() + + +def SysFont(name, size, bold=0, italic=0, constructor=None): + """pygame.ftfont.SysFont(name, size, bold=False, italic=False, constructor=None) -> Font + Create a pygame Font from system font resources. + + This will search the system fonts for the given font + name. You can also enable bold or italic styles, and + the appropriate system font will be selected if available. + + This will always return a valid Font object, and will + fallback on the builtin pygame font if the given font + is not found. + + Name can also be an iterable of font names, a string of + comma-separated font names, or a bytes of comma-separated + font names, in which case the set of names will be searched + in order. Pygame uses a small set of common font aliases. If the + specific font you ask for is not available, a reasonable + alternative may be used. + + If optional constructor is provided, it must be a function with + signature constructor(fontpath, size, bold, italic) which returns + a Font instance. If None, a pygame.ftfont.Font object is created. + """ + if constructor is None: + + def constructor(fontpath, size, bold, italic): + font = Font(fontpath, size) + font.set_bold(bold) + font.set_italic(italic) + return font + + return _SysFont(name, size, bold, italic, constructor) + + +del _Font, get_default_resolution, encode_file_path diff --git a/venv/Lib/site-packages/pygame/gfxdraw.pyi b/venv/Lib/site-packages/pygame/gfxdraw.pyi new file mode 100644 index 0000000..7da2d0f --- /dev/null +++ b/venv/Lib/site-packages/pygame/gfxdraw.pyi @@ -0,0 +1,91 @@ +from typing import Sequence + +from pygame.surface import Surface + +from ._common import _ColorValue, _Coordinate, _RectValue + +def pixel(surface: Surface, x: int, y: int, color: _ColorValue) -> None: ... +def hline(surface: Surface, x1: int, x2: int, y: int, color: _ColorValue) -> None: ... +def vline(surface: Surface, x: int, y1: int, y2: int, color: _ColorValue) -> None: ... +def line( + surface: Surface, x1: int, y1: int, x2: int, y2: int, color: _ColorValue +) -> None: ... +def rectangle(surface: Surface, rect: _RectValue, color: _ColorValue) -> None: ... +def box(surface: Surface, rect: _RectValue, color: _ColorValue) -> None: ... +def circle(surface: Surface, x: int, y: int, r: int, color: _ColorValue) -> None: ... +def aacircle(surface: Surface, x: int, y: int, r: int, color: _ColorValue) -> None: ... +def filled_circle( + surface: Surface, x: int, y: int, r: int, color: _ColorValue +) -> None: ... +def ellipse( + surface: Surface, x: int, y: int, rx: int, ry: int, color: _ColorValue +) -> None: ... +def aaellipse( + surface: Surface, x: int, y: int, rx: int, ry: int, color: _ColorValue +) -> None: ... +def filled_ellipse( + surface: Surface, x: int, y: int, rx: int, ry: int, color: _ColorValue +) -> None: ... +def arc( + surface: Surface, + x: int, + y: int, + r: int, + start_angle: int, + atp_angle: int, + color: _ColorValue, +) -> None: ... +def pie( + surface: Surface, + x: int, + y: int, + r: int, + start_angle: int, + atp_angle: int, + color: _ColorValue, +) -> None: ... +def trigon( + surface: Surface, + x1: int, + y1: int, + x2: int, + y2: int, + x3: int, + y3: int, + color: _ColorValue, +) -> None: ... +def aatrigon( + surface: Surface, + x1: int, + y1: int, + x2: int, + y2: int, + x3: int, + y3: int, + color: _ColorValue, +) -> None: ... +def filled_trigon( + surface: Surface, + x1: int, + y1: int, + x2: int, + y2: int, + x3: int, + y3: int, + color: _ColorValue, +) -> None: ... +def polygon( + surface: Surface, points: Sequence[_Coordinate], color: _ColorValue +) -> None: ... +def aapolygon( + surface: Surface, points: Sequence[_Coordinate], color: _ColorValue +) -> None: ... +def filled_polygon( + surface: Surface, points: Sequence[_Coordinate], color: _ColorValue +) -> None: ... +def textured_polygon( + surface: Surface, points: Sequence[_Coordinate], texture: Surface, tx: int, ty: int +) -> None: ... +def bezier( + surface: Surface, points: Sequence[_Coordinate], steps: int, color: _ColorValue +) -> None: ... diff --git a/venv/Lib/site-packages/pygame/image.pyi b/venv/Lib/site-packages/pygame/image.pyi new file mode 100644 index 0000000..b99a711 --- /dev/null +++ b/venv/Lib/site-packages/pygame/image.pyi @@ -0,0 +1,35 @@ +from typing import List, Literal, Tuple, Union + +from pygame.bufferproxy import BufferProxy +from pygame.surface import Surface + +from ._common import _FileArg + +_BufferStyle = Union[BufferProxy, bytes, bytearray, memoryview] +_to_string_format = Literal[ + "P", "RGB", "RGBX", "RGBA", "ARGB", "RGBA_PREMULT", "ARGB_PREMULT" +] +_from_buffer_format = Literal["P", "RGB", "BGR", "RGBX", "RGBA", "ARGB"] +_from_string_format = Literal["P", "RGB", "RGBX", "RGBA", "ARGB"] + +def load(filename: _FileArg, namehint: str = "") -> Surface: ... +def save(surface: Surface, filename: _FileArg, namehint: str = "") -> None: ... +def get_sdl_image_version() -> Union[None, Tuple[int, int, int]]: ... +def get_extended() -> bool: ... +def tostring( + surface: Surface, format: _to_string_format, flipped: bool = False +) -> str: ... +def fromstring( + string: str, + size: Union[List[int], Tuple[int, int]], + format: _from_string_format, + flipped: bool = False, +) -> Surface: ... +def frombuffer( + bytes: _BufferStyle, + size: Union[List[int], Tuple[int, int]], + format: _from_buffer_format, +) -> Surface: ... +def load_basic(filename: _FileArg) -> Surface: ... +def load_extended(filename: _FileArg, namehint: str = "") -> Surface: ... +def save_extended(surface: Surface, filename: _FileArg, namehint: str = "") -> None: ... diff --git a/venv/Lib/site-packages/pygame/joystick.pyi b/venv/Lib/site-packages/pygame/joystick.pyi new file mode 100644 index 0000000..9ca8532 --- /dev/null +++ b/venv/Lib/site-packages/pygame/joystick.pyi @@ -0,0 +1,29 @@ +from typing import Tuple + +def init() -> None: ... +def quit() -> None: ... +def get_init() -> bool: ... +def get_count() -> int: ... + +class Joystick(object): + def __init__(self, id: int) -> None: ... + def init(self) -> None: ... + def quit(self) -> None: ... + def get_init(self) -> bool: ... + def get_id(self) -> int: ... + def get_instance_id(self) -> int: ... + def get_guid(self) -> str: ... + def get_power_level(self) -> str: ... + def get_name(self) -> str: ... + def get_numaxes(self) -> int: ... + def get_axis(self, axis_number: int) -> float: ... + def get_numballs(self) -> int: ... + def get_ball(self, ball_number: int) -> Tuple[float, float]: ... + def get_numbuttons(self) -> int: ... + def get_button(self, button: int) -> bool: ... + def get_numhats(self) -> int: ... + def get_hat(self, hat_number: int) -> Tuple[float, float]: ... + def rumble( + self, low_frequency: float, high_frequency: float, duration: int + ) -> bool: ... + def stop_rumble(self) -> None: ... diff --git a/venv/Lib/site-packages/pygame/key.pyi b/venv/Lib/site-packages/pygame/key.pyi new file mode 100644 index 0000000..d93beec --- /dev/null +++ b/venv/Lib/site-packages/pygame/key.pyi @@ -0,0 +1,15 @@ +from typing import Sequence, Tuple + +from ._common import _RectValue + +def get_focused() -> bool: ... +def get_pressed() -> Sequence[bool]: ... +def get_mods() -> int: ... +def set_mods(mods: int) -> None: ... +def set_repeat(delay: int = 0, interval: int = 0) -> None: ... +def get_repeat() -> Tuple[int, int]: ... +def name(key: int) -> str: ... +def key_code(name: str) -> int: ... +def start_text_input() -> None: ... +def stop_text_input() -> None: ... +def set_text_input_rect(rect: _RectValue) -> None: ... diff --git a/venv/Lib/site-packages/pygame/libFLAC-8.dll b/venv/Lib/site-packages/pygame/libFLAC-8.dll new file mode 100644 index 0000000..71f2e19 Binary files /dev/null and b/venv/Lib/site-packages/pygame/libFLAC-8.dll differ diff --git a/venv/Lib/site-packages/pygame/libfreetype-6.dll b/venv/Lib/site-packages/pygame/libfreetype-6.dll new file mode 100644 index 0000000..16ef777 Binary files /dev/null and b/venv/Lib/site-packages/pygame/libfreetype-6.dll differ diff --git a/venv/Lib/site-packages/pygame/libjpeg-9.dll b/venv/Lib/site-packages/pygame/libjpeg-9.dll new file mode 100644 index 0000000..9a05528 Binary files /dev/null and b/venv/Lib/site-packages/pygame/libjpeg-9.dll differ diff --git a/venv/Lib/site-packages/pygame/libmodplug-1.dll b/venv/Lib/site-packages/pygame/libmodplug-1.dll new file mode 100644 index 0000000..7c05126 Binary files /dev/null and b/venv/Lib/site-packages/pygame/libmodplug-1.dll differ diff --git a/venv/Lib/site-packages/pygame/libmpg123-0.dll b/venv/Lib/site-packages/pygame/libmpg123-0.dll new file mode 100644 index 0000000..c7809b1 Binary files /dev/null and b/venv/Lib/site-packages/pygame/libmpg123-0.dll differ diff --git a/venv/Lib/site-packages/pygame/libogg-0.dll b/venv/Lib/site-packages/pygame/libogg-0.dll new file mode 100644 index 0000000..5133481 Binary files /dev/null and b/venv/Lib/site-packages/pygame/libogg-0.dll differ diff --git a/venv/Lib/site-packages/pygame/libopus-0.dll b/venv/Lib/site-packages/pygame/libopus-0.dll new file mode 100644 index 0000000..9ba6c38 Binary files /dev/null and b/venv/Lib/site-packages/pygame/libopus-0.dll differ diff --git a/venv/Lib/site-packages/pygame/libopusfile-0.dll b/venv/Lib/site-packages/pygame/libopusfile-0.dll new file mode 100644 index 0000000..97a88b6 Binary files /dev/null and b/venv/Lib/site-packages/pygame/libopusfile-0.dll differ diff --git a/venv/Lib/site-packages/pygame/libpng16-16.dll b/venv/Lib/site-packages/pygame/libpng16-16.dll new file mode 100644 index 0000000..709f724 Binary files /dev/null and b/venv/Lib/site-packages/pygame/libpng16-16.dll differ diff --git a/venv/Lib/site-packages/pygame/libtiff-5.dll b/venv/Lib/site-packages/pygame/libtiff-5.dll new file mode 100644 index 0000000..fc8a7c0 Binary files /dev/null and b/venv/Lib/site-packages/pygame/libtiff-5.dll differ diff --git a/venv/Lib/site-packages/pygame/libvorbis-0.dll b/venv/Lib/site-packages/pygame/libvorbis-0.dll new file mode 100644 index 0000000..f5ae1bf Binary files /dev/null and b/venv/Lib/site-packages/pygame/libvorbis-0.dll differ diff --git a/venv/Lib/site-packages/pygame/libvorbisfile-3.dll b/venv/Lib/site-packages/pygame/libvorbisfile-3.dll new file mode 100644 index 0000000..d078736 Binary files /dev/null and b/venv/Lib/site-packages/pygame/libvorbisfile-3.dll differ diff --git a/venv/Lib/site-packages/pygame/libwebp-7.dll b/venv/Lib/site-packages/pygame/libwebp-7.dll new file mode 100644 index 0000000..fad57b2 Binary files /dev/null and b/venv/Lib/site-packages/pygame/libwebp-7.dll differ diff --git a/venv/Lib/site-packages/pygame/locals.py b/venv/Lib/site-packages/pygame/locals.py new file mode 100644 index 0000000..66e6c24 --- /dev/null +++ b/venv/Lib/site-packages/pygame/locals.py @@ -0,0 +1,576 @@ +# pygame - Python Game Library +# Copyright (C) 2000-2003 Pete Shinners +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Pete Shinners +# pete@shinners.org + + +"""Set of functions from PyGame that are handy to have in +the local namespace for your module""" + +from pygame.constants import * # pylint: disable=wildcard-import; lgtm[py/polluting-import] +from pygame.rect import Rect +from pygame import color + +Color = color.Color + + +__all__ = [ + "Rect", + "Color", + "ACTIVEEVENT", + "ANYFORMAT", + "APPACTIVE", + "APPFOCUSMOUSE", + "APPINPUTFOCUS", + "ASYNCBLIT", + "AUDIODEVICEADDED", + "AUDIODEVICEREMOVED", + "AUDIO_ALLOW_ANY_CHANGE", + "AUDIO_ALLOW_CHANNELS_CHANGE", + "AUDIO_ALLOW_FORMAT_CHANGE", + "AUDIO_ALLOW_FREQUENCY_CHANGE", + "AUDIO_S16", + "AUDIO_S16LSB", + "AUDIO_S16MSB", + "AUDIO_S16SYS", + "AUDIO_S8", + "AUDIO_U16", + "AUDIO_U16LSB", + "AUDIO_U16MSB", + "AUDIO_U16SYS", + "AUDIO_U8", + "BIG_ENDIAN", + "BLENDMODE_ADD", + "BLENDMODE_BLEND", + "BLENDMODE_MOD", + "BLENDMODE_NONE", + "BLEND_ADD", + "BLEND_MAX", + "BLEND_MIN", + "BLEND_MULT", + "BLEND_PREMULTIPLIED", + "BLEND_ALPHA_SDL2", + "BLEND_RGBA_ADD", + "BLEND_RGBA_MAX", + "BLEND_RGBA_MIN", + "BLEND_RGBA_MULT", + "BLEND_RGBA_SUB", + "BLEND_RGB_ADD", + "BLEND_RGB_MAX", + "BLEND_RGB_MIN", + "BLEND_RGB_MULT", + "BLEND_RGB_SUB", + "BLEND_SUB", + "BUTTON_LEFT", + "BUTTON_MIDDLE", + "BUTTON_RIGHT", + "BUTTON_WHEELDOWN", + "BUTTON_WHEELUP", + "BUTTON_X1", + "BUTTON_X2", + "CONTROLLERAXISMOTION", + "CONTROLLERBUTTONDOWN", + "CONTROLLERBUTTONUP", + "CONTROLLERDEVICEADDED", + "CONTROLLERDEVICEREMAPPED", + "CONTROLLERDEVICEREMOVED", + "CONTROLLERTOUCHPADDOWN", + "CONTROLLERTOUCHPADMOTION", + "CONTROLLERTOUCHPADUP", + "CONTROLLER_AXIS_INVALID", + "CONTROLLER_AXIS_LEFTX", + "CONTROLLER_AXIS_LEFTY", + "CONTROLLER_AXIS_MAX", + "CONTROLLER_AXIS_RIGHTX", + "CONTROLLER_AXIS_RIGHTY", + "CONTROLLER_AXIS_TRIGGERLEFT", + "CONTROLLER_AXIS_TRIGGERRIGHT", + "CONTROLLER_BUTTON_A", + "CONTROLLER_BUTTON_B", + "CONTROLLER_BUTTON_BACK", + "CONTROLLER_BUTTON_DPAD_DOWN", + "CONTROLLER_BUTTON_DPAD_LEFT", + "CONTROLLER_BUTTON_DPAD_RIGHT", + "CONTROLLER_BUTTON_DPAD_UP", + "CONTROLLER_BUTTON_GUIDE", + "CONTROLLER_BUTTON_INVALID", + "CONTROLLER_BUTTON_LEFTSHOULDER", + "CONTROLLER_BUTTON_LEFTSTICK", + "CONTROLLER_BUTTON_MAX", + "CONTROLLER_BUTTON_RIGHTSHOULDER", + "CONTROLLER_BUTTON_RIGHTSTICK", + "CONTROLLER_BUTTON_START", + "CONTROLLER_BUTTON_X", + "CONTROLLER_BUTTON_Y", + "DOUBLEBUF", + "DROPBEGIN", + "DROPCOMPLETE", + "DROPFILE", + "DROPTEXT", + "FINGERDOWN", + "FINGERMOTION", + "FINGERUP", + "FULLSCREEN", + "GL_ACCELERATED_VISUAL", + "GL_ACCUM_ALPHA_SIZE", + "GL_ACCUM_BLUE_SIZE", + "GL_ACCUM_GREEN_SIZE", + "GL_ACCUM_RED_SIZE", + "GL_ALPHA_SIZE", + "GL_BLUE_SIZE", + "GL_BUFFER_SIZE", + "GL_CONTEXT_DEBUG_FLAG", + "GL_CONTEXT_FLAGS", + "GL_CONTEXT_FORWARD_COMPATIBLE_FLAG", + "GL_CONTEXT_MAJOR_VERSION", + "GL_CONTEXT_MINOR_VERSION", + "GL_CONTEXT_PROFILE_COMPATIBILITY", + "GL_CONTEXT_PROFILE_CORE", + "GL_CONTEXT_PROFILE_ES", + "GL_CONTEXT_PROFILE_MASK", + "GL_CONTEXT_RELEASE_BEHAVIOR", + "GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH", + "GL_CONTEXT_RELEASE_BEHAVIOR_NONE", + "GL_CONTEXT_RESET_ISOLATION_FLAG", + "GL_CONTEXT_ROBUST_ACCESS_FLAG", + "GL_DEPTH_SIZE", + "GL_DOUBLEBUFFER", + "GL_FRAMEBUFFER_SRGB_CAPABLE", + "GL_GREEN_SIZE", + "GL_MULTISAMPLEBUFFERS", + "GL_MULTISAMPLESAMPLES", + "GL_RED_SIZE", + "GL_SHARE_WITH_CURRENT_CONTEXT", + "GL_STENCIL_SIZE", + "GL_STEREO", + "GL_SWAP_CONTROL", + "HAT_CENTERED", + "HAT_DOWN", + "HAT_LEFT", + "HAT_LEFTDOWN", + "HAT_LEFTUP", + "HAT_RIGHT", + "HAT_RIGHTDOWN", + "HAT_RIGHTUP", + "HAT_UP", + "HIDDEN", + "HWACCEL", + "HWPALETTE", + "HWSURFACE", + "JOYAXISMOTION", + "JOYBALLMOTION", + "JOYBUTTONDOWN", + "JOYBUTTONUP", + "JOYHATMOTION", + "JOYDEVICEADDED", + "JOYDEVICEREMOVED", + "KEYDOWN", + "KEYUP", + "KMOD_ALT", + "KMOD_CAPS", + "KMOD_CTRL", + "KMOD_GUI", + "KMOD_LALT", + "KMOD_LCTRL", + "KMOD_LGUI", + "KMOD_LMETA", + "KMOD_LSHIFT", + "KMOD_META", + "KMOD_MODE", + "KMOD_NONE", + "KMOD_NUM", + "KMOD_RALT", + "KMOD_RCTRL", + "KMOD_RGUI", + "KMOD_RMETA", + "KMOD_RSHIFT", + "KMOD_SHIFT", + "KSCAN_0", + "KSCAN_1", + "KSCAN_2", + "KSCAN_3", + "KSCAN_4", + "KSCAN_5", + "KSCAN_6", + "KSCAN_7", + "KSCAN_8", + "KSCAN_9", + "KSCAN_A", + "KSCAN_APOSTROPHE", + "KSCAN_B", + "KSCAN_BACKSLASH", + "KSCAN_BACKSPACE", + "KSCAN_BREAK", + "KSCAN_C", + "KSCAN_CAPSLOCK", + "KSCAN_CLEAR", + "KSCAN_COMMA", + "KSCAN_CURRENCYSUBUNIT", + "KSCAN_CURRENCYUNIT", + "KSCAN_D", + "KSCAN_DELETE", + "KSCAN_DOWN", + "KSCAN_E", + "KSCAN_END", + "KSCAN_EQUALS", + "KSCAN_ESCAPE", + "KSCAN_EURO", + "KSCAN_F", + "KSCAN_F1", + "KSCAN_F10", + "KSCAN_F11", + "KSCAN_F12", + "KSCAN_F13", + "KSCAN_F14", + "KSCAN_F15", + "KSCAN_F2", + "KSCAN_F3", + "KSCAN_F4", + "KSCAN_F5", + "KSCAN_F6", + "KSCAN_F7", + "KSCAN_F8", + "KSCAN_F9", + "KSCAN_G", + "KSCAN_GRAVE", + "KSCAN_H", + "KSCAN_HELP", + "KSCAN_HOME", + "KSCAN_I", + "KSCAN_INSERT", + "KSCAN_INTERNATIONAL1", + "KSCAN_INTERNATIONAL2", + "KSCAN_INTERNATIONAL3", + "KSCAN_INTERNATIONAL4", + "KSCAN_INTERNATIONAL5", + "KSCAN_INTERNATIONAL6", + "KSCAN_INTERNATIONAL7", + "KSCAN_INTERNATIONAL8", + "KSCAN_INTERNATIONAL9", + "KSCAN_J", + "KSCAN_K", + "KSCAN_KP0", + "KSCAN_KP1", + "KSCAN_KP2", + "KSCAN_KP3", + "KSCAN_KP4", + "KSCAN_KP5", + "KSCAN_KP6", + "KSCAN_KP7", + "KSCAN_KP8", + "KSCAN_KP9", + "KSCAN_KP_0", + "KSCAN_KP_1", + "KSCAN_KP_2", + "KSCAN_KP_3", + "KSCAN_KP_4", + "KSCAN_KP_5", + "KSCAN_KP_6", + "KSCAN_KP_7", + "KSCAN_KP_8", + "KSCAN_KP_9", + "KSCAN_KP_DIVIDE", + "KSCAN_KP_ENTER", + "KSCAN_KP_EQUALS", + "KSCAN_KP_MINUS", + "KSCAN_KP_MULTIPLY", + "KSCAN_KP_PERIOD", + "KSCAN_KP_PLUS", + "KSCAN_L", + "KSCAN_LALT", + "KSCAN_LANG1", + "KSCAN_LANG2", + "KSCAN_LANG3", + "KSCAN_LANG4", + "KSCAN_LANG5", + "KSCAN_LANG6", + "KSCAN_LANG7", + "KSCAN_LANG8", + "KSCAN_LANG9", + "KSCAN_LCTRL", + "KSCAN_LEFT", + "KSCAN_LEFTBRACKET", + "KSCAN_LGUI", + "KSCAN_LMETA", + "KSCAN_LSHIFT", + "KSCAN_LSUPER", + "KSCAN_M", + "KSCAN_MENU", + "KSCAN_MINUS", + "KSCAN_MODE", + "KSCAN_N", + "KSCAN_NONUSBACKSLASH", + "KSCAN_NONUSHASH", + "KSCAN_NUMLOCK", + "KSCAN_NUMLOCKCLEAR", + "KSCAN_O", + "KSCAN_P", + "KSCAN_PAGEDOWN", + "KSCAN_PAGEUP", + "KSCAN_PAUSE", + "KSCAN_PERIOD", + "KSCAN_POWER", + "KSCAN_PRINT", + "KSCAN_PRINTSCREEN", + "KSCAN_Q", + "KSCAN_R", + "KSCAN_RALT", + "KSCAN_RCTRL", + "KSCAN_RETURN", + "KSCAN_RGUI", + "KSCAN_RIGHT", + "KSCAN_RIGHTBRACKET", + "KSCAN_RMETA", + "KSCAN_RSHIFT", + "KSCAN_RSUPER", + "KSCAN_S", + "KSCAN_SCROLLLOCK", + "KSCAN_SCROLLOCK", + "KSCAN_SEMICOLON", + "KSCAN_SLASH", + "KSCAN_SPACE", + "KSCAN_SYSREQ", + "KSCAN_T", + "KSCAN_TAB", + "KSCAN_U", + "KSCAN_UNKNOWN", + "KSCAN_UP", + "KSCAN_V", + "KSCAN_W", + "KSCAN_X", + "KSCAN_Y", + "KSCAN_Z", + "K_0", + "K_1", + "K_2", + "K_3", + "K_4", + "K_5", + "K_6", + "K_7", + "K_8", + "K_9", + "K_AC_BACK", + "K_AMPERSAND", + "K_ASTERISK", + "K_AT", + "K_BACKQUOTE", + "K_BACKSLASH", + "K_BACKSPACE", + "K_BREAK", + "K_CAPSLOCK", + "K_CARET", + "K_CLEAR", + "K_COLON", + "K_COMMA", + "K_CURRENCYSUBUNIT", + "K_CURRENCYUNIT", + "K_DELETE", + "K_DOLLAR", + "K_DOWN", + "K_END", + "K_EQUALS", + "K_ESCAPE", + "K_EURO", + "K_EXCLAIM", + "K_F1", + "K_F10", + "K_F11", + "K_F12", + "K_F13", + "K_F14", + "K_F15", + "K_F2", + "K_F3", + "K_F4", + "K_F5", + "K_F6", + "K_F7", + "K_F8", + "K_F9", + "K_GREATER", + "K_HASH", + "K_HELP", + "K_HOME", + "K_INSERT", + "K_KP0", + "K_KP1", + "K_KP2", + "K_KP3", + "K_KP4", + "K_KP5", + "K_KP6", + "K_KP7", + "K_KP8", + "K_KP9", + "K_KP_0", + "K_KP_1", + "K_KP_2", + "K_KP_3", + "K_KP_4", + "K_KP_5", + "K_KP_6", + "K_KP_7", + "K_KP_8", + "K_KP_9", + "K_KP_DIVIDE", + "K_KP_ENTER", + "K_KP_EQUALS", + "K_KP_MINUS", + "K_KP_MULTIPLY", + "K_KP_PERIOD", + "K_KP_PLUS", + "K_LALT", + "K_LCTRL", + "K_LEFT", + "K_LEFTBRACKET", + "K_LEFTPAREN", + "K_LESS", + "K_LGUI", + "K_LMETA", + "K_LSHIFT", + "K_LSUPER", + "K_MENU", + "K_MINUS", + "K_MODE", + "K_NUMLOCK", + "K_NUMLOCKCLEAR", + "K_PAGEDOWN", + "K_PAGEUP", + "K_PAUSE", + "K_PERCENT", + "K_PERIOD", + "K_PLUS", + "K_POWER", + "K_PRINT", + "K_PRINTSCREEN", + "K_QUESTION", + "K_QUOTE", + "K_QUOTEDBL", + "K_RALT", + "K_RCTRL", + "K_RETURN", + "K_RGUI", + "K_RIGHT", + "K_RIGHTBRACKET", + "K_RIGHTPAREN", + "K_RMETA", + "K_RSHIFT", + "K_RSUPER", + "K_SCROLLLOCK", + "K_SCROLLOCK", + "K_SEMICOLON", + "K_SLASH", + "K_SPACE", + "K_SYSREQ", + "K_TAB", + "K_UNDERSCORE", + "K_UNKNOWN", + "K_UP", + "K_a", + "K_b", + "K_c", + "K_d", + "K_e", + "K_f", + "K_g", + "K_h", + "K_i", + "K_j", + "K_k", + "K_l", + "K_m", + "K_n", + "K_o", + "K_p", + "K_q", + "K_r", + "K_s", + "K_t", + "K_u", + "K_v", + "K_w", + "K_x", + "K_y", + "K_z", + "LIL_ENDIAN", + "MIDIIN", + "MIDIOUT", + "MOUSEBUTTONDOWN", + "MOUSEBUTTONUP", + "MOUSEMOTION", + "MOUSEWHEEL", + "MULTIGESTURE", + "NOEVENT", + "NOFRAME", + "NUMEVENTS", + "OPENGL", + "OPENGLBLIT", + "PREALLOC", + "QUIT", + "RESIZABLE", + "RLEACCEL", + "RLEACCELOK", + "SCALED", + "SCRAP_BMP", + "SCRAP_CLIPBOARD", + "SCRAP_PBM", + "SCRAP_PPM", + "SCRAP_SELECTION", + "SCRAP_TEXT", + "SHOWN", + "SRCALPHA", + "SRCCOLORKEY", + "SWSURFACE", + "SYSTEM_CURSOR_ARROW", + "SYSTEM_CURSOR_CROSSHAIR", + "SYSTEM_CURSOR_HAND", + "SYSTEM_CURSOR_IBEAM", + "SYSTEM_CURSOR_NO", + "SYSTEM_CURSOR_SIZEALL", + "SYSTEM_CURSOR_SIZENESW", + "SYSTEM_CURSOR_SIZENS", + "SYSTEM_CURSOR_SIZENWSE", + "SYSTEM_CURSOR_SIZEWE", + "SYSTEM_CURSOR_WAIT", + "SYSTEM_CURSOR_WAITARROW", + "SYSWMEVENT", + "TEXTEDITING", + "TEXTINPUT", + "TIMER_RESOLUTION", + "USEREVENT", + "USEREVENT_DROPFILE", + "VIDEOEXPOSE", + "VIDEORESIZE", + "WINDOWSHOWN", + "WINDOWHIDDEN", + "WINDOWEXPOSED", + "WINDOWMOVED", + "WINDOWRESIZED", + "WINDOWSIZECHANGED", + "WINDOWMINIMIZED", + "WINDOWMAXIMIZED", + "WINDOWRESTORED", + "WINDOWENTER", + "WINDOWLEAVE", + "WINDOWFOCUSGAINED", + "WINDOWFOCUSLOST", + "WINDOWCLOSE", + "WINDOWTAKEFOCUS", + "WINDOWHITTEST", +] diff --git a/venv/Lib/site-packages/pygame/macosx.py b/venv/Lib/site-packages/pygame/macosx.py new file mode 100644 index 0000000..fca8e21 --- /dev/null +++ b/venv/Lib/site-packages/pygame/macosx.py @@ -0,0 +1,15 @@ +import platform +import os +import sys +from pygame.pkgdata import getResource +from pygame import sdlmain_osx + +__all__ = ["Video_AutoInit"] + + +def Video_AutoInit(): + """Called from the base.c just before display module is initialized.""" + if "Darwin" in platform.platform(): + if (os.getcwd() == "/") and len(sys.argv) > 1: + os.chdir(os.path.dirname(sys.argv[0])) + return True diff --git a/venv/Lib/site-packages/pygame/mask.pyi b/venv/Lib/site-packages/pygame/mask.pyi new file mode 100644 index 0000000..726d3bf --- /dev/null +++ b/venv/Lib/site-packages/pygame/mask.pyi @@ -0,0 +1,58 @@ +from typing import Any, List, Optional, Sequence, Tuple, TypeVar, Union + +from pygame.rect import Rect +from pygame.surface import Surface + +from ._common import _ColorValue, _Coordinate, _RectValue + +_Offset = TypeVar("_Offset", Tuple[int, int], Sequence[int]) + +def from_surface(surface: Surface, threshold: int = 127) -> Mask: ... +def from_threshold( + surface: Surface, + color: _ColorValue, + threshold: _ColorValue = (0, 0, 0, 255), + other_surface: Optional[Surface] = None, + palette_colors: int = 1, +) -> Mask: ... + +class Mask: + def __init__(self, size: _Coordinate, fill: bool = False) -> None: ... + def copy(self) -> Mask: ... + def get_size(self) -> Tuple[int, int]: ... + def get_rect(self, **kwargs: Any) -> Rect: ... # Dict type needs to be completed + def get_at(self, pos: _Coordinate) -> int: ... + def set_at(self, pos: _Coordinate, value: int = 1) -> None: ... + def overlap(self, other: Mask, offset: _Offset) -> Union[Tuple[int, int], None]: ... + def overlap_area(self, other: Mask, offset: _Coordinate) -> int: ... + def overlap_mask(self, other: Mask, offset: _Coordinate) -> Mask: ... + def fill(self) -> None: ... + def clear(self) -> None: ... + def invert(self) -> None: ... + def scale(self, size: _Coordinate) -> Mask: ... + def draw(self, other: Mask, offset: _Coordinate) -> None: ... + def erase(self, other: Mask, offset: _Coordinate) -> None: ... + def count(self) -> int: ... + def centroid(self) -> Tuple[int, int]: ... + def angle(self) -> float: ... + def outline(self, every: int = 1) -> List[Tuple[int, int]]: ... + def convolve( + self, + other: Mask, + output: Optional[Mask] = None, + offset: _Coordinate = (0, 0), + ) -> Mask: ... + def connected_component( + self, pos: Union[List[int], Tuple[int, int]] = ... + ) -> Mask: ... + def connected_components(self, minimum: int = 0) -> List[Mask]: ... + def get_bounding_rects(self) -> Rect: ... + def to_surface( + self, + surface: Optional[Surface] = None, + setsurface: Optional[Surface] = None, + unsetsurface: Optional[Surface] = None, + setcolor: _ColorValue = (255, 255, 255, 255), + unsetcolor: _ColorValue = (0, 0, 0, 255), + dest: Union[_RectValue, _Coordinate] = (0, 0), + ) -> Surface: ... diff --git a/venv/Lib/site-packages/pygame/math.pyi b/venv/Lib/site-packages/pygame/math.pyi new file mode 100644 index 0000000..594acf2 --- /dev/null +++ b/venv/Lib/site-packages/pygame/math.pyi @@ -0,0 +1,281 @@ +from typing import List, Sequence, Tuple, Union, overload + +class _VectorElementwiseProxy2: + def __add__( + self, other: Union[float, Vector2, _VectorElementwiseProxy2] + ) -> Vector2: ... + def __radd__( + self, other: Union[float, Vector2, _VectorElementwiseProxy2] + ) -> Vector2: ... + def __sub__( + self, other: Union[float, Vector2, _VectorElementwiseProxy2] + ) -> Vector2: ... + def __rsub__( + self, other: Union[float, Vector2, _VectorElementwiseProxy2] + ) -> Vector2: ... + def __mul__( + self, other: Union[float, Vector2, _VectorElementwiseProxy2] + ) -> Vector2: ... + def __rmul__( + self, other: Union[float, Vector2, _VectorElementwiseProxy2] + ) -> Vector2: ... + def __truediv__( + self, other: Union[float, Vector2, _VectorElementwiseProxy2] + ) -> Vector2: ... + def __rtruediv__( + self, other: Union[float, Vector2, _VectorElementwiseProxy2] + ) -> Vector2: ... + def __floordiv__( + self, other: Union[float, Vector2, _VectorElementwiseProxy2] + ) -> Vector2: ... + def __rfloordiv__( + self, other: Union[float, Vector2, _VectorElementwiseProxy2] + ) -> Vector2: ... + def __mod__( + self, other: Union[float, Vector2, _VectorElementwiseProxy2] + ) -> Vector2: ... + def __rmod__( + self, other: Union[float, Vector2, _VectorElementwiseProxy2] + ) -> Vector2: ... + def __pow__( + self, power: Union[float, Vector2, _VectorElementwiseProxy2] + ) -> Vector2: ... + def __rpow__( + self, power: Union[float, Vector2, _VectorElementwiseProxy2] + ) -> Vector2: ... + +class _VectorElementwiseProxy3: + def __add__( + self, other: Union[float, Vector3, _VectorElementwiseProxy3] + ) -> Vector3: ... + def __radd__( + self, other: Union[float, Vector3, _VectorElementwiseProxy3] + ) -> Vector3: ... + def __sub__( + self, other: Union[float, Vector3, _VectorElementwiseProxy3] + ) -> Vector3: ... + def __rsub__( + self, other: Union[float, Vector3, _VectorElementwiseProxy3] + ) -> Vector3: ... + def __mul__( + self, other: Union[float, Vector3, _VectorElementwiseProxy3] + ) -> Vector3: ... + def __rmul__( + self, other: Union[float, Vector3, _VectorElementwiseProxy3] + ) -> Vector3: ... + def __truediv__( + self, other: Union[float, Vector3, _VectorElementwiseProxy3] + ) -> Vector3: ... + def __rtruediv__( + self, other: Union[float, Vector3, _VectorElementwiseProxy3] + ) -> Vector3: ... + def __floordiv__( + self, other: Union[float, Vector3, _VectorElementwiseProxy3] + ) -> Vector3: ... + def __rfloordiv__( + self, other: Union[float, Vector3, _VectorElementwiseProxy3] + ) -> Vector3: ... + def __mod__( + self, other: Union[float, Vector3, _VectorElementwiseProxy3] + ) -> Vector3: ... + def __rmod__( + self, other: Union[float, Vector3, _VectorElementwiseProxy3] + ) -> Vector3: ... + def __pow__( + self, power: Union[float, Vector3, _VectorElementwiseProxy3] + ) -> Vector3: ... + def __rpow__( + self, power: Union[float, Vector3, _VectorElementwiseProxy3] + ) -> Vector3: ... + +class Vector2: + x: float + y: float + xx: Vector2 + xy: Vector2 + yx: Vector2 + yy: Vector2 + __hash__: None # type: ignore + @overload + def __init__( + self, + x: Union[float, Tuple[float, float], List[float], Vector2] = 0, + ) -> None: ... + @overload + def __init__(self, x: float, y: float) -> None: ... + def __setitem__(self, key: int, value: float) -> None: ... + @overload + def __getitem__(self, i: int) -> float: ... + @overload + def __getitem__(self, s: slice) -> List[float]: ... + def __add__(self, other: Vector2) -> Vector2: ... + def __sub__(self, other: Vector2) -> Vector2: ... + @overload + def __mul__(self, other: Vector2) -> float: ... + @overload + def __mul__(self, other: float) -> Vector2: ... + def __rmul__(self, other: float) -> Vector2: ... + def __truediv__(self, other: float) -> Vector2: ... + def __floordiv__(self, other: float) -> Vector2: ... + def __neg__(self) -> Vector2: ... + def __pos__(self) -> Vector2: ... + def __bool__(self) -> bool: ... + def __iadd__(self, other: Vector2) -> Vector2: ... + def __isub__(self, other: Vector2) -> Vector2: ... + @overload + def __imul__(self, other: Vector2) -> float: ... + @overload + def __imul__(self, other: float) -> Vector2: ... + def dot(self, other: Vector2) -> float: ... + def cross(self, other: Vector2) -> Vector2: ... + def magnitude(self) -> float: ... + def magnitude_squared(self) -> float: ... + def length(self) -> float: ... + def length_squared(self) -> float: ... + def normalize(self) -> Vector2: ... + def normalize_ip(self) -> None: ... + def is_normalized(self) -> bool: ... + def scale_to_length(self, value: float) -> None: ... + def reflect(self, other: Vector2) -> Vector2: ... + def reflect_ip(self, other: Vector2) -> None: ... + def distance_to(self, other: Union[Vector2, Sequence[float]]) -> float: ... + def distance_squared_to(self, other: Vector2) -> float: ... + def lerp(self, other: Vector2, value: float) -> Vector2: ... + def slerp(self, other: Vector2, value: float) -> Vector2: ... + def elementwise(self) -> _VectorElementwiseProxy2: ... + def rotate(self, angle: float) -> Vector2: ... + def rotate_rad(self, angle: float) -> Vector2: ... + def rotate_ip(self, angle: float) -> None: ... + def rotate_rad_ip(self, angle: float) -> None: ... + def rotate_ip_rad(self, angle: float) -> None: ... + def angle_to(self, other: Vector2) -> float: ... + def as_polar(self) -> Tuple[float, float]: ... + def from_polar( + self, polar_value: Union[List[float], Tuple[float, float]] + ) -> None: ... + def copy(self) -> Vector2: ... + def update( + self, + x: Union[float, Vector2, Tuple[float, float], List[float]] = 0, + y: float = 0, + ) -> None: ... + +class Vector3: + x: float + y: float + z: float + xx: Vector2 + xy: Vector2 + xz: Vector2 + yx: Vector2 + yy: Vector2 + yz: Vector2 + zx: Vector2 + zy: Vector2 + zz: Vector2 + xxx: Vector3 + xxy: Vector3 + xxz: Vector3 + xyx: Vector3 + xyy: Vector3 + xyz: Vector3 + xzx: Vector3 + xzy: Vector3 + xzz: Vector3 + yxx: Vector3 + yxy: Vector3 + yxz: Vector3 + yyx: Vector3 + yyy: Vector3 + yyz: Vector3 + yzx: Vector3 + yzy: Vector3 + yzz: Vector3 + zxx: Vector3 + zxy: Vector3 + zxz: Vector3 + zyx: Vector3 + zyy: Vector3 + zyz: Vector3 + zzx: Vector3 + zzy: Vector3 + zzz: Vector3 + __hash__: None # type: ignore + @overload + def __init__( + self, + xyz: Union[float, Tuple[float, float, float], List[float], Vector3] = 0, + ) -> None: ... + @overload + def __init__(self, x: float, y: float, z: float) -> None: ... + def __setitem__(self, key: int, value: float) -> None: ... + @overload + def __getitem__(self, i: int) -> float: ... + @overload + def __getitem__(self, s: slice) -> List[float]: ... + def __add__(self, other: Vector3) -> Vector3: ... + def __sub__(self, other: Vector3) -> Vector3: ... + @overload + def __mul__(self, other: Vector3) -> float: ... + @overload + def __mul__(self, other: float) -> Vector3: ... + def __rmul__(self, other: float) -> Vector3: ... + def __truediv__(self, other: float) -> Vector3: ... + def __floordiv__(self, other: float) -> Vector3: ... + def __neg__(self) -> Vector3: ... + def __pos__(self) -> Vector3: ... + def __bool__(self) -> bool: ... + def __iadd__(self, other: Vector3) -> Vector3: ... + def __isub__(self, other: Vector3) -> Vector3: ... + @overload + def __imul__(self, other: Vector3) -> float: ... + @overload + def __imul__(self, other: float) -> Vector3: ... + def dot(self, other: Vector3) -> float: ... + def cross(self, other: Vector3) -> Vector3: ... + def magnitude(self) -> float: ... + def magnitude_squared(self) -> float: ... + def length(self) -> float: ... + def length_squared(self) -> float: ... + def normalize(self) -> Vector3: ... + def normalize_ip(self) -> None: ... + def is_normalized(self) -> bool: ... + def scale_to_length(self, value: float) -> None: ... + def reflect(self, other: Vector3) -> Vector3: ... + def reflect_ip(self, other: Vector3) -> None: ... + def distance_to(self, other: Vector3) -> float: ... + def distance_squared_to(self, other: Vector3) -> float: ... + def lerp(self, other: Vector3, value: float) -> Vector3: ... + def slerp(self, other: Vector3, value: float) -> Vector3: ... + def elementwise(self) -> _VectorElementwiseProxy3: ... + def rotate(self, angle: float, axis: Vector3) -> Vector3: ... + def rotate_rad(self, angle: float, axis: Vector3) -> Vector3: ... + def rotate_ip(self, angle: float, axis: Vector3) -> None: ... + def rotate_rad_ip(self, angle: float, axis: Vector3) -> None: ... + def rotate_ip_rad(self, angle: float, axis: Vector3) -> None: ... + def rotate_x(self, angle: float) -> Vector3: ... + def rotate_x_rad(self, angle: float) -> Vector3: ... + def rotate_x_ip(self, angle: float) -> None: ... + def rotate_x_rad_ip(self, angle: float) -> None: ... + def rotate_x_ip_rad(self, angle: float) -> None: ... + def rotate_y(self, angle: float) -> Vector3: ... + def rotate_y_rad(self, angle: float) -> Vector3: ... + def rotate_y_ip(self, angle: float) -> None: ... + def rotate_y_rad_ip(self, angle: float) -> None: ... + def rotate_y_ip_rad(self, angle: float) -> None: ... + def rotate_z(self, angle: float) -> Vector3: ... + def rotate_z_rad(self, angle: float) -> Vector3: ... + def rotate_z_ip(self, angle: float) -> None: ... + def rotate_z_rad_ip(self, angle: float) -> None: ... + def rotate_z_ip_rad(self, angle: float) -> None: ... + def angle_to(self, other: Vector3) -> float: ... + def as_spherical(self) -> Tuple[float, float, float]: ... + def from_spherical(self, spherical: Tuple[float, float, float]) -> None: ... + def copy(self) -> Vector3: ... + @overload + def update( + self, + xyz: Union[float, Tuple[float, float, float], List[float], Vector3] = 0, + ) -> None: ... + @overload + def update(self, x: int, y: int, z: int) -> None: ... diff --git a/venv/Lib/site-packages/pygame/midi.py b/venv/Lib/site-packages/pygame/midi.py new file mode 100644 index 0000000..bcf8d6b --- /dev/null +++ b/venv/Lib/site-packages/pygame/midi.py @@ -0,0 +1,718 @@ +"""pygame.midi +pygame module for interacting with midi input and output. + +The midi module can send output to midi devices, and get input +from midi devices. It can also list midi devices on the system. + +Including real midi devices, and virtual ones. + +It uses the portmidi library. Is portable to which ever platforms +portmidi supports (currently windows, OSX, and linux). + +This uses pyportmidi for now, but may use its own bindings at some +point in the future. The pyportmidi bindings are included with pygame. + +New in pygame 1.9.0. +""" + +# TODO: finish writing tests. +# - likely as interactive tests... so you'd need to plug in +# a midi device. +# TODO: create a background thread version for input threads. +# - that can automatically inject input into the event queue +# once the input object is running. Like joysticks. + +import math +import atexit + +import pygame +import pygame.locals + +import pygame.pypm as _pypm + +# For backward compatibility. +MIDIIN = pygame.locals.MIDIIN +MIDIOUT = pygame.locals.MIDIOUT + +__all__ = [ + "Input", + "MIDIIN", + "MIDIOUT", + "MidiException", + "Output", + "get_count", + "get_default_input_id", + "get_default_output_id", + "get_device_info", + "init", + "midis2events", + "quit", + "get_init", + "time", + "frequency_to_midi", + "midi_to_frequency", + "midi_to_ansi_note", +] + +__theclasses__ = ["Input", "Output"] + + +def _module_init(state=None): + # this is a sneaky dodge to store module level state in a non-public + # function. Helps us dodge using globals. + if state is not None: + _module_init.value = state + return state + + try: + _module_init.value + except AttributeError: + return False + else: + return _module_init.value + + +def init(): + """initialize the midi module + pygame.midi.init(): return None + + Call the initialisation function before using the midi module. + + It is safe to call this more than once. + """ + if not _module_init(): + _pypm.Initialize() + _module_init(True) + atexit.register(quit) + + +def quit(): # pylint: disable=redefined-builtin + """uninitialize the midi module + pygame.midi.quit(): return None + + + Called automatically atexit if you don't call it. + + It is safe to call this function more than once. + """ + if _module_init(): + # TODO: find all Input and Output classes and close them first? + _pypm.Terminate() + _module_init(False) + + +def get_init(): + """returns True if the midi module is currently initialized + pygame.midi.get_init(): return bool + + Returns True if the pygame.midi module is currently initialized. + + New in pygame 1.9.5. + """ + return _module_init() + + +def _check_init(): + if not _module_init(): + raise RuntimeError("pygame.midi not initialised.") + + +def get_count(): + """gets the number of devices. + pygame.midi.get_count(): return num_devices + + + Device ids range from 0 to get_count() -1 + """ + _check_init() + return _pypm.CountDevices() + + +def get_default_input_id(): + """gets default input device number + pygame.midi.get_default_input_id(): return default_id + + + Return the default device ID or -1 if there are no devices. + The result can be passed to the Input()/Output() class. + + On the PC, the user can specify a default device by + setting an environment variable. For example, to use device #1. + + set PM_RECOMMENDED_INPUT_DEVICE=1 + + The user should first determine the available device ID by using + the supplied application "testin" or "testout". + + In general, the registry is a better place for this kind of info, + and with USB devices that can come and go, using integers is not + very reliable for device identification. Under Windows, if + PM_RECOMMENDED_OUTPUT_DEVICE (or PM_RECOMMENDED_INPUT_DEVICE) is + *NOT* found in the environment, then the default device is obtained + by looking for a string in the registry under: + HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Input_Device + and HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Output_Device + for a string. The number of the first device with a substring that + matches the string exactly is returned. For example, if the string + in the registry is "USB", and device 1 is named + "In USB MidiSport 1x1", then that will be the default + input because it contains the string "USB". + + In addition to the name, get_device_info() returns "interf", which + is the interface name. (The "interface" is the underlying software + system or API used by PortMidi to access devices. Examples are + MMSystem, DirectX (not implemented), ALSA, OSS (not implemented), etc.) + At present, the only Win32 interface is "MMSystem", the only Linux + interface is "ALSA", and the only Max OS X interface is "CoreMIDI". + To specify both the interface and the device name in the registry, + separate the two with a comma and a space, e.g.: + MMSystem, In USB MidiSport 1x1 + In this case, the string before the comma must be a substring of + the "interf" string, and the string after the space must be a + substring of the "name" name string in order to match the device. + + Note: in the current release, the default is simply the first device + (the input or output device with the lowest PmDeviceID). + """ + _check_init() + return _pypm.GetDefaultInputDeviceID() + + +def get_default_output_id(): + """gets default output device number + pygame.midi.get_default_output_id(): return default_id + + + Return the default device ID or -1 if there are no devices. + The result can be passed to the Input()/Output() class. + + On the PC, the user can specify a default device by + setting an environment variable. For example, to use device #1. + + set PM_RECOMMENDED_OUTPUT_DEVICE=1 + + The user should first determine the available device ID by using + the supplied application "testin" or "testout". + + In general, the registry is a better place for this kind of info, + and with USB devices that can come and go, using integers is not + very reliable for device identification. Under Windows, if + PM_RECOMMENDED_OUTPUT_DEVICE (or PM_RECOMMENDED_INPUT_DEVICE) is + *NOT* found in the environment, then the default device is obtained + by looking for a string in the registry under: + HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Input_Device + and HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Output_Device + for a string. The number of the first device with a substring that + matches the string exactly is returned. For example, if the string + in the registry is "USB", and device 1 is named + "In USB MidiSport 1x1", then that will be the default + input because it contains the string "USB". + + In addition to the name, get_device_info() returns "interf", which + is the interface name. (The "interface" is the underlying software + system or API used by PortMidi to access devices. Examples are + MMSystem, DirectX (not implemented), ALSA, OSS (not implemented), etc.) + At present, the only Win32 interface is "MMSystem", the only Linux + interface is "ALSA", and the only Max OS X interface is "CoreMIDI". + To specify both the interface and the device name in the registry, + separate the two with a comma and a space, e.g.: + MMSystem, In USB MidiSport 1x1 + In this case, the string before the comma must be a substring of + the "interf" string, and the string after the space must be a + substring of the "name" name string in order to match the device. + + Note: in the current release, the default is simply the first device + (the input or output device with the lowest PmDeviceID). + """ + _check_init() + return _pypm.GetDefaultOutputDeviceID() + + +def get_device_info(an_id): + """returns information about a midi device + pygame.midi.get_device_info(an_id): return (interf, name, + input, output, + opened) + + interf - a text string describing the device interface, eg 'ALSA'. + name - a text string for the name of the device, eg 'Midi Through Port-0' + input - 0, or 1 if the device is an input device. + output - 0, or 1 if the device is an output device. + opened - 0, or 1 if the device is opened. + + If the id is out of range, the function returns None. + """ + _check_init() + return _pypm.GetDeviceInfo(an_id) + + +class Input(object): + """Input is used to get midi input from midi devices. + Input(device_id) + Input(device_id, buffer_size) + + buffer_size - the number of input events to be buffered waiting to + be read using Input.read() + """ + + def __init__(self, device_id, buffer_size=4096): + """ + The buffer_size specifies the number of input events to be buffered + waiting to be read using Input.read(). + """ + _check_init() + + if device_id == -1: + raise MidiException( + "Device id is -1, not a valid output id. " + "-1 usually means there were no default " + "Output devices." + ) + + try: + result = get_device_info(device_id) + except TypeError: + raise TypeError("an integer is required") + except OverflowError: + raise OverflowError("long int too large to convert to int") + + # and now some nasty looking error checking, to provide nice error + # messages to the kind, lovely, midi using people of wherever. + if result: + _, _, is_input, is_output, _ = result + if is_input: + try: + self._input = _pypm.Input(device_id, buffer_size) + except TypeError: + raise TypeError("an integer is required") + self.device_id = device_id + + elif is_output: + raise MidiException( + "Device id given is not a valid" " input id, it is an output id." + ) + else: + raise MidiException("Device id given is not a valid input id.") + else: + raise MidiException("Device id invalid, out of range.") + + def _check_open(self): + if self._input is None: + raise MidiException("midi not open.") + + def close(self): + """closes a midi stream, flushing any pending buffers. + Input.close(): return None + + PortMidi attempts to close open streams when the application + exits -- this is particularly difficult under Windows. + """ + _check_init() + if self._input is not None: + self._input.Close() + self._input = None + + def read(self, num_events): + """reads num_events midi events from the buffer. + Input.read(num_events): return midi_event_list + + Reads from the Input buffer and gives back midi events. + [[[status,data1,data2,data3],timestamp], + [[status,data1,data2,data3],timestamp],...] + """ + _check_init() + self._check_open() + return self._input.Read(num_events) + + def poll(self): + """returns true if there's data, or false if not. + Input.poll(): return Bool + + raises a MidiException on error. + """ + _check_init() + self._check_open() + + result = self._input.Poll() + if result == _pypm.TRUE: + return True + + if result == _pypm.FALSE: + return False + + err_text = _pypm.GetErrorText(result) + raise MidiException((result, err_text)) + + +class Output(object): + """Output is used to send midi to an output device + Output(device_id) + Output(device_id, latency = 0) + Output(device_id, buffer_size = 4096) + Output(device_id, latency, buffer_size) + + The buffer_size specifies the number of output events to be + buffered waiting for output. (In some cases -- see below -- + PortMidi does not buffer output at all and merely passes data + to a lower-level API, in which case buffersize is ignored.) + + latency is the delay in milliseconds applied to timestamps to determine + when the output should actually occur. (If latency is < 0, 0 is + assumed.) + + If latency is zero, timestamps are ignored and all output is delivered + immediately. If latency is greater than zero, output is delayed until + the message timestamp plus the latency. (NOTE: time is measured + relative to the time source indicated by time_proc. Timestamps are + absolute, not relative delays or offsets.) In some cases, PortMidi + can obtain better timing than your application by passing timestamps + along to the device driver or hardware. Latency may also help you + to synchronize midi data to audio data by matching midi latency to + the audio buffer latency. + + """ + + def __init__(self, device_id, latency=0, buffer_size=256): + """Output(device_id) + Output(device_id, latency = 0) + Output(device_id, buffer_size = 4096) + Output(device_id, latency, buffer_size) + + The buffer_size specifies the number of output events to be + buffered waiting for output. (In some cases -- see below -- + PortMidi does not buffer output at all and merely passes data + to a lower-level API, in which case buffersize is ignored.) + + latency is the delay in milliseconds applied to timestamps to determine + when the output should actually occur. (If latency is < 0, 0 is + assumed.) + + If latency is zero, timestamps are ignored and all output is delivered + immediately. If latency is greater than zero, output is delayed until + the message timestamp plus the latency. (NOTE: time is measured + relative to the time source indicated by time_proc. Timestamps are + absolute, not relative delays or offsets.) In some cases, PortMidi + can obtain better timing than your application by passing timestamps + along to the device driver or hardware. Latency may also help you + to synchronize midi data to audio data by matching midi latency to + the audio buffer latency. + """ + + _check_init() + self._aborted = 0 + + if device_id == -1: + raise MidiException( + "Device id is -1, not a valid output id." + " -1 usually means there were no default " + "Output devices." + ) + + try: + result = get_device_info(device_id) + except TypeError: + raise TypeError("an integer is required") + except OverflowError: + raise OverflowError("long int too large to convert to int") + + # and now some nasty looking error checking, to provide nice error + # messages to the kind, lovely, midi using people of wherever. + if result: + _, _, is_input, is_output, _ = result + if is_output: + try: + self._output = _pypm.Output(device_id, latency, buffer_size) + except TypeError: + raise TypeError("an integer is required") + self.device_id = device_id + + elif is_input: + raise MidiException( + "Device id given is not a valid output " "id, it is an input id." + ) + else: + raise MidiException("Device id given is not a" " valid output id.") + else: + raise MidiException("Device id invalid, out of range.") + + def _check_open(self): + if self._output is None: + raise MidiException("midi not open.") + + if self._aborted: + raise MidiException("midi aborted.") + + def close(self): + """closes a midi stream, flushing any pending buffers. + Output.close(): return None + + PortMidi attempts to close open streams when the application + exits -- this is particularly difficult under Windows. + """ + _check_init() + if self._output is not None: + self._output.Close() + self._output = None + + def abort(self): + """terminates outgoing messages immediately + Output.abort(): return None + + The caller should immediately close the output port; + this call may result in transmission of a partial midi message. + There is no abort for Midi input because the user can simply + ignore messages in the buffer and close an input device at + any time. + """ + + _check_init() + if self._output: + self._output.Abort() + self._aborted = 1 + + def write(self, data): + """writes a list of midi data to the Output + Output.write(data) + + writes series of MIDI information in the form of a list: + write([[[status <,data1><,data2><,data3>],timestamp], + [[status <,data1><,data2><,data3>],timestamp],...]) + fields are optional + example: choose program change 1 at time 20000 and + send note 65 with velocity 100 500 ms later. + write([[[0xc0,0,0],20000],[[0x90,60,100],20500]]) + notes: + 1. timestamps will be ignored if latency = 0. + 2. To get a note to play immediately, send MIDI info with + timestamp read from function Time. + 3. understanding optional data fields: + write([[[0xc0,0,0],20000]]) is equivalent to + write([[[0xc0],20000]]) + + Can send up to 1024 elements in your data list, otherwise an + IndexError exception is raised. + """ + _check_init() + self._check_open() + + self._output.Write(data) + + def write_short(self, status, data1=0, data2=0): + """write_short(status <, data1><, data2>) + Output.write_short(status) + Output.write_short(status, data1 = 0, data2 = 0) + + output MIDI information of 3 bytes or less. + data fields are optional + status byte could be: + 0xc0 = program change + 0x90 = note on + etc. + data bytes are optional and assumed 0 if omitted + example: note 65 on with velocity 100 + write_short(0x90,65,100) + """ + _check_init() + self._check_open() + self._output.WriteShort(status, data1, data2) + + def write_sys_ex(self, when, msg): + """writes a timestamped system-exclusive midi message. + Output.write_sys_ex(when, msg) + + msg - can be a *list* or a *string* + when - a timestamp in miliseconds + example: + (assuming o is an onput MIDI stream) + o.write_sys_ex(0,'\\xF0\\x7D\\x10\\x11\\x12\\x13\\xF7') + is equivalent to + o.write_sys_ex(pygame.midi.time(), + [0xF0,0x7D,0x10,0x11,0x12,0x13,0xF7]) + """ + _check_init() + self._check_open() + self._output.WriteSysEx(when, msg) + + def note_on(self, note, velocity, channel=0): + """turns a midi note on. Note must be off. + Output.note_on(note, velocity, channel=0) + + note is an integer from 0 to 127 + velocity is an integer from 0 to 127 + channel is an integer from 0 to 15 + + Turn a note on in the output stream. The note must already + be off for this to work correctly. + """ + if not 0 <= channel <= 15: + raise ValueError("Channel not between 0 and 15.") + + self.write_short(0x90 + channel, note, velocity) + + def note_off(self, note, velocity=0, channel=0): + """turns a midi note off. Note must be on. + Output.note_off(note, velocity=0, channel=0) + + note is an integer from 0 to 127 + velocity is an integer from 0 to 127 (release velocity) + channel is an integer from 0 to 15 + + Turn a note off in the output stream. The note must already + be on for this to work correctly. + """ + if not 0 <= channel <= 15: + raise ValueError("Channel not between 0 and 15.") + + self.write_short(0x80 + channel, note, velocity) + + def set_instrument(self, instrument_id, channel=0): + """select an instrument for a channel, with a value between 0 and 127 + Output.set_instrument(instrument_id, channel=0) + + Also called "patch change" or "program change". + """ + if not 0 <= instrument_id <= 127: + raise ValueError(f"Undefined instrument id: {instrument_id}") + + if not 0 <= channel <= 15: + raise ValueError("Channel not between 0 and 15.") + + self.write_short(0xC0 + channel, instrument_id) + + def pitch_bend(self, value=0, channel=0): + """modify the pitch of a channel. + Output.pitch_bend(value=0, channel=0) + + Adjust the pitch of a channel. The value is a signed integer + from -8192 to +8191. For example, 0 means "no change", +4096 is + typically a semitone higher, and -8192 is 1 whole tone lower (though + the musical range corresponding to the pitch bend range can also be + changed in some synthesizers). + + If no value is given, the pitch bend is returned to "no change". + """ + if not 0 <= channel <= 15: + raise ValueError("Channel not between 0 and 15.") + + if not -8192 <= value <= 8191: + raise ValueError( + f"Pitch bend value must be between -8192 and +8191, not {value}." + ) + + # "The 14 bit value of the pitch bend is defined so that a value of + # 0x2000 is the center corresponding to the normal pitch of the note + # (no pitch change)." so value=0 should send 0x2000 + value = value + 0x2000 + lsb = value & 0x7F # keep least 7 bits + msb = value >> 7 + self.write_short(0xE0 + channel, lsb, msb) + + +# MIDI commands +# +# 0x80 Note Off (note_off) +# 0x90 Note On (note_on) +# 0xA0 Aftertouch +# 0xB0 Continuous controller +# 0xC0 Patch change (set_instrument?) +# 0xD0 Channel Pressure +# 0xE0 Pitch bend +# 0xF0 (non-musical commands) + + +def time(): + """returns the current time in ms of the PortMidi timer + pygame.midi.time(): return time + + The time is reset to 0, when the module is inited. + """ + _check_init() + return _pypm.Time() + + +def midis2events(midis, device_id): + """converts midi events to pygame events + pygame.midi.midis2events(midis, device_id): return [Event, ...] + + Takes a sequence of midi events and returns list of pygame events. + """ + evs = [] + for midi in midis: + ((status, data1, data2, data3), timestamp) = midi + + event = pygame.event.Event( + MIDIIN, + status=status, + data1=data1, + data2=data2, + data3=data3, + timestamp=timestamp, + vice_id=device_id, + ) + evs.append(event) + + return evs + + +class MidiException(Exception): + """exception that pygame.midi functions and classes can raise + MidiException(errno) + """ + + def __init__(self, value): + super(MidiException, self).__init__(value) + self.parameter = value + + def __str__(self): + return repr(self.parameter) + + +def frequency_to_midi(frequency): + """converts a frequency into a MIDI note. + + Rounds to the closest midi note. + + ::Examples:: + + >>> frequency_to_midi(27.5) + 21 + >>> frequency_to_midi(36.7) + 26 + >>> frequency_to_midi(4186.0) + 108 + """ + return int(round(69 + (12 * math.log(frequency / 440.0)) / math.log(2))) + + +def midi_to_frequency(midi_note): + """Converts a midi note to a frequency. + + ::Examples:: + + >>> midi_to_frequency(21) + 27.5 + >>> midi_to_frequency(26) + 36.7 + >>> midi_to_frequency(108) + 4186.0 + """ + return round(440.0 * 2 ** ((midi_note - 69) * (1.0 / 12.0)), 1) + + +def midi_to_ansi_note(midi_note): + """returns the Ansi Note name for a midi number. + + ::Examples:: + + >>> midi_to_ansi_note(21) + 'A0' + >>> midi_to_ansi_note(102) + 'F#7' + >>> midi_to_ansi_note(108) + 'C8' + """ + notes = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"] + num_notes = 12 + note_name = notes[int(((midi_note - 21) % num_notes))] + note_number = (midi_note - 12) // num_notes + return f"{note_name}{note_number}" diff --git a/venv/Lib/site-packages/pygame/midi.pyi b/venv/Lib/site-packages/pygame/midi.pyi new file mode 100644 index 0000000..90cd4a6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/midi.pyi @@ -0,0 +1,49 @@ +from typing import List, Sequence, Tuple, Union + +from pygame.event import Event + +MIDIIN: int +MIDIOUT: int + +class MidiException(Exception): + def __init__(self, errno: str) -> None: ... + +def init() -> None: ... +def quit() -> None: ... +def get_init() -> bool: ... +def get_count() -> int: ... +def get_default_input_id() -> int: ... +def get_default_output_id() -> int: ... +def get_device_info(an_id: int) -> Tuple[str, str, int, int, int]: ... +def midis2events( + midi_events: Sequence[Sequence[Union[Sequence[int], int]]], device_id: int +) -> List[Event]: ... +def time() -> int: ... +def frequency_to_midi(frequency: float) -> int: ... +def midi_to_frequency(midi_note: int) -> float: ... +def midi_to_ansi_note(midi_note: int) -> str: ... + +class Input: + device_id: int + def __init__(self, device_id: int, buffer_size: int = 4096) -> None: ... + def close(self) -> None: ... + def pool(self) -> bool: ... + def read(self, num_events: int) -> List[List[Union[List[int], int]]]: ... + +class Output: + device_id: int + def __init__( + self, + device_id: int, + latency: int = 0, + buffersize: int = 4096, + ) -> None: ... + def abort(self) -> None: ... + def close(self) -> None: ... + def note_off(self, note: int, velocity: int = 0, channel: int = 0) -> None: ... + def note_on(self, note: int, velocity: int = 0, channel: int = 0) -> None: ... + def set_instrument(self, instrument_id: int, channel: int = 0) -> None: ... + def pitch_bend(self, value: int = 0, channel: int = 0) -> None: ... + def write(self, data: List[List[Union[List[int], int]]]) -> None: ... + def write_short(self, status: int, data1: int = 0, data2: int = 0) -> None: ... + def write_sys_ex(self, msg: Union[List[int], str], when: int) -> None: ... diff --git a/venv/Lib/site-packages/pygame/mixer.pyi b/venv/Lib/site-packages/pygame/mixer.pyi new file mode 100644 index 0000000..52681ad --- /dev/null +++ b/venv/Lib/site-packages/pygame/mixer.pyi @@ -0,0 +1,86 @@ +from typing import Any, Optional, Tuple, Union, overload + +import numpy + +from pygame.event import Event + +from . import music as music +from ._common import _FileArg + +def init( + frequency: int = 44100, + size: int = -16, + channels: int = 2, + buffer: int = 512, + devicename: Optional[str] = None, + allowedchanges: int = 5, +) -> None: ... +def pre_init( + frequency: int = 44100, + size: int = -16, + channels: int = 2, + buffer: int = 512, + devicename: Optional[str] = None, + allowedchanges: int = 5, +) -> None: ... +def quit() -> None: ... +def get_init() -> Tuple[int, int, int]: ... +def stop() -> None: ... +def pause() -> None: ... +def unpause() -> None: ... +def fadeout(time: int) -> None: ... +def set_num_channels(count: int) -> None: ... +def get_num_channels() -> int: ... +def set_reserved(count: int) -> int: ... +def find_channel(force: bool = False) -> Channel: ... +def get_busy() -> bool: ... +def get_sdl_mixer_version(linked: bool = True) -> Tuple[int, int, int]: ... + +class Sound: + @overload + def __init__(self, file: _FileArg) -> None: ... + @overload + def __init__( + self, buffer: Any + ) -> None: ... # Buffer protocol is still not implemented in typing + @overload + def __init__( + self, array: numpy.ndarray + ) -> None: ... # Buffer protocol is still not implemented in typing + def play( + self, + loops: int = 0, + maxtime: int = 0, + fade_ms: int = 0, + ) -> Channel: ... + def stop(self) -> None: ... + def fadeout(self, time: int) -> None: ... + def set_volume(self, value: float) -> None: ... + def get_volume(self) -> float: ... + def get_num_channels(self) -> int: ... + def get_length(self) -> float: ... + def get_raw(self) -> bytes: ... + +class Channel: + def __init__(self, id: int) -> None: ... + def play( + self, + sound: Sound, + loops: int = 0, + maxtime: int = 0, + fade_ms: int = 0, + ) -> None: ... + def stop(self) -> None: ... + def pause(self) -> None: ... + def unpause(self) -> None: ... + def fadeout(self, time: int) -> None: ... + @overload + def set_volume(self, value: float) -> None: ... + @overload + def set_volume(self, left: float, right: float) -> None: ... + def get_volume(self) -> float: ... + def get_busy(self) -> bool: ... + def get_sound(self) -> Sound: ... + def get_queue(self) -> Sound: ... + def set_endevent(self, type: Union[int, Event] = 0) -> None: ... + def get_endevent(self) -> int: ... diff --git a/venv/Lib/site-packages/pygame/mouse.pyi b/venv/Lib/site-packages/pygame/mouse.pyi new file mode 100644 index 0000000..84b77ed --- /dev/null +++ b/venv/Lib/site-packages/pygame/mouse.pyi @@ -0,0 +1,34 @@ +from typing import List, Sequence, Tuple, Union, overload + +from pygame.cursors import Cursor +from pygame.surface import Surface + +def get_pressed( + num_buttons: int = 3, +) -> Union[Tuple[bool, bool, bool], Tuple[bool, bool, bool, bool, bool]]: ... +def get_pos() -> Tuple[int, int]: ... +def get_rel() -> Tuple[int, int]: ... +@overload +def set_pos(pos: Union[List[float], Tuple[float, float]]) -> None: ... +@overload +def set_pos(x: float, y: float) -> None: ... +def set_visible(value: bool) -> int: ... +def get_visible() -> bool: ... +def get_focused() -> bool: ... +@overload +def set_cursor(cursor: Cursor) -> None: ... +@overload +def set_cursor(constant: int) -> None: ... +@overload +def set_cursor( + size: Union[Tuple[int, int], List[int]], + hotspot: Union[Tuple[int, int], List[int]], + xormasks: Sequence[int], + andmasks: Sequence[int], +) -> None: ... +@overload +def set_cursor( + hotspot: Union[Tuple[int, int], List[int]], surface: Surface +) -> None: ... +def get_cursor() -> Cursor: ... +def set_system_cursor(cursor: int) -> None: ... diff --git a/venv/Lib/site-packages/pygame/music.pyi b/venv/Lib/site-packages/pygame/music.pyi new file mode 100644 index 0000000..91a6f55 --- /dev/null +++ b/venv/Lib/site-packages/pygame/music.pyi @@ -0,0 +1,20 @@ +from typing import Optional + +from ._common import _FileArg + +def load(filename: _FileArg, namehint: Optional[str] = "") -> None: ... +def unload() -> None: ... +def play(loops: int = 0, start: float = 0.0, fade_ms: int = 0) -> None: ... +def rewind() -> None: ... +def stop() -> None: ... +def pause() -> None: ... +def unpause() -> None: ... +def fadeout(time: int) -> None: ... +def set_volume(volume: float) -> None: ... +def get_volume() -> float: ... +def get_busy() -> bool: ... +def set_pos(pos: float) -> None: ... +def get_pos() -> int: ... +def queue(filename: _FileArg, namehint: str = "", loops: int = 0) -> None: ... +def set_endevent(event_type: int) -> None: ... +def get_endevent() -> int: ... diff --git a/venv/Lib/site-packages/pygame/pixelarray.pyi b/venv/Lib/site-packages/pygame/pixelarray.pyi new file mode 100644 index 0000000..f5e61dd --- /dev/null +++ b/venv/Lib/site-packages/pygame/pixelarray.pyi @@ -0,0 +1,35 @@ +from typing import Sequence, Tuple + +from pygame.surface import Surface + +from ._common import _ColorValue + +class PixelArray: + surface: Surface + itemsize: int + ndim: int + shape: Tuple[int, ...] + strides: Tuple[int, ...] + def __init__(self, surface: Surface) -> None: ... + def make_surface(self) -> Surface: ... + def replace( + self, + color: _ColorValue, + repcolor: _ColorValue, + distance: float = 0, + weights: Sequence[float] = (0.299, 0.587, 0.114), + ) -> None: ... + def extract( + self, + color: _ColorValue, + distance: float = 0, + weights: Sequence[float] = (0.299, 0.587, 0.114), + ) -> PixelArray: ... + def compare( + self, + array: PixelArray, + distance: float = 0, + weights: Sequence[float] = (0.299, 0.587, 0.114), + ) -> PixelArray: ... + def transpose(self) -> PixelArray: ... + def close(self) -> PixelArray: ... diff --git a/venv/Lib/site-packages/pygame/pixelcopy.pyi b/venv/Lib/site-packages/pygame/pixelcopy.pyi new file mode 100644 index 0000000..3734ddf --- /dev/null +++ b/venv/Lib/site-packages/pygame/pixelcopy.pyi @@ -0,0 +1,19 @@ +import numpy +from typing_extensions import Literal + +from pygame.surface import Surface + +_kind = Literal["P", "p", "R", "r", "G", "g", "B", "b", "A", "a", "C", "c"] + +def surface_to_array( + array: numpy.ndarray, + surface: Surface, + kind: _kind = "P", + opaque: int = 255, + clear: int = 0, +) -> None: ... +def array_to_surface(surface: Surface, array: numpy.ndarray) -> None: ... +def map_to_array( + array1: numpy.ndarray, array2: numpy.ndarray, surface: Surface +) -> None: ... +def make_surface(array: numpy.ndarray) -> Surface: ... diff --git a/venv/Lib/site-packages/pygame/pkgdata.py b/venv/Lib/site-packages/pygame/pkgdata.py new file mode 100644 index 0000000..1d89028 --- /dev/null +++ b/venv/Lib/site-packages/pygame/pkgdata.py @@ -0,0 +1,79 @@ +""" +pkgdata is a simple, extensible way for a package to acquire data file +resources. + +The getResource function is equivalent to the standard idioms, such as +the following minimal implementation: + + import sys, os + + def getResource(identifier, pkgname=__name__): + pkgpath = os.path.dirname(sys.modules[pkgname].__file__) + path = os.path.join(pkgpath, identifier) + return file(os.path.normpath(path), mode='rb') + +When a __loader__ is present on the module given by __name__, it will defer +getResource to its get_data implementation and return it as a file-like +object (such as StringIO). +""" + +__all__ = ["getResource"] +import sys +import os + +from io import BytesIO + +try: + from pkg_resources import resource_stream, resource_exists +except ImportError: + + def resource_exists(_package_or_requirement, _resource_name): + """ + A stub for when we fail to import this function. + + :return: Always returns False + """ + return False + + def resource_stream(_package_of_requirement, _resource_name): + """ + A stub for when we fail to import this function. + + Always raises a NotImplementedError when called. + """ + raise NotImplementedError + + +def getResource(identifier, pkgname=__name__): + """ + Acquire a readable object for a given package name and identifier. + An IOError will be raised if the resource can not be found. + + For example: + mydata = getResource('mypkgdata.jpg').read() + + Note that the package name must be fully qualified, if given, such + that it would be found in sys.modules. + + In some cases, getResource will return a real file object. In that + case, it may be useful to use its name attribute to get the path + rather than use it as a file-like object. For example, you may + be handing data off to a C API. + """ + + # When pyinstaller (or similar tools) are used, resource_exists may raise + # NotImplemented error + try: + if resource_exists(pkgname, identifier): + return resource_stream(pkgname, identifier) + except NotImplementedError: + pass + + mod = sys.modules[pkgname] + path_to_file = getattr(mod, "__file__", None) + if path_to_file is None: + raise IOError(f"{repr(mod)} has no __file__!") + path = os.path.join(os.path.dirname(path_to_file), identifier) + + # pylint: disable=consider-using-with + return open(os.path.normpath(path), "rb") diff --git a/venv/Lib/site-packages/pygame/portmidi.dll b/venv/Lib/site-packages/pygame/portmidi.dll new file mode 100644 index 0000000..cc4361c Binary files /dev/null and b/venv/Lib/site-packages/pygame/portmidi.dll differ diff --git a/venv/Lib/site-packages/pygame/py.typed b/venv/Lib/site-packages/pygame/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/pygame/pygame.ico b/venv/Lib/site-packages/pygame/pygame.ico new file mode 100644 index 0000000..06f699e Binary files /dev/null and b/venv/Lib/site-packages/pygame/pygame.ico differ diff --git a/venv/Lib/site-packages/pygame/pygame_icon.bmp b/venv/Lib/site-packages/pygame/pygame_icon.bmp new file mode 100644 index 0000000..74aea77 Binary files /dev/null and b/venv/Lib/site-packages/pygame/pygame_icon.bmp differ diff --git a/venv/Lib/site-packages/pygame/pygame_icon.icns b/venv/Lib/site-packages/pygame/pygame_icon.icns new file mode 100644 index 0000000..44a67bb Binary files /dev/null and b/venv/Lib/site-packages/pygame/pygame_icon.icns differ diff --git a/venv/Lib/site-packages/pygame/pygame_icon_mac.bmp b/venv/Lib/site-packages/pygame/pygame_icon_mac.bmp new file mode 100644 index 0000000..7b58bb1 Binary files /dev/null and b/venv/Lib/site-packages/pygame/pygame_icon_mac.bmp differ diff --git a/venv/Lib/site-packages/pygame/rect.pyi b/venv/Lib/site-packages/pygame/rect.pyi new file mode 100644 index 0000000..c2d662c --- /dev/null +++ b/venv/Lib/site-packages/pygame/rect.pyi @@ -0,0 +1,229 @@ +from typing import Dict, List, Sequence, Tuple, TypeVar, Union, overload + +from pygame.math import Vector2 +from ._common import _Coordinate, _CanBeRect + +_K = TypeVar("_K") +_V = TypeVar("_V") + +class Rect(object): + x: int + y: int + top: int + left: int + bottom: int + right: int + topleft: Tuple[int, int] + bottomleft: Tuple[int, int] + topright: Tuple[int, int] + bottomright: Tuple[int, int] + midtop: Tuple[int, int] + midleft: Tuple[int, int] + midbottom: Tuple[int, int] + midright: Tuple[int, int] + center: Tuple[int, int] + centerx: int + centery: int + size: Tuple[int, int] + width: int + height: int + w: int + h: int + __hash__: None # type: ignore + @overload + def __init__( + self, left: float, top: float, width: float, height: float + ) -> None: ... + @overload + def __init__( + self, + left_top: Union[List[float], Tuple[float, float], Vector2], + width_height: Union[List[float], Tuple[float, float], Vector2], + ) -> None: ... + @overload + def __init__( + self, + left_top_width_height: Union[ + Rect, Tuple[float, float, float, float], List[float] + ], + ) -> None: ... + @overload + def __getitem__(self, i: int) -> int: ... + @overload + def __getitem__(self, s: slice) -> List[int]: ... + def copy(self) -> Rect: ... + @overload + def move(self, x: float, y: float) -> Rect: ... + @overload + def move(self, move_by: _Coordinate) -> Rect: ... + @overload + def move_ip(self, x: float, y: float) -> None: ... + @overload + def move_ip(self, move_by: _Coordinate) -> None: ... + @overload + def inflate(self, x: float, y: float) -> Rect: ... + @overload + def inflate(self, inflate_by: _Coordinate) -> Rect: ... + @overload + def inflate_ip(self, x: float, y: float) -> None: ... + @overload + def inflate_ip(self, inflate_by: _Coordinate) -> None: ... + @overload + def update(self, left: float, top: float, width: float, height: float) -> None: ... + @overload + def update( + self, + left_top: Union[List[float], Tuple[float, float], Vector2], + width_height: Union[List[float], Tuple[float, float], Vector2], + ) -> None: ... + @overload + def update( + self, + left_top_width_height: Union[ + Rect, Tuple[float, float, float, float], List[float] + ], + ) -> None: ... + @overload + def clamp(self, rect: Union[_CanBeRect, Rect]) -> Rect: ... + @overload + def clamp( + self, + left_top: Union[List[float], Tuple[float, float], Vector2], + width_height: Union[List[float], Tuple[float, float], Vector2], + ) -> Rect: ... + @overload + def clamp(self, left: float, top: float, width: float, height: float) -> Rect: ... + @overload + def clamp_ip(self, rect: Union[_CanBeRect, Rect]) -> None: ... + @overload + def clamp_ip( + self, + left_top: Union[List[float], Tuple[float, float], Vector2], + width_height: Union[List[float], Tuple[float, float], Vector2], + ) -> None: ... + @overload + def clamp_ip( + self, left: float, top: float, width: float, height: float + ) -> None: ... + @overload + def clip(self, rect: Union[_CanBeRect, Rect]) -> Rect: ... + @overload + def clip( + self, + left_top: Union[List[float], Tuple[float, float], Vector2], + width_height: Union[List[float], Tuple[float, float], Vector2], + ) -> Rect: ... + @overload + def clip(self, left: float, top: float, width: float, height: float) -> Rect: ... + @overload + def clipline( + self, x1: float, x2: float, x3: float, x4: float + ) -> Union[Tuple[Tuple[int, int], Tuple[int, int]], Tuple[()]]: ... + @overload + def clipline( + self, first_coordinate: _Coordinate, second_coordinate: _Coordinate + ) -> Union[Tuple[Tuple[int, int], Tuple[int, int]], Tuple[()]]: ... + @overload + def clipline( + self, values: Union[Tuple[float, float, float, float], List[float]] + ) -> Union[Tuple[Tuple[int, int], Tuple[int, int]], Tuple[()]]: ... + @overload + def clipline( + self, coordinates: Union[Tuple[_Coordinate, _Coordinate], List[_Coordinate]] + ) -> Union[Tuple[Tuple[int, int], Tuple[int, int]], Tuple[()]]: ... + @overload + def union(self, rect: Union[_CanBeRect, Rect]) -> Rect: ... + @overload + def union( + self, + left_top: Union[List[float], Tuple[float, float], Vector2], + width_height: Union[List[float], Tuple[float, float], Vector2], + ) -> Rect: ... + @overload + def union(self, left: float, top: float, width: float, height: float) -> Rect: ... + @overload + def union_ip(self, rect: Union[_CanBeRect, Rect]) -> None: ... + @overload + def union_ip( + self, + left_top: Union[List[float], Tuple[float, float], Vector2], + width_height: Union[List[float], Tuple[float, float], Vector2], + ) -> None: ... + @overload + def union_ip( + self, left: float, top: float, width: float, height: float + ) -> None: ... + def unionall(self, rect: Sequence[Union[_CanBeRect, Rect]]) -> Rect: ... + def unionall_ip(self, rect_sequence: Sequence[Union[_CanBeRect, Rect]]) -> None: ... + @overload + def fit(self, rect: Union[_CanBeRect, Rect]) -> Rect: ... + @overload + def fit( + self, + left_top: Union[List[float], Tuple[float, float], Vector2], + width_height: Union[List[float], Tuple[float, float], Vector2], + ) -> Rect: ... + @overload + def fit(self, left: float, top: float, width: float, height: float) -> Rect: ... + def normalize(self) -> None: ... + @overload + def __contains__(self, rect: Union[_CanBeRect, Rect, int]) -> bool: ... + @overload + def __contains__( + self, + left_top: Union[List[float], Tuple[float, float], Vector2], + width_height: Union[List[float], Tuple[float, float], Vector2], + ) -> bool: ... + @overload + def __contains__(self, left: float, top: float, width: float, height: float) -> bool: ... + @overload + def contains(self, rect: Union[_CanBeRect, Rect]) -> bool: ... + @overload + def contains( + self, + left_top: Union[List[float], Tuple[float, float], Vector2], + width_height: Union[List[float], Tuple[float, float], Vector2], + ) -> bool: ... + @overload + def contains( + self, left: float, top: float, width: float, height: float + ) -> bool: ... + @overload + def collidepoint(self, x: float, y: float) -> bool: ... + @overload + def collidepoint(self, x_y: Union[List[float], Tuple[float, float]]) -> bool: ... + @overload + def colliderect(self, rect: Union[_CanBeRect, Rect]) -> bool: ... + @overload + def colliderect( + self, + left_top: Union[List[float], Tuple[float, float], Vector2], + width_height: Union[List[float], Tuple[float, float], Vector2], + ) -> bool: ... + @overload + def colliderect( + self, left: float, top: float, width: float, height: float + ) -> bool: ... + def collidelist(self, rect_list: Sequence[Union[Rect, _CanBeRect]]) -> int: ... + def collidelistall( + self, rect_list: Sequence[Union[Rect, _CanBeRect]] + ) -> List[int]: ... + # Also undocumented: the dict collision methods take a 'values' argument + # that defaults to False. If it is False, the keys in rect_dict must be + # Rect-like; otherwise, the values must be Rects. + @overload + def collidedict( + self, rect_dict: Dict[_CanBeRect, _V], values: bool = ... + ) -> Tuple[_CanBeRect, _V]: ... + @overload + def collidedict( + self, rect_dict: Dict[_K, "Rect"], values: bool + ) -> Tuple[_K, "Rect"]: ... + @overload + def collidedictall( + self, rect_dict: Dict[_CanBeRect, _V], values: bool = ... + ) -> List[Tuple[_CanBeRect, _V]]: ... + @overload + def collidedictall( + self, rect_dict: Dict[_K, "Rect"], values: bool + ) -> List[Tuple[_K, "Rect"]]: ... diff --git a/venv/Lib/site-packages/pygame/scrap.pyi b/venv/Lib/site-packages/pygame/scrap.pyi new file mode 100644 index 0000000..7905ce6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/scrap.pyi @@ -0,0 +1,10 @@ +from typing import AnyStr, List + +def init() -> None: ... +def get_init() -> bool: ... +def get(data_type: str) -> AnyStr: ... +def get_types() -> List[str]: ... +def put(data_type: str, data: AnyStr) -> None: ... +def contains(data_type: str) -> bool: ... +def lost() -> bool: ... +def set_mode(mode: int) -> None: ... diff --git a/venv/Lib/site-packages/pygame/sndarray.py b/venv/Lib/site-packages/pygame/sndarray.py new file mode 100644 index 0000000..99ac4c7 --- /dev/null +++ b/venv/Lib/site-packages/pygame/sndarray.py @@ -0,0 +1,139 @@ +## pygame - Python Game Library +## Copyright (C) 2008 Marcus von Appen +## +## This library is free software; you can redistribute it and/or +## modify it under the terms of the GNU Library General Public +## License as published by the Free Software Foundation; either +## version 2 of the License, or (at your option) any later version. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## Library General Public License for more details. +## +## You should have received a copy of the GNU Library General Public +## License along with this library; if not, write to the Free +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +## +## Marcus von Appen +## mva@sysfault.org + +"""pygame module for accessing sound sample data + +Functions to convert between NumPy arrays and Sound objects. This module +will only be functional when pygame can use the external NumPy package. +If NumPy can't be imported, surfarray becomes a MissingModule object. + +Sound data is made of thousands of samples per second, and each sample +is the amplitude of the wave at a particular moment in time. For +example, in 22-kHz format, element number 5 of the array is the +amplitude of the wave after 5/22000 seconds. + +Each sample is an 8-bit or 16-bit integer, depending on the data format. +A stereo sound file has two values per sample, while a mono sound file +only has one. + +Sounds with 16-bit data will be treated as unsigned integers, +if the sound sample type requests this. +""" + +from pygame import mixer +import numpy + +import warnings + + +__all__ = [ + "array", + "samples", + "make_sound", + "use_arraytype", + "get_arraytype", + "get_arraytypes", +] + + +def array(sound): + """pygame.sndarray.array(Sound): return array + + Copy Sound samples into an array. + + Creates a new array for the sound data and copies the samples. The + array will always be in the format returned from + pygame.mixer.get_init(). + """ + + return numpy.array(sound, copy=True) + + +def samples(sound): + """pygame.sndarray.samples(Sound): return array + + Reference Sound samples into an array. + + Creates a new array that directly references the samples in a Sound + object. Modifying the array will change the Sound. The array will + always be in the format returned from pygame.mixer.get_init(). + """ + + return numpy.array(sound, copy=False) + + +def make_sound(array): + """pygame.sndarray.make_sound(array): return Sound + + Convert an array into a Sound object. + + Create a new playable Sound object from an array. The mixer module + must be initialized and the array format must be similar to the mixer + audio format. + """ + + return mixer.Sound(array=array) + + +def use_arraytype(arraytype): + """pygame.sndarray.use_arraytype(arraytype): return None + + DEPRECATED - only numpy arrays are now supported. + """ + warnings.warn( + DeprecationWarning( + "only numpy arrays are now supported, " + "this function will be removed in a " + "future version of the module" + ) + ) + arraytype = arraytype.lower() + if arraytype != "numpy": + raise ValueError("invalid array type") + + +def get_arraytype(): + """pygame.sndarray.get_arraytype(): return str + + DEPRECATED - only numpy arrays are now supported. + """ + warnings.warn( + DeprecationWarning( + "only numpy arrays are now supported, " + "this function will be removed in a " + "future version of the module" + ) + ) + return "numpy" + + +def get_arraytypes(): + """pygame.sndarray.get_arraytypes(): return tuple + + DEPRECATED - only numpy arrays are now supported. + """ + warnings.warn( + DeprecationWarning( + "only numpy arrays are now supported, " + "this function will be removed in a " + "future version of the module" + ) + ) + return ("numpy",) diff --git a/venv/Lib/site-packages/pygame/sndarray.pyi b/venv/Lib/site-packages/pygame/sndarray.pyi new file mode 100644 index 0000000..8b0dd65 --- /dev/null +++ b/venv/Lib/site-packages/pygame/sndarray.pyi @@ -0,0 +1,12 @@ +from typing import Tuple + +import numpy + +from pygame.mixer import Sound + +def array(sound: Sound) -> numpy.ndarray: ... +def samples(sound: Sound) -> numpy.ndarray: ... +def make_sound(array: numpy.ndarray) -> Sound: ... +def use_arraytype(arraytype: str) -> Sound: ... +def get_arraytype() -> str: ... +def get_arraytypes() -> Tuple[str]: ... diff --git a/venv/Lib/site-packages/pygame/sprite.py b/venv/Lib/site-packages/pygame/sprite.py new file mode 100644 index 0000000..553ccfb --- /dev/null +++ b/venv/Lib/site-packages/pygame/sprite.py @@ -0,0 +1,1782 @@ +# pygame - Python Game Library +# Copyright (C) 2000-2003, 2007 Pete Shinners +# (C) 2004 Joe Wreschnig +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Pete Shinners +# pete@shinners.org + +"""pygame module with basic game object classes + +This module contains several simple classes to be used within games. There +are the main Sprite class and several Group classes that contain Sprites. +The use of these classes is entirely optional when using Pygame. The classes +are fairly lightweight and only provide a starting place for the code +that is common to most games. + +The Sprite class is intended to be used as a base class for the different +types of objects in the game. There is also a base Group class that simply +stores sprites. A game could create new types of Group classes that operate +on specially customized Sprite instances they contain. + +The basic Sprite class can draw the Sprites it contains to a Surface. The +Group.draw() method requires that each Sprite have a Surface.image attribute +and a Surface.rect. The Group.clear() method requires these same attributes +and can be used to erase all the Sprites with background. There are also +more advanced Groups: pygame.sprite.RenderUpdates() and +pygame.sprite.OrderedUpdates(). + +Lastly, this module contains several collision functions. These help find +sprites inside multiple groups that have intersecting bounding rectangles. +To find the collisions, the Sprites are required to have a Surface.rect +attribute assigned. + +The groups are designed for high efficiency in removing and adding Sprites +to them. They also allow cheap testing to see if a Sprite already exists in +a Group. A given Sprite can exist in any number of groups. A game could use +some groups to control object rendering, and a completely separate set of +groups to control interaction or player movement. Instead of adding type +attributes or bools to a derived Sprite class, consider keeping the +Sprites inside organized Groups. This will allow for easier lookup later +in the game. + +Sprites and Groups manage their relationships with the add() and remove() +methods. These methods can accept a single or multiple group arguments for +membership. The default initializers for these classes also take a +single group or list of groups as arguments for initial membership. It is safe +to repeatedly add and remove the same Sprite from a Group. + +While it is possible to design sprite and group classes that don't derive +from the Sprite and AbstractGroup classes below, it is strongly recommended +that you extend those when you create a new Sprite or Group class. + +Sprites are not thread safe, so lock them yourself if using threads. + +""" + +# TODO: a group that holds only the 'n' most recent elements. +# sort of like the GroupSingle class, but holding more +# than one sprite +# +# drawing groups that can 'automatically' store the area +# underneath so they can "clear" without needing a background +# function. obviously a little slower than normal, but nice +# to use in many situations. (also remember it must "clear" +# in the reverse order that it draws :]) +# +# the drawing groups should also be able to take a background +# function, instead of just a background surface. the function +# would take a surface and a rectangle on that surface to erase. +# +# perhaps more types of collision functions? the current two +# should handle just about every need, but perhaps more optimized +# specific ones that aren't quite so general but fit into common +# specialized cases. + +from operator import truth +from warnings import warn + +import pygame + +from pygame.rect import Rect +from pygame.time import get_ticks +from pygame.mask import from_surface + + +class Sprite(object): + """simple base class for visible game objects + + pygame.sprite.Sprite(*groups): return Sprite + + The base class for visible game objects. Derived classes will want to + override the Sprite.update() method and assign Sprite.image and Sprite.rect + attributes. The initializer can accept any number of Group instances that + the Sprite will become a member of. + + When subclassing the Sprite class, be sure to call the base initializer + before adding the Sprite to Groups. + + """ + + def __init__(self, *groups): + self.__g = {} # The groups the sprite is in + if groups: + self.add(*groups) + + def add(self, *groups): + """add the sprite to groups + + Sprite.add(*groups): return None + + Any number of Group instances can be passed as arguments. The + Sprite will be added to the Groups it is not already a member of. + + """ + has = self.__g.__contains__ + for group in groups: + if hasattr(group, "_spritegroup"): + if not has(group): + group.add_internal(self) + self.add_internal(group) + else: + self.add(*group) + + def remove(self, *groups): + """remove the sprite from groups + + Sprite.remove(*groups): return None + + Any number of Group instances can be passed as arguments. The Sprite + will be removed from the Groups it is currently a member of. + + """ + has = self.__g.__contains__ + for group in groups: + if hasattr(group, "_spritegroup"): + if has(group): + group.remove_internal(self) + self.remove_internal(group) + else: + self.remove(*group) + + def add_internal(self, group): + """ + For adding this sprite to a group internally. + + :param group: The group we are adding to. + """ + self.__g[group] = 0 + + def remove_internal(self, group): + """ + For removing this sprite from a group internally. + + :param group: The group we are removing from. + """ + del self.__g[group] + + def update(self, *args, **kwargs): + """method to control sprite behavior + + Sprite.update(*args, **kwargs): + + The default implementation of this method does nothing; it's just a + convenient "hook" that you can override. This method is called by + Group.update() with whatever arguments you give it. + + There is no need to use this method if not using the convenience + method by the same name in the Group class. + + """ + + def kill(self): + """remove the Sprite from all Groups + + Sprite.kill(): return None + + The Sprite is removed from all the Groups that contain it. This won't + change anything about the state of the Sprite. It is possible to + continue to use the Sprite after this method has been called, including + adding it to Groups. + + """ + for group in self.__g: + group.remove_internal(self) + self.__g.clear() + + def groups(self): + """list of Groups that contain this Sprite + + Sprite.groups(): return group_list + + Returns a list of all the Groups that contain this Sprite. + + """ + return list(self.__g) + + def alive(self): + """does the sprite belong to any groups + + Sprite.alive(): return bool + + Returns True when the Sprite belongs to one or more Groups. + """ + return truth(self.__g) + + def __repr__(self): + return f"<{self.__class__.__name__} Sprite(in {len(self.__g)} groups)>" + + @property + def layer(self): + """ + Dynamic, read only property for protected _layer attribute. + This will get the _layer variable if it exists. + + If you try to get it before it is set it will raise an attribute error. + + Layer property can only be set before the sprite is added to a group, + after that it is read only and a sprite's layer in a group should be + set via the group's change_layer() method. + + :return: layer as an int, or raise AttributeError. + """ + return getattr(self, "_layer") + + @layer.setter + def layer(self, value): + if not self.alive(): + setattr(self, "_layer", value) + else: + raise AttributeError( + "Can't set layer directly after " + "adding to group. Use " + "group.change_layer(sprite, new_layer) " + "instead." + ) + + +class DirtySprite(Sprite): + """a more featureful subclass of Sprite with more attributes + + pygame.sprite.DirtySprite(*groups): return DirtySprite + + Extra DirtySprite attributes with their default values: + + dirty = 1 + If set to 1, it is repainted and then set to 0 again. + If set to 2, it is always dirty (repainted each frame; + flag is not reset). + If set to 0, it is not dirty and therefore not repainted again. + + blendmode = 0 + It's the special_flags argument of Surface.blit; see the blendmodes in + the Surface.blit documentation + + source_rect = None + This is the source rect to use. Remember that it is relative to the top + left corner (0, 0) of self.image. + + visible = 1 + Normally this is 1. If set to 0, it will not be repainted. (If you + change visible to 1, you must set dirty to 1 for it to be erased from + the screen.) + + _layer = 0 + 0 is the default value but this is able to be set differently + when subclassing. + + """ + + def __init__(self, *groups): + + self.dirty = 1 + + # referred to as special_flags in the documentation of Surface.blit + self.blendmode = 0 + self._visible = 1 + + # Default 0 unless initialized differently. + self._layer = getattr(self, "_layer", 0) + self.source_rect = None + Sprite.__init__(self, *groups) + + def _set_visible(self, val): + """set the visible value (0 or 1) and makes the sprite dirty""" + self._visible = val + if self.dirty < 2: + self.dirty = 1 + + def _get_visible(self): + """return the visible value of that sprite""" + return self._visible + + @property + def visible(self): + """ + You can make this sprite disappear without removing it from the group + assign 0 for invisible and 1 for visible + """ + return self._get_visible() + + @visible.setter + def visible(self, value): + self._set_visible(value) + + @property + def layer(self): + """ + Layer property can only be set before the sprite is added to a group, + after that it is read only and a sprite's layer in a group should be + set via the group's change_layer() method. + + Overwrites dynamic property from sprite class for speed. + """ + return self._layer + + @layer.setter + def layer(self, value): + if not self.alive(): + self._layer = value + else: + raise AttributeError( + "Can't set layer directly after " + "adding to group. Use " + "group.change_layer(sprite, new_layer) " + "instead." + ) + + def __repr__(self): + return ( + f"<{self.__class__.__name__} DirtySprite(in {len(self.groups())} groups)>" + ) + + +class AbstractGroup(object): + """base class for containers of sprites + + AbstractGroup does everything needed to behave as a normal group. You can + easily subclass a new group class from this or the other groups below if + you want to add more features. + + Any AbstractGroup-derived sprite groups act like sequences and support + iteration, len, and so on. + + """ + + # dummy val to identify sprite groups, and avoid infinite recursion + _spritegroup = True + + def __init__(self): + self.spritedict = {} + self.lostsprites = [] + + def sprites(self): + """get a list of sprites in the group + + Group.sprite(): return list + + Returns an object that can be looped over with a 'for' loop. (For now, + it is always a list, but this could change in a future version of + pygame.) Alternatively, you can get the same information by iterating + directly over the sprite group, e.g. 'for sprite in group'. + + """ + return list(self.spritedict) + + def add_internal( + self, + sprite, + layer=None, # noqa pylint: disable=unused-argument; supporting legacy derived classes that override in non-pythonic way + ): + """ + For adding a sprite to this group internally. + + :param sprite: The sprite we are adding. + :param layer: the layer to add to, if the group type supports layers + """ + self.spritedict[sprite] = None + + def remove_internal(self, sprite): + """ + For removing a sprite from this group internally. + + :param sprite: The sprite we are removing. + """ + lost_rect = self.spritedict[sprite] + if lost_rect: + self.lostsprites.append(lost_rect) + del self.spritedict[sprite] + + def has_internal(self, sprite): + """ + For checking if a sprite is in this group internally. + + :param sprite: The sprite we are checking. + """ + return sprite in self.spritedict + + def copy(self): + """copy a group with all the same sprites + + Group.copy(): return Group + + Returns a copy of the group that is an instance of the same class + and has the same sprites in it. + + """ + return self.__class__( # noqa pylint: disable=too-many-function-args + self.sprites() # Needed because copy() won't work on AbstractGroup + ) + + def __iter__(self): + return iter(self.sprites()) + + def __contains__(self, sprite): + return self.has(sprite) + + def add(self, *sprites): + """add sprite(s) to group + + Group.add(sprite, list, group, ...): return None + + Adds a sprite or sequence of sprites to a group. + + """ + for sprite in sprites: + # It's possible that some sprite is also an iterator. + # If this is the case, we should add the sprite itself, + # and not the iterator object. + if isinstance(sprite, Sprite): + if not self.has_internal(sprite): + self.add_internal(sprite) + sprite.add_internal(self) + else: + try: + # See if sprite is an iterator, like a list or sprite + # group. + self.add(*sprite) + except (TypeError, AttributeError): + # Not iterable. This is probably a sprite that is not an + # instance of the Sprite class or is not an instance of a + # subclass of the Sprite class. Alternately, it could be an + # old-style sprite group. + if hasattr(sprite, "_spritegroup"): + for spr in sprite.sprites(): + if not self.has_internal(spr): + self.add_internal(spr) + spr.add_internal(self) + elif not self.has_internal(sprite): + self.add_internal(sprite) + sprite.add_internal(self) + + def remove(self, *sprites): + """remove sprite(s) from group + + Group.remove(sprite, list, or group, ...): return None + + Removes a sprite or sequence of sprites from a group. + + """ + # This function behaves essentially the same as Group.add. It first + # tries to handle each argument as an instance of the Sprite class. If + # that fails, then it tries to handle the argument as an iterable + # object. If that fails, then it tries to handle the argument as an + # old-style sprite group. Lastly, if that fails, it assumes that the + # normal Sprite methods should be used. + for sprite in sprites: + if isinstance(sprite, Sprite): + if self.has_internal(sprite): + self.remove_internal(sprite) + sprite.remove_internal(self) + else: + try: + self.remove(*sprite) + except (TypeError, AttributeError): + if hasattr(sprite, "_spritegroup"): + for spr in sprite.sprites(): + if self.has_internal(spr): + self.remove_internal(spr) + spr.remove_internal(self) + elif self.has_internal(sprite): + self.remove_internal(sprite) + sprite.remove_internal(self) + + def has(self, *sprites): + """ask if group has a sprite or sprites + + Group.has(sprite or group, ...): return bool + + Returns True if the given sprite or sprites are contained in the + group. Alternatively, you can get the same information using the + 'in' operator, e.g. 'sprite in group', 'subgroup in group'. + + """ + if not sprites: + return False # return False if no sprites passed in + + for sprite in sprites: + if isinstance(sprite, Sprite): + # Check for Sprite instance's membership in this group + if not self.has_internal(sprite): + return False + else: + try: + if not self.has(*sprite): + return False + except (TypeError, AttributeError): + if hasattr(sprite, "_spritegroup"): + for spr in sprite.sprites(): + if not self.has_internal(spr): + return False + else: + if not self.has_internal(sprite): + return False + + return True + + def update(self, *args, **kwargs): + """call the update method of every member sprite + + Group.update(*args, **kwargs): return None + + Calls the update method of every member sprite. All arguments that + were passed to this method are passed to the Sprite update function. + + """ + for sprite in self.sprites(): + sprite.update(*args, **kwargs) + + def draw(self, surface): + """draw all sprites onto the surface + + Group.draw(surface): return Rect_list + + Draws all of the member sprites onto the given surface. + + """ + sprites = self.sprites() + if hasattr(surface, "blits"): + self.spritedict.update( + zip(sprites, surface.blits((spr.image, spr.rect) for spr in sprites)) + ) + else: + for spr in sprites: + self.spritedict[spr] = surface.blit(spr.image, spr.rect) + self.lostsprites = [] + dirty = self.lostsprites + + return dirty + + def clear(self, surface, bgd): + """erase the previous position of all sprites + + Group.clear(surface, bgd): return None + + Clears the area under every drawn sprite in the group. The bgd + argument should be Surface which is the same dimensions as the + screen surface. The bgd could also be a function which accepts + the given surface and the area to be cleared as arguments. + + """ + if callable(bgd): + for lost_clear_rect in self.lostsprites: + bgd(surface, lost_clear_rect) + for clear_rect in self.spritedict.values(): + if clear_rect: + bgd(surface, clear_rect) + else: + surface_blit = surface.blit + for lost_clear_rect in self.lostsprites: + surface_blit(bgd, lost_clear_rect, lost_clear_rect) + for clear_rect in self.spritedict.values(): + if clear_rect: + surface_blit(bgd, clear_rect, clear_rect) + + def empty(self): + """remove all sprites + + Group.empty(): return None + + Removes all the sprites from the group. + + """ + for sprite in self.sprites(): + self.remove_internal(sprite) + sprite.remove_internal(self) + + def __nonzero__(self): + return truth(self.sprites()) + + __bool__ = __nonzero__ + + def __len__(self): + """return number of sprites in group + + Group.len(group): return int + + Returns the number of sprites contained in the group. + + """ + return len(self.sprites()) + + def __repr__(self): + return f"<{self.__class__.__name__}({len(self)} sprites)>" + + +class Group(AbstractGroup): + """container class for many Sprites + + pygame.sprite.Group(*sprites): return Group + + A simple container for Sprite objects. This class can be subclassed to + create containers with more specific behaviors. The constructor takes any + number of Sprite arguments to add to the Group. The group supports the + following standard Python operations: + + in test if a Sprite is contained + len the number of Sprites contained + bool test if any Sprites are contained + iter iterate through all the Sprites + + The Sprites in the Group are not ordered, so the Sprites are drawn and + iterated over in no particular order. + + """ + + def __init__(self, *sprites): + AbstractGroup.__init__(self) + self.add(*sprites) + + +RenderPlain = Group +RenderClear = Group + + +class RenderUpdates(Group): + """Group class that tracks dirty updates + + pygame.sprite.RenderUpdates(*sprites): return RenderUpdates + + This class is derived from pygame.sprite.Group(). It has an enhanced draw + method that tracks the changed areas of the screen. + + """ + + def draw(self, surface): + surface_blit = surface.blit + dirty = self.lostsprites + self.lostsprites = [] + dirty_append = dirty.append + for sprite in self.sprites(): + old_rect = self.spritedict[sprite] + new_rect = surface_blit(sprite.image, sprite.rect) + if old_rect: + if new_rect.colliderect(old_rect): + dirty_append(new_rect.union(old_rect)) + else: + dirty_append(new_rect) + dirty_append(old_rect) + else: + dirty_append(new_rect) + self.spritedict[sprite] = new_rect + return dirty + + +class OrderedUpdates(RenderUpdates): + """RenderUpdates class that draws Sprites in order of addition + + pygame.sprite.OrderedUpdates(*spites): return OrderedUpdates + + This class derives from pygame.sprite.RenderUpdates(). It maintains + the order in which the Sprites were added to the Group for rendering. + This makes adding and removing Sprites from the Group a little + slower than regular Groups. + + """ + + def __init__(self, *sprites): + self._spritelist = [] + RenderUpdates.__init__(self, *sprites) + + def sprites(self): + return list(self._spritelist) + + def add_internal(self, sprite, layer=None): + RenderUpdates.add_internal(self, sprite) + self._spritelist.append(sprite) + + def remove_internal(self, sprite): + RenderUpdates.remove_internal(self, sprite) + self._spritelist.remove(sprite) + + +class LayeredUpdates(AbstractGroup): + """LayeredUpdates Group handles layers, which are drawn like OrderedUpdates + + pygame.sprite.LayeredUpdates(*spites, **kwargs): return LayeredUpdates + + This group is fully compatible with pygame.sprite.Sprite. + New in pygame 1.8.0 + + """ + + _init_rect = Rect(0, 0, 0, 0) + + def __init__(self, *sprites, **kwargs): + """initialize an instance of LayeredUpdates with the given attributes + + You can set the default layer through kwargs using 'default_layer' + and an integer for the layer. The default layer is 0. + + If the sprite you add has an attribute _layer, then that layer will be + used. If **kwarg contains 'layer', then the passed sprites will be + added to that layer (overriding the sprite._layer attribute). If + neither the sprite nor **kwarg has a 'layer', then the default layer is + used to add the sprites. + + """ + self._spritelayers = {} + self._spritelist = [] + AbstractGroup.__init__(self) + self._default_layer = kwargs.get("default_layer", 0) + + self.add(*sprites, **kwargs) + + def add_internal(self, sprite, layer=None): + """Do not use this method directly. + + It is used by the group to add a sprite internally. + + """ + self.spritedict[sprite] = self._init_rect + + if layer is None: + try: + layer = sprite.layer + except AttributeError: + layer = self._default_layer + setattr(sprite, "_layer", layer) + elif hasattr(sprite, "_layer"): + setattr(sprite, "_layer", layer) + + sprites = self._spritelist # speedup + sprites_layers = self._spritelayers + sprites_layers[sprite] = layer + + # add the sprite at the right position + # bisect algorithmus + leng = len(sprites) + low = mid = 0 + high = leng - 1 + while low <= high: + mid = low + (high - low) // 2 + if sprites_layers[sprites[mid]] <= layer: + low = mid + 1 + else: + high = mid - 1 + # linear search to find final position + while mid < leng and sprites_layers[sprites[mid]] <= layer: + mid += 1 + sprites.insert(mid, sprite) + + def add(self, *sprites, **kwargs): + """add a sprite or sequence of sprites to a group + + LayeredUpdates.add(*sprites, **kwargs): return None + + If the sprite you add has an attribute _layer, then that layer will be + used. If **kwarg contains 'layer', then the passed sprites will be + added to that layer (overriding the sprite._layer attribute). If + neither the sprite nor **kwarg has a 'layer', then the default layer is + used to add the sprites. + + """ + + if not sprites: + return + layer = kwargs["layer"] if "layer" in kwargs else None + for sprite in sprites: + # It's possible that some sprite is also an iterator. + # If this is the case, we should add the sprite itself, + # and not the iterator object. + if isinstance(sprite, Sprite): + if not self.has_internal(sprite): + self.add_internal(sprite, layer) + sprite.add_internal(self) + else: + try: + # See if sprite is an iterator, like a list or sprite + # group. + self.add(*sprite, **kwargs) + except (TypeError, AttributeError): + # Not iterable. This is probably a sprite that is not an + # instance of the Sprite class or is not an instance of a + # subclass of the Sprite class. Alternately, it could be an + # old-style sprite group. + if hasattr(sprite, "_spritegroup"): + for spr in sprite.sprites(): + if not self.has_internal(spr): + self.add_internal(spr, layer) + spr.add_internal(self) + elif not self.has_internal(sprite): + self.add_internal(sprite, layer) + sprite.add_internal(self) + + def remove_internal(self, sprite): + """Do not use this method directly. + + The group uses it to add a sprite. + + """ + self._spritelist.remove(sprite) + # these dirty rects are suboptimal for one frame + old_rect = self.spritedict[sprite] + if old_rect is not self._init_rect: + self.lostsprites.append(old_rect) # dirty rect + if hasattr(sprite, "rect"): + self.lostsprites.append(sprite.rect) # dirty rect + + del self.spritedict[sprite] + del self._spritelayers[sprite] + + def sprites(self): + """return a ordered list of sprites (first back, last top). + + LayeredUpdates.sprites(): return sprites + + """ + return list(self._spritelist) + + def draw(self, surface): + """draw all sprites in the right order onto the passed surface + + LayeredUpdates.draw(surface): return Rect_list + + """ + spritedict = self.spritedict + surface_blit = surface.blit + dirty = self.lostsprites + self.lostsprites = [] + dirty_append = dirty.append + init_rect = self._init_rect + for spr in self.sprites(): + rec = spritedict[spr] + newrect = surface_blit(spr.image, spr.rect) + if rec is init_rect: + dirty_append(newrect) + else: + if newrect.colliderect(rec): + dirty_append(newrect.union(rec)) + else: + dirty_append(newrect) + dirty_append(rec) + spritedict[spr] = newrect + return dirty + + def get_sprites_at(self, pos): + """return a list with all sprites at that position + + LayeredUpdates.get_sprites_at(pos): return colliding_sprites + + Bottom sprites are listed first; the top ones are listed last. + + """ + _sprites = self._spritelist + rect = Rect(pos, (1, 1)) + colliding_idx = rect.collidelistall(_sprites) + return [_sprites[i] for i in colliding_idx] + + def get_sprite(self, idx): + """return the sprite at the index idx from the groups sprites + + LayeredUpdates.get_sprite(idx): return sprite + + Raises IndexOutOfBounds if the idx is not within range. + + """ + return self._spritelist[idx] + + def remove_sprites_of_layer(self, layer_nr): + """remove all sprites from a layer and return them as a list + + LayeredUpdates.remove_sprites_of_layer(layer_nr): return sprites + + """ + sprites = self.get_sprites_from_layer(layer_nr) + self.remove(*sprites) + return sprites + + # layer methods + def layers(self): + """return a list of unique defined layers defined. + + LayeredUpdates.layers(): return layers + + """ + return sorted(set(self._spritelayers.values())) + + def change_layer(self, sprite, new_layer): + """change the layer of the sprite + + LayeredUpdates.change_layer(sprite, new_layer): return None + + The sprite must have been added to the renderer already. This is not + checked. + + """ + sprites = self._spritelist # speedup + sprites_layers = self._spritelayers # speedup + + sprites.remove(sprite) + sprites_layers.pop(sprite) + + # add the sprite at the right position + # bisect algorithmus + leng = len(sprites) + low = mid = 0 + high = leng - 1 + while low <= high: + mid = low + (high - low) // 2 + if sprites_layers[sprites[mid]] <= new_layer: + low = mid + 1 + else: + high = mid - 1 + # linear search to find final position + while mid < leng and sprites_layers[sprites[mid]] <= new_layer: + mid += 1 + sprites.insert(mid, sprite) + if hasattr(sprite, "_layer"): + setattr(sprite, "_layer", new_layer) + + # add layer info + sprites_layers[sprite] = new_layer + + def get_layer_of_sprite(self, sprite): + """return the layer that sprite is currently in + + If the sprite is not found, then it will return the default layer. + + """ + return self._spritelayers.get(sprite, self._default_layer) + + def get_top_layer(self): + """return the top layer + + LayeredUpdates.get_top_layer(): return layer + + """ + return self._spritelayers[self._spritelist[-1]] + + def get_bottom_layer(self): + """return the bottom layer + + LayeredUpdates.get_bottom_layer(): return layer + + """ + return self._spritelayers[self._spritelist[0]] + + def move_to_front(self, sprite): + """bring the sprite to front layer + + LayeredUpdates.move_to_front(sprite): return None + + Brings the sprite to front by changing the sprite layer to the top-most + layer. The sprite is added at the end of the list of sprites in that + top-most layer. + + """ + self.change_layer(sprite, self.get_top_layer()) + + def move_to_back(self, sprite): + """move the sprite to the bottom layer + + LayeredUpdates.move_to_back(sprite): return None + + Moves the sprite to the bottom layer by moving it to a new layer below + the current bottom layer. + + """ + self.change_layer(sprite, self.get_bottom_layer() - 1) + + def get_top_sprite(self): + """return the topmost sprite + + LayeredUpdates.get_top_sprite(): return Sprite + + """ + return self._spritelist[-1] + + def get_sprites_from_layer(self, layer): + """return all sprites from a layer ordered as they where added + + LayeredUpdates.get_sprites_from_layer(layer): return sprites + + Returns all sprites from a layer. The sprites are ordered in the + sequence that they where added. (The sprites are not removed from the + layer. + + """ + sprites = [] + sprites_append = sprites.append + sprite_layers = self._spritelayers + for spr in self._spritelist: + if sprite_layers[spr] == layer: + sprites_append(spr) + elif sprite_layers[spr] > layer: + # break after because no other will + # follow with same layer + break + return sprites + + def switch_layer(self, layer1_nr, layer2_nr): + """switch the sprites from layer1_nr to layer2_nr + + LayeredUpdates.switch_layer(layer1_nr, layer2_nr): return None + + The layers number must exist. This method does not check for the + existence of the given layers. + + """ + sprites1 = self.remove_sprites_of_layer(layer1_nr) + for spr in self.get_sprites_from_layer(layer2_nr): + self.change_layer(spr, layer1_nr) + self.add(layer=layer2_nr, *sprites1) + + +class LayeredDirty(LayeredUpdates): + """LayeredDirty Group is for DirtySprites; subclasses LayeredUpdates + + pygame.sprite.LayeredDirty(*spites, **kwargs): return LayeredDirty + + This group requires pygame.sprite.DirtySprite or any sprite that + has the following attributes: + image, rect, dirty, visible, blendmode (see doc of DirtySprite). + + It uses the dirty flag technique and is therefore faster than + pygame.sprite.RenderUpdates if you have many static sprites. It + also switches automatically between dirty rect updating and full + screen drawing, so you do no have to worry which would be faster. + + As with the pygame.sprite.Group, you can specify some additional attributes + through kwargs: + _use_update: True/False (default is False) + _default_layer: default layer where the sprites without a layer are + added + _time_threshold: threshold time for switching between dirty rect mode + and fullscreen mode; defaults to updating at 80 frames per second, + which is equal to 1000.0 / 80.0 + + New in pygame 1.8.0 + + """ + + def __init__(self, *sprites, **kwargs): + """initialize group. + + pygame.sprite.LayeredDirty(*spites, **kwargs): return LayeredDirty + + You can specify some additional attributes through kwargs: + _use_update: True/False (default is False) + _default_layer: default layer where the sprites without a layer are + added + _time_threshold: threshold time for switching between dirty rect + mode and fullscreen mode; defaults to updating at 80 frames per + second, which is equal to 1000.0 / 80.0 + + """ + LayeredUpdates.__init__(self, *sprites, **kwargs) + self._clip = None + + self._use_update = False + + self._time_threshold = 1000.0 / 80.0 # 1000.0 / fps + + self._bgd = None + for key, val in kwargs.items(): + if key in ["_use_update", "_time_threshold", "_default_layer"] and hasattr( + self, key + ): + setattr(self, key, val) + + def add_internal(self, sprite, layer=None): + """Do not use this method directly. + + It is used by the group to add a sprite internally. + + """ + # check if all needed attributes are set + if not hasattr(sprite, "dirty"): + raise AttributeError() + if not hasattr(sprite, "visible"): + raise AttributeError() + if not hasattr(sprite, "blendmode"): + raise AttributeError() + + if not isinstance(sprite, DirtySprite): + raise TypeError() + + if sprite.dirty == 0: # set it dirty if it is not + sprite.dirty = 1 + + LayeredUpdates.add_internal(self, sprite, layer) + + def draw( + self, surface, bgd=None + ): # noqa pylint: disable=arguments-differ; unable to change public interface + """draw all sprites in the right order onto the given surface + + LayeredDirty.draw(surface, bgd=None): return Rect_list + + You can pass the background too. If a self.bgd is already set to some + value that is not None, then the bgd argument has no effect. + + """ + # functions and classes assigned locally to speed up loops + orig_clip = surface.get_clip() + latest_clip = self._clip + if latest_clip is None: + latest_clip = orig_clip + + local_sprites = self._spritelist + local_old_rect = self.spritedict + local_update = self.lostsprites + rect_type = Rect + + surf_blit_func = surface.blit + if bgd is not None: + self._bgd = bgd + local_bgd = self._bgd + + surface.set_clip(latest_clip) + # ------- + # 0. decide whether to render with update or flip + start_time = get_ticks() + if self._use_update: # dirty rects mode + # 1. find dirty area on screen and put the rects into + # self.lostsprites still not happy with that part + self._find_dirty_area( + latest_clip, + local_old_rect, + rect_type, + local_sprites, + local_update, + local_update.append, + self._init_rect, + ) + # can it be done better? because that is an O(n**2) algorithm in + # worst case + + # clear using background + if local_bgd is not None: + for rec in local_update: + surf_blit_func(local_bgd, rec, rec) + + # 2. draw + self._draw_dirty_internal( + local_old_rect, rect_type, local_sprites, surf_blit_func, local_update + ) + local_ret = list(local_update) + else: # flip, full screen mode + if local_bgd is not None: + surf_blit_func(local_bgd, (0, 0)) + for spr in local_sprites: + if spr.visible: + local_old_rect[spr] = surf_blit_func( + spr.image, spr.rect, spr.source_rect, spr.blendmode + ) + # return only the part of the screen changed + local_ret = [rect_type(latest_clip)] + + # timing for switching modes + # How may a good threshold be found? It depends on the hardware. + end_time = get_ticks() + if end_time - start_time > self._time_threshold: + self._use_update = False + else: + self._use_update = True + + # emtpy dirty rects list + local_update[:] = [] + + # ------- + # restore original clip + surface.set_clip(orig_clip) + return local_ret + + @staticmethod + def _draw_dirty_internal(_old_rect, _rect, _sprites, _surf_blit, _update): + for spr in _sprites: + if spr.dirty < 1 and spr.visible: + # sprite not dirty; blit only the intersecting part + if spr.source_rect is not None: + # For possible future speed up, source_rect's data + # can be pre-fetched outside of this loop. + _spr_rect = _rect(spr.rect.topleft, spr.source_rect.size) + rect_offset_x = spr.source_rect[0] - _spr_rect[0] + rect_offset_y = spr.source_rect[1] - _spr_rect[1] + else: + _spr_rect = spr.rect + rect_offset_x = -_spr_rect[0] + rect_offset_y = -_spr_rect[1] + + _spr_rect_clip = _spr_rect.clip + + for idx in _spr_rect.collidelistall(_update): + # clip + clip = _spr_rect_clip(_update[idx]) + _surf_blit( + spr.image, + clip, + ( + clip[0] + rect_offset_x, + clip[1] + rect_offset_y, + clip[2], + clip[3], + ), + spr.blendmode, + ) + else: # dirty sprite + if spr.visible: + _old_rect[spr] = _surf_blit( + spr.image, spr.rect, spr.source_rect, spr.blendmode + ) + if spr.dirty == 1: + spr.dirty = 0 + + @staticmethod + def _find_dirty_area( + _clip, _old_rect, _rect, _sprites, _update, _update_append, init_rect + ): + for spr in _sprites: + if spr.dirty > 0: + # chose the right rect + if spr.source_rect: + _union_rect = _rect(spr.rect.topleft, spr.source_rect.size) + else: + _union_rect = _rect(spr.rect) + + _union_rect_collidelist = _union_rect.collidelist + _union_rect_union_ip = _union_rect.union_ip + i = _union_rect_collidelist(_update) + while i > -1: + _union_rect_union_ip(_update[i]) + del _update[i] + i = _union_rect_collidelist(_update) + _update_append(_union_rect.clip(_clip)) + + if _old_rect[spr] is not init_rect: + _union_rect = _rect(_old_rect[spr]) + _union_rect_collidelist = _union_rect.collidelist + _union_rect_union_ip = _union_rect.union_ip + i = _union_rect_collidelist(_update) + while i > -1: + _union_rect_union_ip(_update[i]) + del _update[i] + i = _union_rect_collidelist(_update) + _update_append(_union_rect.clip(_clip)) + + def clear(self, surface, bgd): + """use to set background + + Group.clear(surface, bgd): return None + + """ + self._bgd = bgd + + def repaint_rect(self, screen_rect): + """repaint the given area + + LayeredDirty.repaint_rect(screen_rect): return None + + screen_rect is in screen coordinates. + + """ + if self._clip: + self.lostsprites.append(screen_rect.clip(self._clip)) + else: + self.lostsprites.append(Rect(screen_rect)) + + def set_clip(self, screen_rect=None): + """clip the area where to draw; pass None (default) to reset the clip + + LayeredDirty.set_clip(screen_rect=None): return None + + """ + if screen_rect is None: + self._clip = pygame.display.get_surface().get_rect() + else: + self._clip = screen_rect + self._use_update = False + + def get_clip(self): + """get the area where drawing will occur + + LayeredDirty.get_clip(): return Rect + + """ + return self._clip + + def change_layer(self, sprite, new_layer): + """change the layer of the sprite + + LayeredUpdates.change_layer(sprite, new_layer): return None + + The sprite must have been added to the renderer already. This is not + checked. + + """ + LayeredUpdates.change_layer(self, sprite, new_layer) + if sprite.dirty == 0: + sprite.dirty = 1 + + def set_timing_treshold(self, time_ms): + """set the threshold in milliseconds + + set_timing_treshold(time_ms): return None + + Defaults to 1000.0 / 80.0. This means that the screen will be painted + using the flip method rather than the update method if the update + method is taking so long to update the screen that the frame rate falls + below 80 frames per second. + + Raises TypeError if time_ms is not int or float. + + """ + warn( + "This function will be removed, use set_timing_threshold function instead", + DeprecationWarning, + ) + self.set_timing_threshold(time_ms) + + def set_timing_threshold(self, time_ms): + """set the threshold in milliseconds + + set_timing_threshold(time_ms): return None + + Defaults to 1000.0 / 80.0. This means that the screen will be painted + using the flip method rather than the update method if the update + method is taking so long to update the screen that the frame rate falls + below 80 frames per second. + + Raises TypeError if time_ms is not int or float. + + """ + if isinstance(time_ms, (int, float)): + self._time_threshold = time_ms + else: + raise TypeError( + f"Expected numeric value, got {time_ms.__class__.__name__} instead" + ) + + +class GroupSingle(AbstractGroup): + """A group container that holds a single most recent item. + + This class works just like a regular group, but it only keeps a single + sprite in the group. Whatever sprite has been added to the group last will + be the only sprite in the group. + + You can access its one sprite as the .sprite attribute. Assigning to this + attribute will properly remove the old sprite and then add the new one. + + """ + + def __init__(self, sprite=None): + AbstractGroup.__init__(self) + self.__sprite = None + if sprite is not None: + self.add(sprite) + + def copy(self): + return GroupSingle(self.__sprite) + + def sprites(self): + if self.__sprite is not None: + return [self.__sprite] + return [] + + def add_internal(self, sprite, _=None): + if self.__sprite is not None: + self.__sprite.remove_internal(self) + self.remove_internal(self.__sprite) + self.__sprite = sprite + + def __nonzero__(self): + return self.__sprite is not None + + __bool__ = __nonzero__ + + def _get_sprite(self): + return self.__sprite + + def _set_sprite(self, sprite): + self.add_internal(sprite) + sprite.add_internal(self) + return sprite + + @property + def sprite(self): + """ + Property for the single sprite contained in this group + + :return: The sprite. + """ + return self._get_sprite() + + @sprite.setter + def sprite(self, sprite_to_set): + self._set_sprite(sprite_to_set) + + def remove_internal(self, sprite): + if sprite is self.__sprite: + self.__sprite = None + if sprite in self.spritedict: + AbstractGroup.remove_internal(self, sprite) + + def has_internal(self, sprite): + return self.__sprite is sprite + + # Optimizations... + def __contains__(self, sprite): + return self.__sprite is sprite + + +# Some different collision detection functions that could be used. +def collide_rect(left, right): + """collision detection between two sprites, using rects. + + pygame.sprite.collide_rect(left, right): return bool + + Tests for collision between two sprites. Uses the pygame.Rect colliderect + function to calculate the collision. It is intended to be passed as a + collided callback function to the *collide functions. Sprites must have + "rect" attributes. + + New in pygame 1.8.0 + + """ + return left.rect.colliderect(right.rect) + + +class collide_rect_ratio: # noqa pylint: disable=invalid-name; this is a function-like class + """A callable class that checks for collisions using scaled rects + + The class checks for collisions between two sprites using a scaled version + of the sprites' rects. Is created with a ratio; the instance is then + intended to be passed as a collided callback function to the *collide + functions. + + New in pygame 1.8.1 + + """ + + def __init__(self, ratio): + """create a new collide_rect_ratio callable + + Ratio is expected to be a floating point value used to scale + the underlying sprite rect before checking for collisions. + + """ + self.ratio = ratio + + def __repr__(self): + """ + Turn the class into a string. + """ + # pylint: disable=consider-using-f-string + return "<{klass} @{id:x} {attrs}>".format( + klass=self.__class__.__name__, + id=id(self) & 0xFFFFFF, + attrs=" ".join("{}={!r}".format(k, v) for k, v in self.__dict__.items()), + ) + + def __call__(self, left, right): + """detect collision between two sprites using scaled rects + + pygame.sprite.collide_rect_ratio(ratio)(left, right): return bool + + Tests for collision between two sprites. Uses the pygame.Rect + colliderect function to calculate the collision after scaling the rects + by the stored ratio. Sprites must have "rect" attributes. + + """ + + ratio = self.ratio + + leftrect = left.rect + width = leftrect.width + height = leftrect.height + leftrect = leftrect.inflate(width * ratio - width, height * ratio - height) + + rightrect = right.rect + width = rightrect.width + height = rightrect.height + rightrect = rightrect.inflate(width * ratio - width, height * ratio - height) + + return leftrect.colliderect(rightrect) + + +def collide_circle(left, right): + """detect collision between two sprites using circles + + pygame.sprite.collide_circle(left, right): return bool + + Tests for collision between two sprites by testing whether two circles + centered on the sprites overlap. If the sprites have a "radius" attribute, + then that radius is used to create the circle; otherwise, a circle is + created that is big enough to completely enclose the sprite's rect as + given by the "rect" attribute. This function is intended to be passed as + a collided callback function to the *collide functions. Sprites must have a + "rect" and an optional "radius" attribute. + + New in pygame 1.8.0 + + """ + + xdistance = left.rect.centerx - right.rect.centerx + ydistance = left.rect.centery - right.rect.centery + distancesquared = xdistance ** 2 + ydistance ** 2 + + try: + leftradius = left.radius + except AttributeError: + leftrect = left.rect + # approximating the radius of a square by using half of the diagonal, + # might give false positives (especially if its a long small rect) + leftradius = 0.5 * ((leftrect.width ** 2 + leftrect.height ** 2) ** 0.5) + # store the radius on the sprite for next time + left.radius = leftradius + + try: + rightradius = right.radius + except AttributeError: + rightrect = right.rect + # approximating the radius of a square by using half of the diagonal + # might give false positives (especially if its a long small rect) + rightradius = 0.5 * ((rightrect.width ** 2 + rightrect.height ** 2) ** 0.5) + # store the radius on the sprite for next time + right.radius = rightradius + return distancesquared <= (leftradius + rightradius) ** 2 + + +class collide_circle_ratio( + object +): # noqa pylint: disable=invalid-name; this is a function-like class + """detect collision between two sprites using scaled circles + + This callable class checks for collisions between two sprites using a + scaled version of a sprite's radius. It is created with a ratio as the + argument to the constructor. The instance is then intended to be passed as + a collided callback function to the *collide functions. + + New in pygame 1.8.1 + + """ + + def __init__(self, ratio): + """creates a new collide_circle_ratio callable instance + + The given ratio is expected to be a floating point value used to scale + the underlying sprite radius before checking for collisions. + + When the ratio is ratio=1.0, then it behaves exactly like the + collide_circle method. + + """ + self.ratio = ratio + + def __repr__(self): + """ + Turn the class into a string. + """ + # pylint: disable=consider-using-f-string + return "<{klass} @{id:x} {attrs}>".format( + klass=self.__class__.__name__, + id=id(self) & 0xFFFFFF, + attrs=" ".join("{}={!r}".format(k, v) for k, v in self.__dict__.items()), + ) + + def __call__(self, left, right): + """detect collision between two sprites using scaled circles + + pygame.sprite.collide_circle_radio(ratio)(left, right): return bool + + Tests for collision between two sprites by testing whether two circles + centered on the sprites overlap after scaling the circle's radius by + the stored ratio. If the sprites have a "radius" attribute, that is + used to create the circle; otherwise, a circle is created that is big + enough to completely enclose the sprite's rect as given by the "rect" + attribute. Intended to be passed as a collided callback function to the + *collide functions. Sprites must have a "rect" and an optional "radius" + attribute. + + """ + + ratio = self.ratio + xdistance = left.rect.centerx - right.rect.centerx + ydistance = left.rect.centery - right.rect.centery + distancesquared = xdistance ** 2 + ydistance ** 2 + + try: + leftradius = left.radius + except AttributeError: + leftrect = left.rect + leftradius = 0.5 * ((leftrect.width ** 2 + leftrect.height ** 2) ** 0.5) + # store the radius on the sprite for next time + left.radius = leftradius + leftradius *= ratio + + try: + rightradius = right.radius + except AttributeError: + rightrect = right.rect + rightradius = 0.5 * ((rightrect.width ** 2 + rightrect.height ** 2) ** 0.5) + # store the radius on the sprite for next time + right.radius = rightradius + rightradius *= ratio + + return distancesquared <= (leftradius + rightradius) ** 2 + + +def collide_mask(left, right): + """collision detection between two sprites, using masks. + + pygame.sprite.collide_mask(SpriteLeft, SpriteRight): bool + + Tests for collision between two sprites by testing if their bitmasks + overlap. If the sprites have a "mask" attribute, that is used as the mask; + otherwise, a mask is created from the sprite image. Intended to be passed + as a collided callback function to the *collide functions. Sprites must + have a "rect" and an optional "mask" attribute. + + New in pygame 1.8.0 + + """ + xoffset = right.rect[0] - left.rect[0] + yoffset = right.rect[1] - left.rect[1] + try: + leftmask = left.mask + except AttributeError: + leftmask = from_surface(left.image) + try: + rightmask = right.mask + except AttributeError: + rightmask = from_surface(right.image) + return leftmask.overlap(rightmask, (xoffset, yoffset)) + + +def spritecollide(sprite, group, dokill, collided=None): + """find Sprites in a Group that intersect another Sprite + + pygame.sprite.spritecollide(sprite, group, dokill, collided=None): + return Sprite_list + + Return a list containing all Sprites in a Group that intersect with another + Sprite. Intersection is determined by comparing the Sprite.rect attribute + of each Sprite. + + The dokill argument is a bool. If set to True, all Sprites that collide + will be removed from the Group. + + The collided argument is a callback function used to calculate if two + sprites are colliding. it should take two sprites as values, and return a + bool value indicating if they are colliding. If collided is not passed, all + sprites must have a "rect" value, which is a rectangle of the sprite area, + which will be used to calculate the collision. + + """ + # pull the default collision function in as a local variable outside + # the loop as this makes the loop run faster + default_sprite_collide_func = sprite.rect.colliderect + + if dokill: + + crashed = [] + append = crashed.append + + for group_sprite in group.sprites(): + if collided: + if collided(sprite, group_sprite): + group_sprite.kill() + append(group_sprite) + else: + if default_sprite_collide_func(group_sprite.rect): + group_sprite.kill() + append(group_sprite) + + return crashed + + if collided: + return [ + group_sprite for group_sprite in group if collided(sprite, group_sprite) + ] + + return [ + group_sprite + for group_sprite in group + if default_sprite_collide_func(group_sprite.rect) + ] + + +def groupcollide(groupa, groupb, dokilla, dokillb, collided=None): + """detect collision between a group and another group + + pygame.sprite.groupcollide(groupa, groupb, dokilla, dokillb): + return dict + + Given two groups, this will find the intersections between all sprites in + each group. It returns a dictionary of all sprites in the first group that + collide. The value for each item in the dictionary is a list of the sprites + in the second group it collides with. The two dokill arguments control if + the sprites from either group will be automatically removed from all + groups. Collided is a callback function used to calculate if two sprites + are colliding. it should take two sprites as values, and return a bool + value indicating if they are colliding. If collided is not passed, all + sprites must have a "rect" value, which is a rectangle of the sprite area + that will be used to calculate the collision. + + """ + crashed = {} + # pull the collision function in as a local variable outside + # the loop as this makes the loop run faster + sprite_collide_func = spritecollide + if dokilla: + for group_a_sprite in groupa.sprites(): + collision = sprite_collide_func(group_a_sprite, groupb, dokillb, collided) + if collision: + crashed[group_a_sprite] = collision + group_a_sprite.kill() + else: + for group_a_sprite in groupa: + collision = sprite_collide_func(group_a_sprite, groupb, dokillb, collided) + if collision: + crashed[group_a_sprite] = collision + return crashed + + +def spritecollideany(sprite, group, collided=None): + """finds any sprites in a group that collide with the given sprite + + pygame.sprite.spritecollideany(sprite, group): return sprite + + Given a sprite and a group of sprites, this will return return any single + sprite that collides with with the given sprite. If there are no + collisions, then this returns None. + + If you don't need all the features of the spritecollide function, this + function will be a bit quicker. + + Collided is a callback function used to calculate if two sprites are + colliding. It should take two sprites as values and return a bool value + indicating if they are colliding. If collided is not passed, then all + sprites must have a "rect" value, which is a rectangle of the sprite area, + which will be used to calculate the collision. + + + """ + # pull the default collision function in as a local variable outside + # the loop as this makes the loop run faster + default_sprite_collide_func = sprite.rect.colliderect + + if collided is not None: + for group_sprite in group: + if collided(sprite, group_sprite): + return group_sprite + else: + # Special case old behaviour for speed. + for group_sprite in group: + if default_sprite_collide_func(group_sprite.rect): + return group_sprite + return None diff --git a/venv/Lib/site-packages/pygame/sprite.pyi b/venv/Lib/site-packages/pygame/sprite.pyi new file mode 100644 index 0000000..4e2f0fd --- /dev/null +++ b/venv/Lib/site-packages/pygame/sprite.pyi @@ -0,0 +1,152 @@ +from typing import ( + Any, + Callable, + Dict, + Iterable, + Iterator, + List, + Optional, + Sequence, + SupportsFloat, + Tuple, + Union, +) + +from pygame.rect import Rect +from pygame.surface import Surface + +from ._common import _CanBeRect + +# Some functions violate Liskov substitution principle so mypy will throw errors for this file, but this are the +# best type hints I could do + +class Sprite: + image: Optional[Surface] = None + rect: Optional[Rect] = None + def __init__(self, *groups: AbstractGroup) -> None: ... + def update(self, *args: Any, **kwargs: Any) -> None: ... + def add(self, *groups: AbstractGroup) -> None: ... + def remove(self, *groups: AbstractGroup) -> None: ... + def kill(self) -> None: ... + def alive(self) -> bool: ... + def groups(self) -> List[AbstractGroup]: ... + +class DirtySprite(Sprite): + dirty: int + blendmode: int + source_rect: Rect + visible: int + _layer: int + def _set_visible(self, value: int) -> None: ... + def _get_visible(self) -> int: ... + +class AbstractGroup: + spritedict: Dict[Sprite, Rect] + lostsprites: List[int] # I think + def __init__(self) -> None: ... + def __len__(self) -> int: ... + def __iter__(self) -> Iterator[Sprite]: ... + def copy(self) -> AbstractGroup: ... + def sprites(self) -> List[Sprite]: ... + def add( + self, + *sprites: Union[Sprite, AbstractGroup, Iterable[Union[Sprite, AbstractGroup]]] + ) -> None: ... + def remove(self, *sprites: Sprite) -> None: ... + def has(self, *sprites: Sprite) -> bool: ... + def update(self, *args: Any, **kwargs: Any) -> None: ... + def draw(self, surface: Surface) -> List[Rect]: ... + def clear(self, surface_dest: Surface, background: Surface) -> None: ... + def empty(self) -> None: ... + +class Group(AbstractGroup): + def __init__(self, *sprites: Union[Sprite, Sequence[Sprite]]) -> None: ... + def copy(self) -> Group: ... + +class RenderPlain(Group): + def copy(self) -> RenderPlain: ... + +class RenderClear(Group): + def copy(self) -> RenderClear: ... + +class RenderUpdates(Group): + def copy(self) -> RenderUpdates: ... + def draw(self, surface: Surface) -> List[Rect]: ... + +class OrderedUpdates(RenderUpdates): + def copy(self) -> OrderedUpdates: ... + +class LayeredUpdates(AbstractGroup): + def __init__(self, *sprites: Sprite, **kwargs: Any) -> None: ... + def copy(self) -> LayeredUpdates: ... + def add(self, *sprites: Sprite, **kwargs: Any) -> None: ... + def draw(self, surface: Surface) -> List[Rect]: ... + def get_sprites_at( + self, pos: Union[Tuple[int, int], List[int]] + ) -> List[Sprite]: ... + def get_sprite(self, idx: int) -> Sprite: ... + def remove_sprites_of_layer(self, layer_nr: int) -> List[Sprite]: ... + def layers(self) -> List[int]: ... + def change_layer(self, sprite: Sprite, new_layer: int) -> None: ... + def get_layer_of_sprite(self, sprite: Sprite) -> int: ... + def get_top_layer(self) -> int: ... + def get_bottom_layer(self) -> int: ... + def move_to_front(self, sprite: Sprite) -> None: ... + def move_to_back(self, sprite: Sprite) -> None: ... + def get_top_sprite(self) -> Sprite: ... + def get_sprites_from_layer(self, layer: int) -> List[Sprite]: ... + def switch_layer(self, layer1_nr: int, layer2_nr: int) -> None: ... + +class LayeredDirty(LayeredUpdates): + def __init__(self, *sprites: DirtySprite, **kwargs: Any) -> None: ... + def copy(self) -> LayeredDirty: ... + def draw(self, surface: Surface, bgd: Optional[Surface] = None) -> List[Rect]: ... + def clear(self, surface: Surface, bgd: Surface) -> None: ... + def repaint_rect(self, screen_rect: _CanBeRect) -> None: ... + def set_clip(self, screen_rect: Optional[_CanBeRect] = None) -> None: ... + def get_clip(self) -> Rect: ... + def set_timing_treshold( + self, time_ms: SupportsFloat + ) -> None: ... # This actually accept any value + def set_timing_threshold( + self, time_ms: SupportsFloat + ) -> None: ... # This actually accept any value + +class GroupSingle(AbstractGroup): + sprite: Sprite + def __init__(self, sprite: Optional[Sprite] = None) -> None: ... + def copy(self) -> GroupSingle: ... + +def spritecollide( + sprite: Sprite, + group: AbstractGroup, + dokill: bool, + collided: Optional[Callable[[Sprite, Sprite], bool]] = None, +) -> List[Sprite]: ... +def collide_rect(left: Sprite, right: Sprite) -> bool: ... + +class collide_rect_ratio: + ratio: float + def __init__(self, ratio: float) -> None: ... + def __call__(self, left: Sprite, right: Sprite) -> bool: ... + +def collide_circle(left: Sprite, right: Sprite) -> bool: ... + +class collide_circle_ratio: + ratio: float + def __init__(self, ratio: float) -> None: ... + def __call__(self, left: Sprite, right: Sprite) -> bool: ... + +def collide_mask(sprite1: Sprite, sprite2: Sprite) -> Tuple[int, int]: ... +def groupcollide( + group1: AbstractGroup, + group2: AbstractGroup, + dokill: bool, + dokill2: bool, + collided: Optional[Callable[[Sprite, Sprite], bool]] = None, +) -> Dict[Sprite, Sprite]: ... +def spritecollideany( + sprite: Sprite, + group: AbstractGroup, + collided: Optional[Callable[[Sprite, Sprite], bool]] = None, +) -> Sprite: ... diff --git a/venv/Lib/site-packages/pygame/surface.pyi b/venv/Lib/site-packages/pygame/surface.pyi new file mode 100644 index 0000000..7b086a5 --- /dev/null +++ b/venv/Lib/site-packages/pygame/surface.pyi @@ -0,0 +1,121 @@ +from typing import Any, List, Optional, Sequence, Text, Tuple, Union, overload + +from pygame.bufferproxy import BufferProxy +from pygame.math import Vector2 +from pygame.rect import Rect + +from ._common import _CanBeRect, _ColorValue, _Coordinate, _RgbaOutput + +class Surface(object): + _pixels_address: int + @overload + def __init__( + self, + size: _Coordinate, + flags: int = ..., + depth: int = ..., + masks: Optional[_ColorValue] = ..., + ) -> None: ... + @overload + def __init__( + self, + size: _Coordinate, + flags: int = ..., + surface: Surface = ..., + ) -> None: ... + def blit( + self, + source: Surface, + dest: Union[_Coordinate, _CanBeRect], + area: Optional[_CanBeRect] = ..., + special_flags: int = ..., + ) -> Rect: ... + def blits( + self, + blit_sequence: Sequence[ + Union[ + Tuple[Surface, Union[_Coordinate, _CanBeRect]], + Tuple[Surface, Union[_Coordinate, _CanBeRect], Union[_CanBeRect, int]], + Tuple[Surface, Union[_Coordinate, _CanBeRect], _CanBeRect, int], + ] + ], + doreturn: Union[int, bool] = 1, + ) -> Union[List[Rect], None]: ... + @overload + def convert(self, surface: Surface) -> Surface: ... + @overload + def convert(self, depth: int, flags: int = ...) -> Surface: ... + @overload + def convert(self, masks: _ColorValue, flags: int = ...) -> Surface: ... + @overload + def convert(self) -> Surface: ... + @overload + def convert_alpha(self, surface: Surface) -> Surface: ... + @overload + def convert_alpha(self) -> Surface: ... + def copy(self) -> Surface: ... + def fill( + self, + color: _ColorValue, + rect: Optional[_CanBeRect] = ..., + special_flags: int = ..., + ) -> Rect: ... + def scroll(self, dx: int = ..., dy: int = ...) -> None: ... + @overload + def set_colorkey(self, color: _ColorValue, flags: int = ...) -> None: ... + @overload + def set_colorkey(self, color: None) -> None: ... + def get_colorkey(self) -> Optional[_RgbaOutput]: ... + @overload + def set_alpha(self, value: int, flags: int = ...) -> None: ... + @overload + def set_alpha(self, value: None) -> None: ... + def get_alpha(self) -> Optional[int]: ... + def lock(self) -> None: ... + def unlock(self) -> None: ... + def mustlock(self) -> bool: ... + def get_locked(self) -> bool: ... + def get_locks(self) -> Tuple[Any, ...]: ... + def get_at(self, x_y: Sequence[int]) -> _RgbaOutput: ... + def set_at(self, x_y: Sequence[int], color: _ColorValue) -> None: ... + def get_at_mapped(self, x_y: Sequence[int]) -> int: ... + def get_palette(self) -> List[_RgbaOutput]: ... + def get_palette_at(self, index: int) -> _RgbaOutput: ... + def set_palette(self, palette: List[_ColorValue]) -> None: ... + def set_palette_at(self, index: int, color: _ColorValue) -> None: ... + def map_rgb(self, color: _ColorValue) -> int: ... + def unmap_rgb(self, mapped_int: int) -> _RgbaOutput: ... + def set_clip(self, rect: Optional[_CanBeRect]) -> None: ... + def get_clip(self) -> Rect: ... + @overload + def subsurface(self, rect: Union[_CanBeRect, Rect]) -> Surface: ... + @overload + def subsurface( + self, + left_top: Union[List[float], Tuple[float, float], Vector2], + width_height: Union[List[float], Tuple[float, float], Vector2], + ) -> Surface: ... + @overload + def subsurface( + self, left: float, top: float, width: float, height: float + ) -> Surface: ... + def get_parent(self) -> Surface: ... + def get_abs_parent(self) -> Surface: ... + def get_offset(self) -> Tuple[int, int]: ... + def get_abs_offset(self) -> Tuple[int, int]: ... + def get_size(self) -> Tuple[int, int]: ... + def get_width(self) -> int: ... + def get_height(self) -> int: ... + def get_rect(self, **kwargs: Any) -> Rect: ... + def get_bitsize(self) -> int: ... + def get_bytesize(self) -> int: ... + def get_flags(self) -> int: ... + def get_pitch(self) -> int: ... + def get_masks(self) -> _RgbaOutput: ... + def set_masks(self, color: _ColorValue) -> None: ... + def get_shifts(self) -> _RgbaOutput: ... + def set_shifts(self, color: _ColorValue) -> None: ... + def get_losses(self) -> _RgbaOutput: ... + def get_bounding_rect(self, min_alpha: int = ...) -> Rect: ... + def get_view(self, kind: Text = ...) -> BufferProxy: ... + def get_buffer(self) -> BufferProxy: ... diff --git a/venv/Lib/site-packages/pygame/surfarray.py b/venv/Lib/site-packages/pygame/surfarray.py new file mode 100644 index 0000000..70653fd --- /dev/null +++ b/venv/Lib/site-packages/pygame/surfarray.py @@ -0,0 +1,447 @@ +## pygame - Python Game Library +## Copyright (C) 2007 Marcus von Appen +## +## This library is free software; you can redistribute it and/or +## modify it under the terms of the GNU Library General Public +## License as published by the Free Software Foundation; either +## version 2 of the License, or (at your option) any later version. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## Library General Public License for more details. +## +## You should have received a copy of the GNU Library General Public +## License along with this library; if not, write to the Free +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +## +## Marcus von Appen +## mva@sysfault.org + +"""pygame module for accessing surface pixel data using array interfaces + +Functions to convert between NumPy arrays and Surface objects. This module +will only be functional when pygame can use the external NumPy package. +If NumPy can't be imported, surfarray becomes a MissingModule object. + +Every pixel is stored as a single integer value to represent the red, +green, and blue colors. The 8bit images use a value that looks into a +colormap. Pixels with higher depth use a bit packing process to place +three or four values into a single number. + +The arrays are indexed by the X axis first, followed by the Y +axis. Arrays that treat the pixels as a single integer are referred to +as 2D arrays. This module can also separate the red, green, and blue +color values into separate indices. These types of arrays are referred +to as 3D arrays, and the last index is 0 for red, 1 for green, and 2 for +blue. +""" + + +from pygame.pixelcopy import ( + array_to_surface, + surface_to_array, + map_array as pix_map_array, + make_surface as pix_make_surface, +) +import numpy +from numpy import ( + array as numpy_array, + empty as numpy_empty, + uint32 as numpy_uint32, + ndarray as numpy_ndarray, +) + +import warnings # will be removed in the future + + +# float96 not available on all numpy versions. +numpy_floats = [] +for type_name in "float32 float64 float96".split(): + if hasattr(numpy, type_name): + numpy_floats.append(getattr(numpy, type_name)) +# Added below due to deprecation of numpy.float. See issue #2814 +numpy_floats.append(float) + +# Pixel sizes corresponding to NumPy supported integer sizes, and therefore +# permissible for 2D reference arrays. +_pixel2d_bitdepths = {8, 16, 32} + + +__all__ = [ + "array2d", + "array3d", + "array_alpha", + "array_blue", + "array_colorkey", + "array_green", + "array_red", + "array_to_surface", + "blit_array", + "get_arraytype", + "get_arraytypes", + "make_surface", + "map_array", + "pixels2d", + "pixels3d", + "pixels_alpha", + "pixels_blue", + "pixels_green", + "pixels_red", + "surface_to_array", + "use_arraytype", +] + + +def blit_array(surface, array): + """pygame.surfarray.blit_array(Surface, array): return None + + Blit directly from a array values. + + Directly copy values from an array into a Surface. This is faster than + converting the array into a Surface and blitting. The array must be the + same dimensions as the Surface and will completely replace all pixel + values. Only integer, ascii character and record arrays are accepted. + + This function will temporarily lock the Surface as the new values are + copied. + """ + if isinstance(array, numpy_ndarray) and array.dtype in numpy_floats: + array = array.round(0).astype(numpy_uint32) + return array_to_surface(surface, array) + + +def make_surface(array): + """pygame.surfarray.make_surface (array): return Surface + + Copy an array to a new surface. + + Create a new Surface that best resembles the data and format on the + array. The array can be 2D or 3D with any sized integer values. + """ + if isinstance(array, numpy_ndarray) and array.dtype in numpy_floats: + array = array.round(0).astype(numpy_uint32) + return pix_make_surface(array) + + +def array2d(surface): + """pygame.surfarray.array2d(Surface): return array + + copy pixels into a 2d array + + Copy the pixels from a Surface into a 2D array. The bit depth of the + surface will control the size of the integer values, and will work + for any type of pixel format. + + This function will temporarily lock the Surface as pixels are copied + (see the Surface.lock - lock the Surface memory for pixel access + method). + """ + bpp = surface.get_bytesize() + try: + dtype = (numpy.uint8, numpy.uint16, numpy.int32, numpy.int32)[bpp - 1] + except IndexError: + raise ValueError(f"unsupported bit depth {bpp * 8} for 2D array") + size = surface.get_size() + array = numpy.empty(size, dtype) + surface_to_array(array, surface) + return array + + +def pixels2d(surface): + """pygame.surfarray.pixels2d(Surface): return array + + reference pixels into a 2d array + + Create a new 2D array that directly references the pixel values in a + Surface. Any changes to the array will affect the pixels in the + Surface. This is a fast operation since no data is copied. + + Pixels from a 24-bit Surface cannot be referenced, but all other + Surface bit depths can. + + The Surface this references will remain locked for the lifetime of + the array (see the Surface.lock - lock the Surface memory for pixel + access method). + """ + if surface.get_bitsize() not in _pixel2d_bitdepths: + raise ValueError("unsupport bit depth for 2D reference array") + try: + return numpy_array(surface.get_view("2"), copy=False) + except (ValueError, TypeError): + raise ValueError( + f"bit depth {surface.get_bitsize()} unsupported for 2D reference array" + ) + + +def array3d(surface): + """pygame.surfarray.array3d(Surface): return array + + copy pixels into a 3d array + + Copy the pixels from a Surface into a 3D array. The bit depth of the + surface will control the size of the integer values, and will work + for any type of pixel format. + + This function will temporarily lock the Surface as pixels are copied + (see the Surface.lock - lock the Surface memory for pixel access + method). + """ + width, height = surface.get_size() + array = numpy.empty((width, height, 3), numpy.uint8) + surface_to_array(array, surface) + return array + + +def pixels3d(surface): + """pygame.surfarray.pixels3d(Surface): return array + + reference pixels into a 3d array + + Create a new 3D array that directly references the pixel values in a + Surface. Any changes to the array will affect the pixels in the + Surface. This is a fast operation since no data is copied. + + This will only work on Surfaces that have 24-bit or 32-bit + formats. Lower pixel formats cannot be referenced. + + The Surface this references will remain locked for the lifetime of + the array (see the Surface.lock - lock the Surface memory for pixel + access method). + """ + return numpy_array(surface.get_view("3"), copy=False) + + +def array_alpha(surface): + """pygame.surfarray.array_alpha(Surface): return array + + copy pixel alphas into a 2d array + + Copy the pixel alpha values (degree of transparency) from a Surface + into a 2D array. This will work for any type of Surface + format. Surfaces without a pixel alpha will return an array with all + opaque values. + + This function will temporarily lock the Surface as pixels are copied + (see the Surface.lock - lock the Surface memory for pixel access + method). + """ + size = surface.get_size() + array = numpy.empty(size, numpy.uint8) + surface_to_array(array, surface, "A") + return array + + +def pixels_alpha(surface): + """pygame.surfarray.pixels_alpha(Surface): return array + + reference pixel alphas into a 2d array + + Create a new 2D array that directly references the alpha values + (degree of transparency) in a Surface. Any changes to the array will + affect the pixels in the Surface. This is a fast operation since no + data is copied. + + This can only work on 32-bit Surfaces with a per-pixel alpha value. + + The Surface this array references will remain locked for the + lifetime of the array. + """ + return numpy.array(surface.get_view("A"), copy=False) + + +def pixels_red(surface): + """pygame.surfarray.pixels_red(Surface): return array + + Reference pixel red into a 2d array. + + Create a new 2D array that directly references the red values + in a Surface. Any changes to the array will affect the pixels + in the Surface. This is a fast operation since no data is copied. + + This can only work on 24-bit or 32-bit Surfaces. + + The Surface this array references will remain locked for the + lifetime of the array. + """ + return numpy.array(surface.get_view("R"), copy=False) + + +def array_red(surface): + """pygame.surfarray.array_red(Surface): return array + + copy pixel red into a 2d array + + Copy the pixel red values from a Surface into a 2D array. This will work + for any type of Surface format. + + This function will temporarily lock the Surface as pixels are copied + (see the Surface.lock - lock the Surface memory for pixel access + method). + """ + size = surface.get_size() + array = numpy.empty(size, numpy.uint8) + surface_to_array(array, surface, "R") + return array + + +def pixels_green(surface): + """pygame.surfarray.pixels_green(Surface): return array + + Reference pixel green into a 2d array. + + Create a new 2D array that directly references the green values + in a Surface. Any changes to the array will affect the pixels + in the Surface. This is a fast operation since no data is copied. + + This can only work on 24-bit or 32-bit Surfaces. + + The Surface this array references will remain locked for the + lifetime of the array. + """ + return numpy.array(surface.get_view("G"), copy=False) + + +def array_green(surface): + """pygame.surfarray.array_green(Surface): return array + + copy pixel green into a 2d array + + Copy the pixel green values from a Surface into a 2D array. This will work + for any type of Surface format. + + This function will temporarily lock the Surface as pixels are copied + (see the Surface.lock - lock the Surface memory for pixel access + method). + """ + size = surface.get_size() + array = numpy.empty(size, numpy.uint8) + surface_to_array(array, surface, "G") + return array + + +def pixels_blue(surface): + """pygame.surfarray.pixels_blue(Surface): return array + + Reference pixel blue into a 2d array. + + Create a new 2D array that directly references the blue values + in a Surface. Any changes to the array will affect the pixels + in the Surface. This is a fast operation since no data is copied. + + This can only work on 24-bit or 32-bit Surfaces. + + The Surface this array references will remain locked for the + lifetime of the array. + """ + return numpy.array(surface.get_view("B"), copy=False) + + +def array_blue(surface): + """pygame.surfarray.array_blue(Surface): return array + + copy pixel blue into a 2d array + + Copy the pixel blue values from a Surface into a 2D array. This will work + for any type of Surface format. + + This function will temporarily lock the Surface as pixels are copied + (see the Surface.lock - lock the Surface memory for pixel access + method). + """ + size = surface.get_size() + array = numpy.empty(size, numpy.uint8) + surface_to_array(array, surface, "B") + return array + + +def array_colorkey(surface): + """pygame.surfarray.array_colorkey(Surface): return array + + copy the colorkey values into a 2d array + + Create a new array with the colorkey transparency value from each + pixel. If the pixel matches the colorkey it will be fully + tranparent; otherwise it will be fully opaque. + + This will work on any type of Surface format. If the image has no + colorkey a solid opaque array will be returned. + + This function will temporarily lock the Surface as pixels are + copied. + """ + size = surface.get_size() + array = numpy.empty(size, numpy.uint8) + surface_to_array(array, surface, "C") + return array + + +def map_array(surface, array): + """pygame.surfarray.map_array(Surface, array3d): return array2d + + map a 3d array into a 2d array + + Convert a 3D array into a 2D array. This will use the given Surface + format to control the conversion. + + Note: arrays do not need to be 3D, as long as the minor axis has + three elements giving the component colours, any array shape can be + used (for example, a single colour can be mapped, or an array of + colours). The array shape is limited to eleven dimensions maximum, + including the three element minor axis. + """ + if array.ndim == 0: + raise ValueError("array must have at least 1 dimension") + shape = array.shape + if shape[-1] != 3: + raise ValueError("array must be a 3d array of 3-value color data") + target = numpy_empty(shape[:-1], numpy.int32) + pix_map_array(target, array, surface) + return target + + +def use_arraytype(arraytype): + """pygame.surfarray.use_arraytype(arraytype): return None + + DEPRECATED - only numpy arrays are now supported. + """ + warnings.warn( + DeprecationWarning( + "only numpy arrays are now supported, " + "this function will be removed in a " + "future version of the module" + ) + ) + arraytype = arraytype.lower() + if arraytype != "numpy": + raise ValueError("invalid array type") + + +def get_arraytype(): + """pygame.surfarray.get_arraytype(): return str + + DEPRECATED - only numpy arrays are now supported. + """ + warnings.warn( + DeprecationWarning( + "only numpy arrays are now supported, " + "this function will be removed in a " + "future version of the module" + ) + ) + return "numpy" + + +def get_arraytypes(): + """pygame.surfarray.get_arraytypes(): return tuple + + DEPRECATED - only numpy arrays are now supported. + """ + warnings.warn( + DeprecationWarning( + "only numpy arrays are now supported, " + "this function will be removed in a " + "future version of the module" + ) + ) + return ("numpy",) diff --git a/venv/Lib/site-packages/pygame/surfarray.pyi b/venv/Lib/site-packages/pygame/surfarray.pyi new file mode 100644 index 0000000..33d7dbb --- /dev/null +++ b/venv/Lib/site-packages/pygame/surfarray.pyi @@ -0,0 +1,25 @@ +from typing import Tuple + +import numpy + +from pygame.surface import Surface + +def array2d(surface: Surface) -> numpy.ndarray: ... +def pixels2d(surface: Surface) -> numpy.ndarray: ... +def array3d(surface: Surface) -> numpy.ndarray: ... +def pixels3d(surface: Surface) -> numpy.ndarray: ... +def array_alpha(surface: Surface) -> numpy.ndarray: ... +def pixels_alpha(surface: Surface) -> numpy.ndarray: ... +def array_red(surface: Surface) -> numpy.ndarray: ... +def pixels_red(surface: Surface) -> numpy.ndarray: ... +def array_green(surface: Surface) -> numpy.ndarray: ... +def pixels_green(surface: Surface) -> numpy.ndarray: ... +def array_blue(surface: Surface) -> numpy.ndarray: ... +def pixels_blue(surface: Surface) -> numpy.ndarray: ... +def array_colorkey(surface: Surface) -> numpy.ndarray: ... +def make_surface(array: numpy.ndarray) -> Surface: ... +def blit_array(surface: Surface, array: numpy.ndarray) -> None: ... +def map_array(surface: Surface, array3d: numpy.ndarray) -> numpy.ndarray: ... +def use_arraytype(arraytype: str) -> None: ... +def get_arraytype() -> str: ... +def get_arraytypes() -> Tuple[str]: ... diff --git a/venv/Lib/site-packages/pygame/sysfont.py b/venv/Lib/site-packages/pygame/sysfont.py new file mode 100644 index 0000000..588a5b5 --- /dev/null +++ b/venv/Lib/site-packages/pygame/sysfont.py @@ -0,0 +1,529 @@ +# coding: ascii +# pygame - Python Game Library +# Copyright (C) 2000-2003 Pete Shinners +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Pete Shinners +# pete@shinners.org +"""sysfont, used in the font module to find system fonts""" + +import os +import sys +from os.path import basename, dirname, exists, join, splitext + +from pygame.font import Font + + +OpenType_extensions = frozenset((".ttf", ".ttc", ".otf")) +Sysfonts = {} +Sysalias = {} + +# Python 3 compatibility + + +def toascii(raw): + """convert bytes to ASCII-only string""" + return raw.decode("ascii", "ignore") + + +if os.name == "nt": + import winreg as _winreg +else: + import subprocess + + +def _simplename(name): + """create simple version of the font name""" + # return alphanumeric characters of a string (converted to lowercase) + return "".join(c.lower() for c in name if c.isalnum()) + + +def _addfont(name, bold, italic, font, fontdict): + """insert a font and style into the font dictionary""" + if name not in fontdict: + fontdict[name] = {} + fontdict[name][bold, italic] = font + + +def initsysfonts_win32(): + """initialize fonts dictionary on Windows""" + + fontdir = join(os.environ.get("WINDIR", "C:\\Windows"), "Fonts") + + fonts = {} + + # add fonts entered in the registry + + # find valid registry keys containing font information. + # http://docs.python.org/lib/module-sys.html + # 0 (VER_PLATFORM_WIN32s) Win32s on Windows 3.1 + # 1 (VER_PLATFORM_WIN32_WINDOWS) Windows 95/98/ME + # 2 (VER_PLATFORM_WIN32_NT) Windows NT/2000/XP + # 3 (VER_PLATFORM_WIN32_CE) Windows CE + if sys.getwindowsversion()[0] == 1: + key_name = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts" + else: + key_name = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts" + key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, key_name) + + for i in range(_winreg.QueryInfoKey(key)[1]): + try: + # name is the font's name e.g. Times New Roman (TrueType) + # font is the font's filename e.g. times.ttf + name, font = _winreg.EnumValue(key, i)[0:2] + except EnvironmentError: + break + + # try to handle windows unicode strings for file names with + # international characters + + # here are two documents with some information about it: + # http://www.python.org/peps/pep-0277.html + # https://www.microsoft.com/technet/archive/interopmigration/linux/mvc/lintowin.mspx#ECAA + try: + font = str(font) + except UnicodeEncodeError: + # MBCS is the windows encoding for unicode file names. + try: + font = font.encode("MBCS") + except UnicodeEncodeError: + # no success with str or MBCS encoding... skip this font. + continue + + if splitext(font)[1].lower() not in OpenType_extensions: + continue + if not dirname(font): + font = join(fontdir, font) + + # Some are named A & B, both names should be processed separately + # Ex: the main Cambria file is marked as "Cambria & Cambria Math" + for name in name.split("&"): + _parse_font_entry_win(name, font, fonts) + + return fonts + + +def _parse_font_entry_win(name, font, fonts): + """ + Parse out a simpler name and the font style from the initial file name. + + :param name: The font name + :param font: The font file path + :param fonts: The pygame font dictionary + + :return: Tuple of (bold, italic, name) + """ + true_type_suffix = "(TrueType)" + mods = ("demibold", "narrow", "light", "unicode", "bt", "mt") + if name.endswith(true_type_suffix): + name = name.rstrip(true_type_suffix).rstrip() + name = name.lower().split() + bold = italic = False + for mod in mods: + if mod in name: + name.remove(mod) + if "bold" in name: + name.remove("bold") + bold = True + if "italic" in name: + name.remove("italic") + italic = True + name = "".join(name) + name = _simplename(name) + + _addfont(name, bold, italic, font, fonts) + + +def _parse_font_entry_darwin(name, filepath, fonts): + """ + Parses a font entry for macOS + + :param name: The filepath without extensions or directories + :param filepath: The full path to the font + :param fonts: The pygame font dictionary to add the parsed font data to. + """ + + name = _simplename(name) + + mods = ("regular",) + + for mod in mods: + if mod in name: + name = name.replace(mod, "") + + bold = italic = False + if "bold" in name: + name = name.replace("bold", "") + bold = True + if "italic" in name: + name = name.replace("italic", "") + italic = True + + _addfont(name, bold, italic, filepath, fonts) + + +def _font_finder_darwin(): + locations = [ + "/Library/Fonts", + "/Network/Library/Fonts", + "/System/Library/Fonts", + "/System/Library/Fonts/Supplemental", + ] + + username = os.getenv("USER") + if username: + locations.append("/Users/" + username + "/Library/Fonts") + + strange_root = "/System/Library/Assets/com_apple_MobileAsset_Font3" + if exists(strange_root): + strange_locations = os.listdir(strange_root) + for loc in strange_locations: + locations.append(strange_root + "/" + loc + "/AssetData") + + fonts = {} + + for location in locations: + if not exists(location): + continue + + files = os.listdir(location) + for file in files: + name, extension = splitext(file) + if extension in OpenType_extensions: + _parse_font_entry_darwin(name, join(location, file), fonts) + + return fonts + + +def initsysfonts_darwin(): + """Read the fonts on MacOS, and OS X.""" + # if the X11 binary exists... try and use that. + # Not likely to be there on pre 10.4.x ... or MacOS 10.10+ + if exists("/usr/X11/bin/fc-list"): + fonts = initsysfonts_unix("/usr/X11/bin/fc-list") + # This fc-list path will work with the X11 from the OS X 10.3 installation + # disc + elif exists("/usr/X11R6/bin/fc-list"): + fonts = initsysfonts_unix("/usr/X11R6/bin/fc-list") + else: + # eventually this should probably be the preferred solution + fonts = _font_finder_darwin() + + return fonts + + +# read the fonts on unix +def initsysfonts_unix(path="fc-list"): + """use the fc-list from fontconfig to get a list of fonts""" + fonts = {} + + try: + # pylint: disable=consider-using-with + # subprocess.Popen is not a context manager in all of + # pygame's supported python versions. + + # note, we capture stderr so if fc-list isn't there to stop stderr + # printing. + flout, _ = subprocess.Popen( + f"{path} : file family style", + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + close_fds=True, + ).communicate() + except (OSError, ValueError): + return fonts + + entries = toascii(flout) + try: + for entry in entries.split("\n"): + + try: + _parse_font_entry_unix(entry, fonts) + except ValueError: + # try the next one. + pass + + except ValueError: + pass + + return fonts + + +def _parse_font_entry_unix(entry, fonts): + """ + Parses an entry in the unix font data to add to the pygame font + dictionary. + + :param entry: A entry from the unix font list. + :param fonts: The pygame font dictionary to add the parsed font data to. + + """ + filename, family, style = entry.split(":", 2) + if splitext(filename)[1].lower() in OpenType_extensions: + bold = "Bold" in style + italic = "Italic" in style + oblique = "Oblique" in style + for name in family.strip().split(","): + if name: + break + else: + name = splitext(basename(filename))[0] + + _addfont(_simplename(name), bold, italic or oblique, filename, fonts) + + +def create_aliases(): + """Map common fonts that are absent from the system to similar fonts + that are installed in the system + """ + alias_groups = ( + ( + "monospace", + "misc-fixed", + "courier", + "couriernew", + "console", + "fixed", + "mono", + "freemono", + "bitstreamverasansmono", + "verasansmono", + "monotype", + "lucidaconsole", + "consolas", + "dejavusansmono", + "liberationmono", + ), + ( + "sans", + "arial", + "helvetica", + "swiss", + "freesans", + "bitstreamverasans", + "verasans", + "verdana", + "tahoma", + "calibri", + "gillsans", + "segoeui", + "trebuchetms", + "ubuntu", + "dejavusans", + "liberationsans", + ), + ( + "serif", + "times", + "freeserif", + "bitstreamveraserif", + "roman", + "timesroman", + "timesnewroman", + "dutch", + "veraserif", + "georgia", + "cambria", + "constantia", + "dejavuserif", + "liberationserif", + ), + ("wingdings", "wingbats"), + ("comicsansms", "comicsans"), + ) + for alias_set in alias_groups: + for name in alias_set: + if name in Sysfonts: + found = Sysfonts[name] + break + else: + continue + for name in alias_set: + if name not in Sysfonts: + Sysalias[name] = found + + +def initsysfonts(): + """ + Initialise the sysfont module, called once. Locates the installed fonts + and creates some aliases for common font categories. + + Has different initialisation functions for different platforms. + """ + if sys.platform == "win32": + fonts = initsysfonts_win32() + elif sys.platform == "darwin": + fonts = initsysfonts_darwin() + else: + fonts = initsysfonts_unix() + Sysfonts.update(fonts) + create_aliases() + if not Sysfonts: # dummy so we don't try to reinit + Sysfonts[None] = None + + +def font_constructor(fontpath, size, bold, italic): + """ + pygame.font specific declarations + + :param fontpath: path to a font. + :param size: size of a font. + :param bold: bold style, True or False. + :param italic: italic style, True or False. + + :return: A font.Font object. + """ + + font = Font(fontpath, size) + if bold: + font.set_bold(True) + if italic: + font.set_italic(True) + + return font + + +# the exported functions + + +def SysFont(name, size, bold=False, italic=False, constructor=None): + """pygame.font.SysFont(name, size, bold=False, italic=False, constructor=None) -> Font + Create a pygame Font from system font resources. + + This will search the system fonts for the given font + name. You can also enable bold or italic styles, and + the appropriate system font will be selected if available. + + This will always return a valid Font object, and will + fallback on the builtin pygame font if the given font + is not found. + + Name can also be an iterable of font names, a string of + comma-separated font names, or a bytes of comma-separated + font names, in which case the set of names will be searched + in order. Pygame uses a small set of common font aliases. If the + specific font you ask for is not available, a reasonable + alternative may be used. + + If optional constructor is provided, it must be a function with + signature constructor(fontpath, size, bold, italic) which returns + a Font instance. If None, a pygame.font.Font object is created. + """ + if constructor is None: + constructor = font_constructor + + if not Sysfonts: + initsysfonts() + + gotbold = gotitalic = False + fontname = None + if name: + if isinstance(name, (str, bytes)): + name = name.split(b"," if isinstance(name, bytes) else ",") + for single_name in name: + if isinstance(single_name, bytes): + single_name = single_name.decode() + + single_name = _simplename(single_name) + styles = Sysfonts.get(single_name) + if not styles: + styles = Sysalias.get(single_name) + if styles: + plainname = styles.get((False, False)) + fontname = styles.get((bold, italic)) + if not (fontname or plainname): + # Neither requested style, nor plain font exists, so + # return a font with the name requested, but an + # arbitrary style. + (style, fontname) = list(styles.items())[0] + # Attempt to style it as requested. This can't + # unbold or unitalicize anything, but it can + # fake bold and/or fake italicize. + if bold and style[0]: + gotbold = True + if italic and style[1]: + gotitalic = True + elif not fontname: + fontname = plainname + elif plainname != fontname: + gotbold = bold + gotitalic = italic + if fontname: + break + + set_bold = set_italic = False + if bold and not gotbold: + set_bold = True + if italic and not gotitalic: + set_italic = True + + return constructor(fontname, size, set_bold, set_italic) + + +def get_fonts(): + """pygame.font.get_fonts() -> list + get a list of system font names + + Returns the list of all found system fonts. Note that + the names of the fonts will be all lowercase with spaces + removed. This is how pygame internally stores the font + names for matching. + """ + if not Sysfonts: + initsysfonts() + return list(Sysfonts) + + +def match_font(name, bold=0, italic=0): + """pygame.font.match_font(name, bold=0, italic=0) -> name + find the filename for the named system font + + This performs the same font search as the SysFont() + function, only it returns the path to the TTF file + that would be loaded. The font name can also be an + iterable of font names or a string/bytes of comma-separated + font names to try. + + If no match is found, None is returned. + """ + if not Sysfonts: + initsysfonts() + + fontname = None + if isinstance(name, (str, bytes)): + name = name.split(b"," if isinstance(name, bytes) else ",") + + for single_name in name: + if isinstance(single_name, bytes): + single_name = single_name.decode() + + single_name = _simplename(single_name) + styles = Sysfonts.get(single_name) + if not styles: + styles = Sysalias.get(single_name) + if styles: + while not fontname: + fontname = styles.get((bold, italic)) + if italic: + italic = 0 + elif bold: + bold = 0 + elif not fontname: + fontname = list(styles.values())[0] + if fontname: + break + return fontname diff --git a/venv/Lib/site-packages/pygame/tests/__init__.py b/venv/Lib/site-packages/pygame/tests/__init__.py new file mode 100644 index 0000000..dd26586 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/__init__.py @@ -0,0 +1,40 @@ +"""Pygame unit test suite package + +Exports function run() + +A quick way to run the test suite package from the command line +is by importing the go submodule: + +python -m "import pygame.tests" [] + +Command line option --help displays a usage message. Available options +correspond to the pygame.tests.run arguments. + +The xxxx_test submodules of the tests package are unit test suites for +individual parts of Pygame. Each can also be run as a main program. This is +useful if the test, such as cdrom_test, is interactive. + +For Pygame development the test suite can be run from a Pygame distribution +root directory using run_tests.py. Alternately, test/__main__.py can be run +directly. + +""" + +if __name__ == "pygame.tests": + from pygame.tests.test_utils.run_tests import run +elif __name__ == "__main__": + import os + import sys + + pkg_dir = os.path.split(os.path.abspath(__file__))[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) + + if is_pygame_pkg: + import pygame.tests.__main__ + else: + import test.__main__ +else: + from test.test_utils.run_tests import run diff --git a/venv/Lib/site-packages/pygame/tests/__main__.py b/venv/Lib/site-packages/pygame/tests/__main__.py new file mode 100644 index 0000000..abdd92e --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/__main__.py @@ -0,0 +1,144 @@ +"""Load and run the Pygame test suite + +python -c "import pygame.tests.go" [] + +or + +python test/go.py [] + +Command line option --help displays a command line usage message. + +run_tests.py in the main distribution directory is an alternative to test.go + +""" + +import sys + +if __name__ == "__main__": + import os + + pkg_dir = os.path.split(os.path.abspath(__file__))[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +if is_pygame_pkg: + from pygame.tests.test_utils.run_tests import run_and_exit + from pygame.tests.test_utils.test_runner import opt_parser +else: + from test.test_utils.run_tests import run_and_exit + from test.test_utils.test_runner import opt_parser + +if is_pygame_pkg: + test_pkg_name = "pygame.tests" +else: + test_pkg_name = "test" +program_name = sys.argv[0] +if program_name == "-c": + program_name = 'python -c "import %s.go"' % test_pkg_name + +########################################################################### +# Set additional command line options +# +# Defined in test_runner.py as it shares options, added to here + +opt_parser.set_usage( + """ + +Runs all or some of the %(pkg)s.xxxx_test tests. + +$ %(exec)s sprite threads -sd + +Runs the sprite and threads module tests isolated in subprocesses, dumping +all failing tests info in the form of a dict. + +""" + % {"pkg": test_pkg_name, "exec": program_name} +) + +opt_parser.add_option( + "-d", "--dump", action="store_true", help="dump results as dict ready to eval" +) + +opt_parser.add_option("-F", "--file", help="dump results to a file") + +opt_parser.add_option( + "-m", + "--multi_thread", + metavar="THREADS", + type="int", + help="run subprocessed tests in x THREADS", +) + +opt_parser.add_option( + "-t", + "--time_out", + metavar="SECONDS", + type="int", + help="kill stalled subprocessed tests after SECONDS", +) + +opt_parser.add_option( + "-f", "--fake", metavar="DIR", help="run fake tests in run_tests__tests/$DIR" +) + +opt_parser.add_option( + "-p", + "--python", + metavar="PYTHON", + help="path to python excutable to run subproccesed tests\n" + "default (sys.executable): %s" % sys.executable, +) + +opt_parser.add_option( + "-I", + "--interactive", + action="store_true", + help="include tests requiring user input", +) + +opt_parser.add_option("-S", "--seed", type="int", help="Randomisation seed") + +########################################################################### +# Set run() keyword arguements according to command line arguemnts. +# args will be the test module list, passed as positional argumemts. + +options, args = opt_parser.parse_args() +kwds = {} +if options.incomplete: + kwds["incomplete"] = True +if options.usesubprocess: + kwds["usesubprocess"] = True +else: + kwds["usesubprocess"] = False +if options.dump: + kwds["dump"] = True +if options.file: + kwds["file"] = options.file +if options.exclude: + kwds["exclude"] = options.exclude +if options.unbuffered: + kwds["unbuffered"] = True +if options.randomize: + kwds["randomize"] = True +if options.seed is not None: + kwds["seed"] = options.seed +if options.multi_thread is not None: + kwds["multi_thread"] = options.multi_thread +if options.time_out is not None: + kwds["time_out"] = options.time_out +if options.fake: + kwds["fake"] = options.fake +if options.python: + kwds["python"] = options.python +if options.interactive: + kwds["interactive"] = True +kwds["verbosity"] = options.verbosity if options.verbosity is not None else 1 + + +########################################################################### +# Run the test suite. +run_and_exit(*args, **kwds) diff --git a/venv/Lib/site-packages/pygame/tests/base_test.py b/venv/Lib/site-packages/pygame/tests/base_test.py new file mode 100644 index 0000000..7b7d64a --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/base_test.py @@ -0,0 +1,635 @@ +# -*- coding: utf8 -*- + +import sys +import unittest + +import platform + +IS_PYPY = "PyPy" == platform.python_implementation() + +try: + from pygame.tests.test_utils import arrinter +except NameError: + pass +import pygame + + +quit_count = 0 + + +def quit_hook(): + global quit_count + quit_count += 1 + + +class BaseModuleTest(unittest.TestCase): + def tearDown(self): + # Clean up after each test method. + pygame.quit() + + def test_get_sdl_byteorder(self): + """Ensure the SDL byte order is valid""" + byte_order = pygame.get_sdl_byteorder() + expected_options = (pygame.LIL_ENDIAN, pygame.BIG_ENDIAN) + + self.assertIn(byte_order, expected_options) + + def test_get_sdl_version(self): + """Ensure the SDL version is valid""" + self.assertEqual(len(pygame.get_sdl_version()), 3) + + class ExporterBase(object): + def __init__(self, shape, typechar, itemsize): + import ctypes + + ndim = len(shape) + self.ndim = ndim + self.shape = tuple(shape) + array_len = 1 + for d in shape: + array_len *= d + self.size = itemsize * array_len + self.parent = ctypes.create_string_buffer(self.size) + self.itemsize = itemsize + strides = [itemsize] * ndim + for i in range(ndim - 1, 0, -1): + strides[i - 1] = strides[i] * shape[i] + self.strides = tuple(strides) + self.data = ctypes.addressof(self.parent), False + if self.itemsize == 1: + byteorder = "|" + elif sys.byteorder == "big": + byteorder = ">" + else: + byteorder = "<" + self.typestr = byteorder + typechar + str(self.itemsize) + + def assertSame(self, proxy, obj): + self.assertEqual(proxy.length, obj.size) + iface = proxy.__array_interface__ + self.assertEqual(iface["typestr"], obj.typestr) + self.assertEqual(iface["shape"], obj.shape) + self.assertEqual(iface["strides"], obj.strides) + self.assertEqual(iface["data"], obj.data) + + def test_PgObject_GetBuffer_array_interface(self): + from pygame.bufferproxy import BufferProxy + + class Exporter(self.ExporterBase): + def get__array_interface__(self): + return { + "version": 3, + "typestr": self.typestr, + "shape": self.shape, + "strides": self.strides, + "data": self.data, + } + + __array_interface__ = property(get__array_interface__) + # Should be ignored by PgObject_GetBuffer + __array_struct__ = property(lambda self: None) + + _shape = [2, 3, 5, 7, 11] # Some prime numbers + for ndim in range(1, len(_shape)): + o = Exporter(_shape[0:ndim], "i", 2) + v = BufferProxy(o) + self.assertSame(v, o) + ndim = 2 + shape = _shape[0:ndim] + for typechar in ("i", "u"): + for itemsize in (1, 2, 4, 8): + o = Exporter(shape, typechar, itemsize) + v = BufferProxy(o) + self.assertSame(v, o) + for itemsize in (4, 8): + o = Exporter(shape, "f", itemsize) + v = BufferProxy(o) + self.assertSame(v, o) + + # Is the dict received from an exporting object properly released? + # The dict should be freed before PgObject_GetBuffer returns. + # When the BufferProxy v's length property is referenced, v calls + # PgObject_GetBuffer, which in turn references Exporter2 o's + # __array_interface__ property. The Exporter2 instance o returns a + # dict subclass for which it keeps both a regular reference and a + # weak reference. The regular reference should be the only + # remaining reference when PgObject_GetBuffer returns. This is + # verified by first checking the weak reference both before and + # after the regular reference held by o is removed. + + import weakref, gc + + class NoDictError(RuntimeError): + pass + + class WRDict(dict): + """Weak referenceable dict""" + + pass + + class Exporter2(Exporter): + def get__array_interface__2(self): + self.d = WRDict(Exporter.get__array_interface__(self)) + self.dict_ref = weakref.ref(self.d) + return self.d + + __array_interface__ = property(get__array_interface__2) + + def free_dict(self): + self.d = None + + def is_dict_alive(self): + try: + return self.dict_ref() is not None + except AttributeError: + raise NoDictError("__array_interface__ is unread") + + o = Exporter2((2, 4), "u", 4) + v = BufferProxy(o) + self.assertRaises(NoDictError, o.is_dict_alive) + length = v.length + self.assertTrue(o.is_dict_alive()) + o.free_dict() + gc.collect() + self.assertFalse(o.is_dict_alive()) + + def test_GetView_array_struct(self): + from pygame.bufferproxy import BufferProxy + + class Exporter(self.ExporterBase): + def __init__(self, shape, typechar, itemsize): + super(Exporter, self).__init__(shape, typechar, itemsize) + self.view = BufferProxy(self.__dict__) + + def get__array_struct__(self): + return self.view.__array_struct__ + + __array_struct__ = property(get__array_struct__) + # Should not cause PgObject_GetBuffer to fail + __array_interface__ = property(lambda self: None) + + _shape = [2, 3, 5, 7, 11] # Some prime numbers + for ndim in range(1, len(_shape)): + o = Exporter(_shape[0:ndim], "i", 2) + v = BufferProxy(o) + self.assertSame(v, o) + ndim = 2 + shape = _shape[0:ndim] + for typechar in ("i", "u"): + for itemsize in (1, 2, 4, 8): + o = Exporter(shape, typechar, itemsize) + v = BufferProxy(o) + self.assertSame(v, o) + for itemsize in (4, 8): + o = Exporter(shape, "f", itemsize) + v = BufferProxy(o) + self.assertSame(v, o) + + # Check returned cobject/capsule reference count + try: + from sys import getrefcount + except ImportError: + # PyPy: no reference counting + pass + else: + o = Exporter(shape, typechar, itemsize) + self.assertEqual(getrefcount(o.__array_struct__), 1) + + if pygame.HAVE_NEWBUF: + from pygame.tests.test_utils import buftools + + def NEWBUF_assertSame(self, proxy, exp): + buftools = self.buftools + Importer = buftools.Importer + self.assertEqual(proxy.length, exp.len) + imp = Importer(proxy, buftools.PyBUF_RECORDS_RO) + self.assertEqual(imp.readonly, exp.readonly) + self.assertEqual(imp.format, exp.format) + self.assertEqual(imp.itemsize, exp.itemsize) + self.assertEqual(imp.ndim, exp.ndim) + self.assertEqual(imp.shape, exp.shape) + self.assertEqual(imp.strides, exp.strides) + self.assertTrue(imp.suboffsets is None) + + @unittest.skipIf(not pygame.HAVE_NEWBUF, "newbuf not implemented") + @unittest.skipIf(IS_PYPY, "pypy no likey") + def test_newbuf(self): + from pygame.bufferproxy import BufferProxy + + Exporter = self.buftools.Exporter + _shape = [2, 3, 5, 7, 11] # Some prime numbers + for ndim in range(1, len(_shape)): + o = Exporter(_shape[0:ndim], "=h") + v = BufferProxy(o) + self.NEWBUF_assertSame(v, o) + ndim = 2 + shape = _shape[0:ndim] + for format in [ + "b", + "B", + "=h", + "=H", + "=i", + "=I", + "=q", + "=Q", + "f", + "d", + "1h", + "=1h", + "x", + "1x", + "2x", + "3x", + "4x", + "5x", + "6x", + "7x", + "8x", + "9x", + ]: + o = Exporter(shape, format) + v = BufferProxy(o) + self.NEWBUF_assertSame(v, o) + + @unittest.skipIf(not pygame.HAVE_NEWBUF, "newbuf not implemented") + def test_bad_format(self): + from pygame.bufferproxy import BufferProxy + from pygame.newbuffer import BufferMixin + from ctypes import create_string_buffer, addressof + + buftools = self.buftools + Exporter = buftools.Exporter + Importer = buftools.Importer + PyBUF_FORMAT = buftools.PyBUF_FORMAT + + for format in [ + "", + "=", + "1", + " ", + "2h", + "=2h", + "0x", + "11x", + "=!", + "h ", + " h", + "hh", + "?", + ]: + exp = Exporter((1,), format, itemsize=2) + b = BufferProxy(exp) + self.assertRaises(ValueError, Importer, b, PyBUF_FORMAT) + + @unittest.skipIf(not pygame.HAVE_NEWBUF, "newbuf not implemented") + @unittest.skipIf(IS_PYPY, "fails on pypy") + def test_PgDict_AsBuffer_PyBUF_flags(self): + from pygame.bufferproxy import BufferProxy + + is_lil_endian = pygame.get_sdl_byteorder() == pygame.LIL_ENDIAN + fsys, frev = ("<", ">") if is_lil_endian else (">", "<") + buftools = self.buftools + Importer = buftools.Importer + a = BufferProxy( + {"typestr": "|u4", "shape": (10, 2), "data": (9, False)} + ) # 9? No data accesses. + b = Importer(a, buftools.PyBUF_SIMPLE) + self.assertEqual(b.ndim, 0) + self.assertTrue(b.format is None) + self.assertEqual(b.len, a.length) + self.assertEqual(b.itemsize, 4) + self.assertTrue(b.shape is None) + self.assertTrue(b.strides is None) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, 9) + b = Importer(a, buftools.PyBUF_WRITABLE) + self.assertEqual(b.ndim, 0) + self.assertTrue(b.format is None) + self.assertEqual(b.len, a.length) + self.assertEqual(b.itemsize, 4) + self.assertTrue(b.shape is None) + self.assertTrue(b.strides is None) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, 9) + b = Importer(a, buftools.PyBUF_ND) + self.assertEqual(b.ndim, 2) + self.assertTrue(b.format is None) + self.assertEqual(b.len, a.length) + self.assertEqual(b.itemsize, 4) + self.assertEqual(b.shape, (10, 2)) + self.assertTrue(b.strides is None) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, 9) + a = BufferProxy( + { + "typestr": fsys + "i2", + "shape": (5, 10), + "strides": (24, 2), + "data": (42, False), + } + ) # 42? No data accesses. + b = Importer(a, buftools.PyBUF_STRIDES) + self.assertEqual(b.ndim, 2) + self.assertTrue(b.format is None) + self.assertEqual(b.len, 100) + self.assertEqual(b.itemsize, 2) + self.assertEqual(b.shape, (5, 10)) + self.assertEqual(b.strides, (24, 2)) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, 42) + b = Importer(a, buftools.PyBUF_FULL_RO) + self.assertEqual(b.ndim, 2) + self.assertEqual(b.format, "=h") + self.assertEqual(b.len, 100) + self.assertEqual(b.itemsize, 2) + self.assertEqual(b.shape, (5, 10)) + self.assertEqual(b.strides, (24, 2)) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, 42) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_SIMPLE) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ND) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_C_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_F_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ANY_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_CONTIG) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_SIMPLE) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ND) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_C_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_F_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ANY_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_CONTIG) + a = BufferProxy( + { + "typestr": frev + "i2", + "shape": (3, 5, 10), + "strides": (120, 24, 2), + "data": (1000000, True), + } + ) # 1000000? No data accesses. + b = Importer(a, buftools.PyBUF_FULL_RO) + self.assertEqual(b.ndim, 3) + self.assertEqual(b.format, frev + "h") + self.assertEqual(b.len, 300) + self.assertEqual(b.itemsize, 2) + self.assertEqual(b.shape, (3, 5, 10)) + self.assertEqual(b.strides, (120, 24, 2)) + self.assertTrue(b.suboffsets is None) + self.assertTrue(b.readonly) + self.assertEqual(b.buf, 1000000) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_FULL) + + @unittest.skipIf(IS_PYPY or (not pygame.HAVE_NEWBUF), "newbuf with ctypes") + def test_PgObject_AsBuffer_PyBUF_flags(self): + from pygame.bufferproxy import BufferProxy + import ctypes + + is_lil_endian = pygame.get_sdl_byteorder() == pygame.LIL_ENDIAN + fsys, frev = ("<", ">") if is_lil_endian else (">", "<") + buftools = self.buftools + Importer = buftools.Importer + e = arrinter.Exporter( + (10, 2), typekind="f", itemsize=ctypes.sizeof(ctypes.c_double) + ) + a = BufferProxy(e) + b = Importer(a, buftools.PyBUF_SIMPLE) + self.assertEqual(b.ndim, 0) + self.assertTrue(b.format is None) + self.assertEqual(b.len, e.len) + self.assertEqual(b.itemsize, e.itemsize) + self.assertTrue(b.shape is None) + self.assertTrue(b.strides is None) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, e.data) + b = Importer(a, buftools.PyBUF_WRITABLE) + self.assertEqual(b.ndim, 0) + self.assertTrue(b.format is None) + self.assertEqual(b.len, e.len) + self.assertEqual(b.itemsize, e.itemsize) + self.assertTrue(b.shape is None) + self.assertTrue(b.strides is None) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, e.data) + b = Importer(a, buftools.PyBUF_ND) + self.assertEqual(b.ndim, e.nd) + self.assertTrue(b.format is None) + self.assertEqual(b.len, a.length) + self.assertEqual(b.itemsize, e.itemsize) + self.assertEqual(b.shape, e.shape) + self.assertTrue(b.strides is None) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, e.data) + e = arrinter.Exporter((5, 10), typekind="i", itemsize=2, strides=(24, 2)) + a = BufferProxy(e) + b = Importer(a, buftools.PyBUF_STRIDES) + self.assertEqual(b.ndim, e.nd) + self.assertTrue(b.format is None) + self.assertEqual(b.len, e.len) + self.assertEqual(b.itemsize, e.itemsize) + self.assertEqual(b.shape, e.shape) + self.assertEqual(b.strides, e.strides) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, e.data) + b = Importer(a, buftools.PyBUF_FULL_RO) + self.assertEqual(b.ndim, e.nd) + self.assertEqual(b.format, "=h") + self.assertEqual(b.len, e.len) + self.assertEqual(b.itemsize, e.itemsize) + self.assertEqual(b.shape, e.shape) + self.assertEqual(b.strides, e.strides) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, e.data) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_SIMPLE) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_WRITABLE) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_WRITABLE) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ND) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_C_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_F_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ANY_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_CONTIG) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_SIMPLE) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ND) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_C_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_F_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ANY_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_CONTIG) + e = arrinter.Exporter( + (3, 5, 10), + typekind="i", + itemsize=2, + strides=(120, 24, 2), + flags=arrinter.PAI_ALIGNED, + ) + a = BufferProxy(e) + b = Importer(a, buftools.PyBUF_FULL_RO) + self.assertEqual(b.ndim, e.nd) + self.assertEqual(b.format, frev + "h") + self.assertEqual(b.len, e.len) + self.assertEqual(b.itemsize, e.itemsize) + self.assertEqual(b.shape, e.shape) + self.assertEqual(b.strides, e.strides) + self.assertTrue(b.suboffsets is None) + self.assertTrue(b.readonly) + self.assertEqual(b.buf, e.data) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_FULL) + + def test_PgObject_GetBuffer_exception(self): + # For consistency with surfarray + from pygame.bufferproxy import BufferProxy + + bp = BufferProxy(1) + self.assertRaises(ValueError, getattr, bp, "length") + + def not_init_assertions(self): + self.assertFalse(pygame.get_init(), "pygame shouldn't be initialized") + self.assertFalse(pygame.display.get_init(), "display shouldn't be initialized") + + if "pygame.mixer" in sys.modules: + self.assertFalse(pygame.mixer.get_init(), "mixer shouldn't be initialized") + + if "pygame.font" in sys.modules: + self.assertFalse(pygame.font.get_init(), "init shouldn't be initialized") + + ## !!! TODO : Remove when scrap works for OS X + import platform + + if platform.system().startswith("Darwin"): + return + + try: + self.assertRaises(pygame.error, pygame.scrap.get) + except NotImplementedError: + # Scrap is optional. + pass + + # pygame.cdrom + # pygame.joystick + + def init_assertions(self): + self.assertTrue(pygame.get_init()) + self.assertTrue(pygame.display.get_init()) + + if "pygame.mixer" in sys.modules: + self.assertTrue(pygame.mixer.get_init()) + + if "pygame.font" in sys.modules: + self.assertTrue(pygame.font.get_init()) + + def test_quit__and_init(self): + # __doc__ (as of 2008-06-25) for pygame.base.quit: + + # pygame.quit(): return None + # uninitialize all pygame modules + + # Make sure everything is not init + self.not_init_assertions() + + # Initiate it + pygame.init() + + # Check + self.init_assertions() + + # Quit + pygame.quit() + + # All modules have quit + self.not_init_assertions() + + def test_register_quit(self): + """Ensure that a registered function is called on quit()""" + self.assertEqual(quit_count, 0) + + pygame.init() + pygame.register_quit(quit_hook) + pygame.quit() + + self.assertEqual(quit_count, 1) + + def test_get_error(self): + + # __doc__ (as of 2008-08-02) for pygame.base.get_error: + + # pygame.get_error(): return errorstr + # get the current error message + # + # SDL maintains an internal error message. This message will usually + # be given to you when pygame.error is raised. You will rarely need to + # call this function. + # + + # The first error could be all sorts of nonsense or empty. + e = pygame.get_error() + pygame.set_error("hi") + self.assertEqual(pygame.get_error(), "hi") + pygame.set_error("") + self.assertEqual(pygame.get_error(), "") + + def test_set_error(self): + + # The first error could be all sorts of nonsense or empty. + e = pygame.get_error() + pygame.set_error("hi") + self.assertEqual(pygame.get_error(), "hi") + pygame.set_error("") + self.assertEqual(pygame.get_error(), "") + + def test_unicode_error(self): + pygame.set_error("你好") + self.assertEqual("你好", pygame.get_error()) + + def test_init(self): + """Ensures init() works properly.""" + # Make sure nothing initialized. + self.not_init_assertions() + + # display and joystick must init, at minimum + expected_min_passes = 2 + + # All modules should pass. + expected_fails = 0 + + passes, fails = pygame.init() + + self.init_assertions() + self.assertGreaterEqual(passes, expected_min_passes) + self.assertEqual(fails, expected_fails) + + def test_get_init(self): + # Test if get_init() gets the init state. + self.assertFalse(pygame.get_init()) + + def test_get_init__after_init(self): + # Test if get_init() gets the init state after pygame.init() called. + pygame.init() + + self.assertTrue(pygame.get_init()) + + def test_get_init__after_quit(self): + # Test if get_init() gets the init state after pygame.quit() called. + pygame.init() + pygame.quit() + + self.assertFalse(pygame.get_init()) + + def todo_test_segfault(self): + + # __doc__ (as of 2008-08-02) for pygame.base.segfault: + + # crash + + self.fail() + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/blit_test.py b/venv/Lib/site-packages/pygame/tests/blit_test.py new file mode 100644 index 0000000..906e7c4 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/blit_test.py @@ -0,0 +1,155 @@ +import unittest + +import pygame +from pygame.locals import * + + +class BlitTest(unittest.TestCase): + def test_SRCALPHA(self): + """SRCALPHA tests.""" + # blend(s, 0, d) = d + s = pygame.Surface((1, 1), SRCALPHA, 32) + s.fill((255, 255, 255, 0)) + + d = pygame.Surface((1, 1), SRCALPHA, 32) + d.fill((0, 0, 255, 255)) + + s.blit(d, (0, 0)) + self.assertEqual(s.get_at((0, 0)), d.get_at((0, 0))) + + # blend(s, 255, d) = s + s = pygame.Surface((1, 1), SRCALPHA, 32) + s.fill((123, 0, 0, 255)) + s1 = pygame.Surface((1, 1), SRCALPHA, 32) + s1.fill((123, 0, 0, 255)) + d = pygame.Surface((1, 1), SRCALPHA, 32) + d.fill((10, 0, 0, 0)) + s.blit(d, (0, 0)) + self.assertEqual(s.get_at((0, 0)), s1.get_at((0, 0))) + + # TODO: these should be true too. + # blend(0, sA, 0) = 0 + # blend(255, sA, 255) = 255 + # blend(s, sA, d) <= 255 + + def test_BLEND(self): + """BLEND_ tests.""" + + # test that it doesn't overflow, and that it is saturated. + s = pygame.Surface((1, 1), SRCALPHA, 32) + s.fill((255, 255, 255, 0)) + + d = pygame.Surface((1, 1), SRCALPHA, 32) + d.fill((0, 0, 255, 255)) + + s.blit(d, (0, 0), None, BLEND_ADD) + + # print "d %s" % (d.get_at((0,0)),) + # print s.get_at((0,0)) + # self.assertEqual(s.get_at((0,0))[2], 255 ) + # self.assertEqual(s.get_at((0,0))[3], 0 ) + + s.blit(d, (0, 0), None, BLEND_RGBA_ADD) + # print s.get_at((0,0)) + self.assertEqual(s.get_at((0, 0))[3], 255) + + # test adding works. + s.fill((20, 255, 255, 0)) + d.fill((10, 0, 255, 255)) + s.blit(d, (0, 0), None, BLEND_ADD) + self.assertEqual(s.get_at((0, 0))[2], 255) + + # test subbing works. + s.fill((20, 255, 255, 0)) + d.fill((10, 0, 255, 255)) + s.blit(d, (0, 0), None, BLEND_SUB) + self.assertEqual(s.get_at((0, 0))[0], 10) + + # no overflow in sub blend. + s.fill((20, 255, 255, 0)) + d.fill((30, 0, 255, 255)) + s.blit(d, (0, 0), None, BLEND_SUB) + self.assertEqual(s.get_at((0, 0))[0], 0) + + def make_blit_list(self, num_surfs): + + blit_list = [] + for i in range(num_surfs): + dest = (i * 10, 0) + surf = pygame.Surface((10, 10), SRCALPHA, 32) + color = (i * 1, i * 1, i * 1) + surf.fill(color) + blit_list.append((surf, dest)) + return blit_list + + def test_blits(self): + + NUM_SURFS = 255 + PRINT_TIMING = 0 + dst = pygame.Surface((NUM_SURFS * 10, 10), SRCALPHA, 32) + dst.fill((230, 230, 230)) + blit_list = self.make_blit_list(NUM_SURFS) + + def blits(blit_list): + for surface, dest in blit_list: + dst.blit(surface, dest) + + from time import time + + t0 = time() + results = blits(blit_list) + t1 = time() + if PRINT_TIMING: + print("python blits: %s" % (t1 - t0)) + + dst.fill((230, 230, 230)) + t0 = time() + results = dst.blits(blit_list) + t1 = time() + if PRINT_TIMING: + print("Surface.blits :%s" % (t1 - t0)) + + # check if we blit all the different colors in the correct spots. + for i in range(NUM_SURFS): + color = (i * 1, i * 1, i * 1) + self.assertEqual(dst.get_at((i * 10, 0)), color) + self.assertEqual(dst.get_at(((i * 10) + 5, 5)), color) + + self.assertEqual(len(results), NUM_SURFS) + + t0 = time() + results = dst.blits(blit_list, doreturn=0) + t1 = time() + if PRINT_TIMING: + print("Surface.blits doreturn=0: %s" % (t1 - t0)) + self.assertEqual(results, None) + + t0 = time() + results = dst.blits(((surf, dest) for surf, dest in blit_list)) + t1 = time() + if PRINT_TIMING: + print("Surface.blits generator: %s" % (t1 - t0)) + + def test_blits_not_sequence(self): + dst = pygame.Surface((100, 10), SRCALPHA, 32) + self.assertRaises(ValueError, dst.blits, None) + + def test_blits_wrong_length(self): + dst = pygame.Surface((100, 10), SRCALPHA, 32) + self.assertRaises( + ValueError, dst.blits, [pygame.Surface((10, 10), SRCALPHA, 32)] + ) + + def test_blits_bad_surf_args(self): + dst = pygame.Surface((100, 10), SRCALPHA, 32) + self.assertRaises(TypeError, dst.blits, [(None, None)]) + + def test_blits_bad_dest(self): + dst = pygame.Surface((100, 10), SRCALPHA, 32) + self.assertRaises( + TypeError, dst.blits, [(pygame.Surface((10, 10), SRCALPHA, 32), None)] + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/bufferproxy_test.py b/venv/Lib/site-packages/pygame/tests/bufferproxy_test.py new file mode 100644 index 0000000..3d9c0b3 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/bufferproxy_test.py @@ -0,0 +1,507 @@ +import re +import weakref +import gc +import ctypes +import unittest + +import pygame +from pygame.bufferproxy import BufferProxy + + +try: + BufferError +except NameError: + from pygame import BufferError + + +class BufferProxyTest(unittest.TestCase): + view_keywords = { + "shape": (5, 4, 3), + "typestr": "|u1", + "data": (0, True), + "strides": (4, 20, 1), + } + + def test_module_name(self): + self.assertEqual(pygame.bufferproxy.__name__, "pygame.bufferproxy") + + def test_class_name(self): + self.assertEqual(BufferProxy.__name__, "BufferProxy") + + def test___array_struct___property(self): + kwds = self.view_keywords + v = BufferProxy(kwds) + d = pygame.get_array_interface(v) + self.assertEqual(len(d), 5) + self.assertEqual(d["version"], 3) + self.assertEqual(d["shape"], kwds["shape"]) + self.assertEqual(d["typestr"], kwds["typestr"]) + self.assertEqual(d["data"], kwds["data"]) + self.assertEqual(d["strides"], kwds["strides"]) + + def test___array_interface___property(self): + kwds = self.view_keywords + v = BufferProxy(kwds) + d = v.__array_interface__ + self.assertEqual(len(d), 5) + self.assertEqual(d["version"], 3) + self.assertEqual(d["shape"], kwds["shape"]) + self.assertEqual(d["typestr"], kwds["typestr"]) + self.assertEqual(d["data"], kwds["data"]) + self.assertEqual(d["strides"], kwds["strides"]) + + def test_parent_property(self): + kwds = dict(self.view_keywords) + p = [] + kwds["parent"] = p + v = BufferProxy(kwds) + + self.assertIs(v.parent, p) + + def test_before(self): + def callback(parent): + success.append(parent is p) + + class MyException(Exception): + pass + + def raise_exception(parent): + raise MyException("Just a test.") + + kwds = dict(self.view_keywords) + p = [] + kwds["parent"] = p + + # For array interface + success = [] + kwds["before"] = callback + v = BufferProxy(kwds) + self.assertEqual(len(success), 0) + d = v.__array_interface__ + self.assertEqual(len(success), 1) + self.assertTrue(success[0]) + d = v.__array_interface__ + self.assertEqual(len(success), 1) + d = v = None + gc.collect() + self.assertEqual(len(success), 1) + + # For array struct + success = [] + kwds["before"] = callback + v = BufferProxy(kwds) + self.assertEqual(len(success), 0) + c = v.__array_struct__ + self.assertEqual(len(success), 1) + self.assertTrue(success[0]) + c = v.__array_struct__ + self.assertEqual(len(success), 1) + c = v = None + gc.collect() + self.assertEqual(len(success), 1) + + # Callback raises an exception + kwds["before"] = raise_exception + v = BufferProxy(kwds) + self.assertRaises(MyException, lambda: v.__array_struct__) + + def test_after(self): + def callback(parent): + success.append(parent is p) + + kwds = dict(self.view_keywords) + p = [] + kwds["parent"] = p + + # For array interface + success = [] + kwds["after"] = callback + v = BufferProxy(kwds) + self.assertEqual(len(success), 0) + d = v.__array_interface__ + self.assertEqual(len(success), 0) + d = v.__array_interface__ + self.assertEqual(len(success), 0) + d = v = None + gc.collect() + self.assertEqual(len(success), 1) + self.assertTrue(success[0]) + + # For array struct + success = [] + kwds["after"] = callback + v = BufferProxy(kwds) + self.assertEqual(len(success), 0) + c = v.__array_struct__ + self.assertEqual(len(success), 0) + c = v.__array_struct__ + self.assertEqual(len(success), 0) + c = v = None + gc.collect() + self.assertEqual(len(success), 1) + self.assertTrue(success[0]) + + def test_attribute(self): + v = BufferProxy(self.view_keywords) + self.assertRaises(AttributeError, getattr, v, "undefined") + v.undefined = 12 + self.assertEqual(v.undefined, 12) + del v.undefined + self.assertRaises(AttributeError, getattr, v, "undefined") + + def test_weakref(self): + v = BufferProxy(self.view_keywords) + weak_v = weakref.ref(v) + + self.assertIs(weak_v(), v) + + v = None + gc.collect() + + self.assertIsNone(weak_v()) + + def test_gc(self): + """refcount agnostic check that contained objects are freed""" + + def before_callback(parent): + return r[0] + + def after_callback(parent): + return r[1] + + class Obj(object): + pass + + p = Obj() + a = Obj() + r = [Obj(), Obj()] + weak_p = weakref.ref(p) + weak_a = weakref.ref(a) + weak_r0 = weakref.ref(r[0]) + weak_r1 = weakref.ref(r[1]) + weak_before = weakref.ref(before_callback) + weak_after = weakref.ref(after_callback) + kwds = dict(self.view_keywords) + kwds["parent"] = p + kwds["before"] = before_callback + kwds["after"] = after_callback + v = BufferProxy(kwds) + v.some_attribute = a + weak_v = weakref.ref(v) + kwds = p = a = before_callback = after_callback = None + gc.collect() + self.assertTrue(weak_p() is not None) + self.assertTrue(weak_a() is not None) + self.assertTrue(weak_before() is not None) + self.assertTrue(weak_after() is not None) + v = None + [gc.collect() for x in range(4)] + self.assertTrue(weak_v() is None) + self.assertTrue(weak_p() is None) + self.assertTrue(weak_a() is None) + self.assertTrue(weak_before() is None) + self.assertTrue(weak_after() is None) + self.assertTrue(weak_r0() is not None) + self.assertTrue(weak_r1() is not None) + r = None + gc.collect() + self.assertTrue(weak_r0() is None) + self.assertTrue(weak_r1() is None) + + # Cycle removal + kwds = dict(self.view_keywords) + kwds["parent"] = [] + v = BufferProxy(kwds) + v.some_attribute = v + tracked = True + for o in gc.get_objects(): + if o is v: + break + else: + tracked = False + self.assertTrue(tracked) + kwds["parent"].append(v) + kwds = None + gc.collect() + n1 = len(gc.garbage) + v = None + gc.collect() + n2 = len(gc.garbage) + self.assertEqual(n2, n1) + + def test_c_api(self): + api = pygame.bufferproxy._PYGAME_C_API + api_type = type(pygame.base._PYGAME_C_API) + + self.assertIsInstance(api, api_type) + + def test_repr(self): + v = BufferProxy(self.view_keywords) + cname = BufferProxy.__name__ + oname, ovalue = re.findall(r"<([^)]+)\(([^)]+)\)>", repr(v))[0] + self.assertEqual(oname, cname) + self.assertEqual(v.length, int(ovalue)) + + def test_subclassing(self): + class MyBufferProxy(BufferProxy): + def __repr__(self): + return "*%s*" % (BufferProxy.__repr__(self),) + + kwds = dict(self.view_keywords) + kwds["parent"] = 0 + v = MyBufferProxy(kwds) + self.assertEqual(v.parent, 0) + r = repr(v) + self.assertEqual(r[:2], "*<") + self.assertEqual(r[-2:], ">*") + + @unittest.skipIf(not pygame.HAVE_NEWBUF, "newbuf not implemented") + def NEWBUF_test_newbuf(self): + from ctypes import string_at + + from pygame.tests.test_utils import buftools + + Exporter = buftools.Exporter + Importer = buftools.Importer + exp = Exporter((10,), "B", readonly=True) + b = BufferProxy(exp) + self.assertEqual(b.length, exp.len) + self.assertEqual(b.raw, string_at(exp.buf, exp.len)) + d = b.__array_interface__ + try: + self.assertEqual(d["typestr"], "|u1") + self.assertEqual(d["shape"], exp.shape) + self.assertEqual(d["strides"], exp.strides) + self.assertEqual(d["data"], (exp.buf, True)) + finally: + d = None + exp = Exporter((3,), "=h") + b = BufferProxy(exp) + self.assertEqual(b.length, exp.len) + self.assertEqual(b.raw, string_at(exp.buf, exp.len)) + d = b.__array_interface__ + try: + lil_endian = pygame.get_sdl_byteorder() == pygame.LIL_ENDIAN + f = "{}i{}".format("<" if lil_endian else ">", exp.itemsize) + self.assertEqual(d["typestr"], f) + self.assertEqual(d["shape"], exp.shape) + self.assertEqual(d["strides"], exp.strides) + self.assertEqual(d["data"], (exp.buf, False)) + finally: + d = None + + exp = Exporter((10, 2), "=i") + b = BufferProxy(exp) + imp = Importer(b, buftools.PyBUF_RECORDS) + self.assertTrue(imp.obj is b) + self.assertEqual(imp.buf, exp.buf) + self.assertEqual(imp.ndim, exp.ndim) + self.assertEqual(imp.format, exp.format) + self.assertEqual(imp.readonly, exp.readonly) + self.assertEqual(imp.itemsize, exp.itemsize) + self.assertEqual(imp.len, exp.len) + self.assertEqual(imp.shape, exp.shape) + self.assertEqual(imp.strides, exp.strides) + self.assertTrue(imp.suboffsets is None) + + d = { + "typestr": "|u1", + "shape": (10,), + "strides": (1,), + "data": (9, True), + } # 9? Will not reading the data anyway. + b = BufferProxy(d) + imp = Importer(b, buftools.PyBUF_SIMPLE) + self.assertTrue(imp.obj is b) + self.assertEqual(imp.buf, 9) + self.assertEqual(imp.len, 10) + self.assertEqual(imp.format, None) + self.assertEqual(imp.itemsize, 1) + self.assertEqual(imp.ndim, 0) + self.assertTrue(imp.readonly) + self.assertTrue(imp.shape is None) + self.assertTrue(imp.strides is None) + self.assertTrue(imp.suboffsets is None) + + try: + pygame.bufferproxy.get_segcount + except AttributeError: + pass + else: + + def test_oldbuf_arg(self): + self.OLDBUF_test_oldbuf_arg() + + def OLDBUF_test_oldbuf_arg(self): + from pygame.bufferproxy import get_segcount, get_read_buffer, get_write_buffer + + content = b"\x01\x00\x00\x02" * 12 + memory = ctypes.create_string_buffer(content) + memaddr = ctypes.addressof(memory) + + def raise_exception(o): + raise ValueError("An exception") + + bf = BufferProxy( + { + "shape": (len(content),), + "typestr": "|u1", + "data": (memaddr, False), + "strides": (1,), + } + ) + seglen, segaddr = get_read_buffer(bf, 0) + self.assertEqual(segaddr, 0) + self.assertEqual(seglen, 0) + seglen, segaddr = get_write_buffer(bf, 0) + self.assertEqual(segaddr, 0) + self.assertEqual(seglen, 0) + segcount, buflen = get_segcount(bf) + self.assertEqual(segcount, 1) + self.assertEqual(buflen, len(content)) + seglen, segaddr = get_read_buffer(bf, 0) + self.assertEqual(segaddr, memaddr) + self.assertEqual(seglen, len(content)) + seglen, segaddr = get_write_buffer(bf, 0) + self.assertEqual(segaddr, memaddr) + self.assertEqual(seglen, len(content)) + + bf = BufferProxy( + { + "shape": (len(content),), + "typestr": "|u1", + "data": (memaddr, True), + "strides": (1,), + } + ) + segcount, buflen = get_segcount(bf) + self.assertEqual(segcount, 1) + self.assertEqual(buflen, len(content)) + seglen, segaddr = get_read_buffer(bf, 0) + self.assertEqual(segaddr, memaddr) + self.assertEqual(seglen, len(content)) + self.assertRaises(ValueError, get_write_buffer, bf, 0) + + bf = BufferProxy( + { + "shape": (len(content),), + "typestr": "|u1", + "data": (memaddr, True), + "strides": (1,), + "before": raise_exception, + } + ) + segcount, buflen = get_segcount(bf) + self.assertEqual(segcount, 0) + self.assertEqual(buflen, 0) + + bf = BufferProxy( + { + "shape": (3, 4), + "typestr": "|u4", + "data": (memaddr, True), + "strides": (12, 4), + } + ) + segcount, buflen = get_segcount(bf) + self.assertEqual(segcount, 3 * 4) + self.assertEqual(buflen, 3 * 4 * 4) + for i in range(0, 4): + seglen, segaddr = get_read_buffer(bf, i) + self.assertEqual(segaddr, memaddr + i * 4) + self.assertEqual(seglen, 4) + + +class BufferProxyLegacyTest(unittest.TestCase): + content = b"\x01\x00\x00\x02" * 12 + buffer = ctypes.create_string_buffer(content) + data = (ctypes.addressof(buffer), True) + + def test_length(self): + + # __doc__ (as of 2008-08-02) for pygame.bufferproxy.BufferProxy.length: + + # The size of the buffer data in bytes. + bf = BufferProxy( + {"shape": (3, 4), "typestr": "|u4", "data": self.data, "strides": (12, 4)} + ) + self.assertEqual(bf.length, len(self.content)) + bf = BufferProxy( + {"shape": (3, 3), "typestr": "|u4", "data": self.data, "strides": (12, 4)} + ) + self.assertEqual(bf.length, 3 * 3 * 4) + + def test_raw(self): + + # __doc__ (as of 2008-08-02) for pygame.bufferproxy.BufferProxy.raw: + + # The raw buffer data as string. The string may contain NUL bytes. + + bf = BufferProxy( + {"shape": (len(self.content),), "typestr": "|u1", "data": self.data} + ) + self.assertEqual(bf.raw, self.content) + bf = BufferProxy( + {"shape": (3, 4), "typestr": "|u4", "data": self.data, "strides": (4, 12)} + ) + self.assertEqual(bf.raw, self.content) + bf = BufferProxy( + {"shape": (3, 4), "typestr": "|u1", "data": self.data, "strides": (16, 4)} + ) + self.assertRaises(ValueError, getattr, bf, "raw") + + def test_write(self): + + # __doc__ (as of 2008-08-02) for pygame.bufferproxy.BufferProxy.write: + + # B.write (bufferproxy, buffer, offset) -> None + # + # Writes raw data to the bufferproxy. + # + # Writes the raw data from buffer to the BufferProxy object, starting + # at the specified offset within the BufferProxy. + # If the length of the passed buffer exceeds the length of the + # BufferProxy (reduced by the offset), an IndexError will be raised. + from ctypes import c_byte, sizeof, addressof, string_at, memset + + nullbyte = "\x00".encode("latin_1") + Buf = c_byte * 10 + data_buf = Buf(*range(1, 3 * sizeof(Buf) + 1, 3)) + data = string_at(data_buf, sizeof(data_buf)) + buf = Buf() + bp = BufferProxy( + {"typestr": "|u1", "shape": (sizeof(buf),), "data": (addressof(buf), False)} + ) + try: + self.assertEqual(bp.raw, nullbyte * sizeof(Buf)) + bp.write(data) + self.assertEqual(bp.raw, data) + memset(buf, 0, sizeof(buf)) + bp.write(data[:3], 2) + raw = bp.raw + self.assertEqual(raw[:2], nullbyte * 2) + self.assertEqual(raw[2:5], data[:3]) + self.assertEqual(raw[5:], nullbyte * (sizeof(Buf) - 5)) + bp.write(data[:3], bp.length - 3) + raw = bp.raw + self.assertEqual(raw[-3:], data[:3]) + self.assertRaises(IndexError, bp.write, data, 1) + self.assertRaises(IndexError, bp.write, data[:5], -1) + self.assertRaises(IndexError, bp.write, data[:5], bp.length) + self.assertRaises(TypeError, bp.write, 12) + bp = BufferProxy( + { + "typestr": "|u1", + "shape": (sizeof(buf),), + "data": (addressof(buf), True), + } + ) + self.assertRaises(pygame.BufferError, bp.write, "123".encode("latin_1")) + finally: + # Make sure bp is garbage collected before buf + bp = None + gc.collect() + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/camera_test.py b/venv/Lib/site-packages/pygame/tests/camera_test.py new file mode 100644 index 0000000..79cf0f9 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/camera_test.py @@ -0,0 +1,5 @@ +import unittest + + +class CameraModuleTest(unittest.TestCase): + pass diff --git a/venv/Lib/site-packages/pygame/tests/color_test.py b/venv/Lib/site-packages/pygame/tests/color_test.py new file mode 100644 index 0000000..16eefd1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/color_test.py @@ -0,0 +1,1302 @@ +import unittest +import math +import operator +import platform + +import pygame +from pygame.colordict import THECOLORS + + +IS_PYPY = "PyPy" == platform.python_implementation() +################################### CONSTANTS ################################## + +rgba_vals = [0, 1, 62, 63, 126, 127, 255] + +rgba_combinations = [ + (r, g, b, a) + for r in rgba_vals + for g in rgba_vals + for b in rgba_vals + for a in rgba_vals +] + +################################################################################ + + +def rgba_combos_Color_generator(): + for rgba in rgba_combinations: + yield pygame.Color(*rgba) + + +# Python gamma correct +def gamma_correct(rgba_0_255, gamma): + corrected = round(255.0 * math.pow(rgba_0_255 / 255.0, gamma)) + return max(min(int(corrected), 255), 0) + + +################################################################################ + +# TODO: add tests for +# correct_gamma() -- test against statically defined verified correct values +# coerce () -- ?? + + +def _assignr(x, y): + x.r = y + + +def _assigng(x, y): + x.g = y + + +def _assignb(x, y): + x.b = y + + +def _assigna(x, y): + x.a = y + + +def _assign_item(x, p, y): + x[p] = y + + +class ColorTypeTest(unittest.TestCase): + def test_new(self): + c = pygame.Color.__new__(pygame.Color) + self.assertEqual(c, pygame.Color(0, 0, 0, 255)) + self.assertEqual(len(c), 4) + + def test_init(self): + c = pygame.Color(10, 20, 30, 200) + self.assertEqual(c, (10, 20, 30, 200)) + c.set_length(3) + self.assertEqual(len(c), 3) + c.__init__(100, 110, 120, 128) + self.assertEqual(len(c), 4) + self.assertEqual(c, (100, 110, 120, 128)) + + def test_invalid_html_hex_codes(self): + # This was a problem with the way 2 digit hex numbers were + # calculated. The test_hex_digits test is related to the fix. + Color = pygame.color.Color + self.assertRaises(ValueError, lambda: Color("# f000000")) + self.assertRaises(ValueError, lambda: Color("#f 000000")) + self.assertRaises(ValueError, lambda: Color("#-f000000")) + + def test_hex_digits(self): + # This is an implementation specific test. + # Two digit hex numbers are calculated using table lookups + # for the upper and lower digits. + Color = pygame.color.Color + self.assertEqual(Color("#00000000").r, 0x00) + self.assertEqual(Color("#10000000").r, 0x10) + self.assertEqual(Color("#20000000").r, 0x20) + self.assertEqual(Color("#30000000").r, 0x30) + self.assertEqual(Color("#40000000").r, 0x40) + self.assertEqual(Color("#50000000").r, 0x50) + self.assertEqual(Color("#60000000").r, 0x60) + self.assertEqual(Color("#70000000").r, 0x70) + self.assertEqual(Color("#80000000").r, 0x80) + self.assertEqual(Color("#90000000").r, 0x90) + self.assertEqual(Color("#A0000000").r, 0xA0) + self.assertEqual(Color("#B0000000").r, 0xB0) + self.assertEqual(Color("#C0000000").r, 0xC0) + self.assertEqual(Color("#D0000000").r, 0xD0) + self.assertEqual(Color("#E0000000").r, 0xE0) + self.assertEqual(Color("#F0000000").r, 0xF0) + self.assertEqual(Color("#01000000").r, 0x01) + self.assertEqual(Color("#02000000").r, 0x02) + self.assertEqual(Color("#03000000").r, 0x03) + self.assertEqual(Color("#04000000").r, 0x04) + self.assertEqual(Color("#05000000").r, 0x05) + self.assertEqual(Color("#06000000").r, 0x06) + self.assertEqual(Color("#07000000").r, 0x07) + self.assertEqual(Color("#08000000").r, 0x08) + self.assertEqual(Color("#09000000").r, 0x09) + self.assertEqual(Color("#0A000000").r, 0x0A) + self.assertEqual(Color("#0B000000").r, 0x0B) + self.assertEqual(Color("#0C000000").r, 0x0C) + self.assertEqual(Color("#0D000000").r, 0x0D) + self.assertEqual(Color("#0E000000").r, 0x0E) + self.assertEqual(Color("#0F000000").r, 0x0F) + + def test_comparison(self): + Color = pygame.color.Color + + # Check valid comparisons + self.assertTrue(Color(255, 0, 0, 0) == Color(255, 0, 0, 0)) + self.assertTrue(Color(0, 255, 0, 0) == Color(0, 255, 0, 0)) + self.assertTrue(Color(0, 0, 255, 0) == Color(0, 0, 255, 0)) + self.assertTrue(Color(0, 0, 0, 255) == Color(0, 0, 0, 255)) + self.assertFalse(Color(0, 0, 0, 0) == Color(255, 0, 0, 0)) + self.assertFalse(Color(0, 0, 0, 0) == Color(0, 255, 0, 0)) + self.assertFalse(Color(0, 0, 0, 0) == Color(0, 0, 255, 0)) + self.assertFalse(Color(0, 0, 0, 0) == Color(0, 0, 0, 255)) + self.assertTrue(Color(0, 0, 0, 0) != Color(255, 0, 0, 0)) + self.assertTrue(Color(0, 0, 0, 0) != Color(0, 255, 0, 0)) + self.assertTrue(Color(0, 0, 0, 0) != Color(0, 0, 255, 0)) + self.assertTrue(Color(0, 0, 0, 0) != Color(0, 0, 0, 255)) + self.assertFalse(Color(255, 0, 0, 0) != Color(255, 0, 0, 0)) + self.assertFalse(Color(0, 255, 0, 0) != Color(0, 255, 0, 0)) + self.assertFalse(Color(0, 0, 255, 0) != Color(0, 0, 255, 0)) + self.assertFalse(Color(0, 0, 0, 255) != Color(0, 0, 0, 255)) + + self.assertTrue(Color(255, 0, 0, 0) == (255, 0, 0, 0)) + self.assertTrue(Color(0, 255, 0, 0) == (0, 255, 0, 0)) + self.assertTrue(Color(0, 0, 255, 0) == (0, 0, 255, 0)) + self.assertTrue(Color(0, 0, 0, 255) == (0, 0, 0, 255)) + self.assertFalse(Color(0, 0, 0, 0) == (255, 0, 0, 0)) + self.assertFalse(Color(0, 0, 0, 0) == (0, 255, 0, 0)) + self.assertFalse(Color(0, 0, 0, 0) == (0, 0, 255, 0)) + self.assertFalse(Color(0, 0, 0, 0) == (0, 0, 0, 255)) + self.assertTrue(Color(0, 0, 0, 0) != (255, 0, 0, 0)) + self.assertTrue(Color(0, 0, 0, 0) != (0, 255, 0, 0)) + self.assertTrue(Color(0, 0, 0, 0) != (0, 0, 255, 0)) + self.assertTrue(Color(0, 0, 0, 0) != (0, 0, 0, 255)) + self.assertFalse(Color(255, 0, 0, 0) != (255, 0, 0, 0)) + self.assertFalse(Color(0, 255, 0, 0) != (0, 255, 0, 0)) + self.assertFalse(Color(0, 0, 255, 0) != (0, 0, 255, 0)) + self.assertFalse(Color(0, 0, 0, 255) != (0, 0, 0, 255)) + + self.assertTrue((255, 0, 0, 0) == Color(255, 0, 0, 0)) + self.assertTrue((0, 255, 0, 0) == Color(0, 255, 0, 0)) + self.assertTrue((0, 0, 255, 0) == Color(0, 0, 255, 0)) + self.assertTrue((0, 0, 0, 255) == Color(0, 0, 0, 255)) + self.assertFalse((0, 0, 0, 0) == Color(255, 0, 0, 0)) + self.assertFalse((0, 0, 0, 0) == Color(0, 255, 0, 0)) + self.assertFalse((0, 0, 0, 0) == Color(0, 0, 255, 0)) + self.assertFalse((0, 0, 0, 0) == Color(0, 0, 0, 255)) + self.assertTrue((0, 0, 0, 0) != Color(255, 0, 0, 0)) + self.assertTrue((0, 0, 0, 0) != Color(0, 255, 0, 0)) + self.assertTrue((0, 0, 0, 0) != Color(0, 0, 255, 0)) + self.assertTrue((0, 0, 0, 0) != Color(0, 0, 0, 255)) + self.assertFalse((255, 0, 0, 0) != Color(255, 0, 0, 0)) + self.assertFalse((0, 255, 0, 0) != Color(0, 255, 0, 0)) + self.assertFalse((0, 0, 255, 0) != Color(0, 0, 255, 0)) + self.assertFalse((0, 0, 0, 255) != Color(0, 0, 0, 255)) + + class TupleSubclass(tuple): + pass + + self.assertTrue(Color(255, 0, 0, 0) == TupleSubclass((255, 0, 0, 0))) + self.assertTrue(TupleSubclass((255, 0, 0, 0)) == Color(255, 0, 0, 0)) + self.assertFalse(Color(255, 0, 0, 0) != TupleSubclass((255, 0, 0, 0))) + self.assertFalse(TupleSubclass((255, 0, 0, 0)) != Color(255, 0, 0, 0)) + + # These are not supported so will be unequal. + self.assertFalse(Color(255, 0, 0, 0) == "#ff000000") + self.assertTrue(Color(255, 0, 0, 0) != "#ff000000") + + self.assertFalse("#ff000000" == Color(255, 0, 0, 0)) + self.assertTrue("#ff000000" != Color(255, 0, 0, 0)) + + self.assertFalse(Color(255, 0, 0, 0) == 0xFF000000) + self.assertTrue(Color(255, 0, 0, 0) != 0xFF000000) + + self.assertFalse(0xFF000000 == Color(255, 0, 0, 0)) + self.assertTrue(0xFF000000 != Color(255, 0, 0, 0)) + + self.assertFalse(Color(255, 0, 0, 0) == [255, 0, 0, 0]) + self.assertTrue(Color(255, 0, 0, 0) != [255, 0, 0, 0]) + + self.assertFalse([255, 0, 0, 0] == Color(255, 0, 0, 0)) + self.assertTrue([255, 0, 0, 0] != Color(255, 0, 0, 0)) + + # Comparison is not implemented for invalid color values. + class Test(object): + def __eq__(self, other): + return -1 + + def __ne__(self, other): + return -2 + + class TestTuple(tuple): + def __eq__(self, other): + return -1 + + def __ne__(self, other): + return -2 + + t = Test() + t_tuple = TestTuple(("a", 0, 0, 0)) + black = Color("black") + self.assertEqual(black == t, -1) + self.assertEqual(t == black, -1) + self.assertEqual(black != t, -2) + self.assertEqual(t != black, -2) + self.assertEqual(black == t_tuple, -1) + self.assertEqual(black != t_tuple, -2) + self.assertEqual(t_tuple == black, -1) + self.assertEqual(t_tuple != black, -2) + + def test_ignore_whitespace(self): + self.assertEqual(pygame.color.Color("red"), pygame.color.Color(" r e d ")) + + def test_slice(self): + # """|tags: python3_ignore|""" + + # slicing a color gives you back a tuple. + # do all sorts of slice combinations. + c = pygame.Color(1, 2, 3, 4) + + self.assertEqual((1, 2, 3, 4), c[:]) + self.assertEqual((1, 2, 3), c[:-1]) + + self.assertEqual((), c[:-5]) + + self.assertEqual((1, 2, 3, 4), c[:4]) + self.assertEqual((1, 2, 3, 4), c[:5]) + self.assertEqual((1, 2), c[:2]) + self.assertEqual((1,), c[:1]) + self.assertEqual((), c[:0]) + + self.assertEqual((2,), c[1:-2]) + self.assertEqual((3, 4), c[-2:]) + self.assertEqual((4,), c[-1:]) + + # NOTE: assigning to a slice is currently unsupported. + + def test_unpack(self): + # should be able to unpack to r,g,b,a and r,g,b + c = pygame.Color(1, 2, 3, 4) + r, g, b, a = c + self.assertEqual((1, 2, 3, 4), (r, g, b, a)) + self.assertEqual(c, (r, g, b, a)) + + c.set_length(3) + r, g, b = c + self.assertEqual((1, 2, 3), (r, g, b)) + + def test_length(self): + # should be able to unpack to r,g,b,a and r,g,b + c = pygame.Color(1, 2, 3, 4) + self.assertEqual(len(c), 4) + + c.set_length(3) + self.assertEqual(len(c), 3) + + # it keeps the old alpha anyway... + self.assertEqual(c.a, 4) + + # however you can't get the alpha in this way: + self.assertRaises(IndexError, lambda x: c[x], 4) + + c.set_length(4) + self.assertEqual(len(c), 4) + self.assertEqual(len(c), 4) + + self.assertRaises(ValueError, c.set_length, 5) + self.assertRaises(ValueError, c.set_length, -1) + self.assertRaises(ValueError, c.set_length, 0) + self.assertRaises(ValueError, c.set_length, pow(2, 33)) + + def test_case_insensitivity_of_string_args(self): + self.assertEqual(pygame.color.Color("red"), pygame.color.Color("Red")) + + def test_color(self): + """Ensures Color objects can be created.""" + color = pygame.Color(0, 0, 0, 0) + + self.assertIsInstance(color, pygame.Color) + + def test_color__rgba_int_args(self): + """Ensures Color objects can be created using ints.""" + color = pygame.Color(10, 20, 30, 40) + + self.assertEqual(color.r, 10) + self.assertEqual(color.g, 20) + self.assertEqual(color.b, 30) + self.assertEqual(color.a, 40) + + def test_color__rgba_int_args_without_alpha(self): + """Ensures Color objects can be created without providing alpha.""" + color = pygame.Color(10, 20, 30) + + self.assertEqual(color.r, 10) + self.assertEqual(color.g, 20) + self.assertEqual(color.b, 30) + self.assertEqual(color.a, 255) + + def test_color__rgba_int_args_invalid_value(self): + """Ensures invalid values are detected when creating Color objects.""" + self.assertRaises(ValueError, pygame.Color, 257, 10, 105, 44) + self.assertRaises(ValueError, pygame.Color, 10, 257, 105, 44) + self.assertRaises(ValueError, pygame.Color, 10, 105, 257, 44) + self.assertRaises(ValueError, pygame.Color, 10, 105, 44, 257) + + def test_color__rgba_int_args_invalid_value_without_alpha(self): + """Ensures invalid values are detected when creating Color objects + without providing an alpha. + """ + self.assertRaises(ValueError, pygame.Color, 256, 10, 105) + self.assertRaises(ValueError, pygame.Color, 10, 256, 105) + self.assertRaises(ValueError, pygame.Color, 10, 105, 256) + + def test_color__color_object_arg(self): + """Ensures Color objects can be created using Color objects.""" + color_args = (10, 20, 30, 40) + color_obj = pygame.Color(*color_args) + + new_color_obj = pygame.Color(color_obj) + + self.assertIsInstance(new_color_obj, pygame.Color) + self.assertEqual(new_color_obj, color_obj) + self.assertEqual(new_color_obj.r, color_args[0]) + self.assertEqual(new_color_obj.g, color_args[1]) + self.assertEqual(new_color_obj.b, color_args[2]) + self.assertEqual(new_color_obj.a, color_args[3]) + + def test_color__name_str_arg(self): + """Ensures Color objects can be created using str names.""" + for name in ("aquamarine3", "AQUAMARINE3", "AqUAmArIne3"): + color = pygame.Color(name) + + self.assertEqual(color.r, 102) + self.assertEqual(color.g, 205) + self.assertEqual(color.b, 170) + self.assertEqual(color.a, 255) + + def test_color__name_str_arg_from_colordict(self): + """Ensures Color objects can be created using str names + from the THECOLORS dict.""" + for name, values in THECOLORS.items(): + color = pygame.Color(name) + + self.assertEqual(color.r, values[0]) + self.assertEqual(color.g, values[1]) + self.assertEqual(color.b, values[2]) + self.assertEqual(color.a, values[3]) + + def test_color__html_str_arg(self): + """Ensures Color objects can be created using html strings.""" + # See test_webstyle() for related tests. + color = pygame.Color("#a1B2c3D4") + + self.assertEqual(color.r, 0xA1) + self.assertEqual(color.g, 0xB2) + self.assertEqual(color.b, 0xC3) + self.assertEqual(color.a, 0xD4) + + def test_color__hex_str_arg(self): + """Ensures Color objects can be created using hex strings.""" + # See test_webstyle() for related tests. + color = pygame.Color("0x1a2B3c4D") + + self.assertEqual(color.r, 0x1A) + self.assertEqual(color.g, 0x2B) + self.assertEqual(color.b, 0x3C) + self.assertEqual(color.a, 0x4D) + + def test_color__int_arg(self): + """Ensures Color objects can be created using one int value.""" + for value in (0x0, 0xFFFFFFFF, 0xAABBCCDD): + color = pygame.Color(value) + + self.assertEqual(color.r, (value >> 24) & 0xFF) + self.assertEqual(color.g, (value >> 16) & 0xFF) + self.assertEqual(color.b, (value >> 8) & 0xFF) + self.assertEqual(color.a, value & 0xFF) + + def test_color__int_arg_invalid(self): + """Ensures invalid int values are detected when creating Color objects.""" + with self.assertRaises(ValueError): + color = pygame.Color(0x1FFFFFFFF) + + def test_color__sequence_arg(self): + """Ensures Color objects can be created using tuples/lists.""" + color_values = (33, 44, 55, 66) + for seq_type in (tuple, list): + color = pygame.Color(seq_type(color_values)) + + self.assertEqual(color.r, color_values[0]) + self.assertEqual(color.g, color_values[1]) + self.assertEqual(color.b, color_values[2]) + self.assertEqual(color.a, color_values[3]) + + def test_color__sequence_arg_without_alpha(self): + """Ensures Color objects can be created using tuples/lists + without providing an alpha value. + """ + color_values = (33, 44, 55) + for seq_type in (tuple, list): + color = pygame.Color(seq_type(color_values)) + + self.assertEqual(color.r, color_values[0]) + self.assertEqual(color.g, color_values[1]) + self.assertEqual(color.b, color_values[2]) + self.assertEqual(color.a, 255) + + def test_color__sequence_arg_invalid_value(self): + """Ensures invalid sequences are detected when creating Color objects.""" + cls = pygame.Color + for seq_type in (tuple, list): + self.assertRaises(ValueError, cls, seq_type((256, 90, 80, 70))) + self.assertRaises(ValueError, cls, seq_type((100, 256, 80, 70))) + self.assertRaises(ValueError, cls, seq_type((100, 90, 256, 70))) + self.assertRaises(ValueError, cls, seq_type((100, 90, 80, 256))) + + def test_color__sequence_arg_invalid_value_without_alpha(self): + """Ensures invalid sequences are detected when creating Color objects + without providing an alpha. + """ + cls = pygame.Color + for seq_type in (tuple, list): + self.assertRaises(ValueError, cls, seq_type((256, 90, 80))) + self.assertRaises(ValueError, cls, seq_type((100, 256, 80))) + self.assertRaises(ValueError, cls, seq_type((100, 90, 256))) + + def test_color__sequence_arg_invalid_format(self): + """Ensures invalid sequences are detected when creating Color objects + with the wrong number of values. + """ + cls = pygame.Color + for seq_type in (tuple, list): + self.assertRaises(ValueError, cls, seq_type((100,))) + self.assertRaises(ValueError, cls, seq_type((100, 90))) + self.assertRaises(ValueError, cls, seq_type((100, 90, 80, 70, 60))) + + def test_rgba(self): + c = pygame.Color(0) + self.assertEqual(c.r, 0) + self.assertEqual(c.g, 0) + self.assertEqual(c.b, 0) + self.assertEqual(c.a, 0) + + # Test simple assignments + c.r = 123 + self.assertEqual(c.r, 123) + self.assertRaises(ValueError, _assignr, c, 537) + self.assertEqual(c.r, 123) + self.assertRaises(ValueError, _assignr, c, -3) + self.assertEqual(c.r, 123) + + c.g = 55 + self.assertEqual(c.g, 55) + self.assertRaises(ValueError, _assigng, c, 348) + self.assertEqual(c.g, 55) + self.assertRaises(ValueError, _assigng, c, -44) + self.assertEqual(c.g, 55) + + c.b = 77 + self.assertEqual(c.b, 77) + self.assertRaises(ValueError, _assignb, c, 256) + self.assertEqual(c.b, 77) + self.assertRaises(ValueError, _assignb, c, -12) + self.assertEqual(c.b, 77) + + c.a = 255 + self.assertEqual(c.a, 255) + self.assertRaises(ValueError, _assigna, c, 312) + self.assertEqual(c.a, 255) + self.assertRaises(ValueError, _assigna, c, -10) + self.assertEqual(c.a, 255) + + def test_repr(self): + c = pygame.Color(68, 38, 26, 69) + t = "(68, 38, 26, 69)" + self.assertEqual(repr(c), t) + + def test_add(self): + c1 = pygame.Color(0) + self.assertEqual(c1.r, 0) + self.assertEqual(c1.g, 0) + self.assertEqual(c1.b, 0) + self.assertEqual(c1.a, 0) + + c2 = pygame.Color(20, 33, 82, 193) + self.assertEqual(c2.r, 20) + self.assertEqual(c2.g, 33) + self.assertEqual(c2.b, 82) + self.assertEqual(c2.a, 193) + + c3 = c1 + c2 + self.assertEqual(c3.r, 20) + self.assertEqual(c3.g, 33) + self.assertEqual(c3.b, 82) + self.assertEqual(c3.a, 193) + + c3 = c3 + c2 + self.assertEqual(c3.r, 40) + self.assertEqual(c3.g, 66) + self.assertEqual(c3.b, 164) + self.assertEqual(c3.a, 255) + + # Issue #286: Is type checking done for Python 3.x? + self.assertRaises(TypeError, operator.add, c1, None) + self.assertRaises(TypeError, operator.add, None, c1) + + def test_sub(self): + c1 = pygame.Color(0xFFFFFFFF) + self.assertEqual(c1.r, 255) + self.assertEqual(c1.g, 255) + self.assertEqual(c1.b, 255) + self.assertEqual(c1.a, 255) + + c2 = pygame.Color(20, 33, 82, 193) + self.assertEqual(c2.r, 20) + self.assertEqual(c2.g, 33) + self.assertEqual(c2.b, 82) + self.assertEqual(c2.a, 193) + + c3 = c1 - c2 + self.assertEqual(c3.r, 235) + self.assertEqual(c3.g, 222) + self.assertEqual(c3.b, 173) + self.assertEqual(c3.a, 62) + + c3 = c3 - c2 + self.assertEqual(c3.r, 215) + self.assertEqual(c3.g, 189) + self.assertEqual(c3.b, 91) + self.assertEqual(c3.a, 0) + + # Issue #286: Is type checking done for Python 3.x? + self.assertRaises(TypeError, operator.sub, c1, None) + self.assertRaises(TypeError, operator.sub, None, c1) + + def test_mul(self): + c1 = pygame.Color(0x01010101) + self.assertEqual(c1.r, 1) + self.assertEqual(c1.g, 1) + self.assertEqual(c1.b, 1) + self.assertEqual(c1.a, 1) + + c2 = pygame.Color(2, 5, 3, 22) + self.assertEqual(c2.r, 2) + self.assertEqual(c2.g, 5) + self.assertEqual(c2.b, 3) + self.assertEqual(c2.a, 22) + + c3 = c1 * c2 + self.assertEqual(c3.r, 2) + self.assertEqual(c3.g, 5) + self.assertEqual(c3.b, 3) + self.assertEqual(c3.a, 22) + + c3 = c3 * c2 + self.assertEqual(c3.r, 4) + self.assertEqual(c3.g, 25) + self.assertEqual(c3.b, 9) + self.assertEqual(c3.a, 255) + + # Issue #286: Is type checking done for Python 3.x? + self.assertRaises(TypeError, operator.mul, c1, None) + self.assertRaises(TypeError, operator.mul, None, c1) + + def test_div(self): + c1 = pygame.Color(0x80808080) + self.assertEqual(c1.r, 128) + self.assertEqual(c1.g, 128) + self.assertEqual(c1.b, 128) + self.assertEqual(c1.a, 128) + + c2 = pygame.Color(2, 4, 8, 16) + self.assertEqual(c2.r, 2) + self.assertEqual(c2.g, 4) + self.assertEqual(c2.b, 8) + self.assertEqual(c2.a, 16) + + c3 = c1 // c2 + self.assertEqual(c3.r, 64) + self.assertEqual(c3.g, 32) + self.assertEqual(c3.b, 16) + self.assertEqual(c3.a, 8) + + c3 = c3 // c2 + self.assertEqual(c3.r, 32) + self.assertEqual(c3.g, 8) + self.assertEqual(c3.b, 2) + self.assertEqual(c3.a, 0) + + # Issue #286: Is type checking done for Python 3.x? + self.assertRaises(TypeError, operator.floordiv, c1, None) + self.assertRaises(TypeError, operator.floordiv, None, c1) + + # Division by zero check + dividend = pygame.Color(255, 255, 255, 255) + for i in range(4): + divisor = pygame.Color(64, 64, 64, 64) + divisor[i] = 0 + quotient = pygame.Color(3, 3, 3, 3) + quotient[i] = 0 + self.assertEqual(dividend // divisor, quotient) + + def test_mod(self): + c1 = pygame.Color(0xFFFFFFFF) + self.assertEqual(c1.r, 255) + self.assertEqual(c1.g, 255) + self.assertEqual(c1.b, 255) + self.assertEqual(c1.a, 255) + + c2 = pygame.Color(2, 4, 8, 16) + self.assertEqual(c2.r, 2) + self.assertEqual(c2.g, 4) + self.assertEqual(c2.b, 8) + self.assertEqual(c2.a, 16) + + c3 = c1 % c2 + self.assertEqual(c3.r, 1) + self.assertEqual(c3.g, 3) + self.assertEqual(c3.b, 7) + self.assertEqual(c3.a, 15) + + # Issue #286: Is type checking done for Python 3.x? + self.assertRaises(TypeError, operator.mod, c1, None) + self.assertRaises(TypeError, operator.mod, None, c1) + + # Division by zero check + dividend = pygame.Color(255, 255, 255, 255) + for i in range(4): + divisor = pygame.Color(64, 64, 64, 64) + divisor[i] = 0 + quotient = pygame.Color(63, 63, 63, 63) + quotient[i] = 0 + self.assertEqual(dividend % divisor, quotient) + + def test_float(self): + c = pygame.Color(0xCC00CC00) + self.assertEqual(c.r, 204) + self.assertEqual(c.g, 0) + self.assertEqual(c.b, 204) + self.assertEqual(c.a, 0) + self.assertEqual(float(c), float(0xCC00CC00)) + + c = pygame.Color(0x33727592) + self.assertEqual(c.r, 51) + self.assertEqual(c.g, 114) + self.assertEqual(c.b, 117) + self.assertEqual(c.a, 146) + self.assertEqual(float(c), float(0x33727592)) + + def test_oct(self): + c = pygame.Color(0xCC00CC00) + self.assertEqual(c.r, 204) + self.assertEqual(c.g, 0) + self.assertEqual(c.b, 204) + self.assertEqual(c.a, 0) + self.assertEqual(oct(c), oct(0xCC00CC00)) + + c = pygame.Color(0x33727592) + self.assertEqual(c.r, 51) + self.assertEqual(c.g, 114) + self.assertEqual(c.b, 117) + self.assertEqual(c.a, 146) + self.assertEqual(oct(c), oct(0x33727592)) + + def test_hex(self): + c = pygame.Color(0xCC00CC00) + self.assertEqual(c.r, 204) + self.assertEqual(c.g, 0) + self.assertEqual(c.b, 204) + self.assertEqual(c.a, 0) + self.assertEqual(hex(c), hex(0xCC00CC00)) + + c = pygame.Color(0x33727592) + self.assertEqual(c.r, 51) + self.assertEqual(c.g, 114) + self.assertEqual(c.b, 117) + self.assertEqual(c.a, 146) + self.assertEqual(hex(c), hex(0x33727592)) + + def test_webstyle(self): + c = pygame.Color("#CC00CC11") + self.assertEqual(c.r, 204) + self.assertEqual(c.g, 0) + self.assertEqual(c.b, 204) + self.assertEqual(c.a, 17) + self.assertEqual(hex(c), hex(0xCC00CC11)) + + c = pygame.Color("#CC00CC") + self.assertEqual(c.r, 204) + self.assertEqual(c.g, 0) + self.assertEqual(c.b, 204) + self.assertEqual(c.a, 255) + self.assertEqual(hex(c), hex(0xCC00CCFF)) + + c = pygame.Color("0xCC00CC11") + self.assertEqual(c.r, 204) + self.assertEqual(c.g, 0) + self.assertEqual(c.b, 204) + self.assertEqual(c.a, 17) + self.assertEqual(hex(c), hex(0xCC00CC11)) + + c = pygame.Color("0xCC00CC") + self.assertEqual(c.r, 204) + self.assertEqual(c.g, 0) + self.assertEqual(c.b, 204) + self.assertEqual(c.a, 255) + self.assertEqual(hex(c), hex(0xCC00CCFF)) + + self.assertRaises(ValueError, pygame.Color, "#cc00qq") + self.assertRaises(ValueError, pygame.Color, "0xcc00qq") + self.assertRaises(ValueError, pygame.Color, "09abcdef") + self.assertRaises(ValueError, pygame.Color, "09abcde") + self.assertRaises(ValueError, pygame.Color, "quarky") + + def test_int(self): + # This will be a long + c = pygame.Color(0xCC00CC00) + self.assertEqual(c.r, 204) + self.assertEqual(c.g, 0) + self.assertEqual(c.b, 204) + self.assertEqual(c.a, 0) + self.assertEqual(int(c), int(0xCC00CC00)) + + # This will be an int + c = pygame.Color(0x33727592) + self.assertEqual(c.r, 51) + self.assertEqual(c.g, 114) + self.assertEqual(c.b, 117) + self.assertEqual(c.a, 146) + self.assertEqual(int(c), int(0x33727592)) + + def test_long(self): + # This will be a long + c = pygame.Color(0xCC00CC00) + self.assertEqual(c.r, 204) + self.assertEqual(c.g, 0) + self.assertEqual(c.b, 204) + self.assertEqual(c.a, 0) + self.assertEqual(int(c), int(0xCC00CC00)) + + # This will be an int + c = pygame.Color(0x33727592) + self.assertEqual(c.r, 51) + self.assertEqual(c.g, 114) + self.assertEqual(c.b, 117) + self.assertEqual(c.a, 146) + self.assertEqual(int(c), int(0x33727592)) + + def test_normalize(self): + c = pygame.Color(204, 38, 194, 55) + self.assertEqual(c.r, 204) + self.assertEqual(c.g, 38) + self.assertEqual(c.b, 194) + self.assertEqual(c.a, 55) + + t = c.normalize() + + self.assertAlmostEqual(t[0], 0.800000, 5) + self.assertAlmostEqual(t[1], 0.149016, 5) + self.assertAlmostEqual(t[2], 0.760784, 5) + self.assertAlmostEqual(t[3], 0.215686, 5) + + def test_len(self): + c = pygame.Color(204, 38, 194, 55) + self.assertEqual(len(c), 4) + + def test_get_item(self): + c = pygame.Color(204, 38, 194, 55) + self.assertEqual(c[0], 204) + self.assertEqual(c[1], 38) + self.assertEqual(c[2], 194) + self.assertEqual(c[3], 55) + + def test_set_item(self): + c = pygame.Color(204, 38, 194, 55) + self.assertEqual(c[0], 204) + self.assertEqual(c[1], 38) + self.assertEqual(c[2], 194) + self.assertEqual(c[3], 55) + + c[0] = 33 + self.assertEqual(c[0], 33) + c[1] = 48 + self.assertEqual(c[1], 48) + c[2] = 173 + self.assertEqual(c[2], 173) + c[3] = 213 + self.assertEqual(c[3], 213) + + # Now try some 'invalid' ones + self.assertRaises(TypeError, _assign_item, c, 0, 95.485) + self.assertEqual(c[0], 33) + self.assertRaises(ValueError, _assign_item, c, 1, -83) + self.assertEqual(c[1], 48) + self.assertRaises(TypeError, _assign_item, c, 2, "Hello") + self.assertEqual(c[2], 173) + + def test_Color_type_works_for_Surface_get_and_set_colorkey(self): + s = pygame.Surface((32, 32)) + + c = pygame.Color(33, 22, 11, 255) + s.set_colorkey(c) + + get_r, get_g, get_b, get_a = s.get_colorkey() + + self.assertTrue(get_r == c.r) + self.assertTrue(get_g == c.g) + self.assertTrue(get_b == c.b) + self.assertTrue(get_a == c.a) + + ########## HSLA, HSVA, CMY, I1I2I3 ALL ELEMENTS WITHIN SPECIFIED RANGE ######### + + def test_hsla__all_elements_within_limits(self): + for c in rgba_combos_Color_generator(): + h, s, l, a = c.hsla + self.assertTrue(0 <= h <= 360) + self.assertTrue(0 <= s <= 100) + self.assertTrue(0 <= l <= 100) + self.assertTrue(0 <= a <= 100) + + def test_hsva__all_elements_within_limits(self): + for c in rgba_combos_Color_generator(): + h, s, v, a = c.hsva + self.assertTrue(0 <= h <= 360) + self.assertTrue(0 <= s <= 100) + self.assertTrue(0 <= v <= 100) + self.assertTrue(0 <= a <= 100) + + def test_cmy__all_elements_within_limits(self): + for c in rgba_combos_Color_generator(): + c, m, y = c.cmy + self.assertTrue(0 <= c <= 1) + self.assertTrue(0 <= m <= 1) + self.assertTrue(0 <= y <= 1) + + def test_i1i2i3__all_elements_within_limits(self): + for c in rgba_combos_Color_generator(): + i1, i2, i3 = c.i1i2i3 + self.assertTrue(0 <= i1 <= 1) + self.assertTrue(-0.5 <= i2 <= 0.5) + self.assertTrue(-0.5 <= i3 <= 0.5) + + def test_issue_269(self): + """PyColor OverflowError on HSVA with hue value of 360 + + >>> c = pygame.Color(0) + >>> c.hsva = (360,0,0,0) + Traceback (most recent call last): + File "", line 1, in + OverflowError: this is not allowed to happen ever + >>> pygame.ver + '1.9.1release' + >>> + + """ + + c = pygame.Color(0) + c.hsva = 360, 0, 0, 0 + self.assertEqual(c.hsva, (0, 0, 0, 0)) + c.hsva = 360, 100, 100, 100 + self.assertEqual(c.hsva, (0, 100, 100, 100)) + self.assertEqual(c, (255, 0, 0, 255)) + + ####################### COLORSPACE PROPERTY SANITY TESTS ####################### + + def colorspaces_converted_should_not_raise(self, prop): + fails = 0 + + x = 0 + for c in rgba_combos_Color_generator(): + x += 1 + + other = pygame.Color(0) + + try: + setattr(other, prop, getattr(c, prop)) + # eg other.hsla = c.hsla + + except ValueError: + fails += 1 + + self.assertTrue(x > 0, "x is combination counter, 0 means no tests!") + self.assertTrue((fails, x) == (0, x)) + + def test_hsla__sanity_testing_converted_should_not_raise(self): + self.colorspaces_converted_should_not_raise("hsla") + + def test_hsva__sanity_testing_converted_should_not_raise(self): + self.colorspaces_converted_should_not_raise("hsva") + + def test_cmy__sanity_testing_converted_should_not_raise(self): + self.colorspaces_converted_should_not_raise("cmy") + + def test_i1i2i3__sanity_testing_converted_should_not_raise(self): + self.colorspaces_converted_should_not_raise("i1i2i3") + + ################################################################################ + + def colorspaces_converted_should_equate_bar_rounding(self, prop): + for c in rgba_combos_Color_generator(): + other = pygame.Color(0) + + try: + setattr(other, prop, getattr(c, prop)) + # eg other.hsla = c.hsla + + self.assertTrue(abs(other.r - c.r) <= 1) + self.assertTrue(abs(other.b - c.b) <= 1) + self.assertTrue(abs(other.g - c.g) <= 1) + # CMY and I1I2I3 do not care about the alpha + if not prop in ("cmy", "i1i2i3"): + self.assertTrue(abs(other.a - c.a) <= 1) + + except ValueError: + pass # other tests will notify, this tests equation + + def test_hsla__sanity_testing_converted_should_equate_bar_rounding(self): + self.colorspaces_converted_should_equate_bar_rounding("hsla") + + def test_hsva__sanity_testing_converted_should_equate_bar_rounding(self): + self.colorspaces_converted_should_equate_bar_rounding("hsva") + + def test_cmy__sanity_testing_converted_should_equate_bar_rounding(self): + self.colorspaces_converted_should_equate_bar_rounding("cmy") + + def test_i1i2i3__sanity_testing_converted_should_equate_bar_rounding(self): + self.colorspaces_converted_should_equate_bar_rounding("i1i2i3") + + ################################################################################ + + def test_correct_gamma__verified_against_python_implementation(self): + "|tags:slow|" + # gamma_correct defined at top of page + + gammas = [i / 10.0 for i in range(1, 31)] # [0.1 ... 3.0] + gammas_len = len(gammas) + + for i, c in enumerate(rgba_combos_Color_generator()): + gamma = gammas[i % gammas_len] + + corrected = pygame.Color(*[gamma_correct(x, gamma) for x in tuple(c)]) + lib_corrected = c.correct_gamma(gamma) + + self.assertTrue(corrected.r == lib_corrected.r) + self.assertTrue(corrected.g == lib_corrected.g) + self.assertTrue(corrected.b == lib_corrected.b) + self.assertTrue(corrected.a == lib_corrected.a) + + # TODO: test against statically defined verified _correct_ values + # assert corrected.r == 125 etc. + + def test_pickle(self): + import pickle + + c1 = pygame.Color(1, 2, 3, 4) + # c2 = pygame.Color(255,254,253,252) + pickle_string = pickle.dumps(c1) + c1_frompickle = pickle.loads(pickle_string) + self.assertEqual(c1, c1_frompickle) + + ################################################################################ + # only available if ctypes module is also available + + @unittest.skipIf(IS_PYPY, "PyPy has no ctypes") + def test_arraystruct(self): + + import pygame.tests.test_utils.arrinter as ai + import ctypes as ct + + c_byte_p = ct.POINTER(ct.c_byte) + c = pygame.Color(5, 7, 13, 23) + flags = ai.PAI_CONTIGUOUS | ai.PAI_FORTRAN | ai.PAI_ALIGNED | ai.PAI_NOTSWAPPED + for i in range(1, 5): + c.set_length(i) + inter = ai.ArrayInterface(c) + self.assertEqual(inter.two, 2) + self.assertEqual(inter.nd, 1) + self.assertEqual(inter.typekind, "u") + self.assertEqual(inter.itemsize, 1) + self.assertEqual(inter.flags, flags) + self.assertEqual(inter.shape[0], i) + self.assertEqual(inter.strides[0], 1) + data = ct.cast(inter.data, c_byte_p) + for j in range(i): + self.assertEqual(data[j], c[j]) + + @unittest.skipIf(not pygame.HAVE_NEWBUF, "newbuf not implemented") + def test_newbuf(self): + from pygame.tests.test_utils import buftools + from ctypes import cast, POINTER, c_uint8 + + class ColorImporter(buftools.Importer): + def __init__(self, color, flags): + super(ColorImporter, self).__init__(color, flags) + self.items = cast(self.buf, POINTER(c_uint8)) + + def __getitem__(self, index): + if 0 <= index < 4: + return self.items[index] + raise IndexError( + "valid index values are between 0 and 3: " "got {}".format(index) + ) + + def __setitem__(self, index, value): + if 0 <= index < 4: + self.items[index] = value + else: + raise IndexError( + "valid index values are between 0 and 3: " + "got {}".format(index) + ) + + c = pygame.Color(50, 100, 150, 200) + imp = ColorImporter(c, buftools.PyBUF_SIMPLE) + self.assertTrue(imp.obj is c) + self.assertEqual(imp.ndim, 0) + self.assertEqual(imp.itemsize, 1) + self.assertEqual(imp.len, 4) + self.assertTrue(imp.readonly) + self.assertTrue(imp.format is None) + self.assertTrue(imp.shape is None) + self.assertTrue(imp.strides is None) + self.assertTrue(imp.suboffsets is None) + for i in range(4): + self.assertEqual(c[i], imp[i]) + imp[0] = 60 + self.assertEqual(c.r, 60) + imp[1] = 110 + self.assertEqual(c.g, 110) + imp[2] = 160 + self.assertEqual(c.b, 160) + imp[3] = 210 + self.assertEqual(c.a, 210) + imp = ColorImporter(c, buftools.PyBUF_FORMAT) + self.assertEqual(imp.ndim, 0) + self.assertEqual(imp.itemsize, 1) + self.assertEqual(imp.len, 4) + self.assertEqual(imp.format, "B") + self.assertEqual(imp.ndim, 0) + self.assertEqual(imp.itemsize, 1) + self.assertEqual(imp.len, 4) + imp = ColorImporter(c, buftools.PyBUF_ND) + self.assertEqual(imp.ndim, 1) + self.assertEqual(imp.itemsize, 1) + self.assertEqual(imp.len, 4) + self.assertTrue(imp.format is None) + self.assertEqual(imp.shape, (4,)) + self.assertEqual(imp.strides, None) + imp = ColorImporter(c, buftools.PyBUF_STRIDES) + self.assertEqual(imp.ndim, 1) + self.assertTrue(imp.format is None) + self.assertEqual(imp.shape, (4,)) + self.assertEqual(imp.strides, (1,)) + imp = ColorImporter(c, buftools.PyBUF_C_CONTIGUOUS) + self.assertEqual(imp.ndim, 1) + imp = ColorImporter(c, buftools.PyBUF_F_CONTIGUOUS) + self.assertEqual(imp.ndim, 1) + imp = ColorImporter(c, buftools.PyBUF_ANY_CONTIGUOUS) + self.assertEqual(imp.ndim, 1) + for i in range(1, 5): + c.set_length(i) + imp = ColorImporter(c, buftools.PyBUF_ND) + self.assertEqual(imp.ndim, 1) + self.assertEqual(imp.len, i) + self.assertEqual(imp.shape, (i,)) + self.assertRaises(BufferError, ColorImporter, c, buftools.PyBUF_WRITABLE) + + def test_lerp(self): + # setup + Color = pygame.color.Color + + color0 = Color(0, 0, 0, 0) + color128 = Color(128, 128, 128, 128) + color255 = Color(255, 255, 255, 255) + color100 = Color(100, 100, 100, 100) + + # type checking + self.assertTrue(isinstance(color0.lerp(color128, 0.5), Color)) + + # common value testing + self.assertEqual(color0.lerp(color128, 0.5), Color(64, 64, 64, 64)) + self.assertEqual(color0.lerp(color128, 0.5), Color(64, 64, 64, 64)) + self.assertEqual(color128.lerp(color255, 0.5), Color(192, 192, 192, 192)) + self.assertEqual(color0.lerp(color255, 0.5), Color(128, 128, 128, 128)) + + # testing extremes + self.assertEqual(color0.lerp(color100, 0), color0) + self.assertEqual(color0.lerp(color100, 0.01), Color(1, 1, 1, 1)) + self.assertEqual(color0.lerp(color100, 0.99), Color(99, 99, 99, 99)) + self.assertEqual(color0.lerp(color100, 1), color100) + + # kwarg testing + self.assertEqual(color0.lerp(color=color100, amount=0.5), Color(50, 50, 50, 50)) + self.assertEqual(color0.lerp(amount=0.5, color=color100), Color(50, 50, 50, 50)) + + # invalid input testing + self.assertRaises(ValueError, lambda: color0.lerp(color128, 2.5)) + self.assertRaises(ValueError, lambda: color0.lerp(color128, -0.5)) + self.assertRaises(ValueError, lambda: color0.lerp((256, 0, 0, 0), 0.5)) + self.assertRaises(ValueError, lambda: color0.lerp((0, 256, 0, 0), 0.5)) + self.assertRaises(ValueError, lambda: color0.lerp((0, 0, 256, 0), 0.5)) + self.assertRaises(ValueError, lambda: color0.lerp((0, 0, 0, 256), 0.5)) + self.assertRaises(TypeError, lambda: color0.lerp(0.2, 0.5)) + + def test_premul_alpha(self): + # setup + Color = pygame.color.Color + + color0 = Color(0, 0, 0, 0) + alpha0 = Color(255, 255, 255, 0) + alpha49 = Color(255, 0, 0, 49) + alpha67 = Color(0, 255, 0, 67) + alpha73 = Color(0, 0, 255, 73) + alpha128 = Color(255, 255, 255, 128) + alpha199 = Color(255, 255, 255, 199) + alpha255 = Color(128, 128, 128, 255) + + # type checking + self.assertTrue(isinstance(color0.premul_alpha(), Color)) + + # hand crafted value testing + self.assertEqual(alpha0.premul_alpha(), Color(0, 0, 0, 0)) + self.assertEqual(alpha49.premul_alpha(), Color(49, 0, 0, 49)) + self.assertEqual(alpha67.premul_alpha(), Color(0, 67, 0, 67)) + self.assertEqual(alpha73.premul_alpha(), Color(0, 0, 73, 73)) + self.assertEqual(alpha128.premul_alpha(), Color(128, 128, 128, 128)) + self.assertEqual(alpha199.premul_alpha(), Color(199, 199, 199, 199)) + self.assertEqual(alpha255.premul_alpha(), Color(128, 128, 128, 255)) + + # full range of alpha auto sub-testing + test_colors = [ + (200, 30, 74), + (76, 83, 24), + (184, 21, 6), + (74, 4, 74), + (76, 83, 24), + (184, 21, 234), + (160, 30, 74), + (96, 147, 204), + (198, 201, 60), + (132, 89, 74), + (245, 9, 224), + (184, 112, 6), + ] + + for r, g, b in test_colors: + for a in range(255): + with self.subTest(r=r, g=g, b=b, a=a): + alpha = a / 255.0 + self.assertEqual( + Color(r, g, b, a).premul_alpha(), + Color( + ((r + 1) * a) >> 8, + ((g + 1) * a) >> 8, + ((b + 1) * a) >> 8, + a, + ), + ) + + def test_update(self): + c = pygame.color.Color(0, 0, 0) + c.update(1, 2, 3, 4) + + self.assertEqual(c.r, 1) + self.assertEqual(c.g, 2) + self.assertEqual(c.b, 3) + self.assertEqual(c.a, 4) + + c = pygame.color.Color(0, 0, 0) + c.update([1, 2, 3, 4]) + + self.assertEqual(c.r, 1) + self.assertEqual(c.g, 2) + self.assertEqual(c.b, 3) + self.assertEqual(c.a, 4) + + c = pygame.color.Color(0, 0, 0) + c2 = pygame.color.Color(1, 2, 3, 4) + c.update(c2) + + self.assertEqual(c.r, 1) + self.assertEqual(c.g, 2) + self.assertEqual(c.b, 3) + self.assertEqual(c.a, 4) + + c = pygame.color.Color(1, 1, 1) + c.update("black") + + self.assertEqual(c.r, 0) + self.assertEqual(c.g, 0) + self.assertEqual(c.b, 0) + self.assertEqual(c.a, 255) + + c = pygame.color.Color(0, 0, 0, 120) + c.set_length(3) + c.update(1, 2, 3) + self.assertEqual(len(c), 3) + c.set_length(4) + self.assertEqual(c[3], 120) + + c.set_length(3) + c.update(1, 2, 3, 4) + self.assertEqual(len(c), 4) + + +class SubclassTest(unittest.TestCase): + class MyColor(pygame.Color): + def __init__(self, *args, **kwds): + super(SubclassTest.MyColor, self).__init__(*args, **kwds) + self.an_attribute = True + + def test_add(self): + mc1 = self.MyColor(128, 128, 128, 255) + self.assertTrue(mc1.an_attribute) + c2 = pygame.Color(64, 64, 64, 255) + mc2 = mc1 + c2 + self.assertTrue(isinstance(mc2, self.MyColor)) + self.assertRaises(AttributeError, getattr, mc2, "an_attribute") + c3 = c2 + mc1 + self.assertTrue(type(c3) is pygame.Color) + + def test_sub(self): + mc1 = self.MyColor(128, 128, 128, 255) + self.assertTrue(mc1.an_attribute) + c2 = pygame.Color(64, 64, 64, 255) + mc2 = mc1 - c2 + self.assertTrue(isinstance(mc2, self.MyColor)) + self.assertRaises(AttributeError, getattr, mc2, "an_attribute") + c3 = c2 - mc1 + self.assertTrue(type(c3) is pygame.Color) + + def test_mul(self): + mc1 = self.MyColor(128, 128, 128, 255) + self.assertTrue(mc1.an_attribute) + c2 = pygame.Color(64, 64, 64, 255) + mc2 = mc1 * c2 + self.assertTrue(isinstance(mc2, self.MyColor)) + self.assertRaises(AttributeError, getattr, mc2, "an_attribute") + c3 = c2 * mc1 + self.assertTrue(type(c3) is pygame.Color) + + def test_div(self): + mc1 = self.MyColor(128, 128, 128, 255) + self.assertTrue(mc1.an_attribute) + c2 = pygame.Color(64, 64, 64, 255) + mc2 = mc1 // c2 + self.assertTrue(isinstance(mc2, self.MyColor)) + self.assertRaises(AttributeError, getattr, mc2, "an_attribute") + c3 = c2 // mc1 + self.assertTrue(type(c3) is pygame.Color) + + def test_mod(self): + mc1 = self.MyColor(128, 128, 128, 255) + self.assertTrue(mc1.an_attribute) + c2 = pygame.Color(64, 64, 64, 255) + mc2 = mc1 % c2 + self.assertTrue(isinstance(mc2, self.MyColor)) + self.assertRaises(AttributeError, getattr, mc2, "an_attribute") + c3 = c2 % mc1 + self.assertTrue(type(c3) is pygame.Color) + + def test_inv(self): + mc1 = self.MyColor(64, 64, 64, 64) + self.assertTrue(mc1.an_attribute) + mc2 = ~mc1 + self.assertTrue(isinstance(mc2, self.MyColor)) + self.assertRaises(AttributeError, getattr, mc2, "an_attribute") + + def test_correct_gamma(self): + mc1 = self.MyColor(64, 70, 75, 255) + self.assertTrue(mc1.an_attribute) + mc2 = mc1.correct_gamma(0.03) + self.assertTrue(isinstance(mc2, self.MyColor)) + self.assertRaises(AttributeError, getattr, mc2, "an_attribute") + + +################################################################################ + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/constants_test.py b/venv/Lib/site-packages/pygame/tests/constants_test.py new file mode 100644 index 0000000..452a8fe --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/constants_test.py @@ -0,0 +1,437 @@ +import unittest +import pygame.constants + + +# K_* and KSCAN_* common names. +K_AND_KSCAN_COMMON_NAMES = ( + "UNKNOWN", + "BACKSPACE", + "TAB", + "CLEAR", + "RETURN", + "PAUSE", + "ESCAPE", + "SPACE", + "COMMA", + "MINUS", + "PERIOD", + "SLASH", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "SEMICOLON", + "EQUALS", + "LEFTBRACKET", + "BACKSLASH", + "RIGHTBRACKET", + "DELETE", + "KP0", + "KP1", + "KP2", + "KP3", + "KP4", + "KP5", + "KP6", + "KP7", + "KP8", + "KP9", + "KP_PERIOD", + "KP_DIVIDE", + "KP_MULTIPLY", + "KP_MINUS", + "KP_PLUS", + "KP_ENTER", + "KP_EQUALS", + "UP", + "DOWN", + "RIGHT", + "LEFT", + "INSERT", + "HOME", + "END", + "PAGEUP", + "PAGEDOWN", + "F1", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + "F8", + "F9", + "F10", + "F11", + "F12", + "F13", + "F14", + "F15", + "NUMLOCK", + "CAPSLOCK", + "SCROLLOCK", + "RSHIFT", + "LSHIFT", + "RCTRL", + "LCTRL", + "RALT", + "LALT", + "RMETA", + "LMETA", + "LSUPER", + "RSUPER", + "MODE", + "HELP", + "PRINT", + "SYSREQ", + "BREAK", + "MENU", + "POWER", + "EURO", + "KP_0", + "KP_1", + "KP_2", + "KP_3", + "KP_4", + "KP_5", + "KP_6", + "KP_7", + "KP_8", + "KP_9", + "NUMLOCKCLEAR", + "SCROLLLOCK", + "RGUI", + "LGUI", + "PRINTSCREEN", + "CURRENCYUNIT", + "CURRENCYSUBUNIT", +) + +# Constants that have the same value. +K_AND_KSCAN_COMMON_OVERLAPS = ( + ("KP0", "KP_0"), + ("KP1", "KP_1"), + ("KP2", "KP_2"), + ("KP3", "KP_3"), + ("KP4", "KP_4"), + ("KP5", "KP_5"), + ("KP6", "KP_6"), + ("KP7", "KP_7"), + ("KP8", "KP_8"), + ("KP9", "KP_9"), + ("NUMLOCK", "NUMLOCKCLEAR"), + ("SCROLLOCK", "SCROLLLOCK"), + ("LSUPER", "LMETA", "LGUI"), + ("RSUPER", "RMETA", "RGUI"), + ("PRINT", "PRINTSCREEN"), + ("BREAK", "PAUSE"), + ("EURO", "CURRENCYUNIT"), +) + + +def create_overlap_set(constant_names): + """Helper function to find overlapping constant values/names. + + Returns a set of fronzensets: + set(frozenset(names of overlapping constants), ...) + """ + # Create an overlap dict. + overlap_dict = {} + + for name in constant_names: + value = getattr(pygame.constants, name) + overlap_dict.setdefault(value, set()).add(name) + + # Get all entries with more than 1 value. + overlaps = set() + + for overlap_names in overlap_dict.values(): + if len(overlap_names) > 1: + overlaps.add(frozenset(overlap_names)) + + return overlaps + + +class KConstantsTests(unittest.TestCase): + """Test K_* (key) constants.""" + + # K_* specific names. + K_SPECIFIC_NAMES = ( + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "QUOTE", + "BACKQUOTE", + "EXCLAIM", + "QUOTEDBL", + "HASH", + "DOLLAR", + "AMPERSAND", + "LEFTPAREN", + "RIGHTPAREN", + "ASTERISK", + "PLUS", + "COLON", + "LESS", + "GREATER", + "QUESTION", + "AT", + "CARET", + "UNDERSCORE", + "PERCENT", + ) + + # Create a sequence of all the K_* constant names. + K_NAMES = tuple("K_" + n for n in K_AND_KSCAN_COMMON_NAMES + K_SPECIFIC_NAMES) + + def test_k__existence(self): + """Ensures K constants exist.""" + for name in self.K_NAMES: + self.assertTrue( + hasattr(pygame.constants, name), "missing constant {}".format(name) + ) + + def test_k__type(self): + """Ensures K constants are the correct type.""" + for name in self.K_NAMES: + value = getattr(pygame.constants, name) + + self.assertIs(type(value), int) + + def test_k__value_overlap(self): + """Ensures no unexpected K constant values overlap.""" + EXPECTED_OVERLAPS = set( + [ + frozenset(["K_" + n for n in item]) + for item in K_AND_KSCAN_COMMON_OVERLAPS + ] + ) + + overlaps = create_overlap_set(self.K_NAMES) + + self.assertSetEqual(overlaps, EXPECTED_OVERLAPS) + + +class KscanConstantsTests(unittest.TestCase): + """Test KSCAN_* (scancode) constants.""" + + # KSCAN_* specific names. + KSCAN_SPECIFIC_NAMES = ( + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "APOSTROPHE", + "GRAVE", + "INTERNATIONAL1", + "INTERNATIONAL2", + "INTERNATIONAL3", + "INTERNATIONAL4", + "INTERNATIONAL5", + "INTERNATIONAL6", + "INTERNATIONAL7", + "INTERNATIONAL8", + "INTERNATIONAL9", + "LANG1", + "LANG2", + "LANG3", + "LANG4", + "LANG5", + "LANG6", + "LANG7", + "LANG8", + "LANG9", + "NONUSBACKSLASH", + "NONUSHASH", + ) + + # Create a sequence of all the KSCAN_* constant names. + KSCAN_NAMES = tuple( + "KSCAN_" + n for n in K_AND_KSCAN_COMMON_NAMES + KSCAN_SPECIFIC_NAMES + ) + + def test_kscan__existence(self): + """Ensures KSCAN constants exist.""" + for name in self.KSCAN_NAMES: + self.assertTrue( + hasattr(pygame.constants, name), "missing constant {}".format(name) + ) + + def test_kscan__type(self): + """Ensures KSCAN constants are the correct type.""" + for name in self.KSCAN_NAMES: + value = getattr(pygame.constants, name) + + self.assertIs(type(value), int) + + def test_kscan__value_overlap(self): + """Ensures no unexpected KSCAN constant values overlap.""" + EXPECTED_OVERLAPS = set( + [ + frozenset(["KSCAN_" + n for n in item]) + for item in K_AND_KSCAN_COMMON_OVERLAPS + ] + ) + + overlaps = create_overlap_set(self.KSCAN_NAMES) + + self.assertSetEqual(overlaps, EXPECTED_OVERLAPS) + + +class KmodConstantsTests(unittest.TestCase): + """Test KMOD_* (key modifier) constants.""" + + # KMOD_* constant names. + KMOD_CONSTANTS = ( + "KMOD_NONE", + "KMOD_LSHIFT", + "KMOD_RSHIFT", + "KMOD_SHIFT", + "KMOD_LCTRL", + "KMOD_RCTRL", + "KMOD_CTRL", + "KMOD_LALT", + "KMOD_RALT", + "KMOD_ALT", + "KMOD_LMETA", + "KMOD_RMETA", + "KMOD_META", + "KMOD_NUM", + "KMOD_CAPS", + "KMOD_MODE", + "KMOD_LGUI", + "KMOD_RGUI", + "KMOD_GUI", + ) + + def test_kmod__existence(self): + """Ensures KMOD constants exist.""" + for name in self.KMOD_CONSTANTS: + self.assertTrue( + hasattr(pygame.constants, name), "missing constant {}".format(name) + ) + + def test_kmod__type(self): + """Ensures KMOD constants are the correct type.""" + for name in self.KMOD_CONSTANTS: + value = getattr(pygame.constants, name) + + self.assertIs(type(value), int) + + def test_kmod__value_overlap(self): + """Ensures no unexpected KMOD constant values overlap.""" + # KMODs that have the same values. + EXPECTED_OVERLAPS = { + frozenset(["KMOD_LGUI", "KMOD_LMETA"]), + frozenset(["KMOD_RGUI", "KMOD_RMETA"]), + frozenset(["KMOD_GUI", "KMOD_META"]), + } + + overlaps = create_overlap_set(self.KMOD_CONSTANTS) + + self.assertSetEqual(overlaps, EXPECTED_OVERLAPS) + + def test_kmod__no_bitwise_overlap(self): + """Ensures certain KMOD constants have no overlapping bits.""" + NO_BITWISE_OVERLAP = ( + "KMOD_NONE", + "KMOD_LSHIFT", + "KMOD_RSHIFT", + "KMOD_LCTRL", + "KMOD_RCTRL", + "KMOD_LALT", + "KMOD_RALT", + "KMOD_LMETA", + "KMOD_RMETA", + "KMOD_NUM", + "KMOD_CAPS", + "KMOD_MODE", + ) + + kmods = 0 + + for name in NO_BITWISE_OVERLAP: + value = getattr(pygame.constants, name) + + self.assertFalse(kmods & value) + + kmods |= value + + def test_kmod__bitwise_overlap(self): + """Ensures certain KMOD constants have overlapping bits.""" + # KMODS that are comprised of other KMODs. + KMOD_COMPRISED_DICT = { + "KMOD_SHIFT": ("KMOD_LSHIFT", "KMOD_RSHIFT"), + "KMOD_CTRL": ("KMOD_LCTRL", "KMOD_RCTRL"), + "KMOD_ALT": ("KMOD_LALT", "KMOD_RALT"), + "KMOD_META": ("KMOD_LMETA", "KMOD_RMETA"), + "KMOD_GUI": ("KMOD_LGUI", "KMOD_RGUI"), + } + + for base_name, seq_names in KMOD_COMPRISED_DICT.items(): + expected_value = 0 # Reset. + + for name in seq_names: + expected_value |= getattr(pygame.constants, name) + + value = getattr(pygame.constants, base_name) + + self.assertEqual(value, expected_value) + + +################################################################################ + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/controller_test.py b/venv/Lib/site-packages/pygame/tests/controller_test.py new file mode 100644 index 0000000..f05c00c --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/controller_test.py @@ -0,0 +1,357 @@ +import unittest +import pygame +import pygame._sdl2.controller as controller +from pygame.tests.test_utils import prompt, question + + +class ControllerModuleTest(unittest.TestCase): + def setUp(self): + controller.init() + + def tearDown(self): + controller.quit() + + def test_init(self): + controller.quit() + controller.init() + self.assertTrue(controller.get_init()) + + def test_init__multiple(self): + controller.init() + controller.init() + self.assertTrue(controller.get_init()) + + def test_quit(self): + controller.quit() + self.assertFalse(controller.get_init()) + + def test_quit__multiple(self): + controller.quit() + controller.quit() + self.assertFalse(controller.get_init()) + + def test_get_init(self): + self.assertTrue(controller.get_init()) + + def test_get_eventstate(self): + controller.set_eventstate(True) + self.assertTrue(controller.get_eventstate()) + + controller.set_eventstate(False) + self.assertFalse(controller.get_eventstate()) + + controller.set_eventstate(True) + + def test_get_count(self): + self.assertGreaterEqual(controller.get_count(), 0) + + def test_is_controller(self): + for i in range(controller.get_count()): + if controller.is_controller(i): + c = controller.Controller(i) + self.assertIsInstance(c, controller.Controller) + c.quit() + else: + with self.assertRaises(pygame._sdl2.sdl2.error): + c = controller.Controller(i) + + with self.assertRaises(TypeError): + controller.is_controller("Test") + + def test_name_forindex(self): + self.assertIsNone(controller.name_forindex(-1)) + + +class ControllerTypeTest(unittest.TestCase): + def setUp(self): + controller.init() + + def tearDown(self): + controller.quit() + + def _get_first_controller(self): + for i in range(controller.get_count()): + if controller.is_controller(i): + return controller.Controller(i) + + def test_construction(self): + c = self._get_first_controller() + if c: + self.assertIsInstance(c, controller.Controller) + else: + self.skipTest("No controller connected") + + def test__auto_init(self): + c = self._get_first_controller() + if c: + self.assertTrue(c.get_init()) + else: + self.skipTest("No controller connected") + + def test_get_init(self): + c = self._get_first_controller() + if c: + self.assertTrue(c.get_init()) + c.quit() + self.assertFalse(c.get_init()) + else: + self.skipTest("No controller connected") + + def test_from_joystick(self): + for i in range(controller.get_count()): + if controller.is_controller(i): + joy = pygame.joystick.Joystick(i) + break + else: + self.skipTest("No controller connected") + + c = controller.Controller.from_joystick(joy) + self.assertIsInstance(c, controller.Controller) + + def test_as_joystick(self): + c = self._get_first_controller() + if c: + joy = c.as_joystick() + self.assertIsInstance(joy, type(pygame.joystick.Joystick(0))) + else: + self.skipTest("No controller connected") + + def test_get_mapping(self): + c = self._get_first_controller() + if c: + mapping = c.get_mapping() + self.assertIsInstance(mapping, dict) + self.assertIsNotNone(mapping["a"]) + else: + self.skipTest("No controller connected") + + def test_set_mapping(self): + c = self._get_first_controller() + if c: + mapping = c.get_mapping() + mapping["a"] = "b3" + mapping["y"] = "b0" + c.set_mapping(mapping) + new_mapping = c.get_mapping() + + self.assertEqual(len(mapping), len(new_mapping)) + for i in mapping: + if mapping[i] not in ("a", "y"): + self.assertEqual(mapping[i], new_mapping[i]) + else: + if i == "a": + self.assertEqual(new_mapping[i], mapping["y"]) + else: + self.assertEqual(new_mapping[i], mapping["a"]) + else: + self.skipTest("No controller connected") + + +class ControllerInteractiveTest(unittest.TestCase): + __tags__ = ["interactive"] + + def _get_first_controller(self): + for i in range(controller.get_count()): + if controller.is_controller(i): + return controller.Controller(i) + + def setUp(self): + controller.init() + + def tearDown(self): + controller.quit() + + def test__get_count_interactive(self): + prompt( + "Please connect at least one controller " + "before the test for controller.get_count() starts" + ) + + # Reset the number of joysticks counted + controller.quit() + controller.init() + + joystick_num = controller.get_count() + ans = question( + "get_count() thinks there are {} joysticks " + "connected. Is that correct?".format(joystick_num) + ) + + self.assertTrue(ans) + + def test_set_eventstate_on_interactive(self): + c = self._get_first_controller() + if not c: + self.skipTest("No controller connected") + + pygame.display.init() + pygame.font.init() + + screen = pygame.display.set_mode((400, 400)) + font = pygame.font.Font(None, 20) + running = True + + screen.fill((255, 255, 255)) + screen.blit( + font.render("Press button 'x' (on ps4) or 'a' (on xbox).", True, (0, 0, 0)), + (0, 0), + ) + pygame.display.update() + + controller.set_eventstate(True) + + while running: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + + if event.type == pygame.CONTROLLERBUTTONDOWN: + running = False + + pygame.display.quit() + pygame.font.quit() + + def test_set_eventstate_off_interactive(self): + c = self._get_first_controller() + if not c: + self.skipTest("No controller connected") + + pygame.display.init() + pygame.font.init() + + screen = pygame.display.set_mode((400, 400)) + font = pygame.font.Font(None, 20) + running = True + + screen.fill((255, 255, 255)) + screen.blit( + font.render("Press button 'x' (on ps4) or 'a' (on xbox).", True, (0, 0, 0)), + (0, 0), + ) + pygame.display.update() + + controller.set_eventstate(False) + + while running: + for event in pygame.event.get(pygame.QUIT): + if event: + running = False + + if c.get_button(pygame.CONTROLLER_BUTTON_A): + if pygame.event.peek(pygame.CONTROLLERBUTTONDOWN): + pygame.display.quit() + pygame.font.quit() + self.fail() + else: + running = False + + pygame.display.quit() + pygame.font.quit() + + def test_get_button_interactive(self): + c = self._get_first_controller() + if not c: + self.skipTest("No controller connected") + + pygame.display.init() + pygame.font.init() + + screen = pygame.display.set_mode((400, 400)) + font = pygame.font.Font(None, 20) + running = True + + label1 = font.render( + "Press button 'x' (on ps4) or 'a' (on xbox).", True, (0, 0, 0) + ) + + label2 = font.render( + 'The two values should match up. Press "y" or "n" to confirm.', + True, + (0, 0, 0), + ) + + is_pressed = [False, False] # event, get_button() + while running: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + if event.type == pygame.CONTROLLERBUTTONDOWN and event.button == 0: + is_pressed[0] = True + if event.type == pygame.CONTROLLERBUTTONUP and event.button == 0: + is_pressed[0] = False + + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_y: + running = False + if event.key == pygame.K_n: + running = False + pygame.display.quit() + pygame.font.quit() + self.fail() + + is_pressed[1] = c.get_button(pygame.CONTROLLER_BUTTON_A) + + screen.fill((255, 255, 255)) + screen.blit(label1, (0, 0)) + screen.blit(label2, (0, 20)) + screen.blit(font.render(str(is_pressed), True, (0, 0, 0)), (0, 40)) + pygame.display.update() + + pygame.display.quit() + pygame.font.quit() + + def test_get_axis_interactive(self): + c = self._get_first_controller() + if not c: + self.skipTest("No controller connected") + + pygame.display.init() + pygame.font.init() + + screen = pygame.display.set_mode((400, 400)) + font = pygame.font.Font(None, 20) + running = True + + label1 = font.render( + "Press down the right trigger. The value on-screen should", True, (0, 0, 0) + ) + + label2 = font.render( + "indicate how far the trigger is pressed down. This value should", + True, + (0, 0, 0), + ) + + label3 = font.render( + 'be in the range of 0-32767. Press "y" or "n" to confirm.', True, (0, 0, 0) + ) + + while running: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_y: + running = False + if event.key == pygame.K_n: + running = False + pygame.display.quit() + pygame.font.quit() + self.fail() + + right_trigger = c.get_axis(pygame.CONTROLLER_AXIS_TRIGGERRIGHT) + + screen.fill((255, 255, 255)) + screen.blit(label1, (0, 0)) + screen.blit(label2, (0, 20)) + screen.blit(label3, (0, 40)) + screen.blit(font.render(str(right_trigger), True, (0, 0, 0)), (0, 60)) + pygame.display.update() + + pygame.display.quit() + pygame.font.quit() + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/cursors_test.py b/venv/Lib/site-packages/pygame/tests/cursors_test.py new file mode 100644 index 0000000..bb8f766 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/cursors_test.py @@ -0,0 +1,291 @@ +import unittest +from pygame.tests.test_utils import fixture_path +import pygame + + +class CursorsModuleTest(unittest.TestCase): + def test_compile(self): + + # __doc__ (as of 2008-06-25) for pygame.cursors.compile: + + # pygame.cursors.compile(strings, black, white,xor) -> data, mask + # compile cursor strings into cursor data + # + # This takes a set of strings with equal length and computes + # the binary data for that cursor. The string widths must be + # divisible by 8. + # + # The black and white arguments are single letter strings that + # tells which characters will represent black pixels, and which + # characters represent white pixels. All other characters are + # considered clear. + # + # This returns a tuple containing the cursor data and cursor mask + # data. Both these arguments are used when setting a cursor with + # pygame.mouse.set_cursor(). + + # Various types of input strings + test_cursor1 = ("X.X.XXXX", "XXXXXX..", " XXXX ") + + test_cursor2 = ( + "X.X.XXXX", + "XXXXXX..", + "XXXXXX ", + "XXXXXX..", + "XXXXXX..", + "XXXXXX", + "XXXXXX..", + "XXXXXX..", + ) + test_cursor3 = (".XX.", " ", ".. ", "X.. X") + + # Test such that total number of strings is not divisible by 8 + with self.assertRaises(ValueError): + pygame.cursors.compile(test_cursor1) + + # Test such that size of individual string is not divisible by 8 + with self.assertRaises(ValueError): + pygame.cursors.compile(test_cursor2) + + # Test such that neither size of individual string nor total number of strings is divisible by 8 + with self.assertRaises(ValueError): + pygame.cursors.compile(test_cursor3) + + # Test that checks whether the byte data from compile funtion is equal to actual byte data + actual_byte_data = ( + 192, + 0, + 0, + 224, + 0, + 0, + 240, + 0, + 0, + 216, + 0, + 0, + 204, + 0, + 0, + 198, + 0, + 0, + 195, + 0, + 0, + 193, + 128, + 0, + 192, + 192, + 0, + 192, + 96, + 0, + 192, + 48, + 0, + 192, + 56, + 0, + 192, + 248, + 0, + 220, + 192, + 0, + 246, + 96, + 0, + 198, + 96, + 0, + 6, + 96, + 0, + 3, + 48, + 0, + 3, + 48, + 0, + 1, + 224, + 0, + 1, + 128, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ), ( + 192, + 0, + 0, + 224, + 0, + 0, + 240, + 0, + 0, + 248, + 0, + 0, + 252, + 0, + 0, + 254, + 0, + 0, + 255, + 0, + 0, + 255, + 128, + 0, + 255, + 192, + 0, + 255, + 224, + 0, + 255, + 240, + 0, + 255, + 248, + 0, + 255, + 248, + 0, + 255, + 192, + 0, + 247, + 224, + 0, + 199, + 224, + 0, + 7, + 224, + 0, + 3, + 240, + 0, + 3, + 240, + 0, + 1, + 224, + 0, + 1, + 128, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ) + + cursor = pygame.cursors.compile(pygame.cursors.thickarrow_strings) + self.assertEqual(cursor, actual_byte_data) + + # Test such that cursor byte data obtained from compile function is valid in pygame.mouse.set_cursor() + pygame.display.init() + try: + pygame.mouse.set_cursor((24, 24), (0, 0), *cursor) + except pygame.error as e: + if "not currently supported" in str(e): + unittest.skip("skipping test as set_cursor() is not supported") + finally: + pygame.display.quit() + + ################################################################################ + + def test_load_xbm(self): + # __doc__ (as of 2008-06-25) for pygame.cursors.load_xbm: + + # pygame.cursors.load_xbm(cursorfile, maskfile) -> cursor_args + # reads a pair of XBM files into set_cursor arguments + # + # Arguments can either be filenames or filelike objects + # with the readlines method. Not largely tested, but + # should work with typical XBM files. + + # Test that load_xbm will take filenames as arguments + cursorfile = fixture_path(r"xbm_cursors/white_sizing.xbm") + maskfile = fixture_path(r"xbm_cursors/white_sizing_mask.xbm") + cursor = pygame.cursors.load_xbm(cursorfile, maskfile) + + # Test that load_xbm will take file objects as arguments + with open(cursorfile) as cursor_f, open(maskfile) as mask_f: + cursor = pygame.cursors.load_xbm(cursor_f, mask_f) + + # Can it load using pathlib.Path? + import pathlib + + cursor = pygame.cursors.load_xbm( + pathlib.Path(cursorfile), pathlib.Path(maskfile) + ) + + # Is it in a format that mouse.set_cursor won't blow up on? + pygame.display.init() + try: + pygame.mouse.set_cursor(*cursor) + except pygame.error as e: + if "not currently supported" in str(e): + unittest.skip("skipping test as set_cursor() is not supported") + finally: + pygame.display.quit() + + def test_Cursor(self): + """Ensure that the cursor object parses information properly""" + + c1 = pygame.cursors.Cursor(pygame.SYSTEM_CURSOR_CROSSHAIR) + + self.assertEqual(c1.data, (pygame.SYSTEM_CURSOR_CROSSHAIR,)) + self.assertEqual(c1.type, "system") + + c2 = pygame.cursors.Cursor(c1) + + self.assertEqual(c1, c2) + + with self.assertRaises(TypeError): + pygame.cursors.Cursor(-34002) + with self.assertRaises(TypeError): + pygame.cursors.Cursor("a", "b", "c", "d") + with self.assertRaises(TypeError): + pygame.cursors.Cursor((2,)) + + c3 = pygame.cursors.Cursor((0, 0), pygame.Surface((20, 20))) + + self.assertEqual(c3.data[0], (0, 0)) + self.assertEqual(c3.data[1].get_size(), (20, 20)) + self.assertEqual(c3.type, "color") + + xormask, andmask = pygame.cursors.compile(pygame.cursors.thickarrow_strings) + c4 = pygame.cursors.Cursor((24, 24), (0, 0), xormask, andmask) + + self.assertEqual(c4.data, ((24, 24), (0, 0), xormask, andmask)) + self.assertEqual(c4.type, "bitmap") + + +################################################################################ + +if __name__ == "__main__": + unittest.main() + +################################################################################ diff --git a/venv/Lib/site-packages/pygame/tests/display_test.py b/venv/Lib/site-packages/pygame/tests/display_test.py new file mode 100644 index 0000000..a44ff15 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/display_test.py @@ -0,0 +1,811 @@ +# -*- coding: utf-8 -*- + +import unittest +import os +import time + +import pygame, pygame.transform + +from pygame.tests.test_utils import question + +from pygame import display + + +class DisplayModuleTest(unittest.TestCase): + default_caption = "pygame window" + + def setUp(self): + display.init() + + def tearDown(self): + display.quit() + + def test_Info(self): + inf = pygame.display.Info() + self.assertNotEqual(inf.current_h, -1) + self.assertNotEqual(inf.current_w, -1) + # probably have an older SDL than 1.2.10 if -1. + + screen = pygame.display.set_mode((128, 128)) + inf = pygame.display.Info() + self.assertEqual(inf.current_h, 128) + self.assertEqual(inf.current_w, 128) + + def test_flip(self): + screen = pygame.display.set_mode((100, 100)) + + # test without a change + self.assertIsNone(pygame.display.flip()) + + # test with a change + pygame.Surface.fill(screen, (66, 66, 53)) + self.assertIsNone(pygame.display.flip()) + + # test without display init + pygame.display.quit() + with self.assertRaises(pygame.error): + (pygame.display.flip()) + + # test without window + del screen + with self.assertRaises(pygame.error): + (pygame.display.flip()) + + def test_get_active(self): + """Test the get_active function""" + + # Initially, the display is not active + pygame.display.quit() + self.assertEqual(pygame.display.get_active(), False) + + # get_active defaults to true after a set_mode + pygame.display.init() + pygame.display.set_mode((640, 480)) + self.assertEqual(pygame.display.get_active(), True) + + # get_active after init/quit should be False + # since no display is visible + pygame.display.quit() + pygame.display.init() + self.assertEqual(pygame.display.get_active(), False) + + @unittest.skipIf( + os.environ.get("SDL_VIDEODRIVER") == "dummy", + "requires the SDL_VIDEODRIVER to be a non dummy value", + ) + def test_get_active_iconify(self): + """Test the get_active function after an iconify""" + + # According to the docs, get_active should return + # false if the display is iconified + pygame.display.set_mode((640, 480)) + + pygame.event.clear() + pygame.display.iconify() + + for _ in range(100): + time.sleep(0.01) + pygame.event.pump() + + self.assertEqual(pygame.display.get_active(), False) + + def test_get_caption(self): + screen = display.set_mode((100, 100)) + + self.assertEqual(display.get_caption()[0], self.default_caption) + + def test_set_caption(self): + TEST_CAPTION = "test" + screen = display.set_mode((100, 100)) + + self.assertIsNone(display.set_caption(TEST_CAPTION)) + self.assertEqual(display.get_caption()[0], TEST_CAPTION) + self.assertEqual(display.get_caption()[1], TEST_CAPTION) + + def test_caption_unicode(self): + TEST_CAPTION = "台" + display.set_caption(TEST_CAPTION) + self.assertEqual(display.get_caption()[0], TEST_CAPTION) + + def test_get_driver(self): + drivers = [ + "aalib", + "android", + "arm", + "cocoa", + "dga", + "directx", + "directfb", + "dummy", + "emscripten", + "fbcon", + "ggi", + "haiku", + "khronos", + "kmsdrm", + "nacl", + "offscreen", + "pandora", + "psp", + "qnx", + "raspberry", + "svgalib", + "uikit", + "vgl", + "vivante", + "wayland", + "windows", + "windib", + "winrt", + "x11", + ] + driver = display.get_driver() + self.assertIn(driver, drivers) + + display.quit() + with self.assertRaises(pygame.error): + driver = display.get_driver() + + def test_get_init(self): + """Ensures the module's initialization state can be retrieved.""" + # display.init() already called in setUp() + self.assertTrue(display.get_init()) + + # This test can be uncommented when issues #991 and #993 are resolved. + @unittest.skipIf(True, "SDL2 issues") + def test_get_surface(self): + """Ensures get_surface gets the current display surface.""" + lengths = (1, 5, 100) + + for expected_size in ((w, h) for w in lengths for h in lengths): + for expected_depth in (8, 16, 24, 32): + expected_surface = display.set_mode(expected_size, 0, expected_depth) + + surface = pygame.display.get_surface() + + self.assertEqual(surface, expected_surface) + self.assertIsInstance(surface, pygame.Surface) + self.assertEqual(surface.get_size(), expected_size) + self.assertEqual(surface.get_bitsize(), expected_depth) + + def test_get_surface__mode_not_set(self): + """Ensures get_surface handles the display mode not being set.""" + surface = pygame.display.get_surface() + + self.assertIsNone(surface) + + def test_get_wm_info(self): + wm_info = display.get_wm_info() + # Assert function returns a dictionary type + self.assertIsInstance(wm_info, dict) + + wm_info_potential_keys = { + "colorbuffer", + "connection", + "data", + "dfb", + "display", + "framebuffer", + "fswindow", + "hdc", + "hglrc", + "hinstance", + "lock_func", + "resolveFramebuffer", + "shell_surface", + "surface", + "taskHandle", + "unlock_func", + "wimpVersion", + "window", + "wmwindow", + } + + # If any unexpected dict keys are present, they + # will be stored in set wm_info_remaining_keys + wm_info_remaining_keys = set(wm_info.keys()).difference(wm_info_potential_keys) + + # Assert set is empty (& therefore does not + # contain unexpected dict keys) + self.assertFalse(wm_info_remaining_keys) + + @unittest.skipIf( + ( + "skipping for all because some failures on rasppi and maybe other platforms" + or os.environ.get("SDL_VIDEODRIVER") == "dummy" + ), + 'OpenGL requires a non-"dummy" SDL_VIDEODRIVER', + ) + def test_gl_get_attribute(self): + + screen = display.set_mode((0, 0), pygame.OPENGL) + + # We create a list where we store the original values of the + # flags before setting them with a different value. + original_values = [] + + original_values.append(pygame.display.gl_get_attribute(pygame.GL_ALPHA_SIZE)) + original_values.append(pygame.display.gl_get_attribute(pygame.GL_DEPTH_SIZE)) + original_values.append(pygame.display.gl_get_attribute(pygame.GL_STENCIL_SIZE)) + original_values.append( + pygame.display.gl_get_attribute(pygame.GL_ACCUM_RED_SIZE) + ) + original_values.append( + pygame.display.gl_get_attribute(pygame.GL_ACCUM_GREEN_SIZE) + ) + original_values.append( + pygame.display.gl_get_attribute(pygame.GL_ACCUM_BLUE_SIZE) + ) + original_values.append( + pygame.display.gl_get_attribute(pygame.GL_ACCUM_ALPHA_SIZE) + ) + original_values.append( + pygame.display.gl_get_attribute(pygame.GL_MULTISAMPLEBUFFERS) + ) + original_values.append( + pygame.display.gl_get_attribute(pygame.GL_MULTISAMPLESAMPLES) + ) + original_values.append(pygame.display.gl_get_attribute(pygame.GL_STEREO)) + + original_values.append( + pygame.display.gl_get_attribute(pygame.GL_ACCELERATED_VISUAL) + ) + original_values.append( + pygame.display.gl_get_attribute(pygame.GL_CONTEXT_MAJOR_VERSION) + ) + original_values.append( + pygame.display.gl_get_attribute(pygame.GL_CONTEXT_MINOR_VERSION) + ) + original_values.append(pygame.display.gl_get_attribute(pygame.GL_CONTEXT_FLAGS)) + original_values.append( + pygame.display.gl_get_attribute(pygame.GL_CONTEXT_PROFILE_MASK) + ) + original_values.append( + pygame.display.gl_get_attribute(pygame.GL_SHARE_WITH_CURRENT_CONTEXT) + ) + original_values.append( + pygame.display.gl_get_attribute(pygame.GL_FRAMEBUFFER_SRGB_CAPABLE) + ) + + # Setting the flags with values supposedly different from the original values + + # assign SDL1-supported values with gl_set_attribute + pygame.display.gl_set_attribute(pygame.GL_ALPHA_SIZE, 8) + pygame.display.gl_set_attribute(pygame.GL_DEPTH_SIZE, 24) + pygame.display.gl_set_attribute(pygame.GL_STENCIL_SIZE, 8) + pygame.display.gl_set_attribute(pygame.GL_ACCUM_RED_SIZE, 16) + pygame.display.gl_set_attribute(pygame.GL_ACCUM_GREEN_SIZE, 16) + pygame.display.gl_set_attribute(pygame.GL_ACCUM_BLUE_SIZE, 16) + pygame.display.gl_set_attribute(pygame.GL_ACCUM_ALPHA_SIZE, 16) + pygame.display.gl_set_attribute(pygame.GL_MULTISAMPLEBUFFERS, 1) + pygame.display.gl_set_attribute(pygame.GL_MULTISAMPLESAMPLES, 1) + pygame.display.gl_set_attribute(pygame.GL_STEREO, 0) + pygame.display.gl_set_attribute(pygame.GL_ACCELERATED_VISUAL, 0) + pygame.display.gl_set_attribute(pygame.GL_CONTEXT_MAJOR_VERSION, 1) + pygame.display.gl_set_attribute(pygame.GL_CONTEXT_MINOR_VERSION, 1) + pygame.display.gl_set_attribute(pygame.GL_CONTEXT_FLAGS, 0) + pygame.display.gl_set_attribute(pygame.GL_CONTEXT_PROFILE_MASK, 0) + pygame.display.gl_set_attribute(pygame.GL_SHARE_WITH_CURRENT_CONTEXT, 0) + pygame.display.gl_set_attribute(pygame.GL_FRAMEBUFFER_SRGB_CAPABLE, 0) + + # We create a list where we store the values that we set each flag to + set_values = [8, 24, 8, 16, 16, 16, 16, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0] + + # We create a list where we store the values after getting them + get_values = [] + + get_values.append(pygame.display.gl_get_attribute(pygame.GL_ALPHA_SIZE)) + get_values.append(pygame.display.gl_get_attribute(pygame.GL_DEPTH_SIZE)) + get_values.append(pygame.display.gl_get_attribute(pygame.GL_STENCIL_SIZE)) + get_values.append(pygame.display.gl_get_attribute(pygame.GL_ACCUM_RED_SIZE)) + get_values.append(pygame.display.gl_get_attribute(pygame.GL_ACCUM_GREEN_SIZE)) + get_values.append(pygame.display.gl_get_attribute(pygame.GL_ACCUM_BLUE_SIZE)) + get_values.append(pygame.display.gl_get_attribute(pygame.GL_ACCUM_ALPHA_SIZE)) + get_values.append(pygame.display.gl_get_attribute(pygame.GL_MULTISAMPLEBUFFERS)) + get_values.append(pygame.display.gl_get_attribute(pygame.GL_MULTISAMPLESAMPLES)) + get_values.append(pygame.display.gl_get_attribute(pygame.GL_STEREO)) + get_values.append(pygame.display.gl_get_attribute(pygame.GL_ACCELERATED_VISUAL)) + get_values.append( + pygame.display.gl_get_attribute(pygame.GL_CONTEXT_MAJOR_VERSION) + ) + get_values.append( + pygame.display.gl_get_attribute(pygame.GL_CONTEXT_MINOR_VERSION) + ) + get_values.append(pygame.display.gl_get_attribute(pygame.GL_CONTEXT_FLAGS)) + get_values.append( + pygame.display.gl_get_attribute(pygame.GL_CONTEXT_PROFILE_MASK) + ) + get_values.append( + pygame.display.gl_get_attribute(pygame.GL_SHARE_WITH_CURRENT_CONTEXT) + ) + get_values.append( + pygame.display.gl_get_attribute(pygame.GL_FRAMEBUFFER_SRGB_CAPABLE) + ) + + # We check to see if the values that we get correspond to the values that we set + # them to or to the original values. + for i in range(len(original_values)): + self.assertTrue( + (get_values[i] == original_values[i]) + or (get_values[i] == set_values[i]) + ) + + # test using non-flag argument + with self.assertRaises(TypeError): + pygame.display.gl_get_attribute("DUMMY") + + def todo_test_gl_set_attribute(self): + + # __doc__ (as of 2008-08-02) for pygame.display.gl_set_attribute: + + # pygame.display.gl_set_attribute(flag, value): return None + # request an opengl display attribute for the display mode + # + # When calling pygame.display.set_mode() with the pygame.OPENGL flag, + # Pygame automatically handles setting the OpenGL attributes like + # color and doublebuffering. OpenGL offers several other attributes + # you may want control over. Pass one of these attributes as the flag, + # and its appropriate value. This must be called before + # pygame.display.set_mode() + # + # The OPENGL flags are; + # GL_ALPHA_SIZE, GL_DEPTH_SIZE, GL_STENCIL_SIZE, GL_ACCUM_RED_SIZE, + # GL_ACCUM_GREEN_SIZE, GL_ACCUM_BLUE_SIZE, GL_ACCUM_ALPHA_SIZE, + # GL_MULTISAMPLEBUFFERS, GL_MULTISAMPLESAMPLES, GL_STEREO + + self.fail() + + @unittest.skipIf( + os.environ.get("SDL_VIDEODRIVER") in ["dummy", "android"], + "iconify is only supported on some video drivers/platforms", + ) + def test_iconify(self): + pygame.display.set_mode((640, 480)) + + self.assertEqual(pygame.display.get_active(), True) + + success = pygame.display.iconify() + + if success: + active_event = window_minimized_event = False + # make sure we cycle the event loop enough to get the display + # hidden. Test that both ACTIVEEVENT and WINDOWMINIMISED event appears + for _ in range(50): + time.sleep(0.01) + for event in pygame.event.get(): + if event.type == pygame.ACTIVEEVENT: + if not event.gain and event.state == pygame.APPACTIVE: + active_event = True + if event.type == pygame.WINDOWMINIMIZED: + window_minimized_event = True + + self.assertTrue(window_minimized_event) + self.assertTrue(active_event) + self.assertFalse(pygame.display.get_active()) + + else: + self.fail("Iconify not supported on this platform, please skip") + + def test_init(self): + """Ensures the module is initialized after init called.""" + # display.init() already called in setUp(), so quit and re-init + display.quit() + display.init() + + self.assertTrue(display.get_init()) + + def test_init__multiple(self): + """Ensures the module is initialized after multiple init calls.""" + display.init() + display.init() + + self.assertTrue(display.get_init()) + + def test_list_modes(self): + modes = pygame.display.list_modes(depth=0, flags=pygame.FULLSCREEN, display=0) + # modes == -1 means any mode is supported. + if modes != -1: + self.assertEqual(len(modes[0]), 2) + self.assertEqual(type(modes[0][0]), int) + + modes = pygame.display.list_modes() + if modes != -1: + self.assertEqual(len(modes[0]), 2) + self.assertEqual(type(modes[0][0]), int) + self.assertEqual(len(modes), len(set(modes))) + + modes = pygame.display.list_modes(depth=0, flags=0, display=0) + if modes != -1: + self.assertEqual(len(modes[0]), 2) + self.assertEqual(type(modes[0][0]), int) + + def test_mode_ok(self): + pygame.display.mode_ok((128, 128)) + modes = pygame.display.list_modes() + if modes != -1: + size = modes[0] + self.assertNotEqual(pygame.display.mode_ok(size), 0) + + pygame.display.mode_ok((128, 128), 0, 32) + pygame.display.mode_ok((128, 128), flags=0, depth=32, display=0) + + def test_mode_ok_fullscreen(self): + modes = pygame.display.list_modes() + if modes != -1: + size = modes[0] + self.assertNotEqual( + pygame.display.mode_ok(size, flags=pygame.FULLSCREEN), 0 + ) + + def test_mode_ok_scaled(self): + modes = pygame.display.list_modes() + if modes != -1: + size = modes[0] + self.assertNotEqual(pygame.display.mode_ok(size, flags=pygame.SCALED), 0) + + def test_get_num_displays(self): + self.assertGreater(pygame.display.get_num_displays(), 0) + + def test_quit(self): + """Ensures the module is not initialized after quit called.""" + display.quit() + + self.assertFalse(display.get_init()) + + def test_quit__multiple(self): + """Ensures the module is not initialized after multiple quit calls.""" + display.quit() + display.quit() + + self.assertFalse(display.get_init()) + + @unittest.skipIf( + os.environ.get("SDL_VIDEODRIVER") == "dummy", "Needs a not dummy videodriver" + ) + def test_set_gamma(self): + pygame.display.set_mode((1, 1)) + + gammas = [0.25, 0.5, 0.88, 1.0] + for gamma in gammas: + with self.subTest(gamma=gamma): + self.assertEqual(pygame.display.set_gamma(gamma), True) + + @unittest.skipIf( + os.environ.get("SDL_VIDEODRIVER") == "dummy", "Needs a not dummy videodriver" + ) + def test_set_gamma__tuple(self): + pygame.display.set_mode((1, 1)) + + gammas = [(0.5, 0.5, 0.5), (1.0, 1.0, 1.0), (0.25, 0.33, 0.44)] + for r, g, b in gammas: + with self.subTest(r=r, g=g, b=b): + self.assertEqual(pygame.display.set_gamma(r, g, b), True) + + @unittest.skipIf( + not hasattr(pygame.display, "set_gamma_ramp"), + "Not all systems and hardware support gamma ramps", + ) + def test_set_gamma_ramp(self): + + # __doc__ (as of 2008-08-02) for pygame.display.set_gamma_ramp: + + # change the hardware gamma ramps with a custom lookup + # pygame.display.set_gamma_ramp(red, green, blue): return bool + # set_gamma_ramp(red, green, blue): return bool + # + # Set the red, green, and blue gamma ramps with an explicit lookup + # table. Each argument should be sequence of 256 integers. The + # integers should range between 0 and 0xffff. Not all systems and + # hardware support gamma ramps, if the function succeeds it will + # return True. + # + pygame.display.set_mode((5, 5)) + r = list(range(256)) + g = [number + 256 for number in r] + b = [number + 256 for number in g] + isSupported = pygame.display.set_gamma_ramp(r, g, b) + if isSupported: + self.assertTrue(pygame.display.set_gamma_ramp(r, g, b)) + else: + self.assertFalse(pygame.display.set_gamma_ramp(r, g, b)) + + def test_set_mode_kwargs(self): + + pygame.display.set_mode(size=(1, 1), flags=0, depth=0, display=0) + + def test_set_mode_scaled(self): + surf = pygame.display.set_mode( + size=(1, 1), flags=pygame.SCALED, depth=0, display=0 + ) + winsize = pygame.display.get_window_size() + self.assertEqual( + winsize[0] % surf.get_size()[0], + 0, + "window width should be a multiple of the surface width", + ) + self.assertEqual( + winsize[1] % surf.get_size()[1], + 0, + "window height should be a multiple of the surface height", + ) + self.assertEqual( + winsize[0] / surf.get_size()[0], winsize[1] / surf.get_size()[1] + ) + + def test_set_mode_vector2(self): + pygame.display.set_mode(pygame.Vector2(1, 1)) + + def test_set_mode_unscaled(self): + """Ensures a window created with SCALED can become smaller.""" + # see https://github.com/pygame/pygame/issues/2327 + + screen = pygame.display.set_mode((300, 300), pygame.SCALED) + self.assertEqual(screen.get_size(), (300, 300)) + + screen = pygame.display.set_mode((200, 200)) + self.assertEqual(screen.get_size(), (200, 200)) + + def test_screensaver_support(self): + pygame.display.set_allow_screensaver(True) + self.assertTrue(pygame.display.get_allow_screensaver()) + pygame.display.set_allow_screensaver(False) + self.assertFalse(pygame.display.get_allow_screensaver()) + pygame.display.set_allow_screensaver() + self.assertTrue(pygame.display.get_allow_screensaver()) + + # the following test fails always with SDL2 + @unittest.skipIf(True, "set_palette() not supported in SDL2") + def test_set_palette(self): + with self.assertRaises(pygame.error): + palette = [1, 2, 3] + pygame.display.set_palette(palette) + pygame.display.set_mode((1024, 768), 0, 8) + palette = [] + self.assertIsNone(pygame.display.set_palette(palette)) + + with self.assertRaises(ValueError): + palette = 12 + pygame.display.set_palette(palette) + with self.assertRaises(TypeError): + palette = [[1, 2], [1, 2]] + pygame.display.set_palette(palette) + with self.assertRaises(TypeError): + palette = [[0, 0, 0, 0, 0]] + [[x, x, x, x, x] for x in range(1, 255)] + pygame.display.set_palette(palette) + with self.assertRaises(TypeError): + palette = "qwerty" + pygame.display.set_palette(palette) + with self.assertRaises(TypeError): + palette = [[123, 123, 123] * 10000] + pygame.display.set_palette(palette) + with self.assertRaises(TypeError): + palette = [1, 2, 3] + pygame.display.set_palette(palette) + + skip_list = ["dummy", "android"] + + @unittest.skipIf( + os.environ.get("SDL_VIDEODRIVER") in skip_list, + "requires the SDL_VIDEODRIVER to be non dummy", + ) + def test_toggle_fullscreen(self): + """Test for toggle fullscreen""" + + # try to toggle fullscreen with no active display + # this should result in an error + pygame.display.quit() + with self.assertRaises(pygame.error): + pygame.display.toggle_fullscreen() + + pygame.display.init() + width_height = (640, 480) + test_surf = pygame.display.set_mode(width_height) + + # try to toggle fullscreen + try: + pygame.display.toggle_fullscreen() + + except pygame.error: + self.fail() + + else: + # if toggle success, the width/height should be a + # value found in list_modes + if pygame.display.toggle_fullscreen() == 1: + boolean = ( + test_surf.get_width(), + test_surf.get_height(), + ) in pygame.display.list_modes( + depth=0, flags=pygame.FULLSCREEN, display=0 + ) + + self.assertEqual(boolean, True) + + # if not original width/height should be preserved + else: + self.assertEqual( + (test_surf.get_width(), test_surf.get_height()), width_height + ) + + +class DisplayUpdateTest(unittest.TestCase): + def question(self, qstr): + """this is used in the interactive subclass.""" + + def setUp(self): + display.init() + self.screen = pygame.display.set_mode((500, 500)) + self.screen.fill("black") + pygame.display.flip() + pygame.event.pump() # so mac updates + + def tearDown(self): + display.quit() + + def test_update_negative(self): + """takes rects with negative values.""" + self.screen.fill("green") + + r1 = pygame.Rect(0, 0, 100, 100) + pygame.display.update(r1) + + r2 = pygame.Rect(-10, 0, 100, 100) + pygame.display.update(r2) + + r3 = pygame.Rect(-10, 0, -100, -100) + pygame.display.update(r3) + + self.question("Is the screen green in (0, 0, 100, 100)?") + + def test_update_sequence(self): + """only updates the part of the display given by the rects.""" + self.screen.fill("green") + rects = [ + pygame.Rect(0, 0, 100, 100), + pygame.Rect(100, 0, 100, 100), + pygame.Rect(200, 0, 100, 100), + pygame.Rect(300, 300, 100, 100), + ] + pygame.display.update(rects) + pygame.event.pump() # so mac updates + + self.question(f"Is the screen green in {rects}?") + + def test_update_none_skipped(self): + """None is skipped inside sequences.""" + self.screen.fill("green") + rects = ( + None, + pygame.Rect(100, 0, 100, 100), + None, + pygame.Rect(200, 0, 100, 100), + pygame.Rect(300, 300, 100, 100), + ) + pygame.display.update(rects) + pygame.event.pump() # so mac updates + + self.question(f"Is the screen green in {rects}?") + + def test_update_none(self): + """does NOT update the display.""" + self.screen.fill("green") + pygame.display.update(None) + pygame.event.pump() # so mac updates + self.question(f"Is the screen black and NOT green?") + + def test_update_no_args(self): + """does NOT update the display.""" + self.screen.fill("green") + pygame.display.update() + pygame.event.pump() # so mac updates + self.question(f"Is the WHOLE screen green?") + + def test_update_args(self): + """updates the display using the args as a rect.""" + self.screen.fill("green") + pygame.display.update(100, 100, 100, 100) + pygame.event.pump() # so mac updates + self.question("Is the screen green in (100, 100, 100, 100)?") + + def test_update_incorrect_args(self): + """raises a ValueError when inputs are wrong.""" + + with self.assertRaises(ValueError): + pygame.display.update(100, "asdf", 100, 100) + + with self.assertRaises(ValueError): + pygame.display.update([100, "asdf", 100, 100]) + + def test_update_no_init(self): + """raises a pygame.error.""" + + pygame.display.quit() + with self.assertRaises(pygame.error): + pygame.display.update() + + +class DisplayUpdateInteractiveTest(DisplayUpdateTest): + """Because we want these tests to run as interactive and not interactive.""" + + __tags__ = ["interactive"] + + def question(self, qstr): + """since this is the interactive sublcass we ask a question.""" + question(qstr) + + +class DisplayInteractiveTest(unittest.TestCase): + + __tags__ = ["interactive"] + + def test_set_icon_interactive(self): + + os.environ["SDL_VIDEO_WINDOW_POS"] = "100,250" + pygame.display.quit() + pygame.display.init() + + test_icon = pygame.Surface((32, 32)) + test_icon.fill((255, 0, 0)) + + pygame.display.set_icon(test_icon) + screen = pygame.display.set_mode((400, 100)) + pygame.display.set_caption("Is the window icon a red square?") + + response = question("Is the display icon red square?") + + self.assertTrue(response) + pygame.display.quit() + + def test_set_gamma_ramp(self): + + os.environ["SDL_VIDEO_WINDOW_POS"] = "100,250" + pygame.display.quit() + pygame.display.init() + + screen = pygame.display.set_mode((400, 100)) + screen.fill((100, 100, 100)) + + blue_ramp = [x * 256 for x in range(0, 256)] + blue_ramp[100] = 150 * 256 # Can't tint too far or gamma ramps fail + normal_ramp = [x * 256 for x in range(0, 256)] + # test to see if this platform supports gamma ramps + gamma_success = False + if pygame.display.set_gamma_ramp(normal_ramp, normal_ramp, blue_ramp): + pygame.display.update() + gamma_success = True + + if gamma_success: + response = question("Is the window background tinted blue?") + self.assertTrue(response) + # restore normal ramp + pygame.display.set_gamma_ramp(normal_ramp, normal_ramp, normal_ramp) + + pygame.display.quit() + + +@unittest.skipIf( + os.environ.get("SDL_VIDEODRIVER") == "dummy", + 'OpenGL requires a non-"dummy" SDL_VIDEODRIVER', +) +class DisplayOpenGLTest(unittest.TestCase): + def test_screen_size_opengl(self): + """returns a surface with the same size requested. + |tags:display,slow,opengl| + """ + pygame.display.init() + screen = pygame.display.set_mode((640, 480), pygame.OPENGL) + self.assertEqual((640, 480), screen.get_size()) + + +class X11CrashTest(unittest.TestCase): + def test_x11_set_mode_crash_gh1654(self): + # Test for https://github.com/pygame/pygame/issues/1654 + # If unfixed, this will trip a segmentation fault + pygame.display.init() + pygame.display.quit() + screen = pygame.display.set_mode((640, 480), 0) + self.assertEqual((640, 480), screen.get_size()) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/docs_test.py b/venv/Lib/site-packages/pygame/tests/docs_test.py new file mode 100644 index 0000000..de021a8 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/docs_test.py @@ -0,0 +1,35 @@ +import os +import subprocess +import sys +import unittest + + +class DocsIncludedTest(unittest.TestCase): + def test_doc_import_works(self): + from pygame.docs.__main__ import has_local_docs, open_docs + + @unittest.skipIf("CI" not in os.environ, "Docs not required for local builds") + def test_docs_included(self): + from pygame.docs.__main__ import has_local_docs + + self.assertTrue(has_local_docs()) + + @unittest.skipIf("CI" not in os.environ, "Docs not required for local builds") + def test_docs_command(self): + try: + subprocess.run( + [sys.executable, "-m", "pygame.docs"], + timeout=5, + # check ensures an exception is raised when the process fails + check=True, + # pipe stdout/stderr so that they don't clutter main stdout + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + except subprocess.TimeoutExpired: + # timeout errors are not an issue + pass + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/draw_test.py b/venv/Lib/site-packages/pygame/tests/draw_test.py new file mode 100644 index 0000000..d876060 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/draw_test.py @@ -0,0 +1,6563 @@ +import math +import unittest +import sys +import warnings + +import pygame +from pygame import draw +from pygame import draw_py +from pygame.locals import SRCALPHA +from pygame.tests import test_utils +from pygame.math import Vector2 + + +RED = BG_RED = pygame.Color("red") +GREEN = FG_GREEN = pygame.Color("green") + +# Clockwise from the top left corner and ending with the center point. +RECT_POSITION_ATTRIBUTES = ( + "topleft", + "midtop", + "topright", + "midright", + "bottomright", + "midbottom", + "bottomleft", + "midleft", + "center", +) + + +def get_border_values(surface, width, height): + """Returns a list containing lists with the values of the surface's + borders. + """ + border_top = [surface.get_at((x, 0)) for x in range(width)] + border_left = [surface.get_at((0, y)) for y in range(height)] + border_right = [surface.get_at((width - 1, y)) for y in range(height)] + border_bottom = [surface.get_at((x, height - 1)) for x in range(width)] + + return [border_top, border_left, border_right, border_bottom] + + +def corners(surface): + """Returns a tuple with the corner positions of the given surface. + + Clockwise from the top left corner. + """ + width, height = surface.get_size() + return ((0, 0), (width - 1, 0), (width - 1, height - 1), (0, height - 1)) + + +def rect_corners_mids_and_center(rect): + """Returns a tuple with each corner, mid, and the center for a given rect. + + Clockwise from the top left corner and ending with the center point. + """ + return ( + rect.topleft, + rect.midtop, + rect.topright, + rect.midright, + rect.bottomright, + rect.midbottom, + rect.bottomleft, + rect.midleft, + rect.center, + ) + + +def border_pos_and_color(surface): + """Yields each border position and its color for a given surface. + + Clockwise from the top left corner. + """ + width, height = surface.get_size() + right, bottom = width - 1, height - 1 + + # Top edge. + for x in range(width): + pos = (x, 0) + yield pos, surface.get_at(pos) + + # Right edge. + # Top right done in top edge loop. + for y in range(1, height): + pos = (right, y) + yield pos, surface.get_at(pos) + + # Bottom edge. + # Bottom right done in right edge loop. + for x in range(right - 1, -1, -1): + pos = (x, bottom) + yield pos, surface.get_at(pos) + + # Left edge. + # Bottom left done in bottom edge loop. Top left done in top edge loop. + for y in range(bottom - 1, 0, -1): + pos = (0, y) + yield pos, surface.get_at(pos) + + +def get_color_points(surface, color, bounds_rect=None, match_color=True): + """Get all the points of a given color on the surface within the given + bounds. + + If bounds_rect is None the full surface is checked. + If match_color is True, all points matching the color are returned, + otherwise all points not matching the color are returned. + """ + get_at = surface.get_at # For possible speed up. + + if bounds_rect is None: + x_range = range(surface.get_width()) + y_range = range(surface.get_height()) + else: + x_range = range(bounds_rect.left, bounds_rect.right) + y_range = range(bounds_rect.top, bounds_rect.bottom) + + surface.lock() # For possible speed up. + + if match_color: + pts = [(x, y) for x in x_range for y in y_range if get_at((x, y)) == color] + else: + pts = [(x, y) for x in x_range for y in y_range if get_at((x, y)) != color] + + surface.unlock() + return pts + + +def create_bounding_rect(surface, surf_color, default_pos): + """Create a rect to bound all the pixels that don't match surf_color. + + The default_pos parameter is used to position the bounding rect for the + case where all pixels match the surf_color. + """ + width, height = surface.get_clip().size + xmin, ymin = width, height + xmax, ymax = -1, -1 + get_at = surface.get_at # For possible speed up. + + surface.lock() # For possible speed up. + + for y in range(height): + for x in range(width): + if get_at((x, y)) != surf_color: + xmin = min(x, xmin) + xmax = max(x, xmax) + ymin = min(y, ymin) + ymax = max(y, ymax) + + surface.unlock() + + if -1 == xmax: + # No points means a 0 sized rect positioned at default_pos. + return pygame.Rect(default_pos, (0, 0)) + return pygame.Rect((xmin, ymin), (xmax - xmin + 1, ymax - ymin + 1)) + + +class InvalidBool(object): + """To help test invalid bool values.""" + + __nonzero__ = None + __bool__ = None + + +class DrawTestCase(unittest.TestCase): + """Base class to test draw module functions.""" + + draw_rect = staticmethod(draw.rect) + draw_polygon = staticmethod(draw.polygon) + draw_circle = staticmethod(draw.circle) + draw_ellipse = staticmethod(draw.ellipse) + draw_arc = staticmethod(draw.arc) + draw_line = staticmethod(draw.line) + draw_lines = staticmethod(draw.lines) + draw_aaline = staticmethod(draw.aaline) + draw_aalines = staticmethod(draw.aalines) + + +class PythonDrawTestCase(unittest.TestCase): + """Base class to test draw_py module functions.""" + + # draw_py is currently missing some functions. + # draw_rect = staticmethod(draw_py.draw_rect) + draw_polygon = staticmethod(draw_py.draw_polygon) + # draw_circle = staticmethod(draw_py.draw_circle) + # draw_ellipse = staticmethod(draw_py.draw_ellipse) + # draw_arc = staticmethod(draw_py.draw_arc) + draw_line = staticmethod(draw_py.draw_line) + draw_lines = staticmethod(draw_py.draw_lines) + draw_aaline = staticmethod(draw_py.draw_aaline) + draw_aalines = staticmethod(draw_py.draw_aalines) + + +### Ellipse Testing ########################################################### + + +class DrawEllipseMixin(object): + """Mixin tests for drawing ellipses. + + This class contains all the general ellipse drawing tests. + """ + + def test_ellipse__args(self): + """Ensures draw ellipse accepts the correct args.""" + bounds_rect = self.draw_ellipse( + pygame.Surface((3, 3)), (0, 10, 0, 50), pygame.Rect((0, 0), (3, 2)), 1 + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_ellipse__args_without_width(self): + """Ensures draw ellipse accepts the args without a width.""" + bounds_rect = self.draw_ellipse( + pygame.Surface((2, 2)), (1, 1, 1, 99), pygame.Rect((1, 1), (1, 1)) + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_ellipse__args_with_negative_width(self): + """Ensures draw ellipse accepts the args with negative width.""" + bounds_rect = self.draw_ellipse( + pygame.Surface((3, 3)), (0, 10, 0, 50), pygame.Rect((2, 3), (3, 2)), -1 + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + self.assertEqual(bounds_rect, pygame.Rect(2, 3, 0, 0)) + + def test_ellipse__args_with_width_gt_radius(self): + """Ensures draw ellipse accepts the args with + width > rect.w // 2 and width > rect.h // 2. + """ + rect = pygame.Rect((0, 0), (4, 4)) + bounds_rect = self.draw_ellipse( + pygame.Surface((3, 3)), (0, 10, 0, 50), rect, rect.w // 2 + 1 + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + bounds_rect = self.draw_ellipse( + pygame.Surface((3, 3)), (0, 10, 0, 50), rect, rect.h // 2 + 1 + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_ellipse__kwargs(self): + """Ensures draw ellipse accepts the correct kwargs + with and without a width arg. + """ + kwargs_list = [ + { + "surface": pygame.Surface((4, 4)), + "color": pygame.Color("yellow"), + "rect": pygame.Rect((0, 0), (3, 2)), + "width": 1, + }, + { + "surface": pygame.Surface((2, 1)), + "color": (0, 10, 20), + "rect": (0, 0, 1, 1), + }, + ] + + for kwargs in kwargs_list: + bounds_rect = self.draw_ellipse(**kwargs) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_ellipse__kwargs_order_independent(self): + """Ensures draw ellipse's kwargs are not order dependent.""" + bounds_rect = self.draw_ellipse( + color=(1, 2, 3), + surface=pygame.Surface((3, 2)), + width=0, + rect=pygame.Rect((1, 0), (1, 1)), + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_ellipse__args_missing(self): + """Ensures draw ellipse detects any missing required args.""" + surface = pygame.Surface((1, 1)) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_ellipse(surface, pygame.Color("red")) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_ellipse(surface) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_ellipse() + + def test_ellipse__kwargs_missing(self): + """Ensures draw ellipse detects any missing required kwargs.""" + kwargs = { + "surface": pygame.Surface((1, 2)), + "color": pygame.Color("red"), + "rect": pygame.Rect((1, 0), (2, 2)), + "width": 2, + } + + for name in ("rect", "color", "surface"): + invalid_kwargs = dict(kwargs) + invalid_kwargs.pop(name) # Pop from a copy. + + with self.assertRaises(TypeError): + bounds_rect = self.draw_ellipse(**invalid_kwargs) + + def test_ellipse__arg_invalid_types(self): + """Ensures draw ellipse detects invalid arg types.""" + surface = pygame.Surface((2, 2)) + color = pygame.Color("blue") + rect = pygame.Rect((1, 1), (1, 1)) + + with self.assertRaises(TypeError): + # Invalid width. + bounds_rect = self.draw_ellipse(surface, color, rect, "1") + + with self.assertRaises(TypeError): + # Invalid rect. + bounds_rect = self.draw_ellipse(surface, color, (1, 2, 3, 4, 5), 1) + + with self.assertRaises(TypeError): + # Invalid color. + bounds_rect = self.draw_ellipse(surface, 2.3, rect, 0) + + with self.assertRaises(TypeError): + # Invalid surface. + bounds_rect = self.draw_ellipse(rect, color, rect, 2) + + def test_ellipse__kwarg_invalid_types(self): + """Ensures draw ellipse detects invalid kwarg types.""" + surface = pygame.Surface((3, 3)) + color = pygame.Color("green") + rect = pygame.Rect((0, 1), (1, 1)) + kwargs_list = [ + { + "surface": pygame.Surface, # Invalid surface. + "color": color, + "rect": rect, + "width": 1, + }, + { + "surface": surface, + "color": 2.3, # Invalid color. + "rect": rect, + "width": 1, + }, + { + "surface": surface, + "color": color, + "rect": (0, 0, 0), # Invalid rect. + "width": 1, + }, + {"surface": surface, "color": color, "rect": rect, "width": 1.1}, + ] # Invalid width. + + for kwargs in kwargs_list: + with self.assertRaises(TypeError): + bounds_rect = self.draw_ellipse(**kwargs) + + def test_ellipse__kwarg_invalid_name(self): + """Ensures draw ellipse detects invalid kwarg names.""" + surface = pygame.Surface((2, 3)) + color = pygame.Color("cyan") + rect = pygame.Rect((0, 1), (2, 2)) + kwargs_list = [ + { + "surface": surface, + "color": color, + "rect": rect, + "width": 1, + "invalid": 1, + }, + {"surface": surface, "color": color, "rect": rect, "invalid": 1}, + ] + + for kwargs in kwargs_list: + with self.assertRaises(TypeError): + bounds_rect = self.draw_ellipse(**kwargs) + + def test_ellipse__args_and_kwargs(self): + """Ensures draw ellipse accepts a combination of args/kwargs""" + surface = pygame.Surface((3, 1)) + color = (255, 255, 0, 0) + rect = pygame.Rect((1, 0), (2, 1)) + width = 0 + kwargs = {"surface": surface, "color": color, "rect": rect, "width": width} + + for name in ("surface", "color", "rect", "width"): + kwargs.pop(name) + + if "surface" == name: + bounds_rect = self.draw_ellipse(surface, **kwargs) + elif "color" == name: + bounds_rect = self.draw_ellipse(surface, color, **kwargs) + elif "rect" == name: + bounds_rect = self.draw_ellipse(surface, color, rect, **kwargs) + else: + bounds_rect = self.draw_ellipse(surface, color, rect, width, **kwargs) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_ellipse__valid_width_values(self): + """Ensures draw ellipse accepts different width values.""" + pos = (1, 1) + surface_color = pygame.Color("white") + surface = pygame.Surface((3, 4)) + color = (10, 20, 30, 255) + kwargs = { + "surface": surface, + "color": color, + "rect": pygame.Rect(pos, (3, 2)), + "width": None, + } + + for width in (-1000, -10, -1, 0, 1, 10, 1000): + surface.fill(surface_color) # Clear for each test. + kwargs["width"] = width + expected_color = color if width >= 0 else surface_color + + bounds_rect = self.draw_ellipse(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_ellipse__valid_rect_formats(self): + """Ensures draw ellipse accepts different rect formats.""" + pos = (1, 1) + expected_color = pygame.Color("red") + surface_color = pygame.Color("black") + surface = pygame.Surface((4, 4)) + kwargs = {"surface": surface, "color": expected_color, "rect": None, "width": 0} + rects = (pygame.Rect(pos, (1, 3)), (pos, (2, 1)), (pos[0], pos[1], 1, 1)) + + for rect in rects: + surface.fill(surface_color) # Clear for each test. + kwargs["rect"] = rect + + bounds_rect = self.draw_ellipse(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_ellipse__valid_color_formats(self): + """Ensures draw ellipse accepts different color formats.""" + pos = (1, 1) + green_color = pygame.Color("green") + surface_color = pygame.Color("black") + surface = pygame.Surface((3, 4)) + kwargs = { + "surface": surface, + "color": None, + "rect": pygame.Rect(pos, (1, 2)), + "width": 0, + } + reds = ( + (0, 255, 0), + (0, 255, 0, 255), + surface.map_rgb(green_color), + green_color, + ) + + for color in reds: + surface.fill(surface_color) # Clear for each test. + kwargs["color"] = color + + if isinstance(color, int): + expected_color = surface.unmap_rgb(color) + else: + expected_color = green_color + + bounds_rect = self.draw_ellipse(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_ellipse__invalid_color_formats(self): + """Ensures draw ellipse handles invalid color formats correctly.""" + pos = (1, 1) + surface = pygame.Surface((4, 3)) + kwargs = { + "surface": surface, + "color": None, + "rect": pygame.Rect(pos, (2, 2)), + "width": 1, + } + + for expected_color in (2.3, surface): + kwargs["color"] = expected_color + + with self.assertRaises(TypeError): + bounds_rect = self.draw_ellipse(**kwargs) + + def test_ellipse(self): + """Tests ellipses of differing sizes on surfaces of differing sizes. + + Checks if the number of sides touching the border of the surface is + correct. + """ + left_top = [(0, 0), (1, 0), (0, 1), (1, 1)] + sizes = [(4, 4), (5, 4), (4, 5), (5, 5)] + color = (1, 13, 24, 255) + + def same_size(width, height, border_width): + """Test for ellipses with the same size as the surface.""" + surface = pygame.Surface((width, height)) + + self.draw_ellipse(surface, color, (0, 0, width, height), border_width) + + # For each of the four borders check if it contains the color + borders = get_border_values(surface, width, height) + for border in borders: + self.assertTrue(color in border) + + def not_same_size(width, height, border_width, left, top): + """Test for ellipses that aren't the same size as the surface.""" + surface = pygame.Surface((width, height)) + + self.draw_ellipse( + surface, color, (left, top, width - 1, height - 1), border_width + ) + + borders = get_border_values(surface, width, height) + + # Check if two sides of the ellipse are touching the border + sides_touching = [color in border for border in borders].count(True) + self.assertEqual(sides_touching, 2) + + for width, height in sizes: + for border_width in (0, 1): + same_size(width, height, border_width) + for left, top in left_top: + not_same_size(width, height, border_width, left, top) + + def test_ellipse__big_ellipse(self): + """Test for big ellipse that could overflow in algorithm""" + width = 1025 + height = 1025 + border = 1 + x_value_test = int(0.4 * height) + y_value_test = int(0.4 * height) + surface = pygame.Surface((width, height)) + + self.draw_ellipse(surface, (255, 0, 0), (0, 0, width, height), border) + colored_pixels = 0 + for y in range(height): + if surface.get_at((x_value_test, y)) == (255, 0, 0): + colored_pixels += 1 + for x in range(width): + if surface.get_at((x, y_value_test)) == (255, 0, 0): + colored_pixels += 1 + self.assertEqual(colored_pixels, border * 4) + + def test_ellipse__thick_line(self): + """Ensures a thick lined ellipse is drawn correctly.""" + ellipse_color = pygame.Color("yellow") + surface_color = pygame.Color("black") + surface = pygame.Surface((40, 40)) + rect = pygame.Rect((0, 0), (31, 23)) + rect.center = surface.get_rect().center + + # As the lines get thicker the internals of the ellipse are not + # cleanly defined. So only test up to a few thicknesses before the + # maximum thickness. + for thickness in range(1, min(*rect.size) // 2 - 2): + surface.fill(surface_color) # Clear for each test. + + self.draw_ellipse(surface, ellipse_color, rect, thickness) + + surface.lock() # For possible speed up. + + # Check vertical thickness on the ellipse's top. + x = rect.centerx + y_start = rect.top + y_end = rect.top + thickness - 1 + + for y in range(y_start, y_end + 1): + self.assertEqual(surface.get_at((x, y)), ellipse_color, thickness) + + # Check pixels above and below this line. + self.assertEqual(surface.get_at((x, y_start - 1)), surface_color, thickness) + self.assertEqual(surface.get_at((x, y_end + 1)), surface_color, thickness) + + # Check vertical thickness on the ellipse's bottom. + x = rect.centerx + y_start = rect.bottom - thickness + y_end = rect.bottom - 1 + + for y in range(y_start, y_end + 1): + self.assertEqual(surface.get_at((x, y)), ellipse_color, thickness) + + # Check pixels above and below this line. + self.assertEqual(surface.get_at((x, y_start - 1)), surface_color, thickness) + self.assertEqual(surface.get_at((x, y_end + 1)), surface_color, thickness) + + # Check horizontal thickness on the ellipse's left. + x_start = rect.left + x_end = rect.left + thickness - 1 + y = rect.centery + + for x in range(x_start, x_end + 1): + self.assertEqual(surface.get_at((x, y)), ellipse_color, thickness) + + # Check pixels to the left and right of this line. + self.assertEqual(surface.get_at((x_start - 1, y)), surface_color, thickness) + self.assertEqual(surface.get_at((x_end + 1, y)), surface_color, thickness) + + # Check horizontal thickness on the ellipse's right. + x_start = rect.right - thickness + x_end = rect.right - 1 + y = rect.centery + + for x in range(x_start, x_end + 1): + self.assertEqual(surface.get_at((x, y)), ellipse_color, thickness) + + # Check pixels to the left and right of this line. + self.assertEqual(surface.get_at((x_start - 1, y)), surface_color, thickness) + self.assertEqual(surface.get_at((x_end + 1, y)), surface_color, thickness) + + surface.unlock() + + def test_ellipse__no_holes(self): + width = 80 + height = 70 + surface = pygame.Surface((width + 1, height)) + rect = pygame.Rect(0, 0, width, height) + for thickness in range(1, 37, 5): + surface.fill("BLACK") + self.draw_ellipse(surface, "RED", rect, thickness) + for y in range(height): + number_of_changes = 0 + drawn_pixel = False + for x in range(width + 1): + if ( + not drawn_pixel + and surface.get_at((x, y)) == pygame.Color("RED") + or drawn_pixel + and surface.get_at((x, y)) == pygame.Color("BLACK") + ): + drawn_pixel = not drawn_pixel + number_of_changes += 1 + if y < thickness or y > height - thickness - 1: + self.assertEqual(number_of_changes, 2) + else: + self.assertEqual(number_of_changes, 4) + + def test_ellipse__max_width(self): + """Ensures an ellipse with max width (and greater) is drawn correctly.""" + ellipse_color = pygame.Color("yellow") + surface_color = pygame.Color("black") + surface = pygame.Surface((40, 40)) + rect = pygame.Rect((0, 0), (31, 21)) + rect.center = surface.get_rect().center + max_thickness = (min(*rect.size) + 1) // 2 + + for thickness in range(max_thickness, max_thickness + 3): + surface.fill(surface_color) # Clear for each test. + + self.draw_ellipse(surface, ellipse_color, rect, thickness) + + surface.lock() # For possible speed up. + + # Check vertical thickness. + for y in range(rect.top, rect.bottom): + self.assertEqual(surface.get_at((rect.centerx, y)), ellipse_color) + + # Check horizontal thickness. + for x in range(rect.left, rect.right): + self.assertEqual(surface.get_at((x, rect.centery)), ellipse_color) + + # Check pixels above and below ellipse. + self.assertEqual( + surface.get_at((rect.centerx, rect.top - 1)), surface_color + ) + self.assertEqual( + surface.get_at((rect.centerx, rect.bottom + 1)), surface_color + ) + + # Check pixels to the left and right of the ellipse. + self.assertEqual( + surface.get_at((rect.left - 1, rect.centery)), surface_color + ) + self.assertEqual( + surface.get_at((rect.right + 1, rect.centery)), surface_color + ) + + surface.unlock() + + def _check_1_pixel_sized_ellipse( + self, surface, collide_rect, surface_color, ellipse_color + ): + # Helper method to check the surface for 1 pixel wide and/or high + # ellipses. + surf_w, surf_h = surface.get_size() + + surface.lock() # For possible speed up. + + for pos in ((x, y) for y in range(surf_h) for x in range(surf_w)): + # Since the ellipse is just a line we can use a rect to help find + # where it is expected to be drawn. + if collide_rect.collidepoint(pos): + expected_color = ellipse_color + else: + expected_color = surface_color + + self.assertEqual( + surface.get_at(pos), + expected_color, + "collide_rect={}, pos={}".format(collide_rect, pos), + ) + + surface.unlock() + + def test_ellipse__1_pixel_width(self): + """Ensures an ellipse with a width of 1 is drawn correctly. + + An ellipse with a width of 1 pixel is a vertical line. + """ + ellipse_color = pygame.Color("red") + surface_color = pygame.Color("black") + surf_w, surf_h = 10, 20 + + surface = pygame.Surface((surf_w, surf_h)) + rect = pygame.Rect((0, 0), (1, 0)) + collide_rect = rect.copy() + + # Calculate some positions. + off_left = -1 + off_right = surf_w + off_bottom = surf_h + center_x = surf_w // 2 + center_y = surf_h // 2 + + # Test some even and odd heights. + for ellipse_h in range(6, 10): + collide_rect.h = ellipse_h + rect.h = ellipse_h + + # Calculate some variable positions. + off_top = -(ellipse_h + 1) + half_off_top = -(ellipse_h // 2) + half_off_bottom = surf_h - (ellipse_h // 2) + + # Draw the ellipse in different positions: fully on-surface, + # partially off-surface, and fully off-surface. + positions = ( + (off_left, off_top), + (off_left, half_off_top), + (off_left, center_y), + (off_left, half_off_bottom), + (off_left, off_bottom), + (center_x, off_top), + (center_x, half_off_top), + (center_x, center_y), + (center_x, half_off_bottom), + (center_x, off_bottom), + (off_right, off_top), + (off_right, half_off_top), + (off_right, center_y), + (off_right, half_off_bottom), + (off_right, off_bottom), + ) + + for rect_pos in positions: + surface.fill(surface_color) # Clear before each draw. + rect.topleft = rect_pos + collide_rect.topleft = rect_pos + + self.draw_ellipse(surface, ellipse_color, rect) + + self._check_1_pixel_sized_ellipse( + surface, collide_rect, surface_color, ellipse_color + ) + + def test_ellipse__1_pixel_width_spanning_surface(self): + """Ensures an ellipse with a width of 1 is drawn correctly + when spanning the height of the surface. + + An ellipse with a width of 1 pixel is a vertical line. + """ + ellipse_color = pygame.Color("red") + surface_color = pygame.Color("black") + surf_w, surf_h = 10, 20 + + surface = pygame.Surface((surf_w, surf_h)) + rect = pygame.Rect((0, 0), (1, surf_h + 2)) # Longer than the surface. + + # Draw the ellipse in different positions: on-surface and off-surface. + positions = ( + (-1, -1), # (off_left, off_top) + (0, -1), # (left_edge, off_top) + (surf_w // 2, -1), # (center_x, off_top) + (surf_w - 1, -1), # (right_edge, off_top) + (surf_w, -1), + ) # (off_right, off_top) + + for rect_pos in positions: + surface.fill(surface_color) # Clear before each draw. + rect.topleft = rect_pos + + self.draw_ellipse(surface, ellipse_color, rect) + + self._check_1_pixel_sized_ellipse( + surface, rect, surface_color, ellipse_color + ) + + def test_ellipse__1_pixel_height(self): + """Ensures an ellipse with a height of 1 is drawn correctly. + + An ellipse with a height of 1 pixel is a horizontal line. + """ + ellipse_color = pygame.Color("red") + surface_color = pygame.Color("black") + surf_w, surf_h = 20, 10 + + surface = pygame.Surface((surf_w, surf_h)) + rect = pygame.Rect((0, 0), (0, 1)) + collide_rect = rect.copy() + + # Calculate some positions. + off_right = surf_w + off_top = -1 + off_bottom = surf_h + center_x = surf_w // 2 + center_y = surf_h // 2 + + # Test some even and odd widths. + for ellipse_w in range(6, 10): + collide_rect.w = ellipse_w + rect.w = ellipse_w + + # Calculate some variable positions. + off_left = -(ellipse_w + 1) + half_off_left = -(ellipse_w // 2) + half_off_right = surf_w - (ellipse_w // 2) + + # Draw the ellipse in different positions: fully on-surface, + # partially off-surface, and fully off-surface. + positions = ( + (off_left, off_top), + (half_off_left, off_top), + (center_x, off_top), + (half_off_right, off_top), + (off_right, off_top), + (off_left, center_y), + (half_off_left, center_y), + (center_x, center_y), + (half_off_right, center_y), + (off_right, center_y), + (off_left, off_bottom), + (half_off_left, off_bottom), + (center_x, off_bottom), + (half_off_right, off_bottom), + (off_right, off_bottom), + ) + + for rect_pos in positions: + surface.fill(surface_color) # Clear before each draw. + rect.topleft = rect_pos + collide_rect.topleft = rect_pos + + self.draw_ellipse(surface, ellipse_color, rect) + + self._check_1_pixel_sized_ellipse( + surface, collide_rect, surface_color, ellipse_color + ) + + def test_ellipse__1_pixel_height_spanning_surface(self): + """Ensures an ellipse with a height of 1 is drawn correctly + when spanning the width of the surface. + + An ellipse with a height of 1 pixel is a horizontal line. + """ + ellipse_color = pygame.Color("red") + surface_color = pygame.Color("black") + surf_w, surf_h = 20, 10 + + surface = pygame.Surface((surf_w, surf_h)) + rect = pygame.Rect((0, 0), (surf_w + 2, 1)) # Wider than the surface. + + # Draw the ellipse in different positions: on-surface and off-surface. + positions = ( + (-1, -1), # (off_left, off_top) + (-1, 0), # (off_left, top_edge) + (-1, surf_h // 2), # (off_left, center_y) + (-1, surf_h - 1), # (off_left, bottom_edge) + (-1, surf_h), + ) # (off_left, off_bottom) + + for rect_pos in positions: + surface.fill(surface_color) # Clear before each draw. + rect.topleft = rect_pos + + self.draw_ellipse(surface, ellipse_color, rect) + + self._check_1_pixel_sized_ellipse( + surface, rect, surface_color, ellipse_color + ) + + def test_ellipse__1_pixel_width_and_height(self): + """Ensures an ellipse with a width and height of 1 is drawn correctly. + + An ellipse with a width and height of 1 pixel is a single pixel. + """ + ellipse_color = pygame.Color("red") + surface_color = pygame.Color("black") + surf_w, surf_h = 10, 10 + + surface = pygame.Surface((surf_w, surf_h)) + rect = pygame.Rect((0, 0), (1, 1)) + + # Calculate some positions. + off_left = -1 + off_right = surf_w + off_top = -1 + off_bottom = surf_h + left_edge = 0 + right_edge = surf_w - 1 + top_edge = 0 + bottom_edge = surf_h - 1 + center_x = surf_w // 2 + center_y = surf_h // 2 + + # Draw the ellipse in different positions: center surface, + # top/bottom/left/right edges, and off-surface. + positions = ( + (off_left, off_top), + (off_left, top_edge), + (off_left, center_y), + (off_left, bottom_edge), + (off_left, off_bottom), + (left_edge, off_top), + (left_edge, top_edge), + (left_edge, center_y), + (left_edge, bottom_edge), + (left_edge, off_bottom), + (center_x, off_top), + (center_x, top_edge), + (center_x, center_y), + (center_x, bottom_edge), + (center_x, off_bottom), + (right_edge, off_top), + (right_edge, top_edge), + (right_edge, center_y), + (right_edge, bottom_edge), + (right_edge, off_bottom), + (off_right, off_top), + (off_right, top_edge), + (off_right, center_y), + (off_right, bottom_edge), + (off_right, off_bottom), + ) + + for rect_pos in positions: + surface.fill(surface_color) # Clear before each draw. + rect.topleft = rect_pos + + self.draw_ellipse(surface, ellipse_color, rect) + + self._check_1_pixel_sized_ellipse( + surface, rect, surface_color, ellipse_color + ) + + def test_ellipse__bounding_rect(self): + """Ensures draw ellipse returns the correct bounding rect. + + Tests ellipses on and off the surface and a range of width/thickness + values. + """ + ellipse_color = pygame.Color("red") + surf_color = pygame.Color("black") + min_width = min_height = 5 + max_width = max_height = 7 + sizes = ((min_width, min_height), (max_width, max_height)) + surface = pygame.Surface((20, 20), 0, 32) + surf_rect = surface.get_rect() + # Make a rect that is bigger than the surface to help test drawing + # ellipses off and partially off the surface. + big_rect = surf_rect.inflate(min_width * 2 + 1, min_height * 2 + 1) + + for pos in rect_corners_mids_and_center( + surf_rect + ) + rect_corners_mids_and_center(big_rect): + # Each of the ellipse's rect position attributes will be set to + # the pos value. + for attr in RECT_POSITION_ATTRIBUTES: + # Test using different rect sizes and thickness values. + for width, height in sizes: + ellipse_rect = pygame.Rect((0, 0), (width, height)) + setattr(ellipse_rect, attr, pos) + + for thickness in (0, 1, 2, 3, min(width, height)): + surface.fill(surf_color) # Clear for each test. + + bounding_rect = self.draw_ellipse( + surface, ellipse_color, ellipse_rect, thickness + ) + + # Calculating the expected_rect after the ellipse + # is drawn (it uses what is actually drawn). + expected_rect = create_bounding_rect( + surface, surf_color, ellipse_rect.topleft + ) + + self.assertEqual(bounding_rect, expected_rect) + + def test_ellipse__surface_clip(self): + """Ensures draw ellipse respects a surface's clip area. + + Tests drawing the ellipse filled and unfilled. + """ + surfw = surfh = 30 + ellipse_color = pygame.Color("red") + surface_color = pygame.Color("green") + surface = pygame.Surface((surfw, surfh)) + surface.fill(surface_color) + + clip_rect = pygame.Rect((0, 0), (11, 11)) + clip_rect.center = surface.get_rect().center + pos_rect = clip_rect.copy() # Manages the ellipse's pos. + + for width in (0, 1): # Filled and unfilled. + # Test centering the ellipse along the clip rect's edge. + for center in rect_corners_mids_and_center(clip_rect): + # Get the expected points by drawing the ellipse without the + # clip area set. + pos_rect.center = center + surface.set_clip(None) + surface.fill(surface_color) + self.draw_ellipse(surface, ellipse_color, pos_rect, width) + expected_pts = get_color_points(surface, ellipse_color, clip_rect) + + # Clear the surface and set the clip area. Redraw the ellipse + # and check that only the clip area is modified. + surface.fill(surface_color) + surface.set_clip(clip_rect) + + self.draw_ellipse(surface, ellipse_color, pos_rect, width) + + surface.lock() # For possible speed up. + + # Check all the surface points to ensure only the expected_pts + # are the ellipse_color. + for pt in ((x, y) for x in range(surfw) for y in range(surfh)): + if pt in expected_pts: + expected_color = ellipse_color + else: + expected_color = surface_color + + self.assertEqual(surface.get_at(pt), expected_color, pt) + + surface.unlock() + + +class DrawEllipseTest(DrawEllipseMixin, DrawTestCase): + """Test draw module function ellipse. + + This class inherits the general tests from DrawEllipseMixin. It is also + the class to add any draw.ellipse specific tests to. + """ + + +# Commented out to avoid cluttering the test output. Add back in if draw_py +# ever properly supports drawing ellipses. +# @unittest.skip('draw_py.draw_ellipse not supported yet') +# class PythonDrawEllipseTest(DrawEllipseMixin, PythonDrawTestCase): +# """Test draw_py module function draw_ellipse. +# +# This class inherits the general tests from DrawEllipseMixin. It is also +# the class to add any draw_py.draw_ellipse specific tests to. +# """ + + +### Line/Lines/AALine/AALines Testing ######################################### + + +class BaseLineMixin(object): + """Mixin base for drawing various lines. + + This class contains general helper methods and setup for testing the + different types of lines. + """ + + COLORS = ( + (0, 0, 0), + (255, 0, 0), + (0, 255, 0), + (0, 0, 255), + (255, 255, 0), + (255, 0, 255), + (0, 255, 255), + (255, 255, 255), + ) + + @staticmethod + def _create_surfaces(): + # Create some surfaces with different sizes, depths, and flags. + surfaces = [] + for size in ((49, 49), (50, 50)): + for depth in (8, 16, 24, 32): + for flags in (0, SRCALPHA): + surface = pygame.display.set_mode(size, flags, depth) + surfaces.append(surface) + surfaces.append(surface.convert_alpha()) + return surfaces + + @staticmethod + def _rect_lines(rect): + # Yields pairs of end points and their reverse (to test symmetry). + # Uses a rect with the points radiating from its midleft. + for pt in rect_corners_mids_and_center(rect): + if pt in [rect.midleft, rect.center]: + # Don't bother with these points. + continue + yield (rect.midleft, pt) + yield (pt, rect.midleft) + + +### Line Testing ############################################################## + + +class LineMixin(BaseLineMixin): + """Mixin test for drawing a single line. + + This class contains all the general single line drawing tests. + """ + + def test_line__args(self): + """Ensures draw line accepts the correct args.""" + bounds_rect = self.draw_line( + pygame.Surface((3, 3)), (0, 10, 0, 50), (0, 0), (1, 1), 1 + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_line__args_without_width(self): + """Ensures draw line accepts the args without a width.""" + bounds_rect = self.draw_line( + pygame.Surface((2, 2)), (0, 0, 0, 50), (0, 0), (2, 2) + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_line__kwargs(self): + """Ensures draw line accepts the correct kwargs + with and without a width arg. + """ + surface = pygame.Surface((4, 4)) + color = pygame.Color("yellow") + start_pos = (1, 1) + end_pos = (2, 2) + kwargs_list = [ + { + "surface": surface, + "color": color, + "start_pos": start_pos, + "end_pos": end_pos, + "width": 1, + }, + { + "surface": surface, + "color": color, + "start_pos": start_pos, + "end_pos": end_pos, + }, + ] + + for kwargs in kwargs_list: + bounds_rect = self.draw_line(**kwargs) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_line__kwargs_order_independent(self): + """Ensures draw line's kwargs are not order dependent.""" + bounds_rect = self.draw_line( + start_pos=(1, 2), + end_pos=(2, 1), + width=2, + color=(10, 20, 30), + surface=pygame.Surface((3, 2)), + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_line__args_missing(self): + """Ensures draw line detects any missing required args.""" + surface = pygame.Surface((1, 1)) + color = pygame.Color("blue") + + with self.assertRaises(TypeError): + bounds_rect = self.draw_line(surface, color, (0, 0)) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_line(surface, color) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_line(surface) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_line() + + def test_line__kwargs_missing(self): + """Ensures draw line detects any missing required kwargs.""" + kwargs = { + "surface": pygame.Surface((3, 2)), + "color": pygame.Color("red"), + "start_pos": (2, 1), + "end_pos": (2, 2), + "width": 1, + } + + for name in ("end_pos", "start_pos", "color", "surface"): + invalid_kwargs = dict(kwargs) + invalid_kwargs.pop(name) # Pop from a copy. + + with self.assertRaises(TypeError): + bounds_rect = self.draw_line(**invalid_kwargs) + + def test_line__arg_invalid_types(self): + """Ensures draw line detects invalid arg types.""" + surface = pygame.Surface((2, 2)) + color = pygame.Color("blue") + start_pos = (0, 1) + end_pos = (1, 2) + + with self.assertRaises(TypeError): + # Invalid width. + bounds_rect = self.draw_line(surface, color, start_pos, end_pos, "1") + + with self.assertRaises(TypeError): + # Invalid end_pos. + bounds_rect = self.draw_line(surface, color, start_pos, (1, 2, 3)) + + with self.assertRaises(TypeError): + # Invalid start_pos. + bounds_rect = self.draw_line(surface, color, (1,), end_pos) + + with self.assertRaises(TypeError): + # Invalid color. + bounds_rect = self.draw_line(surface, 2.3, start_pos, end_pos) + + with self.assertRaises(TypeError): + # Invalid surface. + bounds_rect = self.draw_line((1, 2, 3, 4), color, start_pos, end_pos) + + def test_line__kwarg_invalid_types(self): + """Ensures draw line detects invalid kwarg types.""" + surface = pygame.Surface((3, 3)) + color = pygame.Color("green") + start_pos = (1, 0) + end_pos = (2, 0) + width = 1 + kwargs_list = [ + { + "surface": pygame.Surface, # Invalid surface. + "color": color, + "start_pos": start_pos, + "end_pos": end_pos, + "width": width, + }, + { + "surface": surface, + "color": 2.3, # Invalid color. + "start_pos": start_pos, + "end_pos": end_pos, + "width": width, + }, + { + "surface": surface, + "color": color, + "start_pos": (0, 0, 0), # Invalid start_pos. + "end_pos": end_pos, + "width": width, + }, + { + "surface": surface, + "color": color, + "start_pos": start_pos, + "end_pos": (0,), # Invalid end_pos. + "width": width, + }, + { + "surface": surface, + "color": color, + "start_pos": start_pos, + "end_pos": end_pos, + "width": 1.2, + }, + ] # Invalid width. + + for kwargs in kwargs_list: + with self.assertRaises(TypeError): + bounds_rect = self.draw_line(**kwargs) + + def test_line__kwarg_invalid_name(self): + """Ensures draw line detects invalid kwarg names.""" + surface = pygame.Surface((2, 3)) + color = pygame.Color("cyan") + start_pos = (1, 1) + end_pos = (2, 0) + kwargs_list = [ + { + "surface": surface, + "color": color, + "start_pos": start_pos, + "end_pos": end_pos, + "width": 1, + "invalid": 1, + }, + { + "surface": surface, + "color": color, + "start_pos": start_pos, + "end_pos": end_pos, + "invalid": 1, + }, + ] + + for kwargs in kwargs_list: + with self.assertRaises(TypeError): + bounds_rect = self.draw_line(**kwargs) + + def test_line__args_and_kwargs(self): + """Ensures draw line accepts a combination of args/kwargs""" + surface = pygame.Surface((3, 2)) + color = (255, 255, 0, 0) + start_pos = (0, 1) + end_pos = (1, 2) + width = 0 + kwargs = { + "surface": surface, + "color": color, + "start_pos": start_pos, + "end_pos": end_pos, + "width": width, + } + + for name in ("surface", "color", "start_pos", "end_pos", "width"): + kwargs.pop(name) + + if "surface" == name: + bounds_rect = self.draw_line(surface, **kwargs) + elif "color" == name: + bounds_rect = self.draw_line(surface, color, **kwargs) + elif "start_pos" == name: + bounds_rect = self.draw_line(surface, color, start_pos, **kwargs) + elif "end_pos" == name: + bounds_rect = self.draw_line( + surface, color, start_pos, end_pos, **kwargs + ) + else: + bounds_rect = self.draw_line( + surface, color, start_pos, end_pos, width, **kwargs + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_line__valid_width_values(self): + """Ensures draw line accepts different width values.""" + line_color = pygame.Color("yellow") + surface_color = pygame.Color("white") + surface = pygame.Surface((3, 4)) + pos = (2, 1) + kwargs = { + "surface": surface, + "color": line_color, + "start_pos": pos, + "end_pos": (2, 2), + "width": None, + } + + for width in (-100, -10, -1, 0, 1, 10, 100): + surface.fill(surface_color) # Clear for each test. + kwargs["width"] = width + expected_color = line_color if width > 0 else surface_color + + bounds_rect = self.draw_line(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_line__valid_start_pos_formats(self): + """Ensures draw line accepts different start_pos formats.""" + expected_color = pygame.Color("red") + surface_color = pygame.Color("black") + surface = pygame.Surface((4, 4)) + kwargs = { + "surface": surface, + "color": expected_color, + "start_pos": None, + "end_pos": (2, 2), + "width": 2, + } + x, y = 2, 1 # start position + + # The point values can be ints or floats. + for start_pos in ((x, y), (x + 0.1, y), (x, y + 0.1), (x + 0.1, y + 0.1)): + # The point type can be a tuple/list/Vector2. + for seq_type in (tuple, list, Vector2): + surface.fill(surface_color) # Clear for each test. + kwargs["start_pos"] = seq_type(start_pos) + + bounds_rect = self.draw_line(**kwargs) + + self.assertEqual(surface.get_at((x, y)), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_line__valid_end_pos_formats(self): + """Ensures draw line accepts different end_pos formats.""" + expected_color = pygame.Color("red") + surface_color = pygame.Color("black") + surface = pygame.Surface((4, 4)) + kwargs = { + "surface": surface, + "color": expected_color, + "start_pos": (2, 1), + "end_pos": None, + "width": 2, + } + x, y = 2, 2 # end position + + # The point values can be ints or floats. + for end_pos in ((x, y), (x + 0.2, y), (x, y + 0.2), (x + 0.2, y + 0.2)): + # The point type can be a tuple/list/Vector2. + for seq_type in (tuple, list, Vector2): + surface.fill(surface_color) # Clear for each test. + kwargs["end_pos"] = seq_type(end_pos) + + bounds_rect = self.draw_line(**kwargs) + + self.assertEqual(surface.get_at((x, y)), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_line__invalid_start_pos_formats(self): + """Ensures draw line handles invalid start_pos formats correctly.""" + kwargs = { + "surface": pygame.Surface((4, 4)), + "color": pygame.Color("red"), + "start_pos": None, + "end_pos": (2, 2), + "width": 1, + } + + start_pos_fmts = ( + (2,), # Too few coords. + (2, 1, 0), # Too many coords. + (2, "1"), # Wrong type. + set([2, 1]), # Wrong type. + dict(((2, 1),)), + ) # Wrong type. + + for start_pos in start_pos_fmts: + kwargs["start_pos"] = start_pos + + with self.assertRaises(TypeError): + bounds_rect = self.draw_line(**kwargs) + + def test_line__invalid_end_pos_formats(self): + """Ensures draw line handles invalid end_pos formats correctly.""" + kwargs = { + "surface": pygame.Surface((4, 4)), + "color": pygame.Color("red"), + "start_pos": (2, 2), + "end_pos": None, + "width": 1, + } + + end_pos_fmts = ( + (2,), # Too few coords. + (2, 1, 0), # Too many coords. + (2, "1"), # Wrong type. + set([2, 1]), # Wrong type. + dict(((2, 1),)), + ) # Wrong type. + + for end_pos in end_pos_fmts: + kwargs["end_pos"] = end_pos + + with self.assertRaises(TypeError): + bounds_rect = self.draw_line(**kwargs) + + def test_line__valid_color_formats(self): + """Ensures draw line accepts different color formats.""" + green_color = pygame.Color("green") + surface_color = pygame.Color("black") + surface = pygame.Surface((3, 4)) + pos = (1, 1) + kwargs = { + "surface": surface, + "color": None, + "start_pos": pos, + "end_pos": (2, 1), + "width": 3, + } + greens = ( + (0, 255, 0), + (0, 255, 0, 255), + surface.map_rgb(green_color), + green_color, + ) + + for color in greens: + surface.fill(surface_color) # Clear for each test. + kwargs["color"] = color + + if isinstance(color, int): + expected_color = surface.unmap_rgb(color) + else: + expected_color = green_color + + bounds_rect = self.draw_line(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_line__invalid_color_formats(self): + """Ensures draw line handles invalid color formats correctly.""" + kwargs = { + "surface": pygame.Surface((4, 3)), + "color": None, + "start_pos": (1, 1), + "end_pos": (2, 1), + "width": 1, + } + + for expected_color in (2.3, self): + kwargs["color"] = expected_color + + with self.assertRaises(TypeError): + bounds_rect = self.draw_line(**kwargs) + + def test_line__color(self): + """Tests if the line drawn is the correct color.""" + pos = (0, 0) + for surface in self._create_surfaces(): + for expected_color in self.COLORS: + self.draw_line(surface, expected_color, pos, (1, 0)) + + self.assertEqual( + surface.get_at(pos), expected_color, "pos={}".format(pos) + ) + + def test_line__color_with_thickness(self): + """Ensures a thick line is drawn using the correct color.""" + from_x = 5 + to_x = 10 + y = 5 + for surface in self._create_surfaces(): + for expected_color in self.COLORS: + self.draw_line(surface, expected_color, (from_x, y), (to_x, y), 5) + for pos in ((x, y + i) for i in (-2, 0, 2) for x in (from_x, to_x)): + self.assertEqual( + surface.get_at(pos), expected_color, "pos={}".format(pos) + ) + + def test_line__gaps(self): + """Tests if the line drawn contains any gaps.""" + expected_color = (255, 255, 255) + for surface in self._create_surfaces(): + width = surface.get_width() + self.draw_line(surface, expected_color, (0, 0), (width - 1, 0)) + + for x in range(width): + pos = (x, 0) + self.assertEqual( + surface.get_at(pos), expected_color, "pos={}".format(pos) + ) + + def test_line__gaps_with_thickness(self): + """Ensures a thick line is drawn without any gaps.""" + expected_color = (255, 255, 255) + thickness = 5 + for surface in self._create_surfaces(): + width = surface.get_width() - 1 + h = width // 5 + w = h * 5 + self.draw_line(surface, expected_color, (0, 5), (w, 5 + h), thickness) + + for x in range(w + 1): + for y in range(3, 8): + pos = (x, y + ((x + 2) // 5)) + self.assertEqual( + surface.get_at(pos), expected_color, "pos={}".format(pos) + ) + + def test_line__bounding_rect(self): + """Ensures draw line returns the correct bounding rect. + + Tests lines with endpoints on and off the surface and a range of + width/thickness values. + """ + if isinstance(self, PythonDrawTestCase): + self.skipTest("bounding rects not supported in draw_py.draw_line") + + line_color = pygame.Color("red") + surf_color = pygame.Color("black") + width = height = 30 + # Using a rect to help manage where the lines are drawn. + helper_rect = pygame.Rect((0, 0), (width, height)) + + # Testing surfaces of different sizes. One larger than the helper_rect + # and one smaller (to test lines that span the surface). + for size in ((width + 5, height + 5), (width - 5, height - 5)): + surface = pygame.Surface(size, 0, 32) + surf_rect = surface.get_rect() + + # Move the helper rect to different positions to test line + # endpoints on and off the surface. + for pos in rect_corners_mids_and_center(surf_rect): + helper_rect.center = pos + + # Draw using different thicknesses. + for thickness in range(-1, 5): + for start, end in self._rect_lines(helper_rect): + surface.fill(surf_color) # Clear for each test. + + bounding_rect = self.draw_line( + surface, line_color, start, end, thickness + ) + + if 0 < thickness: + # Calculating the expected_rect after the line is + # drawn (it uses what is actually drawn). + expected_rect = create_bounding_rect( + surface, surf_color, start + ) + else: + # Nothing drawn. + expected_rect = pygame.Rect(start, (0, 0)) + + self.assertEqual( + bounding_rect, + expected_rect, + "start={}, end={}, size={}, thickness={}".format( + start, end, size, thickness + ), + ) + + def test_line__surface_clip(self): + """Ensures draw line respects a surface's clip area.""" + surfw = surfh = 30 + line_color = pygame.Color("red") + surface_color = pygame.Color("green") + surface = pygame.Surface((surfw, surfh)) + surface.fill(surface_color) + + clip_rect = pygame.Rect((0, 0), (11, 11)) + clip_rect.center = surface.get_rect().center + pos_rect = clip_rect.copy() # Manages the line's pos. + + for thickness in (1, 3): # Test different line widths. + # Test centering the line along the clip rect's edge. + for center in rect_corners_mids_and_center(clip_rect): + # Get the expected points by drawing the line without the + # clip area set. + pos_rect.center = center + surface.set_clip(None) + surface.fill(surface_color) + self.draw_line( + surface, line_color, pos_rect.midtop, pos_rect.midbottom, thickness + ) + expected_pts = get_color_points(surface, line_color, clip_rect) + + # Clear the surface and set the clip area. Redraw the line + # and check that only the clip area is modified. + surface.fill(surface_color) + surface.set_clip(clip_rect) + + self.draw_line( + surface, line_color, pos_rect.midtop, pos_rect.midbottom, thickness + ) + + surface.lock() # For possible speed up. + + # Check all the surface points to ensure only the expected_pts + # are the line_color. + for pt in ((x, y) for x in range(surfw) for y in range(surfh)): + if pt in expected_pts: + expected_color = line_color + else: + expected_color = surface_color + + self.assertEqual(surface.get_at(pt), expected_color, pt) + + surface.unlock() + + +# Commented out to avoid cluttering the test output. Add back in if draw_py +# ever fully supports drawing single lines. +# @unittest.skip('draw_py.draw_line not fully supported yet') +# class PythonDrawLineTest(LineMixin, PythonDrawTestCase): +# """Test draw_py module function line. +# +# This class inherits the general tests from LineMixin. It is also the class +# to add any draw_py.draw_line specific tests to. +# """ + + +class DrawLineTest(LineMixin, DrawTestCase): + """Test draw module function line. + + This class inherits the general tests from LineMixin. It is also the class + to add any draw.line specific tests to. + """ + + def test_line_endianness(self): + """test color component order""" + for depth in (24, 32): + surface = pygame.Surface((5, 3), 0, depth) + surface.fill(pygame.Color(0, 0, 0)) + self.draw_line(surface, pygame.Color(255, 0, 0), (0, 1), (2, 1), 1) + + self.assertGreater(surface.get_at((1, 1)).r, 0, "there should be red here") + + surface.fill(pygame.Color(0, 0, 0)) + self.draw_line(surface, pygame.Color(0, 0, 255), (0, 1), (2, 1), 1) + + self.assertGreater(surface.get_at((1, 1)).b, 0, "there should be blue here") + + def test_line(self): + # (l, t), (l, t) + self.surf_size = (320, 200) + self.surf = pygame.Surface(self.surf_size, pygame.SRCALPHA) + self.color = (1, 13, 24, 205) + + drawn = draw.line(self.surf, self.color, (1, 0), (200, 0)) + self.assertEqual( + drawn.right, 201, "end point arg should be (or at least was) inclusive" + ) + + # Should be colored where it's supposed to be + for pt in test_utils.rect_area_pts(drawn): + self.assertEqual(self.surf.get_at(pt), self.color) + + # And not where it shouldn't + for pt in test_utils.rect_outer_bounds(drawn): + self.assertNotEqual(self.surf.get_at(pt), self.color) + + # Line width greater that 1 + line_width = 2 + offset = 5 + a = (offset, offset) + b = (self.surf_size[0] - offset, a[1]) + c = (a[0], self.surf_size[1] - offset) + d = (b[0], c[1]) + e = (a[0] + offset, c[1]) + f = (b[0], c[0] + 5) + lines = [ + (a, d), + (b, c), + (c, b), + (d, a), + (a, b), + (b, a), + (a, c), + (c, a), + (a, e), + (e, a), + (a, f), + (f, a), + (a, a), + ] + + for p1, p2 in lines: + msg = "%s - %s" % (p1, p2) + if p1[0] <= p2[0]: + plow = p1 + phigh = p2 + else: + plow = p2 + phigh = p1 + + self.surf.fill((0, 0, 0)) + rec = draw.line(self.surf, (255, 255, 255), p1, p2, line_width) + xinc = yinc = 0 + + if abs(p1[0] - p2[0]) > abs(p1[1] - p2[1]): + yinc = 1 + else: + xinc = 1 + + for i in range(line_width): + p = (p1[0] + xinc * i, p1[1] + yinc * i) + self.assertEqual(self.surf.get_at(p), (255, 255, 255), msg) + + p = (p2[0] + xinc * i, p2[1] + yinc * i) + self.assertEqual(self.surf.get_at(p), (255, 255, 255), msg) + + p = (plow[0] - 1, plow[1]) + self.assertEqual(self.surf.get_at(p), (0, 0, 0), msg) + + p = (plow[0] + xinc * line_width, plow[1] + yinc * line_width) + self.assertEqual(self.surf.get_at(p), (0, 0, 0), msg) + + p = (phigh[0] + xinc * line_width, phigh[1] + yinc * line_width) + self.assertEqual(self.surf.get_at(p), (0, 0, 0), msg) + + if p1[0] < p2[0]: + rx = p1[0] + else: + rx = p2[0] + + if p1[1] < p2[1]: + ry = p1[1] + else: + ry = p2[1] + + w = abs(p2[0] - p1[0]) + 1 + xinc * (line_width - 1) + h = abs(p2[1] - p1[1]) + 1 + yinc * (line_width - 1) + msg += ", %s" % (rec,) + + self.assertEqual(rec, (rx, ry, w, h), msg) + + def test_line_for_gaps(self): + # This checks bug Thick Line Bug #448 + + width = 200 + height = 200 + surf = pygame.Surface((width, height), pygame.SRCALPHA) + + def white_surrounded_pixels(x, y): + offsets = [(1, 0), (0, 1), (-1, 0), (0, -1)] + WHITE = (255, 255, 255, 255) + return len( + [1 for dx, dy in offsets if surf.get_at((x + dx, y + dy)) == WHITE] + ) + + def check_white_line(start, end): + surf.fill((0, 0, 0)) + pygame.draw.line(surf, (255, 255, 255), start, end, 30) + + BLACK = (0, 0, 0, 255) + for x in range(1, width - 1): + for y in range(1, height - 1): + if surf.get_at((x, y)) == BLACK: + self.assertTrue(white_surrounded_pixels(x, y) < 3) + + check_white_line((50, 50), (140, 0)) + check_white_line((50, 50), (0, 120)) + check_white_line((50, 50), (199, 198)) + + +### Lines Testing ############################################################# + + +class LinesMixin(BaseLineMixin): + """Mixin test for drawing lines. + + This class contains all the general lines drawing tests. + """ + + def test_lines__args(self): + """Ensures draw lines accepts the correct args.""" + bounds_rect = self.draw_lines( + pygame.Surface((3, 3)), (0, 10, 0, 50), False, ((0, 0), (1, 1)), 1 + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_lines__args_without_width(self): + """Ensures draw lines accepts the args without a width.""" + bounds_rect = self.draw_lines( + pygame.Surface((2, 2)), (0, 0, 0, 50), False, ((0, 0), (1, 1)) + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_lines__kwargs(self): + """Ensures draw lines accepts the correct kwargs + with and without a width arg. + """ + surface = pygame.Surface((4, 4)) + color = pygame.Color("yellow") + points = ((0, 0), (1, 1), (2, 2)) + kwargs_list = [ + { + "surface": surface, + "color": color, + "closed": False, + "points": points, + "width": 1, + }, + {"surface": surface, "color": color, "closed": False, "points": points}, + ] + + for kwargs in kwargs_list: + bounds_rect = self.draw_lines(**kwargs) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_lines__kwargs_order_independent(self): + """Ensures draw lines's kwargs are not order dependent.""" + bounds_rect = self.draw_lines( + closed=1, + points=((0, 0), (1, 1), (2, 2)), + width=2, + color=(10, 20, 30), + surface=pygame.Surface((3, 2)), + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_lines__args_missing(self): + """Ensures draw lines detects any missing required args.""" + surface = pygame.Surface((1, 1)) + color = pygame.Color("blue") + + with self.assertRaises(TypeError): + bounds_rect = self.draw_lines(surface, color, 0) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_lines(surface, color) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_lines(surface) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_lines() + + def test_lines__kwargs_missing(self): + """Ensures draw lines detects any missing required kwargs.""" + kwargs = { + "surface": pygame.Surface((3, 2)), + "color": pygame.Color("red"), + "closed": 1, + "points": ((2, 2), (1, 1)), + "width": 1, + } + + for name in ("points", "closed", "color", "surface"): + invalid_kwargs = dict(kwargs) + invalid_kwargs.pop(name) # Pop from a copy. + + with self.assertRaises(TypeError): + bounds_rect = self.draw_lines(**invalid_kwargs) + + def test_lines__arg_invalid_types(self): + """Ensures draw lines detects invalid arg types.""" + surface = pygame.Surface((2, 2)) + color = pygame.Color("blue") + closed = 0 + points = ((1, 2), (2, 1)) + + with self.assertRaises(TypeError): + # Invalid width. + bounds_rect = self.draw_lines(surface, color, closed, points, "1") + + with self.assertRaises(TypeError): + # Invalid points. + bounds_rect = self.draw_lines(surface, color, closed, (1, 2, 3)) + + with self.assertRaises(TypeError): + # Invalid closed. + bounds_rect = self.draw_lines(surface, color, InvalidBool(), points) + + with self.assertRaises(TypeError): + # Invalid color. + bounds_rect = self.draw_lines(surface, 2.3, closed, points) + + with self.assertRaises(TypeError): + # Invalid surface. + bounds_rect = self.draw_lines((1, 2, 3, 4), color, closed, points) + + def test_lines__kwarg_invalid_types(self): + """Ensures draw lines detects invalid kwarg types.""" + valid_kwargs = { + "surface": pygame.Surface((3, 3)), + "color": pygame.Color("green"), + "closed": False, + "points": ((1, 2), (2, 1)), + "width": 1, + } + + invalid_kwargs = { + "surface": pygame.Surface, + "color": 2.3, + "closed": InvalidBool(), + "points": (0, 0, 0), + "width": 1.2, + } + + for kwarg in ("surface", "color", "closed", "points", "width"): + kwargs = dict(valid_kwargs) + kwargs[kwarg] = invalid_kwargs[kwarg] + + with self.assertRaises(TypeError): + bounds_rect = self.draw_lines(**kwargs) + + def test_lines__kwarg_invalid_name(self): + """Ensures draw lines detects invalid kwarg names.""" + surface = pygame.Surface((2, 3)) + color = pygame.Color("cyan") + closed = 1 + points = ((1, 2), (2, 1)) + kwargs_list = [ + { + "surface": surface, + "color": color, + "closed": closed, + "points": points, + "width": 1, + "invalid": 1, + }, + { + "surface": surface, + "color": color, + "closed": closed, + "points": points, + "invalid": 1, + }, + ] + + for kwargs in kwargs_list: + with self.assertRaises(TypeError): + bounds_rect = self.draw_lines(**kwargs) + + def test_lines__args_and_kwargs(self): + """Ensures draw lines accepts a combination of args/kwargs""" + surface = pygame.Surface((3, 2)) + color = (255, 255, 0, 0) + closed = 0 + points = ((1, 2), (2, 1)) + width = 1 + kwargs = { + "surface": surface, + "color": color, + "closed": closed, + "points": points, + "width": width, + } + + for name in ("surface", "color", "closed", "points", "width"): + kwargs.pop(name) + + if "surface" == name: + bounds_rect = self.draw_lines(surface, **kwargs) + elif "color" == name: + bounds_rect = self.draw_lines(surface, color, **kwargs) + elif "closed" == name: + bounds_rect = self.draw_lines(surface, color, closed, **kwargs) + elif "points" == name: + bounds_rect = self.draw_lines(surface, color, closed, points, **kwargs) + else: + bounds_rect = self.draw_lines( + surface, color, closed, points, width, **kwargs + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_lines__valid_width_values(self): + """Ensures draw lines accepts different width values.""" + line_color = pygame.Color("yellow") + surface_color = pygame.Color("white") + surface = pygame.Surface((3, 4)) + pos = (1, 1) + kwargs = { + "surface": surface, + "color": line_color, + "closed": False, + "points": (pos, (2, 1)), + "width": None, + } + + for width in (-100, -10, -1, 0, 1, 10, 100): + surface.fill(surface_color) # Clear for each test. + kwargs["width"] = width + expected_color = line_color if width > 0 else surface_color + + bounds_rect = self.draw_lines(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_lines__valid_points_format(self): + """Ensures draw lines accepts different points formats.""" + expected_color = (10, 20, 30, 255) + surface_color = pygame.Color("white") + surface = pygame.Surface((3, 4)) + kwargs = { + "surface": surface, + "color": expected_color, + "closed": False, + "points": None, + "width": 1, + } + + # The point type can be a tuple/list/Vector2. + point_types = ( + (tuple, tuple, tuple, tuple), # all tuples + (list, list, list, list), # all lists + (Vector2, Vector2, Vector2, Vector2), # all Vector2s + (list, Vector2, tuple, Vector2), + ) # mix + + # The point values can be ints or floats. + point_values = ( + ((1, 1), (2, 1), (2, 2), (1, 2)), + ((1, 1), (2.2, 1), (2.1, 2.2), (1, 2.1)), + ) + + # Each sequence of points can be a tuple or a list. + seq_types = (tuple, list) + + for point_type in point_types: + for values in point_values: + check_pos = values[0] + points = [point_type[i](pt) for i, pt in enumerate(values)] + + for seq_type in seq_types: + surface.fill(surface_color) # Clear for each test. + kwargs["points"] = seq_type(points) + + bounds_rect = self.draw_lines(**kwargs) + + self.assertEqual(surface.get_at(check_pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_lines__invalid_points_formats(self): + """Ensures draw lines handles invalid points formats correctly.""" + kwargs = { + "surface": pygame.Surface((4, 4)), + "color": pygame.Color("red"), + "closed": False, + "points": None, + "width": 1, + } + + points_fmts = ( + ((1, 1), (2,)), # Too few coords. + ((1, 1), (2, 2, 2)), # Too many coords. + ((1, 1), (2, "2")), # Wrong type. + ((1, 1), set([2, 3])), # Wrong type. + ((1, 1), dict(((2, 2), (3, 3)))), # Wrong type. + set(((1, 1), (1, 2))), # Wrong type. + dict(((1, 1), (4, 4))), + ) # Wrong type. + + for points in points_fmts: + kwargs["points"] = points + + with self.assertRaises(TypeError): + bounds_rect = self.draw_lines(**kwargs) + + def test_lines__invalid_points_values(self): + """Ensures draw lines handles invalid points values correctly.""" + kwargs = { + "surface": pygame.Surface((4, 4)), + "color": pygame.Color("red"), + "closed": False, + "points": None, + "width": 1, + } + + for points in ([], ((1, 1),)): # Too few points. + for seq_type in (tuple, list): # Test as tuples and lists. + kwargs["points"] = seq_type(points) + + with self.assertRaises(ValueError): + bounds_rect = self.draw_lines(**kwargs) + + def test_lines__valid_closed_values(self): + """Ensures draw lines accepts different closed values.""" + line_color = pygame.Color("blue") + surface_color = pygame.Color("white") + surface = pygame.Surface((3, 4)) + pos = (1, 2) + kwargs = { + "surface": surface, + "color": line_color, + "closed": None, + "points": ((1, 1), (3, 1), (3, 3), (1, 3)), + "width": 1, + } + + true_values = (-7, 1, 10, "2", 3.1, (4,), [5], True) + false_values = (None, "", 0, (), [], False) + + for closed in true_values + false_values: + surface.fill(surface_color) # Clear for each test. + kwargs["closed"] = closed + expected_color = line_color if closed else surface_color + + bounds_rect = self.draw_lines(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_lines__valid_color_formats(self): + """Ensures draw lines accepts different color formats.""" + green_color = pygame.Color("green") + surface_color = pygame.Color("black") + surface = pygame.Surface((3, 4)) + pos = (1, 1) + kwargs = { + "surface": surface, + "color": None, + "closed": False, + "points": (pos, (2, 1)), + "width": 3, + } + greens = ( + (0, 255, 0), + (0, 255, 0, 255), + surface.map_rgb(green_color), + green_color, + ) + + for color in greens: + surface.fill(surface_color) # Clear for each test. + kwargs["color"] = color + + if isinstance(color, int): + expected_color = surface.unmap_rgb(color) + else: + expected_color = green_color + + bounds_rect = self.draw_lines(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_lines__invalid_color_formats(self): + """Ensures draw lines handles invalid color formats correctly.""" + kwargs = { + "surface": pygame.Surface((4, 3)), + "color": None, + "closed": False, + "points": ((1, 1), (1, 2)), + "width": 1, + } + + for expected_color in (2.3, self): + kwargs["color"] = expected_color + + with self.assertRaises(TypeError): + bounds_rect = self.draw_lines(**kwargs) + + def test_lines__color(self): + """Tests if the lines drawn are the correct color. + + Draws lines around the border of the given surface and checks if all + borders of the surface only contain the given color. + """ + for surface in self._create_surfaces(): + for expected_color in self.COLORS: + self.draw_lines(surface, expected_color, True, corners(surface)) + + for pos, color in border_pos_and_color(surface): + self.assertEqual(color, expected_color, "pos={}".format(pos)) + + def test_lines__color_with_thickness(self): + """Ensures thick lines are drawn using the correct color.""" + x_left = y_top = 5 + for surface in self._create_surfaces(): + x_right = surface.get_width() - 5 + y_bottom = surface.get_height() - 5 + endpoints = ( + (x_left, y_top), + (x_right, y_top), + (x_right, y_bottom), + (x_left, y_bottom), + ) + for expected_color in self.COLORS: + self.draw_lines(surface, expected_color, True, endpoints, 3) + + for t in (-1, 0, 1): + for x in range(x_left, x_right + 1): + for y in (y_top, y_bottom): + pos = (x, y + t) + self.assertEqual( + surface.get_at(pos), + expected_color, + "pos={}".format(pos), + ) + for y in range(y_top, y_bottom + 1): + for x in (x_left, x_right): + pos = (x + t, y) + self.assertEqual( + surface.get_at(pos), + expected_color, + "pos={}".format(pos), + ) + + def test_lines__gaps(self): + """Tests if the lines drawn contain any gaps. + + Draws lines around the border of the given surface and checks if + all borders of the surface contain any gaps. + """ + expected_color = (255, 255, 255) + for surface in self._create_surfaces(): + self.draw_lines(surface, expected_color, True, corners(surface)) + + for pos, color in border_pos_and_color(surface): + self.assertEqual(color, expected_color, "pos={}".format(pos)) + + def test_lines__gaps_with_thickness(self): + """Ensures thick lines are drawn without any gaps.""" + expected_color = (255, 255, 255) + x_left = y_top = 5 + for surface in self._create_surfaces(): + h = (surface.get_width() - 11) // 5 + w = h * 5 + x_right = x_left + w + y_bottom = y_top + h + endpoints = ((x_left, y_top), (x_right, y_top), (x_right, y_bottom)) + self.draw_lines(surface, expected_color, True, endpoints, 3) + + for x in range(x_left, x_right + 1): + for t in (-1, 0, 1): + pos = (x, y_top + t) + self.assertEqual( + surface.get_at(pos), expected_color, "pos={}".format(pos) + ) + pos = (x, y_top + t + ((x - 3) // 5)) + self.assertEqual( + surface.get_at(pos), expected_color, "pos={}".format(pos) + ) + for y in range(y_top, y_bottom + 1): + for t in (-1, 0, 1): + pos = (x_right + t, y) + self.assertEqual( + surface.get_at(pos), expected_color, "pos={}".format(pos) + ) + + def test_lines__bounding_rect(self): + """Ensures draw lines returns the correct bounding rect. + + Tests lines with endpoints on and off the surface and a range of + width/thickness values. + """ + line_color = pygame.Color("red") + surf_color = pygame.Color("black") + width = height = 30 + # Using a rect to help manage where the lines are drawn. + pos_rect = pygame.Rect((0, 0), (width, height)) + + # Testing surfaces of different sizes. One larger than the pos_rect + # and one smaller (to test lines that span the surface). + for size in ((width + 5, height + 5), (width - 5, height - 5)): + surface = pygame.Surface(size, 0, 32) + surf_rect = surface.get_rect() + + # Move pos_rect to different positions to test line endpoints on + # and off the surface. + for pos in rect_corners_mids_and_center(surf_rect): + pos_rect.center = pos + # Shape: Triangle (if closed), ^ caret (if not closed). + pts = (pos_rect.midleft, pos_rect.midtop, pos_rect.midright) + pos = pts[0] # Rect position if nothing drawn. + + # Draw using different thickness and closed values. + for thickness in range(-1, 5): + for closed in (True, False): + surface.fill(surf_color) # Clear for each test. + + bounding_rect = self.draw_lines( + surface, line_color, closed, pts, thickness + ) + + if 0 < thickness: + # Calculating the expected_rect after the lines are + # drawn (it uses what is actually drawn). + expected_rect = create_bounding_rect( + surface, surf_color, pos + ) + else: + # Nothing drawn. + expected_rect = pygame.Rect(pos, (0, 0)) + + self.assertEqual(bounding_rect, expected_rect) + + def test_lines__surface_clip(self): + """Ensures draw lines respects a surface's clip area.""" + surfw = surfh = 30 + line_color = pygame.Color("red") + surface_color = pygame.Color("green") + surface = pygame.Surface((surfw, surfh)) + surface.fill(surface_color) + + clip_rect = pygame.Rect((0, 0), (11, 11)) + clip_rect.center = surface.get_rect().center + pos_rect = clip_rect.copy() # Manages the lines's pos. + + # Test centering the pos_rect along the clip rect's edge to allow for + # drawing the lines over the clip_rect's bounds. + for center in rect_corners_mids_and_center(clip_rect): + pos_rect.center = center + pts = (pos_rect.midtop, pos_rect.center, pos_rect.midbottom) + + for closed in (True, False): # Test closed and not closed. + for thickness in (1, 3): # Test different line widths. + # Get the expected points by drawing the lines without the + # clip area set. + surface.set_clip(None) + surface.fill(surface_color) + self.draw_lines(surface, line_color, closed, pts, thickness) + expected_pts = get_color_points(surface, line_color, clip_rect) + + # Clear the surface and set the clip area. Redraw the lines + # and check that only the clip area is modified. + surface.fill(surface_color) + surface.set_clip(clip_rect) + + self.draw_lines(surface, line_color, closed, pts, thickness) + + surface.lock() # For possible speed up. + + # Check all the surface points to ensure only the + # expected_pts are the line_color. + for pt in ((x, y) for x in range(surfw) for y in range(surfh)): + if pt in expected_pts: + expected_color = line_color + else: + expected_color = surface_color + + self.assertEqual(surface.get_at(pt), expected_color, pt) + + surface.unlock() + + +# Commented out to avoid cluttering the test output. Add back in if draw_py +# ever fully supports drawing lines. +# class PythonDrawLinesTest(LinesMixin, PythonDrawTestCase): +# """Test draw_py module function lines. +# +# This class inherits the general tests from LinesMixin. It is also the +# class to add any draw_py.draw_lines specific tests to. +# """ + + +class DrawLinesTest(LinesMixin, DrawTestCase): + """Test draw module function lines. + + This class inherits the general tests from LinesMixin. It is also the class + to add any draw.lines specific tests to. + """ + + +### AALine Testing ############################################################ + + +class AALineMixin(BaseLineMixin): + """Mixin test for drawing a single aaline. + + This class contains all the general single aaline drawing tests. + """ + + def test_aaline__args(self): + """Ensures draw aaline accepts the correct args.""" + bounds_rect = self.draw_aaline( + pygame.Surface((3, 3)), (0, 10, 0, 50), (0, 0), (1, 1), 1 + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_aaline__args_without_blend(self): + """Ensures draw aaline accepts the args without a blend.""" + bounds_rect = self.draw_aaline( + pygame.Surface((2, 2)), (0, 0, 0, 50), (0, 0), (2, 2) + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_aaline__blend_warning(self): + """From pygame 2, blend=False should raise DeprecationWarning.""" + with warnings.catch_warnings(record=True) as w: + # Cause all warnings to always be triggered. + warnings.simplefilter("always") + # Trigger DeprecationWarning. + self.draw_aaline( + pygame.Surface((2, 2)), (0, 0, 0, 50), (0, 0), (2, 2), False + ) + # Check if there is only one warning and is a DeprecationWarning. + self.assertEqual(len(w), 1) + self.assertTrue(issubclass(w[-1].category, DeprecationWarning)) + + def test_aaline__kwargs(self): + """Ensures draw aaline accepts the correct kwargs + with and without a blend arg. + """ + surface = pygame.Surface((4, 4)) + color = pygame.Color("yellow") + start_pos = (1, 1) + end_pos = (2, 2) + kwargs_list = [ + { + "surface": surface, + "color": color, + "start_pos": start_pos, + "end_pos": end_pos, + "blend": 1, + }, + { + "surface": surface, + "color": color, + "start_pos": start_pos, + "end_pos": end_pos, + }, + ] + + for kwargs in kwargs_list: + bounds_rect = self.draw_aaline(**kwargs) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_aaline__kwargs_order_independent(self): + """Ensures draw aaline's kwargs are not order dependent.""" + bounds_rect = self.draw_aaline( + start_pos=(1, 2), + end_pos=(2, 1), + blend=1, + color=(10, 20, 30), + surface=pygame.Surface((3, 2)), + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_aaline__args_missing(self): + """Ensures draw aaline detects any missing required args.""" + surface = pygame.Surface((1, 1)) + color = pygame.Color("blue") + + with self.assertRaises(TypeError): + bounds_rect = self.draw_aaline(surface, color, (0, 0)) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_aaline(surface, color) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_aaline(surface) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_aaline() + + def test_aaline__kwargs_missing(self): + """Ensures draw aaline detects any missing required kwargs.""" + kwargs = { + "surface": pygame.Surface((3, 2)), + "color": pygame.Color("red"), + "start_pos": (2, 1), + "end_pos": (2, 2), + "blend": 1, + } + + for name in ("end_pos", "start_pos", "color", "surface"): + invalid_kwargs = dict(kwargs) + invalid_kwargs.pop(name) # Pop from a copy. + + with self.assertRaises(TypeError): + bounds_rect = self.draw_aaline(**invalid_kwargs) + + def test_aaline__arg_invalid_types(self): + """Ensures draw aaline detects invalid arg types.""" + surface = pygame.Surface((2, 2)) + color = pygame.Color("blue") + start_pos = (0, 1) + end_pos = (1, 2) + + with self.assertRaises(TypeError): + # Invalid blend. + bounds_rect = self.draw_aaline(surface, color, start_pos, end_pos, "1") + + with self.assertRaises(TypeError): + # Invalid end_pos. + bounds_rect = self.draw_aaline(surface, color, start_pos, (1, 2, 3)) + + with self.assertRaises(TypeError): + # Invalid start_pos. + bounds_rect = self.draw_aaline(surface, color, (1,), end_pos) + + with self.assertRaises(ValueError): + # Invalid color. + bounds_rect = self.draw_aaline(surface, "invalid-color", start_pos, end_pos) + + with self.assertRaises(TypeError): + # Invalid surface. + bounds_rect = self.draw_aaline((1, 2, 3, 4), color, start_pos, end_pos) + + def test_aaline__kwarg_invalid_types(self): + """Ensures draw aaline detects invalid kwarg types.""" + surface = pygame.Surface((3, 3)) + color = pygame.Color("green") + start_pos = (1, 0) + end_pos = (2, 0) + blend = 1 + kwargs_list = [ + { + "surface": pygame.Surface, # Invalid surface. + "color": color, + "start_pos": start_pos, + "end_pos": end_pos, + "blend": blend, + }, + { + "surface": surface, + "color": 2.3, # Invalid color. + "start_pos": start_pos, + "end_pos": end_pos, + "blend": blend, + }, + { + "surface": surface, + "color": color, + "start_pos": (0, 0, 0), # Invalid start_pos. + "end_pos": end_pos, + "blend": blend, + }, + { + "surface": surface, + "color": color, + "start_pos": start_pos, + "end_pos": (0,), # Invalid end_pos. + "blend": blend, + }, + { + "surface": surface, + "color": color, + "start_pos": start_pos, + "end_pos": end_pos, + "blend": 1.2, + }, + ] # Invalid blend. + + for kwargs in kwargs_list: + with self.assertRaises(TypeError): + bounds_rect = self.draw_aaline(**kwargs) + + def test_aaline__kwarg_invalid_name(self): + """Ensures draw aaline detects invalid kwarg names.""" + surface = pygame.Surface((2, 3)) + color = pygame.Color("cyan") + start_pos = (1, 1) + end_pos = (2, 0) + kwargs_list = [ + { + "surface": surface, + "color": color, + "start_pos": start_pos, + "end_pos": end_pos, + "blend": 1, + "invalid": 1, + }, + { + "surface": surface, + "color": color, + "start_pos": start_pos, + "end_pos": end_pos, + "invalid": 1, + }, + ] + + for kwargs in kwargs_list: + with self.assertRaises(TypeError): + bounds_rect = self.draw_aaline(**kwargs) + + def test_aaline__args_and_kwargs(self): + """Ensures draw aaline accepts a combination of args/kwargs""" + surface = pygame.Surface((3, 2)) + color = (255, 255, 0, 0) + start_pos = (0, 1) + end_pos = (1, 2) + blend = 0 + kwargs = { + "surface": surface, + "color": color, + "start_pos": start_pos, + "end_pos": end_pos, + "blend": blend, + } + + for name in ("surface", "color", "start_pos", "end_pos", "blend"): + kwargs.pop(name) + + if "surface" == name: + bounds_rect = self.draw_aaline(surface, **kwargs) + elif "color" == name: + bounds_rect = self.draw_aaline(surface, color, **kwargs) + elif "start_pos" == name: + bounds_rect = self.draw_aaline(surface, color, start_pos, **kwargs) + elif "end_pos" == name: + bounds_rect = self.draw_aaline( + surface, color, start_pos, end_pos, **kwargs + ) + else: + bounds_rect = self.draw_aaline( + surface, color, start_pos, end_pos, blend, **kwargs + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_aaline__valid_blend_values(self): + """Ensures draw aaline accepts different blend values.""" + expected_color = pygame.Color("yellow") + surface_color = pygame.Color("white") + surface = pygame.Surface((3, 4)) + pos = (2, 1) + kwargs = { + "surface": surface, + "color": expected_color, + "start_pos": pos, + "end_pos": (2, 2), + "blend": None, + } + + for blend in (-10, -2, -1, 0, 1, 2, 10): + surface.fill(surface_color) # Clear for each test. + kwargs["blend"] = blend + + bounds_rect = self.draw_aaline(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_aaline__valid_start_pos_formats(self): + """Ensures draw aaline accepts different start_pos formats.""" + expected_color = pygame.Color("red") + surface_color = pygame.Color("black") + surface = pygame.Surface((4, 4)) + kwargs = { + "surface": surface, + "color": expected_color, + "start_pos": None, + "end_pos": (2, 2), + "blend": 0, + } + x, y = 2, 1 # start position + positions = ((x, y), (x + 0.01, y), (x, y + 0.01), (x + 0.01, y + 0.01)) + + for start_pos in positions: + for seq_type in (tuple, list, Vector2): + surface.fill(surface_color) # Clear for each test. + kwargs["start_pos"] = seq_type(start_pos) + + bounds_rect = self.draw_aaline(**kwargs) + + color = surface.get_at((x, y)) + for i, sub_color in enumerate(expected_color): + # The color could be slightly off the expected color due to + # any fractional position arguments. + self.assertGreaterEqual(color[i] + 6, sub_color, start_pos) + self.assertIsInstance(bounds_rect, pygame.Rect, start_pos) + + def test_aaline__valid_end_pos_formats(self): + """Ensures draw aaline accepts different end_pos formats.""" + expected_color = pygame.Color("red") + surface_color = pygame.Color("black") + surface = pygame.Surface((4, 4)) + kwargs = { + "surface": surface, + "color": expected_color, + "start_pos": (2, 1), + "end_pos": None, + "blend": 0, + } + x, y = 2, 2 # end position + positions = ((x, y), (x + 0.02, y), (x, y + 0.02), (x + 0.02, y + 0.02)) + + for end_pos in positions: + for seq_type in (tuple, list, Vector2): + surface.fill(surface_color) # Clear for each test. + kwargs["end_pos"] = seq_type(end_pos) + + bounds_rect = self.draw_aaline(**kwargs) + + color = surface.get_at((x, y)) + for i, sub_color in enumerate(expected_color): + # The color could be slightly off the expected color due to + # any fractional position arguments. + self.assertGreaterEqual(color[i] + 15, sub_color, end_pos) + self.assertIsInstance(bounds_rect, pygame.Rect, end_pos) + + def test_aaline__invalid_start_pos_formats(self): + """Ensures draw aaline handles invalid start_pos formats correctly.""" + kwargs = { + "surface": pygame.Surface((4, 4)), + "color": pygame.Color("red"), + "start_pos": None, + "end_pos": (2, 2), + "blend": 0, + } + + start_pos_fmts = ( + (2,), # Too few coords. + (2, 1, 0), # Too many coords. + (2, "1"), # Wrong type. + set([2, 1]), # Wrong type. + dict(((2, 1),)), + ) # Wrong type. + + for start_pos in start_pos_fmts: + kwargs["start_pos"] = start_pos + + with self.assertRaises(TypeError): + bounds_rect = self.draw_aaline(**kwargs) + + def test_aaline__invalid_end_pos_formats(self): + """Ensures draw aaline handles invalid end_pos formats correctly.""" + kwargs = { + "surface": pygame.Surface((4, 4)), + "color": pygame.Color("red"), + "start_pos": (2, 2), + "end_pos": None, + "blend": 0, + } + + end_pos_fmts = ( + (2,), # Too few coords. + (2, 1, 0), # Too many coords. + (2, "1"), # Wrong type. + set([2, 1]), # Wrong type. + dict(((2, 1),)), + ) # Wrong type. + + for end_pos in end_pos_fmts: + kwargs["end_pos"] = end_pos + + with self.assertRaises(TypeError): + bounds_rect = self.draw_aaline(**kwargs) + + def test_aaline__valid_color_formats(self): + """Ensures draw aaline accepts different color formats.""" + green_color = pygame.Color("green") + surface_color = pygame.Color("black") + surface = pygame.Surface((3, 4)) + pos = (1, 1) + kwargs = { + "surface": surface, + "color": None, + "start_pos": pos, + "end_pos": (2, 1), + "blend": 0, + } + greens = ( + (0, 255, 0), + (0, 255, 0, 255), + surface.map_rgb(green_color), + green_color, + ) + + for color in greens: + surface.fill(surface_color) # Clear for each test. + kwargs["color"] = color + + if isinstance(color, int): + expected_color = surface.unmap_rgb(color) + else: + expected_color = green_color + + bounds_rect = self.draw_aaline(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_aaline__invalid_color_formats(self): + """Ensures draw aaline handles invalid color formats correctly.""" + kwargs = { + "surface": pygame.Surface((4, 3)), + "color": None, + "start_pos": (1, 1), + "end_pos": (2, 1), + "blend": 0, + } + + for expected_color in (2.3, self): + kwargs["color"] = expected_color + + with self.assertRaises(TypeError): + bounds_rect = self.draw_aaline(**kwargs) + + def test_aaline__color(self): + """Tests if the aaline drawn is the correct color.""" + pos = (0, 0) + for surface in self._create_surfaces(): + for expected_color in self.COLORS: + self.draw_aaline(surface, expected_color, pos, (1, 0)) + + self.assertEqual( + surface.get_at(pos), expected_color, "pos={}".format(pos) + ) + + def test_aaline__gaps(self): + """Tests if the aaline drawn contains any gaps. + + See: #512 + """ + expected_color = (255, 255, 255) + for surface in self._create_surfaces(): + width = surface.get_width() + self.draw_aaline(surface, expected_color, (0, 0), (width - 1, 0)) + + for x in range(width): + pos = (x, 0) + self.assertEqual( + surface.get_at(pos), expected_color, "pos={}".format(pos) + ) + + def test_aaline__bounding_rect(self): + """Ensures draw aaline returns the correct bounding rect. + + Tests lines with endpoints on and off the surface and blending + enabled and disabled. + """ + line_color = pygame.Color("red") + surf_color = pygame.Color("blue") + width = height = 30 + # Using a rect to help manage where the lines are drawn. + helper_rect = pygame.Rect((0, 0), (width, height)) + + # Testing surfaces of different sizes. One larger than the helper_rect + # and one smaller (to test lines that span the surface). + for size in ((width + 5, height + 5), (width - 5, height - 5)): + surface = pygame.Surface(size, 0, 32) + surf_rect = surface.get_rect() + + # Move the helper rect to different positions to test line + # endpoints on and off the surface. + for pos in rect_corners_mids_and_center(surf_rect): + helper_rect.center = pos + + for blend in (False, True): # Test non-blending and blending. + for start, end in self._rect_lines(helper_rect): + surface.fill(surf_color) # Clear for each test. + + bounding_rect = self.draw_aaline( + surface, line_color, start, end, blend + ) + + # Calculating the expected_rect after the line is + # drawn (it uses what is actually drawn). + expected_rect = create_bounding_rect(surface, surf_color, start) + + self.assertEqual(bounding_rect, expected_rect) + + def test_aaline__surface_clip(self): + """Ensures draw aaline respects a surface's clip area.""" + surfw = surfh = 30 + aaline_color = pygame.Color("red") + surface_color = pygame.Color("green") + surface = pygame.Surface((surfw, surfh)) + surface.fill(surface_color) + + clip_rect = pygame.Rect((0, 0), (11, 11)) + clip_rect.center = surface.get_rect().center + pos_rect = clip_rect.copy() # Manages the aaline's pos. + + # Test centering the pos_rect along the clip rect's edge to allow for + # drawing the aaline over the clip_rect's bounds. + for center in rect_corners_mids_and_center(clip_rect): + pos_rect.center = center + + for blend in (0, 1): # Test non-blending and blending. + # Get the expected points by drawing the aaline without the + # clip area set. + surface.set_clip(None) + surface.fill(surface_color) + self.draw_aaline( + surface, aaline_color, pos_rect.midtop, pos_rect.midbottom, blend + ) + + # Need to get the points that are NOT surface_color due to the + # way blend=0 uses the color black to antialias. + expected_pts = get_color_points( + surface, surface_color, clip_rect, False + ) + + # Clear the surface and set the clip area. Redraw the aaline + # and check that only the clip area is modified. + surface.fill(surface_color) + surface.set_clip(clip_rect) + + self.draw_aaline( + surface, aaline_color, pos_rect.midtop, pos_rect.midbottom, blend + ) + + surface.lock() # For possible speed up. + + # Check all the surface points to ensure the expected_pts + # are not surface_color. + for pt in ((x, y) for x in range(surfw) for y in range(surfh)): + if pt in expected_pts: + self.assertNotEqual(surface.get_at(pt), surface_color, pt) + else: + self.assertEqual(surface.get_at(pt), surface_color, pt) + + surface.unlock() + + +# Commented out to avoid cluttering the test output. Add back in if draw_py +# ever fully supports drawing single aalines. +# class PythonDrawAALineTest(AALineMixin, PythonDrawTestCase): +# """Test draw_py module function aaline. +# +# This class inherits the general tests from AALineMixin. It is also the +# class to add any draw_py.draw_aaline specific tests to. +# """ + + +class DrawAALineTest(AALineMixin, DrawTestCase): + """Test draw module function aaline. + + This class inherits the general tests from AALineMixin. It is also the + class to add any draw.aaline specific tests to. + """ + + def test_aaline_endianness(self): + """test color component order""" + for depth in (24, 32): + surface = pygame.Surface((5, 3), 0, depth) + surface.fill(pygame.Color(0, 0, 0)) + self.draw_aaline(surface, pygame.Color(255, 0, 0), (0, 1), (2, 1), 1) + + self.assertGreater(surface.get_at((1, 1)).r, 0, "there should be red here") + + surface.fill(pygame.Color(0, 0, 0)) + self.draw_aaline(surface, pygame.Color(0, 0, 255), (0, 1), (2, 1), 1) + + self.assertGreater(surface.get_at((1, 1)).b, 0, "there should be blue here") + + def _check_antialiasing( + self, from_point, to_point, should, check_points, set_endpoints=True + ): + """Draw a line between two points and check colors of check_points.""" + if set_endpoints: + should[from_point] = should[to_point] = FG_GREEN + + def check_one_direction(from_point, to_point, should): + self.draw_aaline(self.surface, FG_GREEN, from_point, to_point, True) + + for pt in check_points: + color = should.get(pt, BG_RED) + with self.subTest(from_pt=from_point, pt=pt, to=to_point): + self.assertEqual(self.surface.get_at(pt), color) + + # reset + draw.rect(self.surface, BG_RED, (0, 0, 10, 10), 0) + + # it is important to test also opposite direction, the algorithm + # is (#512) or was not symmetric + check_one_direction(from_point, to_point, should) + if from_point != to_point: + check_one_direction(to_point, from_point, should) + + def test_short_non_antialiased_lines(self): + """test very short not anti aliased lines in all directions.""" + + # Horizontal, vertical and diagonal lines should not be anti-aliased, + # even with draw.aaline ... + self.surface = pygame.Surface((10, 10)) + draw.rect(self.surface, BG_RED, (0, 0, 10, 10), 0) + + check_points = [(i, j) for i in range(3, 8) for j in range(3, 8)] + + def check_both_directions(from_pt, to_pt, other_points): + should = {pt: FG_GREEN for pt in other_points} + self._check_antialiasing(from_pt, to_pt, should, check_points) + + # 0. one point + check_both_directions((5, 5), (5, 5), []) + # 1. horizontal + check_both_directions((4, 7), (5, 7), []) + check_both_directions((5, 4), (7, 4), [(6, 4)]) + + # 2. vertical + check_both_directions((5, 5), (5, 6), []) + check_both_directions((6, 4), (6, 6), [(6, 5)]) + # 3. diagonals + check_both_directions((5, 5), (6, 6), []) + check_both_directions((5, 5), (7, 7), [(6, 6)]) + check_both_directions((5, 6), (6, 5), []) + check_both_directions((6, 4), (4, 6), [(5, 5)]) + + def test_short_line_anti_aliasing(self): + + self.surface = pygame.Surface((10, 10)) + draw.rect(self.surface, BG_RED, (0, 0, 10, 10), 0) + + check_points = [(i, j) for i in range(3, 8) for j in range(3, 8)] + + def check_both_directions(from_pt, to_pt, should): + self._check_antialiasing(from_pt, to_pt, should, check_points) + + brown = (127, 127, 0) + reddish = (191, 63, 0) + greenish = (63, 191, 0) + + # lets say dx = abs(x0 - x1) ; dy = abs(y0 - y1) + + # dy / dx = 0.5 + check_both_directions((4, 4), (6, 5), {(5, 4): brown, (5, 5): brown}) + check_both_directions((4, 5), (6, 4), {(5, 4): brown, (5, 5): brown}) + + # dy / dx = 2 + check_both_directions((4, 4), (5, 6), {(4, 5): brown, (5, 5): brown}) + check_both_directions((5, 4), (4, 6), {(4, 5): brown, (5, 5): brown}) + + # some little longer lines; so we need to check more points: + check_points = [(i, j) for i in range(2, 9) for j in range(2, 9)] + # dy / dx = 0.25 + should = { + (4, 3): greenish, + (5, 3): brown, + (6, 3): reddish, + (4, 4): reddish, + (5, 4): brown, + (6, 4): greenish, + } + check_both_directions((3, 3), (7, 4), should) + + should = { + (4, 3): reddish, + (5, 3): brown, + (6, 3): greenish, + (4, 4): greenish, + (5, 4): brown, + (6, 4): reddish, + } + check_both_directions((3, 4), (7, 3), should) + + # dy / dx = 4 + should = { + (4, 4): greenish, + (4, 5): brown, + (4, 6): reddish, + (5, 4): reddish, + (5, 5): brown, + (5, 6): greenish, + } + check_both_directions((4, 3), (5, 7), should) + + should = { + (4, 4): reddish, + (4, 5): brown, + (4, 6): greenish, + (5, 4): greenish, + (5, 5): brown, + (5, 6): reddish, + } + check_both_directions((5, 3), (4, 7), should) + + def test_anti_aliasing_float_coordinates(self): + """Float coordinates should be blended smoothly.""" + + self.surface = pygame.Surface((10, 10)) + draw.rect(self.surface, BG_RED, (0, 0, 10, 10), 0) + + check_points = [(i, j) for i in range(5) for j in range(5)] + brown = (127, 127, 0) + reddish = (191, 63, 0) + greenish = (63, 191, 0) + + # 0. identical point : current implementation does no smoothing... + expected = {(2, 2): FG_GREEN} + self._check_antialiasing( + (1.5, 2), (1.5, 2), expected, check_points, set_endpoints=False + ) + expected = {(2, 3): FG_GREEN} + self._check_antialiasing( + (2.49, 2.7), (2.49, 2.7), expected, check_points, set_endpoints=False + ) + + # 1. horizontal lines + # a) blend endpoints + expected = {(1, 2): brown, (2, 2): FG_GREEN} + self._check_antialiasing( + (1.5, 2), (2, 2), expected, check_points, set_endpoints=False + ) + expected = {(1, 2): brown, (2, 2): FG_GREEN, (3, 2): brown} + self._check_antialiasing( + (1.5, 2), (2.5, 2), expected, check_points, set_endpoints=False + ) + expected = {(2, 2): brown, (1, 2): FG_GREEN} + self._check_antialiasing( + (1, 2), (1.5, 2), expected, check_points, set_endpoints=False + ) + expected = {(1, 2): brown, (2, 2): greenish} + self._check_antialiasing( + (1.5, 2), (1.75, 2), expected, check_points, set_endpoints=False + ) + + # b) blend y-coordinate + expected = {(x, y): brown for x in range(2, 5) for y in (1, 2)} + self._check_antialiasing( + (2, 1.5), (4, 1.5), expected, check_points, set_endpoints=False + ) + + # 2. vertical lines + # a) blend endpoints + expected = {(2, 1): brown, (2, 2): FG_GREEN, (2, 3): brown} + self._check_antialiasing( + (2, 1.5), (2, 2.5), expected, check_points, set_endpoints=False + ) + expected = {(2, 1): brown, (2, 2): greenish} + self._check_antialiasing( + (2, 1.5), (2, 1.75), expected, check_points, set_endpoints=False + ) + # b) blend x-coordinate + expected = {(x, y): brown for x in (1, 2) for y in range(2, 5)} + self._check_antialiasing( + (1.5, 2), (1.5, 4), expected, check_points, set_endpoints=False + ) + # 3. diagonal lines + # a) blend endpoints + expected = {(1, 1): brown, (2, 2): FG_GREEN, (3, 3): brown} + self._check_antialiasing( + (1.5, 1.5), (2.5, 2.5), expected, check_points, set_endpoints=False + ) + expected = {(3, 1): brown, (2, 2): FG_GREEN, (1, 3): brown} + self._check_antialiasing( + (2.5, 1.5), (1.5, 2.5), expected, check_points, set_endpoints=False + ) + # b) blend sidewards + expected = {(2, 1): brown, (2, 2): brown, (3, 2): brown, (3, 3): brown} + self._check_antialiasing( + (2, 1.5), (3, 2.5), expected, check_points, set_endpoints=False + ) + + expected = { + (2, 1): greenish, + (2, 2): reddish, + (3, 2): greenish, + (3, 3): reddish, + (4, 3): greenish, + (4, 4): reddish, + } + + self._check_antialiasing( + (2, 1.25), (4, 3.25), expected, check_points, set_endpoints=False + ) + + def test_anti_aliasing_at_and_outside_the_border(self): + """Ensures antialiasing works correct at a surface's borders.""" + + self.surface = pygame.Surface((10, 10)) + draw.rect(self.surface, BG_RED, (0, 0, 10, 10), 0) + + check_points = [(i, j) for i in range(10) for j in range(10)] + + reddish = (191, 63, 0) + brown = (127, 127, 0) + greenish = (63, 191, 0) + from_point, to_point = (3, 3), (7, 4) + should = { + (4, 3): greenish, + (5, 3): brown, + (6, 3): reddish, + (4, 4): reddish, + (5, 4): brown, + (6, 4): greenish, + } + + for dx, dy in ( + (-4, 0), + (4, 0), # moved to left and right borders + (0, -5), + (0, -4), + (0, -3), # upper border + (0, 5), + (0, 6), + (0, 7), # lower border + (-4, -4), + (-4, -3), + (-3, -4), + ): # upper left corner + first = from_point[0] + dx, from_point[1] + dy + second = to_point[0] + dx, to_point[1] + dy + expected = {(x + dx, y + dy): color for (x, y), color in should.items()} + + self._check_antialiasing(first, second, expected, check_points) + + +### AALines Testing ########################################################### + + +class AALinesMixin(BaseLineMixin): + """Mixin test for drawing aalines. + + This class contains all the general aalines drawing tests. + """ + + def test_aalines__args(self): + """Ensures draw aalines accepts the correct args.""" + bounds_rect = self.draw_aalines( + pygame.Surface((3, 3)), (0, 10, 0, 50), False, ((0, 0), (1, 1)), 1 + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_aalines__args_without_blend(self): + """Ensures draw aalines accepts the args without a blend.""" + bounds_rect = self.draw_aalines( + pygame.Surface((2, 2)), (0, 0, 0, 50), False, ((0, 0), (1, 1)) + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_aalines__blend_warning(self): + """From pygame 2, blend=False should raise DeprecationWarning.""" + with warnings.catch_warnings(record=True) as w: + # Cause all warnings to always be triggered. + warnings.simplefilter("always") + # Trigger DeprecationWarning. + self.draw_aalines( + pygame.Surface((2, 2)), (0, 0, 0, 50), False, ((0, 0), (1, 1)), False + ) + # Check if there is only one warning and is a DeprecationWarning. + self.assertEqual(len(w), 1) + self.assertTrue(issubclass(w[-1].category, DeprecationWarning)) + + def test_aalines__kwargs(self): + """Ensures draw aalines accepts the correct kwargs + with and without a blend arg. + """ + surface = pygame.Surface((4, 4)) + color = pygame.Color("yellow") + points = ((0, 0), (1, 1), (2, 2)) + kwargs_list = [ + { + "surface": surface, + "color": color, + "closed": False, + "points": points, + "blend": 1, + }, + {"surface": surface, "color": color, "closed": False, "points": points}, + ] + + for kwargs in kwargs_list: + bounds_rect = self.draw_aalines(**kwargs) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_aalines__kwargs_order_independent(self): + """Ensures draw aalines's kwargs are not order dependent.""" + bounds_rect = self.draw_aalines( + closed=1, + points=((0, 0), (1, 1), (2, 2)), + blend=1, + color=(10, 20, 30), + surface=pygame.Surface((3, 2)), + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_aalines__args_missing(self): + """Ensures draw aalines detects any missing required args.""" + surface = pygame.Surface((1, 1)) + color = pygame.Color("blue") + + with self.assertRaises(TypeError): + bounds_rect = self.draw_aalines(surface, color, 0) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_aalines(surface, color) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_aalines(surface) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_aalines() + + def test_aalines__kwargs_missing(self): + """Ensures draw aalines detects any missing required kwargs.""" + kwargs = { + "surface": pygame.Surface((3, 2)), + "color": pygame.Color("red"), + "closed": 1, + "points": ((2, 2), (1, 1)), + "blend": 1, + } + + for name in ("points", "closed", "color", "surface"): + invalid_kwargs = dict(kwargs) + invalid_kwargs.pop(name) # Pop from a copy. + + with self.assertRaises(TypeError): + bounds_rect = self.draw_aalines(**invalid_kwargs) + + def test_aalines__arg_invalid_types(self): + """Ensures draw aalines detects invalid arg types.""" + surface = pygame.Surface((2, 2)) + color = pygame.Color("blue") + closed = 0 + points = ((1, 2), (2, 1)) + + with self.assertRaises(TypeError): + # Invalid blend. + bounds_rect = self.draw_aalines(surface, color, closed, points, "1") + + with self.assertRaises(TypeError): + # Invalid points. + bounds_rect = self.draw_aalines(surface, color, closed, (1, 2, 3)) + + with self.assertRaises(TypeError): + # Invalid closed. + bounds_rect = self.draw_aalines(surface, color, InvalidBool(), points) + + with self.assertRaises(TypeError): + # Invalid color. + bounds_rect = self.draw_aalines(surface, 2.3, closed, points) + + with self.assertRaises(TypeError): + # Invalid surface. + bounds_rect = self.draw_aalines((1, 2, 3, 4), color, closed, points) + + def test_aalines__kwarg_invalid_types(self): + """Ensures draw aalines detects invalid kwarg types.""" + valid_kwargs = { + "surface": pygame.Surface((3, 3)), + "color": pygame.Color("green"), + "closed": False, + "points": ((1, 2), (2, 1)), + "blend": 1, + } + + invalid_kwargs = { + "surface": pygame.Surface, + "color": 2.3, + "closed": InvalidBool(), + "points": (0, 0, 0), + "blend": 1.2, + } + + for kwarg in ("surface", "color", "closed", "points", "blend"): + kwargs = dict(valid_kwargs) + kwargs[kwarg] = invalid_kwargs[kwarg] + + with self.assertRaises(TypeError): + bounds_rect = self.draw_aalines(**kwargs) + + def test_aalines__kwarg_invalid_name(self): + """Ensures draw aalines detects invalid kwarg names.""" + surface = pygame.Surface((2, 3)) + color = pygame.Color("cyan") + closed = 1 + points = ((1, 2), (2, 1)) + kwargs_list = [ + { + "surface": surface, + "color": color, + "closed": closed, + "points": points, + "blend": 1, + "invalid": 1, + }, + { + "surface": surface, + "color": color, + "closed": closed, + "points": points, + "invalid": 1, + }, + ] + + for kwargs in kwargs_list: + with self.assertRaises(TypeError): + bounds_rect = self.draw_aalines(**kwargs) + + def test_aalines__args_and_kwargs(self): + """Ensures draw aalines accepts a combination of args/kwargs""" + surface = pygame.Surface((3, 2)) + color = (255, 255, 0, 0) + closed = 0 + points = ((1, 2), (2, 1)) + blend = 1 + kwargs = { + "surface": surface, + "color": color, + "closed": closed, + "points": points, + "blend": blend, + } + + for name in ("surface", "color", "closed", "points", "blend"): + kwargs.pop(name) + + if "surface" == name: + bounds_rect = self.draw_aalines(surface, **kwargs) + elif "color" == name: + bounds_rect = self.draw_aalines(surface, color, **kwargs) + elif "closed" == name: + bounds_rect = self.draw_aalines(surface, color, closed, **kwargs) + elif "points" == name: + bounds_rect = self.draw_aalines( + surface, color, closed, points, **kwargs + ) + else: + bounds_rect = self.draw_aalines( + surface, color, closed, points, blend, **kwargs + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_aalines__valid_blend_values(self): + """Ensures draw aalines accepts different blend values.""" + expected_color = pygame.Color("yellow") + surface_color = pygame.Color("white") + surface = pygame.Surface((3, 4)) + pos = (1, 1) + kwargs = { + "surface": surface, + "color": expected_color, + "closed": False, + "points": (pos, (1, 3)), + "blend": None, + } + + for blend in (-10, -2, -1, 0, 1, 2, 10): + surface.fill(surface_color) # Clear for each test. + kwargs["blend"] = blend + + bounds_rect = self.draw_aalines(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color, blend) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_aalines__valid_points_format(self): + """Ensures draw aalines accepts different points formats.""" + expected_color = (10, 20, 30, 255) + surface_color = pygame.Color("white") + surface = pygame.Surface((3, 4)) + kwargs = { + "surface": surface, + "color": expected_color, + "closed": False, + "points": None, + "blend": 0, + } + + # The point type can be a tuple/list/Vector2. + point_types = ( + (tuple, tuple, tuple, tuple), # all tuples + (list, list, list, list), # all lists + (Vector2, Vector2, Vector2, Vector2), # all Vector2s + (list, Vector2, tuple, Vector2), + ) # mix + + # The point values can be ints or floats. + point_values = ( + ((1, 1), (2, 1), (2, 2), (1, 2)), + ((1, 1), (2.2, 1), (2.1, 2.2), (1, 2.1)), + ) + + # Each sequence of points can be a tuple or a list. + seq_types = (tuple, list) + + for point_type in point_types: + for values in point_values: + check_pos = values[0] + points = [point_type[i](pt) for i, pt in enumerate(values)] + + for seq_type in seq_types: + surface.fill(surface_color) # Clear for each test. + kwargs["points"] = seq_type(points) + + bounds_rect = self.draw_aalines(**kwargs) + + self.assertEqual(surface.get_at(check_pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_aalines__invalid_points_formats(self): + """Ensures draw aalines handles invalid points formats correctly.""" + kwargs = { + "surface": pygame.Surface((4, 4)), + "color": pygame.Color("red"), + "closed": False, + "points": None, + "blend": 1, + } + + points_fmts = ( + ((1, 1), (2,)), # Too few coords. + ((1, 1), (2, 2, 2)), # Too many coords. + ((1, 1), (2, "2")), # Wrong type. + ((1, 1), set([2, 3])), # Wrong type. + ((1, 1), dict(((2, 2), (3, 3)))), # Wrong type. + set(((1, 1), (1, 2))), # Wrong type. + dict(((1, 1), (4, 4))), + ) # Wrong type. + + for points in points_fmts: + kwargs["points"] = points + + with self.assertRaises(TypeError): + bounds_rect = self.draw_aalines(**kwargs) + + def test_aalines__invalid_points_values(self): + """Ensures draw aalines handles invalid points values correctly.""" + kwargs = { + "surface": pygame.Surface((4, 4)), + "color": pygame.Color("red"), + "closed": False, + "points": None, + "blend": 1, + } + + for points in ([], ((1, 1),)): # Too few points. + for seq_type in (tuple, list): # Test as tuples and lists. + kwargs["points"] = seq_type(points) + + with self.assertRaises(ValueError): + bounds_rect = self.draw_aalines(**kwargs) + + def test_aalines__valid_closed_values(self): + """Ensures draw aalines accepts different closed values.""" + line_color = pygame.Color("blue") + surface_color = pygame.Color("white") + surface = pygame.Surface((5, 5)) + pos = (1, 3) + kwargs = { + "surface": surface, + "color": line_color, + "closed": None, + "points": ((1, 1), (4, 1), (4, 4), (1, 4)), + "blend": 0, + } + + true_values = (-7, 1, 10, "2", 3.1, (4,), [5], True) + false_values = (None, "", 0, (), [], False) + + for closed in true_values + false_values: + surface.fill(surface_color) # Clear for each test. + kwargs["closed"] = closed + expected_color = line_color if closed else surface_color + + bounds_rect = self.draw_aalines(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_aalines__valid_color_formats(self): + """Ensures draw aalines accepts different color formats.""" + green_color = pygame.Color("green") + surface_color = pygame.Color("black") + surface = pygame.Surface((3, 4)) + pos = (1, 1) + kwargs = { + "surface": surface, + "color": None, + "closed": False, + "points": (pos, (2, 1)), + "blend": 0, + } + greens = ( + (0, 255, 0), + (0, 255, 0, 255), + surface.map_rgb(green_color), + green_color, + ) + + for color in greens: + surface.fill(surface_color) # Clear for each test. + kwargs["color"] = color + + if isinstance(color, int): + expected_color = surface.unmap_rgb(color) + else: + expected_color = green_color + + bounds_rect = self.draw_aalines(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_aalines__invalid_color_formats(self): + """Ensures draw aalines handles invalid color formats correctly.""" + kwargs = { + "surface": pygame.Surface((4, 3)), + "color": None, + "closed": False, + "points": ((1, 1), (1, 2)), + "blend": 0, + } + + for expected_color in (2.3, self): + kwargs["color"] = expected_color + + with self.assertRaises(TypeError): + bounds_rect = self.draw_aalines(**kwargs) + + def test_aalines__color(self): + """Tests if the aalines drawn are the correct color. + + Draws aalines around the border of the given surface and checks if all + borders of the surface only contain the given color. + """ + for surface in self._create_surfaces(): + for expected_color in self.COLORS: + self.draw_aalines(surface, expected_color, True, corners(surface)) + + for pos, color in border_pos_and_color(surface): + self.assertEqual(color, expected_color, "pos={}".format(pos)) + + def test_aalines__gaps(self): + """Tests if the aalines drawn contain any gaps. + + Draws aalines around the border of the given surface and checks if + all borders of the surface contain any gaps. + + See: #512 + """ + expected_color = (255, 255, 255) + for surface in self._create_surfaces(): + self.draw_aalines(surface, expected_color, True, corners(surface)) + + for pos, color in border_pos_and_color(surface): + self.assertEqual(color, expected_color, "pos={}".format(pos)) + + def test_aalines__bounding_rect(self): + """Ensures draw aalines returns the correct bounding rect. + + Tests lines with endpoints on and off the surface and blending + enabled and disabled. + """ + line_color = pygame.Color("red") + surf_color = pygame.Color("blue") + width = height = 30 + # Using a rect to help manage where the lines are drawn. + pos_rect = pygame.Rect((0, 0), (width, height)) + + # Testing surfaces of different sizes. One larger than the pos_rect + # and one smaller (to test lines that span the surface). + for size in ((width + 5, height + 5), (width - 5, height - 5)): + surface = pygame.Surface(size, 0, 32) + surf_rect = surface.get_rect() + + # Move pos_rect to different positions to test line endpoints on + # and off the surface. + for pos in rect_corners_mids_and_center(surf_rect): + pos_rect.center = pos + # Shape: Triangle (if closed), ^ caret (if not closed). + pts = (pos_rect.midleft, pos_rect.midtop, pos_rect.midright) + pos = pts[0] # Rect position if nothing drawn. + + for blend in (False, True): # Test non-blending and blending. + for closed in (True, False): + surface.fill(surf_color) # Clear for each test. + + bounding_rect = self.draw_aalines( + surface, line_color, closed, pts, blend + ) + + # Calculating the expected_rect after the lines are + # drawn (it uses what is actually drawn). + expected_rect = create_bounding_rect(surface, surf_color, pos) + + self.assertEqual(bounding_rect, expected_rect) + + def test_aalines__surface_clip(self): + """Ensures draw aalines respects a surface's clip area.""" + surfw = surfh = 30 + aaline_color = pygame.Color("red") + surface_color = pygame.Color("green") + surface = pygame.Surface((surfw, surfh)) + surface.fill(surface_color) + + clip_rect = pygame.Rect((0, 0), (11, 11)) + clip_rect.center = surface.get_rect().center + pos_rect = clip_rect.copy() # Manages the aalines's pos. + + # Test centering the pos_rect along the clip rect's edge to allow for + # drawing the aalines over the clip_rect's bounds. + for center in rect_corners_mids_and_center(clip_rect): + pos_rect.center = center + pts = (pos_rect.midtop, pos_rect.center, pos_rect.midbottom) + + for closed in (True, False): # Test closed and not closed. + for blend in (0, 1): # Test non-blending and blending. + # Get the expected points by drawing the aalines without + # the clip area set. + surface.set_clip(None) + surface.fill(surface_color) + self.draw_aalines(surface, aaline_color, closed, pts, blend) + + # Need to get the points that are NOT surface_color due to + # the way blend=0 uses the color black to antialias. + expected_pts = get_color_points( + surface, surface_color, clip_rect, False + ) + + # Clear the surface and set the clip area. Redraw the + # aalines and check that only the clip area is modified. + surface.fill(surface_color) + surface.set_clip(clip_rect) + + self.draw_aalines(surface, aaline_color, closed, pts, blend) + + surface.lock() # For possible speed up. + + # Check all the surface points to ensure the expected_pts + # are not surface_color. + for pt in ((x, y) for x in range(surfw) for y in range(surfh)): + if pt in expected_pts: + self.assertNotEqual(surface.get_at(pt), surface_color, pt) + else: + self.assertEqual(surface.get_at(pt), surface_color, pt) + + surface.unlock() + + +# Commented out to avoid cluttering the test output. Add back in if draw_py +# ever fully supports drawing aalines. +# class PythonDrawAALinesTest(AALinesMixin, PythonDrawTestCase): +# """Test draw_py module function aalines. +# +# This class inherits the general tests from AALinesMixin. It is also the +# class to add any draw_py.draw_aalines specific tests to. +# """ + + +class DrawAALinesTest(AALinesMixin, DrawTestCase): + """Test draw module function aalines. + + This class inherits the general tests from AALinesMixin. It is also the + class to add any draw.aalines specific tests to. + """ + + +### Polygon Testing ########################################################### + +SQUARE = ([0, 0], [3, 0], [3, 3], [0, 3]) +DIAMOND = [(1, 3), (3, 5), (5, 3), (3, 1)] +CROSS = ( + [2, 0], + [4, 0], + [4, 2], + [6, 2], + [6, 4], + [4, 4], + [4, 6], + [2, 6], + [2, 4], + [0, 4], + [0, 2], + [2, 2], +) + + +class DrawPolygonMixin(object): + """Mixin tests for drawing polygons. + + This class contains all the general polygon drawing tests. + """ + + def setUp(self): + self.surface = pygame.Surface((20, 20)) + + def test_polygon__args(self): + """Ensures draw polygon accepts the correct args.""" + bounds_rect = self.draw_polygon( + pygame.Surface((3, 3)), (0, 10, 0, 50), ((0, 0), (1, 1), (2, 2)), 1 + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_polygon__args_without_width(self): + """Ensures draw polygon accepts the args without a width.""" + bounds_rect = self.draw_polygon( + pygame.Surface((2, 2)), (0, 0, 0, 50), ((0, 0), (1, 1), (2, 2)) + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_polygon__kwargs(self): + """Ensures draw polygon accepts the correct kwargs + with and without a width arg. + """ + surface = pygame.Surface((4, 4)) + color = pygame.Color("yellow") + points = ((0, 0), (1, 1), (2, 2)) + kwargs_list = [ + {"surface": surface, "color": color, "points": points, "width": 1}, + {"surface": surface, "color": color, "points": points}, + ] + + for kwargs in kwargs_list: + bounds_rect = self.draw_polygon(**kwargs) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_polygon__kwargs_order_independent(self): + """Ensures draw polygon's kwargs are not order dependent.""" + bounds_rect = self.draw_polygon( + color=(10, 20, 30), + surface=pygame.Surface((3, 2)), + width=0, + points=((0, 1), (1, 2), (2, 3)), + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_polygon__args_missing(self): + """Ensures draw polygon detects any missing required args.""" + surface = pygame.Surface((1, 1)) + color = pygame.Color("blue") + + with self.assertRaises(TypeError): + bounds_rect = self.draw_polygon(surface, color) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_polygon(surface) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_polygon() + + def test_polygon__kwargs_missing(self): + """Ensures draw polygon detects any missing required kwargs.""" + kwargs = { + "surface": pygame.Surface((1, 2)), + "color": pygame.Color("red"), + "points": ((2, 1), (2, 2), (2, 3)), + "width": 1, + } + + for name in ("points", "color", "surface"): + invalid_kwargs = dict(kwargs) + invalid_kwargs.pop(name) # Pop from a copy. + + with self.assertRaises(TypeError): + bounds_rect = self.draw_polygon(**invalid_kwargs) + + def test_polygon__arg_invalid_types(self): + """Ensures draw polygon detects invalid arg types.""" + surface = pygame.Surface((2, 2)) + color = pygame.Color("blue") + points = ((0, 1), (1, 2), (1, 3)) + + with self.assertRaises(TypeError): + # Invalid width. + bounds_rect = self.draw_polygon(surface, color, points, "1") + + with self.assertRaises(TypeError): + # Invalid points. + bounds_rect = self.draw_polygon(surface, color, (1, 2, 3)) + + with self.assertRaises(TypeError): + # Invalid color. + bounds_rect = self.draw_polygon(surface, 2.3, points) + + with self.assertRaises(TypeError): + # Invalid surface. + bounds_rect = self.draw_polygon((1, 2, 3, 4), color, points) + + def test_polygon__kwarg_invalid_types(self): + """Ensures draw polygon detects invalid kwarg types.""" + surface = pygame.Surface((3, 3)) + color = pygame.Color("green") + points = ((0, 0), (1, 0), (2, 0)) + width = 1 + kwargs_list = [ + { + "surface": pygame.Surface, # Invalid surface. + "color": color, + "points": points, + "width": width, + }, + { + "surface": surface, + "color": 2.3, # Invalid color. + "points": points, + "width": width, + }, + { + "surface": surface, + "color": color, + "points": ((1,), (1,), (1,)), # Invalid points. + "width": width, + }, + {"surface": surface, "color": color, "points": points, "width": 1.2}, + ] # Invalid width. + + for kwargs in kwargs_list: + with self.assertRaises(TypeError): + bounds_rect = self.draw_polygon(**kwargs) + + def test_polygon__kwarg_invalid_name(self): + """Ensures draw polygon detects invalid kwarg names.""" + surface = pygame.Surface((2, 3)) + color = pygame.Color("cyan") + points = ((1, 1), (1, 2), (1, 3)) + kwargs_list = [ + { + "surface": surface, + "color": color, + "points": points, + "width": 1, + "invalid": 1, + }, + {"surface": surface, "color": color, "points": points, "invalid": 1}, + ] + + for kwargs in kwargs_list: + with self.assertRaises(TypeError): + bounds_rect = self.draw_polygon(**kwargs) + + def test_polygon__args_and_kwargs(self): + """Ensures draw polygon accepts a combination of args/kwargs""" + surface = pygame.Surface((3, 1)) + color = (255, 255, 0, 0) + points = ((0, 1), (1, 2), (2, 3)) + width = 0 + kwargs = {"surface": surface, "color": color, "points": points, "width": width} + + for name in ("surface", "color", "points", "width"): + kwargs.pop(name) + + if "surface" == name: + bounds_rect = self.draw_polygon(surface, **kwargs) + elif "color" == name: + bounds_rect = self.draw_polygon(surface, color, **kwargs) + elif "points" == name: + bounds_rect = self.draw_polygon(surface, color, points, **kwargs) + else: + bounds_rect = self.draw_polygon(surface, color, points, width, **kwargs) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_polygon__valid_width_values(self): + """Ensures draw polygon accepts different width values.""" + surface_color = pygame.Color("white") + surface = pygame.Surface((3, 4)) + color = (10, 20, 30, 255) + kwargs = { + "surface": surface, + "color": color, + "points": ((1, 1), (2, 1), (2, 2), (1, 2)), + "width": None, + } + pos = kwargs["points"][0] + + for width in (-100, -10, -1, 0, 1, 10, 100): + surface.fill(surface_color) # Clear for each test. + kwargs["width"] = width + expected_color = color if width >= 0 else surface_color + + bounds_rect = self.draw_polygon(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_polygon__valid_points_format(self): + """Ensures draw polygon accepts different points formats.""" + expected_color = (10, 20, 30, 255) + surface_color = pygame.Color("white") + surface = pygame.Surface((3, 4)) + kwargs = { + "surface": surface, + "color": expected_color, + "points": None, + "width": 0, + } + + # The point type can be a tuple/list/Vector2. + point_types = ( + (tuple, tuple, tuple, tuple), # all tuples + (list, list, list, list), # all lists + (Vector2, Vector2, Vector2, Vector2), # all Vector2s + (list, Vector2, tuple, Vector2), + ) # mix + + # The point values can be ints or floats. + point_values = ( + ((1, 1), (2, 1), (2, 2), (1, 2)), + ((1, 1), (2.2, 1), (2.1, 2.2), (1, 2.1)), + ) + + # Each sequence of points can be a tuple or a list. + seq_types = (tuple, list) + + for point_type in point_types: + for values in point_values: + check_pos = values[0] + points = [point_type[i](pt) for i, pt in enumerate(values)] + + for seq_type in seq_types: + surface.fill(surface_color) # Clear for each test. + kwargs["points"] = seq_type(points) + + bounds_rect = self.draw_polygon(**kwargs) + + self.assertEqual(surface.get_at(check_pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_polygon__invalid_points_formats(self): + """Ensures draw polygon handles invalid points formats correctly.""" + kwargs = { + "surface": pygame.Surface((4, 4)), + "color": pygame.Color("red"), + "points": None, + "width": 0, + } + + points_fmts = ( + ((1, 1), (2, 1), (2,)), # Too few coords. + ((1, 1), (2, 1), (2, 2, 2)), # Too many coords. + ((1, 1), (2, 1), (2, "2")), # Wrong type. + ((1, 1), (2, 1), set([2, 3])), # Wrong type. + ((1, 1), (2, 1), dict(((2, 2), (3, 3)))), # Wrong type. + set(((1, 1), (2, 1), (2, 2), (1, 2))), # Wrong type. + dict(((1, 1), (2, 2), (3, 3), (4, 4))), + ) # Wrong type. + + for points in points_fmts: + kwargs["points"] = points + + with self.assertRaises(TypeError): + bounds_rect = self.draw_polygon(**kwargs) + + def test_polygon__invalid_points_values(self): + """Ensures draw polygon handles invalid points values correctly.""" + kwargs = { + "surface": pygame.Surface((4, 4)), + "color": pygame.Color("red"), + "points": None, + "width": 0, + } + + points_fmts = ( + tuple(), # Too few points. + ((1, 1),), # Too few points. + ((1, 1), (2, 1)), + ) # Too few points. + + for points in points_fmts: + for seq_type in (tuple, list): # Test as tuples and lists. + kwargs["points"] = seq_type(points) + + with self.assertRaises(ValueError): + bounds_rect = self.draw_polygon(**kwargs) + + def test_polygon__valid_color_formats(self): + """Ensures draw polygon accepts different color formats.""" + green_color = pygame.Color("green") + surface_color = pygame.Color("black") + surface = pygame.Surface((3, 4)) + kwargs = { + "surface": surface, + "color": None, + "points": ((1, 1), (2, 1), (2, 2), (1, 2)), + "width": 0, + } + pos = kwargs["points"][0] + greens = ( + (0, 255, 0), + (0, 255, 0, 255), + surface.map_rgb(green_color), + green_color, + ) + + for color in greens: + surface.fill(surface_color) # Clear for each test. + kwargs["color"] = color + + if isinstance(color, int): + expected_color = surface.unmap_rgb(color) + else: + expected_color = green_color + + bounds_rect = self.draw_polygon(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_polygon__invalid_color_formats(self): + """Ensures draw polygon handles invalid color formats correctly.""" + kwargs = { + "surface": pygame.Surface((4, 3)), + "color": None, + "points": ((1, 1), (2, 1), (2, 2), (1, 2)), + "width": 0, + } + + for expected_color in (2.3, self): + kwargs["color"] = expected_color + + with self.assertRaises(TypeError): + bounds_rect = self.draw_polygon(**kwargs) + + def test_draw_square(self): + self.draw_polygon(self.surface, RED, SQUARE, 0) + # note : there is a discussion (#234) if draw.polygon should include or + # not the right or lower border; here we stick with current behavior, + # eg include those borders ... + for x in range(4): + for y in range(4): + self.assertEqual(self.surface.get_at((x, y)), RED) + + def test_draw_diamond(self): + pygame.draw.rect(self.surface, RED, (0, 0, 10, 10), 0) + self.draw_polygon(self.surface, GREEN, DIAMOND, 0) + # this diamond shape is equivalent to its four corners, plus inner square + for x, y in DIAMOND: + self.assertEqual(self.surface.get_at((x, y)), GREEN, msg=str((x, y))) + for x in range(2, 5): + for y in range(2, 5): + self.assertEqual(self.surface.get_at((x, y)), GREEN) + + def test_1_pixel_high_or_wide_shapes(self): + # 1. one-pixel-high, filled + pygame.draw.rect(self.surface, RED, (0, 0, 10, 10), 0) + self.draw_polygon(self.surface, GREEN, [(x, 2) for x, _y in CROSS], 0) + cross_size = 6 # the maximum x or y coordinate of the cross + for x in range(cross_size + 1): + self.assertEqual(self.surface.get_at((x, 1)), RED) + self.assertEqual(self.surface.get_at((x, 2)), GREEN) + self.assertEqual(self.surface.get_at((x, 3)), RED) + pygame.draw.rect(self.surface, RED, (0, 0, 10, 10), 0) + # 2. one-pixel-high, not filled + self.draw_polygon(self.surface, GREEN, [(x, 5) for x, _y in CROSS], 1) + for x in range(cross_size + 1): + self.assertEqual(self.surface.get_at((x, 4)), RED) + self.assertEqual(self.surface.get_at((x, 5)), GREEN) + self.assertEqual(self.surface.get_at((x, 6)), RED) + pygame.draw.rect(self.surface, RED, (0, 0, 10, 10), 0) + # 3. one-pixel-wide, filled + self.draw_polygon(self.surface, GREEN, [(3, y) for _x, y in CROSS], 0) + for y in range(cross_size + 1): + self.assertEqual(self.surface.get_at((2, y)), RED) + self.assertEqual(self.surface.get_at((3, y)), GREEN) + self.assertEqual(self.surface.get_at((4, y)), RED) + pygame.draw.rect(self.surface, RED, (0, 0, 10, 10), 0) + # 4. one-pixel-wide, not filled + self.draw_polygon(self.surface, GREEN, [(4, y) for _x, y in CROSS], 1) + for y in range(cross_size + 1): + self.assertEqual(self.surface.get_at((3, y)), RED) + self.assertEqual(self.surface.get_at((4, y)), GREEN) + self.assertEqual(self.surface.get_at((5, y)), RED) + + def test_draw_symetric_cross(self): + """non-regression on issue #234 : x and y where handled inconsistently. + + Also, the result is/was different whether we fill or not the polygon. + """ + # 1. case width = 1 (not filled: `polygon` calls internally the `lines` function) + pygame.draw.rect(self.surface, RED, (0, 0, 10, 10), 0) + self.draw_polygon(self.surface, GREEN, CROSS, 1) + inside = [(x, 3) for x in range(1, 6)] + [(3, y) for y in range(1, 6)] + for x in range(10): + for y in range(10): + if (x, y) in inside: + self.assertEqual(self.surface.get_at((x, y)), RED) + elif (x in range(2, 5) and y < 7) or (y in range(2, 5) and x < 7): + # we are on the border of the cross: + self.assertEqual(self.surface.get_at((x, y)), GREEN) + else: + # we are outside + self.assertEqual(self.surface.get_at((x, y)), RED) + + # 2. case width = 0 (filled; this is the example from #234) + pygame.draw.rect(self.surface, RED, (0, 0, 10, 10), 0) + self.draw_polygon(self.surface, GREEN, CROSS, 0) + inside = [(x, 3) for x in range(1, 6)] + [(3, y) for y in range(1, 6)] + for x in range(10): + for y in range(10): + if (x in range(2, 5) and y < 7) or (y in range(2, 5) and x < 7): + # we are on the border of the cross: + self.assertEqual( + self.surface.get_at((x, y)), GREEN, msg=str((x, y)) + ) + else: + # we are outside + self.assertEqual(self.surface.get_at((x, y)), RED) + + def test_illumine_shape(self): + """non-regression on issue #313""" + rect = pygame.Rect((0, 0, 20, 20)) + path_data = [ + (0, 0), + (rect.width - 1, 0), # upper border + (rect.width - 5, 5 - 1), + (5 - 1, 5 - 1), # upper inner + (5 - 1, rect.height - 5), + (0, rect.height - 1), + ] # lower diagonal + # The shape looks like this (the numbers are the indices of path_data) + + # 0**********************1 <-- upper border + # *********************** + # ********************** + # ********************* + # ****3**************2 <-- upper inner border + # ***** + # ***** (more lines here) + # ***** + # ****4 + # **** + # *** + # ** + # 5 + # + + # the current bug is that the "upper inner" line is not drawn, but only + # if 4 or some lower corner exists + pygame.draw.rect(self.surface, RED, (0, 0, 20, 20), 0) + + # 1. First without the corners 4 & 5 + self.draw_polygon(self.surface, GREEN, path_data[:4], 0) + for x in range(20): + self.assertEqual(self.surface.get_at((x, 0)), GREEN) # upper border + for x in range(4, rect.width - 5 + 1): + self.assertEqual(self.surface.get_at((x, 4)), GREEN) # upper inner + + # 2. with the corners 4 & 5 + pygame.draw.rect(self.surface, RED, (0, 0, 20, 20), 0) + self.draw_polygon(self.surface, GREEN, path_data, 0) + for x in range(4, rect.width - 5 + 1): + self.assertEqual(self.surface.get_at((x, 4)), GREEN) # upper inner + + def test_invalid_points(self): + self.assertRaises( + TypeError, + lambda: self.draw_polygon( + self.surface, RED, ((0, 0), (0, 20), (20, 20), 20), 0 + ), + ) + + def test_polygon__bounding_rect(self): + """Ensures draw polygon returns the correct bounding rect. + + Tests polygons on and off the surface and a range of width/thickness + values. + """ + polygon_color = pygame.Color("red") + surf_color = pygame.Color("black") + min_width = min_height = 5 + max_width = max_height = 7 + sizes = ((min_width, min_height), (max_width, max_height)) + surface = pygame.Surface((20, 20), 0, 32) + surf_rect = surface.get_rect() + # Make a rect that is bigger than the surface to help test drawing + # polygons off and partially off the surface. + big_rect = surf_rect.inflate(min_width * 2 + 1, min_height * 2 + 1) + + for pos in rect_corners_mids_and_center( + surf_rect + ) + rect_corners_mids_and_center(big_rect): + # A rect (pos_rect) is used to help create and position the + # polygon. Each of this rect's position attributes will be set to + # the pos value. + for attr in RECT_POSITION_ATTRIBUTES: + # Test using different rect sizes and thickness values. + for width, height in sizes: + pos_rect = pygame.Rect((0, 0), (width, height)) + setattr(pos_rect, attr, pos) + # Points form a triangle with no fully + # horizontal/vertical lines. + vertices = ( + pos_rect.midleft, + pos_rect.midtop, + pos_rect.bottomright, + ) + + for thickness in range(4): + surface.fill(surf_color) # Clear for each test. + + bounding_rect = self.draw_polygon( + surface, polygon_color, vertices, thickness + ) + + # Calculating the expected_rect after the polygon + # is drawn (it uses what is actually drawn). + expected_rect = create_bounding_rect( + surface, surf_color, vertices[0] + ) + + self.assertEqual( + bounding_rect, + expected_rect, + "thickness={}".format(thickness), + ) + + def test_polygon__surface_clip(self): + """Ensures draw polygon respects a surface's clip area. + + Tests drawing the polygon filled and unfilled. + """ + surfw = surfh = 30 + polygon_color = pygame.Color("red") + surface_color = pygame.Color("green") + surface = pygame.Surface((surfw, surfh)) + surface.fill(surface_color) + + clip_rect = pygame.Rect((0, 0), (8, 10)) + clip_rect.center = surface.get_rect().center + pos_rect = clip_rect.copy() # Manages the polygon's pos. + + for width in (0, 1): # Filled and unfilled. + # Test centering the polygon along the clip rect's edge. + for center in rect_corners_mids_and_center(clip_rect): + # Get the expected points by drawing the polygon without the + # clip area set. + pos_rect.center = center + vertices = ( + pos_rect.topleft, + pos_rect.topright, + pos_rect.bottomright, + pos_rect.bottomleft, + ) + surface.set_clip(None) + surface.fill(surface_color) + self.draw_polygon(surface, polygon_color, vertices, width) + expected_pts = get_color_points(surface, polygon_color, clip_rect) + + # Clear the surface and set the clip area. Redraw the polygon + # and check that only the clip area is modified. + surface.fill(surface_color) + surface.set_clip(clip_rect) + + self.draw_polygon(surface, polygon_color, vertices, width) + + surface.lock() # For possible speed up. + + # Check all the surface points to ensure only the expected_pts + # are the polygon_color. + for pt in ((x, y) for x in range(surfw) for y in range(surfh)): + if pt in expected_pts: + expected_color = polygon_color + else: + expected_color = surface_color + + self.assertEqual(surface.get_at(pt), expected_color, pt) + + surface.unlock() + + +class DrawPolygonTest(DrawPolygonMixin, DrawTestCase): + """Test draw module function polygon. + + This class inherits the general tests from DrawPolygonMixin. It is also + the class to add any draw.polygon specific tests to. + """ + + +# Commented out to avoid cluttering the test output. Add back in if draw_py +# ever fully supports drawing polygons. +# @unittest.skip('draw_py.draw_polygon not fully supported yet') +# class PythonDrawPolygonTest(DrawPolygonMixin, PythonDrawTestCase): +# """Test draw_py module function draw_polygon. +# +# This class inherits the general tests from DrawPolygonMixin. It is also +# the class to add any draw_py.draw_polygon specific tests to. +# """ + + +### Rect Testing ############################################################## + + +class DrawRectMixin(object): + """Mixin tests for drawing rects. + + This class contains all the general rect drawing tests. + """ + + def test_rect__args(self): + """Ensures draw rect accepts the correct args.""" + bounds_rect = self.draw_rect( + pygame.Surface((2, 2)), + (20, 10, 20, 150), + pygame.Rect((0, 0), (1, 1)), + 2, + 1, + 2, + 3, + 4, + 5, + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_rect__args_without_width(self): + """Ensures draw rect accepts the args without a width and borders.""" + bounds_rect = self.draw_rect( + pygame.Surface((3, 5)), (0, 0, 0, 255), pygame.Rect((0, 0), (1, 1)) + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_rect__kwargs(self): + """Ensures draw rect accepts the correct kwargs + with and without a width and border_radius arg. + """ + kwargs_list = [ + { + "surface": pygame.Surface((5, 5)), + "color": pygame.Color("red"), + "rect": pygame.Rect((0, 0), (1, 2)), + "width": 1, + "border_radius": 10, + "border_top_left_radius": 5, + "border_top_right_radius": 20, + "border_bottom_left_radius": 15, + "border_bottom_right_radius": 0, + }, + { + "surface": pygame.Surface((1, 2)), + "color": (0, 100, 200), + "rect": (0, 0, 1, 1), + }, + ] + + for kwargs in kwargs_list: + bounds_rect = self.draw_rect(**kwargs) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_rect__kwargs_order_independent(self): + """Ensures draw rect's kwargs are not order dependent.""" + bounds_rect = self.draw_rect( + color=(0, 1, 2), + border_radius=10, + surface=pygame.Surface((2, 3)), + border_top_left_radius=5, + width=-2, + border_top_right_radius=20, + border_bottom_right_radius=0, + rect=pygame.Rect((0, 0), (0, 0)), + border_bottom_left_radius=15, + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_rect__args_missing(self): + """Ensures draw rect detects any missing required args.""" + surface = pygame.Surface((1, 1)) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_rect(surface, pygame.Color("white")) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_rect(surface) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_rect() + + def test_rect__kwargs_missing(self): + """Ensures draw rect detects any missing required kwargs.""" + kwargs = { + "surface": pygame.Surface((1, 3)), + "color": pygame.Color("red"), + "rect": pygame.Rect((0, 0), (2, 2)), + "width": 5, + "border_radius": 10, + "border_top_left_radius": 5, + "border_top_right_radius": 20, + "border_bottom_left_radius": 15, + "border_bottom_right_radius": 0, + } + + for name in ("rect", "color", "surface"): + invalid_kwargs = dict(kwargs) + invalid_kwargs.pop(name) # Pop from a copy. + + with self.assertRaises(TypeError): + bounds_rect = self.draw_rect(**invalid_kwargs) + + def test_rect__arg_invalid_types(self): + """Ensures draw rect detects invalid arg types.""" + surface = pygame.Surface((3, 3)) + color = pygame.Color("white") + rect = pygame.Rect((1, 1), (1, 1)) + + with self.assertRaises(TypeError): + # Invalid border_bottom_right_radius. + bounds_rect = self.draw_rect( + surface, color, rect, 2, border_bottom_right_radius="rad" + ) + + with self.assertRaises(TypeError): + # Invalid border_bottom_left_radius. + bounds_rect = self.draw_rect( + surface, color, rect, 2, border_bottom_left_radius="rad" + ) + + with self.assertRaises(TypeError): + # Invalid border_top_right_radius. + bounds_rect = self.draw_rect( + surface, color, rect, 2, border_top_right_radius="rad" + ) + + with self.assertRaises(TypeError): + # Invalid border_top_left_radius. + bounds_rect = self.draw_rect( + surface, color, rect, 2, border_top_left_radius="draw" + ) + + with self.assertRaises(TypeError): + # Invalid border_radius. + bounds_rect = self.draw_rect(surface, color, rect, 2, "rad") + + with self.assertRaises(TypeError): + # Invalid width. + bounds_rect = self.draw_rect(surface, color, rect, "2", 4) + + with self.assertRaises(TypeError): + # Invalid rect. + bounds_rect = self.draw_rect(surface, color, (1, 2, 3), 2, 6) + + with self.assertRaises(TypeError): + # Invalid color. + bounds_rect = self.draw_rect(surface, 2.3, rect, 3, 8) + + with self.assertRaises(TypeError): + # Invalid surface. + bounds_rect = self.draw_rect(rect, color, rect, 4, 10) + + def test_rect__kwarg_invalid_types(self): + """Ensures draw rect detects invalid kwarg types.""" + surface = pygame.Surface((2, 3)) + color = pygame.Color("red") + rect = pygame.Rect((0, 0), (1, 1)) + kwargs_list = [ + { + "surface": pygame.Surface, # Invalid surface. + "color": color, + "rect": rect, + "width": 1, + "border_radius": 10, + "border_top_left_radius": 5, + "border_top_right_radius": 20, + "border_bottom_left_radius": 15, + "border_bottom_right_radius": 0, + }, + { + "surface": surface, + "color": 2.3, # Invalid color. + "rect": rect, + "width": 1, + "border_radius": 10, + "border_top_left_radius": 5, + "border_top_right_radius": 20, + "border_bottom_left_radius": 15, + "border_bottom_right_radius": 0, + }, + { + "surface": surface, + "color": color, + "rect": (1, 1, 2), # Invalid rect. + "width": 1, + "border_radius": 10, + "border_top_left_radius": 5, + "border_top_right_radius": 20, + "border_bottom_left_radius": 15, + "border_bottom_right_radius": 0, + }, + { + "surface": surface, + "color": color, + "rect": rect, + "width": 1.1, # Invalid width. + "border_radius": 10, + "border_top_left_radius": 5, + "border_top_right_radius": 20, + "border_bottom_left_radius": 15, + "border_bottom_right_radius": 0, + }, + { + "surface": surface, + "color": color, + "rect": rect, + "width": 1, + "border_radius": 10.5, # Invalid border_radius. + "border_top_left_radius": 5, + "border_top_right_radius": 20, + "border_bottom_left_radius": 15, + "border_bottom_right_radius": 0, + }, + { + "surface": surface, + "color": color, + "rect": rect, + "width": 1, + "border_radius": 10, + "border_top_left_radius": 5.5, # Invalid top_left_radius. + "border_top_right_radius": 20, + "border_bottom_left_radius": 15, + "border_bottom_right_radius": 0, + }, + { + "surface": surface, + "color": color, + "rect": rect, + "width": 1, + "border_radius": 10, + "border_top_left_radius": 5, + "border_top_right_radius": "a", # Invalid top_right_radius. + "border_bottom_left_radius": 15, + "border_bottom_right_radius": 0, + }, + { + "surface": surface, + "color": color, + "rect": rect, + "width": 1, + "border_radius": 10, + "border_top_left_radius": 5, + "border_top_right_radius": 20, + "border_bottom_left_radius": "c", # Invalid bottom_left_radius + "border_bottom_right_radius": 0, + }, + { + "surface": surface, + "color": color, + "rect": rect, + "width": 1, + "border_radius": 10, + "border_top_left_radius": 5, + "border_top_right_radius": 20, + "border_bottom_left_radius": 15, + "border_bottom_right_radius": "d", # Invalid bottom_right. + }, + ] + + for kwargs in kwargs_list: + with self.assertRaises(TypeError): + bounds_rect = self.draw_rect(**kwargs) + + def test_rect__kwarg_invalid_name(self): + """Ensures draw rect detects invalid kwarg names.""" + surface = pygame.Surface((2, 1)) + color = pygame.Color("green") + rect = pygame.Rect((0, 0), (3, 3)) + kwargs_list = [ + { + "surface": surface, + "color": color, + "rect": rect, + "width": 1, + "border_radius": 10, + "border_top_left_radius": 5, + "border_top_right_radius": 20, + "border_bottom_left_radius": 15, + "border_bottom_right_radius": 0, + "invalid": 1, + }, + {"surface": surface, "color": color, "rect": rect, "invalid": 1}, + ] + + for kwargs in kwargs_list: + with self.assertRaises(TypeError): + bounds_rect = self.draw_rect(**kwargs) + + def test_rect__args_and_kwargs(self): + """Ensures draw rect accepts a combination of args/kwargs""" + surface = pygame.Surface((3, 1)) + color = (255, 255, 255, 0) + rect = pygame.Rect((1, 0), (2, 5)) + width = 0 + kwargs = {"surface": surface, "color": color, "rect": rect, "width": width} + + for name in ("surface", "color", "rect", "width"): + kwargs.pop(name) + + if "surface" == name: + bounds_rect = self.draw_rect(surface, **kwargs) + elif "color" == name: + bounds_rect = self.draw_rect(surface, color, **kwargs) + elif "rect" == name: + bounds_rect = self.draw_rect(surface, color, rect, **kwargs) + else: + bounds_rect = self.draw_rect(surface, color, rect, width, **kwargs) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_rect__valid_width_values(self): + """Ensures draw rect accepts different width values.""" + pos = (1, 1) + surface_color = pygame.Color("black") + surface = pygame.Surface((3, 4)) + color = (1, 2, 3, 255) + kwargs = { + "surface": surface, + "color": color, + "rect": pygame.Rect(pos, (2, 2)), + "width": None, + } + + for width in (-1000, -10, -1, 0, 1, 10, 1000): + surface.fill(surface_color) # Clear for each test. + kwargs["width"] = width + expected_color = color if width >= 0 else surface_color + + bounds_rect = self.draw_rect(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_rect__valid_rect_formats(self): + """Ensures draw rect accepts different rect formats.""" + pos = (1, 1) + expected_color = pygame.Color("yellow") + surface_color = pygame.Color("black") + surface = pygame.Surface((3, 4)) + kwargs = {"surface": surface, "color": expected_color, "rect": None, "width": 0} + rects = ( + pygame.Rect(pos, (1, 1)), + (pos, (2, 2)), + (pos[0], pos[1], 3, 3), + [pos, (2.1, 2.2)], + ) + + for rect in rects: + surface.fill(surface_color) # Clear for each test. + kwargs["rect"] = rect + + bounds_rect = self.draw_rect(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_rect__invalid_rect_formats(self): + """Ensures draw rect handles invalid rect formats correctly.""" + kwargs = { + "surface": pygame.Surface((4, 4)), + "color": pygame.Color("red"), + "rect": None, + "width": 0, + } + + invalid_fmts = ( + [], + [1], + [1, 2], + [1, 2, 3], + [1, 2, 3, 4, 5], + set([1, 2, 3, 4]), + [1, 2, 3, "4"], + ) + + for rect in invalid_fmts: + kwargs["rect"] = rect + + with self.assertRaises(TypeError): + bounds_rect = self.draw_rect(**kwargs) + + def test_rect__valid_color_formats(self): + """Ensures draw rect accepts different color formats.""" + pos = (1, 1) + red_color = pygame.Color("red") + surface_color = pygame.Color("black") + surface = pygame.Surface((3, 4)) + kwargs = { + "surface": surface, + "color": None, + "rect": pygame.Rect(pos, (1, 1)), + "width": 3, + } + reds = ((255, 0, 0), (255, 0, 0, 255), surface.map_rgb(red_color), red_color) + + for color in reds: + surface.fill(surface_color) # Clear for each test. + kwargs["color"] = color + + if isinstance(color, int): + expected_color = surface.unmap_rgb(color) + else: + expected_color = red_color + + bounds_rect = self.draw_rect(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_rect__invalid_color_formats(self): + """Ensures draw rect handles invalid color formats correctly.""" + pos = (1, 1) + surface = pygame.Surface((3, 4)) + kwargs = { + "surface": surface, + "color": None, + "rect": pygame.Rect(pos, (1, 1)), + "width": 1, + } + + for expected_color in (2.3, self): + kwargs["color"] = expected_color + + with self.assertRaises(TypeError): + bounds_rect = self.draw_rect(**kwargs) + + def test_rect__fill(self): + self.surf_w, self.surf_h = self.surf_size = (320, 200) + self.surf = pygame.Surface(self.surf_size, pygame.SRCALPHA) + self.color = (1, 13, 24, 205) + rect = pygame.Rect(10, 10, 25, 20) + drawn = self.draw_rect(self.surf, self.color, rect, 0) + + self.assertEqual(drawn, rect) + + # Should be colored where it's supposed to be + for pt in test_utils.rect_area_pts(rect): + color_at_pt = self.surf.get_at(pt) + + self.assertEqual(color_at_pt, self.color) + + # And not where it shouldn't + for pt in test_utils.rect_outer_bounds(rect): + color_at_pt = self.surf.get_at(pt) + + self.assertNotEqual(color_at_pt, self.color) + + # Issue #310: Cannot draw rectangles that are 1 pixel high + bgcolor = pygame.Color("black") + self.surf.fill(bgcolor) + hrect = pygame.Rect(1, 1, self.surf_w - 2, 1) + vrect = pygame.Rect(1, 3, 1, self.surf_h - 4) + + drawn = self.draw_rect(self.surf, self.color, hrect, 0) + + self.assertEqual(drawn, hrect) + + x, y = hrect.topleft + w, h = hrect.size + + self.assertEqual(self.surf.get_at((x - 1, y)), bgcolor) + self.assertEqual(self.surf.get_at((x + w, y)), bgcolor) + for i in range(x, x + w): + self.assertEqual(self.surf.get_at((i, y)), self.color) + + drawn = self.draw_rect(self.surf, self.color, vrect, 0) + + self.assertEqual(drawn, vrect) + + x, y = vrect.topleft + w, h = vrect.size + + self.assertEqual(self.surf.get_at((x, y - 1)), bgcolor) + self.assertEqual(self.surf.get_at((x, y + h)), bgcolor) + for i in range(y, y + h): + self.assertEqual(self.surf.get_at((x, i)), self.color) + + def test_rect__one_pixel_lines(self): + self.surf = pygame.Surface((320, 200), pygame.SRCALPHA) + self.color = (1, 13, 24, 205) + + rect = pygame.Rect(10, 10, 56, 20) + + drawn = self.draw_rect(self.surf, self.color, rect, 1) + + self.assertEqual(drawn, rect) + + # Should be colored where it's supposed to be + for pt in test_utils.rect_perimeter_pts(drawn): + color_at_pt = self.surf.get_at(pt) + + self.assertEqual(color_at_pt, self.color) + + # And not where it shouldn't + for pt in test_utils.rect_outer_bounds(drawn): + color_at_pt = self.surf.get_at(pt) + + self.assertNotEqual(color_at_pt, self.color) + + def test_rect__draw_line_width(self): + surface = pygame.Surface((100, 100)) + surface.fill("black") + color = pygame.Color(255, 255, 255) + rect_width = 80 + rect_height = 50 + line_width = 10 + pygame.draw.rect( + surface, color, pygame.Rect(0, 0, rect_width, rect_height), line_width + ) + for i in range(line_width): + self.assertEqual(surface.get_at((i, i)), color) + self.assertEqual(surface.get_at((rect_width - i - 1, i)), color) + self.assertEqual(surface.get_at((i, rect_height - i - 1)), color) + self.assertEqual( + surface.get_at((rect_width - i - 1, rect_height - i - 1)), color + ) + self.assertEqual(surface.get_at((line_width, line_width)), (0, 0, 0)) + self.assertEqual( + surface.get_at((rect_width - line_width - 1, line_width)), (0, 0, 0) + ) + self.assertEqual( + surface.get_at((line_width, rect_height - line_width - 1)), (0, 0, 0) + ) + self.assertEqual( + surface.get_at((rect_width - line_width - 1, rect_height - line_width - 1)), + (0, 0, 0), + ) + + def test_rect__bounding_rect(self): + """Ensures draw rect returns the correct bounding rect. + + Tests rects on and off the surface and a range of width/thickness + values. + """ + rect_color = pygame.Color("red") + surf_color = pygame.Color("black") + min_width = min_height = 5 + max_width = max_height = 7 + sizes = ((min_width, min_height), (max_width, max_height)) + surface = pygame.Surface((20, 20), 0, 32) + surf_rect = surface.get_rect() + # Make a rect that is bigger than the surface to help test drawing + # rects off and partially off the surface. + big_rect = surf_rect.inflate(min_width * 2 + 1, min_height * 2 + 1) + + for pos in rect_corners_mids_and_center( + surf_rect + ) + rect_corners_mids_and_center(big_rect): + # Each of the rect's position attributes will be set to the pos + # value. + for attr in RECT_POSITION_ATTRIBUTES: + # Test using different rect sizes and thickness values. + for width, height in sizes: + rect = pygame.Rect((0, 0), (width, height)) + setattr(rect, attr, pos) + + for thickness in range(4): + surface.fill(surf_color) # Clear for each test. + + bounding_rect = self.draw_rect( + surface, rect_color, rect, thickness + ) + + # Calculating the expected_rect after the rect is + # drawn (it uses what is actually drawn). + expected_rect = create_bounding_rect( + surface, surf_color, rect.topleft + ) + + self.assertEqual( + bounding_rect, + expected_rect, + "thickness={}".format(thickness), + ) + + def test_rect__surface_clip(self): + """Ensures draw rect respects a surface's clip area. + + Tests drawing the rect filled and unfilled. + """ + surfw = surfh = 30 + rect_color = pygame.Color("red") + surface_color = pygame.Color("green") + surface = pygame.Surface((surfw, surfh)) + surface.fill(surface_color) + + clip_rect = pygame.Rect((0, 0), (8, 10)) + clip_rect.center = surface.get_rect().center + test_rect = clip_rect.copy() # Manages the rect's pos. + + for width in (0, 1): # Filled and unfilled. + # Test centering the rect along the clip rect's edge. + for center in rect_corners_mids_and_center(clip_rect): + # Get the expected points by drawing the rect without the + # clip area set. + test_rect.center = center + surface.set_clip(None) + surface.fill(surface_color) + self.draw_rect(surface, rect_color, test_rect, width) + expected_pts = get_color_points(surface, rect_color, clip_rect) + + # Clear the surface and set the clip area. Redraw the rect + # and check that only the clip area is modified. + surface.fill(surface_color) + surface.set_clip(clip_rect) + + self.draw_rect(surface, rect_color, test_rect, width) + + surface.lock() # For possible speed up. + + # Check all the surface points to ensure only the expected_pts + # are the rect_color. + for pt in ((x, y) for x in range(surfw) for y in range(surfh)): + if pt in expected_pts: + expected_color = rect_color + else: + expected_color = surface_color + + self.assertEqual(surface.get_at(pt), expected_color, pt) + + surface.unlock() + + +class DrawRectTest(DrawRectMixin, DrawTestCase): + """Test draw module function rect. + + This class inherits the general tests from DrawRectMixin. It is also the + class to add any draw.rect specific tests to. + """ + + +# Commented out to avoid cluttering the test output. Add back in if draw_py +# ever properly supports drawing rects. +# @unittest.skip('draw_py.draw_rect not supported yet') +# class PythonDrawRectTest(DrawRectMixin, PythonDrawTestCase): +# """Test draw_py module function draw_rect. +# +# This class inherits the general tests from DrawRectMixin. It is also the +# class to add any draw_py.draw_rect specific tests to. +# """ + + +### Circle Testing ############################################################ + + +class DrawCircleMixin(object): + """Mixin tests for drawing circles. + + This class contains all the general circle drawing tests. + """ + + def test_circle__args(self): + """Ensures draw circle accepts the correct args.""" + bounds_rect = self.draw_circle( + pygame.Surface((3, 3)), (0, 10, 0, 50), (0, 0), 3, 1, 1, 0, 1, 1 + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_circle__args_without_width(self): + """Ensures draw circle accepts the args without a width and + quadrants.""" + bounds_rect = self.draw_circle(pygame.Surface((2, 2)), (0, 0, 0, 50), (1, 1), 1) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_circle__args_with_negative_width(self): + """Ensures draw circle accepts the args with negative width.""" + bounds_rect = self.draw_circle( + pygame.Surface((2, 2)), (0, 0, 0, 50), (1, 1), 1, -1 + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + self.assertEqual(bounds_rect, pygame.Rect(1, 1, 0, 0)) + + def test_circle__args_with_width_gt_radius(self): + """Ensures draw circle accepts the args with width > radius.""" + bounds_rect = self.draw_circle( + pygame.Surface((2, 2)), (0, 0, 0, 50), (1, 1), 2, 3, 0, 0, 0, 0 + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + self.assertEqual(bounds_rect, pygame.Rect(0, 0, 2, 2)) + + def test_circle__kwargs(self): + """Ensures draw circle accepts the correct kwargs + with and without a width and quadrant arguments. + """ + kwargs_list = [ + { + "surface": pygame.Surface((4, 4)), + "color": pygame.Color("yellow"), + "center": (2, 2), + "radius": 2, + "width": 1, + "draw_top_right": True, + "draw_top_left": True, + "draw_bottom_left": False, + "draw_bottom_right": True, + }, + { + "surface": pygame.Surface((2, 1)), + "color": (0, 10, 20), + "center": (1, 1), + "radius": 1, + }, + ] + + for kwargs in kwargs_list: + bounds_rect = self.draw_circle(**kwargs) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_circle__kwargs_order_independent(self): + """Ensures draw circle's kwargs are not order dependent.""" + bounds_rect = self.draw_circle( + draw_top_right=False, + color=(10, 20, 30), + surface=pygame.Surface((3, 2)), + width=0, + draw_bottom_left=False, + center=(1, 0), + draw_bottom_right=False, + radius=2, + draw_top_left=True, + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_circle__args_missing(self): + """Ensures draw circle detects any missing required args.""" + surface = pygame.Surface((1, 1)) + color = pygame.Color("blue") + + with self.assertRaises(TypeError): + bounds_rect = self.draw_circle(surface, color, (0, 0)) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_circle(surface, color) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_circle(surface) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_circle() + + def test_circle__kwargs_missing(self): + """Ensures draw circle detects any missing required kwargs.""" + kwargs = { + "surface": pygame.Surface((1, 2)), + "color": pygame.Color("red"), + "center": (1, 0), + "radius": 2, + "width": 1, + "draw_top_right": False, + "draw_top_left": False, + "draw_bottom_left": False, + "draw_bottom_right": True, + } + + for name in ("radius", "center", "color", "surface"): + invalid_kwargs = dict(kwargs) + invalid_kwargs.pop(name) # Pop from a copy. + + with self.assertRaises(TypeError): + bounds_rect = self.draw_circle(**invalid_kwargs) + + def test_circle__arg_invalid_types(self): + """Ensures draw circle detects invalid arg types.""" + surface = pygame.Surface((2, 2)) + color = pygame.Color("blue") + center = (1, 1) + radius = 1 + + with self.assertRaises(TypeError): + # Invalid draw_top_right. + bounds_rect = self.draw_circle( + surface, color, center, radius, 1, "a", 1, 1, 1 + ) + + with self.assertRaises(TypeError): + # Invalid draw_top_left. + bounds_rect = self.draw_circle( + surface, color, center, radius, 1, 1, "b", 1, 1 + ) + + with self.assertRaises(TypeError): + # Invalid draw_bottom_left. + bounds_rect = self.draw_circle( + surface, color, center, radius, 1, 1, 1, "c", 1 + ) + + with self.assertRaises(TypeError): + # Invalid draw_bottom_right. + bounds_rect = self.draw_circle( + surface, color, center, radius, 1, 1, 1, 1, "d" + ) + + with self.assertRaises(TypeError): + # Invalid width. + bounds_rect = self.draw_circle(surface, color, center, radius, "1") + + with self.assertRaises(TypeError): + # Invalid radius. + bounds_rect = self.draw_circle(surface, color, center, "2") + + with self.assertRaises(TypeError): + # Invalid center. + bounds_rect = self.draw_circle(surface, color, (1, 2, 3), radius) + + with self.assertRaises(TypeError): + # Invalid color. + bounds_rect = self.draw_circle(surface, 2.3, center, radius) + + with self.assertRaises(TypeError): + # Invalid surface. + bounds_rect = self.draw_circle((1, 2, 3, 4), color, center, radius) + + def test_circle__kwarg_invalid_types(self): + """Ensures draw circle detects invalid kwarg types.""" + surface = pygame.Surface((3, 3)) + color = pygame.Color("green") + center = (0, 1) + radius = 1 + width = 1 + quadrant = 1 + kwargs_list = [ + { + "surface": pygame.Surface, # Invalid surface. + "color": color, + "center": center, + "radius": radius, + "width": width, + "draw_top_right": True, + "draw_top_left": True, + "draw_bottom_left": True, + "draw_bottom_right": True, + }, + { + "surface": surface, + "color": 2.3, # Invalid color. + "center": center, + "radius": radius, + "width": width, + "draw_top_right": True, + "draw_top_left": True, + "draw_bottom_left": True, + "draw_bottom_right": True, + }, + { + "surface": surface, + "color": color, + "center": (1, 1, 1), # Invalid center. + "radius": radius, + "width": width, + "draw_top_right": True, + "draw_top_left": True, + "draw_bottom_left": True, + "draw_bottom_right": True, + }, + { + "surface": surface, + "color": color, + "center": center, + "radius": "1", # Invalid radius. + "width": width, + "draw_top_right": True, + "draw_top_left": True, + "draw_bottom_left": True, + "draw_bottom_right": True, + }, + { + "surface": surface, + "color": color, + "center": center, + "radius": radius, + "width": 1.2, # Invalid width. + "draw_top_right": True, + "draw_top_left": True, + "draw_bottom_left": True, + "draw_bottom_right": True, + }, + { + "surface": surface, + "color": color, + "center": center, + "radius": radius, + "width": width, + "draw_top_right": "True", # Invalid draw_top_right + "draw_top_left": True, + "draw_bottom_left": True, + "draw_bottom_right": True, + }, + { + "surface": surface, + "color": color, + "center": center, + "radius": radius, + "width": width, + "draw_top_right": True, + "draw_top_left": "True", # Invalid draw_top_left + "draw_bottom_left": True, + "draw_bottom_right": True, + }, + { + "surface": surface, + "color": color, + "center": center, + "radius": radius, + "width": width, + "draw_top_right": True, + "draw_top_left": True, + "draw_bottom_left": 3.14, # Invalid draw_bottom_left + "draw_bottom_right": True, + }, + { + "surface": surface, + "color": color, + "center": center, + "radius": radius, + "width": width, + "draw_top_right": True, + "draw_top_left": True, + "draw_bottom_left": True, + "draw_bottom_right": "quadrant", # Invalid draw_bottom_right + }, + ] + + for kwargs in kwargs_list: + with self.assertRaises(TypeError): + bounds_rect = self.draw_circle(**kwargs) + + def test_circle__kwarg_invalid_name(self): + """Ensures draw circle detects invalid kwarg names.""" + surface = pygame.Surface((2, 3)) + color = pygame.Color("cyan") + center = (0, 0) + radius = 2 + kwargs_list = [ + { + "surface": surface, + "color": color, + "center": center, + "radius": radius, + "width": 1, + "quadrant": 1, + "draw_top_right": True, + "draw_top_left": True, + "draw_bottom_left": True, + "draw_bottom_right": True, + }, + { + "surface": surface, + "color": color, + "center": center, + "radius": radius, + "invalid": 1, + }, + ] + + for kwargs in kwargs_list: + with self.assertRaises(TypeError): + bounds_rect = self.draw_circle(**kwargs) + + def test_circle__args_and_kwargs(self): + """Ensures draw circle accepts a combination of args/kwargs""" + surface = pygame.Surface((3, 1)) + color = (255, 255, 0, 0) + center = (1, 0) + radius = 2 + width = 0 + draw_top_right = True + draw_top_left = False + draw_bottom_left = False + draw_bottom_right = True + kwargs = { + "surface": surface, + "color": color, + "center": center, + "radius": radius, + "width": width, + "draw_top_right": True, + "draw_top_left": True, + "draw_bottom_left": True, + "draw_bottom_right": True, + } + + for name in ( + "surface", + "color", + "center", + "radius", + "width", + "draw_top_right", + "draw_top_left", + "draw_bottom_left", + "draw_bottom_right", + ): + kwargs.pop(name) + + if "surface" == name: + bounds_rect = self.draw_circle(surface, **kwargs) + elif "color" == name: + bounds_rect = self.draw_circle(surface, color, **kwargs) + elif "center" == name: + bounds_rect = self.draw_circle(surface, color, center, **kwargs) + elif "radius" == name: + bounds_rect = self.draw_circle(surface, color, center, radius, **kwargs) + elif "width" == name: + bounds_rect = self.draw_circle( + surface, color, center, radius, width, **kwargs + ) + elif "draw_top_right" == name: + bounds_rect = self.draw_circle( + surface, color, center, radius, width, draw_top_right, **kwargs + ) + elif "draw_top_left" == name: + bounds_rect = self.draw_circle( + surface, + color, + center, + radius, + width, + draw_top_right, + draw_top_left, + **kwargs + ) + elif "draw_bottom_left" == name: + bounds_rect = self.draw_circle( + surface, + color, + center, + radius, + width, + draw_top_right, + draw_top_left, + draw_bottom_left, + **kwargs + ) + else: + bounds_rect = self.draw_circle( + surface, + color, + center, + radius, + width, + draw_top_right, + draw_top_left, + draw_bottom_left, + draw_bottom_right, + **kwargs + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_circle__valid_width_values(self): + """Ensures draw circle accepts different width values.""" + center = (2, 2) + radius = 1 + pos = (center[0] - radius, center[1]) + surface_color = pygame.Color("white") + surface = pygame.Surface((3, 4)) + color = (10, 20, 30, 255) + kwargs = { + "surface": surface, + "color": color, + "center": center, + "radius": radius, + "width": None, + "draw_top_right": True, + "draw_top_left": True, + "draw_bottom_left": True, + "draw_bottom_right": True, + } + + for width in (-100, -10, -1, 0, 1, 10, 100): + surface.fill(surface_color) # Clear for each test. + kwargs["width"] = width + expected_color = color if width >= 0 else surface_color + + bounds_rect = self.draw_circle(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_circle__valid_radius_values(self): + """Ensures draw circle accepts different radius values.""" + pos = center = (2, 2) + surface_color = pygame.Color("white") + surface = pygame.Surface((3, 4)) + color = (10, 20, 30, 255) + kwargs = { + "surface": surface, + "color": color, + "center": center, + "radius": None, + "width": 0, + "draw_top_right": True, + "draw_top_left": True, + "draw_bottom_left": True, + "draw_bottom_right": True, + } + + for radius in (-10, -1, 0, 1, 10): + surface.fill(surface_color) # Clear for each test. + kwargs["radius"] = radius + expected_color = color if radius > 0 else surface_color + + bounds_rect = self.draw_circle(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_circle__valid_center_formats(self): + """Ensures draw circle accepts different center formats.""" + expected_color = pygame.Color("red") + surface_color = pygame.Color("black") + surface = pygame.Surface((4, 4)) + kwargs = { + "surface": surface, + "color": expected_color, + "center": None, + "radius": 1, + "width": 0, + "draw_top_right": True, + "draw_top_left": True, + "draw_bottom_left": True, + "draw_bottom_right": True, + } + x, y = 2, 2 # center position + + # The center values can be ints or floats. + for center in ((x, y), (x + 0.1, y), (x, y + 0.1), (x + 0.1, y + 0.1)): + # The center type can be a tuple/list/Vector2. + for seq_type in (tuple, list, Vector2): + surface.fill(surface_color) # Clear for each test. + kwargs["center"] = seq_type(center) + + bounds_rect = self.draw_circle(**kwargs) + + self.assertEqual(surface.get_at((x, y)), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_circle__valid_color_formats(self): + """Ensures draw circle accepts different color formats.""" + center = (2, 2) + radius = 1 + pos = (center[0] - radius, center[1]) + green_color = pygame.Color("green") + surface_color = pygame.Color("black") + surface = pygame.Surface((3, 4)) + kwargs = { + "surface": surface, + "color": None, + "center": center, + "radius": radius, + "width": 0, + "draw_top_right": True, + "draw_top_left": True, + "draw_bottom_left": True, + "draw_bottom_right": True, + } + greens = ( + (0, 255, 0), + (0, 255, 0, 255), + surface.map_rgb(green_color), + green_color, + ) + + for color in greens: + surface.fill(surface_color) # Clear for each test. + kwargs["color"] = color + + if isinstance(color, int): + expected_color = surface.unmap_rgb(color) + else: + expected_color = green_color + + bounds_rect = self.draw_circle(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_circle__invalid_color_formats(self): + """Ensures draw circle handles invalid color formats correctly.""" + kwargs = { + "surface": pygame.Surface((4, 3)), + "color": None, + "center": (1, 2), + "radius": 1, + "width": 0, + "draw_top_right": True, + "draw_top_left": True, + "draw_bottom_left": True, + "draw_bottom_right": True, + } + + for expected_color in (2.3, self): + kwargs["color"] = expected_color + + with self.assertRaises(TypeError): + bounds_rect = self.draw_circle(**kwargs) + + def test_circle__floats(self): + """Ensure that floats are accepted.""" + draw.circle( + surface=pygame.Surface((4, 4)), + color=(255, 255, 127), + center=(1.5, 1.5), + radius=1.3, + width=0, + draw_top_right=True, + draw_top_left=True, + draw_bottom_left=True, + draw_bottom_right=True, + ) + + draw.circle( + surface=pygame.Surface((4, 4)), + color=(255, 255, 127), + center=Vector2(1.5, 1.5), + radius=1.3, + width=0, + draw_top_right=True, + draw_top_left=True, + draw_bottom_left=True, + draw_bottom_right=True, + ) + + draw.circle(pygame.Surface((2, 2)), (0, 0, 0, 50), (1.3, 1.3), 1.2) + + # def test_circle_clip(self): + # """ maybe useful to help work out circle clip algorithm.""" + # MAX = max + # MIN = min + # posx=30 + # posy=15 + # radius=1 + # l=29 + # t=14 + # r=30 + # b=16 + # clip_rect_x=0 + # clip_rect_y=0 + # clip_rect_w=30 + # clip_rect_h=30 + + # l = MAX(posx - radius, clip_rect_x) + # t = MAX(posy - radius, clip_rect_y) + # r = MIN(posx + radius, clip_rect_x + clip_rect_w) + # b = MIN(posy + radius, clip_rect_y + clip_rect_h) + + # l, t, MAX(r - l, 0), MAX(b - t, 0) + + def test_circle__bounding_rect(self): + """Ensures draw circle returns the correct bounding rect. + + Tests circles on and off the surface and a range of width/thickness + values. + """ + circle_color = pygame.Color("red") + surf_color = pygame.Color("black") + max_radius = 3 + surface = pygame.Surface((30, 30), 0, 32) + surf_rect = surface.get_rect() + # Make a rect that is bigger than the surface to help test drawing + # circles off and partially off the surface. Make this rect such that + # when centering the test circle on one of its corners, the circle is + # drawn fully off the test surface, but a rect bounding the circle + # would still overlap with the test surface. + big_rect = surf_rect.inflate(max_radius * 2 - 1, max_radius * 2 - 1) + + for pos in rect_corners_mids_and_center( + surf_rect + ) + rect_corners_mids_and_center(big_rect): + # Test using different radius and thickness values. + for radius in range(max_radius + 1): + for thickness in range(radius + 1): + surface.fill(surf_color) # Clear for each test. + + bounding_rect = self.draw_circle( + surface, circle_color, pos, radius, thickness + ) + + # Calculating the expected_rect after the circle is + # drawn (it uses what is actually drawn). + expected_rect = create_bounding_rect(surface, surf_color, pos) + # print("pos:%s:, radius:%s:, thickness:%s:" % (pos, radius, thickness)) + self.assertEqual(bounding_rect, expected_rect) + + def test_circle_negative_radius(self): + """Ensures negative radius circles return zero sized bounding rect.""" + surf = pygame.Surface((200, 200)) + color = (0, 0, 0, 50) + center = surf.get_height() // 2, surf.get_height() // 2 + + bounding_rect = self.draw_circle(surf, color, center, radius=-1, width=1) + self.assertEqual(bounding_rect.size, (0, 0)) + + def test_circle_zero_radius(self): + """Ensures zero radius circles does not draw a center pixel. + + NOTE: This is backwards incompatible behaviour with 1.9.x. + """ + surf = pygame.Surface((200, 200)) + circle_color = pygame.Color("red") + surf_color = pygame.Color("black") + surf.fill((0, 0, 0)) + center = (100, 100) + radius = 0 + width = 1 + + bounding_rect = self.draw_circle(surf, circle_color, center, radius, width) + expected_rect = create_bounding_rect(surf, surf_color, center) + self.assertEqual(bounding_rect, expected_rect) + self.assertEqual(bounding_rect, pygame.Rect(100, 100, 0, 0)) + + def test_circle__surface_clip(self): + """Ensures draw circle respects a surface's clip area. + + Tests drawing the circle filled and unfilled. + """ + surfw = surfh = 25 + circle_color = pygame.Color("red") + surface_color = pygame.Color("green") + surface = pygame.Surface((surfw, surfh)) + surface.fill(surface_color) + + clip_rect = pygame.Rect((0, 0), (10, 10)) + clip_rect.center = surface.get_rect().center + radius = clip_rect.w // 2 + 1 + + for width in (0, 1): # Filled and unfilled. + # Test centering the circle along the clip rect's edge. + for center in rect_corners_mids_and_center(clip_rect): + # Get the expected points by drawing the circle without the + # clip area set. + surface.set_clip(None) + surface.fill(surface_color) + self.draw_circle(surface, circle_color, center, radius, width) + expected_pts = get_color_points(surface, circle_color, clip_rect) + + # Clear the surface and set the clip area. Redraw the circle + # and check that only the clip area is modified. + surface.fill(surface_color) + surface.set_clip(clip_rect) + + self.draw_circle(surface, circle_color, center, radius, width) + + surface.lock() # For possible speed up. + + # Check all the surface points to ensure only the expected_pts + # are the circle_color. + for pt in ((x, y) for x in range(surfw) for y in range(surfh)): + if pt in expected_pts: + expected_color = circle_color + else: + expected_color = surface_color + + self.assertEqual(surface.get_at(pt), expected_color, pt) + + surface.unlock() + + def test_circle_shape(self): + """Ensures there are no holes in the circle, and no overdrawing. + + Tests drawing a thick circle. + Measures the distance of the drawn pixels from the circle center. + """ + surfw = surfh = 100 + circle_color = pygame.Color("red") + surface_color = pygame.Color("green") + surface = pygame.Surface((surfw, surfh)) + surface.fill(surface_color) + + (cx, cy) = center = (50, 50) + radius = 45 + width = 25 + + dest_rect = self.draw_circle(surface, circle_color, center, radius, width) + + for pt in test_utils.rect_area_pts(dest_rect): + x, y = pt + sqr_distance = (x - cx) ** 2 + (y - cy) ** 2 + if (radius - width + 1) ** 2 < sqr_distance < (radius - 1) ** 2: + self.assertEqual(surface.get_at(pt), circle_color) + if ( + sqr_distance < (radius - width - 1) ** 2 + or sqr_distance > (radius + 1) ** 2 + ): + self.assertEqual(surface.get_at(pt), surface_color) + + def test_circle__diameter(self): + """Ensures draw circle is twice size of radius high and wide.""" + surf = pygame.Surface((200, 200)) + color = (0, 0, 0, 50) + center = surf.get_height() // 2, surf.get_height() // 2 + width = 1 + radius = 6 + for radius in range(1, 65): + bounding_rect = self.draw_circle(surf, color, center, radius, width) + self.assertEqual(bounding_rect.width, radius * 2) + self.assertEqual(bounding_rect.height, radius * 2) + + +class DrawCircleTest(DrawCircleMixin, DrawTestCase): + """Test draw module function circle. + + This class inherits the general tests from DrawCircleMixin. It is also + the class to add any draw.circle specific tests to. + """ + + +# Commented out to avoid cluttering the test output. Add back in if draw_py +# ever properly supports drawing circles. +# @unittest.skip('draw_py.draw_circle not supported yet') +# class PythonDrawCircleTest(DrawCircleMixin, PythonDrawTestCase): +# """Test draw_py module function draw_circle." +# +# This class inherits the general tests from DrawCircleMixin. It is also +# the class to add any draw_py.draw_circle specific tests to. +# """ + + +### Arc Testing ############################################################### + + +class DrawArcMixin(object): + """Mixin tests for drawing arcs. + + This class contains all the general arc drawing tests. + """ + + def test_arc__args(self): + """Ensures draw arc accepts the correct args.""" + bounds_rect = self.draw_arc( + pygame.Surface((3, 3)), (0, 10, 0, 50), (1, 1, 2, 2), 0, 1, 1 + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_arc__args_without_width(self): + """Ensures draw arc accepts the args without a width.""" + bounds_rect = self.draw_arc( + pygame.Surface((2, 2)), (1, 1, 1, 99), pygame.Rect((0, 0), (2, 2)), 1.1, 2.1 + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_arc__args_with_negative_width(self): + """Ensures draw arc accepts the args with negative width.""" + bounds_rect = self.draw_arc( + pygame.Surface((3, 3)), (10, 10, 50, 50), (1, 1, 2, 2), 0, 1, -1 + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + self.assertEqual(bounds_rect, pygame.Rect(1, 1, 0, 0)) + + def test_arc__args_with_width_gt_radius(self): + """Ensures draw arc accepts the args with + width > rect.w // 2 and width > rect.h // 2. + """ + rect = pygame.Rect((0, 0), (4, 4)) + bounds_rect = self.draw_arc( + pygame.Surface((3, 3)), (10, 10, 50, 50), rect, 0, 45, rect.w // 2 + 1 + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + bounds_rect = self.draw_arc( + pygame.Surface((3, 3)), (10, 10, 50, 50), rect, 0, 45, rect.h // 2 + 1 + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_arc__kwargs(self): + """Ensures draw arc accepts the correct kwargs + with and without a width arg. + """ + kwargs_list = [ + { + "surface": pygame.Surface((4, 4)), + "color": pygame.Color("yellow"), + "rect": pygame.Rect((0, 0), (3, 2)), + "start_angle": 0.5, + "stop_angle": 3, + "width": 1, + }, + { + "surface": pygame.Surface((2, 1)), + "color": (0, 10, 20), + "rect": (0, 0, 2, 2), + "start_angle": 1, + "stop_angle": 3.1, + }, + ] + + for kwargs in kwargs_list: + bounds_rect = self.draw_arc(**kwargs) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_arc__kwargs_order_independent(self): + """Ensures draw arc's kwargs are not order dependent.""" + bounds_rect = self.draw_arc( + stop_angle=1, + start_angle=2.2, + color=(1, 2, 3), + surface=pygame.Surface((3, 2)), + width=1, + rect=pygame.Rect((1, 0), (2, 3)), + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_arc__args_missing(self): + """Ensures draw arc detects any missing required args.""" + surface = pygame.Surface((1, 1)) + color = pygame.Color("red") + rect = pygame.Rect((0, 0), (2, 2)) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_arc(surface, color, rect, 0.1) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_arc(surface, color, rect) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_arc(surface, color) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_arc(surface) + + with self.assertRaises(TypeError): + bounds_rect = self.draw_arc() + + def test_arc__kwargs_missing(self): + """Ensures draw arc detects any missing required kwargs.""" + kwargs = { + "surface": pygame.Surface((1, 2)), + "color": pygame.Color("red"), + "rect": pygame.Rect((1, 0), (2, 2)), + "start_angle": 0.1, + "stop_angle": 2, + "width": 1, + } + + for name in ("stop_angle", "start_angle", "rect", "color", "surface"): + invalid_kwargs = dict(kwargs) + invalid_kwargs.pop(name) # Pop from a copy. + + with self.assertRaises(TypeError): + bounds_rect = self.draw_arc(**invalid_kwargs) + + def test_arc__arg_invalid_types(self): + """Ensures draw arc detects invalid arg types.""" + surface = pygame.Surface((2, 2)) + color = pygame.Color("blue") + rect = pygame.Rect((1, 1), (3, 3)) + + with self.assertRaises(TypeError): + # Invalid width. + bounds_rect = self.draw_arc(surface, color, rect, 0, 1, "1") + + with self.assertRaises(TypeError): + # Invalid stop_angle. + bounds_rect = self.draw_arc(surface, color, rect, 0, "1", 1) + + with self.assertRaises(TypeError): + # Invalid start_angle. + bounds_rect = self.draw_arc(surface, color, rect, "1", 0, 1) + + with self.assertRaises(TypeError): + # Invalid rect. + bounds_rect = self.draw_arc(surface, color, (1, 2, 3, 4, 5), 0, 1, 1) + + with self.assertRaises(TypeError): + # Invalid color. + bounds_rect = self.draw_arc(surface, 2.3, rect, 0, 1, 1) + + with self.assertRaises(TypeError): + # Invalid surface. + bounds_rect = self.draw_arc(rect, color, rect, 0, 1, 1) + + def test_arc__kwarg_invalid_types(self): + """Ensures draw arc detects invalid kwarg types.""" + surface = pygame.Surface((3, 3)) + color = pygame.Color("green") + rect = pygame.Rect((0, 1), (4, 2)) + start = 3 + stop = 4 + kwargs_list = [ + { + "surface": pygame.Surface, # Invalid surface. + "color": color, + "rect": rect, + "start_angle": start, + "stop_angle": stop, + "width": 1, + }, + { + "surface": surface, + "color": 2.3, # Invalid color. + "rect": rect, + "start_angle": start, + "stop_angle": stop, + "width": 1, + }, + { + "surface": surface, + "color": color, + "rect": (0, 0, 0), # Invalid rect. + "start_angle": start, + "stop_angle": stop, + "width": 1, + }, + { + "surface": surface, + "color": color, + "rect": rect, + "start_angle": "1", # Invalid start_angle. + "stop_angle": stop, + "width": 1, + }, + { + "surface": surface, + "color": color, + "rect": rect, + "start_angle": start, + "stop_angle": "1", # Invalid stop_angle. + "width": 1, + }, + { + "surface": surface, + "color": color, + "rect": rect, + "start_angle": start, + "stop_angle": stop, + "width": 1.1, + }, + ] # Invalid width. + + for kwargs in kwargs_list: + with self.assertRaises(TypeError): + bounds_rect = self.draw_arc(**kwargs) + + def test_arc__kwarg_invalid_name(self): + """Ensures draw arc detects invalid kwarg names.""" + surface = pygame.Surface((2, 3)) + color = pygame.Color("cyan") + rect = pygame.Rect((0, 1), (2, 2)) + start = 0.9 + stop = 2.3 + kwargs_list = [ + { + "surface": surface, + "color": color, + "rect": rect, + "start_angle": start, + "stop_angle": stop, + "width": 1, + "invalid": 1, + }, + { + "surface": surface, + "color": color, + "rect": rect, + "start_angle": start, + "stop_angle": stop, + "invalid": 1, + }, + ] + + for kwargs in kwargs_list: + with self.assertRaises(TypeError): + bounds_rect = self.draw_arc(**kwargs) + + def test_arc__args_and_kwargs(self): + """Ensures draw arc accepts a combination of args/kwargs""" + surface = pygame.Surface((3, 1)) + color = (255, 255, 0, 0) + rect = pygame.Rect((1, 0), (2, 3)) + start = 0.6 + stop = 2 + width = 1 + kwargs = { + "surface": surface, + "color": color, + "rect": rect, + "start_angle": start, + "stop_angle": stop, + "width": width, + } + + for name in ("surface", "color", "rect", "start_angle", "stop_angle"): + kwargs.pop(name) + + if "surface" == name: + bounds_rect = self.draw_arc(surface, **kwargs) + elif "color" == name: + bounds_rect = self.draw_arc(surface, color, **kwargs) + elif "rect" == name: + bounds_rect = self.draw_arc(surface, color, rect, **kwargs) + elif "start_angle" == name: + bounds_rect = self.draw_arc(surface, color, rect, start, **kwargs) + elif "stop_angle" == name: + bounds_rect = self.draw_arc(surface, color, rect, start, stop, **kwargs) + else: + bounds_rect = self.draw_arc( + surface, color, rect, start, stop, width, **kwargs + ) + + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_arc__valid_width_values(self): + """Ensures draw arc accepts different width values.""" + arc_color = pygame.Color("yellow") + surface_color = pygame.Color("white") + surface = pygame.Surface((6, 6)) + rect = pygame.Rect((0, 0), (4, 4)) + rect.center = surface.get_rect().center + pos = rect.centerx + 1, rect.centery + 1 + kwargs = { + "surface": surface, + "color": arc_color, + "rect": rect, + "start_angle": 0, + "stop_angle": 7, + "width": None, + } + + for width in (-50, -10, -3, -2, -1, 0, 1, 2, 3, 10, 50): + msg = "width={}".format(width) + surface.fill(surface_color) # Clear for each test. + kwargs["width"] = width + expected_color = arc_color if width > 0 else surface_color + + bounds_rect = self.draw_arc(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color, msg) + self.assertIsInstance(bounds_rect, pygame.Rect, msg) + + def test_arc__valid_stop_angle_values(self): + """Ensures draw arc accepts different stop_angle values.""" + expected_color = pygame.Color("blue") + surface_color = pygame.Color("white") + surface = pygame.Surface((6, 6)) + rect = pygame.Rect((0, 0), (4, 4)) + rect.center = surface.get_rect().center + pos = rect.centerx, rect.centery + 1 + kwargs = { + "surface": surface, + "color": expected_color, + "rect": rect, + "start_angle": -17, + "stop_angle": None, + "width": 1, + } + + for stop_angle in (-10, -5.5, -1, 0, 1, 5.5, 10): + msg = "stop_angle={}".format(stop_angle) + surface.fill(surface_color) # Clear for each test. + kwargs["stop_angle"] = stop_angle + + bounds_rect = self.draw_arc(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color, msg) + self.assertIsInstance(bounds_rect, pygame.Rect, msg) + + def test_arc__valid_start_angle_values(self): + """Ensures draw arc accepts different start_angle values.""" + expected_color = pygame.Color("blue") + surface_color = pygame.Color("white") + surface = pygame.Surface((6, 6)) + rect = pygame.Rect((0, 0), (4, 4)) + rect.center = surface.get_rect().center + pos = rect.centerx + 1, rect.centery + 1 + kwargs = { + "surface": surface, + "color": expected_color, + "rect": rect, + "start_angle": None, + "stop_angle": 17, + "width": 1, + } + + for start_angle in (-10.0, -5.5, -1, 0, 1, 5.5, 10.0): + msg = "start_angle={}".format(start_angle) + surface.fill(surface_color) # Clear for each test. + kwargs["start_angle"] = start_angle + + bounds_rect = self.draw_arc(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color, msg) + self.assertIsInstance(bounds_rect, pygame.Rect, msg) + + def test_arc__valid_rect_formats(self): + """Ensures draw arc accepts different rect formats.""" + expected_color = pygame.Color("red") + surface_color = pygame.Color("black") + surface = pygame.Surface((6, 6)) + rect = pygame.Rect((0, 0), (4, 4)) + rect.center = surface.get_rect().center + pos = rect.centerx + 1, rect.centery + 1 + kwargs = { + "surface": surface, + "color": expected_color, + "rect": None, + "start_angle": 0, + "stop_angle": 7, + "width": 1, + } + rects = (rect, (rect.topleft, rect.size), (rect.x, rect.y, rect.w, rect.h)) + + for rect in rects: + surface.fill(surface_color) # Clear for each test. + kwargs["rect"] = rect + + bounds_rect = self.draw_arc(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_arc__valid_color_formats(self): + """Ensures draw arc accepts different color formats.""" + green_color = pygame.Color("green") + surface_color = pygame.Color("black") + surface = pygame.Surface((6, 6)) + rect = pygame.Rect((0, 0), (4, 4)) + rect.center = surface.get_rect().center + pos = rect.centerx + 1, rect.centery + 1 + kwargs = { + "surface": surface, + "color": None, + "rect": rect, + "start_angle": 0, + "stop_angle": 7, + "width": 1, + } + greens = ( + (0, 255, 0), + (0, 255, 0, 255), + surface.map_rgb(green_color), + green_color, + ) + + for color in greens: + surface.fill(surface_color) # Clear for each test. + kwargs["color"] = color + + if isinstance(color, int): + expected_color = surface.unmap_rgb(color) + else: + expected_color = green_color + + bounds_rect = self.draw_arc(**kwargs) + + self.assertEqual(surface.get_at(pos), expected_color) + self.assertIsInstance(bounds_rect, pygame.Rect) + + def test_arc__invalid_color_formats(self): + """Ensures draw arc handles invalid color formats correctly.""" + pos = (1, 1) + surface = pygame.Surface((4, 3)) + kwargs = { + "surface": surface, + "color": None, + "rect": pygame.Rect(pos, (2, 2)), + "start_angle": 5, + "stop_angle": 6.1, + "width": 1, + } + + for expected_color in (2.3, self): + kwargs["color"] = expected_color + + with self.assertRaises(TypeError): + bounds_rect = self.draw_arc(**kwargs) + + def todo_test_arc(self): + """Ensure draw arc works correctly.""" + self.fail() + + def test_arc__bounding_rect(self): + """Ensures draw arc returns the correct bounding rect. + + Tests arcs on and off the surface and a range of width/thickness + values. + """ + arc_color = pygame.Color("red") + surf_color = pygame.Color("black") + min_width = min_height = 5 + max_width = max_height = 7 + sizes = ((min_width, min_height), (max_width, max_height)) + surface = pygame.Surface((20, 20), 0, 32) + surf_rect = surface.get_rect() + # Make a rect that is bigger than the surface to help test drawing + # arcs off and partially off the surface. + big_rect = surf_rect.inflate(min_width * 2 + 1, min_height * 2 + 1) + + # Max angle allows for a full circle to be drawn. + start_angle = 0 + stop_angles = (0, 2, 3, 5, math.ceil(2 * math.pi)) + + for pos in rect_corners_mids_and_center( + surf_rect + ) + rect_corners_mids_and_center(big_rect): + # Each of the arc's rect position attributes will be set to the pos + # value. + for attr in RECT_POSITION_ATTRIBUTES: + # Test using different rect sizes, thickness values and stop + # angles. + for width, height in sizes: + arc_rect = pygame.Rect((0, 0), (width, height)) + setattr(arc_rect, attr, pos) + + for thickness in (0, 1, 2, 3, min(width, height)): + for stop_angle in stop_angles: + surface.fill(surf_color) # Clear for each test. + + bounding_rect = self.draw_arc( + surface, + arc_color, + arc_rect, + start_angle, + stop_angle, + thickness, + ) + + # Calculating the expected_rect after the arc + # is drawn (it uses what is actually drawn). + expected_rect = create_bounding_rect( + surface, surf_color, arc_rect.topleft + ) + + self.assertEqual( + bounding_rect, + expected_rect, + "thickness={}".format(thickness), + ) + + def test_arc__surface_clip(self): + """Ensures draw arc respects a surface's clip area.""" + surfw = surfh = 30 + start = 0.1 + end = 0 # end < start so a full circle will be drawn + arc_color = pygame.Color("red") + surface_color = pygame.Color("green") + surface = pygame.Surface((surfw, surfh)) + surface.fill(surface_color) + + clip_rect = pygame.Rect((0, 0), (11, 11)) + clip_rect.center = surface.get_rect().center + pos_rect = clip_rect.copy() # Manages the arc's pos. + + for thickness in (1, 3): # Different line widths. + # Test centering the arc along the clip rect's edge. + for center in rect_corners_mids_and_center(clip_rect): + # Get the expected points by drawing the arc without the + # clip area set. + pos_rect.center = center + surface.set_clip(None) + surface.fill(surface_color) + self.draw_arc(surface, arc_color, pos_rect, start, end, thickness) + expected_pts = get_color_points(surface, arc_color, clip_rect) + + # Clear the surface and set the clip area. Redraw the arc + # and check that only the clip area is modified. + surface.fill(surface_color) + surface.set_clip(clip_rect) + + self.draw_arc(surface, arc_color, pos_rect, start, end, thickness) + + surface.lock() # For possible speed up. + + # Check all the surface points to ensure only the expected_pts + # are the arc_color. + for pt in ((x, y) for x in range(surfw) for y in range(surfh)): + if pt in expected_pts: + expected_color = arc_color + else: + expected_color = surface_color + + self.assertEqual(surface.get_at(pt), expected_color, pt) + + surface.unlock() + + +class DrawArcTest(DrawArcMixin, DrawTestCase): + """Test draw module function arc. + + This class inherits the general tests from DrawArcMixin. It is also the + class to add any draw.arc specific tests to. + """ + + +# Commented out to avoid cluttering the test output. Add back in if draw_py +# ever properly supports drawing arcs. +# @unittest.skip('draw_py.draw_arc not supported yet') +# class PythonDrawArcTest(DrawArcMixin, PythonDrawTestCase): +# """Test draw_py module function draw_arc. +# +# This class inherits the general tests from DrawArcMixin. It is also the +# class to add any draw_py.draw_arc specific tests to. +# """ + + +### Draw Module Testing ####################################################### + + +class DrawModuleTest(unittest.TestCase): + """General draw module tests.""" + + def test_path_data_validation(self): + """Test validation of multi-point drawing methods. + + See bug #521 + """ + surf = pygame.Surface((5, 5)) + rect = pygame.Rect(0, 0, 5, 5) + bad_values = ( + "text", + b"bytes", + 1 + 1j, # string, bytes, complex, + object(), + (lambda x: x), + ) # object, function + bad_points = list(bad_values) + [(1,), (1, 2, 3)] # wrong tuple length + bad_points.extend((1, v) for v in bad_values) # one wrong value + good_path = [(1, 1), (1, 3), (3, 3), (3, 1)] + # A) draw.lines + check_pts = [(x, y) for x in range(5) for y in range(5)] + + for method, is_polgon in ( + (draw.lines, 0), + (draw.aalines, 0), + (draw.polygon, 1), + ): + for val in bad_values: + # 1. at the beginning + draw.rect(surf, RED, rect, 0) + with self.assertRaises(TypeError): + if is_polgon: + method(surf, GREEN, [val] + good_path, 0) + else: + method(surf, GREEN, True, [val] + good_path) + + # make sure, nothing was drawn : + self.assertTrue(all(surf.get_at(pt) == RED for pt in check_pts)) + + # 2. not at the beginning (was not checked) + draw.rect(surf, RED, rect, 0) + with self.assertRaises(TypeError): + path = good_path[:2] + [val] + good_path[2:] + if is_polgon: + method(surf, GREEN, path, 0) + else: + method(surf, GREEN, True, path) + + # make sure, nothing was drawn : + self.assertTrue(all(surf.get_at(pt) == RED for pt in check_pts)) + + def test_color_validation(self): + surf = pygame.Surface((10, 10)) + colors = 123456, (1, 10, 100), RED, "#ab12df", "red" + points = ((0, 0), (1, 1), (1, 0)) + + # 1. valid colors + for col in colors: + draw.line(surf, col, (0, 0), (1, 1)) + draw.aaline(surf, col, (0, 0), (1, 1)) + draw.aalines(surf, col, True, points) + draw.lines(surf, col, True, points) + draw.arc(surf, col, pygame.Rect(0, 0, 3, 3), 15, 150) + draw.ellipse(surf, col, pygame.Rect(0, 0, 3, 6), 1) + draw.circle(surf, col, (7, 3), 2) + draw.polygon(surf, col, points, 0) + + # 2. invalid colors + for col in (1.256, object(), None): + with self.assertRaises(TypeError): + draw.line(surf, col, (0, 0), (1, 1)) + + with self.assertRaises(TypeError): + draw.aaline(surf, col, (0, 0), (1, 1)) + + with self.assertRaises(TypeError): + draw.aalines(surf, col, True, points) + + with self.assertRaises(TypeError): + draw.lines(surf, col, True, points) + + with self.assertRaises(TypeError): + draw.arc(surf, col, pygame.Rect(0, 0, 3, 3), 15, 150) + + with self.assertRaises(TypeError): + draw.ellipse(surf, col, pygame.Rect(0, 0, 3, 6), 1) + + with self.assertRaises(TypeError): + draw.circle(surf, col, (7, 3), 2) + + with self.assertRaises(TypeError): + draw.polygon(surf, col, points, 0) + + +############################################################################### + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/event_test.py b/venv/Lib/site-packages/pygame/tests/event_test.py new file mode 100644 index 0000000..8d7dfe0 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/event_test.py @@ -0,0 +1,840 @@ +import os +import sys +import unittest +import collections + +import pygame + + +EVENT_TYPES = ( + # pygame.NOEVENT, + # pygame.ACTIVEEVENT, + pygame.KEYDOWN, + pygame.KEYUP, + pygame.MOUSEMOTION, + pygame.MOUSEBUTTONDOWN, + pygame.MOUSEBUTTONUP, + pygame.JOYAXISMOTION, + pygame.JOYBALLMOTION, + pygame.JOYHATMOTION, + pygame.JOYBUTTONDOWN, + pygame.JOYBUTTONUP, + pygame.VIDEORESIZE, + pygame.VIDEOEXPOSE, + pygame.QUIT, + pygame.SYSWMEVENT, + pygame.USEREVENT, + # pygame.NUMEVENTS, +) + +EVENT_TEST_PARAMS = collections.defaultdict(dict) +EVENT_TEST_PARAMS.update( + { + pygame.KEYDOWN: {"key": pygame.K_SPACE}, + pygame.KEYUP: {"key": pygame.K_SPACE}, + pygame.MOUSEMOTION: dict(), + pygame.MOUSEBUTTONDOWN: dict(button=1), + pygame.MOUSEBUTTONUP: dict(button=1), + } +) + + +NAMES_AND_EVENTS = ( + ("NoEvent", pygame.NOEVENT), + ("ActiveEvent", pygame.ACTIVEEVENT), + ("KeyDown", pygame.KEYDOWN), + ("KeyUp", pygame.KEYUP), + ("MouseMotion", pygame.MOUSEMOTION), + ("MouseButtonDown", pygame.MOUSEBUTTONDOWN), + ("MouseButtonUp", pygame.MOUSEBUTTONUP), + ("JoyAxisMotion", pygame.JOYAXISMOTION), + ("JoyBallMotion", pygame.JOYBALLMOTION), + ("JoyHatMotion", pygame.JOYHATMOTION), + ("JoyButtonDown", pygame.JOYBUTTONDOWN), + ("JoyButtonUp", pygame.JOYBUTTONUP), + ("VideoResize", pygame.VIDEORESIZE), + ("VideoExpose", pygame.VIDEOEXPOSE), + ("Quit", pygame.QUIT), + ("SysWMEvent", pygame.SYSWMEVENT), + ("MidiIn", pygame.MIDIIN), + ("MidiOut", pygame.MIDIOUT), + ("UserEvent", pygame.USEREVENT), + ("Unknown", 0xFFFF), + ("FingerMotion", pygame.FINGERMOTION), + ("FingerDown", pygame.FINGERDOWN), + ("FingerUp", pygame.FINGERUP), + ("MultiGesture", pygame.MULTIGESTURE), + ("MouseWheel", pygame.MOUSEWHEEL), + ("TextInput", pygame.TEXTINPUT), + ("TextEditing", pygame.TEXTEDITING), + ("ControllerAxisMotion", pygame.CONTROLLERAXISMOTION), + ("ControllerButtonDown", pygame.CONTROLLERBUTTONDOWN), + ("ControllerButtonUp", pygame.CONTROLLERBUTTONUP), + ("ControllerDeviceAdded", pygame.CONTROLLERDEVICEADDED), + ("ControllerDeviceRemoved", pygame.CONTROLLERDEVICEREMOVED), + ("ControllerDeviceMapped", pygame.CONTROLLERDEVICEREMAPPED), + ("DropFile", pygame.DROPFILE), +) + +# Add in any SDL 2.0.4 specific events. +if pygame.get_sdl_version() >= (2, 0, 4): + NAMES_AND_EVENTS += ( + ("AudioDeviceAdded", pygame.AUDIODEVICEADDED), + ("AudioDeviceRemoved", pygame.AUDIODEVICEREMOVED), + ) + +# Add in any SDL 2.0.5 specific events. +if pygame.get_sdl_version() >= (2, 0, 5): + NAMES_AND_EVENTS += ( + ("DropText", pygame.DROPTEXT), + ("DropBegin", pygame.DROPBEGIN), + ("DropComplete", pygame.DROPCOMPLETE), + ) + + +class EventTypeTest(unittest.TestCase): + def test_Event(self): + """Ensure an Event object can be created.""" + e = pygame.event.Event(pygame.USEREVENT, some_attr=1, other_attr="1") + + self.assertEqual(e.some_attr, 1) + self.assertEqual(e.other_attr, "1") + + # Event now uses tp_dictoffset and tp_members: request 62 + # on Motherhamster Bugzilla. + self.assertEqual(e.type, pygame.USEREVENT) + self.assertIs(e.dict, e.__dict__) + + e.some_attr = 12 + + self.assertEqual(e.some_attr, 12) + + e.new_attr = 15 + + self.assertEqual(e.new_attr, 15) + + self.assertRaises(AttributeError, setattr, e, "type", 0) + self.assertRaises(AttributeError, setattr, e, "dict", None) + + # Ensure attributes are visible to dir(), part of the original + # posted request. + d = dir(e) + attrs = ("type", "dict", "__dict__", "some_attr", "other_attr", "new_attr") + + for attr in attrs: + self.assertIn(attr, d) + + def test_as_str(self): + # Bug reported on Pygame mailing list July 24, 2011: + # For Python 3.x str(event) to raises an UnicodeEncodeError when + # an event attribute is a string with a non-ascii character. + try: + str(pygame.event.Event(EVENT_TYPES[0], a="\xed")) + except UnicodeEncodeError: + self.fail("Event object raised exception for non-ascii character") + # Passed. + + +race_condition_notification = """ +This test is dependent on timing. The event queue is cleared in preparation for +tests. There is a small window where outside events from the OS may have effected +results. Try running the test again. +""" + + +class EventModuleArgsTest(unittest.TestCase): + def setUp(self): + pygame.display.init() + pygame.event.clear() + + def tearDown(self): + pygame.display.quit() + + def test_get(self): + pygame.event.get() + pygame.event.get(None) + pygame.event.get(None, True) + + pygame.event.get(pump=False) + pygame.event.get(pump=True) + pygame.event.get(eventtype=None) + pygame.event.get(eventtype=[pygame.KEYUP, pygame.KEYDOWN]) + pygame.event.get(eventtype=pygame.USEREVENT, pump=False) + + def test_clear(self): + pygame.event.clear() + pygame.event.clear(None) + pygame.event.clear(None, True) + + pygame.event.clear(pump=False) + pygame.event.clear(pump=True) + pygame.event.clear(eventtype=None) + pygame.event.clear(eventtype=[pygame.KEYUP, pygame.KEYDOWN]) + pygame.event.clear(eventtype=pygame.USEREVENT, pump=False) + + def test_peek(self): + pygame.event.peek() + pygame.event.peek(None) + pygame.event.peek(None, True) + + pygame.event.peek(pump=False) + pygame.event.peek(pump=True) + pygame.event.peek(eventtype=None) + pygame.event.peek(eventtype=[pygame.KEYUP, pygame.KEYDOWN]) + pygame.event.peek(eventtype=pygame.USEREVENT, pump=False) + + +class EventCustomTypeTest(unittest.TestCase): + """Those tests are special in that they need the _custom_event counter to + be reset before and/or after being run.""" + + def setUp(self): + pygame.quit() + pygame.init() + pygame.display.init() + + def tearDown(self): + pygame.quit() + + def test_custom_type(self): + self.assertEqual(pygame.event.custom_type(), pygame.USEREVENT + 1) + atype = pygame.event.custom_type() + atype2 = pygame.event.custom_type() + + self.assertEqual(atype, atype2 - 1) + + ev = pygame.event.Event(atype) + pygame.event.post(ev) + queue = pygame.event.get(atype) + self.assertEqual(len(queue), 1) + self.assertEqual(queue[0].type, atype) + + def test_custom_type__end_boundary(self): + """Ensure custom_type() raises error when no more custom types. + + The last allowed custom type number should be (pygame.NUMEVENTS - 1). + """ + start = pygame.event.custom_type() + 1 + for i in range(start, pygame.NUMEVENTS): + last = pygame.event.custom_type() + self.assertEqual(last, pygame.NUMEVENTS - 1) + with self.assertRaises(pygame.error): + pygame.event.custom_type() + + def test_custom_type__reset(self): + """Ensure custom events get 'deregistered' by quit().""" + before = pygame.event.custom_type() + self.assertEqual(before, pygame.event.custom_type() - 1) + pygame.quit() + pygame.init() + pygame.display.init() + self.assertEqual(before, pygame.event.custom_type()) + + +class EventModuleTest(unittest.TestCase): + def _assertCountEqual(self, *args, **kwargs): + # Handle method name differences between Python versions. + # Is this still needed? + self.assertCountEqual(*args, **kwargs) + + def _assertExpectedEvents(self, expected, got): + """Find events like expected events, raise on unexpected or missing, + ignore additional event properties if expected properties are present.""" + + # This does greedy matching, don't encode an NP-hard problem + # into your input data, *please* + items_left = got[:] + for expected_element in expected: + for item in items_left: + for key in expected_element.__dict__: + if item.__dict__[key] != expected_element.__dict__[key]: + break + else: + # found item! + items_left.remove(item) + break + else: + raise AssertionError( + "Expected " + + str(expected_element) + + " among remaining events " + + str(items_left) + + " out of " + + str(got) + ) + if len(items_left) > 0: + raise AssertionError("Unexpected Events: " + str(items_left)) + + def setUp(self): + pygame.display.init() + pygame.event.clear() # flush events + + def tearDown(self): + pygame.event.clear() # flush events + pygame.display.quit() + + def test_event_numevents(self): + """Ensures NUMEVENTS does not exceed the maximum SDL number of events.""" + # Ref: https://www.libsdl.org/tmp/SDL/include/SDL_events.h + MAX_SDL_EVENTS = 0xFFFF # SDL_LASTEVENT = 0xFFFF + + self.assertLessEqual(pygame.NUMEVENTS, MAX_SDL_EVENTS) + + def test_event_attribute(self): + e1 = pygame.event.Event(pygame.USEREVENT, attr1="attr1") + self.assertEqual(e1.attr1, "attr1") + + def test_set_blocked(self): + """Ensure events can be blocked from the queue.""" + event = EVENT_TYPES[0] + pygame.event.set_blocked(event) + + self.assertTrue(pygame.event.get_blocked(event)) + + pygame.event.post( + pygame.event.Event(event, **EVENT_TEST_PARAMS[EVENT_TYPES[0]]) + ) + ret = pygame.event.get() + should_be_blocked = [e for e in ret if e.type == event] + + self.assertEqual(should_be_blocked, []) + + def test_set_blocked__event_sequence(self): + """Ensure a sequence of event types can be blocked.""" + event_types = [ + pygame.KEYDOWN, + pygame.KEYUP, + pygame.MOUSEMOTION, + pygame.MOUSEBUTTONDOWN, + pygame.MOUSEBUTTONUP, + ] + + pygame.event.set_blocked(event_types) + + for etype in event_types: + self.assertTrue(pygame.event.get_blocked(etype)) + + def test_set_blocked_all(self): + """Ensure all events can be unblocked at once.""" + pygame.event.set_blocked(None) + + for e in EVENT_TYPES: + self.assertTrue(pygame.event.get_blocked(e)) + + def test_post__and_poll(self): + """Ensure events can be posted to the queue.""" + e1 = pygame.event.Event(pygame.USEREVENT, attr1="attr1") + pygame.event.post(e1) + posted_event = pygame.event.poll() + + self.assertEqual(e1.attr1, posted_event.attr1, race_condition_notification) + + # fuzzing event types + for i in range(1, 13): + pygame.event.post( + pygame.event.Event(EVENT_TYPES[i], **EVENT_TEST_PARAMS[EVENT_TYPES[i]]) + ) + + self.assertEqual( + pygame.event.poll().type, EVENT_TYPES[i], race_condition_notification + ) + + def test_post_and_get_keydown(self): + """Ensure keydown events can be posted to the queue.""" + activemodkeys = pygame.key.get_mods() + + events = [ + pygame.event.Event(pygame.KEYDOWN, key=pygame.K_p), + pygame.event.Event(pygame.KEYDOWN, key=pygame.K_y, mod=activemodkeys), + pygame.event.Event(pygame.KEYDOWN, key=pygame.K_g, unicode="g"), + pygame.event.Event(pygame.KEYDOWN, key=pygame.K_a, unicode=None), + pygame.event.Event(pygame.KEYDOWN, key=pygame.K_m, mod=None, window=None), + pygame.event.Event( + pygame.KEYDOWN, key=pygame.K_e, mod=activemodkeys, unicode="e" + ), + ] + + for e in events: + pygame.event.post(e) + posted_event = pygame.event.poll() + self.assertEqual(e, posted_event, race_condition_notification) + + def test_post_large_user_event(self): + pygame.event.post(pygame.event.Event(pygame.USEREVENT, {"a": "a" * 1024})) + e = pygame.event.poll() + + self.assertEqual(e.type, pygame.USEREVENT) + self.assertEqual(e.a, "a" * 1024) + + def test_post_blocked(self): + """ + Test blocked events are not posted. Also test whether post() + returns a boolean correctly + """ + pygame.event.set_blocked(pygame.USEREVENT) + self.assertFalse(pygame.event.post(pygame.event.Event(pygame.USEREVENT))) + self.assertFalse(pygame.event.poll()) + pygame.event.set_allowed(pygame.USEREVENT) + self.assertTrue(pygame.event.post(pygame.event.Event(pygame.USEREVENT))) + self.assertEqual(pygame.event.poll(), pygame.event.Event(pygame.USEREVENT)) + + def test_get(self): + """Ensure get() retrieves all the events on the queue.""" + event_cnt = 10 + for _ in range(event_cnt): + pygame.event.post(pygame.event.Event(pygame.USEREVENT)) + + queue = pygame.event.get() + + self.assertEqual(len(queue), event_cnt) + self.assertTrue(all(e.type == pygame.USEREVENT for e in queue)) + + def test_get_type(self): + ev = pygame.event.Event(pygame.USEREVENT) + pygame.event.post(ev) + queue = pygame.event.get(pygame.USEREVENT) + self.assertEqual(len(queue), 1) + self.assertEqual(queue[0].type, pygame.USEREVENT) + + TESTEVENTS = 10 + for _ in range(TESTEVENTS): + pygame.event.post(ev) + q = pygame.event.get([pygame.USEREVENT]) + self.assertEqual(len(q), TESTEVENTS) + for event in q: + self.assertEqual(event, ev) + + def test_get_exclude_throw(self): + self.assertRaises( + pygame.error, pygame.event.get, pygame.KEYDOWN, False, pygame.KEYUP + ) + + def test_get_exclude(self): + pygame.event.post(pygame.event.Event(pygame.USEREVENT)) + pygame.event.post(pygame.event.Event(pygame.KEYDOWN)) + + queue = pygame.event.get(exclude=pygame.KEYDOWN) + self.assertEqual(len(queue), 1) + self.assertEqual(queue[0].type, pygame.USEREVENT) + + pygame.event.post(pygame.event.Event(pygame.KEYUP)) + pygame.event.post(pygame.event.Event(pygame.USEREVENT)) + queue = pygame.event.get(exclude=(pygame.KEYDOWN, pygame.KEYUP)) + self.assertEqual(len(queue), 1) + self.assertEqual(queue[0].type, pygame.USEREVENT) + + queue = pygame.event.get() + self.assertEqual(len(queue), 2) + + def test_get__empty_queue(self): + """Ensure get() works correctly on an empty queue.""" + expected_events = [] + pygame.event.clear() + + # Ensure all events can be checked. + retrieved_events = pygame.event.get() + + self.assertListEqual(retrieved_events, expected_events) + + # Ensure events can be checked individually. + for event_type in EVENT_TYPES: + retrieved_events = pygame.event.get(event_type) + + self.assertListEqual(retrieved_events, expected_events) + + # Ensure events can be checked as a sequence. + retrieved_events = pygame.event.get(EVENT_TYPES) + + self.assertListEqual(retrieved_events, expected_events) + + def test_get__event_sequence(self): + """Ensure get() can handle a sequence of event types.""" + event_types = [pygame.KEYDOWN, pygame.KEYUP, pygame.MOUSEMOTION] + other_event_type = pygame.MOUSEBUTTONUP + + # Test when no events in the queue. + expected_events = [] + pygame.event.clear() + retrieved_events = pygame.event.get(event_types) + + # don't use self._assertCountEqual here. This checks for + # expected properties in events, and ignores unexpected ones, for + # forward compatibility with SDL2. + self._assertExpectedEvents(expected=expected_events, got=retrieved_events) + + # Test when an event type not in the list is in the queue. + expected_events = [] + pygame.event.clear() + pygame.event.post( + pygame.event.Event(other_event_type, **EVENT_TEST_PARAMS[other_event_type]) + ) + + retrieved_events = pygame.event.get(event_types) + + self._assertExpectedEvents(expected=expected_events, got=retrieved_events) + + # Test when 1 event type in the list is in the queue. + expected_events = [ + pygame.event.Event(event_types[0], **EVENT_TEST_PARAMS[event_types[0]]) + ] + pygame.event.clear() + pygame.event.post(expected_events[0]) + + retrieved_events = pygame.event.get(event_types) + + self._assertExpectedEvents(expected=expected_events, got=retrieved_events) + + # Test all events in the list are in the queue. + pygame.event.clear() + expected_events = [] + + for etype in event_types: + expected_events.append( + pygame.event.Event(etype, **EVENT_TEST_PARAMS[etype]) + ) + pygame.event.post(expected_events[-1]) + + retrieved_events = pygame.event.get(event_types) + + self._assertExpectedEvents(expected=expected_events, got=retrieved_events) + + def test_clear(self): + """Ensure clear() removes all the events on the queue.""" + for e in EVENT_TYPES: + pygame.event.post(pygame.event.Event(e, **EVENT_TEST_PARAMS[e])) + poll_event = pygame.event.poll() + + self.assertNotEqual(poll_event.type, pygame.NOEVENT) + + pygame.event.clear() + poll_event = pygame.event.poll() + + self.assertEqual(poll_event.type, pygame.NOEVENT, race_condition_notification) + + def test_clear__empty_queue(self): + """Ensure clear() works correctly on an empty queue.""" + expected_events = [] + pygame.event.clear() + + # Test calling clear() on an already empty queue. + pygame.event.clear() + + retrieved_events = pygame.event.get() + + self.assertListEqual(retrieved_events, expected_events) + + def test_clear__event_sequence(self): + """Ensure a sequence of event types can be cleared from the queue.""" + cleared_event_types = EVENT_TYPES[:5] + expected_event_types = EVENT_TYPES[5:10] + expected_events = [] + + # Add the events to the queue. + for etype in cleared_event_types: + pygame.event.post(pygame.event.Event(etype, **EVENT_TEST_PARAMS[etype])) + + for etype in expected_events: + expected_events.append( + pygame.event.Event(etype, **EVENT_TEST_PARAMS[etype]) + ) + pygame.event.post(expected_events[-1]) + + # Clear the cleared_events from the queue. + pygame.event.clear(cleared_event_types) + + # Check the rest of the events in the queue. + remaining_events = pygame.event.get() + + self._assertCountEqual(remaining_events, expected_events) + + def test_event_name(self): + """Ensure event_name() returns the correct event name.""" + for expected_name, event in NAMES_AND_EVENTS: + self.assertEqual( + pygame.event.event_name(event), expected_name, "0x{:X}".format(event) + ) + + def test_event_name__userevent_range(self): + """Ensures event_name() returns the correct name for user events. + + Tests the full range of user events. + """ + expected_name = "UserEvent" + + for event in range(pygame.USEREVENT, pygame.NUMEVENTS): + self.assertEqual( + pygame.event.event_name(event), expected_name, "0x{:X}".format(event) + ) + + def test_event_name__userevent_boundary(self): + """Ensures event_name() does not return 'UserEvent' for events + just outside the user event range. + """ + unexpected_name = "UserEvent" + + for event in (pygame.USEREVENT - 1, pygame.NUMEVENTS): + self.assertNotEqual( + pygame.event.event_name(event), unexpected_name, "0x{:X}".format(event) + ) + + def test_wait(self): + """Ensure wait() waits for an event on the queue.""" + # Test case without timeout. + event = pygame.event.Event(EVENT_TYPES[0], **EVENT_TEST_PARAMS[EVENT_TYPES[0]]) + pygame.event.post(event) + wait_event = pygame.event.wait() + + self.assertEqual(wait_event.type, event.type) + + # Test case with timeout and no event in the queue. + wait_event = pygame.event.wait(250) + self.assertEqual(wait_event.type, pygame.NOEVENT) + + # Test case with timeout and an event in the queue. + event = pygame.event.Event(EVENT_TYPES[0], **EVENT_TEST_PARAMS[EVENT_TYPES[0]]) + pygame.event.post(event) + wait_event = pygame.event.wait(250) + + self.assertEqual(wait_event.type, event.type) + + def test_peek(self): + """Ensure queued events can be peeked at.""" + event_types = [pygame.KEYDOWN, pygame.KEYUP, pygame.MOUSEMOTION] + + for event_type in event_types: + pygame.event.post( + pygame.event.Event(event_type, **EVENT_TEST_PARAMS[event_type]) + ) + + # Ensure events can be checked individually. + for event_type in event_types: + self.assertTrue(pygame.event.peek(event_type)) + + # Ensure events can be checked as a sequence. + self.assertTrue(pygame.event.peek(event_types)) + + def test_peek__event_sequence(self): + """Ensure peek() can handle a sequence of event types.""" + event_types = [pygame.KEYDOWN, pygame.KEYUP, pygame.MOUSEMOTION] + other_event_type = pygame.MOUSEBUTTONUP + + # Test when no events in the queue. + pygame.event.clear() + peeked = pygame.event.peek(event_types) + + self.assertFalse(peeked) + + # Test when an event type not in the list is in the queue. + pygame.event.clear() + pygame.event.post( + pygame.event.Event(other_event_type, **EVENT_TEST_PARAMS[other_event_type]) + ) + + peeked = pygame.event.peek(event_types) + + self.assertFalse(peeked) + + # Test when 1 event type in the list is in the queue. + pygame.event.clear() + pygame.event.post( + pygame.event.Event(event_types[0], **EVENT_TEST_PARAMS[event_types[0]]) + ) + + peeked = pygame.event.peek(event_types) + + self.assertTrue(peeked) + + # Test all events in the list are in the queue. + pygame.event.clear() + for etype in event_types: + pygame.event.post(pygame.event.Event(etype, **EVENT_TEST_PARAMS[etype])) + + peeked = pygame.event.peek(event_types) + + self.assertTrue(peeked) + + def test_peek__empty_queue(self): + """Ensure peek() works correctly on an empty queue.""" + pygame.event.clear() + + # Ensure all events can be checked. + peeked = pygame.event.peek() + + self.assertFalse(peeked) + + # Ensure events can be checked individually. + for event_type in EVENT_TYPES: + peeked = pygame.event.peek(event_type) + self.assertFalse(peeked) + + # Ensure events can be checked as a sequence. + peeked = pygame.event.peek(EVENT_TYPES) + + self.assertFalse(peeked) + + def test_set_allowed(self): + """Ensure a blocked event type can be unblocked/allowed.""" + event = EVENT_TYPES[0] + pygame.event.set_blocked(event) + + self.assertTrue(pygame.event.get_blocked(event)) + + pygame.event.set_allowed(event) + + self.assertFalse(pygame.event.get_blocked(event)) + + def test_set_allowed__event_sequence(self): + """Ensure a sequence of blocked event types can be unblocked/allowed.""" + event_types = [ + pygame.KEYDOWN, + pygame.KEYUP, + pygame.MOUSEMOTION, + pygame.MOUSEBUTTONDOWN, + pygame.MOUSEBUTTONUP, + ] + pygame.event.set_blocked(event_types) + + pygame.event.set_allowed(event_types) + + for etype in event_types: + self.assertFalse(pygame.event.get_blocked(etype)) + + def test_set_allowed_all(self): + """Ensure all events can be unblocked/allowed at once.""" + pygame.event.set_blocked(None) + + for e in EVENT_TYPES: + self.assertTrue(pygame.event.get_blocked(e)) + + pygame.event.set_allowed(None) + + for e in EVENT_TYPES: + self.assertFalse(pygame.event.get_blocked(e)) + + def test_pump(self): + """Ensure pump() functions properly.""" + pygame.event.pump() + + # @unittest.skipIf( + # os.environ.get("SDL_VIDEODRIVER") == "dummy", + # 'requires the SDL_VIDEODRIVER to be a non "dummy" value', + # ) + # Fails on SDL 2.0.18 + @unittest.skip("flaky test, and broken on 2.0.18 windows") + def test_set_grab__and_get_symmetric(self): + """Ensure event grabbing can be enabled and disabled. + + WARNING: Moving the mouse off the display during this test can cause it + to fail. + """ + surf = pygame.display.set_mode((10, 10)) + pygame.event.set_grab(True) + + self.assertTrue(pygame.event.get_grab()) + + pygame.event.set_grab(False) + + self.assertFalse(pygame.event.get_grab()) + + def test_event_equality(self): + """Ensure an events can be compared correctly.""" + a = pygame.event.Event(EVENT_TYPES[0], a=1) + b = pygame.event.Event(EVENT_TYPES[0], a=1) + c = pygame.event.Event(EVENT_TYPES[1], a=1) + d = pygame.event.Event(EVENT_TYPES[0], a=2) + + self.assertTrue(a == a) + self.assertFalse(a != a) + self.assertTrue(a == b) + self.assertFalse(a != b) + self.assertTrue(a != c) + self.assertFalse(a == c) + self.assertTrue(a != d) + self.assertFalse(a == d) + + def test_get_blocked(self): + """Ensure an event's blocked state can be retrieved.""" + # Test each event is not blocked. + pygame.event.set_allowed(None) + + for etype in EVENT_TYPES: + blocked = pygame.event.get_blocked(etype) + + self.assertFalse(blocked) + + # Test each event type is blocked. + pygame.event.set_blocked(None) + + for etype in EVENT_TYPES: + blocked = pygame.event.get_blocked(etype) + + self.assertTrue(blocked) + + def test_get_blocked__event_sequence(self): + """Ensure get_blocked() can handle a sequence of event types.""" + event_types = [ + pygame.KEYDOWN, + pygame.KEYUP, + pygame.MOUSEMOTION, + pygame.MOUSEBUTTONDOWN, + pygame.MOUSEBUTTONUP, + ] + + # Test no event types in the list are blocked. + blocked = pygame.event.get_blocked(event_types) + + self.assertFalse(blocked) + + # Test when 1 event type in the list is blocked. + pygame.event.set_blocked(event_types[2]) + + blocked = pygame.event.get_blocked(event_types) + + self.assertTrue(blocked) + + # Test all event types in the list are blocked. + pygame.event.set_blocked(event_types) + + blocked = pygame.event.get_blocked(event_types) + + self.assertTrue(blocked) + + # @unittest.skipIf( + # os.environ.get("SDL_VIDEODRIVER") == "dummy", + # 'requires the SDL_VIDEODRIVER to be a non "dummy" value', + # ) + # Fails on SDL 2.0.18 + @unittest.skip("flaky test, and broken on 2.0.18 windows") + def test_get_grab(self): + """Ensure get_grab() works as expected""" + surf = pygame.display.set_mode((10, 10)) + # Test 5 times + for i in range(5): + pygame.event.set_grab(i % 2) + self.assertEqual(pygame.event.get_grab(), i % 2) + + def test_poll(self): + """Ensure poll() works as expected""" + pygame.event.clear() + ev = pygame.event.poll() + # poll() on empty queue should return NOEVENT + self.assertEqual(ev.type, pygame.NOEVENT) + + # test poll returns stuff in same order + e1 = pygame.event.Event(pygame.USEREVENT) + e2 = pygame.event.Event(pygame.KEYDOWN, key=pygame.K_a) + e3 = pygame.event.Event(pygame.KEYUP, key=pygame.K_a) + pygame.event.post(e1) + pygame.event.post(e2) + pygame.event.post(e3) + + self.assertEqual(pygame.event.poll().type, e1.type) + self.assertEqual(pygame.event.poll().type, e2.type) + self.assertEqual(pygame.event.poll().type, e3.type) + self.assertEqual(pygame.event.poll().type, pygame.NOEVENT) + + +################################################################################ + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/fixtures/fonts/A_PyGameMono-8.png b/venv/Lib/site-packages/pygame/tests/fixtures/fonts/A_PyGameMono-8.png new file mode 100644 index 0000000..b15961f Binary files /dev/null and b/venv/Lib/site-packages/pygame/tests/fixtures/fonts/A_PyGameMono-8.png differ diff --git a/venv/Lib/site-packages/pygame/tests/fixtures/fonts/PyGameMono-18-100dpi.bdf b/venv/Lib/site-packages/pygame/tests/fixtures/fonts/PyGameMono-18-100dpi.bdf new file mode 100644 index 0000000..a88f083 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/fixtures/fonts/PyGameMono-18-100dpi.bdf @@ -0,0 +1,165 @@ +STARTFONT 2.1 +FONT -FontForge-PyGameMono-Medium-R-Normal--25-180-100-100-M-250-ISO10646-1 +SIZE 18 100 100 +FONTBOUNDINGBOX 21 22 0 0 +COMMENT "Generated by fontforge, http://fontforge.sourceforge.net" +COMMENT "Created by Lenard Lindstrom,,, with FontForge 2.0 (http://fontforge.sf.net)" +STARTPROPERTIES 29 +FOUNDRY "FontForge" +FAMILY_NAME "PyGameMono" +WEIGHT_NAME "Medium" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 25 +POINT_SIZE 180 +RESOLUTION_X 100 +RESOLUTION_Y 100 +SPACING "M" +AVERAGE_WIDTH 250 +CHARSET_REGISTRY "ISO10646" +CHARSET_ENCODING "1" +FONTNAME_REGISTRY "" +CHARSET_COLLECTIONS "ISO10646-1" +FONT_NAME "PyGameMono" +FACE_NAME "PyGame Mono" +FONT_VERSION "001.000" +FONT_ASCENT 20 +FONT_DESCENT 5 +UNDERLINE_POSITION -2 +UNDERLINE_THICKNESS 2 +RAW_ASCENT 800 +RAW_DESCENT 200 +RELATIVE_WEIGHT 50 +RELATIVE_SETWIDTH 50 +FIGURE_WIDTH -1 +AVG_UPPERCASE_WIDTH 250 +ENDPROPERTIES +CHARS 5 +STARTCHAR .notdef +ENCODING 0 +SWIDTH 1000 0 +DWIDTH 25 0 +BBX 20 20 0 0 +BITMAP +FFFFF0 +FFFFF0 +FE07F0 +F801F0 +F000F0 +E00070 +E00070 +C00030 +C00030 +C00030 +C00030 +C00030 +C00030 +E00070 +E00070 +F000F0 +F801F0 +FE07F0 +FFFFF0 +FFFFF0 +ENDCHAR +STARTCHAR A +ENCODING 65 +SWIDTH 1000 0 +DWIDTH 25 0 +BBX 20 21 0 1 +BITMAP +03FC00 +1FFF80 +3FFFC0 +7C03E0 +F000F0 +E00070 +E00070 +F000F0 +FC03F0 +FFFFF0 +FFFFF0 +FFFFF0 +FF0FF0 +7C03F0 +7801E0 +7800E0 +7000E0 +700060 +600060 +200040 +200040 +ENDCHAR +STARTCHAR B +ENCODING 66 +SWIDTH 1000 0 +DWIDTH 25 0 +BBX 18 20 1 0 +BITMAP +FFFE00 +FFFF80 +7E0780 +7801C0 +7000C0 +3000C0 +3000C0 +3801C0 +3E0780 +3FFF00 +3FFF00 +3E0780 +380180 +3000C0 +3000C0 +3000C0 +7801C0 +7E07C0 +FFFF80 +FFFE00 +ENDCHAR +STARTCHAR C +ENCODING 67 +SWIDTH 1000 0 +DWIDTH 25 0 +BBX 20 20 0 0 +BITMAP +00FC00 +03FF00 +0FFF80 +1F03E0 +3E0070 +7C0010 +780000 +F80000 +F00000 +F00000 +F00000 +F00000 +F80000 +780000 +7C0010 +3E0070 +1F01E0 +0FFFC0 +03FF80 +00FE00 +ENDCHAR +STARTCHAR u13079 +ENCODING 77945 +SWIDTH 1000 0 +DWIDTH 25 0 +BBX 21 10 0 5 +BITMAP +03FC00 +0FFF80 +1E73C0 +78F8F0 +F0F878 +70F870 +3870E0 +1E03C0 +0FFF80 +03FC00 +ENDCHAR +ENDFONT diff --git a/venv/Lib/site-packages/pygame/tests/fixtures/fonts/PyGameMono-18-75dpi.bdf b/venv/Lib/site-packages/pygame/tests/fixtures/fonts/PyGameMono-18-75dpi.bdf new file mode 100644 index 0000000..127f704 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/fixtures/fonts/PyGameMono-18-75dpi.bdf @@ -0,0 +1,143 @@ +STARTFONT 2.1 +FONT -FontForge-PyGameMono-Medium-R-Normal--19-180-75-75-M-190-ISO10646-1 +SIZE 18 75 75 +FONTBOUNDINGBOX 15 17 0 0 +COMMENT "Generated by fontforge, http://fontforge.sourceforge.net" +COMMENT "Created by Lenard Lindstrom,,, with FontForge 2.0 (http://fontforge.sf.net)" +STARTPROPERTIES 29 +FOUNDRY "FontForge" +FAMILY_NAME "PyGameMono" +WEIGHT_NAME "Medium" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 19 +POINT_SIZE 180 +RESOLUTION_X 75 +RESOLUTION_Y 75 +SPACING "M" +AVERAGE_WIDTH 190 +CHARSET_REGISTRY "ISO10646" +CHARSET_ENCODING "1" +FONTNAME_REGISTRY "" +CHARSET_COLLECTIONS "ISO10646-1" +FONT_NAME "PyGameMono" +FACE_NAME "PyGame Mono" +FONT_VERSION "001.000" +FONT_ASCENT 15 +FONT_DESCENT 4 +UNDERLINE_POSITION -2 +UNDERLINE_THICKNESS 1 +RAW_ASCENT 800 +RAW_DESCENT 200 +RELATIVE_WEIGHT 50 +RELATIVE_SETWIDTH 50 +FIGURE_WIDTH -1 +AVG_UPPERCASE_WIDTH 190 +ENDPROPERTIES +CHARS 5 +STARTCHAR .notdef +ENCODING 0 +SWIDTH 1000 0 +DWIDTH 19 0 +BBX 15 15 0 0 +BITMAP +FFFE +FFFE +FC7E +F01E +E00E +C006 +C006 +C006 +C006 +C006 +E00E +F01E +FC7E +FFFE +FFFE +ENDCHAR +STARTCHAR A +ENCODING 65 +SWIDTH 1000 0 +DWIDTH 19 0 +BBX 15 17 0 0 +BITMAP +0FE0 +3FF8 +783C +F01E +E00E +E00E +F01E +F83E +FFFE +FFFE +FC7E +701C +701C +600C +600C +4004 +4004 +ENDCHAR +STARTCHAR B +ENCODING 66 +SWIDTH 1000 0 +DWIDTH 19 0 +BBX 15 15 0 0 +BITMAP +FFF8 +7FFC +780E +3006 +3006 +380E +3FF8 +3FF8 +3FF8 +380E +3006 +3006 +7C1E +7FFC +FFF8 +ENDCHAR +STARTCHAR C +ENCODING 67 +SWIDTH 1000 0 +DWIDTH 19 0 +BBX 15 15 0 0 +BITMAP +03E0 +0FF8 +3C1C +7806 +7000 +E000 +E000 +E000 +E000 +E000 +7000 +7806 +3C1C +0FF8 +03E0 +ENDCHAR +STARTCHAR u13079 +ENCODING 77945 +SWIDTH 1000 0 +DWIDTH 19 0 +BBX 15 7 0 4 +BITMAP +0FE0 +3838 +638C +E38E +638C +3838 +0FE0 +ENDCHAR +ENDFONT diff --git a/venv/Lib/site-packages/pygame/tests/fixtures/fonts/PyGameMono-8.bdf b/venv/Lib/site-packages/pygame/tests/fixtures/fonts/PyGameMono-8.bdf new file mode 100644 index 0000000..17bef06 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/fixtures/fonts/PyGameMono-8.bdf @@ -0,0 +1,103 @@ +STARTFONT 2.1 +FONT -FontForge-PyGameMono-Medium-R-Normal--8-80-75-75-C-80-ISO10646-1 +SIZE 8 75 75 +FONTBOUNDINGBOX 6 7 0 0 +COMMENT "Generated by fontforge, http://fontforge.sourceforge.net" +COMMENT "Created by Lenard Lindstrom,,, with FontForge 2.0 (http://fontforge.sf.net)" +STARTPROPERTIES 29 +FOUNDRY "FontForge" +FAMILY_NAME "PyGameMono" +WEIGHT_NAME "Medium" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 8 +POINT_SIZE 80 +RESOLUTION_X 75 +RESOLUTION_Y 75 +SPACING "C" +AVERAGE_WIDTH 80 +CHARSET_REGISTRY "ISO10646" +CHARSET_ENCODING "1" +FONTNAME_REGISTRY "" +CHARSET_COLLECTIONS "ISO10646-1" +FONT_NAME "PyGameMono" +FACE_NAME "PyGame Mono" +FONT_VERSION "001.000" +FONT_ASCENT 6 +FONT_DESCENT 2 +UNDERLINE_POSITION -1 +UNDERLINE_THICKNESS 1 +RAW_ASCENT 800 +RAW_DESCENT 200 +RELATIVE_WEIGHT 50 +RELATIVE_SETWIDTH 50 +FIGURE_WIDTH -1 +AVG_UPPERCASE_WIDTH 80 +ENDPROPERTIES +CHARS 5 +STARTCHAR .notdef +ENCODING 0 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 6 6 0 0 +BITMAP +FC +84 +84 +84 +84 +FC +ENDCHAR +STARTCHAR A +ENCODING 65 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 6 7 0 0 +BITMAP +78 +84 +84 +FC +84 +84 +84 +ENDCHAR +STARTCHAR B +ENCODING 66 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 6 6 0 0 +BITMAP +FC +44 +78 +4C +44 +FC +ENDCHAR +STARTCHAR C +ENCODING 67 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 6 6 0 0 +BITMAP +78 +C4 +C0 +C0 +C4 +78 +ENDCHAR +STARTCHAR u13079 +ENCODING 77945 +SWIDTH 1000 0 +DWIDTH 8 0 +BBX 6 4 0 1 +BITMAP +78 +B4 +B4 +78 +ENDCHAR +ENDFONT diff --git a/venv/Lib/site-packages/pygame/tests/fixtures/fonts/PyGameMono.otf b/venv/Lib/site-packages/pygame/tests/fixtures/fonts/PyGameMono.otf new file mode 100644 index 0000000..5e9b66c Binary files /dev/null and b/venv/Lib/site-packages/pygame/tests/fixtures/fonts/PyGameMono.otf differ diff --git a/venv/Lib/site-packages/pygame/tests/fixtures/fonts/test_fixed.otf b/venv/Lib/site-packages/pygame/tests/fixtures/fonts/test_fixed.otf new file mode 100644 index 0000000..3488898 Binary files /dev/null and b/venv/Lib/site-packages/pygame/tests/fixtures/fonts/test_fixed.otf differ diff --git a/venv/Lib/site-packages/pygame/tests/fixtures/fonts/test_sans.ttf b/venv/Lib/site-packages/pygame/tests/fixtures/fonts/test_sans.ttf new file mode 100644 index 0000000..09fac2f Binary files /dev/null and b/venv/Lib/site-packages/pygame/tests/fixtures/fonts/test_sans.ttf differ diff --git a/venv/Lib/site-packages/pygame/tests/fixtures/fonts/u13079_PyGameMono-8.png b/venv/Lib/site-packages/pygame/tests/fixtures/fonts/u13079_PyGameMono-8.png new file mode 100644 index 0000000..911da8a Binary files /dev/null and b/venv/Lib/site-packages/pygame/tests/fixtures/fonts/u13079_PyGameMono-8.png differ diff --git a/venv/Lib/site-packages/pygame/tests/fixtures/xbm_cursors/white_sizing.xbm b/venv/Lib/site-packages/pygame/tests/fixtures/xbm_cursors/white_sizing.xbm new file mode 100644 index 0000000..d334d8d --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/fixtures/xbm_cursors/white_sizing.xbm @@ -0,0 +1,8 @@ +#define resize_white_width 16 +#define resize_white_height 16 +#define resize_white_x_hot 7 +#define resize_white_y_hot 7 +static unsigned char resize_white_bits[] = { + 0xff, 0x03, 0x01, 0x02, 0xfd, 0x03, 0x05, 0x00, 0xf5, 0x0f, 0x15, 0x08, + 0xd5, 0xeb, 0x55, 0xaa, 0x55, 0xaa, 0xd7, 0xab, 0x10, 0xa8, 0xf0, 0xb7, + 0x00, 0xa8, 0xc0, 0x9f, 0x40, 0x80, 0xc0, 0xff}; diff --git a/venv/Lib/site-packages/pygame/tests/fixtures/xbm_cursors/white_sizing_mask.xbm b/venv/Lib/site-packages/pygame/tests/fixtures/xbm_cursors/white_sizing_mask.xbm new file mode 100644 index 0000000..f00bc46 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/fixtures/xbm_cursors/white_sizing_mask.xbm @@ -0,0 +1,8 @@ +#define resize_white_mask_width 16 +#define resize_white_mask_height 16 +#define resize_white_mask_x_hot 7 +#define resize_white_mask_y_hot 7 +static unsigned char resize_white_mask_bits[] = { + 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0x07, 0x00, 0xf7, 0x0f, 0xf7, 0x0f, + 0xf7, 0xef, 0x77, 0xee, 0x77, 0xee, 0xf7, 0xef, 0xf0, 0xef, 0xf0, 0xff, + 0x00, 0xf8, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff}; diff --git a/venv/Lib/site-packages/pygame/tests/font_test.py b/venv/Lib/site-packages/pygame/tests/font_test.py new file mode 100644 index 0000000..e7bbf67 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/font_test.py @@ -0,0 +1,633 @@ +# -*- coding: utf-8 -*- + +import sys +import os +import unittest +import pathlib +import platform + +import pygame +from pygame import font as pygame_font # So font can be replaced with ftfont + + +FONTDIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fixtures", "fonts") + +UCS_4 = sys.maxunicode > 0xFFFF + + +def equal_images(s1, s2): + size = s1.get_size() + if s2.get_size() != size: + return False + w, h = size + for x in range(w): + for y in range(h): + if s1.get_at((x, y)) != s2.get_at((x, y)): + return False + return True + + +IS_PYPY = "PyPy" == platform.python_implementation() + + +@unittest.skipIf(IS_PYPY, "pypy skip known failure") # TODO +class FontModuleTest(unittest.TestCase): + def setUp(self): + pygame_font.init() + + def tearDown(self): + pygame_font.quit() + + def test_SysFont(self): + # Can only check that a font object is returned. + fonts = pygame_font.get_fonts() + if "arial" in fonts: + # Try to use arial font if it is there, rather than a random font + # which can be different depending on installed fonts on the system. + font_name = "arial" + else: + font_name = sorted(fonts)[0] + o = pygame_font.SysFont(font_name, 20) + self.assertTrue(isinstance(o, pygame_font.FontType)) + o = pygame_font.SysFont(font_name, 20, italic=True) + self.assertTrue(isinstance(o, pygame_font.FontType)) + o = pygame_font.SysFont(font_name, 20, bold=True) + self.assertTrue(isinstance(o, pygame_font.FontType)) + o = pygame_font.SysFont("thisisnotafont", 20) + self.assertTrue(isinstance(o, pygame_font.FontType)) + + def test_get_default_font(self): + self.assertEqual(pygame_font.get_default_font(), "freesansbold.ttf") + + def test_get_fonts_returns_something(self): + fnts = pygame_font.get_fonts() + self.assertTrue(fnts) + + # to test if some files exist... + # def XXtest_has_file_osx_10_5_sdk(self): + # import os + # f = "/Developer/SDKs/MacOSX10.5.sdk/usr/X11/include/ft2build.h" + # self.assertEqual(os.path.exists(f), True) + + # def XXtest_has_file_osx_10_4_sdk(self): + # import os + # f = "/Developer/SDKs/MacOSX10.4u.sdk/usr/X11R6/include/ft2build.h" + # self.assertEqual(os.path.exists(f), True) + + def test_get_fonts(self): + fnts = pygame_font.get_fonts() + + self.assertTrue(fnts, msg=repr(fnts)) + + for name in fnts: + # note, on ubuntu 2.6 they are all unicode strings. + + self.assertTrue(isinstance(name, str), name) + # Font names can be comprised of only numeric characters, so + # just checking name.islower() will not work as expected here. + self.assertFalse(any(c.isupper() for c in name)) + self.assertTrue(name.isalnum(), name) + + def test_get_init(self): + self.assertTrue(pygame_font.get_init()) + pygame_font.quit() + self.assertFalse(pygame_font.get_init()) + + def test_init(self): + pygame_font.init() + + def test_match_font_all_exist(self): + fonts = pygame_font.get_fonts() + + # Ensure all listed fonts are in fact available, and the returned file + # name is a full path. + for font in fonts: + path = pygame_font.match_font(font) + self.assertFalse(path is None) + self.assertTrue(os.path.isabs(path)) + + def test_match_font_name(self): + """That match_font accepts names of various types""" + font = pygame_font.get_fonts()[0] + font_path = pygame_font.match_font(font) + self.assertIsNotNone(font_path) + font_b = font.encode() + not_a_font = "thisisnotafont" + not_a_font_b = b"thisisnotafont" + good_font_names = [ + # Check single name bytes. + font_b, + # Check string of comma-separated names. + ",".join([not_a_font, font, not_a_font]), + # Check list of names. + [not_a_font, font, not_a_font], + # Check generator: + (name for name in [not_a_font, font, not_a_font]), + # Check comma-separated bytes. + b",".join([not_a_font_b, font_b, not_a_font_b]), + # Check list of bytes. + [not_a_font_b, font_b, not_a_font_b], + # Check mixed list of bytes and string. + [font, not_a_font, font_b, not_a_font_b], + ] + for font_name in good_font_names: + self.assertEqual(pygame_font.match_font(font_name), font_path, font_name) + + def test_not_match_font_name(self): + """match_font return None when names of various types do not exist""" + not_a_font = "thisisnotafont" + not_a_font_b = b"thisisnotafont" + bad_font_names = [ + not_a_font, + ",".join([not_a_font, not_a_font, not_a_font]), + [not_a_font, not_a_font, not_a_font], + (name for name in [not_a_font, not_a_font, not_a_font]), + not_a_font_b, + b",".join([not_a_font_b, not_a_font_b, not_a_font_b]), + [not_a_font_b, not_a_font_b, not_a_font_b], + [not_a_font, not_a_font_b, not_a_font], + ] + for font_name in bad_font_names: + self.assertIsNone(pygame_font.match_font(font_name), font_name) + + def test_match_font_bold(self): + fonts = pygame_font.get_fonts() + + # Look for a bold font. + self.assertTrue(any(pygame_font.match_font(font, bold=True) for font in fonts)) + + def test_match_font_italic(self): + fonts = pygame_font.get_fonts() + + # Look for an italic font. + self.assertTrue( + any(pygame_font.match_font(font, italic=True) for font in fonts) + ) + + def test_issue_742(self): + """that the font background does not crash.""" + surf = pygame.Surface((320, 240)) + font = pygame_font.Font(None, 24) + image = font.render("Test", 0, (255, 255, 255), (0, 0, 0)) + self.assertIsNone(image.get_colorkey()) + image.set_alpha(255) + surf.blit(image, (0, 0)) + + def test_issue_font_alphablit(self): + """Check that blitting anti-aliased text doesn't + change the background blue""" + pygame.display.set_mode((600, 400)) + + font = pygame_font.Font(None, 24) + + (color, text, center, pos) = ((160, 200, 250), "Music", (190, 170), "midright") + img1 = font.render(text, True, color) + + img = pygame.Surface(img1.get_size(), depth=32) + pre_blit_corner_pixel = img.get_at((0, 0)) + img.blit(img1, (0, 0)) + post_blit_corner_pixel = img.get_at((0, 0)) + + self.assertEqual(pre_blit_corner_pixel, post_blit_corner_pixel) + + def test_segfault_after_reinit(self): + """Reinitialization of font module should not cause + segmentation fault""" + import gc + + font = pygame_font.Font(None, 20) + pygame_font.quit() + pygame_font.init() + del font + gc.collect() + + def test_quit(self): + pygame_font.quit() + + +@unittest.skipIf(IS_PYPY, "pypy skip known failure") # TODO +class FontTest(unittest.TestCase): + def setUp(self): + pygame_font.init() + + def tearDown(self): + pygame_font.quit() + + def test_render_args(self): + screen = pygame.display.set_mode((600, 400)) + rect = screen.get_rect() + f = pygame_font.Font(None, 20) + screen.fill((10, 10, 10)) + font_surface = f.render(" bar", True, (0, 0, 0), (255, 255, 255)) + font_rect = font_surface.get_rect() + font_rect.topleft = rect.topleft + self.assertTrue(font_surface) + screen.blit(font_surface, font_rect, font_rect) + pygame.display.update() + self.assertEqual(tuple(screen.get_at((0, 0)))[:3], (255, 255, 255)) + self.assertEqual(tuple(screen.get_at(font_rect.topleft))[:3], (255, 255, 255)) + + # If we don't have a real display, don't do this test. + # Transparent background doesn't seem to work without a read video card. + if os.environ.get("SDL_VIDEODRIVER") != "dummy": + screen.fill((10, 10, 10)) + font_surface = f.render(" bar", True, (0, 0, 0), None) + font_rect = font_surface.get_rect() + font_rect.topleft = rect.topleft + self.assertTrue(font_surface) + screen.blit(font_surface, font_rect, font_rect) + pygame.display.update() + self.assertEqual(tuple(screen.get_at((0, 0)))[:3], (10, 10, 10)) + self.assertEqual(tuple(screen.get_at(font_rect.topleft))[:3], (10, 10, 10)) + + screen.fill((10, 10, 10)) + font_surface = f.render(" bar", True, (0, 0, 0)) + font_rect = font_surface.get_rect() + font_rect.topleft = rect.topleft + self.assertTrue(font_surface) + screen.blit(font_surface, font_rect, font_rect) + pygame.display.update(rect) + self.assertEqual(tuple(screen.get_at((0, 0)))[:3], (10, 10, 10)) + self.assertEqual(tuple(screen.get_at(font_rect.topleft))[:3], (10, 10, 10)) + + +@unittest.skipIf(IS_PYPY, "pypy skip known failure") # TODO +class FontTypeTest(unittest.TestCase): + def setUp(self): + pygame_font.init() + + def tearDown(self): + pygame_font.quit() + + def test_get_ascent(self): + # Ckecking ascent would need a custom test font to do properly. + f = pygame_font.Font(None, 20) + ascent = f.get_ascent() + self.assertTrue(isinstance(ascent, int)) + self.assertTrue(ascent > 0) + s = f.render("X", False, (255, 255, 255)) + self.assertTrue(s.get_size()[1] > ascent) + + def test_get_descent(self): + # Ckecking descent would need a custom test font to do properly. + f = pygame_font.Font(None, 20) + descent = f.get_descent() + self.assertTrue(isinstance(descent, int)) + self.assertTrue(descent < 0) + + def test_get_height(self): + # Ckecking height would need a custom test font to do properly. + f = pygame_font.Font(None, 20) + height = f.get_height() + self.assertTrue(isinstance(height, int)) + self.assertTrue(height > 0) + s = f.render("X", False, (255, 255, 255)) + self.assertTrue(s.get_size()[1] == height) + + def test_get_linesize(self): + # Ckecking linesize would need a custom test font to do properly. + # Questions: How do linesize, height and descent relate? + f = pygame_font.Font(None, 20) + linesize = f.get_linesize() + self.assertTrue(isinstance(linesize, int)) + self.assertTrue(linesize > 0) + + def test_metrics(self): + # Ensure bytes decoding works correctly. Can only compare results + # with unicode for now. + f = pygame_font.Font(None, 20) + um = f.metrics(".") + bm = f.metrics(b".") + + self.assertEqual(len(um), 1) + self.assertEqual(len(bm), 1) + self.assertIsNotNone(um[0]) + self.assertEqual(um, bm) + + u = "\u212A" + b = u.encode("UTF-16")[2:] # Keep byte order consistent. [2:] skips BOM + bm = f.metrics(b) + + self.assertEqual(len(bm), 2) + + try: # FIXME why do we do this try/except ? + um = f.metrics(u) + except pygame.error: + pass + else: + self.assertEqual(len(um), 1) + self.assertNotEqual(bm[0], um[0]) + self.assertNotEqual(bm[1], um[0]) + + if UCS_4: + u = u"\U00013000" + bm = f.metrics(u) + + self.assertEqual(len(bm), 1) + self.assertIsNone(bm[0]) + + return # unfinished + # The documentation is useless here. How large a list? + # How do list positions relate to character codes? + # What about unicode characters? + + # __doc__ (as of 2008-08-02) for pygame_font.Font.metrics: + + # Font.metrics(text): return list + # Gets the metrics for each character in the pased string. + # + # The list contains tuples for each character, which contain the + # minimum X offset, the maximum X offset, the minimum Y offset, the + # maximum Y offset and the advance offset (bearing plus width) of the + # character. [(minx, maxx, miny, maxy, advance), (minx, maxx, miny, + # maxy, advance), ...] + + self.fail() + + def test_render(self): + f = pygame_font.Font(None, 20) + s = f.render("foo", True, [0, 0, 0], [255, 255, 255]) + s = f.render("xxx", True, [0, 0, 0], [255, 255, 255]) + s = f.render("", True, [0, 0, 0], [255, 255, 255]) + s = f.render("foo", False, [0, 0, 0], [255, 255, 255]) + s = f.render("xxx", False, [0, 0, 0], [255, 255, 255]) + s = f.render("xxx", False, [0, 0, 0]) + s = f.render(" ", False, [0, 0, 0]) + s = f.render(" ", False, [0, 0, 0], [255, 255, 255]) + # null text should be 0 pixel wide. + s = f.render("", False, [0, 0, 0], [255, 255, 255]) + self.assertEqual(s.get_size()[0], 0) + # None text should be 0 pixel wide. + s = f.render(None, False, [0, 0, 0], [255, 255, 255]) + self.assertEqual(s.get_size()[0], 0) + # Non-text should raise a TypeError. + self.assertRaises(TypeError, f.render, [], False, [0, 0, 0], [255, 255, 255]) + self.assertRaises(TypeError, f.render, 1, False, [0, 0, 0], [255, 255, 255]) + # is background transparent for antialiasing? + s = f.render(".", True, [255, 255, 255]) + self.assertEqual(s.get_at((0, 0))[3], 0) + # is Unicode and bytes encoding correct? + # Cannot really test if the correct characters are rendered, but + # at least can assert the encodings differ. + su = f.render(".", False, [0, 0, 0], [255, 255, 255]) + sb = f.render(b".", False, [0, 0, 0], [255, 255, 255]) + self.assertTrue(equal_images(su, sb)) + u = "\u212A" + b = u.encode("UTF-16")[2:] # Keep byte order consistent. [2:] skips BOM + sb = f.render(b, False, [0, 0, 0], [255, 255, 255]) + try: # FIXME why do we do this try/except ? + su = f.render(u, False, [0, 0, 0], [255, 255, 255]) + except pygame.error: + pass + else: + self.assertFalse(equal_images(su, sb)) + + b = b"ab\x00cd" + self.assertRaises(ValueError, f.render, b, 0, [0, 0, 0]) + u = "ab\x00cd" + self.assertRaises(ValueError, f.render, b, 0, [0, 0, 0]) + + def test_render_ucs2_ucs4(self): + """that it renders without raising if there is a new enough SDL_ttf.""" + f = pygame_font.Font(None, 20) + # If the font module is SDL_ttf < 2.0.15 based, then it only supports UCS-2 + # it will raise an exception for an out-of-range UCS-4 code point. + if UCS_4 and hasattr(pygame_font, "UCS_4"): + ucs_2 = "\uFFEE" + s = f.render(ucs_2, False, [0, 0, 0], [255, 255, 255]) + ucs_4 = "\U00010000" + s = f.render(ucs_4, False, [0, 0, 0], [255, 255, 255]) + + def test_set_bold(self): + f = pygame_font.Font(None, 20) + self.assertFalse(f.get_bold()) + f.set_bold(True) + self.assertTrue(f.get_bold()) + f.set_bold(False) + self.assertFalse(f.get_bold()) + + def test_set_italic(self): + f = pygame_font.Font(None, 20) + self.assertFalse(f.get_italic()) + f.set_italic(True) + self.assertTrue(f.get_italic()) + f.set_italic(False) + self.assertFalse(f.get_italic()) + + def test_set_underline(self): + f = pygame_font.Font(None, 20) + self.assertFalse(f.get_underline()) + f.set_underline(True) + self.assertTrue(f.get_underline()) + f.set_underline(False) + self.assertFalse(f.get_underline()) + + def test_bold_attr(self): + f = pygame_font.Font(None, 20) + self.assertFalse(f.bold) + f.bold = True + self.assertTrue(f.bold) + f.bold = False + self.assertFalse(f.bold) + + def test_set_italic_property(self): + f = pygame_font.Font(None, 20) + self.assertFalse(f.italic) + f.italic = True + self.assertTrue(f.italic) + f.italic = False + self.assertFalse(f.italic) + + def test_set_underline_property(self): + f = pygame_font.Font(None, 20) + self.assertFalse(f.underline) + f.underline = True + self.assertTrue(f.underline) + f.underline = False + self.assertFalse(f.underline) + + def test_size(self): + f = pygame_font.Font(None, 20) + text = "Xg" + size = f.size(text) + w, h = size + s = f.render(text, False, (255, 255, 255)) + btext = text.encode("ascii") + + self.assertIsInstance(w, int) + self.assertIsInstance(h, int) + self.assertEqual(s.get_size(), size) + self.assertEqual(f.size(btext), size) + + text = "\u212A" + btext = text.encode("UTF-16")[2:] # Keep the byte order consistent. + bsize = f.size(btext) + size = f.size(text) + + self.assertNotEqual(size, bsize) + + def test_font_file_not_found(self): + # A per BUG reported by Bo Jangeborg on pygame-user mailing list, + # http://www.mail-archive.com/pygame-users@seul.org/msg11675.html + + pygame_font.init() + self.assertRaises( + FileNotFoundError, pygame_font.Font, str("some-fictional-font.ttf"), 20 + ) + + def test_load_from_file(self): + font_name = pygame_font.get_default_font() + font_path = os.path.join( + os.path.split(pygame.__file__)[0], pygame_font.get_default_font() + ) + f = pygame_font.Font(font_path, 20) + + def test_load_from_pathlib(self): + font_name = pygame_font.get_default_font() + font_path = os.path.join( + os.path.split(pygame.__file__)[0], pygame_font.get_default_font() + ) + f = pygame_font.Font(pathlib.Path(font_path), 20) + + def test_load_from_file_obj(self): + font_name = pygame_font.get_default_font() + font_path = os.path.join( + os.path.split(pygame.__file__)[0], pygame_font.get_default_font() + ) + with open(font_path, "rb") as f: + font = pygame_font.Font(f, 20) + + def test_load_default_font_filename(self): + # In font_init, a special case is when the filename argument is + # identical to the default font file name. + f = pygame_font.Font(pygame_font.get_default_font(), 20) + + def _load_unicode(self, path): + import shutil + + fdir = str(FONTDIR) + temp = os.path.join(fdir, path) + pgfont = os.path.join(fdir, u"test_sans.ttf") + shutil.copy(pgfont, temp) + try: + with open(temp, "rb") as f: + pass + except FileNotFoundError: + raise unittest.SkipTest("the path cannot be opened") + try: + pygame_font.Font(temp, 20) + finally: + os.remove(temp) + + def test_load_from_file_unicode_0(self): + """ASCII string as a unicode object""" + self._load_unicode(u"temp_file.ttf") + + def test_load_from_file_unicode_1(self): + self._load_unicode(u"你好.ttf") + + def test_load_from_file_bytes(self): + font_path = os.path.join( + os.path.split(pygame.__file__)[0], pygame_font.get_default_font() + ) + filesystem_encoding = sys.getfilesystemencoding() + filesystem_errors = "replace" if sys.platform == "win32" else "surrogateescape" + try: # FIXME why do we do this try/except ? + font_path = font_path.decode(filesystem_encoding, filesystem_errors) + except AttributeError: + pass + bfont_path = font_path.encode(filesystem_encoding, filesystem_errors) + f = pygame_font.Font(bfont_path, 20) + + +@unittest.skipIf(IS_PYPY, "pypy skip known failure") # TODO +class VisualTests(unittest.TestCase): + + __tags__ = ["interactive"] + + screen = None + aborted = False + + def setUp(self): + if self.screen is None: + pygame.init() + self.screen = pygame.display.set_mode((600, 200)) + self.screen.fill((255, 255, 255)) + pygame.display.flip() + self.f = pygame_font.Font(None, 32) + + def abort(self): + if self.screen is not None: + pygame.quit() + self.aborted = True + + def query(self, bold=False, italic=False, underline=False, antialiase=False): + if self.aborted: + return False + spacing = 10 + offset = 20 + y = spacing + f = self.f + screen = self.screen + screen.fill((255, 255, 255)) + pygame.display.flip() + if not (bold or italic or underline or antialiase): + text = "normal" + else: + modes = [] + if bold: + modes.append("bold") + if italic: + modes.append("italic") + if underline: + modes.append("underlined") + if antialiase: + modes.append("antialiased") + text = "%s (y/n):" % ("-".join(modes),) + f.set_bold(bold) + f.set_italic(italic) + f.set_underline(underline) + s = f.render(text, antialiase, (0, 0, 0)) + screen.blit(s, (offset, y)) + y += s.get_size()[1] + spacing + f.set_bold(False) + f.set_italic(False) + f.set_underline(False) + s = f.render("(some comparison text)", False, (0, 0, 0)) + screen.blit(s, (offset, y)) + pygame.display.flip() + while 1: + for evt in pygame.event.get(): + if evt.type == pygame.KEYDOWN: + if evt.key == pygame.K_ESCAPE: + self.abort() + return False + if evt.key == pygame.K_y: + return True + if evt.key == pygame.K_n: + return False + if evt.type == pygame.QUIT: + self.abort() + return False + + def test_bold(self): + self.assertTrue(self.query(bold=True)) + + def test_italic(self): + self.assertTrue(self.query(italic=True)) + + def test_underline(self): + self.assertTrue(self.query(underline=True)) + + def test_antialiase(self): + self.assertTrue(self.query(antialiase=True)) + + def test_bold_antialiase(self): + self.assertTrue(self.query(bold=True, antialiase=True)) + + def test_italic_underline(self): + self.assertTrue(self.query(italic=True, underline=True)) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/freetype_tags.py b/venv/Lib/site-packages/pygame/tests/freetype_tags.py new file mode 100644 index 0000000..d84cbb7 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/freetype_tags.py @@ -0,0 +1,11 @@ +__tags__ = ["development"] + +exclude = False + +try: + import pygame.freetype +except ImportError: + exclude = True + +if exclude: + __tags__.extend(["ignore", "subprocess_ignore"]) diff --git a/venv/Lib/site-packages/pygame/tests/freetype_test.py b/venv/Lib/site-packages/pygame/tests/freetype_test.py new file mode 100644 index 0000000..815dfe3 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/freetype_test.py @@ -0,0 +1,1799 @@ +import os + +if os.environ.get("SDL_VIDEODRIVER") == "dummy": + __tags__ = ("ignore", "subprocess_ignore") + +import unittest +import ctypes +import weakref +import gc +import pathlib +import platform + +IS_PYPY = "PyPy" == platform.python_implementation() + + +try: + from pygame.tests.test_utils import arrinter +except NameError: + pass + +import pygame + +try: + import pygame.freetype as ft +except ImportError: + ft = None + + +FONTDIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fixtures", "fonts") + + +def nullfont(): + """return an uninitialized font instance""" + return ft.Font.__new__(ft.Font) + + +max_point_size_FX6 = 0x7FFFFFFF +max_point_size = max_point_size_FX6 >> 6 +max_point_size_f = max_point_size_FX6 * 0.015625 + + +def surf_same_image(a, b): + """Return True if a's pixel buffer is identical to b's""" + + a_sz = a.get_height() * a.get_pitch() + b_sz = b.get_height() * b.get_pitch() + if a_sz != b_sz: + return False + a_bytes = ctypes.string_at(a._pixels_address, a_sz) + b_bytes = ctypes.string_at(b._pixels_address, b_sz) + return a_bytes == b_bytes + + +class FreeTypeFontTest(unittest.TestCase): + + _fixed_path = os.path.join(FONTDIR, "test_fixed.otf") + _sans_path = os.path.join(FONTDIR, "test_sans.ttf") + _mono_path = os.path.join(FONTDIR, "PyGameMono.otf") + _bmp_8_75dpi_path = os.path.join(FONTDIR, "PyGameMono-8.bdf") + _bmp_18_75dpi_path = os.path.join(FONTDIR, "PyGameMono-18-75dpi.bdf") + _bmp_18_100dpi_path = os.path.join(FONTDIR, "PyGameMono-18-100dpi.bdf") + _TEST_FONTS = {} + + @classmethod + def setUpClass(cls): + ft.init() + + # Setup the test fonts. + + # Inconsolata is an open-source font designed by Raph Levien. + # Licensed under the Open Font License. + # http://www.levien.com/type/myfonts/inconsolata.html + cls._TEST_FONTS["fixed"] = ft.Font(cls._fixed_path) + + # Liberation Sans is an open-source font designed by Steve Matteson. + # Licensed under the GNU GPL. + # https://fedorahosted.org/liberation-fonts/ + cls._TEST_FONTS["sans"] = ft.Font(cls._sans_path) + + # A scalable mono test font made for pygame. It contains only + # a few glyphs: '\0', 'A', 'B', 'C', and U+13079. + # It also contains two bitmap sizes: 8.0 X 8.0 and 19.0 X 19.0. + cls._TEST_FONTS["mono"] = ft.Font(cls._mono_path) + + # A fixed size bitmap mono test font made for pygame. + # It contains only a few glyphs: '\0', 'A', 'B', 'C', and U+13079. + # The size is 8.0 X 8.0. + cls._TEST_FONTS["bmp-8-75dpi"] = ft.Font(cls._bmp_8_75dpi_path) + + # A fixed size bitmap mono test font made for pygame. + # It contains only a few glyphs: '\0', 'A', 'B', 'C', and U+13079. + # The size is 8.0 X 8.0. + cls._TEST_FONTS["bmp-18-75dpi"] = ft.Font(cls._bmp_18_75dpi_path) + + # A fixed size bitmap mono test font made for pygame. + # It contains only a few glyphs: '\0', 'A', 'B', 'C', and U+13079. + # The size is 8.0 X 8.0. + cls._TEST_FONTS["bmp-18-100dpi"] = ft.Font(cls._bmp_18_100dpi_path) + + @classmethod + def tearDownClass(cls): + ft.quit() + + def test_freetype_defaultfont(self): + font = ft.Font(None) + self.assertEqual(font.name, "FreeSans") + + def test_freetype_Font_init(self): + + self.assertRaises( + FileNotFoundError, ft.Font, os.path.join(FONTDIR, "nonexistent.ttf") + ) + + f = self._TEST_FONTS["sans"] + self.assertIsInstance(f, ft.Font) + + f = self._TEST_FONTS["fixed"] + self.assertIsInstance(f, ft.Font) + + # Test keyword arguments + f = ft.Font(size=22, file=None) + self.assertEqual(f.size, 22) + f = ft.Font(font_index=0, file=None) + self.assertNotEqual(ft.get_default_resolution(), 100) + f = ft.Font(resolution=100, file=None) + self.assertEqual(f.resolution, 100) + f = ft.Font(ucs4=True, file=None) + self.assertTrue(f.ucs4) + self.assertRaises(OverflowError, ft.Font, file=None, size=(max_point_size + 1)) + self.assertRaises(OverflowError, ft.Font, file=None, size=-1) + + f = ft.Font(None, size=24) + self.assertTrue(f.height > 0) + self.assertRaises( + FileNotFoundError, f.__init__, os.path.join(FONTDIR, "nonexistent.ttf") + ) + + # Test attribute preservation during reinitalization + f = ft.Font(self._sans_path, size=24, ucs4=True) + self.assertEqual(f.name, "Liberation Sans") + self.assertTrue(f.scalable) + self.assertFalse(f.fixed_width) + self.assertTrue(f.antialiased) + self.assertFalse(f.oblique) + self.assertTrue(f.ucs4) + f.antialiased = False + f.oblique = True + f.__init__(self._mono_path) + self.assertEqual(f.name, "PyGameMono") + self.assertTrue(f.scalable) + self.assertTrue(f.fixed_width) + self.assertFalse(f.antialiased) + self.assertTrue(f.oblique) + self.assertTrue(f.ucs4) + + # For a bitmap font, the size is automatically set to the first + # size in the available sizes list. + f = ft.Font(self._bmp_8_75dpi_path) + sizes = f.get_sizes() + self.assertEqual(len(sizes), 1) + size_pt, width_px, height_px, x_ppem, y_ppem = sizes[0] + self.assertEqual(f.size, (x_ppem, y_ppem)) + f.__init__(self._bmp_8_75dpi_path, size=12) + self.assertEqual(f.size, 12.0) + + @unittest.skipIf(IS_PYPY, "PyPy doesn't use refcounting") + def test_freetype_Font_dealloc(self): + import sys + + handle = open(self._sans_path, "rb") + + def load_font(): + tempFont = ft.Font(handle) + + try: + load_font() + + self.assertEqual(sys.getrefcount(handle), 2) + finally: + # Ensures file is closed even if test fails. + handle.close() + + def test_freetype_Font_kerning(self): + """Ensures get/set works with the kerning property.""" + ft_font = self._TEST_FONTS["sans"] + + # Test default is disabled. + self.assertFalse(ft_font.kerning) + + # Test setting to True. + ft_font.kerning = True + + self.assertTrue(ft_font.kerning) + + # Test setting to False. + ft_font.kerning = False + + self.assertFalse(ft_font.kerning) + + def test_freetype_Font_kerning__enabled(self): + """Ensures exceptions are not raised when calling freetype methods + while kerning is enabled. + + Note: This does not test what changes occur to a rendered font by + having kerning enabled. + + Related to issue #367. + """ + surface = pygame.Surface((10, 10), 0, 32) + TEST_TEXT = "Freetype Font" + ft_font = self._TEST_FONTS["bmp-8-75dpi"] + + ft_font.kerning = True + + # Call different methods to ensure they don't raise an exception. + metrics = ft_font.get_metrics(TEST_TEXT) + self.assertIsInstance(metrics, list) + + rect = ft_font.get_rect(TEST_TEXT) + self.assertIsInstance(rect, pygame.Rect) + + font_surf, rect = ft_font.render(TEST_TEXT) + self.assertIsInstance(font_surf, pygame.Surface) + self.assertIsInstance(rect, pygame.Rect) + + rect = ft_font.render_to(surface, (0, 0), TEST_TEXT) + self.assertIsInstance(rect, pygame.Rect) + + buf, size = ft_font.render_raw(TEST_TEXT) + self.assertIsInstance(buf, bytes) + self.assertIsInstance(size, tuple) + + rect = ft_font.render_raw_to(surface.get_view("2"), TEST_TEXT) + self.assertIsInstance(rect, pygame.Rect) + + def test_freetype_Font_scalable(self): + + f = self._TEST_FONTS["sans"] + self.assertTrue(f.scalable) + + self.assertRaises(RuntimeError, lambda: nullfont().scalable) + + def test_freetype_Font_fixed_width(self): + + f = self._TEST_FONTS["sans"] + self.assertFalse(f.fixed_width) + + f = self._TEST_FONTS["mono"] + self.assertTrue(f.fixed_width) + + self.assertRaises(RuntimeError, lambda: nullfont().fixed_width) + + def test_freetype_Font_fixed_sizes(self): + + f = self._TEST_FONTS["sans"] + self.assertEqual(f.fixed_sizes, 0) + f = self._TEST_FONTS["bmp-8-75dpi"] + self.assertEqual(f.fixed_sizes, 1) + f = self._TEST_FONTS["mono"] + self.assertEqual(f.fixed_sizes, 2) + + def test_freetype_Font_get_sizes(self): + f = self._TEST_FONTS["sans"] + szlist = f.get_sizes() + self.assertIsInstance(szlist, list) + self.assertEqual(len(szlist), 0) + + f = self._TEST_FONTS["bmp-8-75dpi"] + szlist = f.get_sizes() + self.assertIsInstance(szlist, list) + self.assertEqual(len(szlist), 1) + + size8 = szlist[0] + self.assertIsInstance(size8[0], int) + self.assertEqual(size8[0], 8) + self.assertIsInstance(size8[1], int) + self.assertIsInstance(size8[2], int) + self.assertIsInstance(size8[3], float) + self.assertEqual(int(size8[3] * 64.0 + 0.5), 8 * 64) + self.assertIsInstance(size8[4], float) + self.assertEqual(int(size8[4] * 64.0 + 0.5), 8 * 64) + + f = self._TEST_FONTS["mono"] + szlist = f.get_sizes() + self.assertIsInstance(szlist, list) + self.assertEqual(len(szlist), 2) + + size8 = szlist[0] + self.assertEqual(size8[3], 8) + self.assertEqual(int(size8[3] * 64.0 + 0.5), 8 * 64) + self.assertEqual(int(size8[4] * 64.0 + 0.5), 8 * 64) + + size19 = szlist[1] + self.assertEqual(size19[3], 19) + self.assertEqual(int(size19[3] * 64.0 + 0.5), 19 * 64) + self.assertEqual(int(size19[4] * 64.0 + 0.5), 19 * 64) + + def test_freetype_Font_use_bitmap_strikes(self): + f = self._TEST_FONTS["mono"] + try: + # use_bitmap_strikes == True + # + self.assertTrue(f.use_bitmap_strikes) + + # bitmap compatible properties + s_strike, sz = f.render_raw("A", size=19) + try: + f.vertical = True + s_strike_vert, sz = f.render_raw("A", size=19) + finally: + f.vertical = False + try: + f.wide = True + s_strike_wide, sz = f.render_raw("A", size=19) + finally: + f.wide = False + try: + f.underline = True + s_strike_underline, sz = f.render_raw("A", size=19) + finally: + f.underline = False + + # bitmap incompatible properties + s_strike_rot45, sz = f.render_raw("A", size=19, rotation=45) + try: + f.strong = True + s_strike_strong, sz = f.render_raw("A", size=19) + finally: + f.strong = False + try: + f.oblique = True + s_strike_oblique, sz = f.render_raw("A", size=19) + finally: + f.oblique = False + + # compare with use_bitmap_strikes == False + # + f.use_bitmap_strikes = False + self.assertFalse(f.use_bitmap_strikes) + + # bitmap compatible properties + s_outline, sz = f.render_raw("A", size=19) + self.assertNotEqual(s_outline, s_strike) + try: + f.vertical = True + s_outline, sz = f.render_raw("A", size=19) + self.assertNotEqual(s_outline, s_strike_vert) + finally: + f.vertical = False + try: + f.wide = True + s_outline, sz = f.render_raw("A", size=19) + self.assertNotEqual(s_outline, s_strike_wide) + finally: + f.wide = False + try: + f.underline = True + s_outline, sz = f.render_raw("A", size=19) + self.assertNotEqual(s_outline, s_strike_underline) + finally: + f.underline = False + + # bitmap incompatible properties + s_outline, sz = f.render_raw("A", size=19, rotation=45) + self.assertEqual(s_outline, s_strike_rot45) + try: + f.strong = True + s_outline, sz = f.render_raw("A", size=19) + self.assertEqual(s_outline, s_strike_strong) + finally: + f.strong = False + try: + f.oblique = True + s_outline, sz = f.render_raw("A", size=19) + self.assertEqual(s_outline, s_strike_oblique) + finally: + f.oblique = False + finally: + f.use_bitmap_strikes = True + + def test_freetype_Font_bitmap_files(self): + """Ensure bitmap file restrictions are caught""" + f = self._TEST_FONTS["bmp-8-75dpi"] + f_null = nullfont() + s = pygame.Surface((10, 10), 0, 32) + a = s.get_view("3") + + exception = AttributeError + self.assertRaises(exception, setattr, f, "strong", True) + self.assertRaises(exception, setattr, f, "oblique", True) + self.assertRaises(exception, setattr, f, "style", ft.STYLE_STRONG) + self.assertRaises(exception, setattr, f, "style", ft.STYLE_OBLIQUE) + exception = RuntimeError + self.assertRaises(exception, setattr, f_null, "strong", True) + self.assertRaises(exception, setattr, f_null, "oblique", True) + self.assertRaises(exception, setattr, f_null, "style", ft.STYLE_STRONG) + self.assertRaises(exception, setattr, f_null, "style", ft.STYLE_OBLIQUE) + exception = ValueError + self.assertRaises(exception, f.render, "A", (0, 0, 0), size=8, rotation=1) + self.assertRaises( + exception, f.render, "A", (0, 0, 0), size=8, style=ft.STYLE_OBLIQUE + ) + self.assertRaises( + exception, f.render, "A", (0, 0, 0), size=8, style=ft.STYLE_STRONG + ) + self.assertRaises(exception, f.render_raw, "A", size=8, rotation=1) + self.assertRaises(exception, f.render_raw, "A", size=8, style=ft.STYLE_OBLIQUE) + self.assertRaises(exception, f.render_raw, "A", size=8, style=ft.STYLE_STRONG) + self.assertRaises( + exception, f.render_to, s, (0, 0), "A", (0, 0, 0), size=8, rotation=1 + ) + self.assertRaises( + exception, + f.render_to, + s, + (0, 0), + "A", + (0, 0, 0), + size=8, + style=ft.STYLE_OBLIQUE, + ) + self.assertRaises( + exception, + f.render_to, + s, + (0, 0), + "A", + (0, 0, 0), + size=8, + style=ft.STYLE_STRONG, + ) + self.assertRaises(exception, f.render_raw_to, a, "A", size=8, rotation=1) + self.assertRaises( + exception, f.render_raw_to, a, "A", size=8, style=ft.STYLE_OBLIQUE + ) + self.assertRaises( + exception, f.render_raw_to, a, "A", size=8, style=ft.STYLE_STRONG + ) + self.assertRaises(exception, f.get_rect, "A", size=8, rotation=1) + self.assertRaises(exception, f.get_rect, "A", size=8, style=ft.STYLE_OBLIQUE) + self.assertRaises(exception, f.get_rect, "A", size=8, style=ft.STYLE_STRONG) + + # Unsupported point size + exception = pygame.error + self.assertRaises(exception, f.get_rect, "A", size=42) + self.assertRaises(exception, f.get_metrics, "A", size=42) + self.assertRaises(exception, f.get_sized_ascender, 42) + self.assertRaises(exception, f.get_sized_descender, 42) + self.assertRaises(exception, f.get_sized_height, 42) + self.assertRaises(exception, f.get_sized_glyph_height, 42) + + def test_freetype_Font_get_metrics(self): + + font = self._TEST_FONTS["sans"] + + metrics = font.get_metrics("ABCD", size=24) + self.assertEqual(len(metrics), len("ABCD")) + self.assertIsInstance(metrics, list) + + for metrics_tuple in metrics: + self.assertIsInstance(metrics_tuple, tuple, metrics_tuple) + self.assertEqual(len(metrics_tuple), 6) + + for m in metrics_tuple[:4]: + self.assertIsInstance(m, int) + + for m in metrics_tuple[4:]: + self.assertIsInstance(m, float) + + # test for empty string + metrics = font.get_metrics("", size=24) + self.assertEqual(metrics, []) + + # test for invalid string + self.assertRaises(TypeError, font.get_metrics, 24, 24) + + # raises exception when uninitalized + self.assertRaises(RuntimeError, nullfont().get_metrics, "a", size=24) + + def test_freetype_Font_get_rect(self): + + font = self._TEST_FONTS["sans"] + + def test_rect(r): + self.assertIsInstance(r, pygame.Rect) + + rect_default = font.get_rect("ABCDabcd", size=24) + test_rect(rect_default) + self.assertTrue(rect_default.size > (0, 0)) + self.assertTrue(rect_default.width > rect_default.height) + + rect_bigger = font.get_rect("ABCDabcd", size=32) + test_rect(rect_bigger) + self.assertTrue(rect_bigger.size > rect_default.size) + + rect_strong = font.get_rect("ABCDabcd", size=24, style=ft.STYLE_STRONG) + test_rect(rect_strong) + self.assertTrue(rect_strong.size > rect_default.size) + + font.vertical = True + rect_vert = font.get_rect("ABCDabcd", size=24) + test_rect(rect_vert) + self.assertTrue(rect_vert.width < rect_vert.height) + font.vertical = False + + rect_oblique = font.get_rect("ABCDabcd", size=24, style=ft.STYLE_OBLIQUE) + test_rect(rect_oblique) + self.assertTrue(rect_oblique.width > rect_default.width) + self.assertTrue(rect_oblique.height == rect_default.height) + + rect_under = font.get_rect("ABCDabcd", size=24, style=ft.STYLE_UNDERLINE) + test_rect(rect_under) + self.assertTrue(rect_under.width == rect_default.width) + self.assertTrue(rect_under.height > rect_default.height) + + # Rect size should change if UTF surrogate pairs are treated as + # one code point or two. + ufont = self._TEST_FONTS["mono"] + rect_utf32 = ufont.get_rect("\U00013079", size=24) + rect_utf16 = ufont.get_rect("\uD80C\uDC79", size=24) + self.assertEqual(rect_utf16, rect_utf32) + ufont.ucs4 = True + try: + rect_utf16 = ufont.get_rect("\uD80C\uDC79", size=24) + finally: + ufont.ucs4 = False + self.assertNotEqual(rect_utf16, rect_utf32) + + self.assertRaises(RuntimeError, nullfont().get_rect, "a", size=24) + + # text stretching + rect12 = font.get_rect("A", size=12.0) + rect24 = font.get_rect("A", size=24.0) + rect_x = font.get_rect("A", size=(24.0, 12.0)) + self.assertEqual(rect_x.width, rect24.width) + self.assertEqual(rect_x.height, rect12.height) + rect_y = font.get_rect("A", size=(12.0, 24.0)) + self.assertEqual(rect_y.width, rect12.width) + self.assertEqual(rect_y.height, rect24.height) + + def test_freetype_Font_height(self): + + f = self._TEST_FONTS["sans"] + self.assertEqual(f.height, 2355) + + f = self._TEST_FONTS["fixed"] + self.assertEqual(f.height, 1100) + + self.assertRaises(RuntimeError, lambda: nullfont().height) + + def test_freetype_Font_name(self): + + f = self._TEST_FONTS["sans"] + self.assertEqual(f.name, "Liberation Sans") + + f = self._TEST_FONTS["fixed"] + self.assertEqual(f.name, "Inconsolata") + + nf = nullfont() + self.assertEqual(nf.name, repr(nf)) + + def test_freetype_Font_size(self): + + f = ft.Font(None, size=12) + self.assertEqual(f.size, 12) + f.size = 22 + self.assertEqual(f.size, 22) + f.size = 0 + self.assertEqual(f.size, 0) + f.size = max_point_size + self.assertEqual(f.size, max_point_size) + f.size = 6.5 + self.assertEqual(f.size, 6.5) + f.size = max_point_size_f + self.assertEqual(f.size, max_point_size_f) + self.assertRaises(OverflowError, setattr, f, "size", -1) + self.assertRaises(OverflowError, setattr, f, "size", (max_point_size + 1)) + + f.size = 24.0, 0 + size = f.size + self.assertIsInstance(size, float) + self.assertEqual(size, 24.0) + + f.size = 16, 16 + size = f.size + self.assertIsInstance(size, tuple) + self.assertEqual(len(size), 2) + + x, y = size + self.assertIsInstance(x, float) + self.assertEqual(x, 16.0) + self.assertIsInstance(y, float) + self.assertEqual(y, 16.0) + + f.size = 20.5, 22.25 + x, y = f.size + self.assertEqual(x, 20.5) + self.assertEqual(y, 22.25) + + f.size = 0, 0 + size = f.size + self.assertIsInstance(size, float) + self.assertEqual(size, 0.0) + self.assertRaises(ValueError, setattr, f, "size", (0, 24.0)) + self.assertRaises(TypeError, setattr, f, "size", (24.0,)) + self.assertRaises(TypeError, setattr, f, "size", (24.0, 0, 0)) + self.assertRaises(TypeError, setattr, f, "size", (24.0j, 24.0)) + self.assertRaises(TypeError, setattr, f, "size", (24.0, 24.0j)) + self.assertRaises(OverflowError, setattr, f, "size", (-1, 16)) + self.assertRaises(OverflowError, setattr, f, "size", (max_point_size + 1, 16)) + self.assertRaises(OverflowError, setattr, f, "size", (16, -1)) + self.assertRaises(OverflowError, setattr, f, "size", (16, max_point_size + 1)) + + # bitmap files with identical point size but differing ppems. + f75 = self._TEST_FONTS["bmp-18-75dpi"] + sizes = f75.get_sizes() + self.assertEqual(len(sizes), 1) + size_pt, width_px, height_px, x_ppem, y_ppem = sizes[0] + self.assertEqual(size_pt, 18) + self.assertEqual(x_ppem, 19.0) + self.assertEqual(y_ppem, 19.0) + rect = f75.get_rect("A", size=18) + rect = f75.get_rect("A", size=19) + rect = f75.get_rect("A", size=(19.0, 19.0)) + self.assertRaises(pygame.error, f75.get_rect, "A", size=17) + f100 = self._TEST_FONTS["bmp-18-100dpi"] + sizes = f100.get_sizes() + self.assertEqual(len(sizes), 1) + size_pt, width_px, height_px, x_ppem, y_ppem = sizes[0] + self.assertEqual(size_pt, 18) + self.assertEqual(x_ppem, 25.0) + self.assertEqual(y_ppem, 25.0) + rect = f100.get_rect("A", size=18) + rect = f100.get_rect("A", size=25) + rect = f100.get_rect("A", size=(25.0, 25.0)) + self.assertRaises(pygame.error, f100.get_rect, "A", size=17) + + def test_freetype_Font_rotation(self): + + test_angles = [ + (30, 30), + (360, 0), + (390, 30), + (720, 0), + (764, 44), + (-30, 330), + (-360, 0), + (-390, 330), + (-720, 0), + (-764, 316), + ] + + f = ft.Font(None) + self.assertEqual(f.rotation, 0) + for r, r_reduced in test_angles: + f.rotation = r + self.assertEqual( + f.rotation, + r_reduced, + "for angle %d: %d != %d" % (r, f.rotation, r_reduced), + ) + self.assertRaises(TypeError, setattr, f, "rotation", "12") + + def test_freetype_Font_render_to(self): + # Rendering to an existing target surface is equivalent to + # blitting a surface returned by Font.render with the target. + font = self._TEST_FONTS["sans"] + + surf = pygame.Surface((800, 600)) + color = pygame.Color(0, 0, 0) + + rrect = font.render_to(surf, (32, 32), "FoobarBaz", color, None, size=24) + self.assertIsInstance(rrect, pygame.Rect) + self.assertEqual(rrect.topleft, (32, 32)) + self.assertNotEqual(rrect.bottomright, (32, 32)) + + rcopy = rrect.copy() + rcopy.topleft = (32, 32) + self.assertTrue(surf.get_rect().contains(rcopy)) + + rect = pygame.Rect(20, 20, 2, 2) + rrect = font.render_to(surf, rect, "FoobarBax", color, None, size=24) + self.assertEqual(rect.topleft, rrect.topleft) + self.assertNotEqual(rrect.size, rect.size) + rrect = font.render_to(surf, (20.1, 18.9), "FoobarBax", color, None, size=24) + + rrect = font.render_to(surf, rect, "", color, None, size=24) + self.assertFalse(rrect) + self.assertEqual(rrect.height, font.get_sized_height(24)) + + # invalid surf test + self.assertRaises(TypeError, font.render_to, "not a surface", "text", color) + self.assertRaises(TypeError, font.render_to, pygame.Surface, "text", color) + + # invalid dest test + for dest in [ + None, + 0, + "a", + "ab", + (), + (1,), + ("a", 2), + (1, "a"), + (1 + 2j, 2), + (1, 1 + 2j), + (1, int), + (int, 1), + ]: + self.assertRaises( + TypeError, font.render_to, surf, dest, "foobar", color, size=24 + ) + + # misc parameter test + self.assertRaises(ValueError, font.render_to, surf, (0, 0), "foobar", color) + self.assertRaises( + TypeError, font.render_to, surf, (0, 0), "foobar", color, 2.3, size=24 + ) + self.assertRaises( + ValueError, + font.render_to, + surf, + (0, 0), + "foobar", + color, + None, + style=42, + size=24, + ) + self.assertRaises( + TypeError, + font.render_to, + surf, + (0, 0), + "foobar", + color, + None, + style=None, + size=24, + ) + self.assertRaises( + ValueError, + font.render_to, + surf, + (0, 0), + "foobar", + color, + None, + style=97, + size=24, + ) + + def test_freetype_Font_render(self): + + font = self._TEST_FONTS["sans"] + + surf = pygame.Surface((800, 600)) + color = pygame.Color(0, 0, 0) + + rend = font.render("FoobarBaz", pygame.Color(0, 0, 0), None, size=24) + self.assertIsInstance(rend, tuple) + self.assertEqual(len(rend), 2) + self.assertIsInstance(rend[0], pygame.Surface) + self.assertIsInstance(rend[1], pygame.Rect) + self.assertEqual(rend[0].get_rect().size, rend[1].size) + + s, r = font.render("", pygame.Color(0, 0, 0), None, size=24) + self.assertEqual(r.width, 0) + self.assertEqual(r.height, font.get_sized_height(24)) + self.assertEqual(s.get_size(), r.size) + self.assertEqual(s.get_bitsize(), 32) + + # misc parameter test + self.assertRaises(ValueError, font.render, "foobar", color) + self.assertRaises(TypeError, font.render, "foobar", color, 2.3, size=24) + self.assertRaises( + ValueError, font.render, "foobar", color, None, style=42, size=24 + ) + self.assertRaises( + TypeError, font.render, "foobar", color, None, style=None, size=24 + ) + self.assertRaises( + ValueError, font.render, "foobar", color, None, style=97, size=24 + ) + + # valid surrogate pairs + font2 = self._TEST_FONTS["mono"] + ucs4 = font2.ucs4 + try: + font2.ucs4 = False + rend1 = font2.render("\uD80C\uDC79", color, size=24) + rend2 = font2.render("\U00013079", color, size=24) + self.assertEqual(rend1[1], rend2[1]) + font2.ucs4 = True + rend1 = font2.render("\uD80C\uDC79", color, size=24) + self.assertNotEqual(rend1[1], rend2[1]) + finally: + font2.ucs4 = ucs4 + + # malformed surrogate pairs + self.assertRaises(UnicodeEncodeError, font.render, "\uD80C", color, size=24) + self.assertRaises(UnicodeEncodeError, font.render, "\uDCA7", color, size=24) + self.assertRaises( + UnicodeEncodeError, font.render, "\uD7FF\uDCA7", color, size=24 + ) + self.assertRaises( + UnicodeEncodeError, font.render, "\uDC00\uDCA7", color, size=24 + ) + self.assertRaises( + UnicodeEncodeError, font.render, "\uD80C\uDBFF", color, size=24 + ) + self.assertRaises( + UnicodeEncodeError, font.render, "\uD80C\uE000", color, size=24 + ) + + # raises exception when uninitalized + self.assertRaises(RuntimeError, nullfont().render, "a", (0, 0, 0), size=24) + + # Confirm the correct glpyhs are returned for a couple of + # unicode code points, 'A' and '\U00023079'. For each code point + # the rendered glyph is compared with an image of glyph bitmap + # as exported by FontForge. + path = os.path.join(FONTDIR, "A_PyGameMono-8.png") + A = pygame.image.load(path) + path = os.path.join(FONTDIR, "u13079_PyGameMono-8.png") + u13079 = pygame.image.load(path) + + font = self._TEST_FONTS["mono"] + font.ucs4 = False + A_rendered, r = font.render("A", bgcolor=pygame.Color("white"), size=8) + u13079_rendered, r = font.render( + "\U00013079", bgcolor=pygame.Color("white"), size=8 + ) + + # before comparing the surfaces, make sure they are the same + # pixel format. Use 32-bit SRCALPHA to avoid row padding and + # undefined bytes (the alpha byte will be set to 255.) + bitmap = pygame.Surface(A.get_size(), pygame.SRCALPHA, 32) + bitmap.blit(A, (0, 0)) + rendering = pygame.Surface(A_rendered.get_size(), pygame.SRCALPHA, 32) + rendering.blit(A_rendered, (0, 0)) + self.assertTrue(surf_same_image(rendering, bitmap)) + bitmap = pygame.Surface(u13079.get_size(), pygame.SRCALPHA, 32) + bitmap.blit(u13079, (0, 0)) + rendering = pygame.Surface(u13079_rendered.get_size(), pygame.SRCALPHA, 32) + rendering.blit(u13079_rendered, (0, 0)) + self.assertTrue(surf_same_image(rendering, bitmap)) + + def test_freetype_Font_render_mono(self): + font = self._TEST_FONTS["sans"] + color = pygame.Color("black") + colorkey = pygame.Color("white") + text = "." + + save_antialiased = font.antialiased + font.antialiased = False + try: + surf, r = font.render(text, color, size=24) + self.assertEqual(surf.get_bitsize(), 8) + flags = surf.get_flags() + self.assertTrue(flags & pygame.SRCCOLORKEY) + self.assertFalse(flags & (pygame.SRCALPHA | pygame.HWSURFACE)) + self.assertEqual(surf.get_colorkey(), colorkey) + self.assertIsNone(surf.get_alpha()) + + translucent_color = pygame.Color(*color) + translucent_color.a = 55 + surf, r = font.render(text, translucent_color, size=24) + self.assertEqual(surf.get_bitsize(), 8) + flags = surf.get_flags() + self.assertTrue(flags & (pygame.SRCCOLORKEY | pygame.SRCALPHA)) + self.assertFalse(flags & pygame.HWSURFACE) + self.assertEqual(surf.get_colorkey(), colorkey) + self.assertEqual(surf.get_alpha(), translucent_color.a) + + surf, r = font.render(text, color, colorkey, size=24) + self.assertEqual(surf.get_bitsize(), 32) + finally: + font.antialiased = save_antialiased + + def test_freetype_Font_render_to_mono(self): + # Blitting is done in two stages. First the target is alpha filled + # with the background color, if any. Second, the foreground + # color is alpha blitted to the background. + font = self._TEST_FONTS["sans"] + text = " ." + rect = font.get_rect(text, size=24) + size = rect.size + fg = pygame.Surface((1, 1), pygame.SRCALPHA, 32) + bg = pygame.Surface((1, 1), pygame.SRCALPHA, 32) + surrogate = pygame.Surface((1, 1), pygame.SRCALPHA, 32) + surfaces = [ + pygame.Surface(size, 0, 8), + pygame.Surface(size, 0, 16), + pygame.Surface(size, pygame.SRCALPHA, 16), + pygame.Surface(size, 0, 24), + pygame.Surface(size, 0, 32), + pygame.Surface(size, pygame.SRCALPHA, 32), + ] + fg_colors = [ + surfaces[0].get_palette_at(2), + surfaces[1].unmap_rgb(surfaces[1].map_rgb((128, 64, 200))), + surfaces[2].unmap_rgb(surfaces[2].map_rgb((99, 0, 100, 64))), + (128, 97, 213), + (128, 97, 213), + (128, 97, 213, 60), + ] + fg_colors = [pygame.Color(*c) for c in fg_colors] + self.assertEqual(len(surfaces), len(fg_colors)) # integrity check + bg_colors = [ + surfaces[0].get_palette_at(4), + surfaces[1].unmap_rgb(surfaces[1].map_rgb((220, 20, 99))), + surfaces[2].unmap_rgb(surfaces[2].map_rgb((55, 200, 0, 86))), + (255, 120, 13), + (255, 120, 13), + (255, 120, 13, 180), + ] + bg_colors = [pygame.Color(*c) for c in bg_colors] + self.assertEqual(len(surfaces), len(bg_colors)) # integrity check + + save_antialiased = font.antialiased + font.antialiased = False + try: + fill_color = pygame.Color("black") + for i, surf in enumerate(surfaces): + surf.fill(fill_color) + fg_color = fg_colors[i] + fg.set_at((0, 0), fg_color) + surf.blit(fg, (0, 0)) + r_fg_color = surf.get_at((0, 0)) + surf.set_at((0, 0), fill_color) + rrect = font.render_to(surf, (0, 0), text, fg_color, size=24) + bottomleft = 0, rrect.height - 1 + self.assertEqual( + surf.get_at(bottomleft), + fill_color, + "Position: {}. Depth: {}." + " fg_color: {}.".format(bottomleft, surf.get_bitsize(), fg_color), + ) + bottomright = rrect.width - 1, rrect.height - 1 + self.assertEqual( + surf.get_at(bottomright), + r_fg_color, + "Position: {}. Depth: {}." + " fg_color: {}.".format(bottomright, surf.get_bitsize(), fg_color), + ) + for i, surf in enumerate(surfaces): + surf.fill(fill_color) + fg_color = fg_colors[i] + bg_color = bg_colors[i] + bg.set_at((0, 0), bg_color) + fg.set_at((0, 0), fg_color) + if surf.get_bitsize() == 24: + # For a 24 bit target surface test against Pygame's alpha + # blit as there appears to be a problem with SDL's alpha + # blit: + # + # self.assertEqual(surf.get_at(bottomright), r_fg_color) + # + # raises + # + # AssertionError: (128, 97, 213, 255) != (129, 98, 213, 255) + # + surrogate.set_at((0, 0), fill_color) + surrogate.blit(bg, (0, 0)) + r_bg_color = surrogate.get_at((0, 0)) + surrogate.blit(fg, (0, 0)) + r_fg_color = surrogate.get_at((0, 0)) + else: + # Surface blit values for comparison. + surf.blit(bg, (0, 0)) + r_bg_color = surf.get_at((0, 0)) + surf.blit(fg, (0, 0)) + r_fg_color = surf.get_at((0, 0)) + surf.set_at((0, 0), fill_color) + rrect = font.render_to(surf, (0, 0), text, fg_color, bg_color, size=24) + bottomleft = 0, rrect.height - 1 + self.assertEqual(surf.get_at(bottomleft), r_bg_color) + bottomright = rrect.width - 1, rrect.height - 1 + self.assertEqual(surf.get_at(bottomright), r_fg_color) + finally: + font.antialiased = save_antialiased + + def test_freetype_Font_render_raw(self): + + font = self._TEST_FONTS["sans"] + + text = "abc" + size = font.get_rect(text, size=24).size + rend = font.render_raw(text, size=24) + self.assertIsInstance(rend, tuple) + self.assertEqual(len(rend), 2) + + r, s = rend + self.assertIsInstance(r, bytes) + self.assertIsInstance(s, tuple) + self.assertTrue(len(s), 2) + + w, h = s + self.assertIsInstance(w, int) + self.assertIsInstance(h, int) + self.assertEqual(s, size) + self.assertEqual(len(r), w * h) + + r, (w, h) = font.render_raw("", size=24) + self.assertEqual(w, 0) + self.assertEqual(h, font.height) + self.assertEqual(len(r), 0) + + # bug with decenders: this would crash + rend = font.render_raw("render_raw", size=24) + + # bug with non-printable characters: this would cause a crash + # because the text length was not adjusted for skipped characters. + text = "".join([chr(i) for i in range(31, 64)]) + rend = font.render_raw(text, size=10) + + def test_freetype_Font_render_raw_to(self): + + # This only checks that blits do not crash. It needs to check: + # - int values + # - invert option + # + + font = self._TEST_FONTS["sans"] + text = "abc" + + # No frills antialiased render to int1 (__render_glyph_INT) + srect = font.get_rect(text, size=24) + surf = pygame.Surface(srect.size, 0, 8) + rrect = font.render_raw_to(surf.get_view("2"), text, size=24) + self.assertEqual(rrect, srect) + + for bpp in [24, 32]: + surf = pygame.Surface(srect.size, 0, bpp) + rrect = font.render_raw_to(surf.get_view("r"), text, size=24) + self.assertEqual(rrect, srect) + + # Underlining to int1 (__fill_glyph_INT) + srect = font.get_rect(text, size=24, style=ft.STYLE_UNDERLINE) + surf = pygame.Surface(srect.size, 0, 8) + rrect = font.render_raw_to( + surf.get_view("2"), text, size=24, style=ft.STYLE_UNDERLINE + ) + self.assertEqual(rrect, srect) + + for bpp in [24, 32]: + surf = pygame.Surface(srect.size, 0, bpp) + rrect = font.render_raw_to( + surf.get_view("r"), text, size=24, style=ft.STYLE_UNDERLINE + ) + self.assertEqual(rrect, srect) + + # Unaliased (mono) rendering to int1 (__render_glyph_MONO_as_INT) + font.antialiased = False + try: + srect = font.get_rect(text, size=24) + surf = pygame.Surface(srect.size, 0, 8) + rrect = font.render_raw_to(surf.get_view("2"), text, size=24) + self.assertEqual(rrect, srect) + + for bpp in [24, 32]: + surf = pygame.Surface(srect.size, 0, bpp) + rrect = font.render_raw_to(surf.get_view("r"), text, size=24) + self.assertEqual(rrect, srect) + finally: + font.antialiased = True + + # Antialiased render to ints sized greater than 1 byte + # (__render_glyph_INT) + srect = font.get_rect(text, size=24) + + for bpp in [16, 24, 32]: + surf = pygame.Surface(srect.size, 0, bpp) + rrect = font.render_raw_to(surf.get_view("2"), text, size=24) + self.assertEqual(rrect, srect) + + # Underline render to ints sized greater than 1 byte + # (__fill_glyph_INT) + srect = font.get_rect(text, size=24, style=ft.STYLE_UNDERLINE) + + for bpp in [16, 24, 32]: + surf = pygame.Surface(srect.size, 0, bpp) + rrect = font.render_raw_to( + surf.get_view("2"), text, size=24, style=ft.STYLE_UNDERLINE + ) + self.assertEqual(rrect, srect) + + # Unaliased (mono) rendering to ints greater than 1 byte + # (__render_glyph_MONO_as_INT) + font.antialiased = False + try: + srect = font.get_rect(text, size=24) + + for bpp in [16, 24, 32]: + surf = pygame.Surface(srect.size, 0, bpp) + rrect = font.render_raw_to(surf.get_view("2"), text, size=24) + self.assertEqual(rrect, srect) + finally: + font.antialiased = True + + # Invalid dest parameter test. + srect = font.get_rect(text, size=24) + surf_buf = pygame.Surface(srect.size, 0, 32).get_view("2") + + for dest in [ + 0, + "a", + "ab", + (), + (1,), + ("a", 2), + (1, "a"), + (1 + 2j, 2), + (1, 1 + 2j), + (1, int), + (int, 1), + ]: + self.assertRaises( + TypeError, font.render_raw_to, surf_buf, text, dest, size=24 + ) + + def test_freetype_Font_text_is_None(self): + f = ft.Font(self._sans_path, 36) + f.style = ft.STYLE_NORMAL + f.rotation = 0 + text = "ABCD" + + # reference values + get_rect = f.get_rect(text) + f.vertical = True + get_rect_vert = f.get_rect(text) + + self.assertTrue(get_rect_vert.width < get_rect.width) + self.assertTrue(get_rect_vert.height > get_rect.height) + f.vertical = False + render_to_surf = pygame.Surface(get_rect.size, pygame.SRCALPHA, 32) + + if IS_PYPY: + return + + arr = arrinter.Array(get_rect.size, "u", 1) + render = f.render(text, (0, 0, 0)) + render_to = f.render_to(render_to_surf, (0, 0), text, (0, 0, 0)) + render_raw = f.render_raw(text) + render_raw_to = f.render_raw_to(arr, text) + + # comparisons + surf = pygame.Surface(get_rect.size, pygame.SRCALPHA, 32) + self.assertEqual(f.get_rect(None), get_rect) + s, r = f.render(None, (0, 0, 0)) + self.assertEqual(r, render[1]) + self.assertTrue(surf_same_image(s, render[0])) + r = f.render_to(surf, (0, 0), None, (0, 0, 0)) + self.assertEqual(r, render_to) + self.assertTrue(surf_same_image(surf, render_to_surf)) + px, sz = f.render_raw(None) + self.assertEqual(sz, render_raw[1]) + self.assertEqual(px, render_raw[0]) + sz = f.render_raw_to(arr, None) + self.assertEqual(sz, render_raw_to) + + def test_freetype_Font_text_is_None(self): + f = ft.Font(self._sans_path, 36) + f.style = ft.STYLE_NORMAL + f.rotation = 0 + text = "ABCD" + + # reference values + get_rect = f.get_rect(text) + f.vertical = True + get_rect_vert = f.get_rect(text) + + # vertical: trigger glyph positioning. + f.vertical = True + r = f.get_rect(None) + self.assertEqual(r, get_rect_vert) + f.vertical = False + + # wide style: trigger glyph reload + r = f.get_rect(None, style=ft.STYLE_WIDE) + self.assertEqual(r.height, get_rect.height) + self.assertTrue(r.width > get_rect.width) + r = f.get_rect(None) + self.assertEqual(r, get_rect) + + # rotated: trigger glyph reload + r = f.get_rect(None, rotation=90) + self.assertEqual(r.width, get_rect.height) + self.assertEqual(r.height, get_rect.width) + + # this method will not support None text + self.assertRaises(TypeError, f.get_metrics, None) + + def test_freetype_Font_fgcolor(self): + f = ft.Font(self._bmp_8_75dpi_path) + notdef = "\0" # the PyGameMono .notdef glyph has a pixel at (0, 0) + f.origin = False + f.pad = False + black = pygame.Color("black") # initial color + green = pygame.Color("green") + alpha128 = pygame.Color(10, 20, 30, 128) + + c = f.fgcolor + self.assertIsInstance(c, pygame.Color) + self.assertEqual(c, black) + + s, r = f.render(notdef) + self.assertEqual(s.get_at((0, 0)), black) + + f.fgcolor = green + self.assertEqual(f.fgcolor, green) + + s, r = f.render(notdef) + self.assertEqual(s.get_at((0, 0)), green) + + f.fgcolor = alpha128 + s, r = f.render(notdef) + self.assertEqual(s.get_at((0, 0)), alpha128) + + surf = pygame.Surface(f.get_rect(notdef).size, pygame.SRCALPHA, 32) + f.render_to(surf, (0, 0), None) + self.assertEqual(surf.get_at((0, 0)), alpha128) + + self.assertRaises(AttributeError, setattr, f, "fgcolor", None) + + def test_freetype_Font_bgcolor(self): + f = ft.Font(None, 32) + zero = "0" # the default font 0 glyph does not have a pixel at (0, 0) + f.origin = False + f.pad = False + + transparent_black = pygame.Color(0, 0, 0, 0) # initial color + green = pygame.Color("green") + alpha128 = pygame.Color(10, 20, 30, 128) + + c = f.bgcolor + self.assertIsInstance(c, pygame.Color) + self.assertEqual(c, transparent_black) + + s, r = f.render(zero, pygame.Color(255, 255, 255)) + self.assertEqual(s.get_at((0, 0)), transparent_black) + + f.bgcolor = green + self.assertEqual(f.bgcolor, green) + + s, r = f.render(zero) + self.assertEqual(s.get_at((0, 0)), green) + + f.bgcolor = alpha128 + s, r = f.render(zero) + self.assertEqual(s.get_at((0, 0)), alpha128) + + surf = pygame.Surface(f.get_rect(zero).size, pygame.SRCALPHA, 32) + f.render_to(surf, (0, 0), None) + self.assertEqual(surf.get_at((0, 0)), alpha128) + + self.assertRaises(AttributeError, setattr, f, "bgcolor", None) + + @unittest.skipIf(not pygame.HAVE_NEWBUF, "newbuf not implemented") + @unittest.skipIf(IS_PYPY, "pypy no likey") + def test_newbuf(self): + from pygame.tests.test_utils import buftools + + Exporter = buftools.Exporter + font = self._TEST_FONTS["sans"] + srect = font.get_rect("Hi", size=12) + for format in [ + "b", + "B", + "h", + "H", + "i", + "I", + "l", + "L", + "q", + "Q", + "x", + "1x", + "2x", + "3x", + "4x", + "5x", + "6x", + "7x", + "8x", + "9x", + "h", + "=h", + "@h", + "!h", + "1h", + "=1h", + ]: + newbuf = Exporter(srect.size, format=format) + rrect = font.render_raw_to(newbuf, "Hi", size=12) + self.assertEqual(rrect, srect) + # Some unsupported formats + for format in ["f", "d", "2h", "?", "hh"]: + newbuf = Exporter(srect.size, format=format, itemsize=4) + self.assertRaises(ValueError, font.render_raw_to, newbuf, "Hi", size=12) + + def test_freetype_Font_style(self): + + font = self._TEST_FONTS["sans"] + + # make sure STYLE_NORMAL is the default value + self.assertEqual(ft.STYLE_NORMAL, font.style) + + # make sure we check for style type + with self.assertRaises(TypeError): + font.style = "None" + with self.assertRaises(TypeError): + font.style = None + + # make sure we only accept valid constants + with self.assertRaises(ValueError): + font.style = 112 + + # make assure no assignments happened + self.assertEqual(ft.STYLE_NORMAL, font.style) + + # test assignement + font.style = ft.STYLE_UNDERLINE + self.assertEqual(ft.STYLE_UNDERLINE, font.style) + + # test complex styles + st = ft.STYLE_STRONG | ft.STYLE_UNDERLINE | ft.STYLE_OBLIQUE + + font.style = st + self.assertEqual(st, font.style) + + # and that STYLE_DEFAULT has no effect (continued from above) + self.assertNotEqual(st, ft.STYLE_DEFAULT) + font.style = ft.STYLE_DEFAULT + self.assertEqual(st, font.style) + + # revert changes + font.style = ft.STYLE_NORMAL + self.assertEqual(ft.STYLE_NORMAL, font.style) + + def test_freetype_Font_resolution(self): + text = "|" # Differs in width and height + resolution = ft.get_default_resolution() + new_font = ft.Font(self._sans_path, resolution=2 * resolution) + self.assertEqual(new_font.resolution, 2 * resolution) + size_normal = self._TEST_FONTS["sans"].get_rect(text, size=24).size + size_scaled = new_font.get_rect(text, size=24).size + size_by_2 = size_normal[0] * 2 + self.assertTrue( + size_by_2 + 2 >= size_scaled[0] >= size_by_2 - 2, + "%i not equal %i" % (size_scaled[1], size_by_2), + ) + size_by_2 = size_normal[1] * 2 + self.assertTrue( + size_by_2 + 2 >= size_scaled[1] >= size_by_2 - 2, + "%i not equal %i" % (size_scaled[1], size_by_2), + ) + new_resolution = resolution + 10 + ft.set_default_resolution(new_resolution) + try: + new_font = ft.Font(self._sans_path, resolution=0) + self.assertEqual(new_font.resolution, new_resolution) + finally: + ft.set_default_resolution() + + def test_freetype_Font_path(self): + self.assertEqual(self._TEST_FONTS["sans"].path, self._sans_path) + self.assertRaises(AttributeError, getattr, nullfont(), "path") + + # This Font cache test is conditional on freetype being built by a debug + # version of Python or with the C macro PGFT_DEBUG_CACHE defined. + def test_freetype_Font_cache(self): + glyphs = "abcde" + glen = len(glyphs) + other_glyphs = "123" + oglen = len(other_glyphs) + uempty = str("") + ## many_glyphs = (uempty.join([chr(i) for i in range(32,127)] + + ## [chr(i) for i in range(161,172)] + + ## [chr(i) for i in range(174,239)])) + many_glyphs = uempty.join([chr(i) for i in range(32, 127)]) + mglen = len(many_glyphs) + + count = 0 + access = 0 + hit = 0 + miss = 0 + + f = ft.Font(None, size=24, font_index=0, resolution=72, ucs4=False) + f.style = ft.STYLE_NORMAL + f.antialiased = True + + # Ensure debug counters are zero + self.assertEqual(f._debug_cache_stats, (0, 0, 0, 0, 0)) + # Load some basic glyphs + count = access = miss = glen + f.render_raw(glyphs) + self.assertEqual(f._debug_cache_stats, (count, 0, access, hit, miss)) + # Vertical should not affect the cache + access += glen + hit += glen + f.vertical = True + f.render_raw(glyphs) + f.vertical = False + self.assertEqual(f._debug_cache_stats, (count, 0, access, hit, miss)) + # New glyphs will + count += oglen + access += oglen + miss += oglen + f.render_raw(other_glyphs) + self.assertEqual(f._debug_cache_stats, (count, 0, access, hit, miss)) + # Point size does + count += glen + access += glen + miss += glen + f.render_raw(glyphs, size=12) + self.assertEqual(f._debug_cache_stats, (count, 0, access, hit, miss)) + # Underline style does not + access += oglen + hit += oglen + f.underline = True + f.render_raw(other_glyphs) + f.underline = False + self.assertEqual(f._debug_cache_stats, (count, 0, access, hit, miss)) + # Oblique style does + count += glen + access += glen + miss += glen + f.oblique = True + f.render_raw(glyphs) + f.oblique = False + self.assertEqual(f._debug_cache_stats, (count, 0, access, hit, miss)) + # Strong style does; by this point cache clears can happen + count += glen + access += glen + miss += glen + f.strong = True + f.render_raw(glyphs) + f.strong = False + ccount, cdelete_count, caccess, chit, cmiss = f._debug_cache_stats + self.assertEqual( + (ccount + cdelete_count, caccess, chit, cmiss), (count, access, hit, miss) + ) + # Rotation does + count += glen + access += glen + miss += glen + f.render_raw(glyphs, rotation=10) + ccount, cdelete_count, caccess, chit, cmiss = f._debug_cache_stats + self.assertEqual( + (ccount + cdelete_count, caccess, chit, cmiss), (count, access, hit, miss) + ) + # aliased (mono) glyphs do + count += oglen + access += oglen + miss += oglen + f.antialiased = False + f.render_raw(other_glyphs) + f.antialiased = True + ccount, cdelete_count, caccess, chit, cmiss = f._debug_cache_stats + self.assertEqual( + (ccount + cdelete_count, caccess, chit, cmiss), (count, access, hit, miss) + ) + # Trigger a cleanup for sure. + count += 2 * mglen + access += 2 * mglen + miss += 2 * mglen + f.get_metrics(many_glyphs, size=8) + f.get_metrics(many_glyphs, size=10) + ccount, cdelete_count, caccess, chit, cmiss = f._debug_cache_stats + self.assertTrue(ccount < count) + self.assertEqual( + (ccount + cdelete_count, caccess, chit, cmiss), (count, access, hit, miss) + ) + + try: + ft.Font._debug_cache_stats + except AttributeError: + del test_freetype_Font_cache + + def test_undefined_character_code(self): + # To be consistent with pygame.font.Font, undefined codes + # are rendered as the undefined character, and has metrics + # of None. + font = self._TEST_FONTS["sans"] + + img, size1 = font.render(chr(1), (0, 0, 0), size=24) + img, size0 = font.render("", (0, 0, 0), size=24) + self.assertTrue(size1.width > size0.width) + + metrics = font.get_metrics(chr(1) + chr(48), size=24) + self.assertEqual(len(metrics), 2) + self.assertIsNone(metrics[0]) + self.assertIsInstance(metrics[1], tuple) + + def test_issue_242(self): + """Issue #242: get_rect() uses 0 as default style""" + + # Issue #242: freetype.Font.get_rect() ignores style defaults when + # the style argument is not given + # + # The text boundary rectangle returned by freetype.Font.get_rect() + # should match the boundary of the same text rendered directly to a + # surface. This permits accurate text positioning. To work properly, + # get_rect() should calculate the text boundary to reflect text style, + # such as underline. Instead, it ignores the style settings for the + # Font object when the style argument is omitted. + # + # When the style argument is not given, freetype.get_rect() uses + # unstyled text when calculating the boundary rectangle. This is + # because _ftfont_getrect(), in _freetype.c, set the default + # style to 0 rather than FT_STYLE_DEFAULT. + # + font = self._TEST_FONTS["sans"] + + # Try wide style on a wide character. + prev_style = font.wide + font.wide = True + try: + rect = font.get_rect("M", size=64) + surf, rrect = font.render(None, size=64) + self.assertEqual(rect, rrect) + finally: + font.wide = prev_style + + # Try strong style on several wide characters. + prev_style = font.strong + font.strong = True + try: + rect = font.get_rect("Mm_", size=64) + surf, rrect = font.render(None, size=64) + self.assertEqual(rect, rrect) + finally: + font.strong = prev_style + + # Try oblique style on a tall, narrow character. + prev_style = font.oblique + font.oblique = True + try: + rect = font.get_rect("|", size=64) + surf, rrect = font.render(None, size=64) + self.assertEqual(rect, rrect) + finally: + font.oblique = prev_style + + # Try underline style on a glyphless character. + prev_style = font.underline + font.underline = True + try: + rect = font.get_rect(" ", size=64) + surf, rrect = font.render(None, size=64) + self.assertEqual(rect, rrect) + finally: + font.underline = prev_style + + def test_issue_237(self): + """Issue #237: Memory overrun when rendered with underlining""" + + # Issue #237: Memory overrun when text without descenders is rendered + # with underlining + # + # The bug crashes the Python interpreter. The bug is caught with C + # assertions in ft_render_cb.c when the Pygame module is compiled + # for debugging. So far it is only known to affect Times New Roman. + # + name = "Times New Roman" + font = ft.SysFont(name, 19) + if font.name != name: + # The font is unavailable, so skip the test. + return + font.underline = True + s, r = font.render("Amazon", size=19) + + # Some other checks to make sure nothing else broke. + for adj in [-2, -1.9, -1, 0, 1.9, 2]: + font.underline_adjustment = adj + s, r = font.render("Amazon", size=19) + + def test_issue_243(self): + """Issue Y: trailing space ignored in boundary calculation""" + + # Issue #243: For a string with trailing spaces, freetype ignores the + # last space in boundary calculations + # + font = self._TEST_FONTS["fixed"] + r1 = font.get_rect(" ", size=64) + self.assertTrue(r1.width > 1) + r2 = font.get_rect(" ", size=64) + self.assertEqual(r2.width, 2 * r1.width) + + def test_garbage_collection(self): + """Check reference counting on returned new references""" + + def ref_items(seq): + return [weakref.ref(o) for o in seq] + + font = self._TEST_FONTS["bmp-8-75dpi"] + font.size = font.get_sizes()[0][0] + text = "A" + rect = font.get_rect(text) + surf = pygame.Surface(rect.size, pygame.SRCALPHA, 32) + refs = [] + refs.extend(ref_items(font.render(text, (0, 0, 0)))) + refs.append(weakref.ref(font.render_to(surf, (0, 0), text, (0, 0, 0)))) + refs.append(weakref.ref(font.get_rect(text))) + + n = len(refs) + self.assertTrue(n > 0) + + # for pypy we garbage collection twice. + for i in range(2): + gc.collect() + + for i in range(n): + self.assertIsNone(refs[i](), "ref %d not collected" % i) + + try: + from sys import getrefcount + except ImportError: + pass + else: + array = arrinter.Array(rect.size, "u", 1) + o = font.render_raw(text) + self.assertEqual(getrefcount(o), 2) + self.assertEqual(getrefcount(o[0]), 2) + self.assertEqual(getrefcount(o[1]), 2) + self.assertEqual(getrefcount(font.render_raw_to(array, text)), 1) + o = font.get_metrics("AB") + self.assertEqual(getrefcount(o), 2) + for i in range(len(o)): + self.assertEqual(getrefcount(o[i]), 2, "refcount fail for item %d" % i) + o = font.get_sizes() + self.assertEqual(getrefcount(o), 2) + for i in range(len(o)): + self.assertEqual(getrefcount(o[i]), 2, "refcount fail for item %d" % i) + + def test_display_surface_quit(self): + """Font.render_to() on a closed display surface""" + + # The Font.render_to() method checks that PySurfaceObject.surf is NULL + # and raise a exception if it is. This fixes a bug in Pygame revision + # 0600ea4f1cfb and earlier where Pygame segfaults instead. + null_surface = pygame.Surface.__new__(pygame.Surface) + f = self._TEST_FONTS["sans"] + self.assertRaises( + pygame.error, f.render_to, null_surface, (0, 0), "Crash!", size=12 + ) + + def test_issue_565(self): + """get_metrics supporting rotation/styles/size""" + + tests = [ + {"method": "size", "value": 36, "msg": "metrics same for size"}, + {"method": "rotation", "value": 90, "msg": "metrics same for rotation"}, + {"method": "oblique", "value": True, "msg": "metrics same for oblique"}, + ] + text = "|" + + def run_test(method, value, msg): + font = ft.Font(self._sans_path, size=24) + before = font.get_metrics(text) + font.__setattr__(method, value) + after = font.get_metrics(text) + self.assertNotEqual(before, after, msg) + + for test in tests: + run_test(test["method"], test["value"], test["msg"]) + + def test_freetype_SysFont_name(self): + """that SysFont accepts names of various types""" + fonts = pygame.font.get_fonts() + size = 12 + + # Check single name string: + font_name = ft.SysFont(fonts[0], size).name + self.assertFalse(font_name is None) + + # Check string of comma-separated names. + names = ",".join(fonts) + font_name_2 = ft.SysFont(names, size).name + self.assertEqual(font_name_2, font_name) + + # Check list of names. + font_name_2 = ft.SysFont(fonts, size).name + self.assertEqual(font_name_2, font_name) + + # Check generator: + names = (name for name in fonts) + font_name_2 = ft.SysFont(names, size).name + self.assertEqual(font_name_2, font_name) + + fonts_b = [f.encode() for f in fonts] + + # Check single name bytes. + font_name_2 = ft.SysFont(fonts_b[0], size).name + self.assertEqual(font_name_2, font_name) + + # Check comma-separated bytes. + names = b",".join(fonts_b) + font_name_2 = ft.SysFont(names, size).name + self.assertEqual(font_name_2, font_name) + + # Check list of bytes. + font_name_2 = ft.SysFont(fonts_b, size).name + self.assertEqual(font_name_2, font_name) + + # Check mixed list of bytes and string. + names = [fonts[0], fonts_b[1], fonts[2], fonts_b[3]] + font_name_2 = ft.SysFont(names, size).name + self.assertEqual(font_name_2, font_name) + + def test_pathlib(self): + f = ft.Font(pathlib.Path(self._fixed_path), 20) + + +class FreeTypeTest(unittest.TestCase): + def setUp(self): + ft.init() + + def tearDown(self): + ft.quit() + + def test_resolution(self): + try: + ft.set_default_resolution() + resolution = ft.get_default_resolution() + self.assertEqual(resolution, 72) + new_resolution = resolution + 10 + ft.set_default_resolution(new_resolution) + self.assertEqual(ft.get_default_resolution(), new_resolution) + ft.init(resolution=resolution + 20) + self.assertEqual(ft.get_default_resolution(), new_resolution) + finally: + ft.set_default_resolution() + + def test_autoinit_and_autoquit(self): + pygame.init() + self.assertTrue(ft.get_init()) + pygame.quit() + self.assertFalse(ft.get_init()) + + # Ensure autoquit is replaced at init time + pygame.init() + self.assertTrue(ft.get_init()) + pygame.quit() + self.assertFalse(ft.get_init()) + + def test_init(self): + # Test if module initialized after calling init(). + ft.quit() + ft.init() + + self.assertTrue(ft.get_init()) + + def test_init__multiple(self): + # Test if module initialized after multiple init() calls. + ft.init() + ft.init() + + self.assertTrue(ft.get_init()) + + def test_quit(self): + # Test if module uninitialized after calling quit(). + ft.quit() + + self.assertFalse(ft.get_init()) + + def test_quit__multiple(self): + # Test if module initialized after multiple quit() calls. + ft.quit() + ft.quit() + + self.assertFalse(ft.get_init()) + + def test_get_init(self): + # Test if get_init() gets the init state. + self.assertTrue(ft.get_init()) + + def test_cache_size(self): + DEFAULT_CACHE_SIZE = 64 + self.assertEqual(ft.get_cache_size(), DEFAULT_CACHE_SIZE) + ft.quit() + self.assertEqual(ft.get_cache_size(), 0) + new_cache_size = DEFAULT_CACHE_SIZE * 2 + ft.init(cache_size=new_cache_size) + self.assertEqual(ft.get_cache_size(), new_cache_size) + + def test_get_error(self): + """Ensures get_error() is initially empty (None).""" + error_msg = ft.get_error() + + self.assertIsNone(error_msg) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/ftfont_tags.py b/venv/Lib/site-packages/pygame/tests/ftfont_tags.py new file mode 100644 index 0000000..0d538f4 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/ftfont_tags.py @@ -0,0 +1,11 @@ +__tags__ = ["development"] + +exclude = False + +try: + import pygame.ftfont +except ImportError: + exclude = True + +if exclude: + __tags__.extend(["ignore", "subprocess_ignore"]) diff --git a/venv/Lib/site-packages/pygame/tests/ftfont_test.py b/venv/Lib/site-packages/pygame/tests/ftfont_test.py new file mode 100644 index 0000000..1f71204 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/ftfont_test.py @@ -0,0 +1,19 @@ +import sys +import os +import unittest +from pygame.tests import font_test + +import pygame.ftfont + +font_test.pygame_font = pygame.ftfont +# Disable UCS-4 specific tests as this "Font" type does accept UCS-4 codes. +font_test.UCS_4 = False + +for name in dir(font_test): + obj = getattr(font_test, name) + if isinstance(obj, type) and issubclass(obj, unittest.TestCase): # conditional and + new_name = "Ft%s" % name + globals()[new_name] = type(new_name, (obj,), {}) + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/gfxdraw_test.py b/venv/Lib/site-packages/pygame/tests/gfxdraw_test.py new file mode 100644 index 0000000..293cef3 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/gfxdraw_test.py @@ -0,0 +1,877 @@ +import unittest +import pygame +import pygame.gfxdraw +from pygame.locals import * +from pygame.tests.test_utils import SurfaceSubclass + + +def intensity(c, i): + """Return color c changed by intensity i + + For 0 <= i <= 127 the color is a shade, with 0 being black, 127 being the + unaltered color. + + For 128 <= i <= 255 the color is a tint, with 255 being white, 128 the + unaltered color. + + """ + r, g, b = c[0:3] + if 0 <= i <= 127: + # Darken + return ((r * i) // 127, (g * i) // 127, (b * i) // 127) + # Lighten + return ( + r + ((255 - r) * (255 - i)) // 127, + g + ((255 - g) * (255 - i)) // 127, + b + ((255 - b) * (255 - i)) // 127, + ) + + +class GfxdrawDefaultTest(unittest.TestCase): + + is_started = False + + foreground_color = (128, 64, 8) + background_color = (255, 255, 255) + + def make_palette(base_color): + """Return color palette that is various intensities of base_color""" + # Need this function for Python 3.x so the base_color + # is within the scope of the list comprehension. + return [intensity(base_color, i) for i in range(0, 256)] + + default_palette = make_palette(foreground_color) + + default_size = (100, 100) + + def check_at(self, surf, posn, color): + sc = surf.get_at(posn) + fail_msg = "%s != %s at %s, bitsize: %i, flags: %i, masks: %s" % ( + sc, + color, + posn, + surf.get_bitsize(), + surf.get_flags(), + surf.get_masks(), + ) + self.assertEqual(sc, color, fail_msg) + + def check_not_at(self, surf, posn, color): + sc = surf.get_at(posn) + fail_msg = "%s != %s at %s, bitsize: %i, flags: %i, masks: %s" % ( + sc, + color, + posn, + surf.get_bitsize(), + surf.get_flags(), + surf.get_masks(), + ) + self.assertNotEqual(sc, color, fail_msg) + + @classmethod + def setUpClass(cls): + # Necessary for Surface.set_palette. + pygame.init() + pygame.display.set_mode((1, 1)) + + @classmethod + def tearDownClass(cls): + pygame.quit() + + def setUp(self): + # This makes sure pygame is always initialized before each test (in + # case a test calls pygame.quit()). + if not pygame.get_init(): + pygame.init() + + Surface = pygame.Surface + size = self.default_size + palette = self.default_palette + if not self.is_started: + # Create test surfaces + self.surfaces = [ + Surface(size, 0, 8), + Surface(size, SRCALPHA, 16), + Surface(size, SRCALPHA, 32), + ] + self.surfaces[0].set_palette(palette) + nonpalette_fmts = ( + # (8, (0xe0, 0x1c, 0x3, 0x0)), + (12, (0xF00, 0xF0, 0xF, 0x0)), + (15, (0x7C00, 0x3E0, 0x1F, 0x0)), + (15, (0x1F, 0x3E0, 0x7C00, 0x0)), + (16, (0xF00, 0xF0, 0xF, 0xF000)), + (16, (0xF000, 0xF00, 0xF0, 0xF)), + (16, (0xF, 0xF0, 0xF00, 0xF000)), + (16, (0xF0, 0xF00, 0xF000, 0xF)), + (16, (0x7C00, 0x3E0, 0x1F, 0x8000)), + (16, (0xF800, 0x7C0, 0x3E, 0x1)), + (16, (0x1F, 0x3E0, 0x7C00, 0x8000)), + (16, (0x3E, 0x7C0, 0xF800, 0x1)), + (16, (0xF800, 0x7E0, 0x1F, 0x0)), + (16, (0x1F, 0x7E0, 0xF800, 0x0)), + (24, (0xFF, 0xFF00, 0xFF0000, 0x0)), + (24, (0xFF0000, 0xFF00, 0xFF, 0x0)), + (32, (0xFF0000, 0xFF00, 0xFF, 0x0)), + (32, (0xFF000000, 0xFF0000, 0xFF00, 0x0)), + (32, (0xFF, 0xFF00, 0xFF0000, 0x0)), + (32, (0xFF00, 0xFF0000, 0xFF000000, 0x0)), + (32, (0xFF0000, 0xFF00, 0xFF, 0xFF000000)), + (32, (0xFF000000, 0xFF0000, 0xFF00, 0xFF)), + (32, (0xFF, 0xFF00, 0xFF0000, 0xFF000000)), + (32, (0xFF00, 0xFF0000, 0xFF000000, 0xFF)), + ) + for bitsize, masks in nonpalette_fmts: + self.surfaces.append(Surface(size, 0, bitsize, masks)) + for surf in self.surfaces: + surf.fill(self.background_color) + + def test_gfxdraw__subclassed_surface(self): + """Ensure pygame.gfxdraw works on subclassed surfaces.""" + surface = SurfaceSubclass((11, 13), SRCALPHA, 32) + surface.fill(pygame.Color("blue")) + expected_color = pygame.Color("red") + x, y = 1, 2 + + pygame.gfxdraw.pixel(surface, x, y, expected_color) + + self.assertEqual(surface.get_at((x, y)), expected_color) + + def test_pixel(self): + """pixel(surface, x, y, color): return None""" + fg = self.foreground_color + bg = self.background_color + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.pixel(surf, 2, 2, fg) + for x in range(1, 4): + for y in range(1, 4): + if x == 2 and y == 2: + self.check_at(surf, (x, y), fg_adjusted) + else: + self.check_at(surf, (x, y), bg_adjusted) + + def test_hline(self): + """hline(surface, x1, x2, y, color): return None""" + fg = self.foreground_color + bg = self.background_color + startx = 10 + stopx = 80 + y = 50 + fg_test_points = [(startx, y), (stopx, y), ((stopx - startx) // 2, y)] + bg_test_points = [ + (startx - 1, y), + (stopx + 1, y), + (startx, y - 1), + (startx, y + 1), + (stopx, y - 1), + (stopx, y + 1), + ] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.hline(surf, startx, stopx, y, fg) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + def test_vline(self): + """vline(surface, x, y1, y2, color): return None""" + fg = self.foreground_color + bg = self.background_color + x = 50 + starty = 10 + stopy = 80 + fg_test_points = [(x, starty), (x, stopy), (x, (stopy - starty) // 2)] + bg_test_points = [ + (x, starty - 1), + (x, stopy + 1), + (x - 1, starty), + (x + 1, starty), + (x - 1, stopy), + (x + 1, stopy), + ] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.vline(surf, x, starty, stopy, fg) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + def test_rectangle(self): + """rectangle(surface, rect, color): return None""" + fg = self.foreground_color + bg = self.background_color + rect = pygame.Rect(10, 15, 55, 62) + rect_tuple = tuple(rect) + fg_test_points = [ + rect.topleft, + (rect.right - 1, rect.top), + (rect.left, rect.bottom - 1), + (rect.right - 1, rect.bottom - 1), + ] + bg_test_points = [ + (rect.left - 1, rect.top - 1), + (rect.left + 1, rect.top + 1), + (rect.right, rect.top - 1), + (rect.right - 2, rect.top + 1), + (rect.left - 1, rect.bottom), + (rect.left + 1, rect.bottom - 2), + (rect.right, rect.bottom), + (rect.right - 2, rect.bottom - 2), + ] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.rectangle(surf, rect, fg) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + surf.fill(bg) + pygame.gfxdraw.rectangle(surf, rect_tuple, fg) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + def test_box(self): + """box(surface, rect, color): return None""" + fg = self.foreground_color + bg = self.background_color + rect = pygame.Rect(10, 15, 55, 62) + rect_tuple = tuple(rect) + fg_test_points = [ + rect.topleft, + (rect.left + 1, rect.top + 1), + (rect.right - 1, rect.top), + (rect.right - 2, rect.top + 1), + (rect.left, rect.bottom - 1), + (rect.left + 1, rect.bottom - 2), + (rect.right - 1, rect.bottom - 1), + (rect.right - 2, rect.bottom - 2), + ] + bg_test_points = [ + (rect.left - 1, rect.top - 1), + (rect.right, rect.top - 1), + (rect.left - 1, rect.bottom), + (rect.right, rect.bottom), + ] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.box(surf, rect, fg) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + surf.fill(bg) + pygame.gfxdraw.box(surf, rect_tuple, fg) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + def test_line(self): + """line(surface, x1, y1, x2, y2, color): return None""" + fg = self.foreground_color + bg = self.background_color + x1 = 10 + y1 = 15 + x2 = 92 + y2 = 77 + fg_test_points = [(x1, y1), (x2, y2)] + bg_test_points = [ + (x1 - 1, y1), + (x1, y1 - 1), + (x1 - 1, y1 - 1), + (x2 + 1, y2), + (x2, y2 + 1), + (x2 + 1, y2 + 1), + ] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.line(surf, x1, y1, x2, y2, fg) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + def test_circle(self): + """circle(surface, x, y, r, color): return None""" + fg = self.foreground_color + bg = self.background_color + x = 45 + y = 40 + r = 30 + fg_test_points = [(x, y - r), (x, y + r), (x - r, y), (x + r, y)] + bg_test_points = [ + (x, y), + (x, y - r + 1), + (x, y - r - 1), + (x, y + r + 1), + (x, y + r - 1), + (x - r - 1, y), + (x - r + 1, y), + (x + r + 1, y), + (x + r - 1, y), + ] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.circle(surf, x, y, r, fg) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + def test_arc(self): + """arc(surface, x, y, r, start, end, color): return None""" + fg = self.foreground_color + bg = self.background_color + x = 45 + y = 40 + r = 30 + start = 0 # +x direction, but not (x + r, y) (?) + end = 90 # -y direction, including (x, y + r) + fg_test_points = [(x, y + r), (x + r, y + 1)] + bg_test_points = [ + (x, y), + (x, y - r), + (x - r, y), + (x, y + r + 1), + (x, y + r - 1), + (x - 1, y + r), + (x + r + 1, y), + (x + r - 1, y), + (x + r, y), + ] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.arc(surf, x, y, r, start, end, fg) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + def test_aacircle(self): + """aacircle(surface, x, y, r, color): return None""" + fg = self.foreground_color + bg = self.background_color + x = 45 + y = 40 + r = 30 + fg_test_points = [(x, y - r), (x, y + r), (x - r, y), (x + r, y)] + bg_test_points = [ + (x, y), + (x, y - r + 1), + (x, y - r - 1), + (x, y + r + 1), + (x, y + r - 1), + (x - r - 1, y), + (x - r + 1, y), + (x + r + 1, y), + (x + r - 1, y), + ] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.aacircle(surf, x, y, r, fg) + for posn in fg_test_points: + self.check_not_at(surf, posn, bg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + def test_filled_circle(self): + """filled_circle(surface, x, y, r, color): return None""" + fg = self.foreground_color + bg = self.background_color + x = 45 + y = 40 + r = 30 + fg_test_points = [ + (x, y - r), + (x, y - r + 1), + (x, y + r), + (x, y + r - 1), + (x - r, y), + (x - r + 1, y), + (x + r, y), + (x + r - 1, y), + (x, y), + ] + bg_test_points = [ + (x, y - r - 1), + (x, y + r + 1), + (x - r - 1, y), + (x + r + 1, y), + ] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.filled_circle(surf, x, y, r, fg) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + def test_ellipse(self): + """ellipse(surface, x, y, rx, ry, color): return None""" + fg = self.foreground_color + bg = self.background_color + x = 45 + y = 40 + rx = 30 + ry = 35 + fg_test_points = [(x, y - ry), (x, y + ry), (x - rx, y), (x + rx, y)] + bg_test_points = [ + (x, y), + (x, y - ry + 1), + (x, y - ry - 1), + (x, y + ry + 1), + (x, y + ry - 1), + (x - rx - 1, y), + (x - rx + 1, y), + (x + rx + 1, y), + (x + rx - 1, y), + ] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.ellipse(surf, x, y, rx, ry, fg) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + def test_aaellipse(self): + """aaellipse(surface, x, y, rx, ry, color): return None""" + fg = self.foreground_color + bg = self.background_color + x = 45 + y = 40 + rx = 30 + ry = 35 + fg_test_points = [(x, y - ry), (x, y + ry), (x - rx, y), (x + rx, y)] + bg_test_points = [ + (x, y), + (x, y - ry + 1), + (x, y - ry - 1), + (x, y + ry + 1), + (x, y + ry - 1), + (x - rx - 1, y), + (x - rx + 1, y), + (x + rx + 1, y), + (x + rx - 1, y), + ] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.aaellipse(surf, x, y, rx, ry, fg) + for posn in fg_test_points: + self.check_not_at(surf, posn, bg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + def test_filled_ellipse(self): + """filled_ellipse(surface, x, y, rx, ry, color): return None""" + fg = self.foreground_color + bg = self.background_color + x = 45 + y = 40 + rx = 30 + ry = 35 + fg_test_points = [ + (x, y - ry), + (x, y - ry + 1), + (x, y + ry), + (x, y + ry - 1), + (x - rx, y), + (x - rx + 1, y), + (x + rx, y), + (x + rx - 1, y), + (x, y), + ] + bg_test_points = [ + (x, y - ry - 1), + (x, y + ry + 1), + (x - rx - 1, y), + (x + rx + 1, y), + ] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.filled_ellipse(surf, x, y, rx, ry, fg) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + def test_pie(self): + """pie(surface, x, y, r, start, end, color): return None""" + fg = self.foreground_color + bg = self.background_color + x = 45 + y = 40 + r = 30 + start = 0 # +x direction, including (x + r, y) + end = 90 # -y direction, but not (x, y + r) (?) + fg_test_points = [(x, y), (x + 1, y), (x, y + 1), (x + r, y)] + bg_test_points = [ + (x - 1, y), + (x, y - 1), + (x - 1, y - 1), + (x + 1, y + 1), + (x + r + 1, y), + (x + r, y - 1), + (x, y + r + 1), + ] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.pie(surf, x, y, r, start, end, fg) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + def test_trigon(self): + """trigon(surface, x1, y1, x2, y2, x3, y3, color): return None""" + fg = self.foreground_color + bg = self.background_color + x1 = 10 + y1 = 15 + x2 = 92 + y2 = 77 + x3 = 20 + y3 = 60 + fg_test_points = [(x1, y1), (x2, y2), (x3, y3)] + bg_test_points = [ + (x1 - 1, y1 - 1), + (x2 + 1, y2 + 1), + (x3 - 1, y3 + 1), + (x1 + 10, y1 + 30), + ] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.trigon(surf, x1, y1, x2, y2, x3, y3, fg) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + def test_aatrigon(self): + """aatrigon(surface, x1, y1, x2, y2, x3, y3, color): return None""" + fg = self.foreground_color + bg = self.background_color + x1 = 10 + y1 = 15 + x2 = 92 + y2 = 77 + x3 = 20 + y3 = 60 + fg_test_points = [(x1, y1), (x2, y2), (x3, y3)] + bg_test_points = [ + (x1 - 1, y1 - 1), + (x2 + 1, y2 + 1), + (x3 - 1, y3 + 1), + (x1 + 10, y1 + 30), + ] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.aatrigon(surf, x1, y1, x2, y2, x3, y3, fg) + for posn in fg_test_points: + self.check_not_at(surf, posn, bg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + def test_aatrigon__with_horizontal_edge(self): + """Ensure aatrigon draws horizontal edges correctly. + + This test creates 2 surfaces and draws an aatrigon on each. The pixels + on each surface are compared to ensure they are the same. The only + difference between the 2 aatrigons is the order the points are drawn. + The order of the points should have no impact on the final drawing. + + Related to issue #622. + """ + bg_color = pygame.Color("white") + line_color = pygame.Color("black") + width, height = 11, 10 + expected_surface = pygame.Surface((width, height), 0, 32) + expected_surface.fill(bg_color) + surface = pygame.Surface((width, height), 0, 32) + surface.fill(bg_color) + + x1, y1 = width - 1, 0 + x2, y2 = (width - 1) // 2, height - 1 + x3, y3 = 0, 0 + + # The points in this order draw as expected. + pygame.gfxdraw.aatrigon(expected_surface, x1, y1, x2, y2, x3, y3, line_color) + + # The points in reverse order fail to draw the horizontal edge along + # the top. + pygame.gfxdraw.aatrigon(surface, x3, y3, x2, y2, x1, y1, line_color) + + # The surfaces are locked for a possible speed up of pixel access. + expected_surface.lock() + surface.lock() + for x in range(width): + for y in range(height): + self.assertEqual( + expected_surface.get_at((x, y)), + surface.get_at((x, y)), + "pos=({}, {})".format(x, y), + ) + + surface.unlock() + expected_surface.unlock() + + def test_filled_trigon(self): + """filled_trigon(surface, x1, y1, x2, y2, x3, y3, color): return None""" + fg = self.foreground_color + bg = self.background_color + x1 = 10 + y1 = 15 + x2 = 92 + y2 = 77 + x3 = 20 + y3 = 60 + fg_test_points = [(x1, y1), (x2, y2), (x3, y3), (x1 + 10, y1 + 30)] + bg_test_points = [(x1 - 1, y1 - 1), (x2 + 1, y2 + 1), (x3 - 1, y3 + 1)] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.filled_trigon(surf, x1, y1, x2, y2, x3, y3, fg) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + def test_polygon(self): + """polygon(surface, points, color): return None""" + fg = self.foreground_color + bg = self.background_color + points = [(10, 80), (10, 15), (92, 25), (92, 80)] + fg_test_points = points + [ + (points[0][0], points[0][1] - 1), + (points[0][0] + 1, points[0][1]), + (points[3][0] - 1, points[3][1]), + (points[3][0], points[3][1] - 1), + (points[2][0], points[2][1] + 1), + ] + bg_test_points = [ + (points[0][0] - 1, points[0][1]), + (points[0][0], points[0][1] + 1), + (points[0][0] - 1, points[0][1] + 1), + (points[0][0] + 1, points[0][1] - 1), + (points[3][0] + 1, points[3][1]), + (points[3][0], points[3][1] + 1), + (points[3][0] + 1, points[3][1] + 1), + (points[3][0] - 1, points[3][1] - 1), + (points[2][0] + 1, points[2][1]), + (points[2][0] - 1, points[2][1] + 1), + (points[1][0] - 1, points[1][1]), + (points[1][0], points[1][1] - 1), + (points[1][0] - 1, points[1][1] - 1), + ] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.polygon(surf, points, fg) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + def test_aapolygon(self): + """aapolygon(surface, points, color): return None""" + fg = self.foreground_color + bg = self.background_color + points = [(10, 80), (10, 15), (92, 25), (92, 80)] + fg_test_points = points + bg_test_points = [ + (points[0][0] - 1, points[0][1]), + (points[0][0], points[0][1] + 1), + (points[0][0] - 1, points[0][1] + 1), + (points[0][0] + 1, points[0][1] - 1), + (points[3][0] + 1, points[3][1]), + (points[3][0], points[3][1] + 1), + (points[3][0] + 1, points[3][1] + 1), + (points[3][0] - 1, points[3][1] - 1), + (points[2][0] + 1, points[2][1]), + (points[2][0] - 1, points[2][1] + 1), + (points[1][0] - 1, points[1][1]), + (points[1][0], points[1][1] - 1), + (points[1][0] - 1, points[1][1] - 1), + ] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.aapolygon(surf, points, fg) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_not_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + def test_aapolygon__with_horizontal_edge(self): + """Ensure aapolygon draws horizontal edges correctly. + + This test creates 2 surfaces and draws a polygon on each. The pixels + on each surface are compared to ensure they are the same. The only + difference between the 2 polygons is that one is drawn using + aapolygon() and the other using multiple line() calls. They should + produce the same final drawing. + + Related to issue #622. + """ + bg_color = pygame.Color("white") + line_color = pygame.Color("black") + width, height = 11, 10 + expected_surface = pygame.Surface((width, height), 0, 32) + expected_surface.fill(bg_color) + surface = pygame.Surface((width, height), 0, 32) + surface.fill(bg_color) + + points = ((0, 0), (0, height - 1), (width - 1, height - 1), (width - 1, 0)) + + # The points are used to draw the expected aapolygon using the line() + # function. + for (x1, y1), (x2, y2) in zip(points, points[1:] + points[:1]): + pygame.gfxdraw.line(expected_surface, x1, y1, x2, y2, line_color) + + # The points in this order fail to draw the horizontal edge along + # the top. + pygame.gfxdraw.aapolygon(surface, points, line_color) + + # The surfaces are locked for a possible speed up of pixel access. + expected_surface.lock() + surface.lock() + for x in range(width): + for y in range(height): + self.assertEqual( + expected_surface.get_at((x, y)), + surface.get_at((x, y)), + "pos=({}, {})".format(x, y), + ) + + surface.unlock() + expected_surface.unlock() + + def test_filled_polygon(self): + """filled_polygon(surface, points, color): return None""" + fg = self.foreground_color + bg = self.background_color + points = [(10, 80), (10, 15), (92, 25), (92, 80)] + fg_test_points = points + [ + (points[0][0], points[0][1] - 1), + (points[0][0] + 1, points[0][1]), + (points[0][0] + 1, points[0][1] - 1), + (points[3][0] - 1, points[3][1]), + (points[3][0], points[3][1] - 1), + (points[3][0] - 1, points[3][1] - 1), + (points[2][0], points[2][1] + 1), + (points[2][0] - 1, points[2][1] + 1), + ] + bg_test_points = [ + (points[0][0] - 1, points[0][1]), + (points[0][0], points[0][1] + 1), + (points[0][0] - 1, points[0][1] + 1), + (points[3][0] + 1, points[3][1]), + (points[3][0], points[3][1] + 1), + (points[3][0] + 1, points[3][1] + 1), + (points[2][0] + 1, points[2][1]), + (points[1][0] - 1, points[1][1]), + (points[1][0], points[1][1] - 1), + (points[1][0] - 1, points[1][1] - 1), + ] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.filled_polygon(surf, points, fg) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + def test_textured_polygon(self): + """textured_polygon(surface, points, texture, tx, ty): return None""" + w, h = self.default_size + fg = self.foreground_color + bg = self.background_color + tx = 0 + ty = 0 + texture = pygame.Surface((w + tx, h + ty), 0, 24) + texture.fill(fg, (0, 0, w, h)) + points = [(10, 80), (10, 15), (92, 25), (92, 80)] + # Don't know how to really check this as boarder points may + # or may not be included in the textured polygon. + fg_test_points = [(points[1][0] + 30, points[1][1] + 40)] + bg_test_points = [ + (points[0][0] - 1, points[0][1]), + (points[0][0], points[0][1] + 1), + (points[0][0] - 1, points[0][1] + 1), + (points[3][0] + 1, points[3][1]), + (points[3][0], points[3][1] + 1), + (points[3][0] + 1, points[3][1] + 1), + (points[2][0] + 1, points[2][1]), + (points[1][0] - 1, points[1][1]), + (points[1][0], points[1][1] - 1), + (points[1][0] - 1, points[1][1] - 1), + ] + for surf in self.surfaces[1:]: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.textured_polygon(surf, points, texture, -tx, -ty) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + # Alpha blit to 8 bits-per-pixel surface forbidden. + texture = pygame.Surface(self.default_size, SRCALPHA, 32) + self.assertRaises( + ValueError, + pygame.gfxdraw.textured_polygon, + self.surfaces[0], + points, + texture, + 0, + 0, + ) + + def test_bezier(self): + """bezier(surface, points, steps, color): return None""" + fg = self.foreground_color + bg = self.background_color + points = [(10, 50), (25, 15), (60, 80), (92, 30)] + fg_test_points = [points[0], points[3]] + bg_test_points = [ + (points[0][0] - 1, points[0][1]), + (points[3][0] + 1, points[3][1]), + (points[1][0], points[1][1] + 3), + (points[2][0], points[2][1] - 3), + ] + for surf in self.surfaces: + fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg)) + bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg)) + pygame.gfxdraw.bezier(surf, points, 30, fg) + for posn in fg_test_points: + self.check_at(surf, posn, fg_adjusted) + for posn in bg_test_points: + self.check_at(surf, posn, bg_adjusted) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/image__save_gl_surface_test.py b/venv/Lib/site-packages/pygame/tests/image__save_gl_surface_test.py new file mode 100644 index 0000000..2932f42 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/image__save_gl_surface_test.py @@ -0,0 +1,46 @@ +import os +import unittest + +from pygame.tests import test_utils +import pygame +from pygame.locals import * + + +@unittest.skipIf( + os.environ.get("SDL_VIDEODRIVER") == "dummy", + 'OpenGL requires a non-"dummy" SDL_VIDEODRIVER', +) +class GL_ImageSave(unittest.TestCase): + def test_image_save_works_with_opengl_surfaces(self): + """ + |tags:display,slow,opengl| + """ + + pygame.display.init() + screen = pygame.display.set_mode((640, 480), OPENGL | DOUBLEBUF) + pygame.display.flip() + + tmp_dir = test_utils.get_tmp_dir() + # Try the imageext module. + tmp_file = os.path.join(tmp_dir, "opengl_save_surface_test.png") + pygame.image.save(screen, tmp_file) + + self.assertTrue(os.path.exists(tmp_file)) + + os.remove(tmp_file) + + # Only test the image module. + tmp_file = os.path.join(tmp_dir, "opengl_save_surface_test.bmp") + pygame.image.save(screen, tmp_file) + + self.assertTrue(os.path.exists(tmp_file)) + + os.remove(tmp_file) + + # stops tonnes of tmp dirs building up in trunk dir + os.rmdir(tmp_dir) + pygame.display.quit() + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/image_tags.py b/venv/Lib/site-packages/pygame/tests/image_tags.py new file mode 100644 index 0000000..d847903 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/image_tags.py @@ -0,0 +1,7 @@ +__tags__ = [] + +import pygame +import sys + +if "pygame.image" not in sys.modules: + __tags__.extend(("ignore", "subprocess_ignore")) diff --git a/venv/Lib/site-packages/pygame/tests/image_test.py b/venv/Lib/site-packages/pygame/tests/image_test.py new file mode 100644 index 0000000..a3522fb --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/image_test.py @@ -0,0 +1,1115 @@ +# -*- coding: utf-8 -*- + +import array +import binascii +import io +import os +import tempfile +import unittest +import glob +import pathlib + +from pygame.tests.test_utils import example_path, png, tostring +import pygame, pygame.image, pygame.pkgdata + + +def test_magic(f, magic_hexes): + """Tests a given file to see if the magic hex matches.""" + data = f.read(len(magic_hexes)) + if len(data) != len(magic_hexes): + return 0 + for i, magic_hex in enumerate(magic_hexes): + if magic_hex != data[i]: + return 0 + return 1 + + +class ImageModuleTest(unittest.TestCase): + def testLoadIcon(self): + """see if we can load the pygame icon.""" + f = pygame.pkgdata.getResource("pygame_icon.bmp") + self.assertEqual(f.mode, "rb") + + surf = pygame.image.load_basic(f) + + self.assertEqual(surf.get_at((0, 0)), (5, 4, 5, 255)) + self.assertEqual(surf.get_height(), 32) + self.assertEqual(surf.get_width(), 32) + + def testLoadPNG(self): + """see if we can load a png with color values in the proper channels.""" + # Create a PNG file with known colors + reddish_pixel = (210, 0, 0, 255) + greenish_pixel = (0, 220, 0, 255) + bluish_pixel = (0, 0, 230, 255) + greyish_pixel = (110, 120, 130, 140) + pixel_array = [reddish_pixel + greenish_pixel, bluish_pixel + greyish_pixel] + + f_descriptor, f_path = tempfile.mkstemp(suffix=".png") + + with os.fdopen(f_descriptor, "wb") as f: + w = png.Writer(2, 2, alpha=True) + w.write(f, pixel_array) + + # Read the PNG file and verify that pygame interprets it correctly + surf = pygame.image.load(f_path) + + self.assertEqual(surf.get_at((0, 0)), reddish_pixel) + self.assertEqual(surf.get_at((1, 0)), greenish_pixel) + self.assertEqual(surf.get_at((0, 1)), bluish_pixel) + self.assertEqual(surf.get_at((1, 1)), greyish_pixel) + + # Read the PNG file obj. and verify that pygame interprets it correctly + with open(f_path, "rb") as f: + surf = pygame.image.load(f) + + self.assertEqual(surf.get_at((0, 0)), reddish_pixel) + self.assertEqual(surf.get_at((1, 0)), greenish_pixel) + self.assertEqual(surf.get_at((0, 1)), bluish_pixel) + self.assertEqual(surf.get_at((1, 1)), greyish_pixel) + + os.remove(f_path) + + def testLoadJPG(self): + """to see if we can load a jpg.""" + f = example_path("data/alien1.jpg") + surf = pygame.image.load(f) + + with open(f, "rb") as f: + surf = pygame.image.load(f) + + def testLoadBytesIO(self): + """to see if we can load images with BytesIO.""" + files = [ + "data/alien1.png", + "data/alien1.jpg", + "data/alien1.gif", + "data/asprite.bmp", + ] + + for fname in files: + with self.subTest(fname=fname): + with open(example_path(fname), "rb") as f: + img_bytes = f.read() + img_file = io.BytesIO(img_bytes) + image = pygame.image.load(img_file) + + def testSaveJPG(self): + """JPG equivalent to issue #211 - color channel swapping + + Make sure the SDL surface color masks represent the rgb memory format + required by the JPG library. The masks are machine endian dependent + """ + + from pygame import Color, Rect + + # The source image is a 2 by 2 square of four colors. Since JPEG is + # lossy, there can be color bleed. Make each color square 16 by 16, + # to avoid the significantly color value distorts found at color + # boundaries due to the compression value set by Pygame. + square_len = 16 + sz = 2 * square_len, 2 * square_len + + # +---------------------------------+ + # | red | green | + # |----------------+----------------| + # | blue | (255, 128, 64) | + # +---------------------------------+ + # + # as (rect, color) pairs. + def as_rect(square_x, square_y): + return Rect( + square_x * square_len, square_y * square_len, square_len, square_len + ) + + squares = [ + (as_rect(0, 0), Color("red")), + (as_rect(1, 0), Color("green")), + (as_rect(0, 1), Color("blue")), + (as_rect(1, 1), Color(255, 128, 64)), + ] + + # A surface format which is not directly usable with libjpeg. + surf = pygame.Surface(sz, 0, 32) + for rect, color in squares: + surf.fill(color, rect) + + # Assume pygame.image.Load works correctly as it is handled by the + # third party SDL_image library. + f_path = tempfile.mktemp(suffix=".jpg") + pygame.image.save(surf, f_path) + jpg_surf = pygame.image.load(f_path) + + # Allow for small differences in the restored colors. + def approx(c): + mask = 0xFC + return pygame.Color(c.r & mask, c.g & mask, c.b & mask) + + offset = square_len // 2 + for rect, color in squares: + posn = rect.move((offset, offset)).topleft + self.assertEqual(approx(jpg_surf.get_at(posn)), approx(color)) + + os.remove(f_path) + + def testSavePNG32(self): + """see if we can save a png with color values in the proper channels.""" + # Create a PNG file with known colors + reddish_pixel = (215, 0, 0, 255) + greenish_pixel = (0, 225, 0, 255) + bluish_pixel = (0, 0, 235, 255) + greyish_pixel = (115, 125, 135, 145) + + surf = pygame.Surface((1, 4), pygame.SRCALPHA, 32) + surf.set_at((0, 0), reddish_pixel) + surf.set_at((0, 1), greenish_pixel) + surf.set_at((0, 2), bluish_pixel) + surf.set_at((0, 3), greyish_pixel) + + f_path = tempfile.mktemp(suffix=".png") + pygame.image.save(surf, f_path) + + try: + # Read the PNG file and verify that pygame saved it correctly + reader = png.Reader(filename=f_path) + width, height, pixels, metadata = reader.asRGBA8() + + # pixels is a generator + self.assertEqual(tuple(next(pixels)), reddish_pixel) + self.assertEqual(tuple(next(pixels)), greenish_pixel) + self.assertEqual(tuple(next(pixels)), bluish_pixel) + self.assertEqual(tuple(next(pixels)), greyish_pixel) + + finally: + # Ensures proper clean up. + if not reader.file.closed: + reader.file.close() + del reader + os.remove(f_path) + + def testSavePNG24(self): + """see if we can save a png with color values in the proper channels.""" + # Create a PNG file with known colors + reddish_pixel = (215, 0, 0) + greenish_pixel = (0, 225, 0) + bluish_pixel = (0, 0, 235) + greyish_pixel = (115, 125, 135) + + surf = pygame.Surface((1, 4), 0, 24) + surf.set_at((0, 0), reddish_pixel) + surf.set_at((0, 1), greenish_pixel) + surf.set_at((0, 2), bluish_pixel) + surf.set_at((0, 3), greyish_pixel) + + f_path = tempfile.mktemp(suffix=".png") + pygame.image.save(surf, f_path) + + try: + # Read the PNG file and verify that pygame saved it correctly + reader = png.Reader(filename=f_path) + width, height, pixels, metadata = reader.asRGB8() + + # pixels is a generator + self.assertEqual(tuple(next(pixels)), reddish_pixel) + self.assertEqual(tuple(next(pixels)), greenish_pixel) + self.assertEqual(tuple(next(pixels)), bluish_pixel) + self.assertEqual(tuple(next(pixels)), greyish_pixel) + + finally: + # Ensures proper clean up. + if not reader.file.closed: + reader.file.close() + del reader + os.remove(f_path) + + def test_save(self): + + s = pygame.Surface((10, 10)) + s.fill((23, 23, 23)) + magic_hex = {} + magic_hex["jpg"] = [0xFF, 0xD8, 0xFF, 0xE0] + magic_hex["png"] = [0x89, 0x50, 0x4E, 0x47] + # magic_hex['tga'] = [0x0, 0x0, 0xa] + magic_hex["bmp"] = [0x42, 0x4D] + + formats = ["jpg", "png", "bmp"] + # uppercase too... JPG + formats = formats + [x.upper() for x in formats] + + for fmt in formats: + try: + temp_filename = "%s.%s" % ("tmpimg", fmt) + pygame.image.save(s, temp_filename) + + # Using 'with' ensures the file is closed even if test fails. + with open(temp_filename, "rb") as handle: + # Test the magic numbers at the start of the file to ensure + # they are saved as the correct file type. + self.assertEqual( + (1, fmt), (test_magic(handle, magic_hex[fmt.lower()]), fmt) + ) + + # load the file to make sure it was saved correctly. + # Note load can load a jpg saved with a .png file name. + s2 = pygame.image.load(temp_filename) + # compare contents, might only work reliably for png... + # but because it's all one color it seems to work with jpg. + self.assertEqual(s2.get_at((0, 0)), s.get_at((0, 0))) + finally: + # clean up the temp file, comment out to leave tmp file after run. + os.remove(temp_filename) + + def test_save_to_fileobject(self): + s = pygame.Surface((1, 1)) + s.fill((23, 23, 23)) + bytes_stream = io.BytesIO() + + pygame.image.save(s, bytes_stream) + bytes_stream.seek(0) + s2 = pygame.image.load(bytes_stream, "tga") + self.assertEqual(s.get_at((0, 0)), s2.get_at((0, 0))) + + def test_save_tga(self): + s = pygame.Surface((1, 1)) + s.fill((23, 23, 23)) + with tempfile.NamedTemporaryFile(suffix=".tga", delete=False) as f: + temp_filename = f.name + + try: + pygame.image.save(s, temp_filename) + s2 = pygame.image.load(temp_filename) + self.assertEqual(s2.get_at((0, 0)), s.get_at((0, 0))) + finally: + # clean up the temp file, even if test fails + os.remove(temp_filename) + + def test_save_pathlib(self): + surf = pygame.Surface((1, 1)) + surf.fill((23, 23, 23)) + with tempfile.NamedTemporaryFile(suffix=".tga", delete=False) as f: + temp_filename = f.name + + path = pathlib.Path(temp_filename) + try: + pygame.image.save(surf, path) + s2 = pygame.image.load(path) + self.assertEqual(s2.get_at((0, 0)), surf.get_at((0, 0))) + finally: + os.remove(temp_filename) + + def test_save__to_fileobject_w_namehint_argument(self): + s = pygame.Surface((10, 10)) + s.fill((23, 23, 23)) + magic_hex = {} + magic_hex["jpg"] = [0xFF, 0xD8, 0xFF, 0xE0] + magic_hex["png"] = [0x89, 0x50, 0x4E, 0x47] + magic_hex["bmp"] = [0x42, 0x4D] + + formats = ["tga", "jpg", "bmp", "png"] + # uppercase too... JPG + formats = formats + [x.upper() for x in formats] + + SDL_Im_version = pygame.image.get_sdl_image_version() + # We assume here that minor version and patch level of SDL_Image + # never goes above 99 + isAtLeastSDL_image_2_0_2 = (SDL_Im_version is not None) and ( + SDL_Im_version[0] * 10000 + SDL_Im_version[1] * 100 + SDL_Im_version[2] + ) >= 20002 + for fmt in formats: + tmp_file, tmp_filename = tempfile.mkstemp(suffix=".%s" % fmt) + if not isAtLeastSDL_image_2_0_2 and fmt.lower() == "jpg": + with os.fdopen(tmp_file, "wb") as handle: + with self.assertRaises(pygame.error): + pygame.image.save(s, handle, tmp_filename) + else: + with os.fdopen(tmp_file, "r+b") as handle: + pygame.image.save(s, handle, tmp_filename) + + if fmt.lower() in magic_hex: + # Test the magic numbers at the start of the file to + # ensure they are saved as the correct file type. + handle.seek(0) + self.assertEqual( + (1, fmt), (test_magic(handle, magic_hex[fmt.lower()]), fmt) + ) + # load the file to make sure it was saved correctly. + handle.flush() + handle.seek(0) + s2 = pygame.image.load(handle, tmp_filename) + self.assertEqual(s2.get_at((0, 0)), s.get_at((0, 0))) + os.remove(tmp_filename) + + def test_save_colorkey(self): + """make sure the color key is not changed when saving.""" + s = pygame.Surface((10, 10), pygame.SRCALPHA, 32) + s.fill((23, 23, 23)) + s.set_colorkey((0, 0, 0)) + colorkey1 = s.get_colorkey() + p1 = s.get_at((0, 0)) + + temp_filename = "tmpimg.png" + try: + pygame.image.save(s, temp_filename) + s2 = pygame.image.load(temp_filename) + finally: + os.remove(temp_filename) + + colorkey2 = s.get_colorkey() + # check that the pixel and the colorkey is correct. + self.assertEqual(colorkey1, colorkey2) + self.assertEqual(p1, s2.get_at((0, 0))) + + def test_load_unicode_path(self): + import shutil + + orig = example_path("data/asprite.bmp") + temp = os.path.join(example_path("data"), u"你好.bmp") + shutil.copy(orig, temp) + try: + im = pygame.image.load(temp) + finally: + os.remove(temp) + + def _unicode_save(self, temp_file): + im = pygame.Surface((10, 10), 0, 32) + try: + with open(temp_file, "w") as f: + pass + os.remove(temp_file) + except IOError: + raise unittest.SkipTest("the path cannot be opened") + + self.assertFalse(os.path.exists(temp_file)) + + try: + pygame.image.save(im, temp_file) + + self.assertGreater(os.path.getsize(temp_file), 10) + finally: + try: + os.remove(temp_file) + except EnvironmentError: + pass + + def test_save_unicode_path(self): + """save unicode object with non-ASCII chars""" + self._unicode_save(u"你好.bmp") + + def assertPremultipliedAreEqual(self, string1, string2, source_string): + self.assertEqual(len(string1), len(string2)) + block_size = 20 + if string1 != string2: + for block_start in range(0, len(string1), block_size): + block_end = min(block_start + block_size, len(string1)) + block1 = string1[block_start:block_end] + block2 = string2[block_start:block_end] + if block1 != block2: + source_block = source_string[block_start:block_end] + msg = ( + "string difference in %d to %d of %d:\n%s\n%s\nsource:\n%s" + % ( + block_start, + block_end, + len(string1), + binascii.hexlify(block1), + binascii.hexlify(block2), + binascii.hexlify(source_block), + ) + ) + self.fail(msg) + + def test_to_string__premultiplied(self): + """test to make sure we can export a surface to a premultiplied alpha string""" + + def convertRGBAtoPremultiplied(surface_to_modify): + for x in range(surface_to_modify.get_width()): + for y in range(surface_to_modify.get_height()): + color = surface_to_modify.get_at((x, y)) + premult_color = ( + color[0] * color[3] / 255, + color[1] * color[3] / 255, + color[2] * color[3] / 255, + color[3], + ) + surface_to_modify.set_at((x, y), premult_color) + + test_surface = pygame.Surface((256, 256), pygame.SRCALPHA, 32) + for x in range(test_surface.get_width()): + for y in range(test_surface.get_height()): + i = x + y * test_surface.get_width() + test_surface.set_at( + (x, y), ((i * 7) % 256, (i * 13) % 256, (i * 27) % 256, y) + ) + premultiplied_copy = test_surface.copy() + convertRGBAtoPremultiplied(premultiplied_copy) + self.assertPremultipliedAreEqual( + pygame.image.tostring(test_surface, "RGBA_PREMULT"), + pygame.image.tostring(premultiplied_copy, "RGBA"), + pygame.image.tostring(test_surface, "RGBA"), + ) + self.assertPremultipliedAreEqual( + pygame.image.tostring(test_surface, "ARGB_PREMULT"), + pygame.image.tostring(premultiplied_copy, "ARGB"), + pygame.image.tostring(test_surface, "ARGB"), + ) + + no_alpha_surface = pygame.Surface((256, 256), 0, 24) + self.assertRaises( + ValueError, pygame.image.tostring, no_alpha_surface, "RGBA_PREMULT" + ) + + # Custom assert method to check for identical surfaces. + def _assertSurfaceEqual(self, surf_a, surf_b, msg=None): + a_width, a_height = surf_a.get_width(), surf_a.get_height() + + # Check a few things to see if the surfaces are equal. + self.assertEqual(a_width, surf_b.get_width(), msg) + self.assertEqual(a_height, surf_b.get_height(), msg) + self.assertEqual(surf_a.get_size(), surf_b.get_size(), msg) + self.assertEqual(surf_a.get_rect(), surf_b.get_rect(), msg) + self.assertEqual(surf_a.get_colorkey(), surf_b.get_colorkey(), msg) + self.assertEqual(surf_a.get_alpha(), surf_b.get_alpha(), msg) + self.assertEqual(surf_a.get_flags(), surf_b.get_flags(), msg) + self.assertEqual(surf_a.get_bitsize(), surf_b.get_bitsize(), msg) + self.assertEqual(surf_a.get_bytesize(), surf_b.get_bytesize(), msg) + # Anything else? + + # Making the method lookups local for a possible speed up. + surf_a_get_at = surf_a.get_at + surf_b_get_at = surf_b.get_at + for y in range(a_height): + for x in range(a_width): + self.assertEqual( + surf_a_get_at((x, y)), + surf_b_get_at((x, y)), + "%s (pixel: %d, %d)" % (msg, x, y), + ) + + def test_fromstring__and_tostring(self): + """Ensure methods tostring() and fromstring() are symmetric.""" + + #################################################################### + def RotateRGBAtoARGB(str_buf): + byte_buf = array.array("B", str_buf) + num_quads = len(byte_buf) // 4 + for i in range(num_quads): + alpha = byte_buf[i * 4 + 3] + byte_buf[i * 4 + 3] = byte_buf[i * 4 + 2] + byte_buf[i * 4 + 2] = byte_buf[i * 4 + 1] + byte_buf[i * 4 + 1] = byte_buf[i * 4 + 0] + byte_buf[i * 4 + 0] = alpha + return tostring(byte_buf) + + #################################################################### + def RotateARGBtoRGBA(str_buf): + byte_buf = array.array("B", str_buf) + num_quads = len(byte_buf) // 4 + for i in range(num_quads): + alpha = byte_buf[i * 4 + 0] + byte_buf[i * 4 + 0] = byte_buf[i * 4 + 1] + byte_buf[i * 4 + 1] = byte_buf[i * 4 + 2] + byte_buf[i * 4 + 2] = byte_buf[i * 4 + 3] + byte_buf[i * 4 + 3] = alpha + return tostring(byte_buf) + + #################################################################### + test_surface = pygame.Surface((64, 256), flags=pygame.SRCALPHA, depth=32) + for i in range(256): + for j in range(16): + intensity = j * 16 + 15 + test_surface.set_at((j + 0, i), (intensity, i, i, i)) + test_surface.set_at((j + 16, i), (i, intensity, i, i)) + test_surface.set_at((j + 32, i), (i, i, intensity, i)) + test_surface.set_at((j + 32, i), (i, i, i, intensity)) + + self._assertSurfaceEqual( + test_surface, test_surface, "failing with identical surfaces" + ) + + rgba_buf = pygame.image.tostring(test_surface, "RGBA") + rgba_buf = RotateARGBtoRGBA(RotateRGBAtoARGB(rgba_buf)) + test_rotate_functions = pygame.image.fromstring( + rgba_buf, test_surface.get_size(), "RGBA" + ) + + self._assertSurfaceEqual( + test_surface, test_rotate_functions, "rotate functions are not symmetric" + ) + + rgba_buf = pygame.image.tostring(test_surface, "RGBA") + argb_buf = RotateRGBAtoARGB(rgba_buf) + test_from_argb_string = pygame.image.fromstring( + argb_buf, test_surface.get_size(), "ARGB" + ) + + self._assertSurfaceEqual( + test_surface, test_from_argb_string, '"RGBA" rotated to "ARGB" failed' + ) + + argb_buf = pygame.image.tostring(test_surface, "ARGB") + rgba_buf = RotateARGBtoRGBA(argb_buf) + test_to_argb_string = pygame.image.fromstring( + rgba_buf, test_surface.get_size(), "RGBA" + ) + + self._assertSurfaceEqual( + test_surface, test_to_argb_string, '"ARGB" rotated to "RGBA" failed' + ) + + for fmt in ("ARGB", "RGBA"): + fmt_buf = pygame.image.tostring(test_surface, fmt) + test_to_from_fmt_string = pygame.image.fromstring( + fmt_buf, test_surface.get_size(), fmt + ) + + self._assertSurfaceEqual( + test_surface, + test_to_from_fmt_string, + "tostring/fromstring functions are not " + 'symmetric with "{}" format'.format(fmt), + ) + + def test_tostring_depth_24(self): + test_surface = pygame.Surface((64, 256), depth=24) + for i in range(256): + for j in range(16): + intensity = j * 16 + 15 + test_surface.set_at((j + 0, i), (intensity, i, i, i)) + test_surface.set_at((j + 16, i), (i, intensity, i, i)) + test_surface.set_at((j + 32, i), (i, i, intensity, i)) + test_surface.set_at((j + 32, i), (i, i, i, intensity)) + + fmt = "RGB" + fmt_buf = pygame.image.tostring(test_surface, fmt) + test_to_from_fmt_string = pygame.image.fromstring( + fmt_buf, test_surface.get_size(), fmt + ) + + self._assertSurfaceEqual( + test_surface, + test_to_from_fmt_string, + "tostring/fromstring functions are not " + 'symmetric with "{}" format'.format(fmt), + ) + + def test_frombuffer_8bit(self): + """test reading pixel data from a bytes buffer""" + pygame.display.init() + eight_bit_palette_buffer = bytearray( + [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3] + ) + + eight_bit_surf = pygame.image.frombuffer(eight_bit_palette_buffer, (4, 4), "P") + eight_bit_surf.set_palette( + [(255, 10, 20), (255, 255, 255), (0, 0, 0), (50, 200, 20)] + ) + self.assertEqual(eight_bit_surf.get_at((0, 0)), pygame.Color(255, 10, 20)) + self.assertEqual(eight_bit_surf.get_at((1, 1)), pygame.Color(255, 255, 255)) + self.assertEqual(eight_bit_surf.get_at((2, 2)), pygame.Color(0, 0, 0)) + self.assertEqual(eight_bit_surf.get_at((3, 3)), pygame.Color(50, 200, 20)) + + def test_frombuffer_RGB(self): + rgb_buffer = bytearray( + [ + 255, + 10, + 20, + 255, + 10, + 20, + 255, + 10, + 20, + 255, + 10, + 20, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 50, + 200, + 20, + 50, + 200, + 20, + 50, + 200, + 20, + 50, + 200, + 20, + ] + ) + + rgb_surf = pygame.image.frombuffer(rgb_buffer, (4, 4), "RGB") + self.assertEqual(rgb_surf.get_at((0, 0)), pygame.Color(255, 10, 20)) + self.assertEqual(rgb_surf.get_at((1, 1)), pygame.Color(255, 255, 255)) + self.assertEqual(rgb_surf.get_at((2, 2)), pygame.Color(0, 0, 0)) + self.assertEqual(rgb_surf.get_at((3, 3)), pygame.Color(50, 200, 20)) + + def test_frombuffer_BGR(self): + bgr_buffer = bytearray( + [ + 20, + 10, + 255, + 20, + 10, + 255, + 20, + 10, + 255, + 20, + 10, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 20, + 200, + 50, + 20, + 200, + 50, + 20, + 200, + 50, + 20, + 200, + 50, + ] + ) + + bgr_surf = pygame.image.frombuffer(bgr_buffer, (4, 4), "BGR") + self.assertEqual(bgr_surf.get_at((0, 0)), pygame.Color(255, 10, 20)) + self.assertEqual(bgr_surf.get_at((1, 1)), pygame.Color(255, 255, 255)) + self.assertEqual(bgr_surf.get_at((2, 2)), pygame.Color(0, 0, 0)) + self.assertEqual(bgr_surf.get_at((3, 3)), pygame.Color(50, 200, 20)) + + def test_frombuffer_RGBX(self): + rgbx_buffer = bytearray( + [ + 255, + 10, + 20, + 255, + 255, + 10, + 20, + 255, + 255, + 10, + 20, + 255, + 255, + 10, + 20, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 0, + 0, + 0, + 255, + 0, + 0, + 0, + 255, + 0, + 0, + 0, + 255, + 0, + 0, + 0, + 255, + 50, + 200, + 20, + 255, + 50, + 200, + 20, + 255, + 50, + 200, + 20, + 255, + 50, + 200, + 20, + 255, + ] + ) + + rgbx_surf = pygame.image.frombuffer(rgbx_buffer, (4, 4), "RGBX") + self.assertEqual(rgbx_surf.get_at((0, 0)), pygame.Color(255, 10, 20, 255)) + self.assertEqual(rgbx_surf.get_at((1, 1)), pygame.Color(255, 255, 255, 255)) + self.assertEqual(rgbx_surf.get_at((2, 2)), pygame.Color(0, 0, 0, 255)) + self.assertEqual(rgbx_surf.get_at((3, 3)), pygame.Color(50, 200, 20, 255)) + + def test_frombuffer_RGBA(self): + rgba_buffer = bytearray( + [ + 255, + 10, + 20, + 200, + 255, + 10, + 20, + 200, + 255, + 10, + 20, + 200, + 255, + 10, + 20, + 200, + 255, + 255, + 255, + 127, + 255, + 255, + 255, + 127, + 255, + 255, + 255, + 127, + 255, + 255, + 255, + 127, + 0, + 0, + 0, + 79, + 0, + 0, + 0, + 79, + 0, + 0, + 0, + 79, + 0, + 0, + 0, + 79, + 50, + 200, + 20, + 255, + 50, + 200, + 20, + 255, + 50, + 200, + 20, + 255, + 50, + 200, + 20, + 255, + ] + ) + + rgba_surf = pygame.image.frombuffer(rgba_buffer, (4, 4), "RGBA") + self.assertEqual(rgba_surf.get_at((0, 0)), pygame.Color(255, 10, 20, 200)) + self.assertEqual(rgba_surf.get_at((1, 1)), pygame.Color(255, 255, 255, 127)) + self.assertEqual(rgba_surf.get_at((2, 2)), pygame.Color(0, 0, 0, 79)) + self.assertEqual(rgba_surf.get_at((3, 3)), pygame.Color(50, 200, 20, 255)) + + def test_frombuffer_ARGB(self): + argb_buffer = bytearray( + [ + 200, + 255, + 10, + 20, + 200, + 255, + 10, + 20, + 200, + 255, + 10, + 20, + 200, + 255, + 10, + 20, + 127, + 255, + 255, + 255, + 127, + 255, + 255, + 255, + 127, + 255, + 255, + 255, + 127, + 255, + 255, + 255, + 79, + 0, + 0, + 0, + 79, + 0, + 0, + 0, + 79, + 0, + 0, + 0, + 79, + 0, + 0, + 0, + 255, + 50, + 200, + 20, + 255, + 50, + 200, + 20, + 255, + 50, + 200, + 20, + 255, + 50, + 200, + 20, + ] + ) + + argb_surf = pygame.image.frombuffer(argb_buffer, (4, 4), "ARGB") + self.assertEqual(argb_surf.get_at((0, 0)), pygame.Color(255, 10, 20, 200)) + self.assertEqual(argb_surf.get_at((1, 1)), pygame.Color(255, 255, 255, 127)) + self.assertEqual(argb_surf.get_at((2, 2)), pygame.Color(0, 0, 0, 79)) + self.assertEqual(argb_surf.get_at((3, 3)), pygame.Color(50, 200, 20, 255)) + + def test_get_extended(self): + # Create a png file and try to load it. If it cannot, get_extended() should return False + raw_image = [] + raw_image.append((200, 200, 200, 255, 100, 100, 100, 255)) + + f_descriptor, f_path = tempfile.mkstemp(suffix=".png") + + with os.fdopen(f_descriptor, "wb") as file: + w = png.Writer(2, 1, alpha=True) + w.write(file, raw_image) + + try: + surf = pygame.image.load(f_path) + loaded = True + except pygame.error: + loaded = False + + self.assertEqual(pygame.image.get_extended(), loaded) + os.remove(f_path) + + def test_get_sdl_image_version(self): + # If get_extended() returns False then get_sdl_image_version() should + # return None + if not pygame.image.get_extended(): + self.assertIsNone(pygame.image.get_sdl_image_version()) + else: + expected_length = 3 + expected_type = tuple + expected_item_type = int + + version = pygame.image.get_sdl_image_version() + + self.assertIsInstance(version, expected_type) + self.assertEqual(len(version), expected_length) + + for item in version: + self.assertIsInstance(item, expected_item_type) + + def test_load_basic(self): + """to see if we can load bmp from files and/or file-like objects in memory""" + + # pygame.image.load(filename): return Surface + + # test loading from a file + s = pygame.image.load_basic(example_path("data/asprite.bmp")) + self.assertEqual(s.get_at((0, 0)), (255, 255, 255, 255)) + + # test loading from io.BufferedReader + f = pygame.pkgdata.getResource("pygame_icon.bmp") + self.assertEqual(f.mode, "rb") + + surf = pygame.image.load_basic(f) + + self.assertEqual(surf.get_at((0, 0)), (5, 4, 5, 255)) + self.assertEqual(surf.get_height(), 32) + self.assertEqual(surf.get_width(), 32) + + f.close() + + def test_load_extended(self): + """can load different format images. + + We test loading the following file types: + bmp, png, jpg, gif (non-animated), pcx, tga (uncompressed), tif, xpm, ppm, pgm + Following file types are tested when using SDL 2 + svg, pnm, webp + All the loaded images are smaller than 32 x 32 pixels. + """ + + filename_expected_color = [ + ("asprite.bmp", (255, 255, 255, 255)), + ("laplacian.png", (10, 10, 70, 255)), + ("red.jpg", (254, 0, 0, 255)), + ("blue.gif", (0, 0, 255, 255)), + ("green.pcx", (0, 255, 0, 255)), + ("yellow.tga", (255, 255, 0, 255)), + ("turquoise.tif", (0, 255, 255, 255)), + ("purple.xpm", (255, 0, 255, 255)), + ("black.ppm", (0, 0, 0, 255)), + ("grey.pgm", (120, 120, 120, 255)), + ("teal.svg", (0, 128, 128, 255)), + ("crimson.pnm", (220, 20, 60, 255)), + ("scarlet.webp", (252, 14, 53, 255)), + ] + + for filename, expected_color in filename_expected_color: + with self.subTest( + "Test loading a " + filename.split(".")[-1], + filename="examples/data/" + filename, + expected_color=expected_color, + ): + surf = pygame.image.load_extended(example_path("data/" + filename)) + self.assertEqual(surf.get_at((0, 0)), expected_color) + + def test_load_pathlib(self): + """works loading using a Path argument.""" + path = pathlib.Path(example_path("data/asprite.bmp")) + surf = pygame.image.load_extended(path) + self.assertEqual(surf.get_at((0, 0)), (255, 255, 255, 255)) + + def test_save_extended(self): + surf = pygame.Surface((5, 5)) + surf.fill((23, 23, 23)) + + passing_formats = ["jpg", "png"] + passing_formats += [fmt.upper() for fmt in passing_formats] + + magic_hex = {} + magic_hex["jpg"] = [0xFF, 0xD8, 0xFF, 0xE0] + magic_hex["png"] = [0x89, 0x50, 0x4E, 0x47] + + failing_formats = ["bmp", "tga"] + failing_formats += [fmt.upper() for fmt in failing_formats] + + # check that .jpg and .png save + for fmt in passing_formats: + temp_file_name = "temp_file.%s" % fmt + # save image as .jpg and .png + pygame.image.save_extended(surf, temp_file_name) + with open(temp_file_name, "rb") as file: + # Test the magic numbers at the start of the file to ensure + # they are saved as the correct file type. + self.assertEqual(1, (test_magic(file, magic_hex[fmt.lower()]))) + # load the file to make sure it was saved correctly + loaded_file = pygame.image.load(temp_file_name) + self.assertEqual(loaded_file.get_at((0, 0)), surf.get_at((0, 0))) + # clean up the temp file + os.remove(temp_file_name) + # check that .bmp and .tga do not save + for fmt in failing_formats: + self.assertRaises( + pygame.error, pygame.image.save_extended, surf, "temp_file.%s" % fmt + ) + + def threads_load(self, images): + import pygame.threads + + for i in range(10): + surfs = pygame.threads.tmap(pygame.image.load, images) + for s in surfs: + self.assertIsInstance(s, pygame.Surface) + + def test_load_png_threads(self): + self.threads_load(glob.glob(example_path("data/*.png"))) + + def test_load_jpg_threads(self): + self.threads_load(glob.glob(example_path("data/*.jpg"))) + + def test_load_bmp_threads(self): + self.threads_load(glob.glob(example_path("data/*.bmp"))) + + def test_load_gif_threads(self): + self.threads_load(glob.glob(example_path("data/*.gif"))) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/imageext_tags.py b/venv/Lib/site-packages/pygame/tests/imageext_tags.py new file mode 100644 index 0000000..25cff74 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/imageext_tags.py @@ -0,0 +1,7 @@ +__tags__ = [] + +import pygame +import sys + +if "pygame.imageext" not in sys.modules: + __tags__.extend(("ignore", "subprocess_ignore")) diff --git a/venv/Lib/site-packages/pygame/tests/imageext_test.py b/venv/Lib/site-packages/pygame/tests/imageext_test.py new file mode 100644 index 0000000..19faf83 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/imageext_test.py @@ -0,0 +1,94 @@ +# -*- coding: utf8 -*- +import os +import os.path +import sys +import unittest + +from pygame.tests.test_utils import example_path +import pygame, pygame.image, pygame.pkgdata + + +imageext = sys.modules["pygame.imageext"] + + +class ImageextModuleTest(unittest.TestCase): + # Most of the testing is done indirectly through image_test.py + # This just confirms file path encoding and error handling. + def test_save_non_string_file(self): + im = pygame.Surface((10, 10), 0, 32) + self.assertRaises(TypeError, imageext.save_extended, im, []) + + def test_load_non_string_file(self): + self.assertRaises(TypeError, imageext.load_extended, []) + + @unittest.skip("SDL silently removes invalid characters") + def test_save_bad_filename(self): + im = pygame.Surface((10, 10), 0, 32) + u = u"a\x00b\x00c.png" + self.assertRaises(pygame.error, imageext.save_extended, im, u) + + @unittest.skip("SDL silently removes invalid characters") + def test_load_bad_filename(self): + u = u"a\x00b\x00c.png" + self.assertRaises(pygame.error, imageext.load_extended, u) + + def test_save_unknown_extension(self): + im = pygame.Surface((10, 10), 0, 32) + s = "foo.bar" + self.assertRaises(pygame.error, imageext.save_extended, im, s) + + def test_load_unknown_extension(self): + s = "foo.bar" + self.assertRaises(FileNotFoundError, imageext.load_extended, s) + + def test_load_unknown_file(self): + s = "nonexistent.png" + self.assertRaises(FileNotFoundError, imageext.load_extended, s) + + def test_load_unicode_path_0(self): + u = example_path("data/alien1.png") + im = imageext.load_extended(u) + + def test_load_unicode_path_1(self): + """non-ASCII unicode""" + import shutil + + orig = example_path("data/alien1.png") + temp = os.path.join(example_path("data"), u"你好.png") + shutil.copy(orig, temp) + try: + im = imageext.load_extended(temp) + finally: + os.remove(temp) + + def _unicode_save(self, temp_file): + im = pygame.Surface((10, 10), 0, 32) + try: + with open(temp_file, "w") as f: + pass + os.remove(temp_file) + except IOError: + raise unittest.SkipTest("the path cannot be opened") + + self.assertFalse(os.path.exists(temp_file)) + + try: + imageext.save_extended(im, temp_file) + + self.assertGreater(os.path.getsize(temp_file), 10) + finally: + try: + os.remove(temp_file) + except EnvironmentError: + pass + + def test_save_unicode_path_0(self): + """unicode object with ASCII chars""" + self._unicode_save(u"temp_file.png") + + def test_save_unicode_path_1(self): + self._unicode_save(u"你好.png") + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/joystick_test.py b/venv/Lib/site-packages/pygame/tests/joystick_test.py new file mode 100644 index 0000000..e8cea2d --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/joystick_test.py @@ -0,0 +1,172 @@ +import unittest +from pygame.tests.test_utils import question, prompt + +import pygame +import pygame._sdl2.controller + + +class JoystickTypeTest(unittest.TestCase): + def todo_test_Joystick(self): + + # __doc__ (as of 2008-08-02) for pygame.joystick.Joystick: + + # pygame.joystick.Joystick(id): return Joystick + # create a new Joystick object + # + # Create a new joystick to access a physical device. The id argument + # must be a value from 0 to pygame.joystick.get_count()-1. + # + # To access most of the Joystick methods, you'll need to init() the + # Joystick. This is separate from making sure the joystick module is + # initialized. When multiple Joysticks objects are created for the + # same physical joystick device (i.e., they have the same ID number), + # the state and values for those Joystick objects will be shared. + # + # The Joystick object allows you to get information about the types of + # controls on a joystick device. Once the device is initialized the + # Pygame event queue will start receiving events about its input. + # + # You can call the Joystick.get_name() and Joystick.get_id() functions + # without initializing the Joystick object. + # + + self.fail() + + +class JoystickModuleTest(unittest.TestCase): + def test_get_init(self): + # Check that get_init() matches what is actually happening + def error_check_get_init(): + try: + pygame.joystick.get_count() + except pygame.error: + return False + return True + + # Start uninitialised + self.assertEqual(pygame.joystick.get_init(), False) + + pygame.joystick.init() + self.assertEqual(pygame.joystick.get_init(), error_check_get_init()) # True + pygame.joystick.quit() + self.assertEqual(pygame.joystick.get_init(), error_check_get_init()) # False + + pygame.joystick.init() + pygame.joystick.init() + self.assertEqual(pygame.joystick.get_init(), error_check_get_init()) # True + pygame.joystick.quit() + self.assertEqual(pygame.joystick.get_init(), error_check_get_init()) # False + + pygame.joystick.quit() + self.assertEqual(pygame.joystick.get_init(), error_check_get_init()) # False + + for i in range(100): + pygame.joystick.init() + self.assertEqual(pygame.joystick.get_init(), error_check_get_init()) # True + pygame.joystick.quit() + self.assertEqual(pygame.joystick.get_init(), error_check_get_init()) # False + + for i in range(100): + pygame.joystick.quit() + self.assertEqual(pygame.joystick.get_init(), error_check_get_init()) # False + + def test_init(self): + """ + This unit test is for joystick.init() + It was written to help reduce maintenance costs + and to help test against changes to the code or + different platforms. + """ + pygame.quit() + # test that pygame.init automatically calls joystick.init + pygame.init() + self.assertEqual(pygame.joystick.get_init(), True) + + # Controller module interferes with the joystick module. + pygame._sdl2.controller.quit() + + # test that get_count doesn't work w/o joystick init + # this is done before and after an init to test + # that init activates the joystick functions + pygame.joystick.quit() + with self.assertRaises(pygame.error): + pygame.joystick.get_count() + + # test explicit call(s) to joystick.init. + # Also test that get_count works once init is called + iterations = 20 + for i in range(iterations): + pygame.joystick.init() + self.assertEqual(pygame.joystick.get_init(), True) + self.assertIsNotNone(pygame.joystick.get_count()) + + def test_quit(self): + """Test if joystick.quit works.""" + + pygame.joystick.init() + + self.assertIsNotNone(pygame.joystick.get_count()) # Is not None before quit + + pygame.joystick.quit() + + with self.assertRaises(pygame.error): # Raises error if quit worked + pygame.joystick.get_count() + + def test_get_count(self): + # Test that get_count correctly returns a non-negative number of joysticks + pygame.joystick.init() + + try: + count = pygame.joystick.get_count() + self.assertGreaterEqual( + count, 0, ("joystick.get_count() must " "return a value >= 0") + ) + finally: + pygame.joystick.quit() + + +class JoystickInteractiveTest(unittest.TestCase): + + __tags__ = ["interactive"] + + def test_get_count_interactive(self): + # Test get_count correctly identifies number of connected joysticks + prompt( + ( + "Please connect any joysticks/controllers now before starting the " + "joystick.get_count() test." + ) + ) + + pygame.joystick.init() + # pygame.joystick.get_count(): return count + # number of joysticks on the system, 0 means no joysticks connected + count = pygame.joystick.get_count() + + response = question( + ( + "NOTE: Having Steam open may add an extra virtual controller for " + "each joystick/controller physically plugged in.\n" + "joystick.get_count() thinks there is [{}] joystick(s)/controller(s)" + "connected to this system. Is this correct?".format(count) + ) + ) + + self.assertTrue(response) + + # When you create Joystick objects using Joystick(id), you pass an + # integer that must be lower than this count. + # Test Joystick(id) for each connected joystick + if count != 0: + for x in range(count): + pygame.joystick.Joystick(x) + with self.assertRaises(pygame.error): + pygame.joystick.Joystick(count) + + pygame.joystick.quit() + + +################################################################################ + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/key_test.py b/venv/Lib/site-packages/pygame/tests/key_test.py new file mode 100644 index 0000000..a15199f --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/key_test.py @@ -0,0 +1,110 @@ +import os +import sys +import time +import unittest +import pygame +import pygame.key + + +class KeyModuleTest(unittest.TestCase): + @classmethod + def setUpClass(cls): + pygame.init() + + @classmethod + def tearDownClass(cls): + pygame.quit() + + def setUp(cls): + # This makes sure pygame is always initialized before each test (in + # case a test calls pygame.quit()). + if not pygame.get_init(): + pygame.init() + if not pygame.display.get_init(): + pygame.display.init() + + def test_import(self): + """does it import?""" + import pygame.key + + # fixme: test_get_focused failing systematically in some linux + # fixme: test_get_focused failing on SDL 2.0.18 on Windows + @unittest.skip("flaky test, and broken on 2.0.18 windows") + def test_get_focused(self): + # This test fails in SDL2 in some linux + # This test was skipped in SDL1. + focused = pygame.key.get_focused() + self.assertFalse(focused) # No window to focus + self.assertIsInstance(focused, int) + # Dummy video driver never gets keyboard focus. + if os.environ.get("SDL_VIDEODRIVER") != "dummy": + # Positive test, fullscreen with events grabbed + display_sizes = pygame.display.list_modes() + if display_sizes == -1: + display_sizes = [(500, 500)] + pygame.display.set_mode(size=display_sizes[-1], flags=pygame.FULLSCREEN) + pygame.event.set_grab(True) + # Pump event queue to get window focus on macos + pygame.event.pump() + focused = pygame.key.get_focused() + self.assertIsInstance(focused, int) + self.assertTrue(focused) + # Now test negative, iconify takes away focus + pygame.event.clear() + # TODO: iconify test fails in windows + if os.name != "nt": + pygame.display.iconify() + # Apparent need to pump event queue in order to make sure iconify + # happens. See display_test.py's test_get_active_iconify + for _ in range(50): + time.sleep(0.01) + pygame.event.pump() + self.assertFalse(pygame.key.get_focused()) + # Test if focus is returned when iconify is gone + pygame.display.set_mode(size=display_sizes[-1], flags=pygame.FULLSCREEN) + for i in range(50): + time.sleep(0.01) + pygame.event.pump() + self.assertTrue(pygame.key.get_focused()) + # Test if a quit display raises an error: + pygame.display.quit() + with self.assertRaises(pygame.error) as cm: + pygame.key.get_focused() + + def test_get_pressed(self): + states = pygame.key.get_pressed() + self.assertEqual(states[pygame.K_RIGHT], 0) + + def test_name(self): + self.assertEqual(pygame.key.name(pygame.K_RETURN), "return") + self.assertEqual(pygame.key.name(pygame.K_0), "0") + self.assertEqual(pygame.key.name(pygame.K_SPACE), "space") + + def test_key_code(self): + self.assertEqual(pygame.key.key_code("return"), pygame.K_RETURN) + self.assertEqual(pygame.key.key_code("0"), pygame.K_0) + self.assertEqual(pygame.key.key_code("space"), pygame.K_SPACE) + + self.assertRaises(ValueError, pygame.key.key_code, "fizzbuzz") + + def test_set_and_get_mods(self): + pygame.key.set_mods(pygame.KMOD_CTRL) + self.assertEqual(pygame.key.get_mods(), pygame.KMOD_CTRL) + + pygame.key.set_mods(pygame.KMOD_ALT) + self.assertEqual(pygame.key.get_mods(), pygame.KMOD_ALT) + pygame.key.set_mods(pygame.KMOD_CTRL | pygame.KMOD_ALT) + self.assertEqual(pygame.key.get_mods(), pygame.KMOD_CTRL | pygame.KMOD_ALT) + + def test_set_and_get_repeat(self): + self.assertEqual(pygame.key.get_repeat(), (0, 0)) + + pygame.key.set_repeat(10, 15) + self.assertEqual(pygame.key.get_repeat(), (10, 15)) + + pygame.key.set_repeat() + self.assertEqual(pygame.key.get_repeat(), (0, 0)) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/mask_test.py b/venv/Lib/site-packages/pygame/tests/mask_test.py new file mode 100644 index 0000000..56c0917 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/mask_test.py @@ -0,0 +1,6440 @@ +from collections import OrderedDict +import copy +import platform +import random +import unittest +import sys + +import pygame +from pygame.locals import * +from pygame.math import Vector2 +from pygame.tests.test_utils import AssertRaisesRegexMixin + + +IS_PYPY = "PyPy" == platform.python_implementation() + + +def random_mask(size=(100, 100)): + """random_mask(size=(100,100)): return Mask + Create a mask of the given size, with roughly half the bits set at random.""" + m = pygame.Mask(size) + for i in range(size[0] * size[1] // 2): + x, y = random.randint(0, size[0] - 1), random.randint(0, size[1] - 1) + m.set_at((x, y)) + return m + + +def maskFromSurface(surface, threshold=127): + mask = pygame.Mask(surface.get_size()) + key = surface.get_colorkey() + if key: + for y in range(surface.get_height()): + for x in range(surface.get_width()): + if surface.get_at((x + 0.1, y + 0.1)) != key: + mask.set_at((x, y), 1) + else: + for y in range(surface.get_height()): + for x in range(surface.get_width()): + if surface.get_at((x, y))[3] > threshold: + mask.set_at((x, y), 1) + return mask + + +def create_bounding_rect(points): + """Creates a bounding rect from the given points.""" + xmin = xmax = points[0][0] + ymin = ymax = points[0][1] + + for x, y in points[1:]: + xmin = min(x, xmin) + xmax = max(x, xmax) + ymin = min(y, ymin) + ymax = max(y, ymax) + + return pygame.Rect((xmin, ymin), (xmax - xmin + 1, ymax - ymin + 1)) + + +def zero_size_pairs(width, height): + """Creates a generator which yields pairs of sizes. + + For each pair of sizes at least one of the sizes will have a 0 in it. + """ + sizes = ((width, height), (width, 0), (0, height), (0, 0)) + + return ((a, b) for a in sizes for b in sizes if 0 in a or 0 in b) + + +def corners(mask): + """Returns a tuple with the corner positions of the given mask. + + Clockwise from the top left corner. + """ + width, height = mask.get_size() + return ((0, 0), (width - 1, 0), (width - 1, height - 1), (0, height - 1)) + + +def off_corners(rect): + """Returns a tuple with the positions off of the corners of the given rect. + + Clockwise from the top left corner. + """ + return ( + (rect.left - 1, rect.top), + (rect.left - 1, rect.top - 1), + (rect.left, rect.top - 1), + (rect.right - 1, rect.top - 1), + (rect.right, rect.top - 1), + (rect.right, rect.top), + (rect.right, rect.bottom - 1), + (rect.right, rect.bottom), + (rect.right - 1, rect.bottom), + (rect.left, rect.bottom), + (rect.left - 1, rect.bottom), + (rect.left - 1, rect.bottom - 1), + ) + + +def assertSurfaceFilled(testcase, surface, expected_color, area_rect=None): + """Checks to see if the given surface is filled with the given color. + + If an area_rect is provided, only check that area of the surface. + """ + if area_rect is None: + x_range = range(surface.get_width()) + y_range = range(surface.get_height()) + else: + area_rect.normalize() + area_rect = area_rect.clip(surface.get_rect()) + x_range = range(area_rect.left, area_rect.right) + y_range = range(area_rect.top, area_rect.bottom) + + surface.lock() # Lock for possible speed up. + for pos in ((x, y) for y in y_range for x in x_range): + testcase.assertEqual(surface.get_at(pos), expected_color, pos) + surface.unlock() + + +def assertSurfaceFilledIgnoreArea(testcase, surface, expected_color, ignore_rect): + """Checks if the surface is filled with the given color. The + ignore_rect area is not checked. + """ + x_range = range(surface.get_width()) + y_range = range(surface.get_height()) + ignore_rect.normalize() + + surface.lock() # Lock for possible speed up. + for pos in ((x, y) for y in y_range for x in x_range): + if not ignore_rect.collidepoint(pos): + testcase.assertEqual(surface.get_at(pos), expected_color, pos) + surface.unlock() + + +def assertMaskEqual(testcase, m1, m2, msg=None): + """Checks to see if the 2 given masks are equal.""" + m1_count = m1.count() + + testcase.assertEqual(m1.get_size(), m2.get_size(), msg=msg) + testcase.assertEqual(m1_count, m2.count(), msg=msg) + testcase.assertEqual(m1_count, m1.overlap_area(m2, (0, 0)), msg=msg) + + # This can be used to help debug exact locations. + ##for i in range(m1.get_size()[0]): + ## for j in range(m1.get_size()[1]): + ## testcase.assertEqual(m1.get_at((i, j)), m2.get_at((i, j))) + + +# @unittest.skipIf(IS_PYPY, "pypy has lots of mask failures") # TODO +class MaskTypeTest(AssertRaisesRegexMixin, unittest.TestCase): + ORIGIN_OFFSETS = ( + (0, 0), + (0, 1), + (1, 1), + (1, 0), + (1, -1), + (0, -1), + (-1, -1), + (-1, 0), + (-1, 1), + ) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_mask(self): + """Ensure masks are created correctly without fill parameter.""" + expected_count = 0 + expected_size = (11, 23) + + mask1 = pygame.mask.Mask(expected_size) + mask2 = pygame.mask.Mask(size=expected_size) + + self.assertIsInstance(mask1, pygame.mask.Mask) + self.assertEqual(mask1.count(), expected_count) + self.assertEqual(mask1.get_size(), expected_size) + + self.assertIsInstance(mask2, pygame.mask.Mask) + self.assertEqual(mask2.count(), expected_count) + self.assertEqual(mask2.get_size(), expected_size) + + def test_mask__negative_size(self): + """Ensure the mask constructor handles negative sizes correctly.""" + for size in ((1, -1), (-1, 1), (-1, -1)): + with self.assertRaises(ValueError): + mask = pygame.Mask(size) + + def test_mask__fill_kwarg(self): + """Ensure masks are created correctly using the fill keyword.""" + width, height = 37, 47 + expected_size = (width, height) + fill_counts = {True: width * height, False: 0} + + for fill, expected_count in fill_counts.items(): + msg = "fill={}".format(fill) + + mask = pygame.mask.Mask(expected_size, fill=fill) + + self.assertIsInstance(mask, pygame.mask.Mask, msg) + self.assertEqual(mask.count(), expected_count, msg) + self.assertEqual(mask.get_size(), expected_size, msg) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_mask__fill_kwarg_bit_boundaries(self): + """Ensures masks are created correctly using the fill keyword + over a range of sizes. + + Tests masks of different sizes, including: + -masks 31 to 33 bits wide (32 bit boundaries) + -masks 63 to 65 bits wide (64 bit boundaries) + """ + for height in range(1, 4): + for width in range(1, 66): + expected_count = width * height + expected_size = (width, height) + msg = "size={}".format(expected_size) + + mask = pygame.mask.Mask(expected_size, fill=True) + + self.assertIsInstance(mask, pygame.mask.Mask, msg) + self.assertEqual(mask.count(), expected_count, msg) + self.assertEqual(mask.get_size(), expected_size, msg) + + def test_mask__fill_arg(self): + """Ensure masks are created correctly using a fill arg.""" + width, height = 59, 71 + expected_size = (width, height) + fill_counts = {True: width * height, False: 0} + + for fill, expected_count in fill_counts.items(): + msg = "fill={}".format(fill) + + mask = pygame.mask.Mask(expected_size, fill) + + self.assertIsInstance(mask, pygame.mask.Mask, msg) + self.assertEqual(mask.count(), expected_count, msg) + self.assertEqual(mask.get_size(), expected_size, msg) + + def test_mask__size_kwarg(self): + """Ensure masks are created correctly using the size keyword.""" + width, height = 73, 83 + expected_size = (width, height) + fill_counts = {True: width * height, False: 0} + + for fill, expected_count in fill_counts.items(): + msg = "fill={}".format(fill) + + mask1 = pygame.mask.Mask(fill=fill, size=expected_size) + mask2 = pygame.mask.Mask(size=expected_size, fill=fill) + + self.assertIsInstance(mask1, pygame.mask.Mask, msg) + self.assertIsInstance(mask2, pygame.mask.Mask, msg) + self.assertEqual(mask1.count(), expected_count, msg) + self.assertEqual(mask2.count(), expected_count, msg) + self.assertEqual(mask1.get_size(), expected_size, msg) + self.assertEqual(mask2.get_size(), expected_size, msg) + + def test_copy(self): + """Ensures copy works correctly with some bits set and unset.""" + # Test different widths and heights. + for width in (31, 32, 33, 63, 64, 65): + for height in (31, 32, 33, 63, 64, 65): + mask = pygame.mask.Mask((width, height)) + + # Create a checkerboard pattern of set/unset bits. + for x in range(width): + for y in range(x & 1, height, 2): + mask.set_at((x, y)) + + # Test both the copy() and __copy__() methods. + for mask_copy in (mask.copy(), copy.copy(mask)): + self.assertIsInstance(mask_copy, pygame.mask.Mask) + self.assertIsNot(mask_copy, mask) + assertMaskEqual(self, mask_copy, mask) + + def test_copy__full(self): + """Ensures copy works correctly on a filled masked.""" + # Test different widths and heights. + for width in (31, 32, 33, 63, 64, 65): + for height in (31, 32, 33, 63, 64, 65): + mask = pygame.mask.Mask((width, height), fill=True) + + # Test both the copy() and __copy__() methods. + for mask_copy in (mask.copy(), copy.copy(mask)): + self.assertIsInstance(mask_copy, pygame.mask.Mask) + self.assertIsNot(mask_copy, mask) + assertMaskEqual(self, mask_copy, mask) + + def test_copy__empty(self): + """Ensures copy works correctly on an empty mask.""" + for width in (31, 32, 33, 63, 64, 65): + for height in (31, 32, 33, 63, 64, 65): + mask = pygame.mask.Mask((width, height)) + + # Test both the copy() and __copy__() methods. + for mask_copy in (mask.copy(), copy.copy(mask)): + self.assertIsInstance(mask_copy, pygame.mask.Mask) + self.assertIsNot(mask_copy, mask) + assertMaskEqual(self, mask_copy, mask) + + def test_copy__independent(self): + """Ensures copy makes an independent copy of the mask.""" + mask_set_pos = (64, 1) + mask_copy_set_pos = (64, 2) + mask = pygame.mask.Mask((65, 3)) + + # Test both the copy() and __copy__() methods. + mask_copies = (mask.copy(), copy.copy(mask)) + mask.set_at(mask_set_pos) + + for mask_copy in mask_copies: + mask_copy.set_at(mask_copy_set_pos) + + self.assertIsNot(mask_copy, mask) + self.assertNotEqual( + mask_copy.get_at(mask_set_pos), mask.get_at(mask_set_pos) + ) + self.assertNotEqual( + mask_copy.get_at(mask_copy_set_pos), mask.get_at(mask_copy_set_pos) + ) + + def test_get_size(self): + """Ensure a mask's size is correctly retrieved.""" + expected_size = (93, 101) + mask = pygame.mask.Mask(expected_size) + + self.assertEqual(mask.get_size(), expected_size) + + def test_get_rect(self): + """Ensures get_rect works correctly.""" + expected_rect = pygame.Rect((0, 0), (11, 13)) + + # Test on full and empty masks. + for fill in (True, False): + mask = pygame.mask.Mask(expected_rect.size, fill=fill) + + rect = mask.get_rect() + + self.assertEqual(rect, expected_rect) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_get_rect__one_kwarg(self): + """Ensures get_rect supports a single rect attribute kwarg. + + Tests all the rect attributes. + """ + # Rect attributes that take a single value. + RECT_SINGLE_VALUE_ATTRIBUTES = ( + "x", + "y", + "top", + "left", + "bottom", + "right", + "centerx", + "centery", + "width", + "height", + "w", + "h", + ) + + # Rect attributes that take 2 values. + RECT_DOUBLE_VALUE_ATTRIBUTES = ( + "topleft", + "bottomleft", + "topright", + "bottomright", + "midtop", + "midleft", + "midbottom", + "midright", + "center", + "size", + ) + + # Testing ints/floats and tuples/lists/Vector2s. + # {attribute_names : attribute_values} + rect_attributes = { + RECT_SINGLE_VALUE_ATTRIBUTES: (3, 5.1), + RECT_DOUBLE_VALUE_ATTRIBUTES: ((1, 2.2), [2.3, 3], Vector2(0, 1)), + } + + size = (7, 3) + mask = pygame.mask.Mask(size) + + for attributes, values in rect_attributes.items(): + for attribute in attributes: + for value in values: + expected_rect = pygame.Rect((0, 0), size) + setattr(expected_rect, attribute, value) + + rect = mask.get_rect(**{attribute: value}) + + self.assertEqual(rect, expected_rect) + + def test_get_rect__multiple_kwargs(self): + """Ensures get_rect supports multiple rect attribute kwargs.""" + mask = pygame.mask.Mask((5, 4)) + expected_rect = pygame.Rect((0, 0), (0, 0)) + kwargs = {"x": 7.1, "top": -1, "size": Vector2(2, 3.2)} + + for attrib, value in kwargs.items(): + setattr(expected_rect, attrib, value) + + rect = mask.get_rect(**kwargs) + + self.assertEqual(rect, expected_rect) + + def test_get_rect__no_arg_support(self): + """Ensures get_rect only supports kwargs.""" + mask = pygame.mask.Mask((4, 5)) + + with self.assertRaises(TypeError): + rect = mask.get_rect(3) + + with self.assertRaises(TypeError): + rect = mask.get_rect((1, 2)) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_get_rect__invalid_kwarg_name(self): + """Ensures get_rect detects invalid kwargs.""" + mask = pygame.mask.Mask((1, 2)) + + with self.assertRaises(AttributeError): + rect = mask.get_rect(righte=11) + + with self.assertRaises(AttributeError): + rect = mask.get_rect(toplef=(1, 1)) + + with self.assertRaises(AttributeError): + rect = mask.get_rect(move=(3, 2)) + + def test_get_rect__invalid_kwarg_format(self): + """Ensures get_rect detects invalid kwarg formats.""" + mask = pygame.mask.Mask((3, 11)) + + with self.assertRaises(TypeError): + rect = mask.get_rect(right="1") # Wrong type. + + with self.assertRaises(TypeError): + rect = mask.get_rect(bottom=(1,)) # Wrong type. + + with self.assertRaises(TypeError): + rect = mask.get_rect(centerx=(1, 1)) # Wrong type. + + with self.assertRaises(TypeError): + rect = mask.get_rect(midleft=(1, "1")) # Wrong type. + + with self.assertRaises(TypeError): + rect = mask.get_rect(topright=(1,)) # Too few. + + with self.assertRaises(TypeError): + rect = mask.get_rect(bottomleft=(1, 2, 3)) # Too many. + + with self.assertRaises(TypeError): + rect = mask.get_rect(midbottom=1) # Wrong type. + + def test_get_at(self): + """Ensure individual mask bits are correctly retrieved.""" + width, height = 5, 7 + mask0 = pygame.mask.Mask((width, height)) + mask1 = pygame.mask.Mask((width, height), fill=True) + mask0_expected_bit = 0 + mask1_expected_bit = 1 + pos = (width - 1, height - 1) + + # Check twice to make sure bits aren't toggled. + self.assertEqual(mask0.get_at(pos), mask0_expected_bit) + self.assertEqual(mask0.get_at(pos=pos), mask0_expected_bit) + self.assertEqual(mask1.get_at(Vector2(pos)), mask1_expected_bit) + self.assertEqual(mask1.get_at(pos=Vector2(pos)), mask1_expected_bit) + + def test_get_at__out_of_bounds(self): + """Ensure get_at() checks bounds.""" + width, height = 11, 3 + mask = pygame.mask.Mask((width, height)) + + with self.assertRaises(IndexError): + mask.get_at((width, 0)) + + with self.assertRaises(IndexError): + mask.get_at((0, height)) + + with self.assertRaises(IndexError): + mask.get_at((-1, 0)) + + with self.assertRaises(IndexError): + mask.get_at((0, -1)) + + def test_set_at(self): + """Ensure individual mask bits are set to 1.""" + width, height = 13, 17 + mask0 = pygame.mask.Mask((width, height)) + mask1 = pygame.mask.Mask((width, height), fill=True) + mask0_expected_count = 1 + mask1_expected_count = mask1.count() + expected_bit = 1 + pos = (width - 1, height - 1) + + mask0.set_at(pos, expected_bit) # set 0 to 1 + mask1.set_at(pos=Vector2(pos), value=expected_bit) # set 1 to 1 + + self.assertEqual(mask0.get_at(pos), expected_bit) + self.assertEqual(mask0.count(), mask0_expected_count) + self.assertEqual(mask1.get_at(pos), expected_bit) + self.assertEqual(mask1.count(), mask1_expected_count) + + def test_set_at__to_0(self): + """Ensure individual mask bits are set to 0.""" + width, height = 11, 7 + mask0 = pygame.mask.Mask((width, height)) + mask1 = pygame.mask.Mask((width, height), fill=True) + mask0_expected_count = 0 + mask1_expected_count = mask1.count() - 1 + expected_bit = 0 + pos = (width - 1, height - 1) + + mask0.set_at(pos, expected_bit) # set 0 to 0 + mask1.set_at(pos, expected_bit) # set 1 to 0 + + self.assertEqual(mask0.get_at(pos), expected_bit) + self.assertEqual(mask0.count(), mask0_expected_count) + self.assertEqual(mask1.get_at(pos), expected_bit) + self.assertEqual(mask1.count(), mask1_expected_count) + + def test_set_at__default_value(self): + """Ensure individual mask bits are set using the default value.""" + width, height = 3, 21 + mask0 = pygame.mask.Mask((width, height)) + mask1 = pygame.mask.Mask((width, height), fill=True) + mask0_expected_count = 1 + mask1_expected_count = mask1.count() + expected_bit = 1 + pos = (width - 1, height - 1) + + mask0.set_at(pos) # set 0 to 1 + mask1.set_at(pos) # set 1 to 1 + + self.assertEqual(mask0.get_at(pos), expected_bit) + self.assertEqual(mask0.count(), mask0_expected_count) + self.assertEqual(mask1.get_at(pos), expected_bit) + self.assertEqual(mask1.count(), mask1_expected_count) + + def test_set_at__out_of_bounds(self): + """Ensure set_at() checks bounds.""" + width, height = 11, 3 + mask = pygame.mask.Mask((width, height)) + + with self.assertRaises(IndexError): + mask.set_at((width, 0)) + + with self.assertRaises(IndexError): + mask.set_at((0, height)) + + with self.assertRaises(IndexError): + mask.set_at((-1, 0)) + + with self.assertRaises(IndexError): + mask.set_at((0, -1)) + + def test_overlap(self): + """Ensure the overlap intersection is correctly calculated. + + Testing the different combinations of full/empty masks: + (mask1-filled) 1 overlap 1 (mask2-filled) + (mask1-empty) 0 overlap 1 (mask2-filled) + (mask1-filled) 1 overlap 0 (mask2-empty) + (mask1-empty) 0 overlap 0 (mask2-empty) + """ + expected_size = (4, 4) + offset = (0, 0) + expected_default = None + expected_overlaps = {(True, True): offset} + + for fill2 in (True, False): + mask2 = pygame.mask.Mask(expected_size, fill=fill2) + mask2_count = mask2.count() + + for fill1 in (True, False): + key = (fill1, fill2) + msg = "key={}".format(key) + mask1 = pygame.mask.Mask(expected_size, fill=fill1) + mask1_count = mask1.count() + expected_pos = expected_overlaps.get(key, expected_default) + + overlap_pos = mask1.overlap(mask2, offset) + + self.assertEqual(overlap_pos, expected_pos, msg) + + # Ensure mask1/mask2 unchanged. + self.assertEqual(mask1.count(), mask1_count, msg) + self.assertEqual(mask2.count(), mask2_count, msg) + self.assertEqual(mask1.get_size(), expected_size, msg) + self.assertEqual(mask2.get_size(), expected_size, msg) + + def test_overlap__offset(self): + """Ensure an offset overlap intersection is correctly calculated.""" + mask1 = pygame.mask.Mask((65, 3), fill=True) + mask2 = pygame.mask.Mask((66, 4), fill=True) + mask1_count = mask1.count() + mask2_count = mask2.count() + mask1_size = mask1.get_size() + mask2_size = mask2.get_size() + + for offset in self.ORIGIN_OFFSETS: + msg = "offset={}".format(offset) + expected_pos = (max(offset[0], 0), max(offset[1], 0)) + + overlap_pos = mask1.overlap(other=mask2, offset=offset) + + self.assertEqual(overlap_pos, expected_pos, msg) + + # Ensure mask1/mask2 unchanged. + self.assertEqual(mask1.count(), mask1_count, msg) + self.assertEqual(mask2.count(), mask2_count, msg) + self.assertEqual(mask1.get_size(), mask1_size, msg) + self.assertEqual(mask2.get_size(), mask2_size, msg) + + def test_overlap__offset_with_unset_bits(self): + """Ensure an offset overlap intersection is correctly calculated + when (0, 0) bits not set.""" + mask1 = pygame.mask.Mask((65, 3), fill=True) + mask2 = pygame.mask.Mask((66, 4), fill=True) + unset_pos = (0, 0) + mask1.set_at(unset_pos, 0) + mask2.set_at(unset_pos, 0) + mask1_count = mask1.count() + mask2_count = mask2.count() + mask1_size = mask1.get_size() + mask2_size = mask2.get_size() + + for offset in self.ORIGIN_OFFSETS: + msg = "offset={}".format(offset) + x, y = offset + expected_y = max(y, 0) + if 0 == y: + expected_x = max(x + 1, 1) + elif 0 < y: + expected_x = max(x + 1, 0) + else: + expected_x = max(x, 1) + + overlap_pos = mask1.overlap(mask2, Vector2(offset)) + + self.assertEqual(overlap_pos, (expected_x, expected_y), msg) + + # Ensure mask1/mask2 unchanged. + self.assertEqual(mask1.count(), mask1_count, msg) + self.assertEqual(mask2.count(), mask2_count, msg) + self.assertEqual(mask1.get_size(), mask1_size, msg) + self.assertEqual(mask2.get_size(), mask2_size, msg) + self.assertEqual(mask1.get_at(unset_pos), 0, msg) + self.assertEqual(mask2.get_at(unset_pos), 0, msg) + + def test_overlap__no_overlap(self): + """Ensure an offset overlap intersection is correctly calculated + when there is no overlap.""" + mask1 = pygame.mask.Mask((65, 3), fill=True) + mask1_count = mask1.count() + mask1_size = mask1.get_size() + + mask2_w, mask2_h = 67, 5 + mask2_size = (mask2_w, mask2_h) + mask2 = pygame.mask.Mask(mask2_size) + set_pos = (mask2_w - 1, mask2_h - 1) + mask2.set_at(set_pos) + mask2_count = 1 + + for offset in self.ORIGIN_OFFSETS: + msg = "offset={}".format(offset) + + overlap_pos = mask1.overlap(mask2, offset) + + self.assertIsNone(overlap_pos, msg) + + # Ensure mask1/mask2 unchanged. + self.assertEqual(mask1.count(), mask1_count, msg) + self.assertEqual(mask2.count(), mask2_count, msg) + self.assertEqual(mask1.get_size(), mask1_size, msg) + self.assertEqual(mask2.get_size(), mask2_size, msg) + self.assertEqual(mask2.get_at(set_pos), 1, msg) + + def test_overlap__offset_boundary(self): + """Ensures overlap handles offsets and boundaries correctly.""" + mask1 = pygame.mask.Mask((13, 3), fill=True) + mask2 = pygame.mask.Mask((7, 5), fill=True) + mask1_count = mask1.count() + mask2_count = mask2.count() + mask1_size = mask1.get_size() + mask2_size = mask2.get_size() + + # Check the 4 boundaries. + offsets = ( + (mask1_size[0], 0), # off right + (0, mask1_size[1]), # off bottom + (-mask2_size[0], 0), # off left + (0, -mask2_size[1]), + ) # off top + + for offset in offsets: + msg = "offset={}".format(offset) + + overlap_pos = mask1.overlap(mask2, offset) + + self.assertIsNone(overlap_pos, msg) + + # Ensure mask1/mask2 unchanged. + self.assertEqual(mask1.count(), mask1_count, msg) + self.assertEqual(mask2.count(), mask2_count, msg) + self.assertEqual(mask1.get_size(), mask1_size, msg) + self.assertEqual(mask2.get_size(), mask2_size, msg) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_overlap__bit_boundaries(self): + """Ensures overlap handles masks of different sizes correctly. + + Tests masks of different sizes, including: + -masks 31 to 33 bits wide (32 bit boundaries) + -masks 63 to 65 bits wide (64 bit boundaries) + """ + for height in range(2, 4): + for width in range(2, 66): + mask_size = (width, height) + mask_count = width * height + mask1 = pygame.mask.Mask(mask_size, fill=True) + mask2 = pygame.mask.Mask(mask_size, fill=True) + + # Testing masks offset from each other. + for offset in self.ORIGIN_OFFSETS: + msg = "size={}, offset={}".format(mask_size, offset) + expected_pos = (max(offset[0], 0), max(offset[1], 0)) + + overlap_pos = mask1.overlap(mask2, offset) + + self.assertEqual(overlap_pos, expected_pos, msg) + + # Ensure mask1/mask2 unchanged. + self.assertEqual(mask1.count(), mask_count, msg) + self.assertEqual(mask2.count(), mask_count, msg) + self.assertEqual(mask1.get_size(), mask_size, msg) + self.assertEqual(mask2.get_size(), mask_size, msg) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_overlap__invalid_mask_arg(self): + """Ensure overlap handles invalid mask arguments correctly.""" + size = (5, 3) + offset = (0, 0) + mask = pygame.mask.Mask(size) + invalid_mask = pygame.Surface(size) + + with self.assertRaises(TypeError): + overlap_pos = mask.overlap(invalid_mask, offset) + + def test_overlap__invalid_offset_arg(self): + """Ensure overlap handles invalid offset arguments correctly.""" + size = (2, 7) + offset = "(0, 0)" + mask1 = pygame.mask.Mask(size) + mask2 = pygame.mask.Mask(size) + + with self.assertRaises(TypeError): + overlap_pos = mask1.overlap(mask2, offset) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_overlap_area(self): + """Ensure the overlap_area is correctly calculated. + + Testing the different combinations of full/empty masks: + (mask1-filled) 1 overlap_area 1 (mask2-filled) + (mask1-empty) 0 overlap_area 1 (mask2-filled) + (mask1-filled) 1 overlap_area 0 (mask2-empty) + (mask1-empty) 0 overlap_area 0 (mask2-empty) + """ + expected_size = width, height = (4, 4) + offset = (0, 0) + expected_default = 0 + expected_counts = {(True, True): width * height} + + for fill2 in (True, False): + mask2 = pygame.mask.Mask(expected_size, fill=fill2) + mask2_count = mask2.count() + + for fill1 in (True, False): + key = (fill1, fill2) + msg = "key={}".format(key) + mask1 = pygame.mask.Mask(expected_size, fill=fill1) + mask1_count = mask1.count() + expected_count = expected_counts.get(key, expected_default) + + overlap_count = mask1.overlap_area(mask2, offset) + + self.assertEqual(overlap_count, expected_count, msg) + + # Ensure mask1/mask2 unchanged. + self.assertEqual(mask1.count(), mask1_count, msg) + self.assertEqual(mask2.count(), mask2_count, msg) + self.assertEqual(mask1.get_size(), expected_size, msg) + self.assertEqual(mask2.get_size(), expected_size, msg) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_overlap_area__offset(self): + """Ensure an offset overlap_area is correctly calculated.""" + mask1 = pygame.mask.Mask((65, 3), fill=True) + mask2 = pygame.mask.Mask((66, 4), fill=True) + mask1_count = mask1.count() + mask2_count = mask2.count() + mask1_size = mask1.get_size() + mask2_size = mask2.get_size() + + # Using rects to help determine the overlapping area. + rect1 = mask1.get_rect() + rect2 = mask2.get_rect() + + for offset in self.ORIGIN_OFFSETS: + msg = "offset={}".format(offset) + rect2.topleft = offset + overlap_rect = rect1.clip(rect2) + expected_count = overlap_rect.w * overlap_rect.h + + overlap_count = mask1.overlap_area(other=mask2, offset=offset) + + self.assertEqual(overlap_count, expected_count, msg) + + # Ensure mask1/mask2 unchanged. + self.assertEqual(mask1.count(), mask1_count, msg) + self.assertEqual(mask2.count(), mask2_count, msg) + self.assertEqual(mask1.get_size(), mask1_size, msg) + self.assertEqual(mask2.get_size(), mask2_size, msg) + + def test_overlap_area__offset_boundary(self): + """Ensures overlap_area handles offsets and boundaries correctly.""" + mask1 = pygame.mask.Mask((11, 3), fill=True) + mask2 = pygame.mask.Mask((5, 7), fill=True) + mask1_count = mask1.count() + mask2_count = mask2.count() + mask1_size = mask1.get_size() + mask2_size = mask2.get_size() + expected_count = 0 + + # Check the 4 boundaries. + offsets = ( + (mask1_size[0], 0), # off right + (0, mask1_size[1]), # off bottom + (-mask2_size[0], 0), # off left + (0, -mask2_size[1]), + ) # off top + + for offset in offsets: + msg = "offset={}".format(offset) + + overlap_count = mask1.overlap_area(mask2, Vector2(offset)) + + self.assertEqual(overlap_count, expected_count, msg) + + # Ensure mask1/mask2 unchanged. + self.assertEqual(mask1.count(), mask1_count, msg) + self.assertEqual(mask2.count(), mask2_count, msg) + self.assertEqual(mask1.get_size(), mask1_size, msg) + self.assertEqual(mask2.get_size(), mask2_size, msg) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_overlap_area__bit_boundaries(self): + """Ensures overlap_area handles masks of different sizes correctly. + + Tests masks of different sizes, including: + -masks 31 to 33 bits wide (32 bit boundaries) + -masks 63 to 65 bits wide (64 bit boundaries) + """ + for height in range(2, 4): + for width in range(2, 66): + mask_size = (width, height) + mask_count = width * height + mask1 = pygame.mask.Mask(mask_size, fill=True) + mask2 = pygame.mask.Mask(mask_size, fill=True) + + # Using rects to help determine the overlapping area. + rect1 = mask1.get_rect() + rect2 = mask2.get_rect() + + # Testing masks offset from each other. + for offset in self.ORIGIN_OFFSETS: + msg = "size={}, offset={}".format(mask_size, offset) + rect2.topleft = offset + overlap_rect = rect1.clip(rect2) + expected_overlap_count = overlap_rect.w * overlap_rect.h + + overlap_count = mask1.overlap_area(mask2, offset) + + self.assertEqual(overlap_count, expected_overlap_count, msg) + + # Ensure mask1/mask2 unchanged. + self.assertEqual(mask1.count(), mask_count, msg) + self.assertEqual(mask2.count(), mask_count, msg) + self.assertEqual(mask1.get_size(), mask_size, msg) + self.assertEqual(mask2.get_size(), mask_size, msg) + + def test_overlap_area__invalid_mask_arg(self): + """Ensure overlap_area handles invalid mask arguments correctly.""" + size = (3, 5) + offset = (0, 0) + mask = pygame.mask.Mask(size) + invalid_mask = pygame.Surface(size) + + with self.assertRaises(TypeError): + overlap_count = mask.overlap_area(invalid_mask, offset) + + def test_overlap_area__invalid_offset_arg(self): + """Ensure overlap_area handles invalid offset arguments correctly.""" + size = (7, 2) + offset = "(0, 0)" + mask1 = pygame.mask.Mask(size) + mask2 = pygame.mask.Mask(size) + + with self.assertRaises(TypeError): + overlap_count = mask1.overlap_area(mask2, offset) + + def test_overlap_mask(self): + """Ensure overlap_mask's mask has correct bits set. + + Testing the different combinations of full/empty masks: + (mask1-filled) 1 overlap_mask 1 (mask2-filled) + (mask1-empty) 0 overlap_mask 1 (mask2-filled) + (mask1-filled) 1 overlap_mask 0 (mask2-empty) + (mask1-empty) 0 overlap_mask 0 (mask2-empty) + """ + expected_size = (4, 4) + offset = (0, 0) + expected_default = pygame.mask.Mask(expected_size) + expected_masks = {(True, True): pygame.mask.Mask(expected_size, fill=True)} + + for fill2 in (True, False): + mask2 = pygame.mask.Mask(expected_size, fill=fill2) + mask2_count = mask2.count() + + for fill1 in (True, False): + key = (fill1, fill2) + msg = "key={}".format(key) + mask1 = pygame.mask.Mask(expected_size, fill=fill1) + mask1_count = mask1.count() + expected_mask = expected_masks.get(key, expected_default) + + overlap_mask = mask1.overlap_mask(other=mask2, offset=offset) + + self.assertIsInstance(overlap_mask, pygame.mask.Mask, msg) + assertMaskEqual(self, overlap_mask, expected_mask, msg) + + # Ensure mask1/mask2 unchanged. + self.assertEqual(mask1.count(), mask1_count, msg) + self.assertEqual(mask2.count(), mask2_count, msg) + self.assertEqual(mask1.get_size(), expected_size, msg) + self.assertEqual(mask2.get_size(), expected_size, msg) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_overlap_mask__bits_set(self): + """Ensure overlap_mask's mask has correct bits set.""" + mask1 = pygame.mask.Mask((50, 50), fill=True) + mask2 = pygame.mask.Mask((300, 10), fill=True) + mask1_count = mask1.count() + mask2_count = mask2.count() + mask1_size = mask1.get_size() + mask2_size = mask2.get_size() + + mask3 = mask1.overlap_mask(mask2, (-1, 0)) + + for i in range(50): + for j in range(10): + self.assertEqual(mask3.get_at((i, j)), 1, "({}, {})".format(i, j)) + + for i in range(50): + for j in range(11, 50): + self.assertEqual(mask3.get_at((i, j)), 0, "({}, {})".format(i, j)) + + # Ensure mask1/mask2 unchanged. + self.assertEqual(mask1.count(), mask1_count) + self.assertEqual(mask2.count(), mask2_count) + self.assertEqual(mask1.get_size(), mask1_size) + self.assertEqual(mask2.get_size(), mask2_size) + + def test_overlap_mask__offset(self): + """Ensure an offset overlap_mask's mask is correctly calculated.""" + mask1 = pygame.mask.Mask((65, 3), fill=True) + mask2 = pygame.mask.Mask((66, 4), fill=True) + mask1_count = mask1.count() + mask2_count = mask2.count() + mask1_size = mask1.get_size() + mask2_size = mask2.get_size() + expected_mask = pygame.Mask(mask1_size) + + # Using rects to help determine the overlapping area. + rect1 = mask1.get_rect() + rect2 = mask2.get_rect() + + for offset in self.ORIGIN_OFFSETS: + msg = "offset={}".format(offset) + rect2.topleft = offset + overlap_rect = rect1.clip(rect2) + expected_mask.clear() + expected_mask.draw( + pygame.Mask(overlap_rect.size, fill=True), overlap_rect.topleft + ) + + overlap_mask = mask1.overlap_mask(mask2, offset) + + self.assertIsInstance(overlap_mask, pygame.mask.Mask, msg) + assertMaskEqual(self, overlap_mask, expected_mask, msg) + + # Ensure mask1/mask2 unchanged. + self.assertEqual(mask1.count(), mask1_count, msg) + self.assertEqual(mask2.count(), mask2_count, msg) + self.assertEqual(mask1.get_size(), mask1_size, msg) + self.assertEqual(mask2.get_size(), mask2_size, msg) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_overlap_mask__specific_offsets(self): + """Ensure an offset overlap_mask's mask is correctly calculated. + + Testing the specific case of: + -both masks are wider than 32 bits + -a positive offset is used + -the mask calling overlap_mask() is wider than the mask passed in + """ + mask1 = pygame.mask.Mask((65, 5), fill=True) + mask2 = pygame.mask.Mask((33, 3), fill=True) + expected_mask = pygame.Mask(mask1.get_size()) + + # Using rects to help determine the overlapping area. + rect1 = mask1.get_rect() + rect2 = mask2.get_rect() + + # This rect's corners are used to move rect2 around the inside of + # rect1. + corner_rect = rect1.inflate(-2, -2) + + for corner in ("topleft", "topright", "bottomright", "bottomleft"): + setattr(rect2, corner, getattr(corner_rect, corner)) + offset = rect2.topleft + msg = "offset={}".format(offset) + overlap_rect = rect1.clip(rect2) + expected_mask.clear() + expected_mask.draw( + pygame.Mask(overlap_rect.size, fill=True), overlap_rect.topleft + ) + + overlap_mask = mask1.overlap_mask(mask2, offset) + + self.assertIsInstance(overlap_mask, pygame.mask.Mask, msg) + assertMaskEqual(self, overlap_mask, expected_mask, msg) + + def test_overlap_mask__offset_boundary(self): + """Ensures overlap_mask handles offsets and boundaries correctly.""" + mask1 = pygame.mask.Mask((9, 3), fill=True) + mask2 = pygame.mask.Mask((11, 5), fill=True) + mask1_count = mask1.count() + mask2_count = mask2.count() + mask1_size = mask1.get_size() + mask2_size = mask2.get_size() + expected_count = 0 + expected_size = mask1_size + + # Check the 4 boundaries. + offsets = ( + (mask1_size[0], 0), # off right + (0, mask1_size[1]), # off bottom + (-mask2_size[0], 0), # off left + (0, -mask2_size[1]), + ) # off top + + for offset in offsets: + msg = "offset={}".format(offset) + + overlap_mask = mask1.overlap_mask(mask2, offset) + + self.assertIsInstance(overlap_mask, pygame.mask.Mask, msg) + self.assertEqual(overlap_mask.count(), expected_count, msg) + self.assertEqual(overlap_mask.get_size(), expected_size, msg) + + # Ensure mask1/mask2 unchanged. + self.assertEqual(mask1.count(), mask1_count, msg) + self.assertEqual(mask2.count(), mask2_count, msg) + self.assertEqual(mask1.get_size(), mask1_size, msg) + self.assertEqual(mask2.get_size(), mask2_size, msg) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_overlap_mask__bit_boundaries(self): + """Ensures overlap_mask handles masks of different sizes correctly. + + Tests masks of different sizes, including: + -masks 31 to 33 bits wide (32 bit boundaries) + -masks 63 to 65 bits wide (64 bit boundaries) + """ + for height in range(2, 4): + for width in range(2, 66): + mask_size = (width, height) + mask_count = width * height + mask1 = pygame.mask.Mask(mask_size, fill=True) + mask2 = pygame.mask.Mask(mask_size, fill=True) + expected_mask = pygame.Mask(mask_size) + + # Using rects to help determine the overlapping area. + rect1 = mask1.get_rect() + rect2 = mask2.get_rect() + + # Testing masks offset from each other. + for offset in self.ORIGIN_OFFSETS: + msg = "size={}, offset={}".format(mask_size, offset) + rect2.topleft = offset + overlap_rect = rect1.clip(rect2) + expected_mask.clear() + expected_mask.draw( + pygame.Mask(overlap_rect.size, fill=True), overlap_rect.topleft + ) + + overlap_mask = mask1.overlap_mask(mask2, offset) + + self.assertIsInstance(overlap_mask, pygame.mask.Mask, msg) + assertMaskEqual(self, overlap_mask, expected_mask, msg) + + # Ensure mask1/mask2 unchanged. + self.assertEqual(mask1.count(), mask_count, msg) + self.assertEqual(mask2.count(), mask_count, msg) + self.assertEqual(mask1.get_size(), mask_size, msg) + self.assertEqual(mask2.get_size(), mask_size, msg) + + def test_overlap_mask__invalid_mask_arg(self): + """Ensure overlap_mask handles invalid mask arguments correctly.""" + size = (3, 2) + offset = (0, 0) + mask = pygame.mask.Mask(size) + invalid_mask = pygame.Surface(size) + + with self.assertRaises(TypeError): + overlap_mask = mask.overlap_mask(invalid_mask, offset) + + def test_overlap_mask__invalid_offset_arg(self): + """Ensure overlap_mask handles invalid offset arguments correctly.""" + size = (5, 2) + offset = "(0, 0)" + mask1 = pygame.mask.Mask(size) + mask2 = pygame.mask.Mask(size) + + with self.assertRaises(TypeError): + overlap_mask = mask1.overlap_mask(mask2, offset) + + def test_mask_access(self): + """do the set_at, and get_at parts work correctly?""" + m = pygame.Mask((10, 10)) + m.set_at((0, 0), 1) + self.assertEqual(m.get_at((0, 0)), 1) + m.set_at((9, 0), 1) + self.assertEqual(m.get_at((9, 0)), 1) + + # s = pygame.Surface((10,10)) + # s.set_at((1,0), (0, 0, 1, 255)) + # self.assertEqual(s.get_at((1,0)), (0, 0, 1, 255)) + # s.set_at((-1,0), (0, 0, 1, 255)) + + # out of bounds, should get IndexError + self.assertRaises(IndexError, lambda: m.get_at((-1, 0))) + self.assertRaises(IndexError, lambda: m.set_at((-1, 0), 1)) + self.assertRaises(IndexError, lambda: m.set_at((10, 0), 1)) + self.assertRaises(IndexError, lambda: m.set_at((0, 10), 1)) + + def test_fill(self): + """Ensure a mask can be filled.""" + width, height = 11, 23 + expected_count = width * height + expected_size = (width, height) + mask = pygame.mask.Mask(expected_size) + + mask.fill() + + self.assertEqual(mask.count(), expected_count) + self.assertEqual(mask.get_size(), expected_size) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_fill__bit_boundaries(self): + """Ensures masks of different sizes are filled correctly. + + Tests masks of different sizes, including: + -masks 31 to 33 bits wide (32 bit boundaries) + -masks 63 to 65 bits wide (64 bit boundaries) + """ + for height in range(1, 4): + for width in range(1, 66): + mask = pygame.mask.Mask((width, height)) + expected_count = width * height + + mask.fill() + + self.assertEqual( + mask.count(), expected_count, "size=({}, {})".format(width, height) + ) + + def test_clear(self): + """Ensure a mask can be cleared.""" + expected_count = 0 + expected_size = (13, 27) + mask = pygame.mask.Mask(expected_size, fill=True) + + mask.clear() + + self.assertEqual(mask.count(), expected_count) + self.assertEqual(mask.get_size(), expected_size) + + def test_clear__bit_boundaries(self): + """Ensures masks of different sizes are cleared correctly. + + Tests masks of different sizes, including: + -masks 31 to 33 bits wide (32 bit boundaries) + -masks 63 to 65 bits wide (64 bit boundaries) + """ + expected_count = 0 + + for height in range(1, 4): + for width in range(1, 66): + mask = pygame.mask.Mask((width, height), fill=True) + + mask.clear() + + self.assertEqual( + mask.count(), expected_count, "size=({}, {})".format(width, height) + ) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_invert(self): + """Ensure a mask can be inverted.""" + side = 73 + expected_size = (side, side) + mask1 = pygame.mask.Mask(expected_size) + mask2 = pygame.mask.Mask(expected_size, fill=True) + expected_count1 = side * side + expected_count2 = 0 + + for i in range(side): + expected_count1 -= 1 + expected_count2 += 1 + pos = (i, i) + mask1.set_at(pos) + mask2.set_at(pos, 0) + + mask1.invert() + mask2.invert() + + self.assertEqual(mask1.count(), expected_count1) + self.assertEqual(mask2.count(), expected_count2) + self.assertEqual(mask1.get_size(), expected_size) + self.assertEqual(mask2.get_size(), expected_size) + + for i in range(side): + pos = (i, i) + msg = "pos={}".format(pos) + + self.assertEqual(mask1.get_at(pos), 0, msg) + self.assertEqual(mask2.get_at(pos), 1, msg) + + def test_invert__full(self): + """Ensure a full mask can be inverted.""" + expected_count = 0 + expected_size = (43, 97) + mask = pygame.mask.Mask(expected_size, fill=True) + + mask.invert() + + self.assertEqual(mask.count(), expected_count) + self.assertEqual(mask.get_size(), expected_size) + + def test_invert__empty(self): + """Ensure an empty mask can be inverted.""" + width, height = 43, 97 + expected_size = (width, height) + expected_count = width * height + mask = pygame.mask.Mask(expected_size) + + mask.invert() + + self.assertEqual(mask.count(), expected_count) + self.assertEqual(mask.get_size(), expected_size) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_invert__bit_boundaries(self): + """Ensures masks of different sizes are inverted correctly. + + Tests masks of different sizes, including: + -masks 31 to 33 bits wide (32 bit boundaries) + -masks 63 to 65 bits wide (64 bit boundaries) + """ + for fill in (True, False): + for height in range(1, 4): + for width in range(1, 66): + mask = pygame.mask.Mask((width, height), fill=fill) + expected_count = 0 if fill else width * height + + mask.invert() + + self.assertEqual( + mask.count(), + expected_count, + "fill={}, size=({}, {})".format(fill, width, height), + ) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_scale(self): + """Ensure a mask can be scaled.""" + width, height = 43, 61 + original_size = (width, height) + + for fill in (True, False): + original_mask = pygame.mask.Mask(original_size, fill=fill) + original_count = width * height if fill else 0 + + # Test a range of sizes. Also tests scaling to 'same' + # size when new_w, new_h = width, height + for new_w in range(width - 10, width + 10): + for new_h in range(height - 10, height + 10): + expected_size = (new_w, new_h) + expected_count = new_w * new_h if fill else 0 + msg = "size={}".format(expected_size) + + mask = original_mask.scale(scale=expected_size) + + self.assertIsInstance(mask, pygame.mask.Mask, msg) + self.assertEqual(mask.count(), expected_count, msg) + self.assertEqual(mask.get_size(), expected_size) + + # Ensure the original mask is unchanged. + self.assertEqual(original_mask.count(), original_count, msg) + self.assertEqual(original_mask.get_size(), original_size, msg) + + def test_scale__negative_size(self): + """Ensure scale handles negative sizes correctly.""" + mask = pygame.Mask((100, 100)) + + with self.assertRaises(ValueError): + mask.scale((-1, -1)) + + with self.assertRaises(ValueError): + mask.scale(Vector2(-1, 10)) + + with self.assertRaises(ValueError): + mask.scale((10, -1)) + + def test_draw(self): + """Ensure a mask can be drawn onto another mask. + + Testing the different combinations of full/empty masks: + (mask1-filled) 1 draw 1 (mask2-filled) + (mask1-empty) 0 draw 1 (mask2-filled) + (mask1-filled) 1 draw 0 (mask2-empty) + (mask1-empty) 0 draw 0 (mask2-empty) + """ + expected_size = (4, 4) + offset = (0, 0) + expected_default = pygame.mask.Mask(expected_size, fill=True) + expected_masks = {(False, False): pygame.mask.Mask(expected_size)} + + for fill2 in (True, False): + mask2 = pygame.mask.Mask(expected_size, fill=fill2) + mask2_count = mask2.count() + + for fill1 in (True, False): + key = (fill1, fill2) + msg = "key={}".format(key) + mask1 = pygame.mask.Mask(expected_size, fill=fill1) + expected_mask = expected_masks.get(key, expected_default) + + mask1.draw(mask2, offset) + + assertMaskEqual(self, mask1, expected_mask, msg) + + # Ensure mask2 unchanged. + self.assertEqual(mask2.count(), mask2_count, msg) + self.assertEqual(mask2.get_size(), expected_size, msg) + + def test_draw__offset(self): + """Ensure an offset mask can be drawn onto another mask.""" + mask1 = pygame.mask.Mask((65, 3)) + mask2 = pygame.mask.Mask((66, 4), fill=True) + mask2_count = mask2.count() + mask2_size = mask2.get_size() + expected_mask = pygame.Mask(mask1.get_size()) + + # Using rects to help determine the overlapping area. + rect1 = mask1.get_rect() + rect2 = mask2.get_rect() + + for offset in self.ORIGIN_OFFSETS: + msg = "offset={}".format(offset) + rect2.topleft = offset + overlap_rect = rect1.clip(rect2) + expected_mask.clear() + + # Normally draw() could be used to set these bits, but the draw() + # method is being tested here, so a loop is used instead. + for x in range(overlap_rect.left, overlap_rect.right): + for y in range(overlap_rect.top, overlap_rect.bottom): + expected_mask.set_at((x, y)) + mask1.clear() # Ensure it's empty for testing each offset. + + mask1.draw(other=mask2, offset=offset) + + assertMaskEqual(self, mask1, expected_mask, msg) + + # Ensure mask2 unchanged. + self.assertEqual(mask2.count(), mask2_count, msg) + self.assertEqual(mask2.get_size(), mask2_size, msg) + + def test_draw__specific_offsets(self): + """Ensure an offset mask can be drawn onto another mask. + + Testing the specific case of: + -both masks are wider than 32 bits + -a positive offset is used + -the mask calling draw() is wider than the mask passed in + """ + mask1 = pygame.mask.Mask((65, 5)) + mask2 = pygame.mask.Mask((33, 3), fill=True) + expected_mask = pygame.Mask(mask1.get_size()) + + # Using rects to help determine the overlapping area. + rect1 = mask1.get_rect() + rect2 = mask2.get_rect() + + # This rect's corners are used to move rect2 around the inside of + # rect1. + corner_rect = rect1.inflate(-2, -2) + + for corner in ("topleft", "topright", "bottomright", "bottomleft"): + setattr(rect2, corner, getattr(corner_rect, corner)) + offset = rect2.topleft + msg = "offset={}".format(offset) + overlap_rect = rect1.clip(rect2) + expected_mask.clear() + + # Normally draw() could be used to set these bits, but the draw() + # method is being tested here, so a loop is used instead. + for x in range(overlap_rect.left, overlap_rect.right): + for y in range(overlap_rect.top, overlap_rect.bottom): + expected_mask.set_at((x, y)) + mask1.clear() # Ensure it's empty for testing each offset. + + mask1.draw(mask2, offset) + + assertMaskEqual(self, mask1, expected_mask, msg) + + def test_draw__offset_boundary(self): + """Ensures draw handles offsets and boundaries correctly.""" + mask1 = pygame.mask.Mask((13, 5)) + mask2 = pygame.mask.Mask((7, 3), fill=True) + mask1_count = mask1.count() + mask2_count = mask2.count() + mask1_size = mask1.get_size() + mask2_size = mask2.get_size() + + # Check the 4 boundaries. + offsets = ( + (mask1_size[0], 0), # off right + (0, mask1_size[1]), # off bottom + (-mask2_size[0], 0), # off left + (0, -mask2_size[1]), + ) # off top + + for offset in offsets: + msg = "offset={}".format(offset) + + mask1.draw(mask2, offset) + + # Ensure mask1/mask2 unchanged. + self.assertEqual(mask1.count(), mask1_count, msg) + self.assertEqual(mask2.count(), mask2_count, msg) + self.assertEqual(mask1.get_size(), mask1_size, msg) + self.assertEqual(mask2.get_size(), mask2_size, msg) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_draw__bit_boundaries(self): + """Ensures draw handles masks of different sizes correctly. + + Tests masks of different sizes, including: + -masks 31 to 33 bits wide (32 bit boundaries) + -masks 63 to 65 bits wide (64 bit boundaries) + """ + for height in range(2, 4): + for width in range(2, 66): + mask_size = (width, height) + mask_count = width * height + mask1 = pygame.mask.Mask(mask_size) + mask2 = pygame.mask.Mask(mask_size, fill=True) + expected_mask = pygame.Mask(mask_size) + + # Using rects to help determine the overlapping area. + rect1 = mask1.get_rect() + rect2 = mask2.get_rect() + + # Testing masks offset from each other. + for offset in self.ORIGIN_OFFSETS: + msg = "size={}, offset={}".format(mask_size, offset) + rect2.topleft = offset + overlap_rect = rect1.clip(rect2) + expected_mask.clear() + + # Normally draw() could be used to set these bits, but the + # draw() method is being tested here, so a loop is used + # instead. + for x in range(overlap_rect.left, overlap_rect.right): + for y in range(overlap_rect.top, overlap_rect.bottom): + expected_mask.set_at((x, y)) + mask1.clear() # Ensure it's empty for each test. + + mask1.draw(mask2, offset) + + assertMaskEqual(self, mask1, expected_mask, msg) + + # Ensure mask2 unchanged. + self.assertEqual(mask2.count(), mask_count, msg) + self.assertEqual(mask2.get_size(), mask_size, msg) + + def test_draw__invalid_mask_arg(self): + """Ensure draw handles invalid mask arguments correctly.""" + size = (7, 3) + offset = (0, 0) + mask = pygame.mask.Mask(size) + invalid_mask = pygame.Surface(size) + + with self.assertRaises(TypeError): + mask.draw(invalid_mask, offset) + + def test_draw__invalid_offset_arg(self): + """Ensure draw handles invalid offset arguments correctly.""" + size = (5, 7) + offset = "(0, 0)" + mask1 = pygame.mask.Mask(size) + mask2 = pygame.mask.Mask(size) + + with self.assertRaises(TypeError): + mask1.draw(mask2, offset) + + def test_erase(self): + """Ensure a mask can erase another mask. + + Testing the different combinations of full/empty masks: + (mask1-filled) 1 erase 1 (mask2-filled) + (mask1-empty) 0 erase 1 (mask2-filled) + (mask1-filled) 1 erase 0 (mask2-empty) + (mask1-empty) 0 erase 0 (mask2-empty) + """ + expected_size = (4, 4) + offset = (0, 0) + expected_default = pygame.mask.Mask(expected_size) + expected_masks = {(True, False): pygame.mask.Mask(expected_size, fill=True)} + + for fill2 in (True, False): + mask2 = pygame.mask.Mask(expected_size, fill=fill2) + mask2_count = mask2.count() + + for fill1 in (True, False): + key = (fill1, fill2) + msg = "key={}".format(key) + mask1 = pygame.mask.Mask(expected_size, fill=fill1) + expected_mask = expected_masks.get(key, expected_default) + + mask1.erase(mask2, offset) + + assertMaskEqual(self, mask1, expected_mask, msg) + + # Ensure mask2 unchanged. + self.assertEqual(mask2.count(), mask2_count, msg) + self.assertEqual(mask2.get_size(), expected_size, msg) + + def test_erase__offset(self): + """Ensure an offset mask can erase another mask.""" + mask1 = pygame.mask.Mask((65, 3)) + mask2 = pygame.mask.Mask((66, 4), fill=True) + mask2_count = mask2.count() + mask2_size = mask2.get_size() + expected_mask = pygame.Mask(mask1.get_size()) + + # Using rects to help determine the overlapping area. + rect1 = mask1.get_rect() + rect2 = mask2.get_rect() + + for offset in self.ORIGIN_OFFSETS: + msg = "offset={}".format(offset) + rect2.topleft = offset + overlap_rect = rect1.clip(rect2) + expected_mask.fill() + + # Normally erase() could be used to clear these bits, but the + # erase() method is being tested here, so a loop is used instead. + for x in range(overlap_rect.left, overlap_rect.right): + for y in range(overlap_rect.top, overlap_rect.bottom): + expected_mask.set_at((x, y), 0) + mask1.fill() # Ensure it's filled for testing each offset. + + mask1.erase(other=mask2, offset=offset) + + assertMaskEqual(self, mask1, expected_mask, msg) + + # Ensure mask2 unchanged. + self.assertEqual(mask2.count(), mask2_count, msg) + self.assertEqual(mask2.get_size(), mask2_size, msg) + + def test_erase__specific_offsets(self): + """Ensure an offset mask can erase another mask. + + Testing the specific case of: + -both masks are wider than 32 bits + -a positive offset is used + -the mask calling erase() is wider than the mask passed in + """ + mask1 = pygame.mask.Mask((65, 5)) + mask2 = pygame.mask.Mask((33, 3), fill=True) + expected_mask = pygame.Mask(mask1.get_size()) + + # Using rects to help determine the overlapping area. + rect1 = mask1.get_rect() + rect2 = mask2.get_rect() + + # This rect's corners are used to move rect2 around the inside of + # rect1. + corner_rect = rect1.inflate(-2, -2) + + for corner in ("topleft", "topright", "bottomright", "bottomleft"): + setattr(rect2, corner, getattr(corner_rect, corner)) + offset = rect2.topleft + msg = "offset={}".format(offset) + overlap_rect = rect1.clip(rect2) + expected_mask.fill() + + # Normally erase() could be used to clear these bits, but the + # erase() method is being tested here, so a loop is used instead. + for x in range(overlap_rect.left, overlap_rect.right): + for y in range(overlap_rect.top, overlap_rect.bottom): + expected_mask.set_at((x, y), 0) + mask1.fill() # Ensure it's filled for testing each offset. + + mask1.erase(mask2, Vector2(offset)) + + assertMaskEqual(self, mask1, expected_mask, msg) + + def test_erase__offset_boundary(self): + """Ensures erase handles offsets and boundaries correctly.""" + mask1 = pygame.mask.Mask((7, 11), fill=True) + mask2 = pygame.mask.Mask((3, 13), fill=True) + mask1_count = mask1.count() + mask2_count = mask2.count() + mask1_size = mask1.get_size() + mask2_size = mask2.get_size() + + # Check the 4 boundaries. + offsets = ( + (mask1_size[0], 0), # off right + (0, mask1_size[1]), # off bottom + (-mask2_size[0], 0), # off left + (0, -mask2_size[1]), + ) # off top + + for offset in offsets: + msg = "offset={}".format(offset) + + mask1.erase(mask2, offset) + + # Ensure mask1/mask2 unchanged. + self.assertEqual(mask1.count(), mask1_count, msg) + self.assertEqual(mask2.count(), mask2_count, msg) + self.assertEqual(mask1.get_size(), mask1_size, msg) + self.assertEqual(mask2.get_size(), mask2_size, msg) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_erase__bit_boundaries(self): + """Ensures erase handles masks of different sizes correctly. + + Tests masks of different sizes, including: + -masks 31 to 33 bits wide (32 bit boundaries) + -masks 63 to 65 bits wide (64 bit boundaries) + """ + for height in range(2, 4): + for width in range(2, 66): + mask_size = (width, height) + mask_count = width * height + mask1 = pygame.mask.Mask(mask_size) + mask2 = pygame.mask.Mask(mask_size, fill=True) + expected_mask = pygame.Mask(mask_size) + + # Using rects to help determine the overlapping area. + rect1 = mask1.get_rect() + rect2 = mask2.get_rect() + + # Testing masks offset from each other. + for offset in self.ORIGIN_OFFSETS: + msg = "size={}, offset={}".format(mask_size, offset) + rect2.topleft = offset + overlap_rect = rect1.clip(rect2) + expected_mask.fill() + + # Normally erase() could be used to clear these bits, but + # the erase() method is being tested here, so a loop is + # used instead. + for x in range(overlap_rect.left, overlap_rect.right): + for y in range(overlap_rect.top, overlap_rect.bottom): + expected_mask.set_at((x, y), 0) + mask1.fill() # Ensure it's filled for each test. + + mask1.erase(mask2, offset) + + assertMaskEqual(self, mask1, expected_mask, msg) + + # Ensure mask2 unchanged. + self.assertEqual(mask2.count(), mask_count, msg) + self.assertEqual(mask2.get_size(), mask_size, msg) + + def test_erase__invalid_mask_arg(self): + """Ensure erase handles invalid mask arguments correctly.""" + size = (3, 7) + offset = (0, 0) + mask = pygame.mask.Mask(size) + invalid_mask = pygame.Surface(size) + + with self.assertRaises(TypeError): + mask.erase(invalid_mask, offset) + + def test_erase__invalid_offset_arg(self): + """Ensure erase handles invalid offset arguments correctly.""" + size = (7, 5) + offset = "(0, 0)" + mask1 = pygame.mask.Mask(size) + mask2 = pygame.mask.Mask(size) + + with self.assertRaises(TypeError): + mask1.erase(mask2, offset) + + def test_count(self): + """Ensure a mask's set bits are correctly counted.""" + side = 67 + expected_size = (side, side) + expected_count = 0 + mask = pygame.mask.Mask(expected_size) + + for i in range(side): + expected_count += 1 + mask.set_at((i, i)) + + count = mask.count() + + self.assertEqual(count, expected_count) + self.assertEqual(mask.get_size(), expected_size) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_count__bit_boundaries(self): + """Ensures the set bits of different sized masks are counted correctly. + + Tests masks of different sizes, including: + -masks 31 to 33 bits wide (32 bit boundaries) + -masks 63 to 65 bits wide (64 bit boundaries) + """ + for fill in (True, False): + for height in range(1, 4): + for width in range(1, 66): + mask = pygame.mask.Mask((width, height), fill=fill) + expected_count = width * height if fill else 0 + + # Test toggling each bit. + for pos in ((x, y) for y in range(height) for x in range(width)): + if fill: + mask.set_at(pos, 0) + expected_count -= 1 + else: + mask.set_at(pos, 1) + expected_count += 1 + + count = mask.count() + + self.assertEqual( + count, + expected_count, + "fill={}, size=({}, {}), pos={}".format( + fill, width, height, pos + ), + ) + + def test_count__full_mask(self): + """Ensure a full mask's set bits are correctly counted.""" + width, height = 17, 97 + expected_size = (width, height) + expected_count = width * height + mask = pygame.mask.Mask(expected_size, fill=True) + + count = mask.count() + + self.assertEqual(count, expected_count) + self.assertEqual(mask.get_size(), expected_size) + + def test_count__empty_mask(self): + """Ensure an empty mask's set bits are correctly counted.""" + expected_count = 0 + expected_size = (13, 27) + mask = pygame.mask.Mask(expected_size) + + count = mask.count() + + self.assertEqual(count, expected_count) + self.assertEqual(mask.get_size(), expected_size) + + def test_centroid(self): + """Ensure a filled mask's centroid is correctly calculated.""" + mask = pygame.mask.Mask((5, 7), fill=True) + expected_centroid = mask.get_rect().center + + centroid = mask.centroid() + + self.assertEqual(centroid, expected_centroid) + + def test_centroid__empty_mask(self): + """Ensure an empty mask's centroid is correctly calculated.""" + expected_centroid = (0, 0) + expected_size = (101, 103) + mask = pygame.mask.Mask(expected_size) + + centroid = mask.centroid() + + self.assertEqual(centroid, expected_centroid) + self.assertEqual(mask.get_size(), expected_size) + + def test_centroid__single_row(self): + """Ensure a mask's centroid is correctly calculated + when setting points along a single row.""" + width, height = (5, 7) + mask = pygame.mask.Mask((width, height)) + + for y in range(height): + mask.clear() # Clear for each row. + + for x in range(width): + mask.set_at((x, y)) + expected_centroid = (x // 2, y) + + centroid = mask.centroid() + + self.assertEqual(centroid, expected_centroid) + + def test_centroid__two_rows(self): + """Ensure a mask's centroid is correctly calculated + when setting points along two rows.""" + width, height = (5, 7) + mask = pygame.mask.Mask((width, height)) + + # The first row is tested with each of the other rows. + for y in range(1, height): + mask.clear() # Clear for each set of rows. + + for x in range(width): + mask.set_at((x, 0)) + mask.set_at((x, y)) + expected_centroid = (x // 2, y // 2) + + centroid = mask.centroid() + + self.assertEqual(centroid, expected_centroid) + + def test_centroid__single_column(self): + """Ensure a mask's centroid is correctly calculated + when setting points along a single column.""" + width, height = (5, 7) + mask = pygame.mask.Mask((width, height)) + + for x in range(width): + mask.clear() # Clear for each column. + + for y in range(height): + mask.set_at((x, y)) + expected_centroid = (x, y // 2) + + centroid = mask.centroid() + + self.assertEqual(centroid, expected_centroid) + + def test_centroid__two_columns(self): + """Ensure a mask's centroid is correctly calculated + when setting points along two columns.""" + width, height = (5, 7) + mask = pygame.mask.Mask((width, height)) + + # The first column is tested with each of the other columns. + for x in range(1, width): + mask.clear() # Clear for each set of columns. + + for y in range(height): + mask.set_at((0, y)) + mask.set_at((x, y)) + expected_centroid = (x // 2, y // 2) + + centroid = mask.centroid() + + self.assertEqual(centroid, expected_centroid) + + def test_centroid__all_corners(self): + """Ensure a mask's centroid is correctly calculated + when its corners are set.""" + mask = pygame.mask.Mask((5, 7)) + expected_centroid = mask.get_rect().center + + for corner in corners(mask): + mask.set_at(corner) + + centroid = mask.centroid() + + self.assertEqual(centroid, expected_centroid) + + def test_centroid__two_corners(self): + """Ensure a mask's centroid is correctly calculated + when only two corners are set.""" + mask = pygame.mask.Mask((5, 7)) + mask_rect = mask.get_rect() + mask_corners = corners(mask) + + for i, corner1 in enumerate(mask_corners): + for corner2 in mask_corners[i + 1 :]: + mask.clear() # Clear for each pair of corners. + mask.set_at(corner1) + mask.set_at(corner2) + + if corner1[0] == corner2[0]: + expected_centroid = (corner1[0], abs(corner1[1] - corner2[1]) // 2) + elif corner1[1] == corner2[1]: + expected_centroid = (abs(corner1[0] - corner2[0]) // 2, corner1[1]) + else: + expected_centroid = mask_rect.center + + centroid = mask.centroid() + + self.assertEqual(centroid, expected_centroid) + + def todo_test_angle(self): + """Ensure a mask's orientation angle is correctly calculated.""" + self.fail() + + def test_angle__empty_mask(self): + """Ensure an empty mask's angle is correctly calculated.""" + expected_angle = 0.0 + expected_size = (107, 43) + mask = pygame.mask.Mask(expected_size) + + angle = mask.angle() + + self.assertIsInstance(angle, float) + self.assertAlmostEqual(angle, expected_angle) + self.assertEqual(mask.get_size(), expected_size) + + def test_drawing(self): + """Test fill, clear, invert, draw, erase""" + m = pygame.Mask((100, 100)) + self.assertEqual(m.count(), 0) + + m.fill() + self.assertEqual(m.count(), 10000) + + m2 = pygame.Mask((10, 10), fill=True) + m.erase(m2, (50, 50)) + self.assertEqual(m.count(), 9900) + + m.invert() + self.assertEqual(m.count(), 100) + + m.draw(m2, (0, 0)) + self.assertEqual(m.count(), 200) + + m.clear() + self.assertEqual(m.count(), 0) + + def test_outline(self): + """ """ + + m = pygame.Mask((20, 20)) + self.assertEqual(m.outline(), []) + + m.set_at((10, 10), 1) + self.assertEqual(m.outline(), [(10, 10)]) + + m.set_at((10, 12), 1) + self.assertEqual(m.outline(10), [(10, 10)]) + + m.set_at((11, 11), 1) + self.assertEqual( + m.outline(), [(10, 10), (11, 11), (10, 12), (11, 11), (10, 10)] + ) + self.assertEqual(m.outline(every=2), [(10, 10), (10, 12), (10, 10)]) + + # TODO: Test more corner case outlines. + + def test_convolve__size(self): + sizes = [(1, 1), (31, 31), (32, 32), (100, 100)] + for s1 in sizes: + m1 = pygame.Mask(s1) + for s2 in sizes: + m2 = pygame.Mask(s2) + o = m1.convolve(m2) + + self.assertIsInstance(o, pygame.mask.Mask) + + for i in (0, 1): + self.assertEqual( + o.get_size()[i], m1.get_size()[i] + m2.get_size()[i] - 1 + ) + + def test_convolve__point_identities(self): + """Convolving with a single point is the identity, while convolving a point with something flips it.""" + m = random_mask((100, 100)) + k = pygame.Mask((1, 1)) + k.set_at((0, 0)) + + convolve_mask = m.convolve(k) + + self.assertIsInstance(convolve_mask, pygame.mask.Mask) + assertMaskEqual(self, m, convolve_mask) + + convolve_mask = k.convolve(k.convolve(m)) + + self.assertIsInstance(convolve_mask, pygame.mask.Mask) + assertMaskEqual(self, m, convolve_mask) + + def test_convolve__with_output(self): + """checks that convolution modifies only the correct portion of the output""" + + m = random_mask((10, 10)) + k = pygame.Mask((2, 2)) + k.set_at((0, 0)) + + o = pygame.Mask((50, 50)) + test = pygame.Mask((50, 50)) + + m.convolve(k, o) + test.draw(m, (1, 1)) + + self.assertIsInstance(o, pygame.mask.Mask) + assertMaskEqual(self, o, test) + + o.clear() + test.clear() + + m.convolve(other=k, output=o, offset=Vector2(10, 10)) + test.draw(m, (11, 11)) + + self.assertIsInstance(o, pygame.mask.Mask) + assertMaskEqual(self, o, test) + + def test_convolve__out_of_range(self): + full = pygame.Mask((2, 2), fill=True) + # Tuple of points (out of range) and the expected count for each. + pts_data = (((0, 3), 0), ((0, 2), 3), ((-2, -2), 1), ((-3, -3), 0)) + + for pt, expected_count in pts_data: + convolve_mask = full.convolve(full, None, pt) + + self.assertIsInstance(convolve_mask, pygame.mask.Mask) + self.assertEqual(convolve_mask.count(), expected_count) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_convolve(self): + """Tests the definition of convolution""" + m1 = random_mask((100, 100)) + m2 = random_mask((100, 100)) + conv = m1.convolve(m2) + + self.assertIsInstance(conv, pygame.mask.Mask) + for i in range(conv.get_size()[0]): + for j in range(conv.get_size()[1]): + self.assertEqual( + conv.get_at((i, j)) == 0, m1.overlap(m2, (i - 99, j - 99)) is None + ) + + def _draw_component_pattern_box(self, mask, size, pos, inverse=False): + # Helper method to create/draw a 'box' pattern for testing. + # + # 111 + # 101 3x3 example pattern + # 111 + pattern = pygame.mask.Mask((size, size), fill=True) + pattern.set_at((size // 2, size // 2), 0) + + if inverse: + mask.erase(pattern, pos) + pattern.invert() + else: + mask.draw(pattern, pos) + + return pattern + + def _draw_component_pattern_x(self, mask, size, pos, inverse=False): + # Helper method to create/draw an 'X' pattern for testing. + # + # 101 + # 010 3x3 example pattern + # 101 + pattern = pygame.mask.Mask((size, size)) + + ymax = size - 1 + for y in range(size): + for x in range(size): + if x in [y, ymax - y]: + pattern.set_at((x, y)) + + if inverse: + mask.erase(pattern, pos) + pattern.invert() + else: + mask.draw(pattern, pos) + + return pattern + + def _draw_component_pattern_plus(self, mask, size, pos, inverse=False): + # Helper method to create/draw a '+' pattern for testing. + # + # 010 + # 111 3x3 example pattern + # 010 + pattern = pygame.mask.Mask((size, size)) + + xmid = ymid = size // 2 + for y in range(size): + for x in range(size): + if x == xmid or y == ymid: + pattern.set_at((x, y)) + + if inverse: + mask.erase(pattern, pos) + pattern.invert() + else: + mask.draw(pattern, pos) + + return pattern + + def test_connected_component(self): + """Ensure a mask's connected component is correctly calculated.""" + width, height = 41, 27 + expected_size = (width, height) + original_mask = pygame.mask.Mask(expected_size) + patterns = [] # Patterns and offsets. + + # Draw some connected patterns on the original mask. + offset = (0, 0) + pattern = self._draw_component_pattern_x(original_mask, 3, offset) + patterns.append((pattern, offset)) + + size = 4 + offset = (width - size, 0) + pattern = self._draw_component_pattern_plus(original_mask, size, offset) + patterns.append((pattern, offset)) + + # Make this one the largest connected component. + offset = (width // 2, height // 2) + pattern = self._draw_component_pattern_box(original_mask, 7, offset) + patterns.append((pattern, offset)) + + expected_pattern, expected_offset = patterns[-1] + expected_count = expected_pattern.count() + original_count = sum(p.count() for p, _ in patterns) + + mask = original_mask.connected_component() + + self.assertIsInstance(mask, pygame.mask.Mask) + self.assertEqual(mask.count(), expected_count) + self.assertEqual(mask.get_size(), expected_size) + self.assertEqual( + mask.overlap_area(expected_pattern, expected_offset), expected_count + ) + + # Ensure the original mask is unchanged. + self.assertEqual(original_mask.count(), original_count) + self.assertEqual(original_mask.get_size(), expected_size) + + for pattern, offset in patterns: + self.assertEqual( + original_mask.overlap_area(pattern, offset), pattern.count() + ) + + def test_connected_component__full_mask(self): + """Ensure a mask's connected component is correctly calculated + when the mask is full. + """ + expected_size = (23, 31) + original_mask = pygame.mask.Mask(expected_size, fill=True) + expected_count = original_mask.count() + + mask = original_mask.connected_component() + + self.assertIsInstance(mask, pygame.mask.Mask) + self.assertEqual(mask.count(), expected_count) + self.assertEqual(mask.get_size(), expected_size) + + # Ensure the original mask is unchanged. + self.assertEqual(original_mask.count(), expected_count) + self.assertEqual(original_mask.get_size(), expected_size) + + def test_connected_component__empty_mask(self): + """Ensure a mask's connected component is correctly calculated + when the mask is empty. + """ + expected_size = (37, 43) + original_mask = pygame.mask.Mask(expected_size) + original_count = original_mask.count() + expected_count = 0 + + mask = original_mask.connected_component() + + self.assertIsInstance(mask, pygame.mask.Mask) + self.assertEqual(mask.count(), expected_count) + self.assertEqual(mask.get_size(), expected_size) + + # Ensure the original mask is unchanged. + self.assertEqual(original_mask.count(), original_count) + self.assertEqual(original_mask.get_size(), expected_size) + + def test_connected_component__one_set_bit(self): + """Ensure a mask's connected component is correctly calculated + when the coordinate's bit is set with a connected component of 1 bit. + """ + width, height = 71, 67 + expected_size = (width, height) + original_mask = pygame.mask.Mask(expected_size, fill=True) + xset, yset = width // 2, height // 2 + set_pos = (xset, yset) + expected_offset = (xset - 1, yset - 1) + + # This isolates the bit at set_pos from all the other bits. + expected_pattern = self._draw_component_pattern_box( + original_mask, 3, expected_offset, inverse=True + ) + expected_count = 1 + original_count = original_mask.count() + + mask = original_mask.connected_component(set_pos) + + self.assertIsInstance(mask, pygame.mask.Mask) + self.assertEqual(mask.count(), expected_count) + self.assertEqual(mask.get_size(), expected_size) + self.assertEqual( + mask.overlap_area(expected_pattern, expected_offset), expected_count + ) + + # Ensure the original mask is unchanged. + self.assertEqual(original_mask.count(), original_count) + self.assertEqual(original_mask.get_size(), expected_size) + self.assertEqual( + original_mask.overlap_area(expected_pattern, expected_offset), + expected_count, + ) + + def test_connected_component__multi_set_bits(self): + """Ensure a mask's connected component is correctly calculated + when the coordinate's bit is set with a connected component of > 1 bit. + """ + expected_size = (113, 67) + original_mask = pygame.mask.Mask(expected_size) + p_width, p_height = 11, 13 + set_pos = xset, yset = 11, 21 + expected_offset = (xset - 1, yset - 1) + expected_pattern = pygame.mask.Mask((p_width, p_height), fill=True) + + # Make an unsymmetrical pattern. All the set bits need to be connected + # in the resulting pattern for this to work properly. + for y in range(3, p_height): + for x in range(1, p_width): + if x in [y, y - 3, p_width - 4]: + expected_pattern.set_at((x, y), 0) + + expected_count = expected_pattern.count() + original_mask.draw(expected_pattern, expected_offset) + + mask = original_mask.connected_component(set_pos) + + self.assertIsInstance(mask, pygame.mask.Mask) + self.assertEqual(mask.count(), expected_count) + self.assertEqual(mask.get_size(), expected_size) + self.assertEqual( + mask.overlap_area(expected_pattern, expected_offset), expected_count + ) + + # Ensure the original mask is unchanged. + self.assertEqual(original_mask.count(), expected_count) + self.assertEqual(original_mask.get_size(), expected_size) + self.assertEqual( + original_mask.overlap_area(expected_pattern, expected_offset), + expected_count, + ) + + def test_connected_component__unset_bit(self): + """Ensure a mask's connected component is correctly calculated + when the coordinate's bit is unset. + """ + width, height = 109, 101 + expected_size = (width, height) + original_mask = pygame.mask.Mask(expected_size, fill=True) + unset_pos = (width // 2, height // 2) + original_mask.set_at(unset_pos, 0) + original_count = original_mask.count() + expected_count = 0 + + mask = original_mask.connected_component(unset_pos) + + self.assertIsInstance(mask, pygame.mask.Mask) + self.assertEqual(mask.count(), expected_count) + self.assertEqual(mask.get_size(), expected_size) + + # Ensure the original mask is unchanged. + self.assertEqual(original_mask.count(), original_count) + self.assertEqual(original_mask.get_size(), expected_size) + self.assertEqual(original_mask.get_at(unset_pos), 0) + + def test_connected_component__out_of_bounds(self): + """Ensure connected_component() checks bounds.""" + width, height = 19, 11 + original_size = (width, height) + original_mask = pygame.mask.Mask(original_size, fill=True) + original_count = original_mask.count() + + for pos in ((0, -1), (-1, 0), (0, height + 1), (width + 1, 0)): + with self.assertRaises(IndexError): + mask = original_mask.connected_component(pos) + + # Ensure the original mask is unchanged. + self.assertEqual(original_mask.count(), original_count) + self.assertEqual(original_mask.get_size(), original_size) + + def test_connected_components(self): + """ """ + m = pygame.Mask((10, 10)) + + self.assertListEqual(m.connected_components(), []) + + comp = m.connected_component() + + self.assertEqual(m.count(), comp.count()) + + m.set_at((0, 0), 1) + m.set_at((1, 1), 1) + comp = m.connected_component() + comps = m.connected_components() + comps1 = m.connected_components(1) + comps2 = m.connected_components(2) + comps3 = m.connected_components(3) + + self.assertEqual(comp.count(), comps[0].count()) + self.assertEqual(comps1[0].count(), 2) + self.assertEqual(comps2[0].count(), 2) + self.assertListEqual(comps3, []) + + m.set_at((9, 9), 1) + comp = m.connected_component() + comp1 = m.connected_component((1, 1)) + comp2 = m.connected_component((2, 2)) + comps = m.connected_components() + comps1 = m.connected_components(1) + comps2 = m.connected_components(minimum=2) + comps3 = m.connected_components(3) + + self.assertEqual(comp.count(), 2) + self.assertEqual(comp1.count(), 2) + self.assertEqual(comp2.count(), 0) + self.assertEqual(len(comps), 2) + self.assertEqual(len(comps1), 2) + self.assertEqual(len(comps2), 1) + self.assertEqual(len(comps3), 0) + + for mask in comps: + self.assertIsInstance(mask, pygame.mask.Mask) + + def test_connected_components__negative_min_with_empty_mask(self): + """Ensures connected_components() properly handles negative min values + when the mask is empty. + + Negative and zero values for the min parameter (minimum number of bits + per connected component) equate to setting it to one. + """ + expected_comps = [] + mask_count = 0 + mask_size = (65, 13) + mask = pygame.mask.Mask(mask_size) + + connected_comps = mask.connected_components(-1) + + self.assertListEqual(connected_comps, expected_comps) + + # Ensure the original mask is unchanged. + self.assertEqual(mask.count(), mask_count) + self.assertEqual(mask.get_size(), mask_size) + + def test_connected_components__negative_min_with_full_mask(self): + """Ensures connected_components() properly handles negative min values + when the mask is full. + + Negative and zero values for the min parameter (minimum number of bits + per connected component) equate to setting it to one. + """ + mask_size = (64, 11) + mask = pygame.mask.Mask(mask_size, fill=True) + mask_count = mask.count() + expected_len = 1 + + connected_comps = mask.connected_components(-2) + + self.assertEqual(len(connected_comps), expected_len) + assertMaskEqual(self, connected_comps[0], mask) + + # Ensure the original mask is unchanged. + self.assertEqual(mask.count(), mask_count) + self.assertEqual(mask.get_size(), mask_size) + + def test_connected_components__negative_min_with_some_bits_set(self): + """Ensures connected_components() properly handles negative min values + when the mask has some bits set. + + Negative and zero values for the min parameter (minimum number of bits + per connected component) equate to setting it to one. + """ + mask_size = (64, 12) + mask = pygame.mask.Mask(mask_size) + expected_comps = {} + + # Set the corners and the center positions. A new expected component + # mask is created for each point. + for corner in corners(mask): + mask.set_at(corner) + + new_mask = pygame.mask.Mask(mask_size) + new_mask.set_at(corner) + expected_comps[corner] = new_mask + + center = (mask_size[0] // 2, mask_size[1] // 2) + mask.set_at(center) + + new_mask = pygame.mask.Mask(mask_size) + new_mask.set_at(center) + expected_comps[center] = new_mask + mask_count = mask.count() + + connected_comps = mask.connected_components(-3) + + self.assertEqual(len(connected_comps), len(expected_comps)) + + for comp in connected_comps: + # Since the masks in the connected component list can be in any + # order, loop the expected components to find its match. + found = False + + for pt in tuple(expected_comps.keys()): + if comp.get_at(pt): + found = True + assertMaskEqual(self, comp, expected_comps[pt]) + del expected_comps[pt] # Entry removed so it isn't reused. + break + + self.assertTrue(found, "missing component for pt={}".format(pt)) + + # Ensure the original mask is unchanged. + self.assertEqual(mask.count(), mask_count) + self.assertEqual(mask.get_size(), mask_size) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_get_bounding_rects(self): + """Ensures get_bounding_rects works correctly.""" + # Create masks with different set point groups. Each group of + # connected set points will be contained in its own bounding rect. + # Diagonal points are considered connected. + mask_data = [] # [((size), ((rect1_pts), ...)), ...] + + # Mask 1: + # |0123456789 + # -+---------- + # 0|1100000000 + # 1|1000000000 + # 2|0000000000 + # 3|1001000000 + # 4|0000000000 + # 5|0000000000 + # 6|0000000000 + # 7|0000000000 + # 8|0000000000 + # 9|0000000000 + mask_data.append( + ( + (10, 10), # size + # Points to set for the 3 bounding rects. + (((0, 0), (1, 0), (0, 1)), ((0, 3),), ((3, 3),)), # rect1 # rect2 + ) + ) # rect3 + + # Mask 2: + # |0123 + # -+---- + # 0|1100 + # 1|1111 + mask_data.append( + ( + (4, 2), # size + # Points to set for the 1 bounding rect. + (((0, 0), (1, 0), (0, 1), (1, 1), (2, 1), (3, 1)),), + ) + ) + + # Mask 3: + # |01234 + # -+----- + # 0|00100 + # 1|01110 + # 2|00100 + mask_data.append( + ( + (5, 3), # size + # Points to set for the 1 bounding rect. + (((2, 0), (1, 1), (2, 1), (3, 1), (2, 2)),), + ) + ) + + # Mask 4: + # |01234 + # -+----- + # 0|00010 + # 1|00100 + # 2|01000 + mask_data.append( + ( + (5, 3), # size + # Points to set for the 1 bounding rect. + (((3, 0), (2, 1), (1, 2)),), + ) + ) + + # Mask 5: + # |01234 + # -+----- + # 0|00011 + # 1|11111 + mask_data.append( + ( + (5, 2), # size + # Points to set for the 1 bounding rect. + (((3, 0), (4, 0), (0, 1), (1, 1), (2, 1), (3, 1)),), + ) + ) + + # Mask 6: + # |01234 + # -+----- + # 0|10001 + # 1|00100 + # 2|10001 + mask_data.append( + ( + (5, 3), # size + # Points to set for the 5 bounding rects. + ( + ((0, 0),), # rect1 + ((4, 0),), # rect2 + ((2, 1),), # rect3 + ((0, 2),), # rect4 + ((4, 2),), + ), + ) + ) # rect5 + + for size, rect_point_tuples in mask_data: + rects = [] + mask = pygame.Mask(size) + + for rect_points in rect_point_tuples: + rects.append(create_bounding_rect(rect_points)) + for pt in rect_points: + mask.set_at(pt) + + expected_rects = sorted(rects, key=tuple) + + rects = mask.get_bounding_rects() + + self.assertListEqual( + sorted(mask.get_bounding_rects(), key=tuple), + expected_rects, + "size={}".format(size), + ) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_to_surface(self): + """Ensures empty and full masks can be drawn onto surfaces.""" + expected_ref_count = 3 + size = (33, 65) + surface = pygame.Surface(size, SRCALPHA, 32) + surface_color = pygame.Color("red") + test_fills = ((pygame.Color("white"), True), (pygame.Color("black"), False)) + + for expected_color, fill in test_fills: + surface.fill(surface_color) + mask = pygame.mask.Mask(size, fill=fill) + + to_surface = mask.to_surface(surface) + + self.assertIs(to_surface, surface) + if not IS_PYPY: + self.assertEqual(sys.getrefcount(to_surface), expected_ref_count) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__create_surface(self): + """Ensures empty and full masks can be drawn onto a created surface.""" + expected_ref_count = 2 + expected_flag = SRCALPHA + expected_depth = 32 + size = (33, 65) + test_fills = ((pygame.Color("white"), True), (pygame.Color("black"), False)) + + for expected_color, fill in test_fills: + mask = pygame.mask.Mask(size, fill=fill) + + for use_arg in (True, False): + if use_arg: + to_surface = mask.to_surface(None) + else: + to_surface = mask.to_surface() + + self.assertIsInstance(to_surface, pygame.Surface) + if not IS_PYPY: + self.assertEqual(sys.getrefcount(to_surface), expected_ref_count) + self.assertTrue(to_surface.get_flags() & expected_flag) + self.assertEqual(to_surface.get_bitsize(), expected_depth) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__surface_param(self): + """Ensures to_surface accepts a surface arg/kwarg.""" + expected_ref_count = 4 + expected_color = pygame.Color("white") + surface_color = pygame.Color("red") + size = (5, 3) + mask = pygame.mask.Mask(size, fill=True) + surface = pygame.Surface(size) + kwargs = {"surface": surface} + + for use_kwargs in (True, False): + surface.fill(surface_color) + + if use_kwargs: + to_surface = mask.to_surface(**kwargs) + else: + to_surface = mask.to_surface(kwargs["surface"]) + + self.assertIs(to_surface, surface) + if not IS_PYPY: + self.assertEqual(sys.getrefcount(to_surface), expected_ref_count) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__setsurface_param(self): + """Ensures to_surface accepts a setsurface arg/kwarg.""" + expected_ref_count = 2 + expected_flag = SRCALPHA + expected_depth = 32 + expected_color = pygame.Color("red") + size = (5, 3) + mask = pygame.mask.Mask(size, fill=True) + setsurface = pygame.Surface(size, expected_flag, expected_depth) + setsurface.fill(expected_color) + kwargs = {"setsurface": setsurface} + + for use_kwargs in (True, False): + if use_kwargs: + to_surface = mask.to_surface(**kwargs) + else: + to_surface = mask.to_surface(None, kwargs["setsurface"]) + + self.assertIsInstance(to_surface, pygame.Surface) + + if not IS_PYPY: + self.assertEqual(sys.getrefcount(to_surface), expected_ref_count) + self.assertTrue(to_surface.get_flags() & expected_flag) + self.assertEqual(to_surface.get_bitsize(), expected_depth) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__unsetsurface_param(self): + """Ensures to_surface accepts a unsetsurface arg/kwarg.""" + expected_ref_count = 2 + expected_flag = SRCALPHA + expected_depth = 32 + expected_color = pygame.Color("red") + size = (5, 3) + mask = pygame.mask.Mask(size) + unsetsurface = pygame.Surface(size, expected_flag, expected_depth) + unsetsurface.fill(expected_color) + kwargs = {"unsetsurface": unsetsurface} + + for use_kwargs in (True, False): + if use_kwargs: + to_surface = mask.to_surface(**kwargs) + else: + to_surface = mask.to_surface(None, None, kwargs["unsetsurface"]) + + self.assertIsInstance(to_surface, pygame.Surface) + if not IS_PYPY: + self.assertEqual(sys.getrefcount(to_surface), expected_ref_count) + self.assertTrue(to_surface.get_flags() & expected_flag) + self.assertEqual(to_surface.get_bitsize(), expected_depth) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__setcolor_param(self): + """Ensures to_surface accepts a setcolor arg/kwarg.""" + expected_ref_count = 2 + expected_flag = SRCALPHA + expected_depth = 32 + expected_color = pygame.Color("red") + size = (5, 3) + mask = pygame.mask.Mask(size, fill=True) + kwargs = {"setcolor": expected_color} + + for use_kwargs in (True, False): + if use_kwargs: + to_surface = mask.to_surface(**kwargs) + else: + to_surface = mask.to_surface(None, None, None, kwargs["setcolor"]) + + self.assertIsInstance(to_surface, pygame.Surface) + if not IS_PYPY: + self.assertEqual(sys.getrefcount(to_surface), expected_ref_count) + self.assertTrue(to_surface.get_flags() & expected_flag) + self.assertEqual(to_surface.get_bitsize(), expected_depth) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__setcolor_default(self): + """Ensures the default setcolor is correct.""" + expected_color = pygame.Color("white") + size = (3, 7) + mask = pygame.mask.Mask(size, fill=True) + + to_surface = mask.to_surface( + surface=None, setsurface=None, unsetsurface=None, unsetcolor=None + ) + + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__unsetcolor_param(self): + """Ensures to_surface accepts a unsetcolor arg/kwarg.""" + expected_ref_count = 2 + expected_flag = SRCALPHA + expected_depth = 32 + expected_color = pygame.Color("red") + size = (5, 3) + mask = pygame.mask.Mask(size) + kwargs = {"unsetcolor": expected_color} + + for use_kwargs in (True, False): + if use_kwargs: + to_surface = mask.to_surface(**kwargs) + else: + to_surface = mask.to_surface( + None, None, None, None, kwargs["unsetcolor"] + ) + + self.assertIsInstance(to_surface, pygame.Surface) + if not IS_PYPY: + self.assertEqual(sys.getrefcount(to_surface), expected_ref_count) + self.assertTrue(to_surface.get_flags() & expected_flag) + self.assertEqual(to_surface.get_bitsize(), expected_depth) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__unsetcolor_default(self): + """Ensures the default unsetcolor is correct.""" + expected_color = pygame.Color("black") + size = (3, 7) + mask = pygame.mask.Mask(size) + + to_surface = mask.to_surface( + surface=None, setsurface=None, unsetsurface=None, setcolor=None + ) + + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__dest_param(self): + """Ensures to_surface accepts a dest arg/kwarg.""" + expected_ref_count = 2 + expected_flag = SRCALPHA + expected_depth = 32 + default_surface_color = (0, 0, 0, 0) + default_unsetcolor = pygame.Color("black") + dest = (0, 0) + size = (5, 3) + mask = pygame.mask.Mask(size) + kwargs = {"dest": dest} + + for use_kwargs in (True, False): + if use_kwargs: + expected_color = default_unsetcolor + + to_surface = mask.to_surface(**kwargs) + else: + expected_color = default_surface_color + + to_surface = mask.to_surface( + None, None, None, None, None, kwargs["dest"] + ) + + self.assertIsInstance(to_surface, pygame.Surface) + if not IS_PYPY: + self.assertEqual(sys.getrefcount(to_surface), expected_ref_count) + self.assertTrue(to_surface.get_flags() & expected_flag) + self.assertEqual(to_surface.get_bitsize(), expected_depth) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__dest_default(self): + """Ensures the default dest is correct.""" + expected_color = pygame.Color("white") + surface_color = pygame.Color("red") + + mask_size = (3, 2) + mask = pygame.mask.Mask(mask_size, fill=True) + mask_rect = mask.get_rect() + + # Make the surface bigger than the mask. + surf_size = (mask_size[0] + 2, mask_size[1] + 1) + surface = pygame.Surface(surf_size, SRCALPHA, 32) + surface.fill(surface_color) + + to_surface = mask.to_surface( + surface, setsurface=None, unsetsurface=None, unsetcolor=None + ) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), surf_size) + assertSurfaceFilled(self, to_surface, expected_color, mask_rect) + assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, mask_rect) + + @unittest.expectedFailure + def test_to_surface__area_param(self): + """Ensures to_surface accepts an area arg/kwarg.""" + expected_ref_count = 2 + expected_flag = SRCALPHA + expected_depth = 32 + default_surface_color = (0, 0, 0, 0) + default_unsetcolor = pygame.Color("black") + size = (5, 3) + mask = pygame.mask.Mask(size) + kwargs = {"area": mask.get_rect()} + + for use_kwargs in (True, False): + if use_kwargs: + expected_color = default_unsetcolor + + to_surface = mask.to_surface(**kwargs) + else: + expected_color = default_surface_color + + to_surface = mask.to_surface( + None, None, None, None, None, (0, 0), kwargs["area"] + ) + + self.assertIsInstance(to_surface, pygame.Surface) + if not IS_PYPY: + self.assertEqual(sys.getrefcount(to_surface), expected_ref_count) + self.assertTrue(to_surface.get_flags() & expected_flag) + self.assertEqual(to_surface.get_bitsize(), expected_depth) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__area_default(self): + """Ensures the default area is correct.""" + expected_color = pygame.Color("white") + surface_color = pygame.Color("red") + + mask_size = (3, 2) + mask = pygame.mask.Mask(mask_size, fill=True) + mask_rect = mask.get_rect() + + # Make the surface bigger than the mask. The default area is the full + # area of the mask. + surf_size = (mask_size[0] + 2, mask_size[1] + 1) + surface = pygame.Surface(surf_size, SRCALPHA, 32) + surface.fill(surface_color) + + to_surface = mask.to_surface( + surface, setsurface=None, unsetsurface=None, unsetcolor=None + ) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), surf_size) + assertSurfaceFilled(self, to_surface, expected_color, mask_rect) + assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, mask_rect) + + def test_to_surface__kwargs(self): + """Ensures to_surface accepts the correct kwargs.""" + expected_color = pygame.Color("white") + size = (5, 3) + mask = pygame.mask.Mask(size, fill=True) + surface = pygame.Surface(size) + surface_color = pygame.Color("red") + setsurface = surface.copy() + setsurface.fill(expected_color) + + test_data = ( + (None, None), # None entry allows loop to test all kwargs on first pass. + ("dest", (0, 0)), + ("unsetcolor", pygame.Color("yellow")), + ("setcolor", expected_color), + ("unsetsurface", surface.copy()), + ("setsurface", setsurface), + ("surface", surface), + ) + + kwargs = dict(test_data) + + for name, _ in test_data: + kwargs.pop(name) + surface.fill(surface_color) # Clear for each test. + + to_surface = mask.to_surface(**kwargs) + + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__kwargs_create_surface(self): + """Ensures to_surface accepts the correct kwargs + when creating a surface. + """ + expected_color = pygame.Color("black") + size = (5, 3) + mask = pygame.mask.Mask(size) + setsurface = pygame.Surface(size, SRCALPHA, 32) + setsurface_color = pygame.Color("red") + setsurface.fill(setsurface_color) + unsetsurface = setsurface.copy() + unsetsurface.fill(expected_color) + + test_data = ( + (None, None), # None entry allows loop to test all kwargs on first pass. + ("dest", (0, 0)), + ("unsetcolor", expected_color), + ("setcolor", pygame.Color("yellow")), + ("unsetsurface", unsetsurface), + ("setsurface", setsurface), + ("surface", None), + ) + kwargs = dict(test_data) + + for name, _ in test_data: + kwargs.pop(name) + + to_surface = mask.to_surface(**kwargs) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__kwargs_order_independent(self): + """Ensures to_surface kwargs are not order dependent.""" + expected_color = pygame.Color("blue") + size = (3, 2) + mask = pygame.mask.Mask(size, fill=True) + surface = pygame.Surface(size) + + to_surface = mask.to_surface( + dest=(0, 0), + setcolor=expected_color, + unsetcolor=None, + surface=surface, + unsetsurface=pygame.Surface(size), + setsurface=None, + ) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__args_invalid_types(self): + """Ensures to_surface detects invalid kwarg types.""" + size = (3, 2) + mask = pygame.mask.Mask(size, fill=True) + invalid_surf = pygame.Color("green") + invalid_color = pygame.Surface(size) + + with self.assertRaises(TypeError): + # Invalid dest. + mask.to_surface(None, None, None, None, None, (0,)) + + with self.assertRaises(TypeError): + # Invalid unsetcolor. + mask.to_surface(None, None, None, None, invalid_color) + + with self.assertRaises(TypeError): + # Invalid setcolor. + mask.to_surface(None, None, None, invalid_color, None) + + with self.assertRaises(TypeError): + # Invalid unsetsurface. + mask.to_surface(None, None, invalid_surf, None, None) + + with self.assertRaises(TypeError): + # Invalid setsurface. + mask.to_surface(None, invalid_surf, None, None, None) + + with self.assertRaises(TypeError): + # Invalid surface. + mask.to_surface(invalid_surf, None, None, None, None) + + def test_to_surface__kwargs_invalid_types(self): + """Ensures to_surface detects invalid kwarg types.""" + size = (3, 2) + mask = pygame.mask.Mask(size) + + valid_kwargs = { + "surface": pygame.Surface(size), + "setsurface": pygame.Surface(size), + "unsetsurface": pygame.Surface(size), + "setcolor": pygame.Color("green"), + "unsetcolor": pygame.Color("green"), + "dest": (0, 0), + } + + invalid_kwargs = { + "surface": (1, 2, 3, 4), + "setsurface": pygame.Color("green"), + "unsetsurface": ((1, 2), (2, 1)), + "setcolor": pygame.Mask((1, 2)), + "unsetcolor": pygame.Surface((2, 2)), + "dest": (0, 0, 0), + } + + kwarg_order = ( + "surface", + "setsurface", + "unsetsurface", + "setcolor", + "unsetcolor", + "dest", + ) + + for kwarg in kwarg_order: + kwargs = dict(valid_kwargs) + kwargs[kwarg] = invalid_kwargs[kwarg] + + with self.assertRaises(TypeError): + mask.to_surface(**kwargs) + + def test_to_surface__kwargs_invalid_name(self): + """Ensures to_surface detects invalid kwarg names.""" + mask = pygame.mask.Mask((3, 2)) + kwargs = {"setcolour": pygame.Color("red")} + + with self.assertRaises(TypeError): + mask.to_surface(**kwargs) + + def test_to_surface__args_and_kwargs(self): + """Ensures to_surface accepts a combination of args/kwargs""" + size = (5, 3) + + surface_color = pygame.Color("red") + setsurface_color = pygame.Color("yellow") + unsetsurface_color = pygame.Color("blue") + setcolor = pygame.Color("green") + unsetcolor = pygame.Color("cyan") + + surface = pygame.Surface(size, SRCALPHA, 32) + setsurface = surface.copy() + unsetsurface = surface.copy() + + setsurface.fill(setsurface_color) + unsetsurface.fill(unsetsurface_color) + + mask = pygame.mask.Mask(size, fill=True) + expected_color = setsurface_color + + test_data = ( + (None, None), # None entry allows loop to test all kwargs on first pass. + ("surface", surface), + ("setsurface", setsurface), + ("unsetsurface", unsetsurface), + ("setcolor", setcolor), + ("unsetcolor", unsetcolor), + ("dest", (0, 0)), + ) + + args = [] + kwargs = dict(test_data) + + # Loop gradually moves the kwargs to args. + for name, value in test_data: + if name is not None: + args.append(value) + kwargs.pop(name) + + surface.fill(surface_color) + + to_surface = mask.to_surface(*args, **kwargs) + + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__valid_setcolor_formats(self): + """Ensures to_surface handles valid setcolor formats correctly.""" + size = (5, 3) + mask = pygame.mask.Mask(size, fill=True) + surface = pygame.Surface(size, SRCALPHA, 32) + expected_color = pygame.Color("green") + test_colors = ( + (0, 255, 0), + (0, 255, 0, 255), + surface.map_rgb(expected_color), + expected_color, + "green", + "#00FF00FF", + "0x00FF00FF", + ) + + for setcolor in test_colors: + to_surface = mask.to_surface(setcolor=setcolor) + + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__valid_unsetcolor_formats(self): + """Ensures to_surface handles valid unsetcolor formats correctly.""" + size = (5, 3) + mask = pygame.mask.Mask(size) + surface = pygame.Surface(size, SRCALPHA, 32) + expected_color = pygame.Color("green") + test_colors = ( + (0, 255, 0), + (0, 255, 0, 255), + surface.map_rgb(expected_color), + expected_color, + "green", + "#00FF00FF", + "0x00FF00FF", + ) + + for unsetcolor in test_colors: + to_surface = mask.to_surface(unsetcolor=unsetcolor) + + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__invalid_setcolor_formats(self): + """Ensures to_surface handles invalid setcolor formats correctly.""" + mask = pygame.mask.Mask((5, 3)) + + for setcolor in ("green color", "#00FF00FF0", "0x00FF00FF0", (1, 2)): + with self.assertRaises(ValueError): + mask.to_surface(setcolor=setcolor) + + for setcolor in (pygame.Surface((1, 2)), pygame.Mask((2, 1)), 1.1): + with self.assertRaises(TypeError): + mask.to_surface(setcolor=setcolor) + + def test_to_surface__invalid_unsetcolor_formats(self): + """Ensures to_surface handles invalid unsetcolor formats correctly.""" + mask = pygame.mask.Mask((5, 3)) + + for unsetcolor in ("green color", "#00FF00FF0", "0x00FF00FF0", (1, 2)): + with self.assertRaises(ValueError): + mask.to_surface(unsetcolor=unsetcolor) + + for unsetcolor in (pygame.Surface((1, 2)), pygame.Mask((2, 1)), 1.1): + with self.assertRaises(TypeError): + mask.to_surface(unsetcolor=unsetcolor) + + def test_to_surface__valid_dest_formats(self): + """Ensures to_surface handles valid dest formats correctly.""" + expected_color = pygame.Color("white") + mask = pygame.mask.Mask((3, 5), fill=True) + dests = ( + (0, 0), + [0, 0], + Vector2(0, 0), + (0, 0, 100, 100), + pygame.Rect((0, 0), (10, 10)), + ) + + for dest in dests: + to_surface = mask.to_surface(dest=dest) + + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__invalid_dest_formats(self): + """Ensures to_surface handles invalid dest formats correctly.""" + mask = pygame.mask.Mask((3, 5)) + invalid_dests = ( + (0,), # Incorrect size. + (0, 0, 0), # Incorrect size. + set([0, 1]), # Incorrect type. + {0: 1}, # Incorrect type. + Rect, + ) # Incorrect type. + + for dest in invalid_dests: + with self.assertRaises(TypeError): + mask.to_surface(dest=dest) + + def test_to_surface__negative_sized_dest_rect(self): + """Ensures to_surface correctly handles negative sized dest rects.""" + expected_color = pygame.Color("white") + mask = pygame.mask.Mask((3, 5), fill=True) + dests = ( + pygame.Rect((0, 0), (10, -10)), + pygame.Rect((0, 0), (-10, 10)), + pygame.Rect((0, 0), (-10, -10)), + ) + + for dest in dests: + to_surface = mask.to_surface(dest=dest) + + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__zero_sized_dest_rect(self): + """Ensures to_surface correctly handles zero sized dest rects.""" + expected_color = pygame.Color("white") + mask = pygame.mask.Mask((3, 5), fill=True) + dests = ( + pygame.Rect((0, 0), (0, 10)), + pygame.Rect((0, 0), (10, 0)), + pygame.Rect((0, 0), (0, 0)), + ) + + for dest in dests: + to_surface = mask.to_surface(dest=dest) + + assertSurfaceFilled(self, to_surface, expected_color) + + @unittest.expectedFailure + def test_to_surface__valid_area_formats(self): + """Ensures to_surface handles valid area formats correctly.""" + size = (3, 5) + surface_color = pygame.Color("red") + expected_color = pygame.Color("white") + surface = pygame.Surface(size) + mask = pygame.mask.Mask(size, fill=True) + area_pos = (0, 0) + area_size = (2, 1) + areas = ( + (area_pos[0], area_pos[1], area_size[0], area_size[1]), + (area_pos, area_size), + (area_pos, list(area_size)), + (list(area_pos), area_size), + (list(area_pos), list(area_size)), + [area_pos[0], area_pos[1], area_size[0], area_size[1]], + [area_pos, area_size], + [area_pos, list(area_size)], + [list(area_pos), area_size], + [list(area_pos), list(area_size)], + pygame.Rect(area_pos, area_size), + ) + + for area in areas: + surface.fill(surface_color) + area_rect = pygame.Rect(area) + + to_surface = mask.to_surface(surface, area=area) + + assertSurfaceFilled(self, to_surface, expected_color, area_rect) + assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, area_rect) + + @unittest.expectedFailure + def test_to_surface__invalid_area_formats(self): + """Ensures to_surface handles invalid area formats correctly.""" + mask = pygame.mask.Mask((3, 5)) + invalid_areas = ( + (0,), # Incorrect size. + (0, 0), # Incorrect size. + (0, 0, 1), # Incorrect size. + ((0, 0), (1,)), # Incorrect size. + ((0,), (1, 1)), # Incorrect size. + set([0, 1, 2, 3]), # Incorrect type. + {0: 1, 2: 3}, # Incorrect type. + Rect, # Incorrect type. + ) + + for area in invalid_areas: + with self.assertRaisesRegex(TypeError, "invalid area argument"): + unused_to_surface = mask.to_surface(area=area) + + @unittest.expectedFailure + def test_to_surface__negative_sized_area_rect(self): + """Ensures to_surface correctly handles negative sized area rects.""" + size = (3, 5) + surface_color = pygame.Color("red") + expected_color = pygame.Color("white") + surface = pygame.Surface(size) + mask = pygame.mask.Mask(size) + mask.set_at((0, 0)) + + # These rects should cause position (0, 0) of the mask to be drawn. + areas = ( + pygame.Rect((0, 1), (1, -1)), + pygame.Rect((1, 0), (-1, 1)), + pygame.Rect((1, 1), (-1, -1)), + ) + + for area in areas: + surface.fill(surface_color) + + to_surface = mask.to_surface(surface, area=area) + + assertSurfaceFilled(self, to_surface, expected_color, area) + assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, area) + + @unittest.expectedFailure + def test_to_surface__zero_sized_area_rect(self): + """Ensures to_surface correctly handles zero sized area rects.""" + size = (3, 5) + expected_color = pygame.Color("red") + surface = pygame.Surface(size) + mask = pygame.mask.Mask(size, fill=True) + + # Zero sized rect areas should cause none of the mask to be drawn. + areas = ( + pygame.Rect((0, 0), (0, 1)), + pygame.Rect((0, 0), (1, 0)), + pygame.Rect((0, 0), (0, 0)), + ) + + for area in areas: + surface.fill(expected_color) + + to_surface = mask.to_surface(surface, area=area) + + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__default_surface_with_param_combinations(self): + """Ensures to_surface works with a default surface value + and combinations of other parameters. + + This tests many different parameter combinations with full and empty + masks. + """ + expected_ref_count = 2 + expected_flag = SRCALPHA + expected_depth = 32 + size = (5, 3) + dest = (0, 0) + + default_surface_color = (0, 0, 0, 0) + setsurface_color = pygame.Color("yellow") + unsetsurface_color = pygame.Color("blue") + setcolor = pygame.Color("green") + unsetcolor = pygame.Color("cyan") + + setsurface = pygame.Surface(size, expected_flag, expected_depth) + unsetsurface = setsurface.copy() + + setsurface.fill(setsurface_color) + unsetsurface.fill(unsetsurface_color) + + kwargs = { + "setsurface": None, + "unsetsurface": None, + "setcolor": None, + "unsetcolor": None, + "dest": None, + } + + for fill in (True, False): + mask = pygame.mask.Mask(size, fill=fill) + + # Test different combinations of parameters. + for setsurface_param in (setsurface, None): + kwargs["setsurface"] = setsurface_param + + for unsetsurface_param in (unsetsurface, None): + kwargs["unsetsurface"] = unsetsurface_param + + for setcolor_param in (setcolor, None): + kwargs["setcolor"] = setcolor_param + + for unsetcolor_param in (unsetcolor, None): + kwargs["unsetcolor"] = unsetcolor_param + + for dest_param in (dest, None): + if dest_param is None: + kwargs.pop("dest", None) + else: + kwargs["dest"] = dest_param + + if fill: + if setsurface_param is not None: + expected_color = setsurface_color + elif setcolor_param is not None: + expected_color = setcolor + else: + expected_color = default_surface_color + else: + if unsetsurface_param is not None: + expected_color = unsetsurface_color + elif unsetcolor_param is not None: + expected_color = unsetcolor + else: + expected_color = default_surface_color + + to_surface = mask.to_surface(**kwargs) + + self.assertIsInstance(to_surface, pygame.Surface) + if not IS_PYPY: + self.assertEqual( + sys.getrefcount(to_surface), expected_ref_count + ) + self.assertTrue(to_surface.get_flags() & expected_flag) + self.assertEqual( + to_surface.get_bitsize(), expected_depth + ) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__surface_with_param_combinations(self): + """Ensures to_surface works with a surface value + and combinations of other parameters. + + This tests many different parameter combinations with full and empty + masks. + """ + expected_ref_count = 4 + expected_flag = SRCALPHA + expected_depth = 32 + size = (5, 3) + dest = (0, 0) + + surface_color = pygame.Color("red") + setsurface_color = pygame.Color("yellow") + unsetsurface_color = pygame.Color("blue") + setcolor = pygame.Color("green") + unsetcolor = pygame.Color("cyan") + + surface = pygame.Surface(size, expected_flag, expected_depth) + setsurface = surface.copy() + unsetsurface = surface.copy() + + setsurface.fill(setsurface_color) + unsetsurface.fill(unsetsurface_color) + + kwargs = { + "surface": surface, + "setsurface": None, + "unsetsurface": None, + "setcolor": None, + "unsetcolor": None, + "dest": None, + } + + for fill in (True, False): + mask = pygame.mask.Mask(size, fill=fill) + + # Test different combinations of parameters. + for setsurface_param in (setsurface, None): + kwargs["setsurface"] = setsurface_param + + for unsetsurface_param in (unsetsurface, None): + kwargs["unsetsurface"] = unsetsurface_param + + for setcolor_param in (setcolor, None): + kwargs["setcolor"] = setcolor_param + + for unsetcolor_param in (unsetcolor, None): + kwargs["unsetcolor"] = unsetcolor_param + surface.fill(surface_color) # Clear for each test. + + for dest_param in (dest, None): + if dest_param is None: + kwargs.pop("dest", None) + else: + kwargs["dest"] = dest_param + + if fill: + if setsurface_param is not None: + expected_color = setsurface_color + elif setcolor_param is not None: + expected_color = setcolor + else: + expected_color = surface_color + else: + if unsetsurface_param is not None: + expected_color = unsetsurface_color + elif unsetcolor_param is not None: + expected_color = unsetcolor + else: + expected_color = surface_color + + to_surface = mask.to_surface(**kwargs) + + self.assertIs(to_surface, surface) + if not IS_PYPY: + self.assertEqual( + sys.getrefcount(to_surface), expected_ref_count + ) + self.assertTrue(to_surface.get_flags() & expected_flag) + self.assertEqual( + to_surface.get_bitsize(), expected_depth + ) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__set_and_unset_bits(self): + """Ensures that to_surface works correctly with with set/unset bits + when using the defaults for setcolor and unsetcolor. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + width, height = size = (10, 20) + mask = pygame.mask.Mask(size) + mask_rect = mask.get_rect() + + surface = pygame.Surface(size) + surface_color = pygame.Color("red") + + # Create a checkerboard pattern of set/unset bits. + for pos in ((x, y) for x in range(width) for y in range(x & 1, height, 2)): + mask.set_at(pos) + + # Test different dest values. + for dest in self.ORIGIN_OFFSETS: + mask_rect.topleft = dest + surface.fill(surface_color) + + to_surface = mask.to_surface(surface, dest=dest) + + to_surface.lock() # Lock for possible speed up. + for pos in ((x, y) for x in range(width) for y in range(height)): + mask_pos = (pos[0] - dest[0], pos[1] - dest[1]) + if not mask_rect.collidepoint(pos): + expected_color = surface_color + elif mask.get_at(mask_pos): + expected_color = default_setcolor + else: + expected_color = default_unsetcolor + + self.assertEqual(to_surface.get_at(pos), expected_color, (dest, pos)) + to_surface.unlock() + + def test_to_surface__set_and_unset_bits_with_setsurface_unsetsurface(self): + """Ensures that to_surface works correctly with with set/unset bits + when using setsurface and unsetsurface. + """ + width, height = size = (10, 20) + mask = pygame.mask.Mask(size) + mask_rect = mask.get_rect() + + surface = pygame.Surface(size) + surface_color = pygame.Color("red") + + setsurface = surface.copy() + setsurface_color = pygame.Color("green") + setsurface.fill(setsurface_color) + + unsetsurface = surface.copy() + unsetsurface_color = pygame.Color("blue") + unsetsurface.fill(unsetsurface_color) + + # Create a checkerboard pattern of set/unset bits. + for pos in ((x, y) for x in range(width) for y in range(x & 1, height, 2)): + mask.set_at(pos) + + # Test different dest values. + for dest in self.ORIGIN_OFFSETS: + mask_rect.topleft = dest + + # Tests the color parameters set to None and also as their + # default values. Should have no effect as they are not being + # used, but this exercises different to_surface() code. + for disable_color_params in (True, False): + surface.fill(surface_color) # Clear for each test. + + if disable_color_params: + to_surface = mask.to_surface( + surface, + dest=dest, + setsurface=setsurface, + unsetsurface=unsetsurface, + setcolor=None, + unsetcolor=None, + ) + else: + to_surface = mask.to_surface( + surface, + dest=dest, + setsurface=setsurface, + unsetsurface=unsetsurface, + ) + + to_surface.lock() # Lock for possible speed up. + + for pos in ((x, y) for x in range(width) for y in range(height)): + mask_pos = (pos[0] - dest[0], pos[1] - dest[1]) + + if not mask_rect.collidepoint(pos): + expected_color = surface_color + elif mask.get_at(mask_pos): + expected_color = setsurface_color + else: + expected_color = unsetsurface_color + + self.assertEqual(to_surface.get_at(pos), expected_color) + to_surface.unlock() + + def test_to_surface__surface_narrower_than_mask(self): + """Ensures that surfaces narrower than the mask work correctly. + + For this test the surface's width is less than the mask's width. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + mask_size = (10, 20) + narrow_size = (6, 20) + + surface = pygame.Surface(narrow_size) + surface_color = pygame.Color("red") + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + surface.fill(surface_color) # Clear for each test. + expected_color = default_setcolor if fill else default_unsetcolor + + to_surface = mask.to_surface(surface) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), narrow_size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__setsurface_narrower_than_mask(self): + """Ensures that setsurfaces narrower than the mask work correctly. + + For this test the setsurface's width is less than the mask's width. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + mask_size = (10, 20) + narrow_size = (6, 20) + + setsurface = pygame.Surface(narrow_size, SRCALPHA, 32) + setsurface_color = pygame.Color("red") + setsurface.fill(setsurface_color) + setsurface_rect = setsurface.get_rect() + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + + to_surface = mask.to_surface(setsurface=setsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + + # Different checks depending on if the mask was filled or not. + if fill: + assertSurfaceFilled(self, to_surface, setsurface_color, setsurface_rect) + assertSurfaceFilledIgnoreArea( + self, to_surface, default_setcolor, setsurface_rect + ) + else: + assertSurfaceFilled(self, to_surface, default_unsetcolor) + + def test_to_surface__unsetsurface_narrower_than_mask(self): + """Ensures that unsetsurfaces narrower than the mask work correctly. + + For this test the unsetsurface's width is less than the mask's width. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + mask_size = (10, 20) + narrow_size = (6, 20) + + unsetsurface = pygame.Surface(narrow_size, SRCALPHA, 32) + unsetsurface_color = pygame.Color("red") + unsetsurface.fill(unsetsurface_color) + unsetsurface_rect = unsetsurface.get_rect() + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + + to_surface = mask.to_surface(unsetsurface=unsetsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + + # Different checks depending on if the mask was filled or not. + if fill: + assertSurfaceFilled(self, to_surface, default_setcolor) + else: + assertSurfaceFilled( + self, to_surface, unsetsurface_color, unsetsurface_rect + ) + assertSurfaceFilledIgnoreArea( + self, to_surface, default_unsetcolor, unsetsurface_rect + ) + + def test_to_surface__setsurface_narrower_than_mask_and_colors_none(self): + """Ensures that setsurfaces narrower than the mask work correctly + when setcolor and unsetcolor are set to None. + + For this test the setsurface's width is less than the mask's width. + """ + default_surface_color = (0, 0, 0, 0) + mask_size = (10, 20) + narrow_size = (6, 20) + + setsurface = pygame.Surface(narrow_size, SRCALPHA, 32) + setsurface_color = pygame.Color("red") + setsurface.fill(setsurface_color) + setsurface_rect = setsurface.get_rect() + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + + to_surface = mask.to_surface( + setsurface=setsurface, setcolor=None, unsetcolor=None + ) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + + # Different checks depending on if the mask was filled or not. + if fill: + assertSurfaceFilled(self, to_surface, setsurface_color, setsurface_rect) + assertSurfaceFilledIgnoreArea( + self, to_surface, default_surface_color, setsurface_rect + ) + else: + assertSurfaceFilled(self, to_surface, default_surface_color) + + def test_to_surface__unsetsurface_narrower_than_mask_and_colors_none(self): + """Ensures that unsetsurfaces narrower than the mask work correctly + when setcolor and unsetcolor are set to None. + + For this test the unsetsurface's width is less than the mask's width. + """ + default_surface_color = (0, 0, 0, 0) + mask_size = (10, 20) + narrow_size = (6, 20) + + unsetsurface = pygame.Surface(narrow_size, SRCALPHA, 32) + unsetsurface_color = pygame.Color("red") + unsetsurface.fill(unsetsurface_color) + unsetsurface_rect = unsetsurface.get_rect() + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + + to_surface = mask.to_surface( + unsetsurface=unsetsurface, setcolor=None, unsetcolor=None + ) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + + # Different checks depending on if the mask was filled or not. + if fill: + assertSurfaceFilled(self, to_surface, default_surface_color) + else: + assertSurfaceFilled( + self, to_surface, unsetsurface_color, unsetsurface_rect + ) + assertSurfaceFilledIgnoreArea( + self, to_surface, default_surface_color, unsetsurface_rect + ) + + def test_to_surface__surface_wider_than_mask(self): + """Ensures that surfaces wider than the mask work correctly. + + For this test the surface's width is greater than the mask's width. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + mask_size = (6, 15) + wide_size = (11, 15) + + surface = pygame.Surface(wide_size) + surface_color = pygame.Color("red") + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + mask_rect = mask.get_rect() + surface.fill(surface_color) # Clear for each test. + expected_color = default_setcolor if fill else default_unsetcolor + + to_surface = mask.to_surface(surface) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), wide_size) + assertSurfaceFilled(self, to_surface, expected_color, mask_rect) + assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, mask_rect) + + def test_to_surface__setsurface_wider_than_mask(self): + """Ensures that setsurfaces wider than the mask work correctly. + + For this test the setsurface's width is greater than the mask's width. + """ + default_unsetcolor = pygame.Color("black") + mask_size = (6, 15) + wide_size = (11, 15) + + setsurface = pygame.Surface(wide_size, SRCALPHA, 32) + setsurface_color = pygame.Color("red") + setsurface.fill(setsurface_color) + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + expected_color = setsurface_color if fill else default_unsetcolor + + to_surface = mask.to_surface(setsurface=setsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__unsetsurface_wider_than_mask(self): + """Ensures that unsetsurfaces wider than the mask work correctly. + + For this test the unsetsurface's width is greater than the mask's + width. + """ + default_setcolor = pygame.Color("white") + mask_size = (6, 15) + wide_size = (11, 15) + + unsetsurface = pygame.Surface(wide_size, SRCALPHA, 32) + unsetsurface_color = pygame.Color("red") + unsetsurface.fill(unsetsurface_color) + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + expected_color = default_setcolor if fill else unsetsurface_color + + to_surface = mask.to_surface(unsetsurface=unsetsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__surface_shorter_than_mask(self): + """Ensures that surfaces shorter than the mask work correctly. + + For this test the surface's height is less than the mask's height. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + mask_size = (10, 11) + short_size = (10, 6) + + surface = pygame.Surface(short_size) + surface_color = pygame.Color("red") + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + surface.fill(surface_color) # Clear for each test. + expected_color = default_setcolor if fill else default_unsetcolor + + to_surface = mask.to_surface(surface) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), short_size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__setsurface_shorter_than_mask(self): + """Ensures that setsurfaces shorter than the mask work correctly. + + For this test the setsurface's height is less than the mask's height. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + mask_size = (10, 11) + short_size = (10, 6) + + setsurface = pygame.Surface(short_size, SRCALPHA, 32) + setsurface_color = pygame.Color("red") + setsurface.fill(setsurface_color) + setsurface_rect = setsurface.get_rect() + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + + to_surface = mask.to_surface(setsurface=setsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + + # Different checks depending on if the mask was filled or not. + if fill: + assertSurfaceFilled(self, to_surface, setsurface_color, setsurface_rect) + assertSurfaceFilledIgnoreArea( + self, to_surface, default_setcolor, setsurface_rect + ) + else: + assertSurfaceFilled(self, to_surface, default_unsetcolor) + + def test_to_surface__unsetsurface_shorter_than_mask(self): + """Ensures that unsetsurfaces shorter than the mask work correctly. + + For this test the unsetsurface's height is less than the mask's height. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + mask_size = (10, 11) + short_size = (10, 6) + + unsetsurface = pygame.Surface(short_size, SRCALPHA, 32) + unsetsurface_color = pygame.Color("red") + unsetsurface.fill(unsetsurface_color) + unsetsurface_rect = unsetsurface.get_rect() + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + + to_surface = mask.to_surface(unsetsurface=unsetsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + + # Different checks depending on if the mask was filled or not. + if fill: + assertSurfaceFilled(self, to_surface, default_setcolor) + else: + assertSurfaceFilled( + self, to_surface, unsetsurface_color, unsetsurface_rect + ) + assertSurfaceFilledIgnoreArea( + self, to_surface, default_unsetcolor, unsetsurface_rect + ) + + def test_to_surface__setsurface_shorter_than_mask_and_colors_none(self): + """Ensures that setsurfaces shorter than the mask work correctly + when setcolor and unsetcolor are set to None. + + For this test the setsurface's height is less than the mask's height. + """ + default_surface_color = (0, 0, 0, 0) + mask_size = (10, 11) + short_size = (10, 6) + + setsurface = pygame.Surface(short_size, SRCALPHA, 32) + setsurface_color = pygame.Color("red") + setsurface.fill(setsurface_color) + setsurface_rect = setsurface.get_rect() + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + + to_surface = mask.to_surface( + setsurface=setsurface, setcolor=None, unsetcolor=None + ) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + + # Different checks depending on if the mask was filled or not. + if fill: + assertSurfaceFilled(self, to_surface, setsurface_color, setsurface_rect) + assertSurfaceFilledIgnoreArea( + self, to_surface, default_surface_color, setsurface_rect + ) + else: + assertSurfaceFilled(self, to_surface, default_surface_color) + + def test_to_surface__unsetsurface_shorter_than_mask_and_colors_none(self): + """Ensures that unsetsurfaces shorter than the mask work correctly + when setcolor and unsetcolor are set to None. + + For this test the unsetsurface's height is less than the mask's height. + """ + default_surface_color = (0, 0, 0, 0) + mask_size = (10, 11) + short_size = (10, 6) + + unsetsurface = pygame.Surface(short_size, SRCALPHA, 32) + unsetsurface_color = pygame.Color("red") + unsetsurface.fill(unsetsurface_color) + unsetsurface_rect = unsetsurface.get_rect() + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + + to_surface = mask.to_surface( + unsetsurface=unsetsurface, setcolor=None, unsetcolor=None + ) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + + # Different checks depending on if the mask was filled or not. + if fill: + assertSurfaceFilled(self, to_surface, default_surface_color) + else: + assertSurfaceFilled( + self, to_surface, unsetsurface_color, unsetsurface_rect + ) + assertSurfaceFilledIgnoreArea( + self, to_surface, default_surface_color, unsetsurface_rect + ) + + def test_to_surface__surface_taller_than_mask(self): + """Ensures that surfaces taller than the mask work correctly. + + For this test the surface's height is greater than the mask's height. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + mask_size = (10, 6) + tall_size = (10, 11) + + surface = pygame.Surface(tall_size) + surface_color = pygame.Color("red") + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + mask_rect = mask.get_rect() + surface.fill(surface_color) # Clear for each test. + expected_color = default_setcolor if fill else default_unsetcolor + + to_surface = mask.to_surface(surface) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), tall_size) + assertSurfaceFilled(self, to_surface, expected_color, mask_rect) + assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, mask_rect) + + def test_to_surface__setsurface_taller_than_mask(self): + """Ensures that setsurfaces taller than the mask work correctly. + + For this test the setsurface's height is greater than the mask's + height. + """ + default_unsetcolor = pygame.Color("black") + mask_size = (10, 6) + tall_size = (10, 11) + + setsurface = pygame.Surface(tall_size, SRCALPHA, 32) + setsurface_color = pygame.Color("red") + setsurface.fill(setsurface_color) + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + expected_color = setsurface_color if fill else default_unsetcolor + + to_surface = mask.to_surface(setsurface=setsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__unsetsurface_taller_than_mask(self): + """Ensures that unsetsurfaces taller than the mask work correctly. + + For this test the unsetsurface's height is greater than the mask's + height. + """ + default_setcolor = pygame.Color("white") + mask_size = (10, 6) + tall_size = (10, 11) + + unsetsurface = pygame.Surface(tall_size, SRCALPHA, 32) + unsetsurface_color = pygame.Color("red") + unsetsurface.fill(unsetsurface_color) + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + expected_color = default_setcolor if fill else unsetsurface_color + + to_surface = mask.to_surface(unsetsurface=unsetsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__surface_wider_and_taller_than_mask(self): + """Ensures that surfaces wider and taller than the mask work correctly. + + For this test the surface's width is greater than the mask's width and + the surface's height is greater than the mask's height. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + mask_size = (6, 8) + wide_tall_size = (11, 15) + + surface = pygame.Surface(wide_tall_size) + surface_color = pygame.Color("red") + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + mask_rect = mask.get_rect() + surface.fill(surface_color) # Clear for each test. + expected_color = default_setcolor if fill else default_unsetcolor + + to_surface = mask.to_surface(surface) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), wide_tall_size) + assertSurfaceFilled(self, to_surface, expected_color, mask_rect) + assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, mask_rect) + + def test_to_surface__setsurface_wider_and_taller_than_mask(self): + """Ensures that setsurfaces wider and taller than the mask work + correctly. + + For this test the setsurface's width is greater than the mask's width + and the setsurface's height is greater than the mask's height. + """ + default_unsetcolor = pygame.Color("black") + mask_size = (6, 8) + wide_tall_size = (11, 15) + + setsurface = pygame.Surface(wide_tall_size, SRCALPHA, 32) + setsurface_color = pygame.Color("red") + setsurface.fill(setsurface_color) + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + expected_color = setsurface_color if fill else default_unsetcolor + + to_surface = mask.to_surface(setsurface=setsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__unsetsurface_wider_and_taller_than_mask(self): + """Ensures that unsetsurfaces wider and taller than the mask work + correctly. + + For this test the unsetsurface's width is greater than the mask's width + and the unsetsurface's height is greater than the mask's height. + """ + default_setcolor = pygame.Color("white") + mask_size = (6, 8) + wide_tall_size = (11, 15) + + unsetsurface = pygame.Surface(wide_tall_size, SRCALPHA, 32) + unsetsurface_color = pygame.Color("red") + unsetsurface.fill(unsetsurface_color) + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + expected_color = default_setcolor if fill else unsetsurface_color + + to_surface = mask.to_surface(unsetsurface=unsetsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__surface_wider_and_shorter_than_mask(self): + """Ensures that surfaces wider and shorter than the mask work + correctly. + + For this test the surface's width is greater than the mask's width and + the surface's height is less than the mask's height. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + mask_size = (7, 11) + wide_short_size = (13, 6) + + surface = pygame.Surface(wide_short_size) + surface_color = pygame.Color("red") + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + mask_rect = mask.get_rect() + surface.fill(surface_color) # Clear for each test. + expected_color = default_setcolor if fill else default_unsetcolor + + to_surface = mask.to_surface(surface) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), wide_short_size) + assertSurfaceFilled(self, to_surface, expected_color, mask_rect) + assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, mask_rect) + + def test_to_surface__setsurface_wider_and_shorter_than_mask(self): + """Ensures that setsurfaces wider and shorter than the mask work + correctly. + + For this test the setsurface's width is greater than the mask's width + and the setsurface's height is less than the mask's height. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + mask_size = (7, 11) + wide_short_size = (10, 6) + + setsurface = pygame.Surface(wide_short_size, SRCALPHA, 32) + setsurface_color = pygame.Color("red") + setsurface.fill(setsurface_color) + setsurface_rect = setsurface.get_rect() + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + + to_surface = mask.to_surface(setsurface=setsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + + # Different checks depending on if the mask was filled or not. + if fill: + assertSurfaceFilled(self, to_surface, setsurface_color, setsurface_rect) + assertSurfaceFilledIgnoreArea( + self, to_surface, default_setcolor, setsurface_rect + ) + else: + assertSurfaceFilled(self, to_surface, default_unsetcolor) + + def test_to_surface__unsetsurface_wider_and_shorter_than_mask(self): + """Ensures that unsetsurfaces wider and shorter than the mask work + correctly. + + For this test the unsetsurface's width is greater than the mask's width + and the unsetsurface's height is less than the mask's height. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + mask_size = (7, 11) + wide_short_size = (10, 6) + + unsetsurface = pygame.Surface(wide_short_size, SRCALPHA, 32) + unsetsurface_color = pygame.Color("red") + unsetsurface.fill(unsetsurface_color) + unsetsurface_rect = unsetsurface.get_rect() + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + + to_surface = mask.to_surface(unsetsurface=unsetsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + + # Different checks depending on if the mask was filled or not. + if fill: + assertSurfaceFilled(self, to_surface, default_setcolor) + else: + assertSurfaceFilled( + self, to_surface, unsetsurface_color, unsetsurface_rect + ) + assertSurfaceFilledIgnoreArea( + self, to_surface, default_unsetcolor, unsetsurface_rect + ) + + def test_to_surface__surface_narrower_and_taller_than_mask(self): + """Ensures that surfaces narrower and taller than the mask work + correctly. + + For this test the surface's width is less than the mask's width and + the surface's height is greater than the mask's height. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + mask_size = (10, 8) + narrow_tall_size = (6, 15) + + surface = pygame.Surface(narrow_tall_size) + surface_color = pygame.Color("red") + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + mask_rect = mask.get_rect() + surface.fill(surface_color) # Clear for each test. + expected_color = default_setcolor if fill else default_unsetcolor + + to_surface = mask.to_surface(surface) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), narrow_tall_size) + assertSurfaceFilled(self, to_surface, expected_color, mask_rect) + assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, mask_rect) + + def test_to_surface__setsurface_narrower_and_taller_than_mask(self): + """Ensures that setsurfaces narrower and taller than the mask work + correctly. + + For this test the setsurface's width is less than the mask's width + and the setsurface's height is greater than the mask's height. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + mask_size = (10, 8) + narrow_tall_size = (6, 15) + + setsurface = pygame.Surface(narrow_tall_size, SRCALPHA, 32) + setsurface_color = pygame.Color("red") + setsurface.fill(setsurface_color) + setsurface_rect = setsurface.get_rect() + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + + to_surface = mask.to_surface(setsurface=setsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + + # Different checks depending on if the mask was filled or not. + if fill: + assertSurfaceFilled(self, to_surface, setsurface_color, setsurface_rect) + assertSurfaceFilledIgnoreArea( + self, to_surface, default_setcolor, setsurface_rect + ) + else: + assertSurfaceFilled(self, to_surface, default_unsetcolor) + + def test_to_surface__unsetsurface_narrower_and_taller_than_mask(self): + """Ensures that unsetsurfaces narrower and taller than the mask work + correctly. + + For this test the unsetsurface's width is less than the mask's width + and the unsetsurface's height is greater than the mask's height. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + mask_size = (10, 8) + narrow_tall_size = (6, 15) + + unsetsurface = pygame.Surface(narrow_tall_size, SRCALPHA, 32) + unsetsurface_color = pygame.Color("red") + unsetsurface.fill(unsetsurface_color) + unsetsurface_rect = unsetsurface.get_rect() + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + + to_surface = mask.to_surface(unsetsurface=unsetsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + + # Different checks depending on if the mask was filled or not. + if fill: + assertSurfaceFilled(self, to_surface, default_setcolor) + else: + assertSurfaceFilled( + self, to_surface, unsetsurface_color, unsetsurface_rect + ) + assertSurfaceFilledIgnoreArea( + self, to_surface, default_unsetcolor, unsetsurface_rect + ) + + def test_to_surface__surface_narrower_and_shorter_than_mask(self): + """Ensures that surfaces narrower and shorter than the mask work + correctly. + + For this test the surface's width is less than the mask's width and + the surface's height is less than the mask's height. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + mask_size = (10, 18) + narrow_short_size = (6, 15) + + surface = pygame.Surface(narrow_short_size) + surface_color = pygame.Color("red") + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + mask_rect = mask.get_rect() + surface.fill(surface_color) # Clear for each test. + expected_color = default_setcolor if fill else default_unsetcolor + + to_surface = mask.to_surface(surface) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), narrow_short_size) + assertSurfaceFilled(self, to_surface, expected_color, mask_rect) + assertSurfaceFilledIgnoreArea(self, to_surface, surface_color, mask_rect) + + def test_to_surface__setsurface_narrower_and_shorter_than_mask(self): + """Ensures that setsurfaces narrower and shorter than the mask work + correctly. + + For this test the setsurface's width is less than the mask's width + and the setsurface's height is less than the mask's height. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + mask_size = (10, 18) + narrow_short_size = (6, 15) + + setsurface = pygame.Surface(narrow_short_size, SRCALPHA, 32) + setsurface_color = pygame.Color("red") + setsurface.fill(setsurface_color) + setsurface_rect = setsurface.get_rect() + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + + to_surface = mask.to_surface(setsurface=setsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + + # Different checks depending on if the mask was filled or not. + if fill: + assertSurfaceFilled(self, to_surface, setsurface_color, setsurface_rect) + assertSurfaceFilledIgnoreArea( + self, to_surface, default_setcolor, setsurface_rect + ) + else: + assertSurfaceFilled(self, to_surface, default_unsetcolor) + + def test_to_surface__unsetsurface_narrower_and_shorter_than_mask(self): + """Ensures that unsetsurfaces narrower and shorter than the mask work + correctly. + + For this test the unsetsurface's width is less than the mask's width + and the unsetsurface's height is less than the mask's height. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + mask_size = (10, 18) + narrow_short_size = (6, 15) + + unsetsurface = pygame.Surface(narrow_short_size, SRCALPHA, 32) + unsetsurface_color = pygame.Color("red") + unsetsurface.fill(unsetsurface_color) + unsetsurface_rect = unsetsurface.get_rect() + + for fill in (True, False): + mask = pygame.mask.Mask(mask_size, fill=fill) + + to_surface = mask.to_surface(unsetsurface=unsetsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + + # Different checks depending on if the mask was filled or not. + if fill: + assertSurfaceFilled(self, to_surface, default_setcolor) + else: + assertSurfaceFilled( + self, to_surface, unsetsurface_color, unsetsurface_rect + ) + assertSurfaceFilledIgnoreArea( + self, to_surface, default_unsetcolor, unsetsurface_rect + ) + + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_to_surface__all_surfaces_different_sizes_than_mask(self): + """Ensures that all the surface parameters can be of different sizes.""" + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + surface_color = pygame.Color("red") + setsurface_color = pygame.Color("green") + unsetsurface_color = pygame.Color("blue") + + mask_size = (10, 15) + surface_size = (11, 14) + setsurface_size = (9, 8) + unsetsurface_size = (12, 16) + + surface = pygame.Surface(surface_size) + setsurface = pygame.Surface(setsurface_size) + unsetsurface = pygame.Surface(unsetsurface_size) + + surface.fill(surface_color) + setsurface.fill(setsurface_color) + unsetsurface.fill(unsetsurface_color) + + surface_rect = surface.get_rect() + setsurface_rect = setsurface.get_rect() + unsetsurface_rect = unsetsurface.get_rect() + + # Create a mask that is filled except for a rect in the center. + mask = pygame.mask.Mask(mask_size, fill=True) + mask_rect = mask.get_rect() + unfilled_rect = pygame.Rect((0, 0), (4, 5)) + unfilled_rect.center = mask_rect.center + + for pos in ( + (x, y) + for x in range(unfilled_rect.x, unfilled_rect.w) + for y in range(unfilled_rect.y, unfilled_rect.h) + ): + mask.set_at(pos, 0) + + to_surface = mask.to_surface(surface, setsurface, unsetsurface) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), surface_size) + + # Check each surface pixel for the correct color. + to_surface.lock() # Lock for possible speed up. + + for pos in ( + (x, y) for x in range(surface_rect.w) for y in range(surface_rect.h) + ): + if not mask_rect.collidepoint(pos): + expected_color = surface_color + elif mask.get_at(pos): + # Checking set bit colors. + if setsurface_rect.collidepoint(pos): + expected_color = setsurface_color + else: + expected_color = default_setcolor + else: + # Checking unset bit colors. + if unsetsurface_rect.collidepoint(pos): + expected_color = unsetsurface_color + else: + expected_color = default_unsetcolor + + self.assertEqual(to_surface.get_at(pos), expected_color) + + to_surface.unlock() + + def test_to_surface__dest_locations(self): + """Ensures dest values can be different locations on/off the surface.""" + SIDE = 7 + surface = pygame.Surface((SIDE, SIDE)) + surface_rect = surface.get_rect() + dest_rect = surface_rect.copy() + + surface_color = pygame.Color("red") + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + + directions = ( + ((s, 0) for s in range(-SIDE, SIDE + 1)), # left to right + ((0, s) for s in range(-SIDE, SIDE + 1)), # top to bottom + ((s, s) for s in range(-SIDE, SIDE + 1)), # topleft to bottomright diag + ((-s, s) for s in range(-SIDE, SIDE + 1)), # topright to bottomleft diag + ) + + for fill in (True, False): + mask = pygame.mask.Mask((SIDE, SIDE), fill=fill) + expected_color = default_setcolor if fill else default_unsetcolor + + for direction in directions: + for pos in direction: + dest_rect.topleft = pos + overlap_rect = dest_rect.clip(surface_rect) + surface.fill(surface_color) + + to_surface = mask.to_surface(surface, dest=dest_rect) + + assertSurfaceFilled(self, to_surface, expected_color, overlap_rect) + assertSurfaceFilledIgnoreArea( + self, to_surface, surface_color, overlap_rect + ) + + @unittest.expectedFailure + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_to_surface__area_locations(self): + """Ensures area rects can be different locations on/off the mask.""" + SIDE = 7 + surface = pygame.Surface((SIDE, SIDE)) + + surface_color = pygame.Color("red") + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + + directions = ( + ((s, 0) for s in range(-SIDE, SIDE + 1)), # left to right + ((0, s) for s in range(-SIDE, SIDE + 1)), # top to bottom + ((s, s) for s in range(-SIDE, SIDE + 1)), # topleft to bottomright diag + ((-s, s) for s in range(-SIDE, SIDE + 1)), # topright to bottomleft diag + ) + + for fill in (True, False): + mask = pygame.mask.Mask((SIDE, SIDE), fill=fill) + mask_rect = mask.get_rect() + area_rect = mask_rect.copy() + expected_color = default_setcolor if fill else default_unsetcolor + + for direction in directions: + for pos in direction: + area_rect.topleft = pos + overlap_rect = area_rect.clip(mask_rect) + overlap_rect.topleft = (0, 0) + surface.fill(surface_color) + + to_surface = mask.to_surface(surface, area=area_rect) + + assertSurfaceFilled(self, to_surface, expected_color, overlap_rect) + assertSurfaceFilledIgnoreArea( + self, to_surface, surface_color, overlap_rect + ) + + @unittest.expectedFailure + def test_to_surface__dest_and_area_locations(self): + """Ensures dest/area values can be different locations on/off the + surface/mask. + """ + SIDE = 5 + surface = pygame.Surface((SIDE, SIDE)) + surface_rect = surface.get_rect() + dest_rect = surface_rect.copy() + + surface_color = pygame.Color("red") + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + + dest_directions = ( + ((s, 0) for s in range(-SIDE, SIDE + 1)), # left to right + ((0, s) for s in range(-SIDE, SIDE + 1)), # top to bottom + ((s, s) for s in range(-SIDE, SIDE + 1)), # topleft to bottomright diag + ((-s, s) for s in range(-SIDE, SIDE + 1)), # topright to bottomleft diag + ) + + # Using only the topleft to bottomright diagonal to test the area (to + # reduce the number of loop iterations). + area_positions = list(dest_directions[2]) + + for fill in (True, False): + mask = pygame.mask.Mask((SIDE, SIDE), fill=fill) + mask_rect = mask.get_rect() + area_rect = mask_rect.copy() + expected_color = default_setcolor if fill else default_unsetcolor + + for dest_direction in dest_directions: + for dest_pos in dest_direction: + dest_rect.topleft = dest_pos + + for area_pos in area_positions: + area_rect.topleft = area_pos + area_overlap_rect = area_rect.clip(mask_rect) + area_overlap_rect.topleft = dest_rect.topleft + dest_overlap_rect = dest_rect.clip(area_overlap_rect) + + surface.fill(surface_color) + + to_surface = mask.to_surface( + surface, dest=dest_rect, area=area_rect + ) + + assertSurfaceFilled( + self, to_surface, expected_color, dest_overlap_rect + ) + assertSurfaceFilledIgnoreArea( + self, to_surface, surface_color, dest_overlap_rect + ) + + @unittest.expectedFailure + def test_to_surface__area_sizes(self): + """Ensures area rects can be different sizes.""" + SIDE = 7 + SIZES = ( + (0, 0), + (0, 1), + (1, 0), + (1, 1), + (SIDE - 1, SIDE - 1), + (SIDE - 1, SIDE), + (SIDE, SIDE - 1), + (SIDE, SIDE), + (SIDE + 1, SIDE), + (SIDE, SIDE + 1), + (SIDE + 1, SIDE + 1), + ) + + surface = pygame.Surface((SIDE, SIDE)) + surface_color = pygame.Color("red") + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + + for fill in (True, False): + mask = pygame.mask.Mask((SIDE, SIDE), fill=fill) + mask_rect = mask.get_rect() + expected_color = default_setcolor if fill else default_unsetcolor + + for size in SIZES: + area_rect = pygame.Rect((0, 0), size) + + for pos in self.ORIGIN_OFFSETS: + area_rect.topleft = pos + overlap_rect = area_rect.clip(mask_rect) + overlap_rect.topleft = (0, 0) + surface.fill(surface_color) + + to_surface = mask.to_surface(surface, area=area_rect) + + assertSurfaceFilled(self, to_surface, expected_color, overlap_rect) + assertSurfaceFilledIgnoreArea( + self, to_surface, surface_color, overlap_rect + ) + + def test_to_surface__surface_color_alphas(self): + """Ensures the setsurface/unsetsurface color alpha values are respected.""" + size = (13, 17) + setsurface_color = pygame.Color("green") + setsurface_color.a = 53 + unsetsurface_color = pygame.Color("blue") + unsetsurface_color.a = 109 + + setsurface = pygame.Surface(size, flags=SRCALPHA, depth=32) + unsetsurface = pygame.Surface(size, flags=SRCALPHA, depth=32) + + setsurface.fill(setsurface_color) + unsetsurface.fill(unsetsurface_color) + + for fill in (True, False): + mask = pygame.mask.Mask(size, fill=fill) + expected_color = setsurface_color if fill else unsetsurface_color + + to_surface = mask.to_surface( + setsurface=setsurface, unsetsurface=unsetsurface + ) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__color_alphas(self): + """Ensures the setcolor/unsetcolor alpha values are respected.""" + size = (13, 17) + setcolor = pygame.Color("green") + setcolor.a = 35 + unsetcolor = pygame.Color("blue") + unsetcolor.a = 213 + + for fill in (True, False): + mask = pygame.mask.Mask(size, fill=fill) + expected_color = setcolor if fill else unsetcolor + + to_surface = mask.to_surface(setcolor=setcolor, unsetcolor=unsetcolor) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__depths(self): + """Ensures to_surface works correctly with supported surface depths.""" + size = (13, 17) + surface_color = pygame.Color("red") + setsurface_color = pygame.Color("green") + unsetsurface_color = pygame.Color("blue") + + for depth in (8, 16, 24, 32): + surface = pygame.Surface(size, depth=depth) + setsurface = pygame.Surface(size, depth=depth) + unsetsurface = pygame.Surface(size, depth=depth) + + surface.fill(surface_color) + setsurface.fill(setsurface_color) + unsetsurface.fill(unsetsurface_color) + + for fill in (True, False): + mask = pygame.mask.Mask(size, fill=fill) + + # For non-32 bit depths, the actual color can be different from + # what was filled. + expected_color = ( + setsurface.get_at((0, 0)) if fill else unsetsurface.get_at((0, 0)) + ) + + to_surface = mask.to_surface(surface, setsurface, unsetsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__different_depths(self): + """Ensures an exception is raised when surfaces have different depths.""" + size = (13, 17) + surface_color = pygame.Color("red") + setsurface_color = pygame.Color("green") + unsetsurface_color = pygame.Color("blue") + mask = pygame.mask.Mask(size) + + # Test different combinations of depths. + test_depths = ( + (8, 8, 16), # surface/setsurface/unsetsurface + (8, 8, 24), + (8, 8, 32), + (16, 16, 24), + (16, 16, 32), + (24, 16, 8), + (32, 16, 16), + (32, 32, 16), + (32, 24, 32), + ) + + for depths in test_depths: + surface = pygame.Surface(size, depth=depths[0]) + setsurface = pygame.Surface(size, depth=depths[1]) + unsetsurface = pygame.Surface(size, depth=depths[2]) + + surface.fill(surface_color) + setsurface.fill(setsurface_color) + unsetsurface.fill(unsetsurface_color) + + with self.assertRaises(ValueError): + mask.to_surface(surface, setsurface, unsetsurface) + + def test_to_surface__different_depths_with_created_surfaces(self): + """Ensures an exception is raised when surfaces have different depths + than the created surface. + """ + size = (13, 17) + setsurface_color = pygame.Color("green") + unsetsurface_color = pygame.Color("blue") + mask = pygame.mask.Mask(size) + + # Test different combinations of depths. The created surface always has + # a depth of 32. + test_depths = ( + (8, 8), # setsurface/unsetsurface + (16, 16), + (24, 24), + (24, 16), + (32, 8), + (32, 16), + (32, 24), + (16, 32), + ) + + for set_depth, unset_depth in test_depths: + setsurface = pygame.Surface(size, depth=set_depth) + unsetsurface = pygame.Surface(size, depth=unset_depth) + + setsurface.fill(setsurface_color) + unsetsurface.fill(unsetsurface_color) + + with self.assertRaises(ValueError): + mask.to_surface(setsurface=setsurface, unsetsurface=unsetsurface) + + def test_to_surface__same_srcalphas(self): + """Ensures to_surface works correctly when the SRCALPHA flag is set or not.""" + size = (13, 17) + surface_color = pygame.Color("red") + setsurface_color = pygame.Color("green") + unsetsurface_color = pygame.Color("blue") + + for depth in (16, 32): + for flags in (0, SRCALPHA): + surface = pygame.Surface(size, flags=flags, depth=depth) + setsurface = pygame.Surface(size, flags=flags, depth=depth) + unsetsurface = pygame.Surface(size, flags=flags, depth=depth) + + surface.fill(surface_color) + setsurface.fill(setsurface_color) + unsetsurface.fill(unsetsurface_color) + + for fill in (True, False): + mask = pygame.mask.Mask(size, fill=fill) + expected_color = setsurface_color if fill else unsetsurface_color + + to_surface = mask.to_surface(surface, setsurface, unsetsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + if flags: + self.assertTrue(to_surface.get_flags() & flags) + + def test_to_surface__same_srcalphas_with_created_surfaces(self): + """Ensures to_surface works correctly when it creates a surface + and the SRCALPHA flag is set on both setsurface and unsetsurface. + """ + size = (13, 17) + setsurface_color = pygame.Color("green") + unsetsurface_color = pygame.Color("blue") + # The created surface always has a depth of 32 and the SRCALPHA flag set. + expected_flags = SRCALPHA + + setsurface = pygame.Surface(size, flags=expected_flags, depth=32) + unsetsurface = pygame.Surface(size, flags=expected_flags, depth=32) + + setsurface.fill(setsurface_color) + unsetsurface.fill(unsetsurface_color) + + for fill in (True, False): + mask = pygame.mask.Mask(size, fill=fill) + expected_color = setsurface_color if fill else unsetsurface_color + + to_surface = mask.to_surface( + setsurface=setsurface, unsetsurface=unsetsurface + ) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + self.assertTrue(to_surface.get_flags() & expected_flags) + + def test_to_surface__different_srcalphas(self): + """Ensures an exception is raised when surfaces have different SRCALPHA + flag settings. + """ + size = (13, 17) + surface_color = pygame.Color("red") + setsurface_color = pygame.Color("green") + unsetsurface_color = pygame.Color("blue") + mask = pygame.mask.Mask(size) + + # Test different combinations of SRCALPHA flags. + test_flags = ( + (SRCALPHA, 0, 0), # surface/setsurface/unsetsurface + (SRCALPHA, SRCALPHA, 0), + (0, SRCALPHA, SRCALPHA), + (0, 0, SRCALPHA), + ) + + for depth in (16, 32): + for flags in test_flags: + surface = pygame.Surface(size, flags=flags[0], depth=depth) + setsurface = pygame.Surface(size, flags=flags[1], depth=depth) + unsetsurface = pygame.Surface(size, flags=flags[2], depth=depth) + + surface.fill(surface_color) + setsurface.fill(setsurface_color) + unsetsurface.fill(unsetsurface_color) + + with self.assertRaises(ValueError): + mask.to_surface(surface, setsurface, unsetsurface) + + def test_to_surface__different_srcalphas_with_created_surfaces(self): + """Ensures an exception is raised when surfaces have different SRCALPHA + flag settings than the created surface. + """ + size = (13, 17) + setsurface_color = pygame.Color("green") + unsetsurface_color = pygame.Color("blue") + mask = pygame.mask.Mask(size) + + for depth in (16, 32): + # Test different combinations of SRCALPHA flags. The created + # surface always has the SRCALPHA flag set. + for flags in ((0, 0), (SRCALPHA, 0), (0, SRCALPHA)): + setsurface = pygame.Surface(size, flags=flags[0], depth=depth) + unsetsurface = pygame.Surface(size, flags=flags[1], depth=depth) + + setsurface.fill(setsurface_color) + unsetsurface.fill(unsetsurface_color) + + with self.assertRaises(ValueError): + mask.to_surface(setsurface=setsurface, unsetsurface=unsetsurface) + + def test_to_surface__dest_on_surface(self): + """Ensures dest values on the surface work correctly + when using the defaults for setcolor and unsetcolor. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + width, height = size = (5, 9) + surface = pygame.Surface(size, SRCALPHA, 32) + surface_color = pygame.Color("red") + + for fill in (True, False): + mask = pygame.mask.Mask(size, fill=fill) + mask_rect = mask.get_rect() + expected_color = default_setcolor if fill else default_unsetcolor + + # Test the dest parameter at different locations on the surface. + for dest in ((x, y) for y in range(height) for x in range(width)): + surface.fill(surface_color) # Clear for each test. + mask_rect.topleft = dest + + to_surface = mask.to_surface(surface, dest=dest) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color, mask_rect) + assertSurfaceFilledIgnoreArea( + self, to_surface, surface_color, mask_rect + ) + + def test_to_surface__dest_on_surface_with_setsurface_unsetsurface(self): + """Ensures dest values on the surface work correctly + when using setsurface and unsetsurface. + """ + width, height = size = (5, 9) + surface = pygame.Surface(size, SRCALPHA, 32) + surface_color = pygame.Color("red") + + setsurface = surface.copy() + setsurface_color = pygame.Color("green") + setsurface.fill(setsurface_color) + + unsetsurface = surface.copy() + unsetsurface_color = pygame.Color("blue") + unsetsurface.fill(unsetsurface_color) + + # Using different kwargs to exercise different to_surface() code. + # Should not have any impact on the resulting drawn surfaces. + kwargs = { + "surface": surface, + "setsurface": setsurface, + "unsetsurface": unsetsurface, + "dest": None, + } + + color_kwargs = dict(kwargs) + color_kwargs.update((("setcolor", None), ("unsetcolor", None))) + + for fill in (True, False): + mask = pygame.mask.Mask(size, fill=fill) + mask_rect = mask.get_rect() + expected_color = setsurface_color if fill else unsetsurface_color + + # Test the dest parameter at different locations on the surface. + for dest in ((x, y) for y in range(height) for x in range(width)): + mask_rect.topleft = dest + + for use_color_params in (True, False): + surface.fill(surface_color) # Clear for each test. + + test_kwargs = color_kwargs if use_color_params else kwargs + test_kwargs["dest"] = dest + to_surface = mask.to_surface(**test_kwargs) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color, mask_rect) + assertSurfaceFilledIgnoreArea( + self, to_surface, surface_color, mask_rect + ) + + def test_to_surface__dest_off_surface(self): + """Ensures dest values off the surface work correctly + when using the defaults for setcolor and unsetcolor. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + width, height = size = (5, 7) + surface = pygame.Surface(size, SRCALPHA, 32) + surface_color = pygame.Color("red") + + # Test different dests off the surface. + dests = [(-width, -height), (-width, 0), (0, -height)] + dests.extend(off_corners(surface.get_rect())) + + for fill in (True, False): + mask = pygame.mask.Mask(size, fill=fill) + mask_rect = mask.get_rect() + expected_color = default_setcolor if fill else default_unsetcolor + + for dest in dests: + surface.fill(surface_color) # Clear for each test. + mask_rect.topleft = dest + + to_surface = mask.to_surface(surface, dest=dest) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color, mask_rect) + assertSurfaceFilledIgnoreArea( + self, to_surface, surface_color, mask_rect + ) + + def test_to_surface__dest_off_surface_with_setsurface_unsetsurface(self): + """Ensures dest values off the surface work correctly + when using setsurface and unsetsurface. + """ + width, height = size = (5, 7) + surface = pygame.Surface(size, SRCALPHA, 32) + surface_color = pygame.Color("red") + + setsurface = surface.copy() + setsurface_color = pygame.Color("green") + setsurface.fill(setsurface_color) + + unsetsurface = surface.copy() + unsetsurface_color = pygame.Color("blue") + unsetsurface.fill(unsetsurface_color) + + # Test different dests off the surface. + dests = [(-width, -height), (-width, 0), (0, -height)] + dests.extend(off_corners(surface.get_rect())) + + # Using different kwargs to exercise different to_surface() code. + # Should not have any impact on the resulting drawn surfaces. + kwargs = { + "surface": surface, + "setsurface": setsurface, + "unsetsurface": unsetsurface, + "dest": None, + } + + color_kwargs = dict(kwargs) + color_kwargs.update((("setcolor", None), ("unsetcolor", None))) + + for fill in (True, False): + mask = pygame.mask.Mask(size, fill=fill) + mask_rect = mask.get_rect() + expected_color = setsurface_color if fill else unsetsurface_color + + for dest in dests: + mask_rect.topleft = dest + + for use_color_params in (True, False): + surface.fill(surface_color) # Clear for each test. + test_kwargs = color_kwargs if use_color_params else kwargs + test_kwargs["dest"] = dest + to_surface = mask.to_surface(**test_kwargs) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color, mask_rect) + assertSurfaceFilledIgnoreArea( + self, to_surface, surface_color, mask_rect + ) + + @unittest.expectedFailure + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_to_surface__area_on_mask(self): + """Ensures area values on the mask work correctly + when using the defaults for setcolor and unsetcolor. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + width, height = size = (5, 9) + surface = pygame.Surface(size, SRCALPHA, 32) + surface_color = pygame.Color("red") + + for fill in (True, False): + mask = pygame.mask.Mask(size, fill=fill) + mask_rect = mask.get_rect() + area_rect = mask_rect.copy() + expected_color = default_setcolor if fill else default_unsetcolor + + # Testing the area parameter at different locations on the mask. + for pos in ((x, y) for y in range(height) for x in range(width)): + surface.fill(surface_color) # Clear for each test. + area_rect.topleft = pos + overlap_rect = mask_rect.clip(area_rect) + overlap_rect.topleft = (0, 0) + + to_surface = mask.to_surface(surface, area=area_rect) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color, overlap_rect) + assertSurfaceFilledIgnoreArea( + self, to_surface, surface_color, overlap_rect + ) + + @unittest.expectedFailure + def test_to_surface__area_on_mask_with_setsurface_unsetsurface(self): + """Ensures area values on the mask work correctly + when using setsurface and unsetsurface. + """ + width, height = size = (5, 9) + surface = pygame.Surface(size, SRCALPHA, 32) + surface_color = pygame.Color("red") + + setsurface = surface.copy() + setsurface_color = pygame.Color("green") + setsurface.fill(setsurface_color) + + unsetsurface = surface.copy() + unsetsurface_color = pygame.Color("blue") + unsetsurface.fill(unsetsurface_color) + + # Using the values in kwargs vs color_kwargs tests different to_surface + # code. Should not have any impact on the resulting drawn surfaces. + kwargs = { + "surface": surface, + "setsurface": setsurface, + "unsetsurface": unsetsurface, + "area": pygame.Rect((0, 0), size), + } + + color_kwargs = dict(kwargs) + color_kwargs.update((("setcolor", None), ("unsetcolor", None))) + + for fill in (True, False): + mask = pygame.mask.Mask(size, fill=fill) + mask_rect = mask.get_rect() + area_rect = mask_rect.copy() + expected_color = setsurface_color if fill else unsetsurface_color + + # Testing the area parameter at different locations on the mask. + for pos in ((x, y) for y in range(height) for x in range(width)): + area_rect.topleft = pos + overlap_rect = mask_rect.clip(area_rect) + overlap_rect.topleft = (0, 0) + + for use_color_params in (True, False): + surface.fill(surface_color) # Clear for each test. + test_kwargs = color_kwargs if use_color_params else kwargs + test_kwargs["area"].topleft = pos + overlap_rect = mask_rect.clip(test_kwargs["area"]) + overlap_rect.topleft = (0, 0) + + to_surface = mask.to_surface(**test_kwargs) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color, overlap_rect) + assertSurfaceFilledIgnoreArea( + self, to_surface, surface_color, overlap_rect + ) + + @unittest.expectedFailure + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_to_surface__area_off_mask(self): + """Ensures area values off the mask work correctly + when using the defaults for setcolor and unsetcolor. + """ + default_setcolor = pygame.Color("white") + default_unsetcolor = pygame.Color("black") + width, height = size = (5, 7) + surface = pygame.Surface(size, SRCALPHA, 32) + surface_color = pygame.Color("red") + + # Testing positions off the mask. + positions = [(-width, -height), (-width, 0), (0, -height)] + positions.extend(off_corners(pygame.Rect((0, 0), (width, height)))) + + for fill in (True, False): + mask = pygame.mask.Mask(size, fill=fill) + mask_rect = mask.get_rect() + area_rect = mask_rect.copy() + expected_color = default_setcolor if fill else default_unsetcolor + + for pos in positions: + surface.fill(surface_color) # Clear for each test. + area_rect.topleft = pos + overlap_rect = mask_rect.clip(area_rect) + overlap_rect.topleft = (0, 0) + + to_surface = mask.to_surface(surface, area=area_rect) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color, overlap_rect) + assertSurfaceFilledIgnoreArea( + self, to_surface, surface_color, overlap_rect + ) + + @unittest.expectedFailure + @unittest.skipIf(IS_PYPY, "Segfaults on pypy") + def test_to_surface__area_off_mask_with_setsurface_unsetsurface(self): + """Ensures area values off the mask work correctly + when using setsurface and unsetsurface. + """ + width, height = size = (5, 7) + surface = pygame.Surface(size, SRCALPHA, 32) + surface_color = pygame.Color("red") + + setsurface = surface.copy() + setsurface_color = pygame.Color("green") + setsurface.fill(setsurface_color) + + unsetsurface = surface.copy() + unsetsurface_color = pygame.Color("blue") + unsetsurface.fill(unsetsurface_color) + + # Testing positions off the mask. + positions = [(-width, -height), (-width, 0), (0, -height)] + positions.extend(off_corners(pygame.Rect((0, 0), (width, height)))) + + # Using the values in kwargs vs color_kwargs tests different to_surface + # code. Should not have any impact on the resulting drawn surfaces. + kwargs = { + "surface": surface, + "setsurface": setsurface, + "unsetsurface": unsetsurface, + "area": pygame.Rect((0, 0), size), + } + + color_kwargs = dict(kwargs) + color_kwargs.update((("setcolor", None), ("unsetcolor", None))) + + for fill in (True, False): + mask = pygame.mask.Mask(size, fill=fill) + mask_rect = mask.get_rect() + expected_color = setsurface_color if fill else unsetsurface_color + + for pos in positions: + for use_color_params in (True, False): + surface.fill(surface_color) # Clear for each test. + test_kwargs = color_kwargs if use_color_params else kwargs + test_kwargs["area"].topleft = pos + overlap_rect = mask_rect.clip(test_kwargs["area"]) + overlap_rect.topleft = (0, 0) + + to_surface = mask.to_surface(**test_kwargs) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color, overlap_rect) + assertSurfaceFilledIgnoreArea( + self, to_surface, surface_color, overlap_rect + ) + + def test_to_surface__surface_with_zero_size(self): + """Ensures zero sized surfaces are handled correctly.""" + expected_ref_count = 3 + size = (0, 0) + surface = pygame.Surface(size) + mask = pygame.mask.Mask((3, 4), fill=True) + + to_surface = mask.to_surface(surface) + + self.assertIs(to_surface, surface) + if not IS_PYPY: + self.assertEqual(sys.getrefcount(to_surface), expected_ref_count) + self.assertEqual(to_surface.get_size(), size) + + def test_to_surface__setsurface_with_zero_size(self): + """Ensures zero sized setsurfaces are handled correctly.""" + expected_ref_count = 2 + expected_flag = SRCALPHA + expected_depth = 32 + expected_color = pygame.Color("white") # Default setcolor. + mask_size = (2, 4) + mask = pygame.mask.Mask(mask_size, fill=True) + setsurface = pygame.Surface((0, 0), expected_flag, expected_depth) + + to_surface = mask.to_surface(setsurface=setsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + if not IS_PYPY: + self.assertEqual(sys.getrefcount(to_surface), expected_ref_count) + self.assertTrue(to_surface.get_flags() & expected_flag) + self.assertEqual(to_surface.get_bitsize(), expected_depth) + self.assertEqual(to_surface.get_size(), mask_size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_to_surface__unsetsurface_with_zero_size(self): + """Ensures zero sized unsetsurfaces are handled correctly.""" + expected_ref_count = 2 + expected_flag = SRCALPHA + expected_depth = 32 + expected_color = pygame.Color("black") # Default unsetcolor. + mask_size = (4, 2) + mask = pygame.mask.Mask(mask_size) + unsetsurface = pygame.Surface((0, 0), expected_flag, expected_depth) + + to_surface = mask.to_surface(unsetsurface=unsetsurface) + + self.assertIsInstance(to_surface, pygame.Surface) + if not IS_PYPY: + self.assertEqual(sys.getrefcount(to_surface), expected_ref_count) + self.assertTrue(to_surface.get_flags() & expected_flag) + self.assertEqual(to_surface.get_bitsize(), expected_depth) + self.assertEqual(to_surface.get_size(), mask_size) + assertSurfaceFilled(self, to_surface, expected_color) + + def test_zero_mask(self): + """Ensures masks can be created with zero sizes.""" + for size in ((100, 0), (0, 100), (0, 0)): + for fill in (True, False): + msg = "size={}, fill={}".format(size, fill) + + mask = pygame.mask.Mask(size, fill=fill) + + self.assertIsInstance(mask, pygame.mask.Mask, msg) + self.assertEqual(mask.get_size(), size, msg) + + def test_zero_mask_copy(self): + """Ensures copy correctly handles zero sized masks.""" + for expected_size in ((11, 0), (0, 11), (0, 0)): + mask = pygame.mask.Mask(expected_size) + + mask_copy = mask.copy() + + self.assertIsInstance(mask_copy, pygame.mask.Mask) + self.assertIsNot(mask_copy, mask) + assertMaskEqual(self, mask_copy, mask) + + def test_zero_mask_get_size(self): + """Ensures get_size correctly handles zero sized masks.""" + for expected_size in ((41, 0), (0, 40), (0, 0)): + mask = pygame.mask.Mask(expected_size) + + size = mask.get_size() + + self.assertEqual(size, expected_size) + + def test_zero_mask_get_rect(self): + """Ensures get_rect correctly handles zero sized masks.""" + for expected_size in ((4, 0), (0, 4), (0, 0)): + expected_rect = pygame.Rect((0, 0), expected_size) + mask = pygame.mask.Mask(expected_size) + + rect = mask.get_rect() + + self.assertEqual(rect, expected_rect) + + def test_zero_mask_get_at(self): + """Ensures get_at correctly handles zero sized masks.""" + for size in ((51, 0), (0, 50), (0, 0)): + mask = pygame.mask.Mask(size) + + with self.assertRaises(IndexError): + value = mask.get_at((0, 0)) + + def test_zero_mask_set_at(self): + """Ensures set_at correctly handles zero sized masks.""" + for size in ((31, 0), (0, 30), (0, 0)): + mask = pygame.mask.Mask(size) + + with self.assertRaises(IndexError): + mask.set_at((0, 0)) + + def test_zero_mask_overlap(self): + """Ensures overlap correctly handles zero sized masks. + + Tests combinations of sized and zero sized masks. + """ + offset = (0, 0) + + for size1, size2 in zero_size_pairs(51, 42): + msg = "size1={}, size2={}".format(size1, size2) + mask1 = pygame.mask.Mask(size1, fill=True) + mask2 = pygame.mask.Mask(size2, fill=True) + + overlap_pos = mask1.overlap(mask2, offset) + + self.assertIsNone(overlap_pos, msg) + + def test_zero_mask_overlap_area(self): + """Ensures overlap_area correctly handles zero sized masks. + + Tests combinations of sized and zero sized masks. + """ + offset = (0, 0) + expected_count = 0 + + for size1, size2 in zero_size_pairs(41, 52): + msg = "size1={}, size2={}".format(size1, size2) + mask1 = pygame.mask.Mask(size1, fill=True) + mask2 = pygame.mask.Mask(size2, fill=True) + + overlap_count = mask1.overlap_area(mask2, offset) + + self.assertEqual(overlap_count, expected_count, msg) + + def test_zero_mask_overlap_mask(self): + """Ensures overlap_mask correctly handles zero sized masks. + + Tests combinations of sized and zero sized masks. + """ + offset = (0, 0) + expected_count = 0 + + for size1, size2 in zero_size_pairs(43, 53): + msg = "size1={}, size2={}".format(size1, size2) + mask1 = pygame.mask.Mask(size1, fill=True) + mask2 = pygame.mask.Mask(size2, fill=True) + + overlap_mask = mask1.overlap_mask(mask2, offset) + + self.assertIsInstance(overlap_mask, pygame.mask.Mask, msg) + self.assertEqual(overlap_mask.count(), expected_count, msg) + self.assertEqual(overlap_mask.get_size(), size1, msg) + + def test_zero_mask_fill(self): + """Ensures fill correctly handles zero sized masks.""" + expected_count = 0 + + for size in ((100, 0), (0, 100), (0, 0)): + mask = pygame.mask.Mask(size) + + mask.fill() + + self.assertEqual(mask.count(), expected_count, "size={}".format(size)) + + def test_zero_mask_clear(self): + sizes = ((100, 0), (0, 100), (0, 0)) + + for size in sizes: + mask = pygame.mask.Mask(size) + mask.clear() + self.assertEqual(mask.count(), 0) + + def test_zero_mask_flip(self): + sizes = ((100, 0), (0, 100), (0, 0)) + + for size in sizes: + mask = pygame.mask.Mask(size) + mask.invert() + self.assertEqual(mask.count(), 0) + + def test_zero_mask_scale(self): + sizes = ((100, 0), (0, 100), (0, 0)) + + for size in sizes: + mask = pygame.mask.Mask(size) + mask2 = mask.scale((2, 3)) + + self.assertIsInstance(mask2, pygame.mask.Mask) + self.assertEqual(mask2.get_size(), (2, 3)) + + def test_zero_mask_draw(self): + """Ensures draw correctly handles zero sized masks. + + Tests combinations of sized and zero sized masks. + """ + offset = (0, 0) + + for size1, size2 in zero_size_pairs(31, 37): + msg = "size1={}, size2={}".format(size1, size2) + mask1 = pygame.mask.Mask(size1, fill=True) + mask2 = pygame.mask.Mask(size2, fill=True) + expected_count = mask1.count() + + mask1.draw(mask2, offset) + + self.assertEqual(mask1.count(), expected_count, msg) + self.assertEqual(mask1.get_size(), size1, msg) + + def test_zero_mask_erase(self): + """Ensures erase correctly handles zero sized masks. + + Tests combinations of sized and zero sized masks. + """ + offset = (0, 0) + + for size1, size2 in zero_size_pairs(29, 23): + msg = "size1={}, size2={}".format(size1, size2) + mask1 = pygame.mask.Mask(size1, fill=True) + mask2 = pygame.mask.Mask(size2, fill=True) + expected_count = mask1.count() + + mask1.erase(mask2, offset) + + self.assertEqual(mask1.count(), expected_count, msg) + self.assertEqual(mask1.get_size(), size1, msg) + + def test_zero_mask_count(self): + sizes = ((100, 0), (0, 100), (0, 0)) + + for size in sizes: + mask = pygame.mask.Mask(size, fill=True) + self.assertEqual(mask.count(), 0) + + def test_zero_mask_centroid(self): + sizes = ((100, 0), (0, 100), (0, 0)) + + for size in sizes: + mask = pygame.mask.Mask(size) + self.assertEqual(mask.centroid(), (0, 0)) + + def test_zero_mask_angle(self): + sizes = ((100, 0), (0, 100), (0, 0)) + + for size in sizes: + mask = pygame.mask.Mask(size) + self.assertEqual(mask.angle(), 0.0) + + def test_zero_mask_outline(self): + """Ensures outline correctly handles zero sized masks.""" + expected_points = [] + + for size in ((61, 0), (0, 60), (0, 0)): + mask = pygame.mask.Mask(size) + + points = mask.outline() + + self.assertListEqual(points, expected_points, "size={}".format(size)) + + def test_zero_mask_outline__with_arg(self): + """Ensures outline correctly handles zero sized masks + when using the skip pixels argument.""" + expected_points = [] + + for size in ((66, 0), (0, 65), (0, 0)): + mask = pygame.mask.Mask(size) + + points = mask.outline(10) + + self.assertListEqual(points, expected_points, "size={}".format(size)) + + def test_zero_mask_convolve(self): + """Ensures convolve correctly handles zero sized masks. + + Tests the different combinations of sized and zero sized masks. + """ + for size1 in ((17, 13), (71, 0), (0, 70), (0, 0)): + mask1 = pygame.mask.Mask(size1, fill=True) + + for size2 in ((11, 7), (81, 0), (0, 60), (0, 0)): + msg = "sizes={}, {}".format(size1, size2) + mask2 = pygame.mask.Mask(size2, fill=True) + expected_size = ( + max(0, size1[0] + size2[0] - 1), + max(0, size1[1] + size2[1] - 1), + ) + + mask = mask1.convolve(mask2) + + self.assertIsInstance(mask, pygame.mask.Mask, msg) + self.assertIsNot(mask, mask2, msg) + self.assertEqual(mask.get_size(), expected_size, msg) + + def test_zero_mask_convolve__with_output_mask(self): + """Ensures convolve correctly handles zero sized masks + when using an output mask argument. + + Tests the different combinations of sized and zero sized masks. + """ + for size1 in ((11, 17), (91, 0), (0, 90), (0, 0)): + mask1 = pygame.mask.Mask(size1, fill=True) + + for size2 in ((13, 11), (83, 0), (0, 62), (0, 0)): + mask2 = pygame.mask.Mask(size2, fill=True) + + for output_size in ((7, 5), (71, 0), (0, 70), (0, 0)): + msg = "sizes={}, {}, {}".format(size1, size2, output_size) + output_mask = pygame.mask.Mask(output_size) + + mask = mask1.convolve(mask2, output_mask) + + self.assertIsInstance(mask, pygame.mask.Mask, msg) + self.assertIs(mask, output_mask, msg) + self.assertEqual(mask.get_size(), output_size, msg) + + def test_zero_mask_connected_component(self): + """Ensures connected_component correctly handles zero sized masks.""" + expected_count = 0 + + for size in ((81, 0), (0, 80), (0, 0)): + msg = "size={}".format(size) + mask = pygame.mask.Mask(size) + + cc_mask = mask.connected_component() + + self.assertIsInstance(cc_mask, pygame.mask.Mask, msg) + self.assertEqual(cc_mask.get_size(), size) + self.assertEqual(cc_mask.count(), expected_count, msg) + + def test_zero_mask_connected_component__indexed(self): + """Ensures connected_component correctly handles zero sized masks + when using an index argument.""" + for size in ((91, 0), (0, 90), (0, 0)): + mask = pygame.mask.Mask(size) + + with self.assertRaises(IndexError): + cc_mask = mask.connected_component((0, 0)) + + def test_zero_mask_connected_components(self): + """Ensures connected_components correctly handles zero sized masks.""" + expected_cc_masks = [] + + for size in ((11, 0), (0, 10), (0, 0)): + mask = pygame.mask.Mask(size) + + cc_masks = mask.connected_components() + + self.assertListEqual(cc_masks, expected_cc_masks, "size={}".format(size)) + + def test_zero_mask_get_bounding_rects(self): + """Ensures get_bounding_rects correctly handles zero sized masks.""" + expected_bounding_rects = [] + + for size in ((21, 0), (0, 20), (0, 0)): + mask = pygame.mask.Mask(size) + + bounding_rects = mask.get_bounding_rects() + + self.assertListEqual( + bounding_rects, expected_bounding_rects, "size={}".format(size) + ) + + def test_zero_mask_to_surface(self): + """Ensures to_surface correctly handles zero sized masks and surfaces.""" + mask_color = pygame.Color("blue") + surf_color = pygame.Color("red") + + for surf_size in ((7, 3), (7, 0), (0, 7), (0, 0)): + surface = pygame.Surface(surf_size, SRCALPHA, 32) + surface.fill(surf_color) + + for mask_size in ((5, 0), (0, 5), (0, 0)): + mask = pygame.mask.Mask(mask_size, fill=True) + + to_surface = mask.to_surface(surface, setcolor=mask_color) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), surf_size) + + if 0 not in surf_size: + assertSurfaceFilled(self, to_surface, surf_color) + + def test_zero_mask_to_surface__create_surface(self): + """Ensures to_surface correctly handles zero sized masks and surfaces + when it has to create a default surface. + """ + mask_color = pygame.Color("blue") + + for mask_size in ((3, 0), (0, 3), (0, 0)): + mask = pygame.mask.Mask(mask_size, fill=True) + + to_surface = mask.to_surface(setcolor=mask_color) + + self.assertIsInstance(to_surface, pygame.Surface) + self.assertEqual(to_surface.get_size(), mask_size) + + +class SubMask(pygame.mask.Mask): + """Subclass of the Mask class to help test subclassing.""" + + def __init__(self, *args, **kwargs): + super(SubMask, self).__init__(*args, **kwargs) + self.test_attribute = True + + +class SubMaskCopy(SubMask): + """Subclass of the Mask class to help test copying subclasses.""" + + def copy(self): + mask_copy = super(SubMaskCopy, self).copy() + mask_copy.test_attribute = self.test_attribute + return mask_copy + + +class SubMaskDunderCopy(SubMask): + """Subclass of the Mask class to help test copying subclasses.""" + + def __copy__(self): + mask_copy = super(SubMaskDunderCopy, self).__copy__() + mask_copy.test_attribute = self.test_attribute + return mask_copy + + +class SubMaskCopyAndDunderCopy(SubMaskDunderCopy): + """Subclass of the Mask class to help test copying subclasses.""" + + def copy(self): + return super(SubMaskCopyAndDunderCopy, self).copy() + + +class MaskSubclassTest(unittest.TestCase): + """Test subclassed Masks.""" + + def test_subclass_mask(self): + """Ensures the Mask class can be subclassed.""" + mask = SubMask((5, 3), fill=True) + + self.assertIsInstance(mask, pygame.mask.Mask) + self.assertIsInstance(mask, SubMask) + self.assertTrue(mask.test_attribute) + + def test_subclass_copy(self): + """Ensures copy works for subclassed Masks.""" + mask = SubMask((65, 2), fill=True) + + # Test both the copy() and __copy__() methods. + for mask_copy in (mask.copy(), copy.copy(mask)): + self.assertIsInstance(mask_copy, pygame.mask.Mask) + self.assertIsInstance(mask_copy, SubMask) + self.assertIsNot(mask_copy, mask) + assertMaskEqual(self, mask_copy, mask) + # No subclass attributes because copy()/__copy__() not overridden. + self.assertFalse(hasattr(mask_copy, "test_attribute")) + + def test_subclass_copy__override_copy(self): + """Ensures copy works for subclassed Masks overriding copy.""" + mask = SubMaskCopy((65, 2), fill=True) + + # Test both the copy() and __copy__() methods. + for i, mask_copy in enumerate((mask.copy(), copy.copy(mask))): + self.assertIsInstance(mask_copy, pygame.mask.Mask) + self.assertIsInstance(mask_copy, SubMaskCopy) + self.assertIsNot(mask_copy, mask) + assertMaskEqual(self, mask_copy, mask) + + if 1 == i: + # No subclass attributes because __copy__() not overridden. + self.assertFalse(hasattr(mask_copy, "test_attribute")) + else: + self.assertTrue(mask_copy.test_attribute) + + def test_subclass_copy__override_dunder_copy(self): + """Ensures copy works for subclassed Masks overriding __copy__.""" + mask = SubMaskDunderCopy((65, 2), fill=True) + + # Test both the copy() and __copy__() methods. + for mask_copy in (mask.copy(), copy.copy(mask)): + self.assertIsInstance(mask_copy, pygame.mask.Mask) + self.assertIsInstance(mask_copy, SubMaskDunderCopy) + self.assertIsNot(mask_copy, mask) + assertMaskEqual(self, mask_copy, mask) + # Calls to copy() eventually call __copy__() internally so the + # attributes will be copied. + self.assertTrue(mask_copy.test_attribute) + + def test_subclass_copy__override_both_copy_methods(self): + """Ensures copy works for subclassed Masks overriding copy/__copy__.""" + mask = SubMaskCopyAndDunderCopy((65, 2), fill=True) + + # Test both the copy() and __copy__() methods. + for mask_copy in (mask.copy(), copy.copy(mask)): + self.assertIsInstance(mask_copy, pygame.mask.Mask) + self.assertIsInstance(mask_copy, SubMaskCopyAndDunderCopy) + self.assertIsNot(mask_copy, mask) + assertMaskEqual(self, mask_copy, mask) + self.assertTrue(mask_copy.test_attribute) + + def test_subclass_get_size(self): + """Ensures get_size works for subclassed Masks.""" + expected_size = (2, 3) + mask = SubMask(expected_size) + + size = mask.get_size() + + self.assertEqual(size, expected_size) + + def test_subclass_mask_get_rect(self): + """Ensures get_rect works for subclassed Masks.""" + expected_rect = pygame.Rect((0, 0), (65, 33)) + mask = SubMask(expected_rect.size, fill=True) + + rect = mask.get_rect() + + self.assertEqual(rect, expected_rect) + + def test_subclass_get_at(self): + """Ensures get_at works for subclassed Masks.""" + expected_bit = 1 + mask = SubMask((3, 2), fill=True) + + bit = mask.get_at((0, 0)) + + self.assertEqual(bit, expected_bit) + + def test_subclass_set_at(self): + """Ensures set_at works for subclassed Masks.""" + expected_bit = 1 + expected_count = 1 + pos = (0, 0) + mask = SubMask(fill=False, size=(4, 2)) + + mask.set_at(pos) + + self.assertEqual(mask.get_at(pos), expected_bit) + self.assertEqual(mask.count(), expected_count) + + def test_subclass_overlap(self): + """Ensures overlap works for subclassed Masks.""" + expected_pos = (0, 0) + mask_size = (2, 3) + masks = (pygame.mask.Mask(fill=True, size=mask_size), SubMask(mask_size, True)) + arg_masks = ( + pygame.mask.Mask(fill=True, size=mask_size), + SubMask(mask_size, True), + ) + + # Test different combinations of subclassed and non-subclassed Masks. + for mask in masks: + for arg_mask in arg_masks: + overlap_pos = mask.overlap(arg_mask, (0, 0)) + + self.assertEqual(overlap_pos, expected_pos) + + def test_subclass_overlap_area(self): + """Ensures overlap_area works for subclassed Masks.""" + mask_size = (3, 2) + expected_count = mask_size[0] * mask_size[1] + masks = (pygame.mask.Mask(fill=True, size=mask_size), SubMask(mask_size, True)) + arg_masks = ( + pygame.mask.Mask(fill=True, size=mask_size), + SubMask(mask_size, True), + ) + + # Test different combinations of subclassed and non-subclassed Masks. + for mask in masks: + for arg_mask in arg_masks: + overlap_count = mask.overlap_area(arg_mask, (0, 0)) + + self.assertEqual(overlap_count, expected_count) + + def test_subclass_overlap_mask(self): + """Ensures overlap_mask works for subclassed Masks.""" + expected_size = (4, 5) + expected_count = expected_size[0] * expected_size[1] + masks = ( + pygame.mask.Mask(fill=True, size=expected_size), + SubMask(expected_size, True), + ) + arg_masks = ( + pygame.mask.Mask(fill=True, size=expected_size), + SubMask(expected_size, True), + ) + + # Test different combinations of subclassed and non-subclassed Masks. + for mask in masks: + for arg_mask in arg_masks: + overlap_mask = mask.overlap_mask(arg_mask, (0, 0)) + + self.assertIsInstance(overlap_mask, pygame.mask.Mask) + self.assertNotIsInstance(overlap_mask, SubMask) + self.assertEqual(overlap_mask.count(), expected_count) + self.assertEqual(overlap_mask.get_size(), expected_size) + + def test_subclass_fill(self): + """Ensures fill works for subclassed Masks.""" + mask_size = (2, 4) + expected_count = mask_size[0] * mask_size[1] + mask = SubMask(fill=False, size=mask_size) + + mask.fill() + + self.assertEqual(mask.count(), expected_count) + + def test_subclass_clear(self): + """Ensures clear works for subclassed Masks.""" + mask_size = (4, 3) + expected_count = 0 + mask = SubMask(mask_size, True) + + mask.clear() + + self.assertEqual(mask.count(), expected_count) + + def test_subclass_invert(self): + """Ensures invert works for subclassed Masks.""" + mask_size = (1, 4) + expected_count = mask_size[0] * mask_size[1] + mask = SubMask(fill=False, size=mask_size) + + mask.invert() + + self.assertEqual(mask.count(), expected_count) + + def test_subclass_scale(self): + """Ensures scale works for subclassed Masks.""" + expected_size = (5, 2) + mask = SubMask((1, 4)) + + scaled_mask = mask.scale(expected_size) + + self.assertIsInstance(scaled_mask, pygame.mask.Mask) + self.assertNotIsInstance(scaled_mask, SubMask) + self.assertEqual(scaled_mask.get_size(), expected_size) + + def test_subclass_draw(self): + """Ensures draw works for subclassed Masks.""" + mask_size = (5, 4) + expected_count = mask_size[0] * mask_size[1] + arg_masks = ( + pygame.mask.Mask(fill=True, size=mask_size), + SubMask(mask_size, True), + ) + + # Test different combinations of subclassed and non-subclassed Masks. + for mask in (pygame.mask.Mask(mask_size), SubMask(mask_size)): + for arg_mask in arg_masks: + mask.clear() # Clear for each test. + + mask.draw(arg_mask, (0, 0)) + + self.assertEqual(mask.count(), expected_count) + + def test_subclass_erase(self): + """Ensures erase works for subclassed Masks.""" + mask_size = (3, 4) + expected_count = 0 + masks = (pygame.mask.Mask(mask_size, True), SubMask(mask_size, True)) + arg_masks = (pygame.mask.Mask(mask_size, True), SubMask(mask_size, True)) + + # Test different combinations of subclassed and non-subclassed Masks. + for mask in masks: + for arg_mask in arg_masks: + mask.fill() # Fill for each test. + + mask.erase(arg_mask, (0, 0)) + + self.assertEqual(mask.count(), expected_count) + + def test_subclass_count(self): + """Ensures count works for subclassed Masks.""" + mask_size = (5, 2) + expected_count = mask_size[0] * mask_size[1] - 1 + mask = SubMask(fill=True, size=mask_size) + mask.set_at((1, 1), 0) + + count = mask.count() + + self.assertEqual(count, expected_count) + + def test_subclass_centroid(self): + """Ensures centroid works for subclassed Masks.""" + expected_centroid = (0, 0) + mask_size = (3, 2) + mask = SubMask((3, 2)) + + centroid = mask.centroid() + + self.assertEqual(centroid, expected_centroid) + + def test_subclass_angle(self): + """Ensures angle works for subclassed Masks.""" + expected_angle = 0.0 + mask = SubMask(size=(5, 4)) + + angle = mask.angle() + + self.assertAlmostEqual(angle, expected_angle) + + def test_subclass_outline(self): + """Ensures outline works for subclassed Masks.""" + expected_outline = [] + mask = SubMask((3, 4)) + + outline = mask.outline() + + self.assertListEqual(outline, expected_outline) + + def test_subclass_convolve(self): + """Ensures convolve works for subclassed Masks.""" + width, height = 7, 5 + mask_size = (width, height) + expected_count = 0 + expected_size = (max(0, width * 2 - 1), max(0, height * 2 - 1)) + + arg_masks = (pygame.mask.Mask(mask_size), SubMask(mask_size)) + output_masks = (pygame.mask.Mask(mask_size), SubMask(mask_size)) + + # Test different combinations of subclassed and non-subclassed Masks. + for mask in (pygame.mask.Mask(mask_size), SubMask(mask_size)): + for arg_mask in arg_masks: + convolve_mask = mask.convolve(arg_mask) + + self.assertIsInstance(convolve_mask, pygame.mask.Mask) + self.assertNotIsInstance(convolve_mask, SubMask) + self.assertEqual(convolve_mask.count(), expected_count) + self.assertEqual(convolve_mask.get_size(), expected_size) + + # Test subclassed masks for the output_mask as well. + for output_mask in output_masks: + convolve_mask = mask.convolve(arg_mask, output_mask) + + self.assertIsInstance(convolve_mask, pygame.mask.Mask) + self.assertEqual(convolve_mask.count(), expected_count) + self.assertEqual(convolve_mask.get_size(), mask_size) + + if isinstance(output_mask, SubMask): + self.assertIsInstance(convolve_mask, SubMask) + else: + self.assertNotIsInstance(convolve_mask, SubMask) + + def test_subclass_connected_component(self): + """Ensures connected_component works for subclassed Masks.""" + expected_count = 0 + expected_size = (3, 4) + mask = SubMask(expected_size) + + cc_mask = mask.connected_component() + + self.assertIsInstance(cc_mask, pygame.mask.Mask) + self.assertNotIsInstance(cc_mask, SubMask) + self.assertEqual(cc_mask.count(), expected_count) + self.assertEqual(cc_mask.get_size(), expected_size) + + def test_subclass_connected_components(self): + """Ensures connected_components works for subclassed Masks.""" + expected_ccs = [] + mask = SubMask((5, 4)) + + ccs = mask.connected_components() + + self.assertListEqual(ccs, expected_ccs) + + def test_subclass_get_bounding_rects(self): + """Ensures get_bounding_rects works for subclassed Masks.""" + expected_bounding_rects = [] + mask = SubMask((3, 2)) + + bounding_rects = mask.get_bounding_rects() + + self.assertListEqual(bounding_rects, expected_bounding_rects) + + def test_subclass_to_surface(self): + """Ensures to_surface works for subclassed Masks.""" + expected_color = pygame.Color("blue") + size = (5, 3) + mask = SubMask(size, fill=True) + surface = pygame.Surface(size, SRCALPHA, 32) + surface.fill(pygame.Color("red")) + + to_surface = mask.to_surface(surface, setcolor=expected_color) + + self.assertIs(to_surface, surface) + self.assertEqual(to_surface.get_size(), size) + assertSurfaceFilled(self, to_surface, expected_color) + + +@unittest.skipIf(IS_PYPY, "pypy has lots of mask failures") # TODO +class MaskModuleTest(unittest.TestCase): + def test_from_surface(self): + """Ensures from_surface creates a mask with the correct bits set. + + This test checks the masks created by the from_surface function using + 16 and 32 bit surfaces. Each alpha value (0-255) is tested against + several different threshold values. + Note: On 16 bit surface the requested alpha value can differ from what + is actually set. This test uses the value read from the surface. + """ + threshold_count = 256 + surface_color = [55, 155, 255, 0] + expected_size = (11, 9) + all_set_count = expected_size[0] * expected_size[1] + none_set_count = 0 + + for depth in (16, 32): + surface = pygame.Surface(expected_size, SRCALPHA, depth) + + for alpha in range(threshold_count): + surface_color[3] = alpha + surface.fill(surface_color) + + if depth < 32: + # On surfaces with depths < 32 the requested alpha can be + # different than what gets set. Use the value read from the + # surface. + alpha = surface.get_at((0, 0))[3] + + # Test the mask created at threshold values low, high and + # around alpha. + threshold_test_values = set( + [-1, 0, alpha - 1, alpha, alpha + 1, 255, 256] + ) + + for threshold in threshold_test_values: + msg = "depth={}, alpha={}, threshold={}".format( + depth, alpha, threshold + ) + + if alpha > threshold: + expected_count = all_set_count + else: + expected_count = none_set_count + + mask = pygame.mask.from_surface( + surface=surface, threshold=threshold + ) + + self.assertIsInstance(mask, pygame.mask.Mask, msg) + self.assertEqual(mask.get_size(), expected_size, msg) + self.assertEqual(mask.count(), expected_count, msg) + + def test_from_surface__different_alphas_32bit(self): + """Ensures from_surface creates a mask with the correct bits set + when pixels have different alpha values (32 bits surfaces). + + This test checks the masks created by the from_surface function using + a 32 bit surface. The surface is created with each pixel having a + different alpha value (0-255). This surface is tested over a range + of threshold values (0-255). + """ + offset = (0, 0) + threshold_count = 256 + surface_color = [10, 20, 30, 0] + expected_size = (threshold_count, 1) + expected_mask = pygame.Mask(expected_size, fill=True) + surface = pygame.Surface(expected_size, SRCALPHA, 32) + + # Give each pixel a different alpha. + surface.lock() # Lock for possible speed up. + for a in range(threshold_count): + surface_color[3] = a + surface.set_at((a, 0), surface_color) + surface.unlock() + + # Test the mask created for each different alpha threshold. + for threshold in range(threshold_count): + msg = "threshold={}".format(threshold) + expected_mask.set_at((threshold, 0), 0) + expected_count = expected_mask.count() + + mask = pygame.mask.from_surface(surface, threshold) + + self.assertIsInstance(mask, pygame.mask.Mask, msg) + self.assertEqual(mask.get_size(), expected_size, msg) + self.assertEqual(mask.count(), expected_count, msg) + self.assertEqual( + mask.overlap_area(expected_mask, offset), expected_count, msg + ) + + def test_from_surface__different_alphas_16bit(self): + """Ensures from_surface creates a mask with the correct bits set + when pixels have different alpha values (16 bit surfaces). + + This test checks the masks created by the from_surface function using + a 16 bit surface. Each pixel of the surface is set with a different + alpha value (0-255), but since this is a 16 bit surface the requested + alpha value can differ from what is actually set. The resulting surface + will have groups of alpha values which complicates the test as the + alpha groups will all be set/unset at a given threshold. The setup + calculates these groups and an expected mask for each. This test data + is then used to test each alpha grouping over a range of threshold + values. + """ + threshold_count = 256 + surface_color = [110, 120, 130, 0] + expected_size = (threshold_count, 1) + surface = pygame.Surface(expected_size, SRCALPHA, 16) + + # Give each pixel a different alpha. + surface.lock() # Lock for possible speed up. + for a in range(threshold_count): + surface_color[3] = a + surface.set_at((a, 0), surface_color) + surface.unlock() + + alpha_thresholds = OrderedDict() + special_thresholds = set() + + # Create the threshold ranges and identify any thresholds that need + # special handling. + for threshold in range(threshold_count): + # On surfaces with depths < 32 the requested alpha can be different + # than what gets set. Use the value read from the surface. + alpha = surface.get_at((threshold, 0))[3] + + if alpha not in alpha_thresholds: + alpha_thresholds[alpha] = [threshold] + else: + alpha_thresholds[alpha].append(threshold) + + if threshold < alpha: + special_thresholds.add(threshold) + + # Use each threshold group to create an expected mask. + test_data = [] # [(from_threshold, to_threshold, expected_mask), ...] + offset = (0, 0) + erase_mask = pygame.Mask(expected_size) + exp_mask = pygame.Mask(expected_size, fill=True) + + for thresholds in alpha_thresholds.values(): + for threshold in thresholds: + if threshold in special_thresholds: + # Any special thresholds just reuse previous exp_mask. + test_data.append((threshold, threshold + 1, exp_mask)) + else: + to_threshold = thresholds[-1] + 1 + + # Make the expected mask by erasing the unset bits. + for thres in range(to_threshold): + erase_mask.set_at((thres, 0), 1) + + exp_mask = pygame.Mask(expected_size, fill=True) + exp_mask.erase(erase_mask, offset) + test_data.append((threshold, to_threshold, exp_mask)) + break + + # All the setup is done. Now test the masks created over the threshold + # ranges. + for from_threshold, to_threshold, expected_mask in test_data: + expected_count = expected_mask.count() + + for threshold in range(from_threshold, to_threshold): + msg = "threshold={}".format(threshold) + + mask = pygame.mask.from_surface(surface, threshold) + + self.assertIsInstance(mask, pygame.mask.Mask, msg) + self.assertEqual(mask.get_size(), expected_size, msg) + self.assertEqual(mask.count(), expected_count, msg) + self.assertEqual( + mask.overlap_area(expected_mask, offset), expected_count, msg + ) + + def test_from_surface__with_colorkey_mask_cleared(self): + """Ensures from_surface creates a mask with the correct bits set + when the surface uses a colorkey. + + The surface is filled with the colorkey color so the resulting masks + are expected to have no bits set. + """ + colorkeys = ((0, 0, 0), (1, 2, 3), (50, 100, 200), (255, 255, 255)) + expected_size = (7, 11) + expected_count = 0 + + for depth in (8, 16, 24, 32): + msg = "depth={}".format(depth) + surface = pygame.Surface(expected_size, 0, depth) + + for colorkey in colorkeys: + surface.set_colorkey(colorkey) + # With some depths (i.e. 8 and 16) the actual colorkey can be + # different than what was requested via the set. + surface.fill(surface.get_colorkey()) + + mask = pygame.mask.from_surface(surface) + + self.assertIsInstance(mask, pygame.mask.Mask, msg) + self.assertEqual(mask.get_size(), expected_size, msg) + self.assertEqual(mask.count(), expected_count, msg) + + def test_from_surface__with_colorkey_mask_filled(self): + """Ensures from_surface creates a mask with the correct bits set + when the surface uses a colorkey. + + The surface is filled with a color that is not the colorkey color so + the resulting masks are expected to have all bits set. + """ + colorkeys = ((0, 0, 0), (1, 2, 3), (10, 100, 200), (255, 255, 255)) + surface_color = (50, 100, 200) + expected_size = (11, 7) + expected_count = expected_size[0] * expected_size[1] + + for depth in (8, 16, 24, 32): + msg = "depth={}".format(depth) + surface = pygame.Surface(expected_size, 0, depth) + surface.fill(surface_color) + + for colorkey in colorkeys: + surface.set_colorkey(colorkey) + + mask = pygame.mask.from_surface(surface) + + self.assertIsInstance(mask, pygame.mask.Mask, msg) + self.assertEqual(mask.get_size(), expected_size, msg) + self.assertEqual(mask.count(), expected_count, msg) + + def test_from_surface__with_colorkey_mask_pattern(self): + """Ensures from_surface creates a mask with the correct bits set + when the surface uses a colorkey. + + The surface is filled with alternating pixels of colorkey and + non-colorkey colors, so the resulting masks are expected to have + alternating bits set. + """ + + def alternate(func, set_value, unset_value, width, height): + # Helper function to set alternating values. + setbit = False + for pos in ((x, y) for x in range(width) for y in range(height)): + func(pos, set_value if setbit else unset_value) + setbit = not setbit + + surface_color = (5, 10, 20) + colorkey = (50, 60, 70) + expected_size = (11, 2) + expected_mask = pygame.mask.Mask(expected_size) + alternate(expected_mask.set_at, 1, 0, *expected_size) + expected_count = expected_mask.count() + offset = (0, 0) + + for depth in (8, 16, 24, 32): + msg = "depth={}".format(depth) + surface = pygame.Surface(expected_size, 0, depth) + # Fill the surface with alternating colors. + alternate(surface.set_at, surface_color, colorkey, *expected_size) + surface.set_colorkey(colorkey) + + mask = pygame.mask.from_surface(surface) + + self.assertIsInstance(mask, pygame.mask.Mask, msg) + self.assertEqual(mask.get_size(), expected_size, msg) + self.assertEqual(mask.count(), expected_count, msg) + self.assertEqual( + mask.overlap_area(expected_mask, offset), expected_count, msg + ) + + def test_from_threshold(self): + """Does mask.from_threshold() work correctly?""" + + a = [16, 24, 32] + + for i in a: + surf = pygame.surface.Surface((70, 70), 0, i) + surf.fill((100, 50, 200), (20, 20, 20, 20)) + mask = pygame.mask.from_threshold( + surf, (100, 50, 200, 255), (10, 10, 10, 255) + ) + + rects = mask.get_bounding_rects() + + self.assertEqual(mask.count(), 400) + self.assertEqual(mask.get_bounding_rects(), [pygame.Rect((20, 20, 20, 20))]) + + for i in a: + surf = pygame.surface.Surface((70, 70), 0, i) + surf2 = pygame.surface.Surface((70, 70), 0, i) + surf.fill((100, 100, 100)) + surf2.fill((150, 150, 150)) + surf2.fill((100, 100, 100), (40, 40, 10, 10)) + mask = pygame.mask.from_threshold( + surface=surf, + color=(0, 0, 0, 0), + threshold=(10, 10, 10, 255), + othersurface=surf2, + ) + + self.assertIsInstance(mask, pygame.mask.Mask) + self.assertEqual(mask.count(), 100) + self.assertEqual(mask.get_bounding_rects(), [pygame.Rect((40, 40, 10, 10))]) + + def test_zero_size_from_surface(self): + """Ensures from_surface can create masks from zero sized surfaces.""" + for size in ((100, 0), (0, 100), (0, 0)): + mask = pygame.mask.from_surface(pygame.Surface(size)) + + self.assertIsInstance(mask, pygame.mask.MaskType, "size={}".format(size)) + self.assertEqual(mask.get_size(), size) + + def test_zero_size_from_threshold(self): + a = [16, 24, 32] + sizes = ((100, 0), (0, 100), (0, 0)) + + for size in sizes: + for i in a: + surf = pygame.surface.Surface(size, 0, i) + surf.fill((100, 50, 200), (20, 20, 20, 20)) + mask = pygame.mask.from_threshold( + surf, (100, 50, 200, 255), (10, 10, 10, 255) + ) + + self.assertEqual(mask.count(), 0) + + rects = mask.get_bounding_rects() + self.assertEqual(rects, []) + + for i in a: + surf = pygame.surface.Surface(size, 0, i) + surf2 = pygame.surface.Surface(size, 0, i) + surf.fill((100, 100, 100)) + surf2.fill((150, 150, 150)) + surf2.fill((100, 100, 100), (40, 40, 10, 10)) + mask = pygame.mask.from_threshold( + surf, (0, 0, 0, 0), (10, 10, 10, 255), surf2 + ) + + self.assertIsInstance(mask, pygame.mask.Mask) + self.assertEqual(mask.count(), 0) + + rects = mask.get_bounding_rects() + self.assertEqual(rects, []) + + def test_buffer_interface(self): + size = (1000, 100) + pixels_set = ((0, 1), (100, 10), (173, 90)) + pixels_unset = ((0, 0), (101, 10), (173, 91)) + + mask = pygame.Mask(size) + for point in pixels_set: + mask.set_at(point, 1) + + view = memoryview(mask) + intwidth = 8 * view.strides[1] + + for point in pixels_set: + x, y = point + col = x // intwidth + self.assertEqual( + (view[col, y] >> (x % intwidth)) & 1, + 1, + "the pixel at {} is not set to 1".format(point), + ) + + for point in pixels_unset: + x, y = point + col = x // intwidth + self.assertEqual( + (view[col, y] >> (x % intwidth)) & 1, + 0, + "the pixel at {} is not set to 0".format(point), + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/math_test.py b/venv/Lib/site-packages/pygame/tests/math_test.py new file mode 100644 index 0000000..1d8cd63 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/math_test.py @@ -0,0 +1,2326 @@ +# -*- coding: utf-8 -*- +import sys +import unittest +import math +import platform + +import pygame.math +from pygame.math import Vector2, Vector3 + +IS_PYPY = "PyPy" == platform.python_implementation() + + +class Vector2TypeTest(unittest.TestCase): + def setUp(self): + self.zeroVec = Vector2() + self.e1 = Vector2(1, 0) + self.e2 = Vector2(0, 1) + self.t1 = (1.2, 3.4) + self.l1 = list(self.t1) + self.v1 = Vector2(self.t1) + self.t2 = (5.6, 7.8) + self.l2 = list(self.t2) + self.v2 = Vector2(self.t2) + self.s1 = 5.6 + self.s2 = 7.8 + + def testConstructionDefault(self): + v = Vector2() + self.assertEqual(v.x, 0.0) + self.assertEqual(v.y, 0.0) + + def testConstructionScalar(self): + v = Vector2(1) + self.assertEqual(v.x, 1.0) + self.assertEqual(v.y, 1.0) + + def testConstructionScalarKeywords(self): + v = Vector2(x=1) + self.assertEqual(v.x, 1.0) + self.assertEqual(v.y, 1.0) + + def testConstructionKeywords(self): + v = Vector2(x=1, y=2) + self.assertEqual(v.x, 1.0) + self.assertEqual(v.y, 2.0) + + def testConstructionXY(self): + v = Vector2(1.2, 3.4) + self.assertEqual(v.x, 1.2) + self.assertEqual(v.y, 3.4) + + def testConstructionTuple(self): + v = Vector2((1.2, 3.4)) + self.assertEqual(v.x, 1.2) + self.assertEqual(v.y, 3.4) + + def testConstructionList(self): + v = Vector2([1.2, 3.4]) + self.assertEqual(v.x, 1.2) + self.assertEqual(v.y, 3.4) + + def testConstructionVector2(self): + v = Vector2(Vector2(1.2, 3.4)) + self.assertEqual(v.x, 1.2) + self.assertEqual(v.y, 3.4) + + def testAttributeAccess(self): + tmp = self.v1.x + self.assertEqual(tmp, self.v1.x) + self.assertEqual(tmp, self.v1[0]) + tmp = self.v1.y + self.assertEqual(tmp, self.v1.y) + self.assertEqual(tmp, self.v1[1]) + self.v1.x = 3.141 + self.assertEqual(self.v1.x, 3.141) + self.v1.y = 3.141 + self.assertEqual(self.v1.y, 3.141) + + def assign_nonfloat(): + v = Vector2() + v.x = "spam" + + self.assertRaises(TypeError, assign_nonfloat) + + def testCopy(self): + v_copy0 = Vector2(2004.0, 2022.0) + v_copy1 = v_copy0.copy() + self.assertEqual(v_copy0.x, v_copy1.x) + self.assertEqual(v_copy0.y, v_copy1.y) + + def testSequence(self): + v = Vector2(1.2, 3.4) + Vector2()[:] + self.assertEqual(len(v), 2) + self.assertEqual(v[0], 1.2) + self.assertEqual(v[1], 3.4) + self.assertRaises(IndexError, lambda: v[2]) + self.assertEqual(v[-1], 3.4) + self.assertEqual(v[-2], 1.2) + self.assertRaises(IndexError, lambda: v[-3]) + self.assertEqual(v[:], [1.2, 3.4]) + self.assertEqual(v[1:], [3.4]) + self.assertEqual(v[:1], [1.2]) + self.assertEqual(list(v), [1.2, 3.4]) + self.assertEqual(tuple(v), (1.2, 3.4)) + v[0] = 5.6 + v[1] = 7.8 + self.assertEqual(v.x, 5.6) + self.assertEqual(v.y, 7.8) + v[:] = [9.1, 11.12] + self.assertEqual(v.x, 9.1) + self.assertEqual(v.y, 11.12) + + def overpopulate(): + v = Vector2() + v[:] = [1, 2, 3] + + self.assertRaises(ValueError, overpopulate) + + def underpopulate(): + v = Vector2() + v[:] = [1] + + self.assertRaises(ValueError, underpopulate) + + def assign_nonfloat(): + v = Vector2() + v[0] = "spam" + + self.assertRaises(TypeError, assign_nonfloat) + + def testExtendedSlicing(self): + # deletion + def delSlice(vec, start=None, stop=None, step=None): + if start is not None and stop is not None and step is not None: + del vec[start:stop:step] + elif start is not None and stop is None and step is not None: + del vec[start::step] + elif start is None and stop is None and step is not None: + del vec[::step] + + v = Vector2(self.v1) + self.assertRaises(TypeError, delSlice, v, None, None, 2) + self.assertRaises(TypeError, delSlice, v, 1, None, 2) + self.assertRaises(TypeError, delSlice, v, 1, 2, 1) + + # assignment + v = Vector2(self.v1) + v[::2] = [-1] + self.assertEqual(v, [-1, self.v1.y]) + v = Vector2(self.v1) + v[::-2] = [10] + self.assertEqual(v, [self.v1.x, 10]) + v = Vector2(self.v1) + v[::-1] = v + self.assertEqual(v, [self.v1.y, self.v1.x]) + a = Vector2(self.v1) + b = Vector2(self.v1) + c = Vector2(self.v1) + a[1:2] = [2.2] + b[slice(1, 2)] = [2.2] + c[1:2:] = (2.2,) + self.assertEqual(a, b) + self.assertEqual(a, c) + self.assertEqual(type(a), type(self.v1)) + self.assertEqual(type(b), type(self.v1)) + self.assertEqual(type(c), type(self.v1)) + + def testAdd(self): + v3 = self.v1 + self.v2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.v1.x + self.v2.x) + self.assertEqual(v3.y, self.v1.y + self.v2.y) + v3 = self.v1 + self.t2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.v1.x + self.t2[0]) + self.assertEqual(v3.y, self.v1.y + self.t2[1]) + v3 = self.v1 + self.l2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.v1.x + self.l2[0]) + self.assertEqual(v3.y, self.v1.y + self.l2[1]) + v3 = self.t1 + self.v2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.t1[0] + self.v2.x) + self.assertEqual(v3.y, self.t1[1] + self.v2.y) + v3 = self.l1 + self.v2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.l1[0] + self.v2.x) + self.assertEqual(v3.y, self.l1[1] + self.v2.y) + + def testSub(self): + v3 = self.v1 - self.v2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.v1.x - self.v2.x) + self.assertEqual(v3.y, self.v1.y - self.v2.y) + v3 = self.v1 - self.t2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.v1.x - self.t2[0]) + self.assertEqual(v3.y, self.v1.y - self.t2[1]) + v3 = self.v1 - self.l2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.v1.x - self.l2[0]) + self.assertEqual(v3.y, self.v1.y - self.l2[1]) + v3 = self.t1 - self.v2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.t1[0] - self.v2.x) + self.assertEqual(v3.y, self.t1[1] - self.v2.y) + v3 = self.l1 - self.v2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.l1[0] - self.v2.x) + self.assertEqual(v3.y, self.l1[1] - self.v2.y) + + def testScalarMultiplication(self): + v = self.s1 * self.v1 + self.assertTrue(isinstance(v, type(self.v1))) + self.assertEqual(v.x, self.s1 * self.v1.x) + self.assertEqual(v.y, self.s1 * self.v1.y) + v = self.v1 * self.s2 + self.assertEqual(v.x, self.v1.x * self.s2) + self.assertEqual(v.y, self.v1.y * self.s2) + + def testScalarDivision(self): + v = self.v1 / self.s1 + self.assertTrue(isinstance(v, type(self.v1))) + self.assertAlmostEqual(v.x, self.v1.x / self.s1) + self.assertAlmostEqual(v.y, self.v1.y / self.s1) + v = self.v1 // self.s2 + self.assertTrue(isinstance(v, type(self.v1))) + self.assertEqual(v.x, self.v1.x // self.s2) + self.assertEqual(v.y, self.v1.y // self.s2) + + def testBool(self): + self.assertEqual(bool(self.zeroVec), False) + self.assertEqual(bool(self.v1), True) + self.assertTrue(not self.zeroVec) + self.assertTrue(self.v1) + + def testUnary(self): + v = +self.v1 + self.assertTrue(isinstance(v, type(self.v1))) + self.assertEqual(v.x, self.v1.x) + self.assertEqual(v.y, self.v1.y) + self.assertNotEqual(id(v), id(self.v1)) + v = -self.v1 + self.assertTrue(isinstance(v, type(self.v1))) + self.assertEqual(v.x, -self.v1.x) + self.assertEqual(v.y, -self.v1.y) + self.assertNotEqual(id(v), id(self.v1)) + + def testCompare(self): + int_vec = Vector2(3, -2) + flt_vec = Vector2(3.0, -2.0) + zero_vec = Vector2(0, 0) + self.assertEqual(int_vec == flt_vec, True) + self.assertEqual(int_vec != flt_vec, False) + self.assertEqual(int_vec != zero_vec, True) + self.assertEqual(flt_vec == zero_vec, False) + self.assertEqual(int_vec == (3, -2), True) + self.assertEqual(int_vec != (3, -2), False) + self.assertEqual(int_vec != [0, 0], True) + self.assertEqual(int_vec == [0, 0], False) + self.assertEqual(int_vec != 5, True) + self.assertEqual(int_vec == 5, False) + self.assertEqual(int_vec != [3, -2, 0], True) + self.assertEqual(int_vec == [3, -2, 0], False) + + def testStr(self): + v = Vector2(1.2, 3.4) + self.assertEqual(str(v), "[1.2, 3.4]") + + def testRepr(self): + v = Vector2(1.2, 3.4) + self.assertEqual(v.__repr__(), "") + self.assertEqual(v, Vector2(v.__repr__())) + + def testIter(self): + it = self.v1.__iter__() + next_ = it.__next__ + self.assertEqual(next_(), self.v1[0]) + self.assertEqual(next_(), self.v1[1]) + self.assertRaises(StopIteration, lambda: next_()) + it1 = self.v1.__iter__() + it2 = self.v1.__iter__() + self.assertNotEqual(id(it1), id(it2)) + self.assertEqual(id(it1), id(it1.__iter__())) + self.assertEqual(list(it1), list(it2)) + self.assertEqual(list(self.v1.__iter__()), self.l1) + idx = 0 + for val in self.v1: + self.assertEqual(val, self.v1[idx]) + idx += 1 + + def test_rotate(self): + v1 = Vector2(1, 0) + v2 = v1.rotate(90) + v3 = v1.rotate(90 + 360) + self.assertEqual(v1.x, 1) + self.assertEqual(v1.y, 0) + self.assertEqual(v2.x, 0) + self.assertEqual(v2.y, 1) + self.assertEqual(v3.x, v2.x) + self.assertEqual(v3.y, v2.y) + v1 = Vector2(-1, -1) + v2 = v1.rotate(-90) + self.assertEqual(v2.x, -1) + self.assertEqual(v2.y, 1) + v2 = v1.rotate(360) + self.assertEqual(v1.x, v2.x) + self.assertEqual(v1.y, v2.y) + v2 = v1.rotate(0) + self.assertEqual(v1.x, v2.x) + self.assertEqual(v1.y, v2.y) + # issue 214 + self.assertEqual(Vector2(0, 1).rotate(359.99999999), Vector2(0, 1)) + + def test_rotate_rad(self): + tests = ( + ((1, 0), math.pi), + ((1, 0), math.pi / 2), + ((1, 0), -math.pi / 2), + ((1, 0), math.pi / 4), + ) + for initialVec, radians in tests: + self.assertEqual( + Vector2(initialVec).rotate_rad(radians), + (math.cos(radians), math.sin(radians)), + ) + + def test_rotate_ip(self): + v = Vector2(1, 0) + self.assertEqual(v.rotate_ip(90), None) + self.assertEqual(v.x, 0) + self.assertEqual(v.y, 1) + v = Vector2(-1, -1) + v.rotate_ip(-90) + self.assertEqual(v.x, -1) + self.assertEqual(v.y, 1) + + def test_rotate_rad_ip(self): + tests = ( + ((1, 0), math.pi), + ((1, 0), math.pi / 2), + ((1, 0), -math.pi / 2), + ((1, 0), math.pi / 4), + ) + for initialVec, radians in tests: + vec = Vector2(initialVec) + vec.rotate_rad_ip(radians) + self.assertEqual(vec, (math.cos(radians), math.sin(radians))) + + def test_normalize(self): + v = self.v1.normalize() + # length is 1 + self.assertAlmostEqual(v.x * v.x + v.y * v.y, 1.0) + # v1 is unchanged + self.assertEqual(self.v1.x, self.l1[0]) + self.assertEqual(self.v1.y, self.l1[1]) + # v2 is parallel to v1 + self.assertAlmostEqual(self.v1.x * v.y - self.v1.y * v.x, 0.0) + self.assertRaises(ValueError, lambda: self.zeroVec.normalize()) + + def test_normalize_ip(self): + v = +self.v1 + # v has length != 1 before normalizing + self.assertNotEqual(v.x * v.x + v.y * v.y, 1.0) + # inplace operations should return None + self.assertEqual(v.normalize_ip(), None) + # length is 1 + self.assertAlmostEqual(v.x * v.x + v.y * v.y, 1.0) + # v2 is parallel to v1 + self.assertAlmostEqual(self.v1.x * v.y - self.v1.y * v.x, 0.0) + self.assertRaises(ValueError, lambda: self.zeroVec.normalize_ip()) + + def test_is_normalized(self): + self.assertEqual(self.v1.is_normalized(), False) + v = self.v1.normalize() + self.assertEqual(v.is_normalized(), True) + self.assertEqual(self.e2.is_normalized(), True) + self.assertEqual(self.zeroVec.is_normalized(), False) + + def test_cross(self): + self.assertEqual( + self.v1.cross(self.v2), self.v1.x * self.v2.y - self.v1.y * self.v2.x + ) + self.assertEqual( + self.v1.cross(self.l2), self.v1.x * self.l2[1] - self.v1.y * self.l2[0] + ) + self.assertEqual( + self.v1.cross(self.t2), self.v1.x * self.t2[1] - self.v1.y * self.t2[0] + ) + self.assertEqual(self.v1.cross(self.v2), -self.v2.cross(self.v1)) + self.assertEqual(self.v1.cross(self.v1), 0) + + def test_dot(self): + self.assertAlmostEqual( + self.v1.dot(self.v2), self.v1.x * self.v2.x + self.v1.y * self.v2.y + ) + self.assertAlmostEqual( + self.v1.dot(self.l2), self.v1.x * self.l2[0] + self.v1.y * self.l2[1] + ) + self.assertAlmostEqual( + self.v1.dot(self.t2), self.v1.x * self.t2[0] + self.v1.y * self.t2[1] + ) + self.assertEqual(self.v1.dot(self.v2), self.v2.dot(self.v1)) + self.assertEqual(self.v1.dot(self.v2), self.v1 * self.v2) + + def test_angle_to(self): + self.assertEqual( + self.v1.rotate(self.v1.angle_to(self.v2)).normalize(), self.v2.normalize() + ) + self.assertEqual(Vector2(1, 1).angle_to((-1, 1)), 90) + self.assertEqual(Vector2(1, 0).angle_to((0, -1)), -90) + self.assertEqual(Vector2(1, 0).angle_to((-1, 1)), 135) + self.assertEqual(abs(Vector2(1, 0).angle_to((-1, 0))), 180) + + def test_scale_to_length(self): + v = Vector2(1, 1) + v.scale_to_length(2.5) + self.assertEqual(v, Vector2(2.5, 2.5) / math.sqrt(2)) + self.assertRaises(ValueError, lambda: self.zeroVec.scale_to_length(1)) + self.assertEqual(v.scale_to_length(0), None) + self.assertEqual(v, self.zeroVec) + + def test_length(self): + self.assertEqual(Vector2(3, 4).length(), 5) + self.assertEqual(Vector2(-3, 4).length(), 5) + self.assertEqual(self.zeroVec.length(), 0) + + def test_length_squared(self): + self.assertEqual(Vector2(3, 4).length_squared(), 25) + self.assertEqual(Vector2(-3, 4).length_squared(), 25) + self.assertEqual(self.zeroVec.length_squared(), 0) + + def test_reflect(self): + v = Vector2(1, -1) + n = Vector2(0, 1) + self.assertEqual(v.reflect(n), Vector2(1, 1)) + self.assertEqual(v.reflect(3 * n), v.reflect(n)) + self.assertEqual(v.reflect(-v), -v) + self.assertRaises(ValueError, lambda: v.reflect(self.zeroVec)) + + def test_reflect_ip(self): + v1 = Vector2(1, -1) + v2 = Vector2(v1) + n = Vector2(0, 1) + self.assertEqual(v2.reflect_ip(n), None) + self.assertEqual(v2, Vector2(1, 1)) + v2 = Vector2(v1) + v2.reflect_ip(3 * n) + self.assertEqual(v2, v1.reflect(n)) + v2 = Vector2(v1) + v2.reflect_ip(-v1) + self.assertEqual(v2, -v1) + self.assertRaises(ValueError, lambda: v2.reflect_ip(Vector2())) + + def test_distance_to(self): + diff = self.v1 - self.v2 + self.assertEqual(self.e1.distance_to(self.e2), math.sqrt(2)) + self.assertAlmostEqual( + self.v1.distance_to(self.v2), math.sqrt(diff.x * diff.x + diff.y * diff.y) + ) + self.assertEqual(self.v1.distance_to(self.v1), 0) + self.assertEqual(self.v1.distance_to(self.v2), self.v2.distance_to(self.v1)) + + def test_distance_squared_to(self): + diff = self.v1 - self.v2 + self.assertEqual(self.e1.distance_squared_to(self.e2), 2) + self.assertAlmostEqual( + self.v1.distance_squared_to(self.v2), diff.x * diff.x + diff.y * diff.y + ) + self.assertEqual(self.v1.distance_squared_to(self.v1), 0) + self.assertEqual( + self.v1.distance_squared_to(self.v2), self.v2.distance_squared_to(self.v1) + ) + + def test_update(self): + v = Vector2(3, 4) + v.update(0) + self.assertEqual(v, Vector2((0, 0))) + v.update(5, 1) + self.assertEqual(v, Vector2(5, 1)) + v.update((4, 1)) + self.assertNotEqual(v, Vector2((5, 1))) + + def test_swizzle(self): + self.assertEqual(self.v1.yx, (self.v1.y, self.v1.x)) + self.assertEqual( + self.v1.xxyyxy, + (self.v1.x, self.v1.x, self.v1.y, self.v1.y, self.v1.x, self.v1.y), + ) + self.v1.xy = self.t2 + self.assertEqual(self.v1, self.t2) + self.v1.yx = self.t2 + self.assertEqual(self.v1, (self.t2[1], self.t2[0])) + self.assertEqual(type(self.v1), Vector2) + + def invalidSwizzleX(): + Vector2().xx = (1, 2) + + def invalidSwizzleY(): + Vector2().yy = (1, 2) + + self.assertRaises(AttributeError, invalidSwizzleX) + self.assertRaises(AttributeError, invalidSwizzleY) + + def invalidAssignment(): + Vector2().xy = 3 + + self.assertRaises(TypeError, invalidAssignment) + + def unicodeAttribute(): + getattr(Vector2(), "ä") + + self.assertRaises(AttributeError, unicodeAttribute) + + def test_swizzle_return_types(self): + self.assertEqual(type(self.v1.x), float) + self.assertEqual(type(self.v1.xy), Vector2) + self.assertEqual(type(self.v1.xyx), Vector3) + # but we don't have vector4 or above... so tuple. + self.assertEqual(type(self.v1.xyxy), tuple) + self.assertEqual(type(self.v1.xyxyx), tuple) + + def test_elementwise(self): + # behaviour for "elementwise op scalar" + self.assertEqual( + self.v1.elementwise() + self.s1, (self.v1.x + self.s1, self.v1.y + self.s1) + ) + self.assertEqual( + self.v1.elementwise() - self.s1, (self.v1.x - self.s1, self.v1.y - self.s1) + ) + self.assertEqual( + self.v1.elementwise() * self.s2, (self.v1.x * self.s2, self.v1.y * self.s2) + ) + self.assertEqual( + self.v1.elementwise() / self.s2, (self.v1.x / self.s2, self.v1.y / self.s2) + ) + self.assertEqual( + self.v1.elementwise() // self.s1, + (self.v1.x // self.s1, self.v1.y // self.s1), + ) + self.assertEqual( + self.v1.elementwise() ** self.s1, + (self.v1.x ** self.s1, self.v1.y ** self.s1), + ) + self.assertEqual( + self.v1.elementwise() % self.s1, (self.v1.x % self.s1, self.v1.y % self.s1) + ) + self.assertEqual( + self.v1.elementwise() > self.s1, self.v1.x > self.s1 and self.v1.y > self.s1 + ) + self.assertEqual( + self.v1.elementwise() < self.s1, self.v1.x < self.s1 and self.v1.y < self.s1 + ) + self.assertEqual( + self.v1.elementwise() == self.s1, + self.v1.x == self.s1 and self.v1.y == self.s1, + ) + self.assertEqual( + self.v1.elementwise() != self.s1, + self.v1.x != self.s1 and self.v1.y != self.s1, + ) + self.assertEqual( + self.v1.elementwise() >= self.s1, + self.v1.x >= self.s1 and self.v1.y >= self.s1, + ) + self.assertEqual( + self.v1.elementwise() <= self.s1, + self.v1.x <= self.s1 and self.v1.y <= self.s1, + ) + self.assertEqual( + self.v1.elementwise() != self.s1, + self.v1.x != self.s1 and self.v1.y != self.s1, + ) + # behaviour for "scalar op elementwise" + self.assertEqual(5 + self.v1.elementwise(), Vector2(5, 5) + self.v1) + self.assertEqual(3.5 - self.v1.elementwise(), Vector2(3.5, 3.5) - self.v1) + self.assertEqual(7.5 * self.v1.elementwise(), 7.5 * self.v1) + self.assertEqual( + -3.5 / self.v1.elementwise(), (-3.5 / self.v1.x, -3.5 / self.v1.y) + ) + self.assertEqual( + -3.5 // self.v1.elementwise(), (-3.5 // self.v1.x, -3.5 // self.v1.y) + ) + self.assertEqual( + -(3.5 ** self.v1.elementwise()), (-(3.5 ** self.v1.x), -(3.5 ** self.v1.y)) + ) + self.assertEqual(3 % self.v1.elementwise(), (3 % self.v1.x, 3 % self.v1.y)) + self.assertEqual(2 < self.v1.elementwise(), 2 < self.v1.x and 2 < self.v1.y) + self.assertEqual(2 > self.v1.elementwise(), 2 > self.v1.x and 2 > self.v1.y) + self.assertEqual(1 == self.v1.elementwise(), 1 == self.v1.x and 1 == self.v1.y) + self.assertEqual(1 != self.v1.elementwise(), 1 != self.v1.x and 1 != self.v1.y) + self.assertEqual(2 <= self.v1.elementwise(), 2 <= self.v1.x and 2 <= self.v1.y) + self.assertEqual( + -7 >= self.v1.elementwise(), -7 >= self.v1.x and -7 >= self.v1.y + ) + self.assertEqual( + -7 != self.v1.elementwise(), -7 != self.v1.x and -7 != self.v1.y + ) + + # behaviour for "elementwise op vector" + self.assertEqual(type(self.v1.elementwise() * self.v2), type(self.v1)) + self.assertEqual(self.v1.elementwise() + self.v2, self.v1 + self.v2) + self.assertEqual(self.v1.elementwise() + self.v2, self.v1 + self.v2) + self.assertEqual(self.v1.elementwise() - self.v2, self.v1 - self.v2) + self.assertEqual( + self.v1.elementwise() * self.v2, + (self.v1.x * self.v2.x, self.v1.y * self.v2.y), + ) + self.assertEqual( + self.v1.elementwise() / self.v2, + (self.v1.x / self.v2.x, self.v1.y / self.v2.y), + ) + self.assertEqual( + self.v1.elementwise() // self.v2, + (self.v1.x // self.v2.x, self.v1.y // self.v2.y), + ) + self.assertEqual( + self.v1.elementwise() ** self.v2, + (self.v1.x ** self.v2.x, self.v1.y ** self.v2.y), + ) + self.assertEqual( + self.v1.elementwise() % self.v2, + (self.v1.x % self.v2.x, self.v1.y % self.v2.y), + ) + self.assertEqual( + self.v1.elementwise() > self.v2, + self.v1.x > self.v2.x and self.v1.y > self.v2.y, + ) + self.assertEqual( + self.v1.elementwise() < self.v2, + self.v1.x < self.v2.x and self.v1.y < self.v2.y, + ) + self.assertEqual( + self.v1.elementwise() >= self.v2, + self.v1.x >= self.v2.x and self.v1.y >= self.v2.y, + ) + self.assertEqual( + self.v1.elementwise() <= self.v2, + self.v1.x <= self.v2.x and self.v1.y <= self.v2.y, + ) + self.assertEqual( + self.v1.elementwise() == self.v2, + self.v1.x == self.v2.x and self.v1.y == self.v2.y, + ) + self.assertEqual( + self.v1.elementwise() != self.v2, + self.v1.x != self.v2.x and self.v1.y != self.v2.y, + ) + # behaviour for "vector op elementwise" + self.assertEqual(self.v2 + self.v1.elementwise(), self.v2 + self.v1) + self.assertEqual(self.v2 - self.v1.elementwise(), self.v2 - self.v1) + self.assertEqual( + self.v2 * self.v1.elementwise(), + (self.v2.x * self.v1.x, self.v2.y * self.v1.y), + ) + self.assertEqual( + self.v2 / self.v1.elementwise(), + (self.v2.x / self.v1.x, self.v2.y / self.v1.y), + ) + self.assertEqual( + self.v2 // self.v1.elementwise(), + (self.v2.x // self.v1.x, self.v2.y // self.v1.y), + ) + self.assertEqual( + self.v2 ** self.v1.elementwise(), + (self.v2.x ** self.v1.x, self.v2.y ** self.v1.y), + ) + self.assertEqual( + self.v2 % self.v1.elementwise(), + (self.v2.x % self.v1.x, self.v2.y % self.v1.y), + ) + self.assertEqual( + self.v2 < self.v1.elementwise(), + self.v2.x < self.v1.x and self.v2.y < self.v1.y, + ) + self.assertEqual( + self.v2 > self.v1.elementwise(), + self.v2.x > self.v1.x and self.v2.y > self.v1.y, + ) + self.assertEqual( + self.v2 <= self.v1.elementwise(), + self.v2.x <= self.v1.x and self.v2.y <= self.v1.y, + ) + self.assertEqual( + self.v2 >= self.v1.elementwise(), + self.v2.x >= self.v1.x and self.v2.y >= self.v1.y, + ) + self.assertEqual( + self.v2 == self.v1.elementwise(), + self.v2.x == self.v1.x and self.v2.y == self.v1.y, + ) + self.assertEqual( + self.v2 != self.v1.elementwise(), + self.v2.x != self.v1.x and self.v2.y != self.v1.y, + ) + + # behaviour for "elementwise op elementwise" + self.assertEqual( + self.v2.elementwise() + self.v1.elementwise(), self.v2 + self.v1 + ) + self.assertEqual( + self.v2.elementwise() - self.v1.elementwise(), self.v2 - self.v1 + ) + self.assertEqual( + self.v2.elementwise() * self.v1.elementwise(), + (self.v2.x * self.v1.x, self.v2.y * self.v1.y), + ) + self.assertEqual( + self.v2.elementwise() / self.v1.elementwise(), + (self.v2.x / self.v1.x, self.v2.y / self.v1.y), + ) + self.assertEqual( + self.v2.elementwise() // self.v1.elementwise(), + (self.v2.x // self.v1.x, self.v2.y // self.v1.y), + ) + self.assertEqual( + self.v2.elementwise() ** self.v1.elementwise(), + (self.v2.x ** self.v1.x, self.v2.y ** self.v1.y), + ) + self.assertEqual( + self.v2.elementwise() % self.v1.elementwise(), + (self.v2.x % self.v1.x, self.v2.y % self.v1.y), + ) + self.assertEqual( + self.v2.elementwise() < self.v1.elementwise(), + self.v2.x < self.v1.x and self.v2.y < self.v1.y, + ) + self.assertEqual( + self.v2.elementwise() > self.v1.elementwise(), + self.v2.x > self.v1.x and self.v2.y > self.v1.y, + ) + self.assertEqual( + self.v2.elementwise() <= self.v1.elementwise(), + self.v2.x <= self.v1.x and self.v2.y <= self.v1.y, + ) + self.assertEqual( + self.v2.elementwise() >= self.v1.elementwise(), + self.v2.x >= self.v1.x and self.v2.y >= self.v1.y, + ) + self.assertEqual( + self.v2.elementwise() == self.v1.elementwise(), + self.v2.x == self.v1.x and self.v2.y == self.v1.y, + ) + self.assertEqual( + self.v2.elementwise() != self.v1.elementwise(), + self.v2.x != self.v1.x and self.v2.y != self.v1.y, + ) + + # other behaviour + self.assertEqual(abs(self.v1.elementwise()), (abs(self.v1.x), abs(self.v1.y))) + self.assertEqual(-self.v1.elementwise(), -self.v1) + self.assertEqual(+self.v1.elementwise(), +self.v1) + self.assertEqual(bool(self.v1.elementwise()), bool(self.v1)) + self.assertEqual(bool(Vector2().elementwise()), bool(Vector2())) + self.assertEqual(self.zeroVec.elementwise() ** 0, (1, 1)) + self.assertRaises(ValueError, lambda: pow(Vector2(-1, 0).elementwise(), 1.2)) + self.assertRaises(ZeroDivisionError, lambda: self.zeroVec.elementwise() ** -1) + + def test_elementwise(self): + v1 = self.v1 + v2 = self.v2 + s1 = self.s1 + s2 = self.s2 + # behaviour for "elementwise op scalar" + self.assertEqual(v1.elementwise() + s1, (v1.x + s1, v1.y + s1)) + self.assertEqual(v1.elementwise() - s1, (v1.x - s1, v1.y - s1)) + self.assertEqual(v1.elementwise() * s2, (v1.x * s2, v1.y * s2)) + self.assertEqual(v1.elementwise() / s2, (v1.x / s2, v1.y / s2)) + self.assertEqual(v1.elementwise() // s1, (v1.x // s1, v1.y // s1)) + self.assertEqual(v1.elementwise() ** s1, (v1.x ** s1, v1.y ** s1)) + self.assertEqual(v1.elementwise() % s1, (v1.x % s1, v1.y % s1)) + self.assertEqual(v1.elementwise() > s1, v1.x > s1 and v1.y > s1) + self.assertEqual(v1.elementwise() < s1, v1.x < s1 and v1.y < s1) + self.assertEqual(v1.elementwise() == s1, v1.x == s1 and v1.y == s1) + self.assertEqual(v1.elementwise() != s1, s1 not in [v1.x, v1.y]) + self.assertEqual(v1.elementwise() >= s1, v1.x >= s1 and v1.y >= s1) + self.assertEqual(v1.elementwise() <= s1, v1.x <= s1 and v1.y <= s1) + self.assertEqual(v1.elementwise() != s1, s1 not in [v1.x, v1.y]) + # behaviour for "scalar op elementwise" + self.assertEqual(s1 + v1.elementwise(), (s1 + v1.x, s1 + v1.y)) + self.assertEqual(s1 - v1.elementwise(), (s1 - v1.x, s1 - v1.y)) + self.assertEqual(s1 * v1.elementwise(), (s1 * v1.x, s1 * v1.y)) + self.assertEqual(s1 / v1.elementwise(), (s1 / v1.x, s1 / v1.y)) + self.assertEqual(s1 // v1.elementwise(), (s1 // v1.x, s1 // v1.y)) + self.assertEqual(s1 ** v1.elementwise(), (s1 ** v1.x, s1 ** v1.y)) + self.assertEqual(s1 % v1.elementwise(), (s1 % v1.x, s1 % v1.y)) + self.assertEqual(s1 < v1.elementwise(), s1 < v1.x and s1 < v1.y) + self.assertEqual(s1 > v1.elementwise(), s1 > v1.x and s1 > v1.y) + self.assertEqual(s1 == v1.elementwise(), s1 == v1.x and s1 == v1.y) + self.assertEqual(s1 != v1.elementwise(), s1 not in [v1.x, v1.y]) + self.assertEqual(s1 <= v1.elementwise(), s1 <= v1.x and s1 <= v1.y) + self.assertEqual(s1 >= v1.elementwise(), s1 >= v1.x and s1 >= v1.y) + self.assertEqual(s1 != v1.elementwise(), s1 not in [v1.x, v1.y]) + + # behaviour for "elementwise op vector" + self.assertEqual(type(v1.elementwise() * v2), type(v1)) + self.assertEqual(v1.elementwise() + v2, v1 + v2) + self.assertEqual(v1.elementwise() - v2, v1 - v2) + self.assertEqual(v1.elementwise() * v2, (v1.x * v2.x, v1.y * v2.y)) + self.assertEqual(v1.elementwise() / v2, (v1.x / v2.x, v1.y / v2.y)) + self.assertEqual(v1.elementwise() // v2, (v1.x // v2.x, v1.y // v2.y)) + self.assertEqual(v1.elementwise() ** v2, (v1.x ** v2.x, v1.y ** v2.y)) + self.assertEqual(v1.elementwise() % v2, (v1.x % v2.x, v1.y % v2.y)) + self.assertEqual(v1.elementwise() > v2, v1.x > v2.x and v1.y > v2.y) + self.assertEqual(v1.elementwise() < v2, v1.x < v2.x and v1.y < v2.y) + self.assertEqual(v1.elementwise() >= v2, v1.x >= v2.x and v1.y >= v2.y) + self.assertEqual(v1.elementwise() <= v2, v1.x <= v2.x and v1.y <= v2.y) + self.assertEqual(v1.elementwise() == v2, v1.x == v2.x and v1.y == v2.y) + self.assertEqual(v1.elementwise() != v2, v1.x != v2.x and v1.y != v2.y) + # behaviour for "vector op elementwise" + self.assertEqual(v2 + v1.elementwise(), v2 + v1) + self.assertEqual(v2 - v1.elementwise(), v2 - v1) + self.assertEqual(v2 * v1.elementwise(), (v2.x * v1.x, v2.y * v1.y)) + self.assertEqual(v2 / v1.elementwise(), (v2.x / v1.x, v2.y / v1.y)) + self.assertEqual(v2 // v1.elementwise(), (v2.x // v1.x, v2.y // v1.y)) + self.assertEqual(v2 ** v1.elementwise(), (v2.x ** v1.x, v2.y ** v1.y)) + self.assertEqual(v2 % v1.elementwise(), (v2.x % v1.x, v2.y % v1.y)) + self.assertEqual(v2 < v1.elementwise(), v2.x < v1.x and v2.y < v1.y) + self.assertEqual(v2 > v1.elementwise(), v2.x > v1.x and v2.y > v1.y) + self.assertEqual(v2 <= v1.elementwise(), v2.x <= v1.x and v2.y <= v1.y) + self.assertEqual(v2 >= v1.elementwise(), v2.x >= v1.x and v2.y >= v1.y) + self.assertEqual(v2 == v1.elementwise(), v2.x == v1.x and v2.y == v1.y) + self.assertEqual(v2 != v1.elementwise(), v2.x != v1.x and v2.y != v1.y) + + # behaviour for "elementwise op elementwise" + self.assertEqual(v2.elementwise() + v1.elementwise(), v2 + v1) + self.assertEqual(v2.elementwise() - v1.elementwise(), v2 - v1) + self.assertEqual( + v2.elementwise() * v1.elementwise(), (v2.x * v1.x, v2.y * v1.y) + ) + self.assertEqual( + v2.elementwise() / v1.elementwise(), (v2.x / v1.x, v2.y / v1.y) + ) + self.assertEqual( + v2.elementwise() // v1.elementwise(), (v2.x // v1.x, v2.y // v1.y) + ) + self.assertEqual( + v2.elementwise() ** v1.elementwise(), (v2.x ** v1.x, v2.y ** v1.y) + ) + self.assertEqual( + v2.elementwise() % v1.elementwise(), (v2.x % v1.x, v2.y % v1.y) + ) + self.assertEqual( + v2.elementwise() < v1.elementwise(), v2.x < v1.x and v2.y < v1.y + ) + self.assertEqual( + v2.elementwise() > v1.elementwise(), v2.x > v1.x and v2.y > v1.y + ) + self.assertEqual( + v2.elementwise() <= v1.elementwise(), v2.x <= v1.x and v2.y <= v1.y + ) + self.assertEqual( + v2.elementwise() >= v1.elementwise(), v2.x >= v1.x and v2.y >= v1.y + ) + self.assertEqual( + v2.elementwise() == v1.elementwise(), v2.x == v1.x and v2.y == v1.y + ) + self.assertEqual( + v2.elementwise() != v1.elementwise(), v2.x != v1.x and v2.y != v1.y + ) + + # other behaviour + self.assertEqual(abs(v1.elementwise()), (abs(v1.x), abs(v1.y))) + self.assertEqual(-v1.elementwise(), -v1) + self.assertEqual(+v1.elementwise(), +v1) + self.assertEqual(bool(v1.elementwise()), bool(v1)) + self.assertEqual(bool(Vector2().elementwise()), bool(Vector2())) + self.assertEqual(self.zeroVec.elementwise() ** 0, (1, 1)) + self.assertRaises(ValueError, lambda: pow(Vector2(-1, 0).elementwise(), 1.2)) + self.assertRaises(ZeroDivisionError, lambda: self.zeroVec.elementwise() ** -1) + self.assertRaises(ZeroDivisionError, lambda: self.zeroVec.elementwise() ** -1) + self.assertRaises(ZeroDivisionError, lambda: Vector2(1, 1).elementwise() / 0) + self.assertRaises(ZeroDivisionError, lambda: Vector2(1, 1).elementwise() // 0) + self.assertRaises(ZeroDivisionError, lambda: Vector2(1, 1).elementwise() % 0) + self.assertRaises( + ZeroDivisionError, lambda: Vector2(1, 1).elementwise() / self.zeroVec + ) + self.assertRaises( + ZeroDivisionError, lambda: Vector2(1, 1).elementwise() // self.zeroVec + ) + self.assertRaises( + ZeroDivisionError, lambda: Vector2(1, 1).elementwise() % self.zeroVec + ) + self.assertRaises(ZeroDivisionError, lambda: 2 / self.zeroVec.elementwise()) + self.assertRaises(ZeroDivisionError, lambda: 2 // self.zeroVec.elementwise()) + self.assertRaises(ZeroDivisionError, lambda: 2 % self.zeroVec.elementwise()) + + def test_slerp(self): + self.assertRaises(ValueError, lambda: self.zeroVec.slerp(self.v1, 0.5)) + self.assertRaises(ValueError, lambda: self.v1.slerp(self.zeroVec, 0.5)) + self.assertRaises(ValueError, lambda: self.zeroVec.slerp(self.zeroVec, 0.5)) + v1 = Vector2(1, 0) + v2 = Vector2(0, 1) + steps = 10 + angle_step = v1.angle_to(v2) / steps + for i, u in ((i, v1.slerp(v2, i / float(steps))) for i in range(steps + 1)): + self.assertAlmostEqual(u.length(), 1) + self.assertAlmostEqual(v1.angle_to(u), i * angle_step) + self.assertEqual(u, v2) + + v1 = Vector2(100, 0) + v2 = Vector2(0, 10) + radial_factor = v2.length() / v1.length() + for i, u in ((i, v1.slerp(v2, -i / float(steps))) for i in range(steps + 1)): + self.assertAlmostEqual( + u.length(), + (v2.length() - v1.length()) * (float(i) / steps) + v1.length(), + ) + self.assertEqual(u, v2) + self.assertEqual(v1.slerp(v1, 0.5), v1) + self.assertEqual(v2.slerp(v2, 0.5), v2) + self.assertRaises(ValueError, lambda: v1.slerp(-v1, 0.5)) + + def test_lerp(self): + v1 = Vector2(0, 0) + v2 = Vector2(10, 10) + self.assertEqual(v1.lerp(v2, 0.5), (5, 5)) + self.assertRaises(ValueError, lambda: v1.lerp(v2, 2.5)) + + v1 = Vector2(-10, -5) + v2 = Vector2(10, 10) + self.assertEqual(v1.lerp(v2, 0.5), (0, 2.5)) + + def test_polar(self): + v = Vector2() + v.from_polar(self.v1.as_polar()) + self.assertEqual(self.v1, v) + self.assertEqual(self.e1.as_polar(), (1, 0)) + self.assertEqual(self.e2.as_polar(), (1, 90)) + self.assertEqual((2 * self.e2).as_polar(), (2, 90)) + self.assertRaises(TypeError, lambda: v.from_polar((None, None))) + self.assertRaises(TypeError, lambda: v.from_polar("ab")) + self.assertRaises(TypeError, lambda: v.from_polar((None, 1))) + self.assertRaises(TypeError, lambda: v.from_polar((1, 2, 3))) + self.assertRaises(TypeError, lambda: v.from_polar((1,))) + self.assertRaises(TypeError, lambda: v.from_polar(1, 2)) + v.from_polar((0.5, 90)) + self.assertEqual(v, 0.5 * self.e2) + v.from_polar((1, 0)) + self.assertEqual(v, self.e1) + + def test_subclass_operation(self): + class Vector(pygame.math.Vector2): + pass + + vec = Vector() + + vec_a = Vector(2, 0) + vec_b = Vector(0, 1) + + vec_a + vec_b + vec_a *= 2 + + def test_project_v2_onto_x_axis(self): + """Project onto x-axis, e.g. get the component pointing in the x-axis direction.""" + # arrange + v = Vector2(2, 2) + x_axis = Vector2(10, 0) + + # act + actual = v.project(x_axis) + + # assert + self.assertEqual(v.x, actual.x) + self.assertEqual(0, actual.y) + + def test_project_v2_onto_y_axis(self): + """Project onto y-axis, e.g. get the component pointing in the y-axis direction.""" + # arrange + v = Vector2(2, 2) + y_axis = Vector2(0, 100) + + # act + actual = v.project(y_axis) + + # assert + self.assertEqual(0, actual.x) + self.assertEqual(v.y, actual.y) + + def test_project_v2_onto_other(self): + """Project onto other vector.""" + # arrange + v = Vector2(2, 3) + other = Vector2(3, 5) + + # act + actual = v.project(other) + + # assert + expected = v.dot(other) / other.dot(other) * other + self.assertEqual(expected.x, actual.x) + self.assertEqual(expected.y, actual.y) + + def test_project_v2_raises_if_other_has_zero_length(self): + """Check if exception is raise when projected on vector has zero length.""" + # arrange + v = Vector2(2, 3) + other = Vector2(0, 0) + + # act / assert + self.assertRaises(ValueError, v.project, other) + + def test_project_v2_onto_other_as_tuple(self): + """Project onto other tuple as vector.""" + # arrange + v = Vector2(2, 3) + other = Vector2(3, 5) + + # act + actual = v.project(tuple(other)) + + # assert + expected = v.dot(other) / other.dot(other) * other + self.assertEqual(expected.x, actual.x) + self.assertEqual(expected.y, actual.y) + + def test_project_v2_onto_other_as_list(self): + """Project onto other list as vector.""" + # arrange + v = Vector2(2, 3) + other = Vector2(3, 5) + + # act + actual = v.project(list(other)) + + # assert + expected = v.dot(other) / other.dot(other) * other + self.assertEqual(expected.x, actual.x) + self.assertEqual(expected.y, actual.y) + + def test_project_v2_raises_if_other_has_zero_length(self): + """Check if exception is raise when projected on vector has zero length.""" + # arrange + v = Vector2(2, 3) + other = Vector2(0, 0) + + # act / assert + self.assertRaises(ValueError, v.project, other) + + def test_project_v2_raises_if_other_is_not_iterable(self): + """Check if exception is raise when projected on vector is not iterable.""" + # arrange + v = Vector2(2, 3) + other = 10 + + # act / assert + self.assertRaises(TypeError, v.project, other) + + +class Vector3TypeTest(unittest.TestCase): + def setUp(self): + self.zeroVec = Vector3() + self.e1 = Vector3(1, 0, 0) + self.e2 = Vector3(0, 1, 0) + self.e3 = Vector3(0, 0, 1) + self.t1 = (1.2, 3.4, 9.6) + self.l1 = list(self.t1) + self.v1 = Vector3(self.t1) + self.t2 = (5.6, 7.8, 2.1) + self.l2 = list(self.t2) + self.v2 = Vector3(self.t2) + self.s1 = 5.6 + self.s2 = 7.8 + + def testConstructionDefault(self): + v = Vector3() + self.assertEqual(v.x, 0.0) + self.assertEqual(v.y, 0.0) + self.assertEqual(v.z, 0.0) + + def testConstructionXYZ(self): + v = Vector3(1.2, 3.4, 9.6) + self.assertEqual(v.x, 1.2) + self.assertEqual(v.y, 3.4) + self.assertEqual(v.z, 9.6) + + def testConstructionTuple(self): + v = Vector3((1.2, 3.4, 9.6)) + self.assertEqual(v.x, 1.2) + self.assertEqual(v.y, 3.4) + self.assertEqual(v.z, 9.6) + + def testConstructionList(self): + v = Vector3([1.2, 3.4, -9.6]) + self.assertEqual(v.x, 1.2) + self.assertEqual(v.y, 3.4) + self.assertEqual(v.z, -9.6) + + def testConstructionVector3(self): + v = Vector3(Vector3(1.2, 3.4, -9.6)) + self.assertEqual(v.x, 1.2) + self.assertEqual(v.y, 3.4) + self.assertEqual(v.z, -9.6) + + def testConstructionScalar(self): + v = Vector3(1) + self.assertEqual(v.x, 1.0) + self.assertEqual(v.y, 1.0) + self.assertEqual(v.z, 1.0) + + def testConstructionScalarKeywords(self): + v = Vector3(x=1) + self.assertEqual(v.x, 1.0) + self.assertEqual(v.y, 1.0) + self.assertEqual(v.z, 1.0) + + def testConstructionKeywords(self): + v = Vector3(x=1, y=2, z=3) + self.assertEqual(v.x, 1.0) + self.assertEqual(v.y, 2.0) + self.assertEqual(v.z, 3.0) + + def testConstructionMissing(self): + def assign_missing_value(): + v = Vector3(1, 2) + + self.assertRaises(ValueError, assign_missing_value) + + def assign_missing_value(): + v = Vector3(x=1, y=2) + + self.assertRaises(ValueError, assign_missing_value) + + def testAttributeAccess(self): + tmp = self.v1.x + self.assertEqual(tmp, self.v1.x) + self.assertEqual(tmp, self.v1[0]) + tmp = self.v1.y + self.assertEqual(tmp, self.v1.y) + self.assertEqual(tmp, self.v1[1]) + tmp = self.v1.z + self.assertEqual(tmp, self.v1.z) + self.assertEqual(tmp, self.v1[2]) + self.v1.x = 3.141 + self.assertEqual(self.v1.x, 3.141) + self.v1.y = 3.141 + self.assertEqual(self.v1.y, 3.141) + self.v1.z = 3.141 + self.assertEqual(self.v1.z, 3.141) + + def assign_nonfloat(): + v = Vector2() + v.x = "spam" + + self.assertRaises(TypeError, assign_nonfloat) + + def testSequence(self): + v = Vector3(1.2, 3.4, -9.6) + self.assertEqual(len(v), 3) + self.assertEqual(v[0], 1.2) + self.assertEqual(v[1], 3.4) + self.assertEqual(v[2], -9.6) + self.assertRaises(IndexError, lambda: v[3]) + self.assertEqual(v[-1], -9.6) + self.assertEqual(v[-2], 3.4) + self.assertEqual(v[-3], 1.2) + self.assertRaises(IndexError, lambda: v[-4]) + self.assertEqual(v[:], [1.2, 3.4, -9.6]) + self.assertEqual(v[1:], [3.4, -9.6]) + self.assertEqual(v[:1], [1.2]) + self.assertEqual(v[:-1], [1.2, 3.4]) + self.assertEqual(v[1:2], [3.4]) + self.assertEqual(list(v), [1.2, 3.4, -9.6]) + self.assertEqual(tuple(v), (1.2, 3.4, -9.6)) + v[0] = 5.6 + v[1] = 7.8 + v[2] = -2.1 + self.assertEqual(v.x, 5.6) + self.assertEqual(v.y, 7.8) + self.assertEqual(v.z, -2.1) + v[:] = [9.1, 11.12, -13.41] + self.assertEqual(v.x, 9.1) + self.assertEqual(v.y, 11.12) + self.assertEqual(v.z, -13.41) + + def overpopulate(): + v = Vector3() + v[:] = [1, 2, 3, 4] + + self.assertRaises(ValueError, overpopulate) + + def underpopulate(): + v = Vector3() + v[:] = [1] + + self.assertRaises(ValueError, underpopulate) + + def assign_nonfloat(): + v = Vector2() + v[0] = "spam" + + self.assertRaises(TypeError, assign_nonfloat) + + def testExtendedSlicing(self): + # deletion + def delSlice(vec, start=None, stop=None, step=None): + if start is not None and stop is not None and step is not None: + del vec[start:stop:step] + elif start is not None and stop is None and step is not None: + del vec[start::step] + elif start is None and stop is None and step is not None: + del vec[::step] + + v = Vector3(self.v1) + self.assertRaises(TypeError, delSlice, v, None, None, 2) + self.assertRaises(TypeError, delSlice, v, 1, None, 2) + self.assertRaises(TypeError, delSlice, v, 1, 2, 1) + + # assignment + v = Vector3(self.v1) + v[::2] = [-1.1, -2.2] + self.assertEqual(v, [-1.1, self.v1.y, -2.2]) + v = Vector3(self.v1) + v[::-2] = [10, 20] + self.assertEqual(v, [20, self.v1.y, 10]) + v = Vector3(self.v1) + v[::-1] = v + self.assertEqual(v, [self.v1.z, self.v1.y, self.v1.x]) + a = Vector3(self.v1) + b = Vector3(self.v1) + c = Vector3(self.v1) + a[1:2] = [2.2] + b[slice(1, 2)] = [2.2] + c[1:2:] = (2.2,) + self.assertEqual(a, b) + self.assertEqual(a, c) + self.assertEqual(type(a), type(self.v1)) + self.assertEqual(type(b), type(self.v1)) + self.assertEqual(type(c), type(self.v1)) + + def testAdd(self): + v3 = self.v1 + self.v2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.v1.x + self.v2.x) + self.assertEqual(v3.y, self.v1.y + self.v2.y) + self.assertEqual(v3.z, self.v1.z + self.v2.z) + v3 = self.v1 + self.t2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.v1.x + self.t2[0]) + self.assertEqual(v3.y, self.v1.y + self.t2[1]) + self.assertEqual(v3.z, self.v1.z + self.t2[2]) + v3 = self.v1 + self.l2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.v1.x + self.l2[0]) + self.assertEqual(v3.y, self.v1.y + self.l2[1]) + self.assertEqual(v3.z, self.v1.z + self.l2[2]) + v3 = self.t1 + self.v2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.t1[0] + self.v2.x) + self.assertEqual(v3.y, self.t1[1] + self.v2.y) + self.assertEqual(v3.z, self.t1[2] + self.v2.z) + v3 = self.l1 + self.v2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.l1[0] + self.v2.x) + self.assertEqual(v3.y, self.l1[1] + self.v2.y) + self.assertEqual(v3.z, self.l1[2] + self.v2.z) + + def testSub(self): + v3 = self.v1 - self.v2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.v1.x - self.v2.x) + self.assertEqual(v3.y, self.v1.y - self.v2.y) + self.assertEqual(v3.z, self.v1.z - self.v2.z) + v3 = self.v1 - self.t2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.v1.x - self.t2[0]) + self.assertEqual(v3.y, self.v1.y - self.t2[1]) + self.assertEqual(v3.z, self.v1.z - self.t2[2]) + v3 = self.v1 - self.l2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.v1.x - self.l2[0]) + self.assertEqual(v3.y, self.v1.y - self.l2[1]) + self.assertEqual(v3.z, self.v1.z - self.l2[2]) + v3 = self.t1 - self.v2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.t1[0] - self.v2.x) + self.assertEqual(v3.y, self.t1[1] - self.v2.y) + self.assertEqual(v3.z, self.t1[2] - self.v2.z) + v3 = self.l1 - self.v2 + self.assertTrue(isinstance(v3, type(self.v1))) + self.assertEqual(v3.x, self.l1[0] - self.v2.x) + self.assertEqual(v3.y, self.l1[1] - self.v2.y) + self.assertEqual(v3.z, self.l1[2] - self.v2.z) + + def testScalarMultiplication(self): + v = self.s1 * self.v1 + self.assertTrue(isinstance(v, type(self.v1))) + self.assertEqual(v.x, self.s1 * self.v1.x) + self.assertEqual(v.y, self.s1 * self.v1.y) + self.assertEqual(v.z, self.s1 * self.v1.z) + v = self.v1 * self.s2 + self.assertEqual(v.x, self.v1.x * self.s2) + self.assertEqual(v.y, self.v1.y * self.s2) + self.assertEqual(v.z, self.v1.z * self.s2) + + def testScalarDivision(self): + v = self.v1 / self.s1 + self.assertTrue(isinstance(v, type(self.v1))) + self.assertAlmostEqual(v.x, self.v1.x / self.s1) + self.assertAlmostEqual(v.y, self.v1.y / self.s1) + self.assertAlmostEqual(v.z, self.v1.z / self.s1) + v = self.v1 // self.s2 + self.assertTrue(isinstance(v, type(self.v1))) + self.assertEqual(v.x, self.v1.x // self.s2) + self.assertEqual(v.y, self.v1.y // self.s2) + self.assertEqual(v.z, self.v1.z // self.s2) + + def testBool(self): + self.assertEqual(bool(self.zeroVec), False) + self.assertEqual(bool(self.v1), True) + self.assertTrue(not self.zeroVec) + self.assertTrue(self.v1) + + def testUnary(self): + v = +self.v1 + self.assertTrue(isinstance(v, type(self.v1))) + self.assertEqual(v.x, self.v1.x) + self.assertEqual(v.y, self.v1.y) + self.assertEqual(v.z, self.v1.z) + self.assertNotEqual(id(v), id(self.v1)) + v = -self.v1 + self.assertTrue(isinstance(v, type(self.v1))) + self.assertEqual(v.x, -self.v1.x) + self.assertEqual(v.y, -self.v1.y) + self.assertEqual(v.z, -self.v1.z) + self.assertNotEqual(id(v), id(self.v1)) + + def testCompare(self): + int_vec = Vector3(3, -2, 13) + flt_vec = Vector3(3.0, -2.0, 13.0) + zero_vec = Vector3(0, 0, 0) + self.assertEqual(int_vec == flt_vec, True) + self.assertEqual(int_vec != flt_vec, False) + self.assertEqual(int_vec != zero_vec, True) + self.assertEqual(flt_vec == zero_vec, False) + self.assertEqual(int_vec == (3, -2, 13), True) + self.assertEqual(int_vec != (3, -2, 13), False) + self.assertEqual(int_vec != [0, 0], True) + self.assertEqual(int_vec == [0, 0], False) + self.assertEqual(int_vec != 5, True) + self.assertEqual(int_vec == 5, False) + self.assertEqual(int_vec != [3, -2, 0, 1], True) + self.assertEqual(int_vec == [3, -2, 0, 1], False) + + def testStr(self): + v = Vector3(1.2, 3.4, 5.6) + self.assertEqual(str(v), "[1.2, 3.4, 5.6]") + + def testRepr(self): + v = Vector3(1.2, 3.4, -9.6) + self.assertEqual(v.__repr__(), "") + self.assertEqual(v, Vector3(v.__repr__())) + + def testIter(self): + it = self.v1.__iter__() + next_ = it.__next__ + self.assertEqual(next_(), self.v1[0]) + self.assertEqual(next_(), self.v1[1]) + self.assertEqual(next_(), self.v1[2]) + self.assertRaises(StopIteration, lambda: next_()) + it1 = self.v1.__iter__() + it2 = self.v1.__iter__() + self.assertNotEqual(id(it1), id(it2)) + self.assertEqual(id(it1), id(it1.__iter__())) + self.assertEqual(list(it1), list(it2)) + self.assertEqual(list(self.v1.__iter__()), self.l1) + idx = 0 + for val in self.v1: + self.assertEqual(val, self.v1[idx]) + idx += 1 + + def test_rotate(self): + v1 = Vector3(1, 0, 0) + axis = Vector3(0, 1, 0) + v2 = v1.rotate(90, axis) + v3 = v1.rotate(90 + 360, axis) + self.assertEqual(v1.x, 1) + self.assertEqual(v1.y, 0) + self.assertEqual(v1.z, 0) + self.assertEqual(v2.x, 0) + self.assertEqual(v2.y, 0) + self.assertEqual(v2.z, -1) + self.assertEqual(v3.x, v2.x) + self.assertEqual(v3.y, v2.y) + self.assertEqual(v3.z, v2.z) + v1 = Vector3(-1, -1, -1) + v2 = v1.rotate(-90, axis) + self.assertEqual(v2.x, 1) + self.assertEqual(v2.y, -1) + self.assertEqual(v2.z, -1) + v2 = v1.rotate(360, axis) + self.assertEqual(v1.x, v2.x) + self.assertEqual(v1.y, v2.y) + self.assertEqual(v1.z, v2.z) + v2 = v1.rotate(0, axis) + self.assertEqual(v1.x, v2.x) + self.assertEqual(v1.y, v2.y) + self.assertEqual(v1.z, v2.z) + # issue 214 + self.assertEqual( + Vector3(0, 1, 0).rotate(359.9999999, Vector3(0, 0, 1)), Vector3(0, 1, 0) + ) + + def test_rotate_rad(self): + axis = Vector3(0, 0, 1) + tests = ( + ((1, 0, 0), math.pi), + ((1, 0, 0), math.pi / 2), + ((1, 0, 0), -math.pi / 2), + ((1, 0, 0), math.pi / 4), + ) + for initialVec, radians in tests: + vec = Vector3(initialVec).rotate_rad(radians, axis) + self.assertEqual(vec, (math.cos(radians), math.sin(radians), 0)) + + def test_rotate_ip(self): + v = Vector3(1, 0, 0) + axis = Vector3(0, 1, 0) + self.assertEqual(v.rotate_ip(90, axis), None) + self.assertEqual(v.x, 0) + self.assertEqual(v.y, 0) + self.assertEqual(v.z, -1) + v = Vector3(-1, -1, 1) + v.rotate_ip(-90, axis) + self.assertEqual(v.x, -1) + self.assertEqual(v.y, -1) + self.assertEqual(v.z, -1) + + def test_rotate_rad_ip(self): + axis = Vector3(0, 0, 1) + tests = ( + ((1, 0, 0), math.pi), + ((1, 0, 0), math.pi / 2), + ((1, 0, 0), -math.pi / 2), + ((1, 0, 0), math.pi / 4), + ) + for initialVec, radians in tests: + vec = Vector3(initialVec) + vec.rotate_rad_ip(radians, axis) + self.assertEqual(vec, (math.cos(radians), math.sin(radians), 0)) + + def test_rotate_x(self): + v1 = Vector3(1, 0, 0) + v2 = v1.rotate_x(90) + v3 = v1.rotate_x(90 + 360) + self.assertEqual(v1.x, 1) + self.assertEqual(v1.y, 0) + self.assertEqual(v1.z, 0) + self.assertEqual(v2.x, 1) + self.assertEqual(v2.y, 0) + self.assertEqual(v2.z, 0) + self.assertEqual(v3.x, v2.x) + self.assertEqual(v3.y, v2.y) + self.assertEqual(v3.z, v2.z) + v1 = Vector3(-1, -1, -1) + v2 = v1.rotate_x(-90) + self.assertEqual(v2.x, -1) + self.assertAlmostEqual(v2.y, -1) + self.assertAlmostEqual(v2.z, 1) + v2 = v1.rotate_x(360) + self.assertAlmostEqual(v1.x, v2.x) + self.assertAlmostEqual(v1.y, v2.y) + self.assertAlmostEqual(v1.z, v2.z) + v2 = v1.rotate_x(0) + self.assertEqual(v1.x, v2.x) + self.assertAlmostEqual(v1.y, v2.y) + self.assertAlmostEqual(v1.z, v2.z) + + def test_rotate_x_rad(self): + vec = Vector3(0, 1, 0) + result = vec.rotate_x_rad(math.pi / 2) + self.assertEqual(result, (0, 0, 1)) + + def test_rotate_x_ip(self): + v = Vector3(1, 0, 0) + self.assertEqual(v.rotate_x_ip(90), None) + self.assertEqual(v.x, 1) + self.assertEqual(v.y, 0) + self.assertEqual(v.z, 0) + v = Vector3(-1, -1, 1) + v.rotate_x_ip(-90) + self.assertEqual(v.x, -1) + self.assertAlmostEqual(v.y, 1) + self.assertAlmostEqual(v.z, 1) + + def test_rotate_x_rad_ip(self): + vec = Vector3(0, 1, 0) + vec.rotate_x_rad_ip(math.pi / 2) + self.assertEqual(vec, (0, 0, 1)) + + def test_rotate_y(self): + v1 = Vector3(1, 0, 0) + v2 = v1.rotate_y(90) + v3 = v1.rotate_y(90 + 360) + self.assertEqual(v1.x, 1) + self.assertEqual(v1.y, 0) + self.assertEqual(v1.z, 0) + self.assertAlmostEqual(v2.x, 0) + self.assertEqual(v2.y, 0) + self.assertAlmostEqual(v2.z, -1) + self.assertAlmostEqual(v3.x, v2.x) + self.assertEqual(v3.y, v2.y) + self.assertAlmostEqual(v3.z, v2.z) + v1 = Vector3(-1, -1, -1) + v2 = v1.rotate_y(-90) + self.assertAlmostEqual(v2.x, 1) + self.assertEqual(v2.y, -1) + self.assertAlmostEqual(v2.z, -1) + v2 = v1.rotate_y(360) + self.assertAlmostEqual(v1.x, v2.x) + self.assertEqual(v1.y, v2.y) + self.assertAlmostEqual(v1.z, v2.z) + v2 = v1.rotate_y(0) + self.assertEqual(v1.x, v2.x) + self.assertEqual(v1.y, v2.y) + self.assertEqual(v1.z, v2.z) + + def test_rotate_y_rad(self): + vec = Vector3(1, 0, 0) + result = vec.rotate_y_rad(math.pi / 2) + self.assertEqual(result, (0, 0, -1)) + + def test_rotate_y_ip(self): + v = Vector3(1, 0, 0) + self.assertEqual(v.rotate_y_ip(90), None) + self.assertAlmostEqual(v.x, 0) + self.assertEqual(v.y, 0) + self.assertAlmostEqual(v.z, -1) + v = Vector3(-1, -1, 1) + v.rotate_y_ip(-90) + self.assertAlmostEqual(v.x, -1) + self.assertEqual(v.y, -1) + self.assertAlmostEqual(v.z, -1) + + def test_rotate_y_rad_ip(self): + vec = Vector3(1, 0, 0) + vec.rotate_y_rad_ip(math.pi / 2) + self.assertEqual(vec, (0, 0, -1)) + + def test_rotate_z(self): + v1 = Vector3(1, 0, 0) + v2 = v1.rotate_z(90) + v3 = v1.rotate_z(90 + 360) + self.assertEqual(v1.x, 1) + self.assertEqual(v1.y, 0) + self.assertEqual(v1.z, 0) + self.assertAlmostEqual(v2.x, 0) + self.assertAlmostEqual(v2.y, 1) + self.assertEqual(v2.z, 0) + self.assertAlmostEqual(v3.x, v2.x) + self.assertAlmostEqual(v3.y, v2.y) + self.assertEqual(v3.z, v2.z) + v1 = Vector3(-1, -1, -1) + v2 = v1.rotate_z(-90) + self.assertAlmostEqual(v2.x, -1) + self.assertAlmostEqual(v2.y, 1) + self.assertEqual(v2.z, -1) + v2 = v1.rotate_z(360) + self.assertAlmostEqual(v1.x, v2.x) + self.assertAlmostEqual(v1.y, v2.y) + self.assertEqual(v1.z, v2.z) + v2 = v1.rotate_z(0) + self.assertAlmostEqual(v1.x, v2.x) + self.assertAlmostEqual(v1.y, v2.y) + self.assertEqual(v1.z, v2.z) + + def test_rotate_z_rad(self): + vec = Vector3(1, 0, 0) + result = vec.rotate_z_rad(math.pi / 2) + self.assertEqual(result, (0, 1, 0)) + + def test_rotate_z_ip(self): + v = Vector3(1, 0, 0) + self.assertEqual(v.rotate_z_ip(90), None) + self.assertAlmostEqual(v.x, 0) + self.assertAlmostEqual(v.y, 1) + self.assertEqual(v.z, 0) + v = Vector3(-1, -1, 1) + v.rotate_z_ip(-90) + self.assertAlmostEqual(v.x, -1) + self.assertAlmostEqual(v.y, 1) + self.assertEqual(v.z, 1) + + def test_rotate_z_rad_ip(self): + vec = Vector3(1, 0, 0) + vec.rotate_z_rad_ip(math.pi / 2) + self.assertEqual(vec, (0, 1, 0)) + + def test_normalize(self): + v = self.v1.normalize() + # length is 1 + self.assertAlmostEqual(v.x * v.x + v.y * v.y + v.z * v.z, 1.0) + # v1 is unchanged + self.assertEqual(self.v1.x, self.l1[0]) + self.assertEqual(self.v1.y, self.l1[1]) + self.assertEqual(self.v1.z, self.l1[2]) + # v2 is parallel to v1 (tested via cross product) + cross = ( + (self.v1.y * v.z - self.v1.z * v.y) ** 2 + + (self.v1.z * v.x - self.v1.x * v.z) ** 2 + + (self.v1.x * v.y - self.v1.y * v.x) ** 2 + ) + self.assertAlmostEqual(cross, 0.0) + self.assertRaises(ValueError, lambda: self.zeroVec.normalize()) + + def test_normalize_ip(self): + v = +self.v1 + # v has length != 1 before normalizing + self.assertNotEqual(v.x * v.x + v.y * v.y + v.z * v.z, 1.0) + # inplace operations should return None + self.assertEqual(v.normalize_ip(), None) + # length is 1 + self.assertAlmostEqual(v.x * v.x + v.y * v.y + v.z * v.z, 1.0) + # v2 is parallel to v1 (tested via cross product) + cross = ( + (self.v1.y * v.z - self.v1.z * v.y) ** 2 + + (self.v1.z * v.x - self.v1.x * v.z) ** 2 + + (self.v1.x * v.y - self.v1.y * v.x) ** 2 + ) + self.assertAlmostEqual(cross, 0.0) + self.assertRaises(ValueError, lambda: self.zeroVec.normalize_ip()) + + def test_is_normalized(self): + self.assertEqual(self.v1.is_normalized(), False) + v = self.v1.normalize() + self.assertEqual(v.is_normalized(), True) + self.assertEqual(self.e2.is_normalized(), True) + self.assertEqual(self.zeroVec.is_normalized(), False) + + def test_cross(self): + def cross(a, b): + return Vector3( + a[1] * b[2] - a[2] * b[1], + a[2] * b[0] - a[0] * b[2], + a[0] * b[1] - a[1] * b[0], + ) + + self.assertEqual(self.v1.cross(self.v2), cross(self.v1, self.v2)) + self.assertEqual(self.v1.cross(self.l2), cross(self.v1, self.l2)) + self.assertEqual(self.v1.cross(self.t2), cross(self.v1, self.t2)) + self.assertEqual(self.v1.cross(self.v2), -self.v2.cross(self.v1)) + self.assertEqual(self.v1.cross(self.v1), self.zeroVec) + + def test_dot(self): + self.assertAlmostEqual( + self.v1.dot(self.v2), + self.v1.x * self.v2.x + self.v1.y * self.v2.y + self.v1.z * self.v2.z, + ) + self.assertAlmostEqual( + self.v1.dot(self.l2), + self.v1.x * self.l2[0] + self.v1.y * self.l2[1] + self.v1.z * self.l2[2], + ) + self.assertAlmostEqual( + self.v1.dot(self.t2), + self.v1.x * self.t2[0] + self.v1.y * self.t2[1] + self.v1.z * self.t2[2], + ) + self.assertAlmostEqual(self.v1.dot(self.v2), self.v2.dot(self.v1)) + self.assertAlmostEqual(self.v1.dot(self.v2), self.v1 * self.v2) + + def test_angle_to(self): + self.assertEqual(Vector3(1, 1, 0).angle_to((-1, 1, 0)), 90) + self.assertEqual(Vector3(1, 0, 0).angle_to((0, 0, -1)), 90) + self.assertEqual(Vector3(1, 0, 0).angle_to((-1, 0, 1)), 135) + self.assertEqual(abs(Vector3(1, 0, 1).angle_to((-1, 0, -1))), 180) + # if we rotate v1 by the angle_to v2 around their cross product + # we should look in the same direction + self.assertEqual( + self.v1.rotate( + self.v1.angle_to(self.v2), self.v1.cross(self.v2) + ).normalize(), + self.v2.normalize(), + ) + + def test_scale_to_length(self): + v = Vector3(1, 1, 1) + v.scale_to_length(2.5) + self.assertEqual(v, Vector3(2.5, 2.5, 2.5) / math.sqrt(3)) + self.assertRaises(ValueError, lambda: self.zeroVec.scale_to_length(1)) + self.assertEqual(v.scale_to_length(0), None) + self.assertEqual(v, self.zeroVec) + + def test_length(self): + self.assertEqual(Vector3(3, 4, 5).length(), math.sqrt(3 * 3 + 4 * 4 + 5 * 5)) + self.assertEqual(Vector3(-3, 4, 5).length(), math.sqrt(-3 * -3 + 4 * 4 + 5 * 5)) + self.assertEqual(self.zeroVec.length(), 0) + + def test_length_squared(self): + self.assertEqual(Vector3(3, 4, 5).length_squared(), 3 * 3 + 4 * 4 + 5 * 5) + self.assertEqual(Vector3(-3, 4, 5).length_squared(), -3 * -3 + 4 * 4 + 5 * 5) + self.assertEqual(self.zeroVec.length_squared(), 0) + + def test_reflect(self): + v = Vector3(1, -1, 1) + n = Vector3(0, 1, 0) + self.assertEqual(v.reflect(n), Vector3(1, 1, 1)) + self.assertEqual(v.reflect(3 * n), v.reflect(n)) + self.assertEqual(v.reflect(-v), -v) + self.assertRaises(ValueError, lambda: v.reflect(self.zeroVec)) + + def test_reflect_ip(self): + v1 = Vector3(1, -1, 1) + v2 = Vector3(v1) + n = Vector3(0, 1, 0) + self.assertEqual(v2.reflect_ip(n), None) + self.assertEqual(v2, Vector3(1, 1, 1)) + v2 = Vector3(v1) + v2.reflect_ip(3 * n) + self.assertEqual(v2, v1.reflect(n)) + v2 = Vector3(v1) + v2.reflect_ip(-v1) + self.assertEqual(v2, -v1) + self.assertRaises(ValueError, lambda: v2.reflect_ip(self.zeroVec)) + + def test_distance_to(self): + diff = self.v1 - self.v2 + self.assertEqual(self.e1.distance_to(self.e2), math.sqrt(2)) + self.assertEqual( + self.v1.distance_to(self.v2), + math.sqrt(diff.x * diff.x + diff.y * diff.y + diff.z * diff.z), + ) + self.assertEqual(self.v1.distance_to(self.v1), 0) + self.assertEqual(self.v1.distance_to(self.v2), self.v2.distance_to(self.v1)) + + def test_distance_squared_to(self): + diff = self.v1 - self.v2 + self.assertEqual(self.e1.distance_squared_to(self.e2), 2) + self.assertAlmostEqual( + self.v1.distance_squared_to(self.v2), + diff.x * diff.x + diff.y * diff.y + diff.z * diff.z, + ) + self.assertEqual(self.v1.distance_squared_to(self.v1), 0) + self.assertEqual( + self.v1.distance_squared_to(self.v2), self.v2.distance_squared_to(self.v1) + ) + + def test_swizzle(self): + self.assertEqual(self.v1.yxz, (self.v1.y, self.v1.x, self.v1.z)) + self.assertEqual( + self.v1.xxyyzzxyz, + ( + self.v1.x, + self.v1.x, + self.v1.y, + self.v1.y, + self.v1.z, + self.v1.z, + self.v1.x, + self.v1.y, + self.v1.z, + ), + ) + self.v1.xyz = self.t2 + self.assertEqual(self.v1, self.t2) + self.v1.zxy = self.t2 + self.assertEqual(self.v1, (self.t2[1], self.t2[2], self.t2[0])) + self.v1.yz = self.t2[:2] + self.assertEqual(self.v1, (self.t2[1], self.t2[0], self.t2[1])) + self.assertEqual(type(self.v1), Vector3) + + @unittest.skipIf(IS_PYPY, "known pypy failure") + def test_invalid_swizzle(self): + def invalidSwizzleX(): + Vector3().xx = (1, 2) + + def invalidSwizzleY(): + Vector3().yy = (1, 2) + + def invalidSwizzleZ(): + Vector3().zz = (1, 2) + + def invalidSwizzleW(): + Vector3().ww = (1, 2) + + self.assertRaises(AttributeError, invalidSwizzleX) + self.assertRaises(AttributeError, invalidSwizzleY) + self.assertRaises(AttributeError, invalidSwizzleZ) + self.assertRaises(AttributeError, invalidSwizzleW) + + def invalidAssignment(): + Vector3().xy = 3 + + self.assertRaises(TypeError, invalidAssignment) + + def test_swizzle_return_types(self): + self.assertEqual(type(self.v1.x), float) + self.assertEqual(type(self.v1.xy), Vector2) + self.assertEqual(type(self.v1.xyz), Vector3) + # but we don't have vector4 or above... so tuple. + self.assertEqual(type(self.v1.xyxy), tuple) + self.assertEqual(type(self.v1.xyxyx), tuple) + + def test_dir_works(self): + # not every single one of the attributes... + attributes = set( + ["lerp", "normalize", "normalize_ip", "reflect", "slerp", "x", "y"] + ) + # check if this selection of attributes are all there. + self.assertTrue(attributes.issubset(set(dir(self.v1)))) + + def test_elementwise(self): + # behaviour for "elementwise op scalar" + self.assertEqual( + self.v1.elementwise() + self.s1, + (self.v1.x + self.s1, self.v1.y + self.s1, self.v1.z + self.s1), + ) + self.assertEqual( + self.v1.elementwise() - self.s1, + (self.v1.x - self.s1, self.v1.y - self.s1, self.v1.z - self.s1), + ) + self.assertEqual( + self.v1.elementwise() * self.s2, + (self.v1.x * self.s2, self.v1.y * self.s2, self.v1.z * self.s2), + ) + self.assertEqual( + self.v1.elementwise() / self.s2, + (self.v1.x / self.s2, self.v1.y / self.s2, self.v1.z / self.s2), + ) + self.assertEqual( + self.v1.elementwise() // self.s1, + (self.v1.x // self.s1, self.v1.y // self.s1, self.v1.z // self.s1), + ) + self.assertEqual( + self.v1.elementwise() ** self.s1, + (self.v1.x ** self.s1, self.v1.y ** self.s1, self.v1.z ** self.s1), + ) + self.assertEqual( + self.v1.elementwise() % self.s1, + (self.v1.x % self.s1, self.v1.y % self.s1, self.v1.z % self.s1), + ) + self.assertEqual( + self.v1.elementwise() > self.s1, + self.v1.x > self.s1 and self.v1.y > self.s1 and self.v1.z > self.s1, + ) + self.assertEqual( + self.v1.elementwise() < self.s1, + self.v1.x < self.s1 and self.v1.y < self.s1 and self.v1.z < self.s1, + ) + self.assertEqual( + self.v1.elementwise() == self.s1, + self.v1.x == self.s1 and self.v1.y == self.s1 and self.v1.z == self.s1, + ) + self.assertEqual( + self.v1.elementwise() != self.s1, + self.v1.x != self.s1 and self.v1.y != self.s1 and self.v1.z != self.s1, + ) + self.assertEqual( + self.v1.elementwise() >= self.s1, + self.v1.x >= self.s1 and self.v1.y >= self.s1 and self.v1.z >= self.s1, + ) + self.assertEqual( + self.v1.elementwise() <= self.s1, + self.v1.x <= self.s1 and self.v1.y <= self.s1 and self.v1.z <= self.s1, + ) + # behaviour for "scalar op elementwise" + self.assertEqual(5 + self.v1.elementwise(), Vector3(5, 5, 5) + self.v1) + self.assertEqual(3.5 - self.v1.elementwise(), Vector3(3.5, 3.5, 3.5) - self.v1) + self.assertEqual(7.5 * self.v1.elementwise(), 7.5 * self.v1) + self.assertEqual( + -3.5 / self.v1.elementwise(), + (-3.5 / self.v1.x, -3.5 / self.v1.y, -3.5 / self.v1.z), + ) + self.assertEqual( + -3.5 // self.v1.elementwise(), + (-3.5 // self.v1.x, -3.5 // self.v1.y, -3.5 // self.v1.z), + ) + self.assertEqual( + -(3.5 ** self.v1.elementwise()), + (-(3.5 ** self.v1.x), -(3.5 ** self.v1.y), -(3.5 ** self.v1.z)), + ) + self.assertEqual( + 3 % self.v1.elementwise(), (3 % self.v1.x, 3 % self.v1.y, 3 % self.v1.z) + ) + self.assertEqual( + 2 < self.v1.elementwise(), 2 < self.v1.x and 2 < self.v1.y and 2 < self.v1.z + ) + self.assertEqual( + 2 > self.v1.elementwise(), 2 > self.v1.x and 2 > self.v1.y and 2 > self.v1.z + ) + self.assertEqual( + 1 == self.v1.elementwise(), + 1 == self.v1.x and 1 == self.v1.y and 1 == self.v1.z, + ) + self.assertEqual( + 1 != self.v1.elementwise(), + 1 != self.v1.x and 1 != self.v1.y and 1 != self.v1.z, + ) + self.assertEqual( + 2 <= self.v1.elementwise(), + 2 <= self.v1.x and 2 <= self.v1.y and 2 <= self.v1.z, + ) + self.assertEqual( + -7 >= self.v1.elementwise(), + -7 >= self.v1.x and -7 >= self.v1.y and -7 >= self.v1.z, + ) + self.assertEqual( + -7 != self.v1.elementwise(), + -7 != self.v1.x and -7 != self.v1.y and -7 != self.v1.z, + ) + + # behaviour for "elementwise op vector" + self.assertEqual(type(self.v1.elementwise() * self.v2), type(self.v1)) + self.assertEqual(self.v1.elementwise() + self.v2, self.v1 + self.v2) + self.assertEqual(self.v1.elementwise() + self.v2, self.v1 + self.v2) + self.assertEqual(self.v1.elementwise() - self.v2, self.v1 - self.v2) + self.assertEqual( + self.v1.elementwise() * self.v2, + (self.v1.x * self.v2.x, self.v1.y * self.v2.y, self.v1.z * self.v2.z), + ) + self.assertEqual( + self.v1.elementwise() / self.v2, + (self.v1.x / self.v2.x, self.v1.y / self.v2.y, self.v1.z / self.v2.z), + ) + self.assertEqual( + self.v1.elementwise() // self.v2, + (self.v1.x // self.v2.x, self.v1.y // self.v2.y, self.v1.z // self.v2.z), + ) + self.assertEqual( + self.v1.elementwise() ** self.v2, + (self.v1.x ** self.v2.x, self.v1.y ** self.v2.y, self.v1.z ** self.v2.z), + ) + self.assertEqual( + self.v1.elementwise() % self.v2, + (self.v1.x % self.v2.x, self.v1.y % self.v2.y, self.v1.z % self.v2.z), + ) + self.assertEqual( + self.v1.elementwise() > self.v2, + self.v1.x > self.v2.x and self.v1.y > self.v2.y and self.v1.z > self.v2.z, + ) + self.assertEqual( + self.v1.elementwise() < self.v2, + self.v1.x < self.v2.x and self.v1.y < self.v2.y and self.v1.z < self.v2.z, + ) + self.assertEqual( + self.v1.elementwise() >= self.v2, + self.v1.x >= self.v2.x + and self.v1.y >= self.v2.y + and self.v1.z >= self.v2.z, + ) + self.assertEqual( + self.v1.elementwise() <= self.v2, + self.v1.x <= self.v2.x + and self.v1.y <= self.v2.y + and self.v1.z <= self.v2.z, + ) + self.assertEqual( + self.v1.elementwise() == self.v2, + self.v1.x == self.v2.x + and self.v1.y == self.v2.y + and self.v1.z == self.v2.z, + ) + self.assertEqual( + self.v1.elementwise() != self.v2, + self.v1.x != self.v2.x + and self.v1.y != self.v2.y + and self.v1.z != self.v2.z, + ) + # behaviour for "vector op elementwise" + self.assertEqual(self.v2 + self.v1.elementwise(), self.v2 + self.v1) + self.assertEqual(self.v2 - self.v1.elementwise(), self.v2 - self.v1) + self.assertEqual( + self.v2 * self.v1.elementwise(), + (self.v2.x * self.v1.x, self.v2.y * self.v1.y, self.v2.z * self.v1.z), + ) + self.assertEqual( + self.v2 / self.v1.elementwise(), + (self.v2.x / self.v1.x, self.v2.y / self.v1.y, self.v2.z / self.v1.z), + ) + self.assertEqual( + self.v2 // self.v1.elementwise(), + (self.v2.x // self.v1.x, self.v2.y // self.v1.y, self.v2.z // self.v1.z), + ) + self.assertEqual( + self.v2 ** self.v1.elementwise(), + (self.v2.x ** self.v1.x, self.v2.y ** self.v1.y, self.v2.z ** self.v1.z), + ) + self.assertEqual( + self.v2 % self.v1.elementwise(), + (self.v2.x % self.v1.x, self.v2.y % self.v1.y, self.v2.z % self.v1.z), + ) + self.assertEqual( + self.v2 < self.v1.elementwise(), + self.v2.x < self.v1.x and self.v2.y < self.v1.y and self.v2.z < self.v1.z, + ) + self.assertEqual( + self.v2 > self.v1.elementwise(), + self.v2.x > self.v1.x and self.v2.y > self.v1.y and self.v2.z > self.v1.z, + ) + self.assertEqual( + self.v2 <= self.v1.elementwise(), + self.v2.x <= self.v1.x + and self.v2.y <= self.v1.y + and self.v2.z <= self.v1.z, + ) + self.assertEqual( + self.v2 >= self.v1.elementwise(), + self.v2.x >= self.v1.x + and self.v2.y >= self.v1.y + and self.v2.z >= self.v1.z, + ) + self.assertEqual( + self.v2 == self.v1.elementwise(), + self.v2.x == self.v1.x + and self.v2.y == self.v1.y + and self.v2.z == self.v1.z, + ) + self.assertEqual( + self.v2 != self.v1.elementwise(), + self.v2.x != self.v1.x + and self.v2.y != self.v1.y + and self.v2.z != self.v1.z, + ) + + # behaviour for "elementwise op elementwise" + self.assertEqual( + self.v2.elementwise() + self.v1.elementwise(), self.v2 + self.v1 + ) + self.assertEqual( + self.v2.elementwise() - self.v1.elementwise(), self.v2 - self.v1 + ) + self.assertEqual( + self.v2.elementwise() * self.v1.elementwise(), + (self.v2.x * self.v1.x, self.v2.y * self.v1.y, self.v2.z * self.v1.z), + ) + self.assertEqual( + self.v2.elementwise() / self.v1.elementwise(), + (self.v2.x / self.v1.x, self.v2.y / self.v1.y, self.v2.z / self.v1.z), + ) + self.assertEqual( + self.v2.elementwise() // self.v1.elementwise(), + (self.v2.x // self.v1.x, self.v2.y // self.v1.y, self.v2.z // self.v1.z), + ) + self.assertEqual( + self.v2.elementwise() ** self.v1.elementwise(), + (self.v2.x ** self.v1.x, self.v2.y ** self.v1.y, self.v2.z ** self.v1.z), + ) + self.assertEqual( + self.v2.elementwise() % self.v1.elementwise(), + (self.v2.x % self.v1.x, self.v2.y % self.v1.y, self.v2.z % self.v1.z), + ) + self.assertEqual( + self.v2.elementwise() < self.v1.elementwise(), + self.v2.x < self.v1.x and self.v2.y < self.v1.y and self.v2.z < self.v1.z, + ) + self.assertEqual( + self.v2.elementwise() > self.v1.elementwise(), + self.v2.x > self.v1.x and self.v2.y > self.v1.y and self.v2.z > self.v1.z, + ) + self.assertEqual( + self.v2.elementwise() <= self.v1.elementwise(), + self.v2.x <= self.v1.x + and self.v2.y <= self.v1.y + and self.v2.z <= self.v1.z, + ) + self.assertEqual( + self.v2.elementwise() >= self.v1.elementwise(), + self.v2.x >= self.v1.x + and self.v2.y >= self.v1.y + and self.v2.z >= self.v1.z, + ) + self.assertEqual( + self.v2.elementwise() == self.v1.elementwise(), + self.v2.x == self.v1.x + and self.v2.y == self.v1.y + and self.v2.z == self.v1.z, + ) + self.assertEqual( + self.v2.elementwise() != self.v1.elementwise(), + self.v2.x != self.v1.x + and self.v2.y != self.v1.y + and self.v2.z != self.v1.z, + ) + + # other behaviour + self.assertEqual( + abs(self.v1.elementwise()), (abs(self.v1.x), abs(self.v1.y), abs(self.v1.z)) + ) + self.assertEqual(-self.v1.elementwise(), -self.v1) + self.assertEqual(+self.v1.elementwise(), +self.v1) + self.assertEqual(bool(self.v1.elementwise()), bool(self.v1)) + self.assertEqual(bool(Vector3().elementwise()), bool(Vector3())) + self.assertEqual(self.zeroVec.elementwise() ** 0, (1, 1, 1)) + self.assertRaises(ValueError, lambda: pow(Vector3(-1, 0, 0).elementwise(), 1.2)) + self.assertRaises(ZeroDivisionError, lambda: self.zeroVec.elementwise() ** -1) + self.assertRaises(ZeroDivisionError, lambda: Vector3(1, 1, 1).elementwise() / 0) + self.assertRaises( + ZeroDivisionError, lambda: Vector3(1, 1, 1).elementwise() // 0 + ) + self.assertRaises(ZeroDivisionError, lambda: Vector3(1, 1, 1).elementwise() % 0) + self.assertRaises( + ZeroDivisionError, lambda: Vector3(1, 1, 1).elementwise() / self.zeroVec + ) + self.assertRaises( + ZeroDivisionError, lambda: Vector3(1, 1, 1).elementwise() // self.zeroVec + ) + self.assertRaises( + ZeroDivisionError, lambda: Vector3(1, 1, 1).elementwise() % self.zeroVec + ) + self.assertRaises(ZeroDivisionError, lambda: 2 / self.zeroVec.elementwise()) + self.assertRaises(ZeroDivisionError, lambda: 2 // self.zeroVec.elementwise()) + self.assertRaises(ZeroDivisionError, lambda: 2 % self.zeroVec.elementwise()) + + def test_slerp(self): + self.assertRaises(ValueError, lambda: self.zeroVec.slerp(self.v1, 0.5)) + self.assertRaises(ValueError, lambda: self.v1.slerp(self.zeroVec, 0.5)) + self.assertRaises(ValueError, lambda: self.zeroVec.slerp(self.zeroVec, 0.5)) + steps = 10 + angle_step = self.e1.angle_to(self.e2) / steps + for i, u in ( + (i, self.e1.slerp(self.e2, i / float(steps))) for i in range(steps + 1) + ): + self.assertAlmostEqual(u.length(), 1) + self.assertAlmostEqual(self.e1.angle_to(u), i * angle_step) + self.assertEqual(u, self.e2) + + v1 = Vector3(100, 0, 0) + v2 = Vector3(0, 10, 7) + radial_factor = v2.length() / v1.length() + for i, u in ((i, v1.slerp(v2, -i / float(steps))) for i in range(steps + 1)): + self.assertAlmostEqual( + u.length(), + (v2.length() - v1.length()) * (float(i) / steps) + v1.length(), + ) + self.assertEqual(u, v2) + self.assertEqual(v1.slerp(v1, 0.5), v1) + self.assertEqual(v2.slerp(v2, 0.5), v2) + self.assertRaises(ValueError, lambda: v1.slerp(-v1, 0.5)) + + def test_lerp(self): + v1 = Vector3(0, 0, 0) + v2 = Vector3(10, 10, 10) + self.assertEqual(v1.lerp(v2, 0.5), (5, 5, 5)) + self.assertRaises(ValueError, lambda: v1.lerp(v2, 2.5)) + + v1 = Vector3(-10, -5, -20) + v2 = Vector3(10, 10, -20) + self.assertEqual(v1.lerp(v2, 0.5), (0, 2.5, -20)) + + def test_spherical(self): + v = Vector3() + v.from_spherical(self.v1.as_spherical()) + self.assertEqual(self.v1, v) + self.assertEqual(self.e1.as_spherical(), (1, 90, 0)) + self.assertEqual(self.e2.as_spherical(), (1, 90, 90)) + self.assertEqual(self.e3.as_spherical(), (1, 0, 0)) + self.assertEqual((2 * self.e2).as_spherical(), (2, 90, 90)) + self.assertRaises(TypeError, lambda: v.from_spherical((None, None, None))) + self.assertRaises(TypeError, lambda: v.from_spherical("abc")) + self.assertRaises(TypeError, lambda: v.from_spherical((None, 1, 2))) + self.assertRaises(TypeError, lambda: v.from_spherical((1, 2, 3, 4))) + self.assertRaises(TypeError, lambda: v.from_spherical((1, 2))) + self.assertRaises(TypeError, lambda: v.from_spherical(1, 2, 3)) + v.from_spherical((0.5, 90, 90)) + self.assertEqual(v, 0.5 * self.e2) + + def test_inplace_operators(self): + + v = Vector3(1, 1, 1) + v *= 2 + self.assertEqual(v, (2.0, 2.0, 2.0)) + + v = Vector3(4, 4, 4) + v /= 2 + self.assertEqual(v, (2.0, 2.0, 2.0)) + + v = Vector3(3.0, 3.0, 3.0) + v -= (1, 1, 1) + self.assertEqual(v, (2.0, 2.0, 2.0)) + + v = Vector3(3.0, 3.0, 3.0) + v += (1, 1, 1) + self.assertEqual(v, (4.0, 4.0, 4.0)) + + def test_pickle(self): + import pickle + + v2 = Vector2(1, 2) + v3 = Vector3(1, 2, 3) + self.assertEqual(pickle.loads(pickle.dumps(v2)), v2) + self.assertEqual(pickle.loads(pickle.dumps(v3)), v3) + + def test_subclass_operation(self): + class Vector(pygame.math.Vector3): + pass + + v = Vector(2.0, 2.0, 2.0) + v *= 2 + self.assertEqual(v, (4.0, 4.0, 4.0)) + + def test_swizzle_constants(self): + """We can get constant values from a swizzle.""" + v = Vector2(7, 6) + self.assertEqual( + v.xy1, + (7.0, 6.0, 1.0), + ) + + def test_swizzle_four_constants(self): + """We can get 4 constant values from a swizzle.""" + v = Vector2(7, 6) + self.assertEqual( + v.xy01, + (7.0, 6.0, 0.0, 1.0), + ) + + def test_swizzle_oob(self): + """An out-of-bounds swizzle raises an AttributeError.""" + v = Vector2(7, 6) + with self.assertRaises(AttributeError): + v.xyz + + @unittest.skipIf(IS_PYPY, "known pypy failure") + def test_swizzle_set_oob(self): + """An out-of-bounds swizzle set raises an AttributeError.""" + v = Vector2(7, 6) + with self.assertRaises(AttributeError): + v.xz = (1, 1) + + def test_project_v3_onto_x_axis(self): + """Project onto x-axis, e.g. get the component pointing in the x-axis direction.""" + # arrange + v = Vector3(2, 3, 4) + x_axis = Vector3(10, 0, 0) + + # act + actual = v.project(x_axis) + + # assert + self.assertEqual(v.x, actual.x) + self.assertEqual(0, actual.y) + self.assertEqual(0, actual.z) + + def test_project_v3_onto_y_axis(self): + """Project onto y-axis, e.g. get the component pointing in the y-axis direction.""" + # arrange + v = Vector3(2, 3, 4) + y_axis = Vector3(0, 100, 0) + + # act + actual = v.project(y_axis) + + # assert + self.assertEqual(0, actual.x) + self.assertEqual(v.y, actual.y) + self.assertEqual(0, actual.z) + + def test_project_v3_onto_z_axis(self): + """Project onto z-axis, e.g. get the component pointing in the z-axis direction.""" + # arrange + v = Vector3(2, 3, 4) + y_axis = Vector3(0, 0, 77) + + # act + actual = v.project(y_axis) + + # assert + self.assertEqual(0, actual.x) + self.assertEqual(0, actual.y) + self.assertEqual(v.z, actual.z) + + def test_project_v3_onto_other(self): + """Project onto other vector.""" + # arrange + v = Vector3(2, 3, 4) + other = Vector3(3, 5, 7) + + # act + actual = v.project(other) + + # assert + expected = v.dot(other) / other.dot(other) * other + self.assertAlmostEqual(expected.x, actual.x) + self.assertAlmostEqual(expected.y, actual.y) + self.assertAlmostEqual(expected.z, actual.z) + + def test_project_v3_onto_other_as_tuple(self): + """Project onto other tuple as vector.""" + # arrange + v = Vector3(2, 3, 4) + other = Vector3(3, 5, 7) + + # act + actual = v.project(tuple(other)) + + # assert + expected = v.dot(other) / other.dot(other) * other + self.assertAlmostEqual(expected.x, actual.x) + self.assertAlmostEqual(expected.y, actual.y) + self.assertAlmostEqual(expected.z, actual.z) + + def test_project_v3_onto_other_as_list(self): + """Project onto other list as vector.""" + # arrange + v = Vector3(2, 3, 4) + other = Vector3(3, 5, 7) + + # act + actual = v.project(list(other)) + + # assert + expected = v.dot(other) / other.dot(other) * other + self.assertAlmostEqual(expected.x, actual.x) + self.assertAlmostEqual(expected.y, actual.y) + self.assertAlmostEqual(expected.z, actual.z) + + def test_project_v3_raises_if_other_has_zero_length(self): + """Check if exception is raise when projected on vector has zero length.""" + # arrange + v = Vector3(2, 3, 4) + other = Vector3(0, 0, 0) + + # act / assert + self.assertRaises(ValueError, v.project, other) + + def test_project_v3_raises_if_other_is_not_iterable(self): + """Check if exception is raise when projected on vector is not iterable.""" + # arrange + v = Vector3(2, 3, 4) + other = 10 + + # act / assert + self.assertRaises(TypeError, v.project, other) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/midi_test.py b/venv/Lib/site-packages/pygame/tests/midi_test.py new file mode 100644 index 0000000..ffbe8ff --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/midi_test.py @@ -0,0 +1,472 @@ +import unittest + + +import pygame + + +class MidiInputTest(unittest.TestCase): + __tags__ = ["interactive"] + + def setUp(self): + import pygame.midi + + pygame.midi.init() + in_id = pygame.midi.get_default_input_id() + if in_id != -1: + self.midi_input = pygame.midi.Input(in_id) + else: + self.midi_input = None + + def tearDown(self): + if self.midi_input: + self.midi_input.close() + pygame.midi.quit() + + def test_Input(self): + i = pygame.midi.get_default_input_id() + if self.midi_input: + self.assertEqual(self.midi_input.device_id, i) + + # try feeding it an input id. + i = pygame.midi.get_default_output_id() + + # can handle some invalid input too. + self.assertRaises(pygame.midi.MidiException, pygame.midi.Input, i) + self.assertRaises(pygame.midi.MidiException, pygame.midi.Input, 9009) + self.assertRaises(pygame.midi.MidiException, pygame.midi.Input, -1) + self.assertRaises(TypeError, pygame.midi.Input, "1234") + self.assertRaises(OverflowError, pygame.midi.Input, pow(2, 99)) + + def test_poll(self): + + if not self.midi_input: + self.skipTest("No midi Input device") + + self.assertFalse(self.midi_input.poll()) + # TODO fake some incoming data + + pygame.midi.quit() + self.assertRaises(RuntimeError, self.midi_input.poll) + # set midi_input to None to avoid error in tearDown + self.midi_input = None + + def test_read(self): + + if not self.midi_input: + self.skipTest("No midi Input device") + + read = self.midi_input.read(5) + self.assertEqual(read, []) + # TODO fake some incoming data + + pygame.midi.quit() + self.assertRaises(RuntimeError, self.midi_input.read, 52) + # set midi_input to None to avoid error in tearDown + self.midi_input = None + + def test_close(self): + if not self.midi_input: + self.skipTest("No midi Input device") + + self.assertIsNotNone(self.midi_input._input) + self.midi_input.close() + self.assertIsNone(self.midi_input._input) + + +class MidiOutputTest(unittest.TestCase): + __tags__ = ["interactive"] + + def setUp(self): + import pygame.midi + + pygame.midi.init() + m_out_id = pygame.midi.get_default_output_id() + if m_out_id != -1: + self.midi_output = pygame.midi.Output(m_out_id) + else: + self.midi_output = None + + def tearDown(self): + if self.midi_output: + self.midi_output.close() + pygame.midi.quit() + + def test_Output(self): + i = pygame.midi.get_default_output_id() + if self.midi_output: + self.assertEqual(self.midi_output.device_id, i) + + # try feeding it an input id. + i = pygame.midi.get_default_input_id() + + # can handle some invalid input too. + self.assertRaises(pygame.midi.MidiException, pygame.midi.Output, i) + self.assertRaises(pygame.midi.MidiException, pygame.midi.Output, 9009) + self.assertRaises(pygame.midi.MidiException, pygame.midi.Output, -1) + self.assertRaises(TypeError, pygame.midi.Output, "1234") + self.assertRaises(OverflowError, pygame.midi.Output, pow(2, 99)) + + def test_note_off(self): + if self.midi_output: + out = self.midi_output + out.note_on(5, 30, 0) + out.note_off(5, 30, 0) + with self.assertRaises(ValueError) as cm: + out.note_off(5, 30, 25) + self.assertEqual(str(cm.exception), "Channel not between 0 and 15.") + with self.assertRaises(ValueError) as cm: + out.note_off(5, 30, -1) + self.assertEqual(str(cm.exception), "Channel not between 0 and 15.") + + def test_note_on(self): + if self.midi_output: + out = self.midi_output + out.note_on(5, 30, 0) + out.note_on(5, 42, 10) + with self.assertRaises(ValueError) as cm: + out.note_on(5, 30, 25) + self.assertEqual(str(cm.exception), "Channel not between 0 and 15.") + with self.assertRaises(ValueError) as cm: + out.note_on(5, 30, -1) + self.assertEqual(str(cm.exception), "Channel not between 0 and 15.") + + def test_set_instrument(self): + + if not self.midi_output: + self.skipTest("No midi device") + out = self.midi_output + out.set_instrument(5) + out.set_instrument(42, channel=2) + with self.assertRaises(ValueError) as cm: + out.set_instrument(-6) + self.assertEqual(str(cm.exception), "Undefined instrument id: -6") + with self.assertRaises(ValueError) as cm: + out.set_instrument(156) + self.assertEqual(str(cm.exception), "Undefined instrument id: 156") + with self.assertRaises(ValueError) as cm: + out.set_instrument(5, -1) + self.assertEqual(str(cm.exception), "Channel not between 0 and 15.") + with self.assertRaises(ValueError) as cm: + out.set_instrument(5, 16) + self.assertEqual(str(cm.exception), "Channel not between 0 and 15.") + + def test_write(self): + if not self.midi_output: + self.skipTest("No midi device") + + out = self.midi_output + out.write([[[0xC0, 0, 0], 20000]]) + # is equivalent to + out.write([[[0xC0], 20000]]) + # example from the docstring : + # 1. choose program change 1 at time 20000 and + # 2. send note 65 with velocity 100 500 ms later + out.write([[[0xC0, 0, 0], 20000], [[0x90, 60, 100], 20500]]) + + out.write([]) + verrry_long = [[[0x90, 60, i % 100], 20000 + 100 * i] for i in range(1024)] + out.write(verrry_long) + + too_long = [[[0x90, 60, i % 100], 20000 + 100 * i] for i in range(1025)] + self.assertRaises(IndexError, out.write, too_long) + # test wrong data + with self.assertRaises(TypeError) as cm: + out.write("Non sens ?") + error_msg = "unsupported operand type(s) for &: 'str' and 'int'" + self.assertEqual(str(cm.exception), error_msg) + + with self.assertRaises(TypeError) as cm: + out.write(["Hey what's that?"]) + self.assertEqual(str(cm.exception), error_msg) + + def test_write_short(self): + if not self.midi_output: + self.skipTest("No midi device") + + out = self.midi_output + # program change + out.write_short(0xC0) + # put a note on, then off. + out.write_short(0x90, 65, 100) + out.write_short(0x80, 65, 100) + out.write_short(0x90) + + def test_write_sys_ex(self): + if not self.midi_output: + self.skipTest("No midi device") + + out = self.midi_output + out.write_sys_ex(pygame.midi.time(), [0xF0, 0x7D, 0x10, 0x11, 0x12, 0x13, 0xF7]) + + def test_pitch_bend(self): + # FIXME : pitch_bend in the code, but not in documentation + if not self.midi_output: + self.skipTest("No midi device") + + out = self.midi_output + with self.assertRaises(ValueError) as cm: + out.pitch_bend(5, channel=-1) + self.assertEqual(str(cm.exception), "Channel not between 0 and 15.") + with self.assertRaises(ValueError) as cm: + out.pitch_bend(5, channel=16) + with self.assertRaises(ValueError) as cm: + out.pitch_bend(-10001, 1) + self.assertEqual( + str(cm.exception), + "Pitch bend value must be between " "-8192 and +8191, not -10001.", + ) + with self.assertRaises(ValueError) as cm: + out.pitch_bend(10665, 2) + + def test_close(self): + if not self.midi_output: + self.skipTest("No midi device") + self.assertIsNotNone(self.midi_output._output) + self.midi_output.close() + self.assertIsNone(self.midi_output._output) + + def test_abort(self): + if not self.midi_output: + self.skipTest("No midi device") + self.assertEqual(self.midi_output._aborted, 0) + self.midi_output.abort() + self.assertEqual(self.midi_output._aborted, 1) + + +class MidiModuleTest(unittest.TestCase): + """Midi module tests that require midi hardware or midi.init(). + + See MidiModuleNonInteractiveTest for non-interactive module tests. + """ + + __tags__ = ["interactive"] + + def setUp(self): + import pygame.midi + + pygame.midi.init() + + def tearDown(self): + pygame.midi.quit() + + def test_get_count(self): + c = pygame.midi.get_count() + self.assertIsInstance(c, int) + self.assertTrue(c >= 0) + + def test_get_default_input_id(self): + + midin_id = pygame.midi.get_default_input_id() + # if there is a not None return make sure it is an int. + self.assertIsInstance(midin_id, int) + self.assertTrue(midin_id >= -1) + pygame.midi.quit() + self.assertRaises(RuntimeError, pygame.midi.get_default_output_id) + + def test_get_default_output_id(self): + + c = pygame.midi.get_default_output_id() + self.assertIsInstance(c, int) + self.assertTrue(c >= -1) + pygame.midi.quit() + self.assertRaises(RuntimeError, pygame.midi.get_default_output_id) + + def test_get_device_info(self): + + an_id = pygame.midi.get_default_output_id() + if an_id != -1: + interf, name, input, output, opened = pygame.midi.get_device_info(an_id) + self.assertEqual(output, 1) + self.assertEqual(input, 0) + self.assertEqual(opened, 0) + + an_in_id = pygame.midi.get_default_input_id() + if an_in_id != -1: + r = pygame.midi.get_device_info(an_in_id) + # if r is None, it means that the id is out of range. + interf, name, input, output, opened = r + + self.assertEqual(output, 0) + self.assertEqual(input, 1) + self.assertEqual(opened, 0) + out_of_range = pygame.midi.get_count() + for num in range(out_of_range): + self.assertIsNotNone(pygame.midi.get_device_info(num)) + info = pygame.midi.get_device_info(out_of_range) + self.assertIsNone(info) + + def test_init(self): + + pygame.midi.quit() + self.assertRaises(RuntimeError, pygame.midi.get_count) + # initialising many times should be fine. + pygame.midi.init() + pygame.midi.init() + pygame.midi.init() + pygame.midi.init() + + self.assertTrue(pygame.midi.get_init()) + + def test_quit(self): + + # It is safe to call this more than once. + pygame.midi.quit() + pygame.midi.init() + pygame.midi.quit() + pygame.midi.quit() + pygame.midi.init() + pygame.midi.init() + pygame.midi.quit() + + self.assertFalse(pygame.midi.get_init()) + + def test_get_init(self): + # Already initialized as pygame.midi.init() was called in setUp(). + self.assertTrue(pygame.midi.get_init()) + + def test_time(self): + + mtime = pygame.midi.time() + self.assertIsInstance(mtime, int) + # should be close to 2-3... since the timer is just init'd. + self.assertTrue(0 <= mtime < 100) + + +class MidiModuleNonInteractiveTest(unittest.TestCase): + """Midi module tests that do not require midi hardware or midi.init(). + + See MidiModuleTest for interactive module tests. + """ + + def setUp(self): + import pygame.midi + + def test_midiin(self): + """Ensures the MIDIIN event id exists in the midi module. + + The MIDIIN event id can be accessed via the midi module for backward + compatibility. + """ + self.assertEqual(pygame.midi.MIDIIN, pygame.MIDIIN) + self.assertEqual(pygame.midi.MIDIIN, pygame.locals.MIDIIN) + + self.assertNotEqual(pygame.midi.MIDIIN, pygame.MIDIOUT) + self.assertNotEqual(pygame.midi.MIDIIN, pygame.locals.MIDIOUT) + + def test_midiout(self): + """Ensures the MIDIOUT event id exists in the midi module. + + The MIDIOUT event id can be accessed via the midi module for backward + compatibility. + """ + self.assertEqual(pygame.midi.MIDIOUT, pygame.MIDIOUT) + self.assertEqual(pygame.midi.MIDIOUT, pygame.locals.MIDIOUT) + + self.assertNotEqual(pygame.midi.MIDIOUT, pygame.MIDIIN) + self.assertNotEqual(pygame.midi.MIDIOUT, pygame.locals.MIDIIN) + + def test_MidiException(self): + """Ensures the MidiException is raised as expected.""" + + def raiseit(): + raise pygame.midi.MidiException("Hello Midi param") + + with self.assertRaises(pygame.midi.MidiException) as cm: + raiseit() + + self.assertEqual(cm.exception.parameter, "Hello Midi param") + + def test_midis2events(self): + """Ensures midi events are properly converted to pygame events.""" + # List/tuple indexes. + MIDI_DATA = 0 + MD_STATUS = 0 + MD_DATA1 = 1 + MD_DATA2 = 2 + MD_DATA3 = 3 + + TIMESTAMP = 1 + + # Midi events take the form of: + # ((status, data1, data2, data3), timestamp) + midi_events = ( + ((0xC0, 0, 1, 2), 20000), + ((0x90, 60, 1000, "string_data"), 20001), + (("0", "1", "2", "3"), "4"), + ) + expected_num_events = len(midi_events) + + # Test different device ids. + for device_id in range(3): + pg_events = pygame.midi.midis2events(midi_events, device_id) + + self.assertEqual(len(pg_events), expected_num_events) + + for i, pg_event in enumerate(pg_events): + # Get the original midi data for comparison. + midi_event = midi_events[i] + midi_event_data = midi_event[MIDI_DATA] + + # Can't directly check event instance as pygame.event.Event is + # a function. + # self.assertIsInstance(pg_event, pygame.event.Event) + self.assertEqual(pg_event.__class__.__name__, "Event") + self.assertEqual(pg_event.type, pygame.MIDIIN) + self.assertEqual(pg_event.status, midi_event_data[MD_STATUS]) + self.assertEqual(pg_event.data1, midi_event_data[MD_DATA1]) + self.assertEqual(pg_event.data2, midi_event_data[MD_DATA2]) + self.assertEqual(pg_event.data3, midi_event_data[MD_DATA3]) + self.assertEqual(pg_event.timestamp, midi_event[TIMESTAMP]) + self.assertEqual(pg_event.vice_id, device_id) + + def test_midis2events__missing_event_data(self): + """Ensures midi events with missing values are handled properly.""" + midi_event_missing_data = ((0xC0, 0, 1), 20000) + midi_event_missing_timestamp = ((0xC0, 0, 1, 2),) + + for midi_event in (midi_event_missing_data, midi_event_missing_timestamp): + with self.assertRaises(ValueError): + events = pygame.midi.midis2events([midi_event], 0) + + def test_midis2events__extra_event_data(self): + """Ensures midi events with extra values are handled properly.""" + midi_event_extra_data = ((0xC0, 0, 1, 2, "extra"), 20000) + midi_event_extra_timestamp = ((0xC0, 0, 1, 2), 20000, "extra") + + for midi_event in (midi_event_extra_data, midi_event_extra_timestamp): + with self.assertRaises(ValueError): + events = pygame.midi.midis2events([midi_event], 0) + + def test_midis2events__extra_event_data_missing_timestamp(self): + """Ensures midi events with extra data and no timestamps are handled + properly. + """ + midi_event_extra_data_no_timestamp = ((0xC0, 0, 1, 2, "extra"),) + + with self.assertRaises(ValueError): + events = pygame.midi.midis2events([midi_event_extra_data_no_timestamp], 0) + + def test_conversions(self): + """of frequencies to midi note numbers and ansi note names.""" + from pygame.midi import frequency_to_midi, midi_to_frequency, midi_to_ansi_note + + self.assertEqual(frequency_to_midi(27.5), 21) + self.assertEqual(frequency_to_midi(36.7), 26) + self.assertEqual(frequency_to_midi(4186.0), 108) + self.assertEqual(midi_to_frequency(21), 27.5) + self.assertEqual(midi_to_frequency(26), 36.7) + self.assertEqual(midi_to_frequency(108), 4186.0) + self.assertEqual(midi_to_ansi_note(21), "A0") + self.assertEqual(midi_to_ansi_note(71), "B4") + self.assertEqual(midi_to_ansi_note(82), "A#5") + self.assertEqual(midi_to_ansi_note(83), "B5") + self.assertEqual(midi_to_ansi_note(93), "A6") + self.assertEqual(midi_to_ansi_note(94), "A#6") + self.assertEqual(midi_to_ansi_note(95), "B6") + self.assertEqual(midi_to_ansi_note(96), "C7") + self.assertEqual(midi_to_ansi_note(102), "F#7") + self.assertEqual(midi_to_ansi_note(108), "C8") + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/mixer_music_tags.py b/venv/Lib/site-packages/pygame/tests/mixer_music_tags.py new file mode 100644 index 0000000..30f6893 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/mixer_music_tags.py @@ -0,0 +1,7 @@ +__tags__ = [] + +import pygame +import sys + +if "pygame.mixer_music" not in sys.modules: + __tags__.extend(("ignore", "subprocess_ignore")) diff --git a/venv/Lib/site-packages/pygame/tests/mixer_music_test.py b/venv/Lib/site-packages/pygame/tests/mixer_music_test.py new file mode 100644 index 0000000..3d1c1f7 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/mixer_music_test.py @@ -0,0 +1,415 @@ +# -*- coding: utf-8 -*- + +import os +import sys +import platform +import unittest +import time + +from pygame.tests.test_utils import example_path +import pygame + + +class MixerMusicModuleTest(unittest.TestCase): + @classmethod + def setUpClass(cls): + # Initializing the mixer is slow, so minimize the times it is called. + pygame.mixer.init() + + @classmethod + def tearDownClass(cls): + pygame.mixer.quit() + + def setUp(cls): + # This makes sure the mixer is always initialized before each test (in + # case a test calls pygame.mixer.quit()). + if pygame.mixer.get_init() is None: + pygame.mixer.init() + + def test_load_mp3(self): + "|tags:music|" + self.music_load("mp3") + + def test_load_ogg(self): + "|tags:music|" + self.music_load("ogg") + + def test_load_wav(self): + "|tags:music|" + self.music_load("wav") + + def music_load(self, format): + data_fname = example_path("data") + + path = os.path.join(data_fname, "house_lo.%s" % format) + if os.sep == "\\": + path = path.replace("\\", "\\\\") + umusfn = str(path) + bmusfn = umusfn.encode() + + pygame.mixer.music.load(umusfn) + pygame.mixer.music.load(bmusfn) + + def test_load_object(self): + """test loading music from file-like objects.""" + formats = ["ogg", "wav"] + data_fname = example_path("data") + for f in formats: + path = os.path.join(data_fname, "house_lo.%s" % f) + if os.sep == "\\": + path = path.replace("\\", "\\\\") + bmusfn = path.encode() + + with open(bmusfn, "rb") as musf: + pygame.mixer.music.load(musf) + + def test_object_namehint(self): + """test loading & queuing music from file-like objects with namehint argument.""" + formats = ["wav", "ogg"] + data_fname = example_path("data") + for f in formats: + path = os.path.join(data_fname, "house_lo.%s" % f) + if os.sep == "\\": + path = path.replace("\\", "\\\\") + bmusfn = path.encode() + + # these two "with open" blocks need to be separate, which is kinda weird + with open(bmusfn, "rb") as musf: + pygame.mixer.music.load(musf, f) + + with open(bmusfn, "rb") as musf: + pygame.mixer.music.queue(musf, f) + + with open(bmusfn, "rb") as musf: + pygame.mixer.music.load(musf, namehint=f) + + with open(bmusfn, "rb") as musf: + pygame.mixer.music.queue(musf, namehint=f) + + def test_load_unicode(self): + """test non-ASCII unicode path""" + import shutil + + ep = example_path("data") + temp_file = os.path.join(ep, u"你好.wav") + org_file = os.path.join(ep, u"house_lo.wav") + try: + with open(temp_file, "w") as f: + pass + os.remove(temp_file) + except IOError: + raise unittest.SkipTest("the path cannot be opened") + shutil.copy(org_file, temp_file) + try: + pygame.mixer.music.load(temp_file) + pygame.mixer.music.load(org_file) # unload + finally: + os.remove(temp_file) + + def test_unload(self): + import shutil + import tempfile + + ep = example_path("data") + org_file = os.path.join(ep, u"house_lo.wav") + tmpfd, tmppath = tempfile.mkstemp(".wav") + os.close(tmpfd) + shutil.copy(org_file, tmppath) + try: + pygame.mixer.music.load(tmppath) + pygame.mixer.music.unload() + finally: + os.remove(tmppath) + + def test_queue_mp3(self): + """Ensures queue() accepts mp3 files. + + |tags:music| + """ + filename = example_path(os.path.join("data", "house_lo.mp3")) + pygame.mixer.music.queue(filename) + + def test_queue_ogg(self): + """Ensures queue() accepts ogg files. + + |tags:music| + """ + filename = example_path(os.path.join("data", "house_lo.ogg")) + pygame.mixer.music.queue(filename) + + def test_queue_wav(self): + """Ensures queue() accepts wav files. + + |tags:music| + """ + filename = example_path(os.path.join("data", "house_lo.wav")) + pygame.mixer.music.queue(filename) + + def test_queue__multiple_calls(self): + """Ensures queue() can be called multiple times.""" + ogg_file = example_path(os.path.join("data", "house_lo.ogg")) + wav_file = example_path(os.path.join("data", "house_lo.wav")) + + pygame.mixer.music.queue(ogg_file) + pygame.mixer.music.queue(wav_file) + + def test_queue__arguments(self): + """Ensures queue() can be called with proper arguments.""" + wav_file = example_path(os.path.join("data", "house_lo.wav")) + + pygame.mixer.music.queue(wav_file, loops=2) + pygame.mixer.music.queue(wav_file, namehint="") + pygame.mixer.music.queue(wav_file, "") + pygame.mixer.music.queue(wav_file, "", 2) + + def test_queue__no_file(self): + """Ensures queue() correctly handles missing the file argument.""" + with self.assertRaises(TypeError): + pygame.mixer.music.queue() + + def test_queue__invalid_sound_type(self): + """Ensures queue() correctly handles invalid file types.""" + not_a_sound_file = example_path(os.path.join("data", "city.png")) + + with self.assertRaises(pygame.error): + pygame.mixer.music.queue(not_a_sound_file) + + def test_queue__invalid_filename(self): + """Ensures queue() correctly handles invalid filenames.""" + with self.assertRaises(pygame.error): + pygame.mixer.music.queue("") + + def test_music_pause__unpause(self): + """Ensure music has the correct position immediately after unpausing + + |tags:music| + """ + filename = example_path(os.path.join("data", "house_lo.mp3")) + pygame.mixer.music.load(filename) + pygame.mixer.music.play() + + # Wait 0.05s, then pause + time.sleep(0.05) + pygame.mixer.music.pause() + # Wait 0.05s, get position, unpause, then get position again + time.sleep(0.05) + before_unpause = pygame.mixer.music.get_pos() + pygame.mixer.music.unpause() + after_unpause = pygame.mixer.music.get_pos() + + self.assertEqual(before_unpause, after_unpause) + + def todo_test_stop(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer_music.stop: + + # Stops the music playback if it is currently playing. + + self.fail() + + def todo_test_rewind(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer_music.rewind: + + # Resets playback of the current music to the beginning. + + self.fail() + + def todo_test_get_pos(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer_music.get_pos: + + # This gets the number of milliseconds that the music has been playing + # for. The returned time only represents how long the music has been + # playing; it does not take into account any starting position + # offsets. + # + + self.fail() + + def todo_test_fadeout(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer_music.fadeout: + + # This will stop the music playback after it has been faded out over + # the specified time (measured in milliseconds). + # + # Note, that this function blocks until the music has faded out. + + self.fail() + + @unittest.skipIf( + os.environ.get("SDL_AUDIODRIVER") == "disk", + 'disk audio driver "playback" writing to disk is slow', + ) + def test_play__start_time(self): + + pygame.display.init() + + # music file is 7 seconds long + filename = example_path(os.path.join("data", "house_lo.ogg")) + pygame.mixer.music.load(filename) + start_time_in_seconds = 6.0 # 6 seconds + + music_finished = False + clock = pygame.time.Clock() + start_time_in_ms = clock.tick() + # should play the last 1 second + pygame.mixer.music.play(0, start=start_time_in_seconds) + running = True + while running: + pygame.event.pump() + + if not (pygame.mixer.music.get_busy() or music_finished): + music_finished = True + time_to_finish = (clock.tick() - start_time_in_ms) // 1000 + self.assertEqual(time_to_finish, 1) + running = False + + def todo_test_play(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer_music.play: + + # This will play the loaded music stream. If the music is already + # playing it will be restarted. + # + # The loops argument controls the number of repeats a music will play. + # play(5) will cause the music to played once, then repeated five + # times, for a total of six. If the loops is -1 then the music will + # repeat indefinitely. + # + # The starting position argument controls where in the music the song + # starts playing. The starting position is dependent on the format of + # music playing. MP3 and OGG use the position as time (in seconds). + # MOD music it is the pattern order number. Passing a startpos will + # raise a NotImplementedError if it cannot set the start position + # + + self.fail() + + def todo_test_load(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer_music.load: + + # This will load a music file and prepare it for playback. If a music + # stream is already playing it will be stopped. This does not start + # the music playing. + # + # Music can only be loaded from filenames, not python file objects + # like the other pygame loading functions. + # + + self.fail() + + def todo_test_get_volume(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer_music.get_volume: + + # Returns the current volume for the mixer. The value will be between + # 0.0 and 1.0. + # + + self.fail() + + def todo_test_set_endevent(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer_music.set_endevent: + + # This causes Pygame to signal (by means of the event queue) when the + # music is done playing. The argument determines the type of event + # that will be queued. + # + # The event will be queued every time the music finishes, not just the + # first time. To stop the event from being queued, call this method + # with no argument. + # + + self.fail() + + def todo_test_pause(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer_music.pause: + + # Temporarily stop playback of the music stream. It can be resumed + # with the pygame.mixer.music.unpause() function. + # + + self.fail() + + def test_get_busy(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer_music.get_busy: + + # Returns True when the music stream is actively playing. When the + # music is idle this returns False. + # + + self.music_load("ogg") + self.assertFalse(pygame.mixer.music.get_busy()) + pygame.mixer.music.play() + self.assertTrue(pygame.mixer.music.get_busy()) + pygame.mixer.music.pause() + self.assertFalse(pygame.mixer.music.get_busy()) + + def todo_test_get_endevent(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer_music.get_endevent: + + # Returns the event type to be sent every time the music finishes + # playback. If there is no endevent the function returns + # pygame.NOEVENT. + # + + self.fail() + + def todo_test_unpause(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer_music.unpause: + + # This will resume the playback of a music stream after it has been paused. + + self.fail() + + def todo_test_set_volume(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer_music.set_volume: + + # Set the volume of the music playback. The value argument is between + # 0.0 and 1.0. When new music is loaded the volume is reset. + # + + self.fail() + + def todo_test_set_pos(self): + + # __doc__ (as of 2010-24-05) for pygame.mixer_music.set_pos: + + # This sets the position in the music file where playback will start. The + # meaning of "pos", a float (or a number that can be converted to a float), + # depends on the music format. Newer versions of SDL_mixer have better + # positioning support than earlier. An SDLError is raised if a particular + # format does not support positioning. + # + + self.fail() + + def test_init(self): + """issue #955. unload music whenever mixer.quit() is called""" + import tempfile + import shutil + + testfile = example_path(os.path.join("data", "house_lo.wav")) + tempcopy = os.path.join(tempfile.gettempdir(), "tempfile.wav") + + for i in range(10): + pygame.mixer.init() + try: + shutil.copy2(testfile, tempcopy) + pygame.mixer.music.load(tempcopy) + pygame.mixer.quit() + finally: + os.remove(tempcopy) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/mixer_tags.py b/venv/Lib/site-packages/pygame/tests/mixer_tags.py new file mode 100644 index 0000000..06a9de2 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/mixer_tags.py @@ -0,0 +1,7 @@ +__tags__ = [] + +import pygame +import sys + +if "pygame.mixer" not in sys.modules: + __tags__.extend(("ignore", "subprocess_ignore")) diff --git a/venv/Lib/site-packages/pygame/tests/mixer_test.py b/venv/Lib/site-packages/pygame/tests/mixer_test.py new file mode 100644 index 0000000..0d5985d --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/mixer_test.py @@ -0,0 +1,1193 @@ +# -*- coding: utf8 -*- + +import sys +import os +import unittest +import pathlib +import platform + +from pygame.tests.test_utils import example_path, AssertRaisesRegexMixin + +import pygame +from pygame import mixer + +IS_PYPY = "PyPy" == platform.python_implementation() + +################################### CONSTANTS ################################## + +FREQUENCIES = [11025, 22050, 44100, 48000] +SIZES = [-16, -8, 8, 16] # fixme +# size 32 failed in test_get_init__returns_exact_values_used_for_init +CHANNELS = [1, 2] +BUFFERS = [3024] + +CONFIGS = [ + {"frequency": f, "size": s, "channels": c} + for f in FREQUENCIES + for s in SIZES + for c in CHANNELS +] +# Using all CONFIGS fails on a Mac; probably older SDL_mixer; we could do: +# if platform.system() == 'Darwin': +# But using all CONFIGS is very slow (> 10 sec for example) +# And probably, we don't need to be so exhaustive, hence: + +CONFIG = {"frequency": 44100, "size": 32, "channels": 2, "allowedchanges": 0} + + +class InvalidBool(object): + """To help test invalid bool values.""" + + __nonzero__ = None + __bool__ = None + + +############################## MODULE LEVEL TESTS ############################# + + +class MixerModuleTest(unittest.TestCase): + def tearDown(self): + mixer.quit() + mixer.pre_init(0, 0, 0, 0) + + def test_init__keyword_args(self): + # note: this test used to loop over all CONFIGS, but it's very slow.. + mixer.init(**CONFIG) + mixer_conf = mixer.get_init() + + self.assertEqual(mixer_conf[0], CONFIG["frequency"]) + # Not all "sizes" are supported on all systems, hence "abs". + self.assertEqual(abs(mixer_conf[1]), abs(CONFIG["size"])) + self.assertGreaterEqual(mixer_conf[2], CONFIG["channels"]) + + def test_pre_init__keyword_args(self): + # note: this test used to loop over all CONFIGS, but it's very slow.. + mixer.pre_init(**CONFIG) + mixer.init() + + mixer_conf = mixer.get_init() + + self.assertEqual(mixer_conf[0], CONFIG["frequency"]) + # Not all "sizes" are supported on all systems, hence "abs". + self.assertEqual(abs(mixer_conf[1]), abs(CONFIG["size"])) + self.assertGreaterEqual(mixer_conf[2], CONFIG["channels"]) + + def test_pre_init__zero_values(self): + # Ensure that argument values of 0 are replaced with + # default values. No way to check buffer size though. + mixer.pre_init(22050, -8, 1) # Non default values + mixer.pre_init(0, 0, 0) # Should reset to default values + mixer.init(allowedchanges=0) + self.assertEqual(mixer.get_init()[0], 44100) + self.assertEqual(mixer.get_init()[1], -16) + self.assertGreaterEqual(mixer.get_init()[2], 2) + + def test_init__zero_values(self): + # Ensure that argument values of 0 are replaced with + # preset values. No way to check buffer size though. + mixer.pre_init(44100, 8, 1, allowedchanges=0) # None default values + mixer.init(0, 0, 0) + self.assertEqual(mixer.get_init(), (44100, 8, 1)) + + def test_get_init__returns_exact_values_used_for_init(self): + # TODO: size 32 fails in this test (maybe SDL_mixer bug) + + for init_conf in CONFIGS: + frequency, size, channels = init_conf.values() + if (frequency, size) == (22050, 16): + continue + mixer.init(frequency, size, channels) + + mixer_conf = mixer.get_init() + + self.assertEqual(tuple(init_conf.values()), mixer_conf) + mixer.quit() + + def test_get_init__returns_None_if_mixer_not_initialized(self): + self.assertIsNone(mixer.get_init()) + + def test_get_num_channels__defaults_eight_after_init(self): + mixer.init() + self.assertEqual(mixer.get_num_channels(), 8) + + def test_set_num_channels(self): + mixer.init() + + default_num_channels = mixer.get_num_channels() + for i in range(1, default_num_channels + 1): + mixer.set_num_channels(i) + self.assertEqual(mixer.get_num_channels(), i) + + def test_quit(self): + """get_num_channels() Should throw pygame.error if uninitialized + after mixer.quit()""" + mixer.init() + mixer.quit() + self.assertRaises(pygame.error, mixer.get_num_channels) + + # TODO: FIXME: appveyor and pypy (on linux) fails here sometimes. + @unittest.skipIf(sys.platform.startswith("win"), "See github issue 892.") + @unittest.skipIf(IS_PYPY, "random errors here with pypy") + def test_sound_args(self): + def get_bytes(snd): + return snd.get_raw() + + mixer.init() + + sample = b"\x00\xff" * 24 + wave_path = example_path(os.path.join("data", "house_lo.wav")) + uwave_path = str(wave_path) + bwave_path = uwave_path.encode(sys.getfilesystemencoding()) + snd = mixer.Sound(file=wave_path) + self.assertTrue(snd.get_length() > 0.5) + snd_bytes = get_bytes(snd) + self.assertTrue(len(snd_bytes) > 1000) + + self.assertEqual(get_bytes(mixer.Sound(wave_path)), snd_bytes) + + self.assertEqual(get_bytes(mixer.Sound(file=uwave_path)), snd_bytes) + self.assertEqual(get_bytes(mixer.Sound(uwave_path)), snd_bytes) + arg_emsg = "Sound takes either 1 positional or 1 keyword argument" + + with self.assertRaises(TypeError) as cm: + mixer.Sound() + self.assertEqual(str(cm.exception), arg_emsg) + with self.assertRaises(TypeError) as cm: + mixer.Sound(wave_path, buffer=sample) + self.assertEqual(str(cm.exception), arg_emsg) + with self.assertRaises(TypeError) as cm: + mixer.Sound(sample, file=wave_path) + self.assertEqual(str(cm.exception), arg_emsg) + with self.assertRaises(TypeError) as cm: + mixer.Sound(buffer=sample, file=wave_path) + self.assertEqual(str(cm.exception), arg_emsg) + + with self.assertRaises(TypeError) as cm: + mixer.Sound(foobar=sample) + self.assertEqual(str(cm.exception), "Unrecognized keyword argument 'foobar'") + + snd = mixer.Sound(wave_path, **{}) + self.assertEqual(get_bytes(snd), snd_bytes) + snd = mixer.Sound(*[], **{"file": wave_path}) + + with self.assertRaises(TypeError) as cm: + mixer.Sound([]) + self.assertEqual(str(cm.exception), "Unrecognized argument (type list)") + + with self.assertRaises(TypeError) as cm: + snd = mixer.Sound(buffer=[]) + emsg = "Expected object with buffer interface: got a list" + self.assertEqual(str(cm.exception), emsg) + + ufake_path = str("12345678") + self.assertRaises(IOError, mixer.Sound, ufake_path) + self.assertRaises(IOError, mixer.Sound, "12345678") + + with self.assertRaises(TypeError) as cm: + mixer.Sound(buffer=str("something")) + emsg = "Unicode object not allowed as buffer object" + self.assertEqual(str(cm.exception), emsg) + self.assertEqual(get_bytes(mixer.Sound(buffer=sample)), sample) + if type(sample) != str: + somebytes = get_bytes(mixer.Sound(sample)) + # on python 2 we do not allow using string except as file name. + self.assertEqual(somebytes, sample) + self.assertEqual(get_bytes(mixer.Sound(file=bwave_path)), snd_bytes) + self.assertEqual(get_bytes(mixer.Sound(bwave_path)), snd_bytes) + + snd = mixer.Sound(wave_path) + with self.assertRaises(TypeError) as cm: + mixer.Sound(wave_path, array=snd) + self.assertEqual(str(cm.exception), arg_emsg) + with self.assertRaises(TypeError) as cm: + mixer.Sound(buffer=sample, array=snd) + self.assertEqual(str(cm.exception), arg_emsg) + snd2 = mixer.Sound(array=snd) + self.assertEqual(snd.get_raw(), snd2.get_raw()) + + def test_sound_unicode(self): + """test non-ASCII unicode path""" + mixer.init() + import shutil + + ep = example_path("data") + temp_file = os.path.join(ep, u"你好.wav") + org_file = os.path.join(ep, u"house_lo.wav") + shutil.copy(org_file, temp_file) + try: + with open(temp_file, "rb") as f: + pass + except IOError: + raise unittest.SkipTest("the path cannot be opened") + + try: + sound = mixer.Sound(temp_file) + del sound + finally: + os.remove(temp_file) + + @unittest.skipIf( + os.environ.get("SDL_AUDIODRIVER") == "disk", + "this test fails without real sound card", + ) + def test_array_keyword(self): + try: + from numpy import ( + array, + arange, + zeros, + int8, + uint8, + int16, + uint16, + int32, + uint32, + ) + except ImportError: + self.skipTest("requires numpy") + + freq = 22050 + format_list = [-8, 8, -16, 16] + channels_list = [1, 2] + + a_lists = dict((f, []) for f in format_list) + a32u_mono = arange(0, 256, 1, uint32) + a16u_mono = a32u_mono.astype(uint16) + a8u_mono = a32u_mono.astype(uint8) + au_list_mono = [(1, a) for a in [a8u_mono, a16u_mono, a32u_mono]] + for format in format_list: + if format > 0: + a_lists[format].extend(au_list_mono) + a32s_mono = arange(-128, 128, 1, int32) + a16s_mono = a32s_mono.astype(int16) + a8s_mono = a32s_mono.astype(int8) + as_list_mono = [(1, a) for a in [a8s_mono, a16s_mono, a32s_mono]] + for format in format_list: + if format < 0: + a_lists[format].extend(as_list_mono) + a32u_stereo = zeros([a32u_mono.shape[0], 2], uint32) + a32u_stereo[:, 0] = a32u_mono + a32u_stereo[:, 1] = 255 - a32u_mono + a16u_stereo = a32u_stereo.astype(uint16) + a8u_stereo = a32u_stereo.astype(uint8) + au_list_stereo = [(2, a) for a in [a8u_stereo, a16u_stereo, a32u_stereo]] + for format in format_list: + if format > 0: + a_lists[format].extend(au_list_stereo) + a32s_stereo = zeros([a32s_mono.shape[0], 2], int32) + a32s_stereo[:, 0] = a32s_mono + a32s_stereo[:, 1] = -1 - a32s_mono + a16s_stereo = a32s_stereo.astype(int16) + a8s_stereo = a32s_stereo.astype(int8) + as_list_stereo = [(2, a) for a in [a8s_stereo, a16s_stereo, a32s_stereo]] + for format in format_list: + if format < 0: + a_lists[format].extend(as_list_stereo) + + for format in format_list: + for channels in channels_list: + try: + mixer.init(freq, format, channels) + except pygame.error: + # Some formats (e.g. 16) may not be supported. + continue + try: + __, f, c = mixer.get_init() + if f != format or c != channels: + # Some formats (e.g. -8) may not be supported. + continue + for c, a in a_lists[format]: + self._test_array_argument(format, a, c == channels) + finally: + mixer.quit() + + def _test_array_argument(self, format, a, test_pass): + from numpy import array, all as all_ + + try: + snd = mixer.Sound(array=a) + except ValueError: + if not test_pass: + return + self.fail("Raised ValueError: Format %i, dtype %s" % (format, a.dtype)) + if not test_pass: + self.fail( + "Did not raise ValueError: Format %i, dtype %s" % (format, a.dtype) + ) + a2 = array(snd) + a3 = a.astype(a2.dtype) + lshift = abs(format) - 8 * a.itemsize + if lshift >= 0: + # This is asymmetric with respect to downcasting. + a3 <<= lshift + self.assertTrue(all_(a2 == a3), "Format %i, dtype %s" % (format, a.dtype)) + + def _test_array_interface_fail(self, a): + self.assertRaises(ValueError, mixer.Sound, array=a) + + def test_array_interface(self): + mixer.init(22050, -16, 1, allowedchanges=0) + snd = mixer.Sound(buffer=b"\x00\x7f" * 20) + d = snd.__array_interface__ + self.assertTrue(isinstance(d, dict)) + if pygame.get_sdl_byteorder() == pygame.LIL_ENDIAN: + typestr = "") if is_lil_endian else (">", "<") + shape = (10, channels)[:ndim] + strides = (channels * itemsize, itemsize)[2 - ndim :] + exp = Exporter(shape, format=frev + "i") + snd = mixer.Sound(array=exp) + buflen = len(exp) * itemsize * channels + imp = Importer(snd, buftools.PyBUF_SIMPLE) + self.assertEqual(imp.ndim, 0) + self.assertTrue(imp.format is None) + self.assertEqual(imp.len, buflen) + self.assertEqual(imp.itemsize, itemsize) + self.assertTrue(imp.shape is None) + self.assertTrue(imp.strides is None) + self.assertTrue(imp.suboffsets is None) + self.assertFalse(imp.readonly) + self.assertEqual(imp.buf, snd._samples_address) + imp = Importer(snd, buftools.PyBUF_WRITABLE) + self.assertEqual(imp.ndim, 0) + self.assertTrue(imp.format is None) + self.assertEqual(imp.len, buflen) + self.assertEqual(imp.itemsize, itemsize) + self.assertTrue(imp.shape is None) + self.assertTrue(imp.strides is None) + self.assertTrue(imp.suboffsets is None) + self.assertFalse(imp.readonly) + self.assertEqual(imp.buf, snd._samples_address) + imp = Importer(snd, buftools.PyBUF_FORMAT) + self.assertEqual(imp.ndim, 0) + self.assertEqual(imp.format, format) + self.assertEqual(imp.len, buflen) + self.assertEqual(imp.itemsize, itemsize) + self.assertTrue(imp.shape is None) + self.assertTrue(imp.strides is None) + self.assertTrue(imp.suboffsets is None) + self.assertFalse(imp.readonly) + self.assertEqual(imp.buf, snd._samples_address) + imp = Importer(snd, buftools.PyBUF_ND) + self.assertEqual(imp.ndim, ndim) + self.assertTrue(imp.format is None) + self.assertEqual(imp.len, buflen) + self.assertEqual(imp.itemsize, itemsize) + self.assertEqual(imp.shape, shape) + self.assertTrue(imp.strides is None) + self.assertTrue(imp.suboffsets is None) + self.assertFalse(imp.readonly) + self.assertEqual(imp.buf, snd._samples_address) + imp = Importer(snd, buftools.PyBUF_STRIDES) + self.assertEqual(imp.ndim, ndim) + self.assertTrue(imp.format is None) + self.assertEqual(imp.len, buflen) + self.assertEqual(imp.itemsize, itemsize) + self.assertEqual(imp.shape, shape) + self.assertEqual(imp.strides, strides) + self.assertTrue(imp.suboffsets is None) + self.assertFalse(imp.readonly) + self.assertEqual(imp.buf, snd._samples_address) + imp = Importer(snd, buftools.PyBUF_FULL_RO) + self.assertEqual(imp.ndim, ndim) + self.assertEqual(imp.format, format) + self.assertEqual(imp.len, buflen) + self.assertEqual(imp.itemsize, 2) + self.assertEqual(imp.shape, shape) + self.assertEqual(imp.strides, strides) + self.assertTrue(imp.suboffsets is None) + self.assertFalse(imp.readonly) + self.assertEqual(imp.buf, snd._samples_address) + imp = Importer(snd, buftools.PyBUF_FULL_RO) + self.assertEqual(imp.ndim, ndim) + self.assertEqual(imp.format, format) + self.assertEqual(imp.len, buflen) + self.assertEqual(imp.itemsize, itemsize) + self.assertEqual(imp.shape, exp.shape) + self.assertEqual(imp.strides, strides) + self.assertTrue(imp.suboffsets is None) + self.assertFalse(imp.readonly) + self.assertEqual(imp.buf, snd._samples_address) + imp = Importer(snd, buftools.PyBUF_C_CONTIGUOUS) + self.assertEqual(imp.ndim, ndim) + self.assertTrue(imp.format is None) + self.assertEqual(imp.strides, strides) + imp = Importer(snd, buftools.PyBUF_ANY_CONTIGUOUS) + self.assertEqual(imp.ndim, ndim) + self.assertTrue(imp.format is None) + self.assertEqual(imp.strides, strides) + if ndim == 1: + imp = Importer(snd, buftools.PyBUF_F_CONTIGUOUS) + self.assertEqual(imp.ndim, 1) + self.assertTrue(imp.format is None) + self.assertEqual(imp.strides, strides) + else: + self.assertRaises(BufferError, Importer, snd, buftools.PyBUF_F_CONTIGUOUS) + + def todo_test_fadeout(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer.fadeout: + + # pygame.mixer.fadeout(time): return None + # fade out the volume on all sounds before stopping + # + # This will fade out the volume on all active channels over the time + # argument in milliseconds. After the sound is muted the playback will + # stop. + # + + self.fail() + + def test_find_channel(self): + # __doc__ (as of 2008-08-02) for pygame.mixer.find_channel: + + # pygame.mixer.find_channel(force=False): return Channel + # find an unused channel + mixer.init() + + filename = example_path(os.path.join("data", "house_lo.wav")) + sound = mixer.Sound(file=filename) + + num_channels = mixer.get_num_channels() + + if num_channels > 0: + found_channel = mixer.find_channel() + self.assertIsNotNone(found_channel) + + # try playing on all channels + channels = [] + for channel_id in range(0, num_channels): + channel = mixer.Channel(channel_id) + channel.play(sound) + channels.append(channel) + + # should fail without being forceful + found_channel = mixer.find_channel() + self.assertIsNone(found_channel) + + # try forcing without keyword + found_channel = mixer.find_channel(True) + self.assertIsNotNone(found_channel) + + # try forcing with keyword + found_channel = mixer.find_channel(force=True) + self.assertIsNotNone(found_channel) + + for channel in channels: + channel.stop() + found_channel = mixer.find_channel() + self.assertIsNotNone(found_channel) + + def todo_test_get_busy(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer.get_busy: + + # pygame.mixer.get_busy(): return bool + # test if any sound is being mixed + # + # Returns True if the mixer is busy mixing any channels. If the mixer + # is idle then this return False. + # + + self.fail() + + def todo_test_pause(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer.pause: + + # pygame.mixer.pause(): return None + # temporarily stop playback of all sound channels + # + # This will temporarily stop all playback on the active mixer + # channels. The playback can later be resumed with + # pygame.mixer.unpause() + # + + self.fail() + + def test_set_reserved(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer.set_reserved: + + # pygame.mixer.set_reserved(count): return count + mixer.init() + default_num_channels = mixer.get_num_channels() + + # try reserving all the channels + result = mixer.set_reserved(default_num_channels) + self.assertEqual(result, default_num_channels) + + # try reserving all the channels + 1 + result = mixer.set_reserved(default_num_channels + 1) + # should still be default + self.assertEqual(result, default_num_channels) + + # try unreserving all + result = mixer.set_reserved(0) + # should still be default + self.assertEqual(result, 0) + + # try reserving half + result = mixer.set_reserved(int(default_num_channels / 2)) + # should still be default + self.assertEqual(result, int(default_num_channels / 2)) + + def todo_test_stop(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer.stop: + + # pygame.mixer.stop(): return None + # stop playback of all sound channels + # + # This will stop all playback of all active mixer channels. + + self.fail() + + def todo_test_unpause(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer.unpause: + + # pygame.mixer.unpause(): return None + # resume paused playback of sound channels + # + # This will resume all active sound channels after they have been paused. + + self.fail() + + def test_get_sdl_mixer_version(self): + """Ensures get_sdl_mixer_version works correctly with no args.""" + expected_length = 3 + expected_type = tuple + expected_item_type = int + + version = pygame.mixer.get_sdl_mixer_version() + + self.assertIsInstance(version, expected_type) + self.assertEqual(len(version), expected_length) + + for item in version: + self.assertIsInstance(item, expected_item_type) + + def test_get_sdl_mixer_version__args(self): + """Ensures get_sdl_mixer_version works correctly using args.""" + expected_length = 3 + expected_type = tuple + expected_item_type = int + + for value in (True, False): + version = pygame.mixer.get_sdl_mixer_version(value) + + self.assertIsInstance(version, expected_type) + self.assertEqual(len(version), expected_length) + + for item in version: + self.assertIsInstance(item, expected_item_type) + + def test_get_sdl_mixer_version__kwargs(self): + """Ensures get_sdl_mixer_version works correctly using kwargs.""" + expected_length = 3 + expected_type = tuple + expected_item_type = int + + for value in (True, False): + version = pygame.mixer.get_sdl_mixer_version(linked=value) + + self.assertIsInstance(version, expected_type) + self.assertEqual(len(version), expected_length) + + for item in version: + self.assertIsInstance(item, expected_item_type) + + def test_get_sdl_mixer_version__invalid_args_kwargs(self): + """Ensures get_sdl_mixer_version handles invalid args and kwargs.""" + invalid_bool = InvalidBool() + + with self.assertRaises(TypeError): + version = pygame.mixer.get_sdl_mixer_version(invalid_bool) + + with self.assertRaises(TypeError): + version = pygame.mixer.get_sdl_mixer_version(linked=invalid_bool) + + def test_get_sdl_mixer_version__linked_equals_compiled(self): + """Ensures get_sdl_mixer_version's linked/compiled versions are equal.""" + linked_version = pygame.mixer.get_sdl_mixer_version(linked=True) + complied_version = pygame.mixer.get_sdl_mixer_version(linked=False) + + self.assertTupleEqual(linked_version, complied_version) + + +############################## CHANNEL CLASS TESTS ############################# + + +class ChannelTypeTest(AssertRaisesRegexMixin, unittest.TestCase): + @classmethod + def setUpClass(cls): + # Initializing the mixer is slow, so minimize the times it is called. + mixer.init() + + @classmethod + def tearDownClass(cls): + mixer.quit() + + def setUp(cls): + # This makes sure the mixer is always initialized before each test (in + # case a test calls pygame.mixer.quit()). + if mixer.get_init() is None: + mixer.init() + + def test_channel(self): + """Ensure Channel() creation works.""" + channel = mixer.Channel(0) + + self.assertIsInstance(channel, mixer.ChannelType) + self.assertEqual(channel.__class__.__name__, "Channel") + + def test_channel__without_arg(self): + """Ensure exception for Channel() creation with no argument.""" + with self.assertRaises(TypeError): + mixer.Channel() + + def test_channel__invalid_id(self): + """Ensure exception for Channel() creation with an invalid id.""" + with self.assertRaises(IndexError): + mixer.Channel(-1) + + def test_channel__before_init(self): + """Ensure exception for Channel() creation with non-init mixer.""" + mixer.quit() + + with self.assertRaisesRegex(pygame.error, "mixer not initialized"): + mixer.Channel(0) + + def todo_test_fadeout(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer.Channel.fadeout: + + # Channel.fadeout(time): return None + # stop playback after fading channel out + # + # Stop playback of a channel after fading out the sound over the given + # time argument in milliseconds. + # + + self.fail() + + def test_get_busy(self): + """Ensure an idle channel's busy state is correct.""" + expected_busy = False + channel = mixer.Channel(0) + + busy = channel.get_busy() + + self.assertEqual(busy, expected_busy) + + def todo_test_get_busy__active(self): + """Ensure an active channel's busy state is correct.""" + self.fail() + + def todo_test_get_endevent(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer.Channel.get_endevent: + + # Channel.get_endevent(): return type + # get the event a channel sends when playback stops + # + # Returns the event type to be sent every time the Channel finishes + # playback of a Sound. If there is no endevent the function returns + # pygame.NOEVENT. + # + + self.fail() + + def todo_test_get_queue(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer.Channel.get_queue: + + # Channel.get_queue(): return Sound + # return any Sound that is queued + # + # If a Sound is already queued on this channel it will be returned. + # Once the queued sound begins playback it will no longer be on the + # queue. + # + + self.fail() + + def todo_test_get_sound(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer.Channel.get_sound: + + # Channel.get_sound(): return Sound + # get the currently playing Sound + # + # Return the actual Sound object currently playing on this channel. If + # the channel is idle None is returned. + # + + self.fail() + + def test_get_volume(self): + """Ensure a channel's volume can be retrieved.""" + expected_volume = 1.0 # default + channel = mixer.Channel(0) + + volume = channel.get_volume() + + self.assertAlmostEqual(volume, expected_volume) + + def todo_test_get_volume__while_playing(self): + """Ensure a channel's volume can be retrieved while playing.""" + self.fail() + + def todo_test_pause(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer.Channel.pause: + + # Channel.pause(): return None + # temporarily stop playback of a channel + # + # Temporarily stop the playback of sound on a channel. It can be + # resumed at a later time with Channel.unpause() + # + + self.fail() + + def todo_test_play(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer.Channel.play: + + # Channel.play(Sound, loops=0, maxtime=0, fade_ms=0): return None + # play a Sound on a specific Channel + # + # This will begin playback of a Sound on a specific Channel. If the + # Channel is currently playing any other Sound it will be stopped. + # + # The loops argument has the same meaning as in Sound.play(): it is + # the number of times to repeat the sound after the first time. If it + # is 3, the sound will be played 4 times (the first time, then three + # more). If loops is -1 then the playback will repeat indefinitely. + # + # As in Sound.play(), the maxtime argument can be used to stop + # playback of the Sound after a given number of milliseconds. + # + # As in Sound.play(), the fade_ms argument can be used fade in the sound. + + self.fail() + + def todo_test_queue(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer.Channel.queue: + + # Channel.queue(Sound): return None + # queue a Sound object to follow the current + # + # When a Sound is queued on a Channel, it will begin playing + # immediately after the current Sound is finished. Each channel can + # only have a single Sound queued at a time. The queued Sound will + # only play if the current playback finished automatically. It is + # cleared on any other call to Channel.stop() or Channel.play(). + # + # If there is no sound actively playing on the Channel then the Sound + # will begin playing immediately. + # + + self.fail() + + def todo_test_set_endevent(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer.Channel.set_endevent: + + # Channel.set_endevent(): return None + # Channel.set_endevent(type): return None + # have the channel send an event when playback stops + # + # When an endevent is set for a channel, it will send an event to the + # pygame queue every time a sound finishes playing on that channel + # (not just the first time). Use pygame.event.get() to retrieve the + # endevent once it's sent. + # + # Note that if you called Sound.play(n) or Channel.play(sound,n), the + # end event is sent only once: after the sound has been played "n+1" + # times (see the documentation of Sound.play). + # + # If Channel.stop() or Channel.play() is called while the sound was + # still playing, the event will be posted immediately. + # + # The type argument will be the event id sent to the queue. This can + # be any valid event type, but a good choice would be a value between + # pygame.locals.USEREVENT and pygame.locals.NUMEVENTS. If no type + # argument is given then the Channel will stop sending endevents. + # + + self.fail() + + def todo_test_set_volume(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer.Channel.set_volume: + + # Channel.set_volume(value): return None + # Channel.set_volume(left, right): return None + # set the volume of a playing channel + # + # Set the volume (loudness) of a playing sound. When a channel starts + # to play its volume value is reset. This only affects the current + # sound. The value argument is between 0.0 and 1.0. + # + # If one argument is passed, it will be the volume of both speakers. + # If two arguments are passed and the mixer is in stereo mode, the + # first argument will be the volume of the left speaker and the second + # will be the volume of the right speaker. (If the second argument is + # None, the first argument will be the volume of both speakers.) + # + # If the channel is playing a Sound on which set_volume() has also + # been called, both calls are taken into account. For example: + # + # sound = pygame.mixer.Sound("s.wav") + # channel = s.play() # Sound plays at full volume by default + # sound.set_volume(0.9) # Now plays at 90% of full volume. + # sound.set_volume(0.6) # Now plays at 60% (previous value replaced). + # channel.set_volume(0.5) # Now plays at 30% (0.6 * 0.5). + + self.fail() + + def todo_test_stop(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer.Channel.stop: + + # Channel.stop(): return None + # stop playback on a Channel + # + # Stop sound playback on a channel. After playback is stopped the + # channel becomes available for new Sounds to play on it. + # + + self.fail() + + def todo_test_unpause(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer.Channel.unpause: + + # Channel.unpause(): return None + # resume pause playback of a channel + # + # Resume the playback on a paused channel. + + self.fail() + + +############################### SOUND CLASS TESTS ############################## + + +class SoundTypeTest(AssertRaisesRegexMixin, unittest.TestCase): + @classmethod + def tearDownClass(cls): + mixer.quit() + + def setUp(cls): + # This makes sure the mixer is always initialized before each test (in + # case a test calls pygame.mixer.quit()). + if mixer.get_init() is None: + mixer.init() + + # See MixerModuleTest's methods test_sound_args(), test_sound_unicode(), + # and test_array_keyword() for additional testing of Sound() creation. + def test_sound(self): + """Ensure Sound() creation with a filename works.""" + filename = example_path(os.path.join("data", "house_lo.wav")) + sound1 = mixer.Sound(filename) + sound2 = mixer.Sound(file=filename) + + self.assertIsInstance(sound1, mixer.Sound) + self.assertIsInstance(sound2, mixer.Sound) + + def test_sound__from_file_object(self): + """Ensure Sound() creation with a file object works.""" + filename = example_path(os.path.join("data", "house_lo.wav")) + + # Using 'with' ensures the file is closed even if test fails. + with open(filename, "rb") as file_obj: + sound = mixer.Sound(file_obj) + + self.assertIsInstance(sound, mixer.Sound) + + def test_sound__from_sound_object(self): + """Ensure Sound() creation with a Sound() object works.""" + filename = example_path(os.path.join("data", "house_lo.wav")) + sound_obj = mixer.Sound(file=filename) + + sound = mixer.Sound(sound_obj) + + self.assertIsInstance(sound, mixer.Sound) + + def test_sound__from_pathlib(self): + """Ensure Sound() creation with a pathlib.Path object works.""" + path = pathlib.Path(example_path(os.path.join("data", "house_lo.wav"))) + sound1 = mixer.Sound(path) + sound2 = mixer.Sound(file=path) + self.assertIsInstance(sound1, mixer.Sound) + self.assertIsInstance(sound2, mixer.Sound) + + def todo_test_sound__from_buffer(self): + """Ensure Sound() creation with a buffer works.""" + self.fail() + + def todo_test_sound__from_array(self): + """Ensure Sound() creation with an array works.""" + self.fail() + + def test_sound__without_arg(self): + """Ensure exception raised for Sound() creation with no argument.""" + with self.assertRaises(TypeError): + mixer.Sound() + + def test_sound__before_init(self): + """Ensure exception raised for Sound() creation with non-init mixer.""" + mixer.quit() + filename = example_path(os.path.join("data", "house_lo.wav")) + + with self.assertRaisesRegex(pygame.error, "mixer not initialized"): + mixer.Sound(file=filename) + + @unittest.skipIf(IS_PYPY, "pypy skip") + def test_samples_address(self): + """Test the _samples_address getter.""" + try: + from ctypes import pythonapi, c_void_p, py_object + + Bytes_FromString = pythonapi.PyBytes_FromString + + Bytes_FromString.restype = c_void_p + Bytes_FromString.argtypes = [py_object] + samples = b"abcdefgh" # keep byte size a multiple of 4 + sample_bytes = Bytes_FromString(samples) + + snd = mixer.Sound(buffer=samples) + + self.assertNotEqual(snd._samples_address, sample_bytes) + finally: + pygame.mixer.quit() + with self.assertRaisesRegex(pygame.error, "mixer not initialized"): + snd._samples_address + + def todo_test_fadeout(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer.Sound.fadeout: + + # Sound.fadeout(time): return None + # stop sound playback after fading out + # + # This will stop playback of the sound after fading it out over the + # time argument in milliseconds. The Sound will fade and stop on all + # actively playing channels. + # + + self.fail() + + def test_get_length(self): + """Tests if get_length returns a correct length.""" + try: + for size in SIZES: + pygame.mixer.quit() + pygame.mixer.init(size=size) + filename = example_path(os.path.join("data", "punch.wav")) + sound = mixer.Sound(file=filename) + # The sound data is in the mixer output format. So dividing the + # length of the raw sound data by the mixer settings gives + # the expected length of the sound. + sound_bytes = sound.get_raw() + mix_freq, mix_bits, mix_channels = pygame.mixer.get_init() + mix_bytes = abs(mix_bits) / 8 + expected_length = ( + float(len(sound_bytes)) / mix_freq / mix_bytes / mix_channels + ) + self.assertAlmostEqual(expected_length, sound.get_length()) + finally: + pygame.mixer.quit() + with self.assertRaisesRegex(pygame.error, "mixer not initialized"): + sound.get_length() + + def test_get_num_channels(self): + """ + Tests if Sound.get_num_channels returns the correct number + of channels playing a specific sound. + """ + try: + filename = example_path(os.path.join("data", "house_lo.wav")) + sound = mixer.Sound(file=filename) + + self.assertEqual(sound.get_num_channels(), 0) + sound.play() + self.assertEqual(sound.get_num_channels(), 1) + sound.play() + self.assertEqual(sound.get_num_channels(), 2) + sound.stop() + self.assertEqual(sound.get_num_channels(), 0) + finally: + pygame.mixer.quit() + with self.assertRaisesRegex(pygame.error, "mixer not initialized"): + sound.get_num_channels() + + def test_get_volume(self): + """Ensure a sound's volume can be retrieved.""" + try: + expected_volume = 1.0 # default + filename = example_path(os.path.join("data", "house_lo.wav")) + sound = mixer.Sound(file=filename) + + volume = sound.get_volume() + + self.assertAlmostEqual(volume, expected_volume) + finally: + pygame.mixer.quit() + with self.assertRaisesRegex(pygame.error, "mixer not initialized"): + sound.get_volume() + + def todo_test_get_volume__while_playing(self): + """Ensure a sound's volume can be retrieved while playing.""" + self.fail() + + def todo_test_play(self): + + # __doc__ (as of 2008-08-02) for pygame.mixer.Sound.play: + + # Sound.play(loops=0, maxtime=0, fade_ms=0): return Channel + # begin sound playback + # + # Begin playback of the Sound (i.e., on the computer's speakers) on an + # available Channel. This will forcibly select a Channel, so playback + # may cut off a currently playing sound if necessary. + # + # The loops argument controls how many times the sample will be + # repeated after being played the first time. A value of 5 means that + # the sound will be played once, then repeated five times, and so is + # played a total of six times. The default value (zero) means the + # Sound is not repeated, and so is only played once. If loops is set + # to -1 the Sound will loop indefinitely (though you can still call + # stop() to stop it). + # + # The maxtime argument can be used to stop playback after a given + # number of milliseconds. + # + # The fade_ms argument will make the sound start playing at 0 volume + # and fade up to full volume over the time given. The sample may end + # before the fade-in is complete. + # + # This returns the Channel object for the channel that was selected. + + self.fail() + + def test_set_volume(self): + """Ensure a sound's volume can be set.""" + try: + float_delta = 1.0 / 128 # SDL volume range is 0 to 128 + filename = example_path(os.path.join("data", "house_lo.wav")) + sound = mixer.Sound(file=filename) + current_volume = sound.get_volume() + + # (volume_set_value : expected_volume) + volumes = ( + (-1, current_volume), # value < 0 won't change volume + (0, 0.0), + (0.01, 0.01), + (0.1, 0.1), + (0.5, 0.5), + (0.9, 0.9), + (0.99, 0.99), + (1, 1.0), + (1.1, 1.0), + (2.0, 1.0), + ) + + for volume_set_value, expected_volume in volumes: + sound.set_volume(volume_set_value) + + self.assertAlmostEqual( + sound.get_volume(), expected_volume, delta=float_delta + ) + finally: + pygame.mixer.quit() + with self.assertRaisesRegex(pygame.error, "mixer not initialized"): + sound.set_volume(1) + + def todo_test_set_volume__while_playing(self): + """Ensure a sound's volume can be set while playing.""" + self.fail() + + def test_stop(self): + """Ensure stop can be called while not playing a sound.""" + try: + expected_channels = 0 + filename = example_path(os.path.join("data", "house_lo.wav")) + sound = mixer.Sound(file=filename) + + sound.stop() + + self.assertEqual(sound.get_num_channels(), expected_channels) + finally: + pygame.mixer.quit() + with self.assertRaisesRegex(pygame.error, "mixer not initialized"): + sound.stop() + + def todo_test_stop__while_playing(self): + """Ensure stop stops a playing sound.""" + self.fail() + + def test_get_raw(self): + """Ensure get_raw returns the correct bytestring.""" + try: + samples = b"abcdefgh" # keep byte size a multiple of 4 + snd = mixer.Sound(buffer=samples) + + raw = snd.get_raw() + + self.assertIsInstance(raw, bytes) + self.assertEqual(raw, samples) + finally: + pygame.mixer.quit() + with self.assertRaisesRegex(pygame.error, "mixer not initialized"): + snd.get_raw() + + +##################################### MAIN ##################################### + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/mouse_test.py b/venv/Lib/site-packages/pygame/tests/mouse_test.py new file mode 100644 index 0000000..c23035f --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/mouse_test.py @@ -0,0 +1,350 @@ +import unittest +import os +import platform +import warnings +import pygame + + +DARWIN = "Darwin" in platform.platform() + + +class MouseTests(unittest.TestCase): + @classmethod + def setUpClass(cls): + # The display needs to be initialized for mouse functions. + pygame.display.init() + + @classmethod + def tearDownClass(cls): + pygame.display.quit() + + +class MouseModuleInteractiveTest(MouseTests): + + __tags__ = ["interactive"] + + def test_set_pos(self): + """Ensures set_pos works correctly. + Requires tester to move the mouse to be on the window. + """ + pygame.display.set_mode((500, 500)) + pygame.event.get() # Pump event queue to make window get focus on macos. + + if not pygame.mouse.get_focused(): + # The window needs to be focused for the mouse.set_pos to work on macos. + return + clock = pygame.time.Clock() + + expected_pos = ((10, 0), (0, 0), (499, 0), (499, 499), (341, 143), (94, 49)) + + for x, y in expected_pos: + pygame.mouse.set_pos(x, y) + pygame.event.get() + found_pos = pygame.mouse.get_pos() + + clock.tick() + time_passed = 0.0 + ready_to_test = False + + while not ready_to_test and time_passed <= 1000.0: # Avoid endless loop + time_passed += clock.tick() + for event in pygame.event.get(): + if event.type == pygame.MOUSEMOTION: + ready_to_test = True + + self.assertEqual(found_pos, (x, y)) + + +class MouseModuleTest(MouseTests): + @unittest.skipIf( + os.environ.get("SDL_VIDEODRIVER", "") == "dummy", + "Cursors not supported on headless test machines", + ) + def test_get_cursor(self): + """Ensures get_cursor works correctly.""" + + # error should be raised when the display is unintialized + with self.assertRaises(pygame.error): + pygame.display.quit() + pygame.mouse.get_cursor() + + pygame.display.init() + + size = (8, 8) + hotspot = (0, 0) + xormask = (0, 96, 120, 126, 112, 96, 0, 0) + andmask = (224, 240, 254, 255, 254, 240, 96, 0) + + expected_length = 4 + expected_cursor = pygame.cursors.Cursor(size, hotspot, xormask, andmask) + pygame.mouse.set_cursor(expected_cursor) + + try: + cursor = pygame.mouse.get_cursor() + + self.assertIsInstance(cursor, pygame.cursors.Cursor) + self.assertEqual(len(cursor), expected_length) + + for info in cursor: + self.assertIsInstance(info, tuple) + + pygame.mouse.set_cursor(size, hotspot, xormask, andmask) + self.assertEqual(pygame.mouse.get_cursor(), expected_cursor) + + # SDLError should be raised when the mouse cursor is NULL + except pygame.error: + with self.assertRaises(pygame.error): + pygame.mouse.get_cursor() + + @unittest.skipIf( + os.environ.get("SDL_VIDEODRIVER", "") == "dummy", + "mouse.set_system_cursor only available in SDL2", + ) + def test_set_system_cursor(self): + """Ensures set_system_cursor works correctly.""" + + with warnings.catch_warnings(record=True) as w: + """From Pygame 2.0.1, set_system_cursor() should raise a deprecation warning""" + # Cause all warnings to always be triggered. + warnings.simplefilter("always") + + # Error should be raised when the display is uninitialized + with self.assertRaises(pygame.error): + pygame.display.quit() + pygame.mouse.set_system_cursor(pygame.SYSTEM_CURSOR_HAND) + + pygame.display.init() + + # TypeError raised when PyArg_ParseTuple fails to parse parameters + with self.assertRaises(TypeError): + pygame.mouse.set_system_cursor("b") + with self.assertRaises(TypeError): + pygame.mouse.set_system_cursor(None) + with self.assertRaises(TypeError): + pygame.mouse.set_system_cursor((8, 8), (0, 0)) + + # Right type, invalid value + with self.assertRaises(pygame.error): + pygame.mouse.set_system_cursor(2000) + + # Working as intended + self.assertEqual( + pygame.mouse.set_system_cursor(pygame.SYSTEM_CURSOR_ARROW), None + ) + + # Making sure the warnings are working properly + self.assertEqual(len(w), 6) + self.assertTrue( + all([issubclass(warn.category, DeprecationWarning) for warn in w]) + ) + + @unittest.skipIf( + os.environ.get("SDL_VIDEODRIVER", "") == "dummy", + "Cursors not supported on headless test machines", + ) + def test_set_cursor(self): + """Ensures set_cursor works correctly.""" + + # Bitmap cursor information + size = (8, 8) + hotspot = (0, 0) + xormask = (0, 126, 64, 64, 32, 16, 0, 0) + andmask = (254, 255, 254, 112, 56, 28, 12, 0) + bitmap_cursor = pygame.cursors.Cursor(size, hotspot, xormask, andmask) + + # System cursor information + constant = pygame.SYSTEM_CURSOR_ARROW + system_cursor = pygame.cursors.Cursor(constant) + + # Color cursor information (also uses hotspot variable from Bitmap cursor info) + surface = pygame.Surface((10, 10)) + color_cursor = pygame.cursors.Cursor(hotspot, surface) + + pygame.display.quit() + + # Bitmap: Error should be raised when the display is uninitialized + with self.assertRaises(pygame.error): + pygame.mouse.set_cursor(bitmap_cursor) + + # System: Error should be raised when the display is uninitialized + with self.assertRaises(pygame.error): + pygame.mouse.set_cursor(system_cursor) + + # Color: Error should be raised when the display is uninitialized + with self.assertRaises(pygame.error): + pygame.mouse.set_cursor(color_cursor) + + pygame.display.init() + + # Bitmap: TypeError raised when PyArg_ParseTuple fails to parse parameters + with self.assertRaises(TypeError): + pygame.mouse.set_cursor(("w", "h"), hotspot, xormask, andmask) + with self.assertRaises(TypeError): + pygame.mouse.set_cursor(size, ("0", "0"), xormask, andmask) + with self.assertRaises(TypeError): + pygame.mouse.set_cursor(size, ("x", "y", "z"), xormask, andmask) + + # Bitmap: TypeError raised when either mask is not a sequence + with self.assertRaises(TypeError): + pygame.mouse.set_cursor(size, hotspot, 12345678, andmask) + with self.assertRaises(TypeError): + pygame.mouse.set_cursor(size, hotspot, xormask, 12345678) + + # Bitmap: TypeError raised when element of mask is not an integer + with self.assertRaises(TypeError): + pygame.mouse.set_cursor(size, hotspot, "00000000", andmask) + with self.assertRaises(TypeError): + pygame.mouse.set_cursor(size, hotspot, xormask, (2, [0], 4, 0, 0, 8, 0, 1)) + + # Bitmap: ValueError raised when width not divisible by 8 + with self.assertRaises(ValueError): + pygame.mouse.set_cursor((3, 8), hotspot, xormask, andmask) + + # Bitmap: ValueError raised when length of either mask != width * height / 8 + with self.assertRaises(ValueError): + pygame.mouse.set_cursor((16, 2), hotspot, (128, 64, 32), andmask) + with self.assertRaises(ValueError): + pygame.mouse.set_cursor((16, 2), hotspot, xormask, (192, 96, 48, 0, 1)) + + # Bitmap: Working as intended + self.assertEqual( + pygame.mouse.set_cursor((16, 1), hotspot, (8, 0), (0, 192)), None + ) + pygame.mouse.set_cursor(size, hotspot, xormask, andmask) + self.assertEqual(pygame.mouse.get_cursor(), bitmap_cursor) + + # Bitmap: Working as intended + lists + masks with no references + pygame.mouse.set_cursor(size, hotspot, list(xormask), list(andmask)) + self.assertEqual(pygame.mouse.get_cursor(), bitmap_cursor) + + # System: TypeError raised when constant is invalid + with self.assertRaises(TypeError): + pygame.mouse.set_cursor(-50021232) + with self.assertRaises(TypeError): + pygame.mouse.set_cursor("yellow") + + # System: Working as intended + self.assertEqual(pygame.mouse.set_cursor(constant), None) + pygame.mouse.set_cursor(constant) + self.assertEqual(pygame.mouse.get_cursor(), system_cursor) + pygame.mouse.set_cursor(system_cursor) + self.assertEqual(pygame.mouse.get_cursor(), system_cursor) + + # Color: TypeError raised with invalid parameters + with self.assertRaises(TypeError): + pygame.mouse.set_cursor(("x", "y"), surface) + with self.assertRaises(TypeError): + pygame.mouse.set_cursor(hotspot, "not_a_surface") + + # Color: Working as intended + self.assertEqual(pygame.mouse.set_cursor(hotspot, surface), None) + pygame.mouse.set_cursor(hotspot, surface) + self.assertEqual(pygame.mouse.get_cursor(), color_cursor) + pygame.mouse.set_cursor(color_cursor) + self.assertEqual(pygame.mouse.get_cursor(), color_cursor) + + # Color: Working as intended + Surface with no references is returned okay + pygame.mouse.set_cursor((0, 0), pygame.Surface((20, 20))) + cursor = pygame.mouse.get_cursor() + self.assertEqual(cursor.type, "color") + self.assertEqual(cursor.data[0], (0, 0)) + self.assertEqual(cursor.data[1].get_size(), (20, 20)) + + def test_get_focused(self): + """Ensures get_focused returns the correct type.""" + focused = pygame.mouse.get_focused() + + self.assertIsInstance(focused, int) + + def test_get_pressed(self): + """Ensures get_pressed returns the correct types.""" + expected_length = 3 + buttons_pressed = pygame.mouse.get_pressed() + self.assertIsInstance(buttons_pressed, tuple) + self.assertEqual(len(buttons_pressed), expected_length) + for value in buttons_pressed: + self.assertIsInstance(value, bool) + + expected_length = 5 + buttons_pressed = pygame.mouse.get_pressed(num_buttons=5) + self.assertIsInstance(buttons_pressed, tuple) + self.assertEqual(len(buttons_pressed), expected_length) + for value in buttons_pressed: + self.assertIsInstance(value, bool) + + expected_length = 3 + buttons_pressed = pygame.mouse.get_pressed(3) + self.assertIsInstance(buttons_pressed, tuple) + self.assertEqual(len(buttons_pressed), expected_length) + for value in buttons_pressed: + self.assertIsInstance(value, bool) + + expected_length = 5 + buttons_pressed = pygame.mouse.get_pressed(5) + self.assertIsInstance(buttons_pressed, tuple) + self.assertEqual(len(buttons_pressed), expected_length) + for value in buttons_pressed: + self.assertIsInstance(value, bool) + + with self.assertRaises(ValueError): + pygame.mouse.get_pressed(4) + + def test_get_pos(self): + """Ensures get_pos returns the correct types.""" + expected_length = 2 + + pos = pygame.mouse.get_pos() + + self.assertIsInstance(pos, tuple) + self.assertEqual(len(pos), expected_length) + for value in pos: + self.assertIsInstance(value, int) + + def test_set_pos__invalid_pos(self): + """Ensures set_pos handles invalid positions correctly.""" + for invalid_pos in ((1,), [1, 2, 3], 1, "1", (1, "1"), []): + + with self.assertRaises(TypeError): + pygame.mouse.set_pos(invalid_pos) + + def test_get_rel(self): + """Ensures get_rel returns the correct types.""" + expected_length = 2 + + rel = pygame.mouse.get_rel() + + self.assertIsInstance(rel, tuple) + self.assertEqual(len(rel), expected_length) + for value in rel: + self.assertIsInstance(value, int) + + def test_get_visible(self): + """Ensures get_visible works correctly.""" + for expected_value in (False, True): + pygame.mouse.set_visible(expected_value) + + visible = pygame.mouse.get_visible() + + self.assertEqual(visible, expected_value) + + def test_set_visible(self): + """Ensures set_visible returns the correct values.""" + # Set to a known state. + pygame.mouse.set_visible(True) + + for expected_visible in (False, True): + prev_visible = pygame.mouse.set_visible(expected_visible) + + self.assertEqual(prev_visible, not expected_visible) + + def test_set_visible__invalid_value(self): + """Ensures set_visible handles invalid positions correctly.""" + for invalid_value in ((1,), [1, 2, 3], 1.1, "1", (1, "1"), []): + with self.assertRaises(TypeError): + prev_visible = pygame.mouse.set_visible(invalid_value) + + +################################################################################ + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/pixelarray_test.py b/venv/Lib/site-packages/pygame/tests/pixelarray_test.py new file mode 100644 index 0000000..c93f36a --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/pixelarray_test.py @@ -0,0 +1,1660 @@ +import sys +import platform + +try: + reduce +except NameError: + from functools import reduce +import operator +import weakref +import gc +import unittest + +from pygame.tests.test_utils import SurfaceSubclass + +try: + from pygame.tests.test_utils import arrinter +except NameError: + pass + +import pygame + + +IS_PYPY = "PyPy" == platform.python_implementation() + + +class TestMixin(object): + def assert_surfaces_equal(self, s1, s2, msg=None): + """Checks if two surfaces are equal in size and color.""" + w, h = s1.get_size() + + self.assertTupleEqual((w, h), s2.get_size(), msg) + + msg = "" if msg is None else "{}, ".format(msg) + msg += "size: ({}, {})".format(w, h) + + for x in range(w): + for y in range(h): + self.assertEqual( + s1.get_at((x, y)), + s2.get_at((x, y)), + "{}, position: ({}, {})".format(msg, x, y), + ) + + def assert_surface_filled(self, surface, expected_color, msg=None): + """Checks if the surface is filled with the given color.""" + width, height = surface.get_size() + + surface.lock() # Lock for possible speed up. + for pos in ((x, y) for y in range(height) for x in range(width)): + self.assertEqual(surface.get_at(pos), expected_color, msg) + surface.unlock() + + +@unittest.skipIf(IS_PYPY, "pypy having issues") +class PixelArrayTypeTest(unittest.TestCase, TestMixin): + def test_compare(self): + # __doc__ (as of 2008-06-25) for pygame.pixelarray.PixelArray.compare: + + # PixelArray.compare (array, distance=0, weights=(0.299, 0.587, 0.114)): Return PixelArray + # Compares the PixelArray with another one. + + w = 10 + h = 20 + size = w, h + sf = pygame.Surface(size, 0, 32) + ar = pygame.PixelArray(sf) + sf2 = pygame.Surface(size, 0, 32) + self.assertRaises(TypeError, ar.compare, sf2) + ar2 = pygame.PixelArray(sf2) + ar3 = ar.compare(ar2) + self.assertTrue(isinstance(ar3, pygame.PixelArray)) + self.assertEqual(ar3.shape, size) + sf2.fill(pygame.Color("white")) + self.assert_surfaces_equal(sf2, ar3.surface) + del ar3 + r = pygame.Rect(2, 5, 6, 13) + sf.fill(pygame.Color("blue"), r) + sf2.fill(pygame.Color("red")) + sf2.fill(pygame.Color("blue"), r) + ar3 = ar.compare(ar2) + sf.fill(pygame.Color("white"), r) + self.assert_surfaces_equal(sf, ar3.surface) + + # FINISH ME! + # Test other bit depths, slices, and distance != 0. + + def test_compare__same_colors_within_distance(self): + """Ensures compare works correctly with same colored surfaces.""" + size = (3, 5) + pixelarray_result_color = pygame.Color("white") + surface_color = (127, 127, 127, 255) + + for depth in (8, 16, 24, 32): + expected_pixelarray_surface = pygame.Surface(size, depth=depth) + expected_pixelarray_surface.fill(pixelarray_result_color) + + # Copy the surface to ensure same dimensions/formatting. + surf_a = expected_pixelarray_surface.copy() + surf_a.fill(surface_color) + # For non-32 bit depths, the actual color can be different from what + # was filled. + expected_surface_color = surf_a.get_at((0, 0)) + + pixelarray_a = pygame.PixelArray(surf_a) + pixelarray_b = pygame.PixelArray(surf_a.copy()) + + for distance in (0.0, 0.01, 0.1, 1.0): + pixelarray_result = pixelarray_a.compare( + pixelarray_b, distance=distance + ) + + # Ensure the resulting pixelarray is correct and that the original + # surfaces were not changed. + self.assert_surfaces_equal( + pixelarray_result.surface, + expected_pixelarray_surface, + (depth, distance), + ) + self.assert_surface_filled( + pixelarray_a.surface, expected_surface_color, (depth, distance) + ) + self.assert_surface_filled( + pixelarray_b.surface, expected_surface_color, (depth, distance) + ) + + pixelarray_a.close() + pixelarray_b.close() + pixelarray_result.close() + + def test_compare__different_colors_within_distance(self): + """Ensures compare works correctly with different colored surfaces + and the color difference is within the given distance. + """ + size = (3, 5) + pixelarray_result_color = pygame.Color("white") + surface_a_color = (127, 127, 127, 255) + surface_b_color = (128, 127, 127, 255) + + for depth in (8, 16, 24, 32): + expected_pixelarray_surface = pygame.Surface(size, depth=depth) + expected_pixelarray_surface.fill(pixelarray_result_color) + + # Copy the surface to ensure same dimensions/formatting. + surf_a = expected_pixelarray_surface.copy() + surf_a.fill(surface_a_color) + # For non-32 bit depths, the actual color can be different from what + # was filled. + expected_surface_a_color = surf_a.get_at((0, 0)) + pixelarray_a = pygame.PixelArray(surf_a) + + surf_b = expected_pixelarray_surface.copy() + surf_b.fill(surface_b_color) + # For non-32 bit depths, the actual color can be different from what + # was filled. + expected_surface_b_color = surf_b.get_at((0, 0)) + pixelarray_b = pygame.PixelArray(surf_b) + + for distance in (0.2, 0.3, 0.5, 1.0): + pixelarray_result = pixelarray_a.compare( + pixelarray_b, distance=distance + ) + + # Ensure the resulting pixelarray is correct and that the original + # surfaces were not changed. + self.assert_surfaces_equal( + pixelarray_result.surface, + expected_pixelarray_surface, + (depth, distance), + ) + self.assert_surface_filled( + pixelarray_a.surface, expected_surface_a_color, (depth, distance) + ) + self.assert_surface_filled( + pixelarray_b.surface, expected_surface_b_color, (depth, distance) + ) + + pixelarray_a.close() + pixelarray_b.close() + pixelarray_result.close() + + def test_compare__different_colors_not_within_distance(self): + """Ensures compare works correctly with different colored surfaces + and the color difference is not within the given distance. + """ + size = (3, 5) + pixelarray_result_color = pygame.Color("black") + surface_a_color = (127, 127, 127, 255) + surface_b_color = (128, 127, 127, 255) + + for depth in (8, 16, 24, 32): + expected_pixelarray_surface = pygame.Surface(size, depth=depth) + expected_pixelarray_surface.fill(pixelarray_result_color) + + # Copy the surface to ensure same dimensions/formatting. + surf_a = expected_pixelarray_surface.copy() + surf_a.fill(surface_a_color) + # For non-32 bit depths, the actual color can be different from what + # was filled. + expected_surface_a_color = surf_a.get_at((0, 0)) + pixelarray_a = pygame.PixelArray(surf_a) + + surf_b = expected_pixelarray_surface.copy() + surf_b.fill(surface_b_color) + # For non-32 bit depths, the actual color can be different from what + # was filled. + expected_surface_b_color = surf_b.get_at((0, 0)) + pixelarray_b = pygame.PixelArray(surf_b) + + for distance in (0.0, 0.00001, 0.0001, 0.001): + pixelarray_result = pixelarray_a.compare( + pixelarray_b, distance=distance + ) + + # Ensure the resulting pixelarray is correct and that the original + # surfaces were not changed. + self.assert_surfaces_equal( + pixelarray_result.surface, + expected_pixelarray_surface, + (depth, distance), + ) + self.assert_surface_filled( + pixelarray_a.surface, expected_surface_a_color, (depth, distance) + ) + self.assert_surface_filled( + pixelarray_b.surface, expected_surface_b_color, (depth, distance) + ) + + pixelarray_a.close() + pixelarray_b.close() + pixelarray_result.close() + + def test_close(self): + """does not crash when it is deleted.""" + s = pygame.Surface((10, 10)) + a = pygame.PixelArray(s) + a.close() + del a + + def test_close_raises(self): + """when you try to do an operation after it is closed.""" + s = pygame.Surface((10, 10)) + a = pygame.PixelArray(s) + a.close() + + def do_operation(): + a[:] + + self.assertRaises(ValueError, do_operation) + + def do_operation2(): + a[:] = 1 + + self.assertRaises(ValueError, do_operation2) + + def do_operation3(): + a.make_surface() + + self.assertRaises(ValueError, do_operation3) + + def do_operation4(): + for x in a: + pass + + self.assertRaises(ValueError, do_operation4) + + def test_context_manager(self): + """closes properly.""" + s = pygame.Surface((10, 10)) + with pygame.PixelArray(s) as a: + a[:] + + def test_pixel_array(self): + for bpp in (8, 16, 24, 32): + sf = pygame.Surface((10, 20), 0, bpp) + sf.fill((0, 0, 0)) + ar = pygame.PixelArray(sf) + + self.assertEqual(ar._pixels_address, sf._pixels_address) + + if sf.mustlock(): + self.assertTrue(sf.get_locked()) + + self.assertEqual(len(ar), 10) + + del ar + if sf.mustlock(): + self.assertFalse(sf.get_locked()) + + def test_as_class(self): + # Check general new-style class freatures. + sf = pygame.Surface((2, 3), 0, 32) + ar = pygame.PixelArray(sf) + self.assertRaises(AttributeError, getattr, ar, "nonnative") + ar.nonnative = "value" + self.assertEqual(ar.nonnative, "value") + r = weakref.ref(ar) + self.assertTrue(r() is ar) + del ar + gc.collect() + self.assertTrue(r() is None) + + class C(pygame.PixelArray): + def __str__(self): + return "string (%i, %i)" % self.shape + + ar = C(sf) + self.assertEqual(str(ar), "string (2, 3)") + r = weakref.ref(ar) + self.assertTrue(r() is ar) + del ar + gc.collect() + self.assertTrue(r() is None) + + def test_pixelarray__subclassed_surface(self): + """Ensure the PixelArray constructor accepts subclassed surfaces.""" + surface = SurfaceSubclass((3, 5), 0, 32) + pixelarray = pygame.PixelArray(surface) + + self.assertIsInstance(pixelarray, pygame.PixelArray) + + # Sequence interfaces + def test_get_column(self): + for bpp in (8, 16, 24, 32): + sf = pygame.Surface((6, 8), 0, bpp) + sf.fill((0, 0, 255)) + val = sf.map_rgb((0, 0, 255)) + ar = pygame.PixelArray(sf) + + ar2 = ar.__getitem__(1) + self.assertEqual(len(ar2), 8) + self.assertEqual(ar2.__getitem__(0), val) + self.assertEqual(ar2.__getitem__(1), val) + self.assertEqual(ar2.__getitem__(2), val) + + ar2 = ar.__getitem__(-1) + self.assertEqual(len(ar2), 8) + self.assertEqual(ar2.__getitem__(0), val) + self.assertEqual(ar2.__getitem__(1), val) + self.assertEqual(ar2.__getitem__(2), val) + + @unittest.skipIf(IS_PYPY, "pypy malloc abort") + def test_get_pixel(self): + w = 10 + h = 20 + size = w, h + bg_color = (0, 0, 255) + fg_color_y = (0, 0, 128) + fg_color_x = (0, 0, 11) + for bpp in (8, 16, 24, 32): + sf = pygame.Surface(size, 0, bpp) + mapped_bg_color = sf.map_rgb(bg_color) + mapped_fg_color_y = sf.map_rgb(fg_color_y) + mapped_fg_color_x = sf.map_rgb(fg_color_x) + self.assertNotEqual( + mapped_fg_color_y, + mapped_bg_color, + "Unusable test colors for bpp %i" % (bpp,), + ) + self.assertNotEqual( + mapped_fg_color_x, + mapped_bg_color, + "Unusable test colors for bpp %i" % (bpp,), + ) + self.assertNotEqual( + mapped_fg_color_y, + mapped_fg_color_x, + "Unusable test colors for bpp %i" % (bpp,), + ) + sf.fill(bg_color) + + ar = pygame.PixelArray(sf) + + ar_y = ar.__getitem__(1) + for y in range(h): + ar2 = ar_y.__getitem__(y) + self.assertEqual( + ar2, + mapped_bg_color, + "ar[1][%i] == %i, mapped_bg_color == %i" + % (y, ar2, mapped_bg_color), + ) + + sf.set_at((1, y), fg_color_y) + ar2 = ar_y.__getitem__(y) + self.assertEqual( + ar2, + mapped_fg_color_y, + "ar[1][%i] == %i, mapped_fg_color_y == %i" + % (y, ar2, mapped_fg_color_y), + ) + + sf.set_at((1, 1), bg_color) + for x in range(w): + ar2 = ar.__getitem__(x).__getitem__(1) + self.assertEqual( + ar2, + mapped_bg_color, + "ar[%i][1] = %i, mapped_bg_color = %i" % (x, ar2, mapped_bg_color), + ) + sf.set_at((x, 1), fg_color_x) + ar2 = ar.__getitem__(x).__getitem__(1) + self.assertEqual( + ar2, + mapped_fg_color_x, + "ar[%i][1] = %i, mapped_fg_color_x = %i" + % (x, ar2, mapped_fg_color_x), + ) + + ar2 = ar.__getitem__(0).__getitem__(0) + self.assertEqual(ar2, mapped_bg_color, "bpp = %i" % (bpp,)) + + ar2 = ar.__getitem__(1).__getitem__(0) + self.assertEqual(ar2, mapped_fg_color_y, "bpp = %i" % (bpp,)) + + ar2 = ar.__getitem__(-4).__getitem__(1) + self.assertEqual(ar2, mapped_fg_color_x, "bpp = %i" % (bpp,)) + + ar2 = ar.__getitem__(-4).__getitem__(5) + self.assertEqual(ar2, mapped_bg_color, "bpp = %i" % (bpp,)) + + ar2 = ar.__getitem__(-4).__getitem__(0) + self.assertEqual(ar2, mapped_bg_color, "bpp = %i" % (bpp,)) + + ar2 = ar.__getitem__(-w + 1).__getitem__(0) + self.assertEqual(ar2, mapped_fg_color_y, "bpp = %i" % (bpp,)) + + ar2 = ar.__getitem__(-w).__getitem__(0) + self.assertEqual(ar2, mapped_bg_color, "bpp = %i" % (bpp,)) + + ar2 = ar.__getitem__(5).__getitem__(-4) + self.assertEqual(ar2, mapped_bg_color, "bpp = %i" % (bpp,)) + + ar2 = ar.__getitem__(5).__getitem__(-h + 1) + self.assertEqual(ar2, mapped_fg_color_x, "bpp = %i" % (bpp,)) + + ar2 = ar.__getitem__(5).__getitem__(-h) + self.assertEqual(ar2, mapped_bg_color, "bpp = %i" % (bpp,)) + + ar2 = ar.__getitem__(0).__getitem__(-h + 1) + self.assertEqual(ar2, mapped_fg_color_x, "bpp = %i" % (bpp,)) + + ar2 = ar.__getitem__(0).__getitem__(-h) + self.assertEqual(ar2, mapped_bg_color, "bpp = %i" % (bpp,)) + + def test_set_pixel(self): + for bpp in (8, 16, 24, 32): + sf = pygame.Surface((10, 20), 0, bpp) + sf.fill((0, 0, 0)) + ar = pygame.PixelArray(sf) + + ar.__getitem__(0).__setitem__(0, (0, 255, 0)) + self.assertEqual(ar[0][0], sf.map_rgb((0, 255, 0))) + + ar.__getitem__(1).__setitem__(1, (128, 128, 128)) + self.assertEqual(ar[1][1], sf.map_rgb((128, 128, 128))) + + ar.__getitem__(-1).__setitem__(-1, (128, 128, 128)) + self.assertEqual(ar[9][19], sf.map_rgb((128, 128, 128))) + + ar.__getitem__(-2).__setitem__(-2, (128, 128, 128)) + self.assertEqual(ar[8][-2], sf.map_rgb((128, 128, 128))) + + def test_set_column(self): + for bpp in (8, 16, 24, 32): + sf = pygame.Surface((6, 8), 0, bpp) + sf.fill((0, 0, 0)) + ar = pygame.PixelArray(sf) + + sf2 = pygame.Surface((6, 8), 0, bpp) + sf2.fill((0, 255, 255)) + ar2 = pygame.PixelArray(sf2) + + # Test single value assignment + ar.__setitem__(2, (128, 128, 128)) + self.assertEqual(ar[2][0], sf.map_rgb((128, 128, 128))) + self.assertEqual(ar[2][1], sf.map_rgb((128, 128, 128))) + + ar.__setitem__(-1, (0, 255, 255)) + self.assertEqual(ar[5][0], sf.map_rgb((0, 255, 255))) + self.assertEqual(ar[-1][1], sf.map_rgb((0, 255, 255))) + + ar.__setitem__(-2, (255, 255, 0)) + self.assertEqual(ar[4][0], sf.map_rgb((255, 255, 0))) + self.assertEqual(ar[-2][1], sf.map_rgb((255, 255, 0))) + + # Test list assignment. + ar.__setitem__(0, [(255, 255, 255)] * 8) + self.assertEqual(ar[0][0], sf.map_rgb((255, 255, 255))) + self.assertEqual(ar[0][1], sf.map_rgb((255, 255, 255))) + + # Test tuple assignment. + # Changed in Pygame 1.9.2 - Raises an exception. + self.assertRaises( + ValueError, + ar.__setitem__, + 1, + ( + (204, 0, 204), + (17, 17, 17), + (204, 0, 204), + (17, 17, 17), + (204, 0, 204), + (17, 17, 17), + (204, 0, 204), + (17, 17, 17), + ), + ) + + # Test pixel array assignment. + ar.__setitem__(1, ar2.__getitem__(3)) + self.assertEqual(ar[1][0], sf.map_rgb((0, 255, 255))) + self.assertEqual(ar[1][1], sf.map_rgb((0, 255, 255))) + + def test_get_slice(self): + for bpp in (8, 16, 24, 32): + sf = pygame.Surface((10, 20), 0, bpp) + sf.fill((0, 0, 0)) + ar = pygame.PixelArray(sf) + + self.assertEqual(len(ar[0:2]), 2) + self.assertEqual(len(ar[3:7][3]), 20) + + self.assertEqual(ar[0:0], None) + self.assertEqual(ar[5:5], None) + self.assertEqual(ar[9:9], None) + + # Has to resolve to ar[7:8] + self.assertEqual(len(ar[-3:-2]), 1) # 2D + self.assertEqual(len(ar[-3:-2][0]), 20) # 1D + + # Try assignments. + + # 2D assignment. + ar[2:5] = (255, 255, 255) + + # 1D assignment + ar[3][3:7] = (10, 10, 10) + self.assertEqual(ar[3][5], sf.map_rgb((10, 10, 10))) + self.assertEqual(ar[3][6], sf.map_rgb((10, 10, 10))) + + @unittest.skipIf(IS_PYPY, "skipping for PyPy (segfaults on mac pypy3 6.0.0)") + def test_contains(self): + for bpp in (8, 16, 24, 32): + sf = pygame.Surface((10, 20), 0, bpp) + sf.fill((0, 0, 0)) + sf.set_at((8, 8), (255, 255, 255)) + + ar = pygame.PixelArray(sf) + self.assertTrue((0, 0, 0) in ar) + self.assertTrue((255, 255, 255) in ar) + self.assertFalse((255, 255, 0) in ar) + self.assertFalse(0x0000FF in ar) + + # Test sliced array + self.assertTrue((0, 0, 0) in ar[8]) + self.assertTrue((255, 255, 255) in ar[8]) + self.assertFalse((255, 255, 0) in ar[8]) + self.assertFalse(0x0000FF in ar[8]) + + def test_get_surface(self): + for bpp in (8, 16, 24, 32): + sf = pygame.Surface((10, 20), 0, bpp) + sf.fill((0, 0, 0)) + ar = pygame.PixelArray(sf) + self.assertTrue(ar.surface is sf) + + def test_get_surface__subclassed_surface(self): + """Ensure the surface attribute can handle subclassed surfaces.""" + expected_surface = SurfaceSubclass((5, 3), 0, 32) + pixelarray = pygame.PixelArray(expected_surface) + + surface = pixelarray.surface + + self.assertIs(surface, expected_surface) + self.assertIsInstance(surface, pygame.Surface) + self.assertIsInstance(surface, SurfaceSubclass) + + def test_set_slice(self): + for bpp in (8, 16, 24, 32): + sf = pygame.Surface((6, 8), 0, bpp) + sf.fill((0, 0, 0)) + ar = pygame.PixelArray(sf) + + # Test single value assignment + val = sf.map_rgb((128, 128, 128)) + ar[0:2] = val + self.assertEqual(ar[0][0], val) + self.assertEqual(ar[0][1], val) + self.assertEqual(ar[1][0], val) + self.assertEqual(ar[1][1], val) + + val = sf.map_rgb((0, 255, 255)) + ar[-3:-1] = val + self.assertEqual(ar[3][0], val) + self.assertEqual(ar[-2][1], val) + + val = sf.map_rgb((255, 255, 255)) + ar[-3:] = (255, 255, 255) + self.assertEqual(ar[4][0], val) + self.assertEqual(ar[-1][1], val) + + # Test array size mismatch. + # Changed in ver. 1.9.2 + # (was "Test list assignment, this is a vertical assignment.") + val = sf.map_rgb((0, 255, 0)) + self.assertRaises(ValueError, ar.__setitem__, slice(2, 4), [val] * 8) + + # And the horizontal assignment. + val = sf.map_rgb((255, 0, 0)) + val2 = sf.map_rgb((128, 0, 255)) + ar[0:2] = [val, val2] + self.assertEqual(ar[0][0], val) + self.assertEqual(ar[1][0], val2) + self.assertEqual(ar[0][1], val) + self.assertEqual(ar[1][1], val2) + self.assertEqual(ar[0][4], val) + self.assertEqual(ar[1][4], val2) + self.assertEqual(ar[0][5], val) + self.assertEqual(ar[1][5], val2) + + # Test pixelarray assignment. + ar[:] = (0, 0, 0) + sf2 = pygame.Surface((6, 8), 0, bpp) + sf2.fill((255, 0, 255)) + + val = sf.map_rgb((255, 0, 255)) + ar2 = pygame.PixelArray(sf2) + + ar[:] = ar2[:] + self.assertEqual(ar[0][0], val) + self.assertEqual(ar[5][7], val) + + # Ensure p1 ... pn are freed for array[...] = [p1, ..., pn] + # Bug fix: reference counting. + if hasattr(sys, "getrefcount"): + + class Int(int): + """Unique int instances""" + + pass + + sf = pygame.Surface((5, 2), 0, 32) + ar = pygame.PixelArray(sf) + pixel_list = [Int(i) for i in range(ar.shape[0])] + refcnts_before = [sys.getrefcount(i) for i in pixel_list] + ar[...] = pixel_list + refcnts_after = [sys.getrefcount(i) for i in pixel_list] + gc.collect() + self.assertEqual(refcnts_after, refcnts_before) + + def test_subscript(self): + # By default we do not need to work with any special __***__ + # methods as map subscripts are the first looked up by the + # object system. + for bpp in (8, 16, 24, 32): + sf = pygame.Surface((6, 8), 0, bpp) + sf.set_at((1, 3), (0, 255, 0)) + sf.set_at((0, 0), (0, 255, 0)) + sf.set_at((4, 4), (0, 255, 0)) + val = sf.map_rgb((0, 255, 0)) + + ar = pygame.PixelArray(sf) + + # Test single value requests. + self.assertEqual(ar[1, 3], val) + self.assertEqual(ar[0, 0], val) + self.assertEqual(ar[4, 4], val) + self.assertEqual(ar[1][3], val) + self.assertEqual(ar[0][0], val) + self.assertEqual(ar[4][4], val) + + # Test ellipse working. + self.assertEqual(len(ar[..., ...]), 6) + self.assertEqual(len(ar[1, ...]), 8) + self.assertEqual(len(ar[..., 3]), 6) + + # Test simple slicing + self.assertEqual(len(ar[:, :]), 6) + self.assertEqual( + len( + ar[ + :, + ] + ), + 6, + ) + self.assertEqual(len(ar[1, :]), 8) + self.assertEqual(len(ar[:, 2]), 6) + # Empty slices + self.assertEqual( + ar[ + 4:4, + ], + None, + ) + self.assertEqual(ar[4:4, ...], None) + self.assertEqual(ar[4:4, 2:2], None) + self.assertEqual(ar[4:4, 1:4], None) + self.assertEqual( + ar[ + 4:4:2, + ], + None, + ) + self.assertEqual( + ar[ + 4:4:-2, + ], + None, + ) + self.assertEqual(ar[4:4:1, ...], None) + self.assertEqual(ar[4:4:-1, ...], None) + self.assertEqual(ar[4:4:1, 2:2], None) + self.assertEqual(ar[4:4:-1, 1:4], None) + self.assertEqual(ar[..., 4:4], None) + self.assertEqual(ar[1:4, 4:4], None) + self.assertEqual(ar[..., 4:4:1], None) + self.assertEqual(ar[..., 4:4:-1], None) + self.assertEqual(ar[2:2, 4:4:1], None) + self.assertEqual(ar[1:4, 4:4:-1], None) + + # Test advanced slicing + ar[0] = 0 + ar[1] = 1 + ar[2] = 2 + ar[3] = 3 + ar[4] = 4 + ar[5] = 5 + + # We should receive something like [0,2,4] + self.assertEqual(ar[::2, 1][0], 0) + self.assertEqual(ar[::2, 1][1], 2) + self.assertEqual(ar[::2, 1][2], 4) + # We should receive something like [2,2,2] + self.assertEqual(ar[2, ::2][0], 2) + self.assertEqual(ar[2, ::2][1], 2) + self.assertEqual(ar[2, ::2][2], 2) + + # Should create a 3x3 array of [0,2,4] + ar2 = ar[::2, ::2] + self.assertEqual(len(ar2), 3) + self.assertEqual(ar2[0][0], 0) + self.assertEqual(ar2[0][1], 0) + self.assertEqual(ar2[0][2], 0) + self.assertEqual(ar2[2][0], 4) + self.assertEqual(ar2[2][1], 4) + self.assertEqual(ar2[2][2], 4) + self.assertEqual(ar2[1][0], 2) + self.assertEqual(ar2[2][0], 4) + self.assertEqual(ar2[1][1], 2) + + # Should create a reversed 3x8 array over X of [1,2,3] -> [3,2,1] + ar2 = ar[3:0:-1] + self.assertEqual(len(ar2), 3) + self.assertEqual(ar2[0][0], 3) + self.assertEqual(ar2[0][1], 3) + self.assertEqual(ar2[0][2], 3) + self.assertEqual(ar2[0][7], 3) + self.assertEqual(ar2[2][0], 1) + self.assertEqual(ar2[2][1], 1) + self.assertEqual(ar2[2][2], 1) + self.assertEqual(ar2[2][7], 1) + self.assertEqual(ar2[1][0], 2) + self.assertEqual(ar2[1][1], 2) + # Should completely reverse the array over X -> [5,4,3,2,1,0] + ar2 = ar[::-1] + self.assertEqual(len(ar2), 6) + self.assertEqual(ar2[0][0], 5) + self.assertEqual(ar2[0][1], 5) + self.assertEqual(ar2[0][3], 5) + self.assertEqual(ar2[0][-1], 5) + self.assertEqual(ar2[1][0], 4) + self.assertEqual(ar2[1][1], 4) + self.assertEqual(ar2[1][3], 4) + self.assertEqual(ar2[1][-1], 4) + self.assertEqual(ar2[-1][-1], 0) + self.assertEqual(ar2[-2][-2], 1) + self.assertEqual(ar2[-3][-1], 2) + + # Test advanced slicing + ar[:] = 0 + ar2 = ar[:, 1] + ar2[:] = [99] * len(ar2) + self.assertEqual(ar2[0], 99) + self.assertEqual(ar2[-1], 99) + self.assertEqual(ar2[-2], 99) + self.assertEqual(ar2[2], 99) + self.assertEqual(ar[0, 1], 99) + self.assertEqual(ar[1, 1], 99) + self.assertEqual(ar[2, 1], 99) + self.assertEqual(ar[-1, 1], 99) + self.assertEqual(ar[-2, 1], 99) + + # Cases where a 2d array should have a dimension of length 1. + ar2 = ar[1:2, :] + self.assertEqual(ar2.shape, (1, ar.shape[1])) + ar2 = ar[:, 1:2] + self.assertEqual(ar2.shape, (ar.shape[0], 1)) + sf2 = pygame.Surface((1, 5), 0, 32) + ar2 = pygame.PixelArray(sf2) + self.assertEqual(ar2.shape, sf2.get_size()) + sf2 = pygame.Surface((7, 1), 0, 32) + ar2 = pygame.PixelArray(sf2) + self.assertEqual(ar2.shape, sf2.get_size()) + + # Array has a single ellipsis subscript: the identity operator + ar2 = ar[...] + self.assertTrue(ar2 is ar) + + # Ensure x and y are freed for p = array[x, y] + # Bug fix: reference counting + if hasattr(sys, "getrefcount"): + + class Int(int): + """Unique int instances""" + + pass + + sf = pygame.Surface((2, 2), 0, 32) + ar = pygame.PixelArray(sf) + x, y = Int(0), Int(1) + rx_before, ry_before = sys.getrefcount(x), sys.getrefcount(y) + p = ar[x, y] + rx_after, ry_after = sys.getrefcount(x), sys.getrefcount(y) + self.assertEqual(rx_after, rx_before) + self.assertEqual(ry_after, ry_before) + + def test_ass_subscript(self): + for bpp in (8, 16, 24, 32): + sf = pygame.Surface((6, 8), 0, bpp) + sf.fill((255, 255, 255)) + ar = pygame.PixelArray(sf) + + # Test ellipse working + ar[..., ...] = (0, 0, 0) + self.assertEqual(ar[0, 0], 0) + self.assertEqual(ar[1, 0], 0) + self.assertEqual(ar[-1, -1], 0) + ar[ + ..., + ] = (0, 0, 255) + self.assertEqual(ar[0, 0], sf.map_rgb((0, 0, 255))) + self.assertEqual(ar[1, 0], sf.map_rgb((0, 0, 255))) + self.assertEqual(ar[-1, -1], sf.map_rgb((0, 0, 255))) + ar[:, ...] = (255, 0, 0) + self.assertEqual(ar[0, 0], sf.map_rgb((255, 0, 0))) + self.assertEqual(ar[1, 0], sf.map_rgb((255, 0, 0))) + self.assertEqual(ar[-1, -1], sf.map_rgb((255, 0, 0))) + ar[...] = (0, 255, 0) + self.assertEqual(ar[0, 0], sf.map_rgb((0, 255, 0))) + self.assertEqual(ar[1, 0], sf.map_rgb((0, 255, 0))) + self.assertEqual(ar[-1, -1], sf.map_rgb((0, 255, 0))) + + # Ensure x and y are freed for array[x, y] = p + # Bug fix: reference counting + if hasattr(sys, "getrefcount"): + + class Int(int): + """Unique int instances""" + + pass + + sf = pygame.Surface((2, 2), 0, 32) + ar = pygame.PixelArray(sf) + x, y = Int(0), Int(1) + rx_before, ry_before = sys.getrefcount(x), sys.getrefcount(y) + ar[x, y] = 0 + rx_after, ry_after = sys.getrefcount(x), sys.getrefcount(y) + self.assertEqual(rx_after, rx_before) + self.assertEqual(ry_after, ry_before) + + def test_pixels_field(self): + for bpp in [1, 2, 3, 4]: + sf = pygame.Surface((11, 7), 0, bpp * 8) + ar = pygame.PixelArray(sf) + ar2 = ar[1:, :] + self.assertEqual(ar2._pixels_address - ar._pixels_address, ar.itemsize) + ar2 = ar[:, 1:] + self.assertEqual(ar2._pixels_address - ar._pixels_address, ar.strides[1]) + ar2 = ar[::-1, :] + self.assertEqual( + ar2._pixels_address - ar._pixels_address, + (ar.shape[0] - 1) * ar.itemsize, + ) + ar2 = ar[::-2, :] + self.assertEqual( + ar2._pixels_address - ar._pixels_address, + (ar.shape[0] - 1) * ar.itemsize, + ) + ar2 = ar[:, ::-1] + self.assertEqual( + ar2._pixels_address - ar._pixels_address, + (ar.shape[1] - 1) * ar.strides[1], + ) + ar3 = ar2[::-1, :] + self.assertEqual( + ar3._pixels_address - ar._pixels_address, + (ar.shape[0] - 1) * ar.strides[0] + (ar.shape[1] - 1) * ar.strides[1], + ) + ar2 = ar[:, ::-2] + self.assertEqual( + ar2._pixels_address - ar._pixels_address, + (ar.shape[1] - 1) * ar.strides[1], + ) + ar2 = ar[2::, 3::] + self.assertEqual( + ar2._pixels_address - ar._pixels_address, + ar.strides[0] * 2 + ar.strides[1] * 3, + ) + ar2 = ar[2::2, 3::4] + self.assertEqual( + ar2._pixels_address - ar._pixels_address, + ar.strides[0] * 2 + ar.strides[1] * 3, + ) + ar2 = ar[9:2:-1, :] + self.assertEqual( + ar2._pixels_address - ar._pixels_address, ar.strides[0] * 9 + ) + ar2 = ar[:, 5:2:-1] + self.assertEqual( + ar2._pixels_address - ar._pixels_address, ar.strides[1] * 5 + ) + ##? ar2 = ar[:,9:2:-1] + + def test_make_surface(self): + bg_color = pygame.Color(255, 255, 255) + fg_color = pygame.Color(128, 100, 0) + for bpp in (8, 16, 24, 32): + sf = pygame.Surface((10, 20), 0, bpp) + bg_color_adj = sf.unmap_rgb(sf.map_rgb(bg_color)) + fg_color_adj = sf.unmap_rgb(sf.map_rgb(fg_color)) + sf.fill(bg_color_adj) + sf.fill(fg_color_adj, (2, 5, 4, 11)) + ar = pygame.PixelArray(sf) + newsf = ar[::2, ::2].make_surface() + rect = newsf.get_rect() + self.assertEqual(rect.width, 5) + self.assertEqual(rect.height, 10) + for p in [ + (0, 2), + (0, 3), + (1, 2), + (2, 2), + (3, 2), + (3, 3), + (0, 7), + (0, 8), + (1, 8), + (2, 8), + (3, 8), + (3, 7), + ]: + self.assertEqual(newsf.get_at(p), bg_color_adj) + for p in [(1, 3), (2, 3), (1, 5), (2, 5), (1, 7), (2, 7)]: + self.assertEqual(newsf.get_at(p), fg_color_adj) + + # Bug when array width is not a multiple of the slice step. + w = 17 + lst = list(range(w)) + w_slice = len(lst[::2]) + h = 3 + sf = pygame.Surface((w, h), 0, 32) + ar = pygame.PixelArray(sf) + ar2 = ar[::2, :] + sf2 = ar2.make_surface() + w2, h2 = sf2.get_size() + self.assertEqual(w2, w_slice) + self.assertEqual(h2, h) + + # Bug when array height is not a multiple of the slice step. + # This can hang the Python interpreter. + h = 17 + lst = list(range(h)) + h_slice = len(lst[::2]) + w = 3 + sf = pygame.Surface((w, h), 0, 32) + ar = pygame.PixelArray(sf) + ar2 = ar[:, ::2] + sf2 = ar2.make_surface() # Hangs here. + w2, h2 = sf2.get_size() + self.assertEqual(w2, w) + self.assertEqual(h2, h_slice) + + def test_make_surface__subclassed_surface(self): + """Ensure make_surface can handle subclassed surfaces.""" + expected_size = (3, 5) + expected_flags = 0 + expected_depth = 32 + original_surface = SurfaceSubclass( + expected_size, expected_flags, expected_depth + ) + pixelarray = pygame.PixelArray(original_surface) + + surface = pixelarray.make_surface() + + self.assertIsNot(surface, original_surface) + self.assertIsInstance(surface, pygame.Surface) + self.assertNotIsInstance(surface, SurfaceSubclass) + self.assertEqual(surface.get_size(), expected_size) + self.assertEqual(surface.get_flags(), expected_flags) + self.assertEqual(surface.get_bitsize(), expected_depth) + + def test_iter(self): + for bpp in (8, 16, 24, 32): + sf = pygame.Surface((5, 10), 0, bpp) + ar = pygame.PixelArray(sf) + iterations = 0 + for col in ar: + self.assertEqual(len(col), 10) + iterations += 1 + self.assertEqual(iterations, 5) + + def test_replace(self): + # print "replace start" + for bpp in (8, 16, 24, 32): + sf = pygame.Surface((10, 10), 0, bpp) + sf.fill((255, 0, 0)) + rval = sf.map_rgb((0, 0, 255)) + oval = sf.map_rgb((255, 0, 0)) + ar = pygame.PixelArray(sf) + ar[::2].replace((255, 0, 0), (0, 0, 255)) + self.assertEqual(ar[0][0], rval) + self.assertEqual(ar[1][0], oval) + self.assertEqual(ar[2][3], rval) + self.assertEqual(ar[3][6], oval) + self.assertEqual(ar[8][9], rval) + self.assertEqual(ar[9][9], oval) + + ar[::2].replace((0, 0, 255), (255, 0, 0), weights=(10, 20, 50)) + self.assertEqual(ar[0][0], oval) + self.assertEqual(ar[2][3], oval) + self.assertEqual(ar[3][6], oval) + self.assertEqual(ar[8][9], oval) + self.assertEqual(ar[9][9], oval) + # print "replace end" + + def test_extract(self): + # print "extract start" + for bpp in (8, 16, 24, 32): + sf = pygame.Surface((10, 10), 0, bpp) + sf.fill((0, 0, 255)) + sf.fill((255, 0, 0), (2, 2, 6, 6)) + + white = sf.map_rgb((255, 255, 255)) + black = sf.map_rgb((0, 0, 0)) + + ar = pygame.PixelArray(sf) + newar = ar.extract((255, 0, 0)) + + self.assertEqual(newar[0][0], black) + self.assertEqual(newar[1][0], black) + self.assertEqual(newar[2][3], white) + self.assertEqual(newar[3][6], white) + self.assertEqual(newar[8][9], black) + self.assertEqual(newar[9][9], black) + + newar = ar.extract((255, 0, 0), weights=(10, 0.1, 50)) + self.assertEqual(newar[0][0], black) + self.assertEqual(newar[1][0], black) + self.assertEqual(newar[2][3], white) + self.assertEqual(newar[3][6], white) + self.assertEqual(newar[8][9], black) + self.assertEqual(newar[9][9], black) + # print "extract end" + + def test_2dslice_assignment(self): + w = 2 * 5 * 8 + h = 3 * 5 * 9 + sf = pygame.Surface((w, h), 0, 32) + ar = pygame.PixelArray(sf) + size = (w, h) + strides = (1, w) + offset = 0 + self._test_assignment(sf, ar, size, strides, offset) + xslice = slice(None, None, 2) + yslice = slice(None, None, 3) + ar, size, strides, offset = self._array_slice( + ar, size, (xslice, yslice), strides, offset + ) + self._test_assignment(sf, ar, size, strides, offset) + xslice = slice(5, None, 5) + yslice = slice(5, None, 5) + ar, size, strides, offset = self._array_slice( + ar, size, (xslice, yslice), strides, offset + ) + self._test_assignment(sf, ar, size, strides, offset) + + def _test_assignment(self, sf, ar, ar_size, ar_strides, ar_offset): + self.assertEqual(ar.shape, ar_size) + ar_w, ar_h = ar_size + ar_xstride, ar_ystride = ar_strides + sf_w, sf_h = sf.get_size() + black = pygame.Color("black") + color = pygame.Color(0, 0, 12) + pxcolor = sf.map_rgb(color) + sf.fill(black) + for ar_x, ar_y in [ + (0, 0), + (0, ar_h - 4), + (ar_w - 3, 0), + (0, ar_h - 1), + (ar_w - 1, 0), + (ar_w - 1, ar_h - 1), + ]: + sf_offset = ar_offset + ar_x * ar_xstride + ar_y * ar_ystride + sf_y = sf_offset // sf_w + sf_x = sf_offset - sf_y * sf_w + sf_posn = (sf_x, sf_y) + sf_pix = sf.get_at(sf_posn) + self.assertEqual( + sf_pix, + black, + "at pixarr posn (%i, %i) (surf posn (%i, %i)): " + "%s != %s" % (ar_x, ar_y, sf_x, sf_y, sf_pix, black), + ) + ar[ar_x, ar_y] = pxcolor + sf_pix = sf.get_at(sf_posn) + self.assertEqual( + sf_pix, + color, + "at pixarr posn (%i, %i) (surf posn (%i, %i)): " + "%s != %s" % (ar_x, ar_y, sf_x, sf_y, sf_pix, color), + ) + + def _array_slice(self, ar, size, slices, strides, offset): + ar = ar[slices] + xslice, yslice = slices + w, h = size + xstart, xstop, xstep = xslice.indices(w) + ystart, ystop, ystep = yslice.indices(h) + w = (xstop - xstart + xstep - 1) // xstep + h = (ystop - ystart + ystep - 1) // ystep + xstride, ystride = strides + offset += xstart * xstride + ystart * ystride + xstride *= xstep + ystride *= ystep + return ar, (w, h), (xstride, ystride), offset + + def test_array_properties(self): + # itemsize, ndim, shape, and strides. + for bpp in [1, 2, 3, 4]: + sf = pygame.Surface((2, 2), 0, bpp * 8) + ar = pygame.PixelArray(sf) + self.assertEqual(ar.itemsize, bpp) + + for shape in [(4, 16), (5, 13)]: + w, h = shape + sf = pygame.Surface(shape, 0, 32) + bpp = sf.get_bytesize() + pitch = sf.get_pitch() + ar = pygame.PixelArray(sf) + self.assertEqual(ar.ndim, 2) + self.assertEqual(ar.shape, shape) + self.assertEqual(ar.strides, (bpp, pitch)) + ar2 = ar[::2, :] + w2 = len(([0] * w)[::2]) + self.assertEqual(ar2.ndim, 2) + self.assertEqual(ar2.shape, (w2, h)) + self.assertEqual(ar2.strides, (2 * bpp, pitch)) + ar2 = ar[:, ::2] + h2 = len(([0] * h)[::2]) + self.assertEqual(ar2.ndim, 2) + self.assertEqual(ar2.shape, (w, h2)) + self.assertEqual(ar2.strides, (bpp, 2 * pitch)) + ar2 = ar[1] + self.assertEqual(ar2.ndim, 1) + self.assertEqual(ar2.shape, (h,)) + self.assertEqual(ar2.strides, (pitch,)) + ar2 = ar[:, 1] + self.assertEqual(ar2.ndim, 1) + self.assertEqual(ar2.shape, (w,)) + self.assertEqual(ar2.strides, (bpp,)) + + def test_self_assign(self): + # This differs from NumPy arrays. + w = 10 + max_x = w - 1 + h = 20 + max_y = h - 1 + for bpp in [1, 2, 3, 4]: + sf = pygame.Surface((w, h), 0, bpp * 8) + ar = pygame.PixelArray(sf) + for i in range(w * h): + ar[i % w, i // w] = i + ar[:, :] = ar[::-1, :] + for i in range(w * h): + self.assertEqual(ar[max_x - i % w, i // w], i) + ar = pygame.PixelArray(sf) + for i in range(w * h): + ar[i % w, i // w] = i + ar[:, :] = ar[:, ::-1] + for i in range(w * h): + self.assertEqual(ar[i % w, max_y - i // w], i) + ar = pygame.PixelArray(sf) + for i in range(w * h): + ar[i % w, i // w] = i + ar[:, :] = ar[::-1, ::-1] + for i in range(w * h): + self.assertEqual(ar[max_x - i % w, max_y - i // w], i) + + def test_color_value(self): + # Confirm that a PixelArray slice assignment distinguishes between + # pygame.Color and tuple objects as single (r, g, b[, a]) colors + # and other sequences as sequences of colors to be treated as + # slices. + sf = pygame.Surface((5, 5), 0, 32) + ar = pygame.PixelArray(sf) + index = slice(None, None, 1) + ar.__setitem__(index, (1, 2, 3)) + self.assertEqual(ar[0, 0], sf.map_rgb((1, 2, 3))) + ar.__setitem__(index, pygame.Color(10, 11, 12)) + self.assertEqual(ar[0, 0], sf.map_rgb((10, 11, 12))) + self.assertRaises(ValueError, ar.__setitem__, index, (1, 2, 3, 4, 5)) + self.assertRaises(ValueError, ar.__setitem__, (index, index), (1, 2, 3, 4, 5)) + self.assertRaises(ValueError, ar.__setitem__, index, [1, 2, 3]) + self.assertRaises(ValueError, ar.__setitem__, (index, index), [1, 2, 3]) + sf = pygame.Surface((3, 3), 0, 32) + ar = pygame.PixelArray(sf) + ar[:] = (20, 30, 40) + self.assertEqual(ar[0, 0], sf.map_rgb((20, 30, 40))) + ar[:] = [20, 30, 40] + self.assertEqual(ar[0, 0], 20) + self.assertEqual(ar[1, 0], 30) + self.assertEqual(ar[2, 0], 40) + + def test_transpose(self): + # PixelArray.transpose(): swap axis on a 2D array, add a length + # 1 x axis to a 1D array. + sf = pygame.Surface((3, 7), 0, 32) + ar = pygame.PixelArray(sf) + w, h = ar.shape + dx, dy = ar.strides + for i in range(w * h): + x = i % w + y = i // w + ar[x, y] = i + ar_t = ar.transpose() + self.assertEqual(ar_t.shape, (h, w)) + self.assertEqual(ar_t.strides, (dy, dx)) + for i in range(w * h): + x = i % w + y = i // w + self.assertEqual(ar_t[y, x], ar[x, y]) + ar1D = ar[0] + ar2D = ar1D.transpose() + self.assertEqual(ar2D.shape, (1, h)) + for y in range(h): + self.assertEqual(ar1D[y], ar2D[0, y]) + ar1D = ar[:, 0] + ar2D = ar1D.transpose() + self.assertEqual(ar2D.shape, (1, w)) + for x in range(2): + self.assertEqual(ar1D[x], ar2D[0, x]) + + def test_length_1_dimension_broadcast(self): + w = 5 + sf = pygame.Surface((w, w), 0, 32) + ar = pygame.PixelArray(sf) + # y-axis broadcast. + sf_x = pygame.Surface((w, 1), 0, 32) + ar_x = pygame.PixelArray(sf_x) + for i in range(w): + ar_x[i, 0] = (w + 1) * 10 + ar[...] = ar_x + for y in range(w): + for x in range(w): + self.assertEqual(ar[x, y], ar_x[x, 0]) + # x-axis broadcast. + ar[...] = 0 + sf_y = pygame.Surface((1, w), 0, 32) + ar_y = pygame.PixelArray(sf_y) + for i in range(w): + ar_y[0, i] = (w + 1) * 10 + ar[...] = ar_y + for x in range(w): + for y in range(w): + self.assertEqual(ar[x, y], ar_y[0, y]) + # (1, 1) array broadcast. + ar[...] = 0 + sf_1px = pygame.Surface((1, 1), 0, 32) + ar_1px = pygame.PixelArray(sf_1px) + ar_1px[0, 0] = 42 # Well it had to show up somewhere. + ar[...] = ar_1px + for y in range(w): + for x in range(w): + self.assertEqual(ar[x, y], 42) + + def test_assign_size_mismatch(self): + sf = pygame.Surface((7, 11), 0, 32) + ar = pygame.PixelArray(sf) + self.assertRaises(ValueError, ar.__setitem__, Ellipsis, ar[:, 0:2]) + self.assertRaises(ValueError, ar.__setitem__, Ellipsis, ar[0:2, :]) + + def test_repr(self): + # Python 3.x bug: the tp_repr slot function returned NULL instead + # of a Unicode string, triggering an exception. + sf = pygame.Surface((3, 1), pygame.SRCALPHA, 16) + ar = pygame.PixelArray(sf) + ar[...] = 42 + pixel = sf.get_at_mapped((0, 0)) + self.assertEqual(repr(ar), type(ar).__name__ + "([\n [42, 42, 42]]\n)") + + +@unittest.skipIf(IS_PYPY, "pypy having issues") +class PixelArrayArrayInterfaceTest(unittest.TestCase, TestMixin): + @unittest.skipIf(IS_PYPY, "skipping for PyPy (why?)") + def test_basic(self): + # Check unchanging fields. + sf = pygame.Surface((2, 2), 0, 32) + ar = pygame.PixelArray(sf) + + ai = arrinter.ArrayInterface(ar) + self.assertEqual(ai.two, 2) + self.assertEqual(ai.typekind, "u") + self.assertEqual(ai.nd, 2) + self.assertEqual(ai.data, ar._pixels_address) + + @unittest.skipIf(IS_PYPY, "skipping for PyPy (why?)") + def test_shape(self): + + for shape in [[4, 16], [5, 13]]: + w, h = shape + sf = pygame.Surface(shape, 0, 32) + ar = pygame.PixelArray(sf) + ai = arrinter.ArrayInterface(ar) + ai_shape = [ai.shape[i] for i in range(ai.nd)] + self.assertEqual(ai_shape, shape) + ar2 = ar[::2, :] + ai2 = arrinter.ArrayInterface(ar2) + w2 = len(([0] * w)[::2]) + ai_shape = [ai2.shape[i] for i in range(ai2.nd)] + self.assertEqual(ai_shape, [w2, h]) + ar2 = ar[:, ::2] + ai2 = arrinter.ArrayInterface(ar2) + h2 = len(([0] * h)[::2]) + ai_shape = [ai2.shape[i] for i in range(ai2.nd)] + self.assertEqual(ai_shape, [w, h2]) + + @unittest.skipIf(IS_PYPY, "skipping for PyPy (why?)") + def test_itemsize(self): + for bytes_per_pixel in range(1, 5): + bits_per_pixel = 8 * bytes_per_pixel + sf = pygame.Surface((2, 2), 0, bits_per_pixel) + ar = pygame.PixelArray(sf) + ai = arrinter.ArrayInterface(ar) + self.assertEqual(ai.itemsize, bytes_per_pixel) + + @unittest.skipIf(IS_PYPY, "skipping for PyPy (why?)") + def test_flags(self): + aim = arrinter + common_flags = aim.PAI_NOTSWAPPED | aim.PAI_WRITEABLE | aim.PAI_ALIGNED + s = pygame.Surface((10, 2), 0, 32) + ar = pygame.PixelArray(s) + ai = aim.ArrayInterface(ar) + self.assertEqual(ai.flags, common_flags | aim.PAI_FORTRAN) + + ar2 = ar[::2, :] + ai = aim.ArrayInterface(ar2) + self.assertEqual(ai.flags, common_flags) + + s = pygame.Surface((8, 2), 0, 24) + ar = pygame.PixelArray(s) + ai = aim.ArrayInterface(ar) + self.assertEqual(ai.flags, common_flags | aim.PAI_FORTRAN) + + s = pygame.Surface((7, 2), 0, 24) + ar = pygame.PixelArray(s) + ai = aim.ArrayInterface(ar) + self.assertEqual(ai.flags, common_flags) + + def test_slicing(self): + # This will implicitly test data and strides fields. + # + # Need an 8 bit test surfaces because pixelcopy.make_surface + # returns an 8 bit surface for a 2d array. + + factors = [7, 3, 11] + + w = reduce(operator.mul, factors, 1) + h = 13 + sf = pygame.Surface((w, h), 0, 8) + color = sf.map_rgb((1, 17, 128)) + ar = pygame.PixelArray(sf) + for f in factors[:-1]: + w = w // f + sf.fill((0, 0, 0)) + ar = ar[f : f + w, :] + ar[0][0] = color + ar[-1][-2] = color + ar[0][-3] = color + sf2 = ar.make_surface() + sf3 = pygame.pixelcopy.make_surface(ar) + self.assert_surfaces_equal(sf3, sf2) + + h = reduce(operator.mul, factors, 1) + w = 13 + sf = pygame.Surface((w, h), 0, 8) + color = sf.map_rgb((1, 17, 128)) + ar = pygame.PixelArray(sf) + for f in factors[:-1]: + h = h // f + sf.fill((0, 0, 0)) + ar = ar[:, f : f + h] + ar[0][0] = color + ar[-1][-2] = color + ar[0][-3] = color + sf2 = ar.make_surface() + sf3 = pygame.pixelcopy.make_surface(ar) + self.assert_surfaces_equal(sf3, sf2) + + w = 20 + h = 10 + sf = pygame.Surface((w, h), 0, 8) + color = sf.map_rgb((1, 17, 128)) + ar = pygame.PixelArray(sf) + for slices in [ + (slice(w), slice(h)), + (slice(0, w, 2), slice(h)), + (slice(0, w, 3), slice(h)), + (slice(w), slice(0, h, 2)), + (slice(w), slice(0, h, 3)), + (slice(0, w, 2), slice(0, h, 2)), + (slice(0, w, 3), slice(0, h, 3)), + ]: + sf.fill((0, 0, 0)) + ar2 = ar[slices] + ar2[0][0] = color + ar2[-1][-2] = color + ar2[0][-3] = color + sf2 = ar2.make_surface() + sf3 = pygame.pixelcopy.make_surface(ar2) + self.assert_surfaces_equal(sf3, sf2) + + +@unittest.skipIf(not pygame.HAVE_NEWBUF, "newbuf not implemented") +@unittest.skipIf(IS_PYPY, "pypy having issues") +class PixelArrayNewBufferTest(unittest.TestCase, TestMixin): + + if pygame.HAVE_NEWBUF: + from pygame.tests.test_utils import buftools + + bitsize_to_format = {8: "B", 16: "=H", 24: "3x", 32: "=I"} + + def test_newbuf_2D(self): + buftools = self.buftools + Importer = buftools.Importer + + for bit_size in [8, 16, 24, 32]: + s = pygame.Surface((10, 2), 0, bit_size) + ar = pygame.PixelArray(s) + format = self.bitsize_to_format[bit_size] + itemsize = ar.itemsize + shape = ar.shape + w, h = shape + strides = ar.strides + length = w * h * itemsize + imp = Importer(ar, buftools.PyBUF_FULL) + self.assertTrue(imp.obj, ar) + self.assertEqual(imp.len, length) + self.assertEqual(imp.ndim, 2) + self.assertEqual(imp.itemsize, itemsize) + self.assertEqual(imp.format, format) + self.assertFalse(imp.readonly) + self.assertEqual(imp.shape, shape) + self.assertEqual(imp.strides, strides) + self.assertTrue(imp.suboffsets is None) + self.assertEqual(imp.buf, s._pixels_address) + + s = pygame.Surface((8, 16), 0, 32) + ar = pygame.PixelArray(s) + format = self.bitsize_to_format[s.get_bitsize()] + itemsize = ar.itemsize + shape = ar.shape + w, h = shape + strides = ar.strides + length = w * h * itemsize + imp = Importer(ar, buftools.PyBUF_SIMPLE) + self.assertTrue(imp.obj, ar) + self.assertEqual(imp.len, length) + self.assertEqual(imp.ndim, 0) + self.assertEqual(imp.itemsize, itemsize) + self.assertTrue(imp.format is None) + self.assertFalse(imp.readonly) + self.assertTrue(imp.shape is None) + self.assertTrue(imp.strides is None) + self.assertTrue(imp.suboffsets is None) + self.assertEqual(imp.buf, s._pixels_address) + imp = Importer(ar, buftools.PyBUF_FORMAT) + self.assertEqual(imp.ndim, 0) + self.assertEqual(imp.format, format) + imp = Importer(ar, buftools.PyBUF_WRITABLE) + self.assertEqual(imp.ndim, 0) + self.assertTrue(imp.format is None) + imp = Importer(ar, buftools.PyBUF_F_CONTIGUOUS) + self.assertEqual(imp.ndim, 2) + self.assertTrue(imp.format is None) + self.assertEqual(imp.shape, shape) + self.assertEqual(imp.strides, strides) + imp = Importer(ar, buftools.PyBUF_ANY_CONTIGUOUS) + self.assertEqual(imp.ndim, 2) + self.assertTrue(imp.format is None) + self.assertEqual(imp.shape, shape) + self.assertEqual(imp.strides, strides) + self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_C_CONTIGUOUS) + self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_ND) + + ar_sliced = ar[:, ::2] + format = self.bitsize_to_format[s.get_bitsize()] + itemsize = ar_sliced.itemsize + shape = ar_sliced.shape + w, h = shape + strides = ar_sliced.strides + length = w * h * itemsize + imp = Importer(ar_sliced, buftools.PyBUF_STRIDED) + self.assertEqual(imp.len, length) + self.assertEqual(imp.ndim, 2) + self.assertEqual(imp.itemsize, itemsize) + self.assertTrue(imp.format is None) + self.assertFalse(imp.readonly) + self.assertEqual(imp.shape, shape) + self.assertEqual(imp.strides, strides) + self.assertEqual(imp.buf, s._pixels_address) + self.assertRaises(BufferError, Importer, ar_sliced, buftools.PyBUF_SIMPLE) + self.assertRaises(BufferError, Importer, ar_sliced, buftools.PyBUF_ND) + self.assertRaises(BufferError, Importer, ar_sliced, buftools.PyBUF_C_CONTIGUOUS) + self.assertRaises(BufferError, Importer, ar_sliced, buftools.PyBUF_F_CONTIGUOUS) + self.assertRaises( + BufferError, Importer, ar_sliced, buftools.PyBUF_ANY_CONTIGUOUS + ) + + ar_sliced = ar[::2, :] + format = self.bitsize_to_format[s.get_bitsize()] + itemsize = ar_sliced.itemsize + shape = ar_sliced.shape + w, h = shape + strides = ar_sliced.strides + length = w * h * itemsize + imp = Importer(ar_sliced, buftools.PyBUF_STRIDED) + self.assertEqual(imp.len, length) + self.assertEqual(imp.ndim, 2) + self.assertEqual(imp.itemsize, itemsize) + self.assertTrue(imp.format is None) + self.assertFalse(imp.readonly) + self.assertEqual(imp.shape, shape) + self.assertEqual(imp.strides, strides) + self.assertEqual(imp.buf, s._pixels_address) + self.assertRaises(BufferError, Importer, ar_sliced, buftools.PyBUF_SIMPLE) + self.assertRaises(BufferError, Importer, ar_sliced, buftools.PyBUF_ND) + self.assertRaises(BufferError, Importer, ar_sliced, buftools.PyBUF_C_CONTIGUOUS) + self.assertRaises(BufferError, Importer, ar_sliced, buftools.PyBUF_F_CONTIGUOUS) + self.assertRaises( + BufferError, Importer, ar_sliced, buftools.PyBUF_ANY_CONTIGUOUS + ) + + s2 = s.subsurface((2, 3, 5, 7)) + ar = pygame.PixelArray(s2) + format = self.bitsize_to_format[s.get_bitsize()] + itemsize = ar.itemsize + shape = ar.shape + w, h = shape + strides = ar.strides + length = w * h * itemsize + imp = Importer(ar, buftools.PyBUF_STRIDES) + self.assertTrue(imp.obj, ar) + self.assertEqual(imp.len, length) + self.assertEqual(imp.ndim, 2) + self.assertEqual(imp.itemsize, itemsize) + self.assertTrue(imp.format is None) + self.assertFalse(imp.readonly) + self.assertEqual(imp.shape, shape) + self.assertEqual(imp.strides, strides) + self.assertTrue(imp.suboffsets is None) + self.assertEqual(imp.buf, s2._pixels_address) + self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_SIMPLE) + self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_FORMAT) + self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_WRITABLE) + self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_ND) + self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_C_CONTIGUOUS) + self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_F_CONTIGUOUS) + self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_ANY_CONTIGUOUS) + + def test_newbuf_1D(self): + buftools = self.buftools + Importer = buftools.Importer + + s = pygame.Surface((2, 16), 0, 32) + ar_2D = pygame.PixelArray(s) + x = 0 + ar = ar_2D[x] + format = self.bitsize_to_format[s.get_bitsize()] + itemsize = ar.itemsize + shape = ar.shape + h = shape[0] + strides = ar.strides + length = h * itemsize + buf = s._pixels_address + x * itemsize + imp = Importer(ar, buftools.PyBUF_STRIDES) + self.assertTrue(imp.obj, ar) + self.assertEqual(imp.len, length) + self.assertEqual(imp.ndim, 1) + self.assertEqual(imp.itemsize, itemsize) + self.assertTrue(imp.format is None) + self.assertFalse(imp.readonly) + self.assertEqual(imp.shape, shape) + self.assertEqual(imp.strides, strides) + self.assertTrue(imp.suboffsets is None) + self.assertEqual(imp.buf, buf) + imp = Importer(ar, buftools.PyBUF_FULL) + self.assertEqual(imp.ndim, 1) + self.assertEqual(imp.format, format) + self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_SIMPLE) + self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_FORMAT) + self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_WRITABLE) + self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_ND) + self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_C_CONTIGUOUS) + self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_F_CONTIGUOUS) + self.assertRaises(BufferError, Importer, ar, buftools.PyBUF_ANY_CONTIGUOUS) + y = 10 + ar = ar_2D[:, y] + shape = ar.shape + w = shape[0] + strides = ar.strides + length = w * itemsize + buf = s._pixels_address + y * s.get_pitch() + imp = Importer(ar, buftools.PyBUF_FULL) + self.assertEqual(imp.len, length) + self.assertEqual(imp.ndim, 1) + self.assertEqual(imp.itemsize, itemsize) + self.assertEqual(imp.format, format) + self.assertFalse(imp.readonly) + self.assertEqual(imp.shape, shape) + self.assertEqual(imp.strides, strides) + self.assertEqual(imp.buf, buf) + self.assertTrue(imp.suboffsets is None) + imp = Importer(ar, buftools.PyBUF_SIMPLE) + self.assertEqual(imp.len, length) + self.assertEqual(imp.ndim, 0) + self.assertEqual(imp.itemsize, itemsize) + self.assertTrue(imp.format is None) + self.assertFalse(imp.readonly) + self.assertTrue(imp.shape is None) + self.assertTrue(imp.strides is None) + imp = Importer(ar, buftools.PyBUF_ND) + self.assertEqual(imp.len, length) + self.assertEqual(imp.ndim, 1) + self.assertEqual(imp.itemsize, itemsize) + self.assertTrue(imp.format is None) + self.assertFalse(imp.readonly) + self.assertEqual(imp.shape, shape) + self.assertTrue(imp.strides is None) + imp = Importer(ar, buftools.PyBUF_C_CONTIGUOUS) + self.assertEqual(imp.ndim, 1) + imp = Importer(ar, buftools.PyBUF_F_CONTIGUOUS) + self.assertEqual(imp.ndim, 1) + imp = Importer(ar, buftools.PyBUF_ANY_CONTIGUOUS) + self.assertEqual(imp.ndim, 1) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/pixelcopy_test.py b/venv/Lib/site-packages/pygame/tests/pixelcopy_test.py new file mode 100644 index 0000000..f89c665 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/pixelcopy_test.py @@ -0,0 +1,712 @@ +import platform +import unittest + +try: + from pygame.tests.test_utils import arrinter +except NameError: + pass +import pygame +from pygame.locals import * +from pygame.pixelcopy import surface_to_array, map_array, array_to_surface, make_surface + +IS_PYPY = "PyPy" == platform.python_implementation() + + +def unsigned32(i): + """cast signed 32 bit integer to an unsigned integer""" + return i & 0xFFFFFFFF + + +@unittest.skipIf(IS_PYPY, "pypy having illegal instruction on mac") +class PixelcopyModuleTest(unittest.TestCase): + + bitsizes = [8, 16, 32] + + test_palette = [ + (0, 0, 0, 255), + (10, 30, 60, 255), + (25, 75, 100, 255), + (100, 150, 200, 255), + (0, 100, 200, 255), + ] + + surf_size = (10, 12) + test_points = [ + ((0, 0), 1), + ((4, 5), 1), + ((9, 0), 2), + ((5, 5), 2), + ((0, 11), 3), + ((4, 6), 3), + ((9, 11), 4), + ((5, 6), 4), + ] + + def __init__(self, *args, **kwds): + pygame.display.init() + try: + unittest.TestCase.__init__(self, *args, **kwds) + self.sources = [ + self._make_src_surface(8), + self._make_src_surface(16), + self._make_src_surface(16, srcalpha=True), + self._make_src_surface(24), + self._make_src_surface(32), + self._make_src_surface(32, srcalpha=True), + ] + finally: + pygame.display.quit() + + def _make_surface(self, bitsize, srcalpha=False, palette=None): + if palette is None: + palette = self.test_palette + flags = 0 + if srcalpha: + flags |= SRCALPHA + surf = pygame.Surface(self.surf_size, flags, bitsize) + if bitsize == 8: + surf.set_palette([c[:3] for c in palette]) + return surf + + def _fill_surface(self, surf, palette=None): + if palette is None: + palette = self.test_palette + surf.fill(palette[1], (0, 0, 5, 6)) + surf.fill(palette[2], (5, 0, 5, 6)) + surf.fill(palette[3], (0, 6, 5, 6)) + surf.fill(palette[4], (5, 6, 5, 6)) + + def _make_src_surface(self, bitsize, srcalpha=False, palette=None): + surf = self._make_surface(bitsize, srcalpha, palette) + self._fill_surface(surf, palette) + return surf + + def setUp(self): + pygame.display.init() + + def tearDown(self): + pygame.display.quit() + + def test_surface_to_array_2d(self): + alpha_color = (0, 0, 0, 128) + + for surf in self.sources: + src_bitsize = surf.get_bitsize() + for dst_bitsize in self.bitsizes: + # dst in a surface standing in for a 2 dimensional array + # of unsigned integers. The byte order is system dependent. + dst = pygame.Surface(surf.get_size(), 0, dst_bitsize) + dst.fill((0, 0, 0, 0)) + view = dst.get_view("2") + self.assertFalse(surf.get_locked()) + if dst_bitsize < src_bitsize: + self.assertRaises(ValueError, surface_to_array, view, surf) + self.assertFalse(surf.get_locked()) + continue + surface_to_array(view, surf) + self.assertFalse(surf.get_locked()) + for posn, i in self.test_points: + sp = surf.get_at_mapped(posn) + dp = dst.get_at_mapped(posn) + self.assertEqual( + dp, + sp, + "%s != %s: flags: %i" + ", bpp: %i, posn: %s" + % (dp, sp, surf.get_flags(), surf.get_bitsize(), posn), + ) + del view + + if surf.get_masks()[3]: + dst.fill((0, 0, 0, 0)) + view = dst.get_view("2") + posn = (2, 1) + surf.set_at(posn, alpha_color) + self.assertFalse(surf.get_locked()) + surface_to_array(view, surf) + self.assertFalse(surf.get_locked()) + sp = surf.get_at_mapped(posn) + dp = dst.get_at_mapped(posn) + self.assertEqual( + dp, sp, "%s != %s: bpp: %i" % (dp, sp, surf.get_bitsize()) + ) + + if IS_PYPY: + return + # Swapped endian destination array + pai_flags = arrinter.PAI_ALIGNED | arrinter.PAI_WRITEABLE + for surf in self.sources: + for itemsize in [1, 2, 4, 8]: + if itemsize < surf.get_bytesize(): + continue + a = arrinter.Array(surf.get_size(), "u", itemsize, flags=pai_flags) + surface_to_array(a, surf) + for posn, i in self.test_points: + sp = unsigned32(surf.get_at_mapped(posn)) + dp = a[posn] + self.assertEqual( + dp, + sp, + "%s != %s: itemsize: %i, flags: %i" + ", bpp: %i, posn: %s" + % ( + dp, + sp, + itemsize, + surf.get_flags(), + surf.get_bitsize(), + posn, + ), + ) + + def test_surface_to_array_3d(self): + self.iter_surface_to_array_3d((0xFF, 0xFF00, 0xFF0000, 0)) + self.iter_surface_to_array_3d((0xFF0000, 0xFF00, 0xFF, 0)) + + def iter_surface_to_array_3d(self, rgba_masks): + dst = pygame.Surface(self.surf_size, 0, 24, masks=rgba_masks) + + for surf in self.sources: + dst.fill((0, 0, 0, 0)) + src_bitsize = surf.get_bitsize() + view = dst.get_view("3") + self.assertFalse(surf.get_locked()) + surface_to_array(view, surf) + self.assertFalse(surf.get_locked()) + for posn, i in self.test_points: + sc = surf.get_at(posn)[0:3] + dc = dst.get_at(posn)[0:3] + self.assertEqual( + dc, + sc, + "%s != %s: flags: %i" + ", bpp: %i, posn: %s" + % (dc, sc, surf.get_flags(), surf.get_bitsize(), posn), + ) + view = None + + def test_map_array(self): + targets = [ + self._make_surface(8), + self._make_surface(16), + self._make_surface(16, srcalpha=True), + self._make_surface(24), + self._make_surface(32), + self._make_surface(32, srcalpha=True), + ] + source = pygame.Surface( + self.surf_size, 0, 24, masks=[0xFF, 0xFF00, 0xFF0000, 0] + ) + self._fill_surface(source) + source_view = source.get_view("3") # (w, h, 3) + for t in targets: + map_array(t.get_view("2"), source_view, t) + for posn, i in self.test_points: + sc = t.map_rgb(source.get_at(posn)) + dc = t.get_at_mapped(posn) + self.assertEqual( + dc, + sc, + "%s != %s: flags: %i" + ", bpp: %i, posn: %s" + % (dc, sc, t.get_flags(), t.get_bitsize(), posn), + ) + + color = pygame.Color("salmon") + color.set_length(3) + for t in targets: + map_array(t.get_view("2"), color, t) + sc = t.map_rgb(color) + for posn, i in self.test_points: + dc = t.get_at_mapped(posn) + self.assertEqual( + dc, + sc, + "%s != %s: flags: %i" + ", bpp: %i, posn: %s" + % (dc, sc, t.get_flags(), t.get_bitsize(), posn), + ) + + # mismatched shapes + w, h = source.get_size() + target = pygame.Surface((w, h + 1), 0, 32) + self.assertRaises(ValueError, map_array, target, source, target) + target = pygame.Surface((w - 1, h), 0, 32) + self.assertRaises(ValueError, map_array, target, source, target) + + def test_array_to_surface_broadcasting(self): + # target surfaces + targets = [ + self._make_surface(8), + self._make_surface(16), + self._make_surface(16, srcalpha=True), + self._make_surface(24), + self._make_surface(32), + self._make_surface(32, srcalpha=True), + ] + + w, h = self.surf_size + + # broadcast column + column = pygame.Surface((1, h), 0, 32) + for target in targets: + source = pygame.Surface((1, h), 0, target) + for y in range(h): + source.set_at((0, y), pygame.Color(y + 1, y + h + 1, y + 2 * h + 1)) + pygame.pixelcopy.surface_to_array(column.get_view("2"), source) + pygame.pixelcopy.array_to_surface(target, column.get_view("2")) + for x in range(w): + for y in range(h): + self.assertEqual( + target.get_at_mapped((x, y)), column.get_at_mapped((0, y)) + ) + + # broadcast row + row = pygame.Surface((w, 1), 0, 32) + for target in targets: + source = pygame.Surface((w, 1), 0, target) + for x in range(w): + source.set_at((x, 0), pygame.Color(x + 1, x + w + 1, x + 2 * w + 1)) + pygame.pixelcopy.surface_to_array(row.get_view("2"), source) + pygame.pixelcopy.array_to_surface(target, row.get_view("2")) + for x in range(w): + for y in range(h): + self.assertEqual( + target.get_at_mapped((x, y)), row.get_at_mapped((x, 0)) + ) + + # broadcast pixel + pixel = pygame.Surface((1, 1), 0, 32) + for target in targets: + source = pygame.Surface((1, 1), 0, target) + source.set_at((0, 0), pygame.Color(13, 47, 101)) + pygame.pixelcopy.surface_to_array(pixel.get_view("2"), source) + pygame.pixelcopy.array_to_surface(target, pixel.get_view("2")) + p = pixel.get_at_mapped((0, 0)) + for x in range(w): + for y in range(h): + self.assertEqual(target.get_at_mapped((x, y)), p) + + +@unittest.skipIf(IS_PYPY, "pypy having illegal instruction on mac") +class PixelCopyTestWithArray(unittest.TestCase): + try: + import numpy + except ImportError: + __tags__ = ["ignore", "subprocess_ignore"] + else: + pygame.surfarray.use_arraytype("numpy") + + bitsizes = [8, 16, 32] + + test_palette = [ + (0, 0, 0, 255), + (10, 30, 60, 255), + (25, 75, 100, 255), + (100, 150, 200, 255), + (0, 100, 200, 255), + ] + + surf_size = (10, 12) + test_points = [ + ((0, 0), 1), + ((4, 5), 1), + ((9, 0), 2), + ((5, 5), 2), + ((0, 11), 3), + ((4, 6), 3), + ((9, 11), 4), + ((5, 6), 4), + ] + + pixels2d = set([8, 16, 32]) + pixels3d = set([24, 32]) + array2d = set([8, 16, 24, 32]) + array3d = set([24, 32]) + + def __init__(self, *args, **kwds): + import numpy + + self.dst_types = [numpy.uint8, numpy.uint16, numpy.uint32] + try: + self.dst_types.append(numpy.uint64) + except AttributeError: + pass + pygame.display.init() + try: + unittest.TestCase.__init__(self, *args, **kwds) + self.sources = [ + self._make_src_surface(8), + self._make_src_surface(16), + self._make_src_surface(16, srcalpha=True), + self._make_src_surface(24), + self._make_src_surface(32), + self._make_src_surface(32, srcalpha=True), + ] + finally: + pygame.display.quit() + + def _make_surface(self, bitsize, srcalpha=False, palette=None): + if palette is None: + palette = self.test_palette + flags = 0 + if srcalpha: + flags |= SRCALPHA + surf = pygame.Surface(self.surf_size, flags, bitsize) + if bitsize == 8: + surf.set_palette([c[:3] for c in palette]) + return surf + + def _fill_surface(self, surf, palette=None): + if palette is None: + palette = self.test_palette + surf.fill(palette[1], (0, 0, 5, 6)) + surf.fill(palette[2], (5, 0, 5, 6)) + surf.fill(palette[3], (0, 6, 5, 6)) + surf.fill(palette[4], (5, 6, 5, 6)) + + def _make_src_surface(self, bitsize, srcalpha=False, palette=None): + surf = self._make_surface(bitsize, srcalpha, palette) + self._fill_surface(surf, palette) + return surf + + def setUp(self): + pygame.display.init() + + def tearDown(self): + pygame.display.quit() + + def test_surface_to_array_2d(self): + try: + from numpy import empty, dtype + except ImportError: + return + + palette = self.test_palette + alpha_color = (0, 0, 0, 128) + + dst_dims = self.surf_size + destinations = [empty(dst_dims, t) for t in self.dst_types] + if pygame.get_sdl_byteorder() == pygame.LIL_ENDIAN: + swapped_dst = empty(dst_dims, dtype(">u4")) + else: + swapped_dst = empty(dst_dims, dtype("u4")) + else: + swapped_dst = empty(dst_dims, dtype("i", + "!i", + "1i", + "=1i", + "@q", + "q", + "4x", + "8x", + ]: + surface.fill((255, 254, 253)) + exp = Exporter(shape, format=format) + exp._buf[:] = [42] * exp.buflen + array_to_surface(surface, exp) + for x in range(w): + for y in range(h): + self.assertEqual(surface.get_at((x, y)), (42, 42, 42, 255)) + # Some unsupported formats for array_to_surface and a 32 bit surface + for format in ["f", "d", "?", "x", "1x", "2x", "3x", "5x", "6x", "7x", "9x"]: + exp = Exporter(shape, format=format) + self.assertRaises(ValueError, array_to_surface, surface, exp) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/rect_test.py b/venv/Lib/site-packages/pygame/tests/rect_test.py new file mode 100644 index 0000000..0d635c8 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/rect_test.py @@ -0,0 +1,2152 @@ +import math +import sys +import unittest +import platform + +from pygame import Rect, Vector2 +from pygame.tests import test_utils + + +IS_PYPY = "PyPy" == platform.python_implementation() + + +class RectTypeTest(unittest.TestCase): + def _assertCountEqual(self, *args, **kwargs): + self.assertCountEqual(*args, **kwargs) + + def testConstructionXYWidthHeight(self): + r = Rect(1, 2, 3, 4) + self.assertEqual(1, r.left) + self.assertEqual(2, r.top) + self.assertEqual(3, r.width) + self.assertEqual(4, r.height) + + def testConstructionTopLeftSize(self): + r = Rect((1, 2), (3, 4)) + self.assertEqual(1, r.left) + self.assertEqual(2, r.top) + self.assertEqual(3, r.width) + self.assertEqual(4, r.height) + + def testCalculatedAttributes(self): + r = Rect(1, 2, 3, 4) + + self.assertEqual(r.left + r.width, r.right) + self.assertEqual(r.top + r.height, r.bottom) + self.assertEqual((r.width, r.height), r.size) + self.assertEqual((r.left, r.top), r.topleft) + self.assertEqual((r.right, r.top), r.topright) + self.assertEqual((r.left, r.bottom), r.bottomleft) + self.assertEqual((r.right, r.bottom), r.bottomright) + + midx = r.left + r.width // 2 + midy = r.top + r.height // 2 + + self.assertEqual(midx, r.centerx) + self.assertEqual(midy, r.centery) + self.assertEqual((r.centerx, r.centery), r.center) + self.assertEqual((r.centerx, r.top), r.midtop) + self.assertEqual((r.centerx, r.bottom), r.midbottom) + self.assertEqual((r.left, r.centery), r.midleft) + self.assertEqual((r.right, r.centery), r.midright) + + def test_normalize(self): + """Ensures normalize works when width and height are both negative.""" + test_rect = Rect((1, 2), (-3, -6)) + expected_normalized_rect = ( + (test_rect.x + test_rect.w, test_rect.y + test_rect.h), + (-test_rect.w, -test_rect.h), + ) + + test_rect.normalize() + + self.assertEqual(test_rect, expected_normalized_rect) + + @unittest.skipIf(IS_PYPY, "fails on pypy sometimes") + def test_normalize__positive_height(self): + """Ensures normalize works with a negative width and a positive height.""" + test_rect = Rect((1, 2), (-3, 6)) + expected_normalized_rect = ( + (test_rect.x + test_rect.w, test_rect.y), + (-test_rect.w, test_rect.h), + ) + + test_rect.normalize() + + self.assertEqual(test_rect, expected_normalized_rect) + + @unittest.skipIf(IS_PYPY, "fails on pypy sometimes") + def test_normalize__positive_width(self): + """Ensures normalize works with a positive width and a negative height.""" + test_rect = Rect((1, 2), (3, -6)) + expected_normalized_rect = ( + (test_rect.x, test_rect.y + test_rect.h), + (test_rect.w, -test_rect.h), + ) + + test_rect.normalize() + + self.assertEqual(test_rect, expected_normalized_rect) + + @unittest.skipIf(IS_PYPY, "fails on pypy sometimes") + def test_normalize__zero_height(self): + """Ensures normalize works with a negative width and a zero height.""" + test_rect = Rect((1, 2), (-3, 0)) + expected_normalized_rect = ( + (test_rect.x + test_rect.w, test_rect.y), + (-test_rect.w, test_rect.h), + ) + + test_rect.normalize() + + self.assertEqual(test_rect, expected_normalized_rect) + + @unittest.skipIf(IS_PYPY, "fails on pypy sometimes") + def test_normalize__zero_width(self): + """Ensures normalize works with a zero width and a negative height.""" + test_rect = Rect((1, 2), (0, -6)) + expected_normalized_rect = ( + (test_rect.x, test_rect.y + test_rect.h), + (test_rect.w, -test_rect.h), + ) + + test_rect.normalize() + + self.assertEqual(test_rect, expected_normalized_rect) + + @unittest.skipIf(IS_PYPY, "fails on pypy") + def test_normalize__non_negative(self): + """Ensures normalize works when width and height are both non-negative. + + Tests combinations of positive and zero values for width and height. + The normalize method has no impact when both width and height are + non-negative. + """ + for size in ((3, 6), (3, 0), (0, 6), (0, 0)): + test_rect = Rect((1, 2), size) + expected_normalized_rect = Rect(test_rect) + + test_rect.normalize() + + self.assertEqual(test_rect, expected_normalized_rect) + + def test_x(self): + """Ensures changing the x attribute moves the rect and does not change + the rect's size. + """ + expected_x = 10 + expected_y = 2 + expected_size = (3, 4) + r = Rect((1, expected_y), expected_size) + + r.x = expected_x + + self.assertEqual(r.x, expected_x) + self.assertEqual(r.x, r.left) + self.assertEqual(r.y, expected_y) + self.assertEqual(r.size, expected_size) + + def test_x__invalid_value(self): + """Ensures the x attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.x = value + + def test_x__del(self): + """Ensures the x attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.x + + def test_y(self): + """Ensures changing the y attribute moves the rect and does not change + the rect's size. + """ + expected_x = 1 + expected_y = 20 + expected_size = (3, 4) + r = Rect((expected_x, 2), expected_size) + + r.y = expected_y + + self.assertEqual(r.y, expected_y) + self.assertEqual(r.y, r.top) + self.assertEqual(r.x, expected_x) + self.assertEqual(r.size, expected_size) + + def test_y__invalid_value(self): + """Ensures the y attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.y = value + + def test_y__del(self): + """Ensures the y attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.y + + def test_left(self): + """Changing the left attribute moves the rect and does not change + the rect's width + """ + r = Rect(1, 2, 3, 4) + new_left = 10 + + r.left = new_left + self.assertEqual(new_left, r.left) + self.assertEqual(Rect(new_left, 2, 3, 4), r) + + def test_left__invalid_value(self): + """Ensures the left attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.left = value + + def test_left__del(self): + """Ensures the left attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.left + + def test_right(self): + """Changing the right attribute moves the rect and does not change + the rect's width + """ + r = Rect(1, 2, 3, 4) + new_right = r.right + 20 + expected_left = r.left + 20 + old_width = r.width + + r.right = new_right + self.assertEqual(new_right, r.right) + self.assertEqual(expected_left, r.left) + self.assertEqual(old_width, r.width) + + def test_right__invalid_value(self): + """Ensures the right attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.right = value + + def test_right__del(self): + """Ensures the right attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.right + + def test_top(self): + """Changing the top attribute moves the rect and does not change + the rect's width + """ + r = Rect(1, 2, 3, 4) + new_top = 10 + + r.top = new_top + self.assertEqual(Rect(1, new_top, 3, 4), r) + self.assertEqual(new_top, r.top) + + def test_top__invalid_value(self): + """Ensures the top attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.top = value + + def test_top__del(self): + """Ensures the top attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.top + + def test_bottom(self): + """Changing the bottom attribute moves the rect and does not change + the rect's height + """ + r = Rect(1, 2, 3, 4) + new_bottom = r.bottom + 20 + expected_top = r.top + 20 + old_height = r.height + + r.bottom = new_bottom + self.assertEqual(new_bottom, r.bottom) + self.assertEqual(expected_top, r.top) + self.assertEqual(old_height, r.height) + + def test_bottom__invalid_value(self): + """Ensures the bottom attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.bottom = value + + def test_bottom__del(self): + """Ensures the bottom attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.bottom + + def test_centerx(self): + """Changing the centerx attribute moves the rect and does not change + the rect's width + """ + r = Rect(1, 2, 3, 4) + new_centerx = r.centerx + 20 + expected_left = r.left + 20 + old_width = r.width + + r.centerx = new_centerx + self.assertEqual(new_centerx, r.centerx) + self.assertEqual(expected_left, r.left) + self.assertEqual(old_width, r.width) + + def test_centerx__invalid_value(self): + """Ensures the centerx attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.centerx = value + + def test_centerx__del(self): + """Ensures the centerx attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.centerx + + def test_centery(self): + """Changing the centery attribute moves the rect and does not change + the rect's width + """ + r = Rect(1, 2, 3, 4) + new_centery = r.centery + 20 + expected_top = r.top + 20 + old_height = r.height + + r.centery = new_centery + self.assertEqual(new_centery, r.centery) + self.assertEqual(expected_top, r.top) + self.assertEqual(old_height, r.height) + + def test_centery__invalid_value(self): + """Ensures the centery attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.centery = value + + def test_centery__del(self): + """Ensures the centery attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.centery + + def test_topleft(self): + """Changing the topleft attribute moves the rect and does not change + the rect's size + """ + r = Rect(1, 2, 3, 4) + new_topleft = (r.left + 20, r.top + 30) + old_size = r.size + + r.topleft = new_topleft + self.assertEqual(new_topleft, r.topleft) + self.assertEqual(old_size, r.size) + + def test_topleft__invalid_value(self): + """Ensures the topleft attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", 1, (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.topleft = value + + def test_topleft__del(self): + """Ensures the topleft attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.topleft + + def test_bottomleft(self): + """Changing the bottomleft attribute moves the rect and does not change + the rect's size + """ + r = Rect(1, 2, 3, 4) + new_bottomleft = (r.left + 20, r.bottom + 30) + expected_topleft = (r.left + 20, r.top + 30) + old_size = r.size + + r.bottomleft = new_bottomleft + self.assertEqual(new_bottomleft, r.bottomleft) + self.assertEqual(expected_topleft, r.topleft) + self.assertEqual(old_size, r.size) + + def test_bottomleft__invalid_value(self): + """Ensures the bottomleft attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", 1, (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.bottomleft = value + + def test_bottomleft__del(self): + """Ensures the bottomleft attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.bottomleft + + def test_topright(self): + """Changing the topright attribute moves the rect and does not change + the rect's size + """ + r = Rect(1, 2, 3, 4) + new_topright = (r.right + 20, r.top + 30) + expected_topleft = (r.left + 20, r.top + 30) + old_size = r.size + + r.topright = new_topright + self.assertEqual(new_topright, r.topright) + self.assertEqual(expected_topleft, r.topleft) + self.assertEqual(old_size, r.size) + + def test_topright__invalid_value(self): + """Ensures the topright attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", 1, (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.topright = value + + def test_topright__del(self): + """Ensures the topright attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.topright + + def test_bottomright(self): + """Changing the bottomright attribute moves the rect and does not change + the rect's size + """ + r = Rect(1, 2, 3, 4) + new_bottomright = (r.right + 20, r.bottom + 30) + expected_topleft = (r.left + 20, r.top + 30) + old_size = r.size + + r.bottomright = new_bottomright + self.assertEqual(new_bottomright, r.bottomright) + self.assertEqual(expected_topleft, r.topleft) + self.assertEqual(old_size, r.size) + + def test_bottomright__invalid_value(self): + """Ensures the bottomright attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", 1, (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.bottomright = value + + def test_bottomright__del(self): + """Ensures the bottomright attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.bottomright + + def test_center(self): + """Changing the center attribute moves the rect and does not change + the rect's size + """ + r = Rect(1, 2, 3, 4) + new_center = (r.centerx + 20, r.centery + 30) + expected_topleft = (r.left + 20, r.top + 30) + old_size = r.size + + r.center = new_center + self.assertEqual(new_center, r.center) + self.assertEqual(expected_topleft, r.topleft) + self.assertEqual(old_size, r.size) + + def test_center__invalid_value(self): + """Ensures the center attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", 1, (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.center = value + + def test_center__del(self): + """Ensures the center attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.center + + def test_midleft(self): + """Changing the midleft attribute moves the rect and does not change + the rect's size + """ + r = Rect(1, 2, 3, 4) + new_midleft = (r.left + 20, r.centery + 30) + expected_topleft = (r.left + 20, r.top + 30) + old_size = r.size + + r.midleft = new_midleft + self.assertEqual(new_midleft, r.midleft) + self.assertEqual(expected_topleft, r.topleft) + self.assertEqual(old_size, r.size) + + def test_midleft__invalid_value(self): + """Ensures the midleft attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", 1, (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.midleft = value + + def test_midleft__del(self): + """Ensures the midleft attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.midleft + + def test_midright(self): + """Changing the midright attribute moves the rect and does not change + the rect's size + """ + r = Rect(1, 2, 3, 4) + new_midright = (r.right + 20, r.centery + 30) + expected_topleft = (r.left + 20, r.top + 30) + old_size = r.size + + r.midright = new_midright + self.assertEqual(new_midright, r.midright) + self.assertEqual(expected_topleft, r.topleft) + self.assertEqual(old_size, r.size) + + def test_midright__invalid_value(self): + """Ensures the midright attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", 1, (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.midright = value + + def test_midright__del(self): + """Ensures the midright attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.midright + + def test_midtop(self): + """Changing the midtop attribute moves the rect and does not change + the rect's size + """ + r = Rect(1, 2, 3, 4) + new_midtop = (r.centerx + 20, r.top + 30) + expected_topleft = (r.left + 20, r.top + 30) + old_size = r.size + + r.midtop = new_midtop + self.assertEqual(new_midtop, r.midtop) + self.assertEqual(expected_topleft, r.topleft) + self.assertEqual(old_size, r.size) + + def test_midtop__invalid_value(self): + """Ensures the midtop attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", 1, (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.midtop = value + + def test_midtop__del(self): + """Ensures the midtop attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.midtop + + def test_midbottom(self): + """Changing the midbottom attribute moves the rect and does not change + the rect's size + """ + r = Rect(1, 2, 3, 4) + new_midbottom = (r.centerx + 20, r.bottom + 30) + expected_topleft = (r.left + 20, r.top + 30) + old_size = r.size + + r.midbottom = new_midbottom + self.assertEqual(new_midbottom, r.midbottom) + self.assertEqual(expected_topleft, r.topleft) + self.assertEqual(old_size, r.size) + + def test_midbottom__invalid_value(self): + """Ensures the midbottom attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", 1, (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.midbottom = value + + def test_midbottom__del(self): + """Ensures the midbottom attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.midbottom + + def test_width(self): + """Changing the width resizes the rect from the top-left corner""" + r = Rect(1, 2, 3, 4) + new_width = 10 + old_topleft = r.topleft + old_height = r.height + + r.width = new_width + self.assertEqual(new_width, r.width) + self.assertEqual(old_height, r.height) + self.assertEqual(old_topleft, r.topleft) + + def test_width__invalid_value(self): + """Ensures the width attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.width = value + + def test_width__del(self): + """Ensures the width attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.width + + def test_height(self): + """Changing the height resizes the rect from the top-left corner""" + r = Rect(1, 2, 3, 4) + new_height = 10 + old_topleft = r.topleft + old_width = r.width + + r.height = new_height + self.assertEqual(new_height, r.height) + self.assertEqual(old_width, r.width) + self.assertEqual(old_topleft, r.topleft) + + def test_height__invalid_value(self): + """Ensures the height attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.height = value + + def test_height__del(self): + """Ensures the height attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.height + + def test_size(self): + """Changing the size resizes the rect from the top-left corner""" + r = Rect(1, 2, 3, 4) + new_size = (10, 20) + old_topleft = r.topleft + + r.size = new_size + self.assertEqual(new_size, r.size) + self.assertEqual(old_topleft, r.topleft) + + def test_size__invalid_value(self): + """Ensures the size attribute handles invalid values correctly.""" + r = Rect(0, 0, 1, 1) + + for value in (None, [], "1", 1, (1,), [1, 2, 3]): + with self.assertRaises(TypeError): + r.size = value + + def test_size__del(self): + """Ensures the size attribute can't be deleted.""" + r = Rect(0, 0, 1, 1) + + with self.assertRaises(AttributeError): + del r.size + + def test_contains(self): + r = Rect(1, 2, 3, 4) + + self.assertTrue( + r.contains(Rect(2, 3, 1, 1)), "r does not contain Rect(2, 3, 1, 1)" + ) + self.assertTrue(Rect(2, 3, 1, 1) in r, "r does not contain Rect(2, 3, 1, 1) 2") + self.assertTrue( + r.contains(Rect(r)), "r does not contain the same rect as itself" + ) + self.assertTrue(r in Rect(r), "r does not contain the same rect as itself") + self.assertTrue( + r.contains(Rect(2, 3, 0, 0)), + "r does not contain an empty rect within its bounds", + ) + self.assertTrue( + Rect(2, 3, 0, 0) in r, + "r does not contain an empty rect within its bounds", + ) + self.assertFalse(r.contains(Rect(0, 0, 1, 2)), "r contains Rect(0, 0, 1, 2)") + self.assertFalse(r.contains(Rect(4, 6, 1, 1)), "r contains Rect(4, 6, 1, 1)") + self.assertFalse(r.contains(Rect(4, 6, 0, 0)), "r contains Rect(4, 6, 0, 0)") + self.assertFalse(Rect(0, 0, 1, 2) in r, "r contains Rect(0, 0, 1, 2)") + self.assertFalse(Rect(4, 6, 1, 1) in r, "r contains Rect(4, 6, 1, 1)") + self.assertFalse(Rect(4, 6, 0, 0) in r, "r contains Rect(4, 6, 0, 0)") + self.assertTrue(2 in Rect(0, 0, 1, 2), "r does not contain 2") + self.assertFalse(3 in Rect(0, 0, 1, 2), "r contains 3") + + def test_collidepoint(self): + r = Rect(1, 2, 3, 4) + + self.assertTrue( + r.collidepoint(r.left, r.top), "r does not collide with point (left, top)" + ) + self.assertFalse( + r.collidepoint(r.left - 1, r.top), "r collides with point (left - 1, top)" + ) + self.assertFalse( + r.collidepoint(r.left, r.top - 1), "r collides with point (left, top - 1)" + ) + self.assertFalse( + r.collidepoint(r.left - 1, r.top - 1), + "r collides with point (left - 1, top - 1)", + ) + + self.assertTrue( + r.collidepoint(r.right - 1, r.bottom - 1), + "r does not collide with point (right - 1, bottom - 1)", + ) + self.assertFalse( + r.collidepoint(r.right, r.bottom), "r collides with point (right, bottom)" + ) + self.assertFalse( + r.collidepoint(r.right - 1, r.bottom), + "r collides with point (right - 1, bottom)", + ) + self.assertFalse( + r.collidepoint(r.right, r.bottom - 1), + "r collides with point (right, bottom - 1)", + ) + + def test_inflate__larger(self): + """The inflate method inflates around the center of the rectangle""" + r = Rect(2, 4, 6, 8) + r2 = r.inflate(4, 6) + + self.assertEqual(r.center, r2.center) + self.assertEqual(r.left - 2, r2.left) + self.assertEqual(r.top - 3, r2.top) + self.assertEqual(r.right + 2, r2.right) + self.assertEqual(r.bottom + 3, r2.bottom) + self.assertEqual(r.width + 4, r2.width) + self.assertEqual(r.height + 6, r2.height) + + def test_inflate__smaller(self): + """The inflate method inflates around the center of the rectangle""" + r = Rect(2, 4, 6, 8) + r2 = r.inflate(-4, -6) + + self.assertEqual(r.center, r2.center) + self.assertEqual(r.left + 2, r2.left) + self.assertEqual(r.top + 3, r2.top) + self.assertEqual(r.right - 2, r2.right) + self.assertEqual(r.bottom - 3, r2.bottom) + self.assertEqual(r.width - 4, r2.width) + self.assertEqual(r.height - 6, r2.height) + + def test_inflate_ip__larger(self): + """The inflate_ip method inflates around the center of the rectangle""" + r = Rect(2, 4, 6, 8) + r2 = Rect(r) + r2.inflate_ip(-4, -6) + + self.assertEqual(r.center, r2.center) + self.assertEqual(r.left + 2, r2.left) + self.assertEqual(r.top + 3, r2.top) + self.assertEqual(r.right - 2, r2.right) + self.assertEqual(r.bottom - 3, r2.bottom) + self.assertEqual(r.width - 4, r2.width) + self.assertEqual(r.height - 6, r2.height) + + def test_inflate_ip__smaller(self): + """The inflate method inflates around the center of the rectangle""" + r = Rect(2, 4, 6, 8) + r2 = Rect(r) + r2.inflate_ip(-4, -6) + + self.assertEqual(r.center, r2.center) + self.assertEqual(r.left + 2, r2.left) + self.assertEqual(r.top + 3, r2.top) + self.assertEqual(r.right - 2, r2.right) + self.assertEqual(r.bottom - 3, r2.bottom) + self.assertEqual(r.width - 4, r2.width) + self.assertEqual(r.height - 6, r2.height) + + def test_clamp(self): + r = Rect(10, 10, 10, 10) + c = Rect(19, 12, 5, 5).clamp(r) + self.assertEqual(c.right, r.right) + self.assertEqual(c.top, 12) + c = Rect(1, 2, 3, 4).clamp(r) + self.assertEqual(c.topleft, r.topleft) + c = Rect(5, 500, 22, 33).clamp(r) + self.assertEqual(c.center, r.center) + + def test_clamp_ip(self): + r = Rect(10, 10, 10, 10) + c = Rect(19, 12, 5, 5) + c.clamp_ip(r) + self.assertEqual(c.right, r.right) + self.assertEqual(c.top, 12) + c = Rect(1, 2, 3, 4) + c.clamp_ip(r) + self.assertEqual(c.topleft, r.topleft) + c = Rect(5, 500, 22, 33) + c.clamp_ip(r) + self.assertEqual(c.center, r.center) + + def test_clip(self): + r1 = Rect(1, 2, 3, 4) + self.assertEqual(Rect(1, 2, 2, 2), r1.clip(Rect(0, 0, 3, 4))) + self.assertEqual(Rect(2, 2, 2, 4), r1.clip(Rect(2, 2, 10, 20))) + self.assertEqual(Rect(2, 3, 1, 2), r1.clip(Rect(2, 3, 1, 2))) + self.assertEqual((0, 0), r1.clip(20, 30, 5, 6).size) + self.assertEqual( + r1, r1.clip(Rect(r1)), "r1 does not clip an identical rect to itself" + ) + + def test_clipline(self): + """Ensures clipline handles four int parameters. + + Tests the clipline(x1, y1, x2, y2) format. + """ + rect = Rect((1, 2), (35, 40)) + x1 = 5 + y1 = 6 + x2 = 11 + y2 = 19 + expected_line = ((x1, y1), (x2, y2)) + + clipped_line = rect.clipline(x1, y1, x2, y2) + + self.assertIsInstance(clipped_line, tuple) + self.assertTupleEqual(clipped_line, expected_line) + + def test_clipline__two_sequences(self): + """Ensures clipline handles a sequence of two sequences. + + Tests the clipline((x1, y1), (x2, y2)) format. + Tests the sequences as different types. + """ + rect = Rect((1, 2), (35, 40)) + pt1 = (5, 6) + pt2 = (11, 19) + + INNER_SEQUENCES = (list, tuple, Vector2) + expected_line = (pt1, pt2) + + for inner_seq1 in INNER_SEQUENCES: + endpt1 = inner_seq1(pt1) + + for inner_seq2 in INNER_SEQUENCES: + clipped_line = rect.clipline((endpt1, inner_seq2(pt2))) + + self.assertIsInstance(clipped_line, tuple) + self.assertTupleEqual(clipped_line, expected_line) + + def test_clipline__sequence_of_four_ints(self): + """Ensures clipline handles a sequence of four ints. + + Tests the clipline((x1, y1, x2, y2)) format. + Tests the sequence as different types. + """ + rect = Rect((1, 2), (35, 40)) + line = (5, 6, 11, 19) + expected_line = ((line[0], line[1]), (line[2], line[3])) + + for outer_seq in (list, tuple): + clipped_line = rect.clipline(outer_seq(line)) + + self.assertIsInstance(clipped_line, tuple) + self.assertTupleEqual(clipped_line, expected_line) + + def test_clipline__sequence_of_two_sequences(self): + """Ensures clipline handles a sequence of two sequences. + + Tests the clipline(((x1, y1), (x2, y2))) format. + Tests the sequences as different types. + """ + rect = Rect((1, 2), (35, 40)) + pt1 = (5, 6) + pt2 = (11, 19) + + INNER_SEQUENCES = (list, tuple, Vector2) + expected_line = (pt1, pt2) + + for inner_seq1 in INNER_SEQUENCES: + endpt1 = inner_seq1(pt1) + + for inner_seq2 in INNER_SEQUENCES: + endpt2 = inner_seq2(pt2) + + for outer_seq in (list, tuple): + clipped_line = rect.clipline(outer_seq((endpt1, endpt2))) + + self.assertIsInstance(clipped_line, tuple) + self.assertTupleEqual(clipped_line, expected_line) + + def test_clipline__floats(self): + """Ensures clipline handles float parameters.""" + rect = Rect((1, 2), (35, 40)) + x1 = 5.9 + y1 = 6.9 + x2 = 11.9 + y2 = 19.9 + + # Floats are truncated. + expected_line = ( + (math.floor(x1), math.floor(y1)), + (math.floor(x2), math.floor(y2)), + ) + + clipped_line = rect.clipline(x1, y1, x2, y2) + + self.assertIsInstance(clipped_line, tuple) + self.assertTupleEqual(clipped_line, expected_line) + + def test_clipline__no_overlap(self): + """Ensures lines that do not overlap the rect are not clipped.""" + rect = Rect((10, 25), (15, 20)) + # Use a bigger rect to help create test lines. + big_rect = rect.inflate(2, 2) + lines = ( + (big_rect.bottomleft, big_rect.topleft), # Left edge. + (big_rect.topleft, big_rect.topright), # Top edge. + (big_rect.topright, big_rect.bottomright), # Right edge. + (big_rect.bottomright, big_rect.bottomleft), + ) # Bottom edge. + expected_line = () + + # Test lines outside rect. + for line in lines: + clipped_line = rect.clipline(line) + + self.assertTupleEqual(clipped_line, expected_line) + + def test_clipline__both_endpoints_outside(self): + """Ensures lines that overlap the rect are clipped. + + Testing lines with both endpoints outside the rect. + """ + rect = Rect((0, 0), (20, 20)) + # Use a bigger rect to help create test lines. + big_rect = rect.inflate(2, 2) + + # Create a dict of lines and expected results. + line_dict = { + (big_rect.midleft, big_rect.midright): ( + rect.midleft, + (rect.midright[0] - 1, rect.midright[1]), + ), + (big_rect.midtop, big_rect.midbottom): ( + rect.midtop, + (rect.midbottom[0], rect.midbottom[1] - 1), + ), + # Diagonals. + (big_rect.topleft, big_rect.bottomright): ( + rect.topleft, + (rect.bottomright[0] - 1, rect.bottomright[1] - 1), + ), + # This line needs a small adjustment to make sure it intersects + # the rect correctly. + ( + (big_rect.topright[0] - 1, big_rect.topright[1]), + (big_rect.bottomleft[0], big_rect.bottomleft[1] - 1), + ): ( + (rect.topright[0] - 1, rect.topright[1]), + (rect.bottomleft[0], rect.bottomleft[1] - 1), + ), + } + + for line, expected_line in line_dict.items(): + clipped_line = rect.clipline(line) + + self.assertTupleEqual(clipped_line, expected_line) + + # Swap endpoints to test for symmetry. + expected_line = (expected_line[1], expected_line[0]) + + clipped_line = rect.clipline((line[1], line[0])) + + self.assertTupleEqual(clipped_line, expected_line) + + def test_clipline__both_endpoints_inside(self): + """Ensures lines that overlap the rect are clipped. + + Testing lines with both endpoints inside the rect. + """ + rect = Rect((-10, -5), (20, 20)) + # Use a smaller rect to help create test lines. + small_rect = rect.inflate(-2, -2) + + lines = ( + (small_rect.midleft, small_rect.midright), + (small_rect.midtop, small_rect.midbottom), + # Diagonals. + (small_rect.topleft, small_rect.bottomright), + (small_rect.topright, small_rect.bottomleft), + ) + + for line in lines: + expected_line = line + + clipped_line = rect.clipline(line) + + self.assertTupleEqual(clipped_line, expected_line) + + # Swap endpoints to test for symmetry. + expected_line = (expected_line[1], expected_line[0]) + + clipped_line = rect.clipline((line[1], line[0])) + + self.assertTupleEqual(clipped_line, expected_line) + + def test_clipline__endpoints_inside_and_outside(self): + """Ensures lines that overlap the rect are clipped. + + Testing lines with one endpoint outside the rect and the other is + inside the rect. + """ + rect = Rect((0, 0), (21, 21)) + # Use a bigger rect to help create test lines. + big_rect = rect.inflate(2, 2) + + # Create a dict of lines and expected results. + line_dict = { + (big_rect.midleft, rect.center): (rect.midleft, rect.center), + (big_rect.midtop, rect.center): (rect.midtop, rect.center), + (big_rect.midright, rect.center): ( + (rect.midright[0] - 1, rect.midright[1]), + rect.center, + ), + (big_rect.midbottom, rect.center): ( + (rect.midbottom[0], rect.midbottom[1] - 1), + rect.center, + ), + # Diagonals. + (big_rect.topleft, rect.center): (rect.topleft, rect.center), + (big_rect.topright, rect.center): ( + (rect.topright[0] - 1, rect.topright[1]), + rect.center, + ), + (big_rect.bottomright, rect.center): ( + (rect.bottomright[0] - 1, rect.bottomright[1] - 1), + rect.center, + ), + # This line needs a small adjustment to make sure it intersects + # the rect correctly. + ((big_rect.bottomleft[0], big_rect.bottomleft[1] - 1), rect.center): ( + (rect.bottomleft[0], rect.bottomleft[1] - 1), + rect.center, + ), + } + + for line, expected_line in line_dict.items(): + clipped_line = rect.clipline(line) + + self.assertTupleEqual(clipped_line, expected_line) + + # Swap endpoints to test for symmetry. + expected_line = (expected_line[1], expected_line[0]) + + clipped_line = rect.clipline((line[1], line[0])) + + self.assertTupleEqual(clipped_line, expected_line) + + def test_clipline__edges(self): + """Ensures clipline properly clips line that are along the rect edges.""" + rect = Rect((10, 25), (15, 20)) + + # Create a dict of edges and expected results. + edge_dict = { + # Left edge. + (rect.bottomleft, rect.topleft): ( + (rect.bottomleft[0], rect.bottomleft[1] - 1), + rect.topleft, + ), + # Top edge. + (rect.topleft, rect.topright): ( + rect.topleft, + (rect.topright[0] - 1, rect.topright[1]), + ), + # Right edge. + (rect.topright, rect.bottomright): (), + # Bottom edge. + (rect.bottomright, rect.bottomleft): (), + } + + for edge, expected_line in edge_dict.items(): + clipped_line = rect.clipline(edge) + + self.assertTupleEqual(clipped_line, expected_line) + + # Swap endpoints to test for symmetry. + if expected_line: + expected_line = (expected_line[1], expected_line[0]) + + clipped_line = rect.clipline((edge[1], edge[0])) + + self.assertTupleEqual(clipped_line, expected_line) + + def test_clipline__equal_endpoints_with_overlap(self): + """Ensures clipline handles lines with both endpoints the same. + + Testing lines that overlap the rect. + """ + rect = Rect((10, 25), (15, 20)) + + # Test all the points in and on a rect. + pts = ( + (x, y) + for x in range(rect.left, rect.right) + for y in range(rect.top, rect.bottom) + ) + + for pt in pts: + expected_line = (pt, pt) + + clipped_line = rect.clipline((pt, pt)) + + self.assertTupleEqual(clipped_line, expected_line) + + def test_clipline__equal_endpoints_no_overlap(self): + """Ensures clipline handles lines with both endpoints the same. + + Testing lines that do not overlap the rect. + """ + expected_line = () + rect = Rect((10, 25), (15, 20)) + + # Test points outside rect. + for pt in test_utils.rect_perimeter_pts(rect.inflate(2, 2)): + clipped_line = rect.clipline((pt, pt)) + + self.assertTupleEqual(clipped_line, expected_line) + + def test_clipline__zero_size_rect(self): + """Ensures clipline handles zero sized rects correctly.""" + expected_line = () + + for size in ((0, 15), (15, 0), (0, 0)): + rect = Rect((10, 25), size) + + clipped_line = rect.clipline(rect.topleft, rect.topleft) + + self.assertTupleEqual(clipped_line, expected_line) + + def test_clipline__negative_size_rect(self): + """Ensures clipline handles negative sized rects correctly.""" + expected_line = () + + for size in ((-15, 20), (15, -20), (-15, -20)): + rect = Rect((10, 25), size) + norm_rect = rect.copy() + norm_rect.normalize() + # Use a bigger rect to help create test lines. + big_rect = norm_rect.inflate(2, 2) + + # Create a dict of lines and expected results. Some line have both + # endpoints outside the rect and some have one inside and one + # outside. + line_dict = { + (big_rect.midleft, big_rect.midright): ( + norm_rect.midleft, + (norm_rect.midright[0] - 1, norm_rect.midright[1]), + ), + (big_rect.midtop, big_rect.midbottom): ( + norm_rect.midtop, + (norm_rect.midbottom[0], norm_rect.midbottom[1] - 1), + ), + (big_rect.midleft, norm_rect.center): ( + norm_rect.midleft, + norm_rect.center, + ), + (big_rect.midtop, norm_rect.center): ( + norm_rect.midtop, + norm_rect.center, + ), + (big_rect.midright, norm_rect.center): ( + (norm_rect.midright[0] - 1, norm_rect.midright[1]), + norm_rect.center, + ), + (big_rect.midbottom, norm_rect.center): ( + (norm_rect.midbottom[0], norm_rect.midbottom[1] - 1), + norm_rect.center, + ), + } + + for line, expected_line in line_dict.items(): + clipped_line = rect.clipline(line) + + # Make sure rect wasn't normalized. + self.assertNotEqual(rect, norm_rect) + self.assertTupleEqual(clipped_line, expected_line) + + # Swap endpoints to test for symmetry. + expected_line = (expected_line[1], expected_line[0]) + + clipped_line = rect.clipline((line[1], line[0])) + + self.assertTupleEqual(clipped_line, expected_line) + + def test_clipline__invalid_line(self): + """Ensures clipline handles invalid lines correctly.""" + rect = Rect((0, 0), (10, 20)) + invalid_lines = ( + (), + (1,), + (1, 2), + (1, 2, 3), + (1, 2, 3, 4, 5), + ((1, 2),), + ((1, 2), (3,)), + ((1, 2), 3), + ((1, 2, 5), (3, 4)), + ((1, 2), (3, 4, 5)), + ((1, 2), (3, 4), (5, 6)), + ) + + for line in invalid_lines: + with self.assertRaises(TypeError): + clipped_line = rect.clipline(line) + + with self.assertRaises(TypeError): + clipped_line = rect.clipline(*line) + + @unittest.skipIf(IS_PYPY, "fails on pypy sometimes") + def test_move(self): + r = Rect(1, 2, 3, 4) + move_x = 10 + move_y = 20 + r2 = r.move(move_x, move_y) + expected_r2 = Rect(r.left + move_x, r.top + move_y, r.width, r.height) + self.assertEqual(expected_r2, r2) + + @unittest.skipIf(IS_PYPY, "fails on pypy sometimes") + def test_move_ip(self): + r = Rect(1, 2, 3, 4) + r2 = Rect(r) + move_x = 10 + move_y = 20 + r2.move_ip(move_x, move_y) + expected_r2 = Rect(r.left + move_x, r.top + move_y, r.width, r.height) + self.assertEqual(expected_r2, r2) + + def test_update_XYWidthHeight(self): + """Test update with 4 int values(x, y, w, h)""" + rect = Rect(0, 0, 1, 1) + rect.update(1, 2, 3, 4) + + self.assertEqual(1, rect.left) + self.assertEqual(2, rect.top) + self.assertEqual(3, rect.width) + self.assertEqual(4, rect.height) + + def test_update__TopLeftSize(self): + """Test update with 2 tuples((x, y), (w, h))""" + rect = Rect(0, 0, 1, 1) + rect.update((1, 2), (3, 4)) + + self.assertEqual(1, rect.left) + self.assertEqual(2, rect.top) + self.assertEqual(3, rect.width) + self.assertEqual(4, rect.height) + + def test_update__List(self): + """Test update with list""" + rect = Rect(0, 0, 1, 1) + rect2 = [1, 2, 3, 4] + rect.update(rect2) + + self.assertEqual(1, rect.left) + self.assertEqual(2, rect.top) + self.assertEqual(3, rect.width) + self.assertEqual(4, rect.height) + + def test_update__RectObject(self): + """Test update with other rect object""" + rect = Rect(0, 0, 1, 1) + rect2 = Rect(1, 2, 3, 4) + rect.update(rect2) + + self.assertEqual(1, rect.left) + self.assertEqual(2, rect.top) + self.assertEqual(3, rect.width) + self.assertEqual(4, rect.height) + + def test_union(self): + r1 = Rect(1, 1, 1, 2) + r2 = Rect(-2, -2, 1, 2) + self.assertEqual(Rect(-2, -2, 4, 5), r1.union(r2)) + + def test_union__with_identical_Rect(self): + r1 = Rect(1, 2, 3, 4) + self.assertEqual(r1, r1.union(Rect(r1))) + + def test_union_ip(self): + r1 = Rect(1, 1, 1, 2) + r2 = Rect(-2, -2, 1, 2) + r1.union_ip(r2) + self.assertEqual(Rect(-2, -2, 4, 5), r1) + + def test_unionall(self): + r1 = Rect(0, 0, 1, 1) + r2 = Rect(-2, -2, 1, 1) + r3 = Rect(2, 2, 1, 1) + + r4 = r1.unionall([r2, r3]) + self.assertEqual(Rect(-2, -2, 5, 5), r4) + + def test_unionall__invalid_rect_format(self): + """Ensures unionall correctly handles invalid rect parameters.""" + numbers = [0, 1.2, 2, 3.3] + strs = ["a", "b", "c"] + nones = [None, None] + + for invalid_rects in (numbers, strs, nones): + with self.assertRaises(TypeError): + Rect(0, 0, 1, 1).unionall(invalid_rects) + + def test_unionall_ip(self): + r1 = Rect(0, 0, 1, 1) + r2 = Rect(-2, -2, 1, 1) + r3 = Rect(2, 2, 1, 1) + + r1.unionall_ip([r2, r3]) + self.assertEqual(Rect(-2, -2, 5, 5), r1) + + # Bug for an empty list. Would return a Rect instead of None. + self.assertTrue(r1.unionall_ip([]) is None) + + def test_unionall__invalid_rect_format(self): + """Ensures unionall_ip correctly handles invalid rect parameters.""" + numbers = [0, 1.2, 2, 3.3] + strs = ["a", "b", "c"] + nones = [None, None] + + for invalid_rects in (numbers, strs, nones): + with self.assertRaises(TypeError): + Rect(0, 0, 1, 1).unionall_ip(invalid_rects) + + def test_colliderect(self): + r1 = Rect(1, 2, 3, 4) + self.assertTrue( + r1.colliderect(Rect(0, 0, 2, 3)), + "r1 does not collide with Rect(0, 0, 2, 3)", + ) + self.assertFalse( + r1.colliderect(Rect(0, 0, 1, 2)), "r1 collides with Rect(0, 0, 1, 2)" + ) + self.assertFalse( + r1.colliderect(Rect(r1.right, r1.bottom, 2, 2)), + "r1 collides with Rect(r1.right, r1.bottom, 2, 2)", + ) + self.assertTrue( + r1.colliderect(Rect(r1.left + 1, r1.top + 1, r1.width - 2, r1.height - 2)), + "r1 does not collide with Rect(r1.left + 1, r1.top + 1, " + + "r1.width - 2, r1.height - 2)", + ) + self.assertTrue( + r1.colliderect(Rect(r1.left - 1, r1.top - 1, r1.width + 2, r1.height + 2)), + "r1 does not collide with Rect(r1.left - 1, r1.top - 1, " + + "r1.width + 2, r1.height + 2)", + ) + self.assertTrue( + r1.colliderect(Rect(r1)), "r1 does not collide with an identical rect" + ) + self.assertFalse( + r1.colliderect(Rect(r1.right, r1.bottom, 0, 0)), + "r1 collides with Rect(r1.right, r1.bottom, 0, 0)", + ) + self.assertFalse( + r1.colliderect(Rect(r1.right, r1.bottom, 1, 1)), + "r1 collides with Rect(r1.right, r1.bottom, 1, 1)", + ) + + @unittest.skipIf(IS_PYPY, "fails on pypy3 sometimes") + def testEquals(self): + """check to see how the rect uses __eq__""" + r1 = Rect(1, 2, 3, 4) + r2 = Rect(10, 20, 30, 40) + r3 = (10, 20, 30, 40) + r4 = Rect(10, 20, 30, 40) + + class foo(Rect): + def __eq__(self, other): + return id(self) == id(other) + + def __ne__(self, other): + return id(self) != id(other) + + class foo2(Rect): + pass + + r5 = foo(10, 20, 30, 40) + r6 = foo2(10, 20, 30, 40) + + self.assertNotEqual(r5, r2) + + # because we define equality differently for this subclass. + self.assertEqual(r6, r2) + + rect_list = [r1, r2, r3, r4, r6] + + # see if we can remove 4 of these. + rect_list.remove(r2) + rect_list.remove(r2) + rect_list.remove(r2) + rect_list.remove(r2) + self.assertRaises(ValueError, rect_list.remove, r2) + + def test_collidedict(self): + """Ensures collidedict detects collisions.""" + rect = Rect(1, 1, 10, 10) + + collide_item1 = ("collide 1", rect.copy()) + collide_item2 = ("collide 2", Rect(5, 5, 10, 10)) + no_collide_item1 = ("no collide 1", Rect(60, 60, 10, 10)) + no_collide_item2 = ("no collide 2", Rect(70, 70, 10, 10)) + + # Dict to check collisions with values. + rect_values = dict( + (collide_item1, collide_item2, no_collide_item1, no_collide_item2) + ) + value_collide_items = (collide_item1, collide_item2) + + # Dict to check collisions with keys. + rect_keys = {tuple(v): k for k, v in rect_values.items()} + key_collide_items = tuple((tuple(v), k) for k, v in value_collide_items) + + for use_values in (True, False): + if use_values: + expected_items = value_collide_items + d = rect_values + else: + expected_items = key_collide_items + d = rect_keys + + collide_item = rect.collidedict(d, use_values) + + # The detected collision could be any of the possible items. + self.assertIn(collide_item, expected_items) + + def test_collidedict__no_collision(self): + """Ensures collidedict returns None when no collisions.""" + rect = Rect(1, 1, 10, 10) + + no_collide_item1 = ("no collide 1", Rect(50, 50, 10, 10)) + no_collide_item2 = ("no collide 2", Rect(60, 60, 10, 10)) + no_collide_item3 = ("no collide 3", Rect(70, 70, 10, 10)) + + # Dict to check collisions with values. + rect_values = dict((no_collide_item1, no_collide_item2, no_collide_item3)) + + # Dict to check collisions with keys. + rect_keys = {tuple(v): k for k, v in rect_values.items()} + + for use_values in (True, False): + d = rect_values if use_values else rect_keys + + collide_item = rect.collidedict(d, use_values) + + self.assertIsNone(collide_item) + + def test_collidedict__barely_touching(self): + """Ensures collidedict works correctly for rects that barely touch.""" + rect = Rect(1, 1, 10, 10) + # Small rect to test barely touching collisions. + collide_rect = Rect(0, 0, 1, 1) + + collide_item1 = ("collide 1", collide_rect) + no_collide_item1 = ("no collide 1", Rect(50, 50, 10, 10)) + no_collide_item2 = ("no collide 2", Rect(60, 60, 10, 10)) + no_collide_item3 = ("no collide 3", Rect(70, 70, 10, 10)) + + # Dict to check collisions with values. + no_collide_rect_values = dict( + (no_collide_item1, no_collide_item2, no_collide_item3) + ) + + # Dict to check collisions with keys. + no_collide_rect_keys = {tuple(v): k for k, v in no_collide_rect_values.items()} + + # Tests the collide_rect on each of the rect's corners. + for attr in ("topleft", "topright", "bottomright", "bottomleft"): + setattr(collide_rect, attr, getattr(rect, attr)) + + for use_values in (True, False): + if use_values: + expected_item = collide_item1 + d = dict(no_collide_rect_values) + else: + expected_item = (tuple(collide_item1[1]), collide_item1[0]) + d = dict(no_collide_rect_keys) + + d.update((expected_item,)) # Add in the expected item. + + collide_item = rect.collidedict(d, use_values) + + self.assertTupleEqual(collide_item, expected_item) + + def test_collidedict__zero_sized_rects(self): + """Ensures collidedict works correctly with zero sized rects. + + There should be no collisions with zero sized rects. + """ + zero_rect1 = Rect(1, 1, 0, 0) + zero_rect2 = Rect(1, 1, 1, 0) + zero_rect3 = Rect(1, 1, 0, 1) + zero_rect4 = Rect(1, 1, -1, 0) + zero_rect5 = Rect(1, 1, 0, -1) + + no_collide_item1 = ("no collide 1", zero_rect1.copy()) + no_collide_item2 = ("no collide 2", zero_rect2.copy()) + no_collide_item3 = ("no collide 3", zero_rect3.copy()) + no_collide_item4 = ("no collide 4", zero_rect4.copy()) + no_collide_item5 = ("no collide 5", zero_rect5.copy()) + no_collide_item6 = ("no collide 6", Rect(0, 0, 10, 10)) + no_collide_item7 = ("no collide 7", Rect(0, 0, 2, 2)) + + # Dict to check collisions with values. + rect_values = dict( + ( + no_collide_item1, + no_collide_item2, + no_collide_item3, + no_collide_item4, + no_collide_item5, + no_collide_item6, + no_collide_item7, + ) + ) + + # Dict to check collisions with keys. + rect_keys = {tuple(v): k for k, v in rect_values.items()} + + for use_values in (True, False): + d = rect_values if use_values else rect_keys + + for zero_rect in ( + zero_rect1, + zero_rect2, + zero_rect3, + zero_rect4, + zero_rect5, + ): + collide_item = zero_rect.collidedict(d, use_values) + + self.assertIsNone(collide_item) + + def test_collidedict__zero_sized_rects_as_args(self): + """Ensures collidedict works correctly with zero sized rects as args. + + There should be no collisions with zero sized rects. + """ + rect = Rect(0, 0, 10, 10) + + no_collide_item1 = ("no collide 1", Rect(1, 1, 0, 0)) + no_collide_item2 = ("no collide 2", Rect(1, 1, 1, 0)) + no_collide_item3 = ("no collide 3", Rect(1, 1, 0, 1)) + + # Dict to check collisions with values. + rect_values = dict((no_collide_item1, no_collide_item2, no_collide_item3)) + + # Dict to check collisions with keys. + rect_keys = {tuple(v): k for k, v in rect_values.items()} + + for use_values in (True, False): + d = rect_values if use_values else rect_keys + + collide_item = rect.collidedict(d, use_values) + + self.assertIsNone(collide_item) + + def test_collidedict__negative_sized_rects(self): + """Ensures collidedict works correctly with negative sized rects.""" + neg_rect = Rect(1, 1, -1, -1) + + collide_item1 = ("collide 1", neg_rect.copy()) + collide_item2 = ("collide 2", Rect(0, 0, 10, 10)) + no_collide_item1 = ("no collide 1", Rect(1, 1, 10, 10)) + + # Dict to check collisions with values. + rect_values = dict((collide_item1, collide_item2, no_collide_item1)) + value_collide_items = (collide_item1, collide_item2) + + # Dict to check collisions with keys. + rect_keys = {tuple(v): k for k, v in rect_values.items()} + key_collide_items = tuple((tuple(v), k) for k, v in value_collide_items) + + for use_values in (True, False): + if use_values: + collide_items = value_collide_items + d = rect_values + else: + collide_items = key_collide_items + d = rect_keys + + collide_item = neg_rect.collidedict(d, use_values) + + # The detected collision could be any of the possible items. + self.assertIn(collide_item, collide_items) + + def test_collidedict__negative_sized_rects_as_args(self): + """Ensures collidedict works correctly with negative sized rect args.""" + rect = Rect(0, 0, 10, 10) + + collide_item1 = ("collide 1", Rect(1, 1, -1, -1)) + no_collide_item1 = ("no collide 1", Rect(1, 1, -1, 0)) + no_collide_item2 = ("no collide 2", Rect(1, 1, 0, -1)) + + # Dict to check collisions with values. + rect_values = dict((collide_item1, no_collide_item1, no_collide_item2)) + + # Dict to check collisions with keys. + rect_keys = {tuple(v): k for k, v in rect_values.items()} + + for use_values in (True, False): + if use_values: + expected_item = collide_item1 + d = rect_values + else: + expected_item = (tuple(collide_item1[1]), collide_item1[0]) + d = rect_keys + + collide_item = rect.collidedict(d, use_values) + + self.assertTupleEqual(collide_item, expected_item) + + def test_collidedict__invalid_dict_format(self): + """Ensures collidedict correctly handles invalid dict parameters.""" + rect = Rect(0, 0, 10, 10) + + invalid_value_dict = ("collide", rect.copy()) + invalid_key_dict = tuple(invalid_value_dict[1]), invalid_value_dict[0] + + for use_values in (True, False): + d = invalid_value_dict if use_values else invalid_key_dict + + with self.assertRaises(TypeError): + collide_item = rect.collidedict(d, use_values) + + def test_collidedict__invalid_dict_value_format(self): + """Ensures collidedict correctly handles dicts with invalid values.""" + rect = Rect(0, 0, 10, 10) + rect_keys = {tuple(rect): "collide"} + + with self.assertRaises(TypeError): + collide_item = rect.collidedict(rect_keys, 1) + + def test_collidedict__invalid_dict_key_format(self): + """Ensures collidedict correctly handles dicts with invalid keys.""" + rect = Rect(0, 0, 10, 10) + rect_values = {"collide": rect.copy()} + + with self.assertRaises(TypeError): + collide_item = rect.collidedict(rect_values) + + def test_collidedict__invalid_use_values_format(self): + """Ensures collidedict correctly handles invalid use_values parameters.""" + rect = Rect(0, 0, 1, 1) + d = {} + + for invalid_param in (None, d, 1.1): + with self.assertRaises(TypeError): + collide_item = rect.collidedict(d, invalid_param) + + def test_collidedictall(self): + """Ensures collidedictall detects collisions.""" + rect = Rect(1, 1, 10, 10) + + collide_item1 = ("collide 1", rect.copy()) + collide_item2 = ("collide 2", Rect(5, 5, 10, 10)) + no_collide_item1 = ("no collide 1", Rect(60, 60, 20, 20)) + no_collide_item2 = ("no collide 2", Rect(70, 70, 20, 20)) + + # Dict to check collisions with values. + rect_values = dict( + (collide_item1, collide_item2, no_collide_item1, no_collide_item2) + ) + value_collide_items = [collide_item1, collide_item2] + + # Dict to check collisions with keys. + rect_keys = {tuple(v): k for k, v in rect_values.items()} + key_collide_items = [(tuple(v), k) for k, v in value_collide_items] + + for use_values in (True, False): + if use_values: + expected_items = value_collide_items + d = rect_values + else: + expected_items = key_collide_items + d = rect_keys + + collide_items = rect.collidedictall(d, use_values) + + self._assertCountEqual(collide_items, expected_items) + + def test_collidedictall__no_collision(self): + """Ensures collidedictall returns an empty list when no collisions.""" + rect = Rect(1, 1, 10, 10) + + no_collide_item1 = ("no collide 1", Rect(50, 50, 20, 20)) + no_collide_item2 = ("no collide 2", Rect(60, 60, 20, 20)) + no_collide_item3 = ("no collide 3", Rect(70, 70, 20, 20)) + + # Dict to check collisions with values. + rect_values = dict((no_collide_item1, no_collide_item2, no_collide_item3)) + + # Dict to check collisions with keys. + rect_keys = {tuple(v): k for k, v in rect_values.items()} + + expected_items = [] + + for use_values in (True, False): + d = rect_values if use_values else rect_keys + + collide_items = rect.collidedictall(d, use_values) + + self._assertCountEqual(collide_items, expected_items) + + def test_collidedictall__barely_touching(self): + """Ensures collidedictall works correctly for rects that barely touch.""" + rect = Rect(1, 1, 10, 10) + # Small rect to test barely touching collisions. + collide_rect = Rect(0, 0, 1, 1) + + collide_item1 = ("collide 1", collide_rect) + no_collide_item1 = ("no collide 1", Rect(50, 50, 20, 20)) + no_collide_item2 = ("no collide 2", Rect(60, 60, 20, 20)) + no_collide_item3 = ("no collide 3", Rect(70, 70, 20, 20)) + + # Dict to check collisions with values. + no_collide_rect_values = dict( + (no_collide_item1, no_collide_item2, no_collide_item3) + ) + + # Dict to check collisions with keys. + no_collide_rect_keys = {tuple(v): k for k, v in no_collide_rect_values.items()} + + # Tests the collide_rect on each of the rect's corners. + for attr in ("topleft", "topright", "bottomright", "bottomleft"): + setattr(collide_rect, attr, getattr(rect, attr)) + + for use_values in (True, False): + if use_values: + expected_items = [collide_item1] + d = dict(no_collide_rect_values) + else: + expected_items = [(tuple(collide_item1[1]), collide_item1[0])] + d = dict(no_collide_rect_keys) + + d.update(expected_items) # Add in the expected items. + + collide_items = rect.collidedictall(d, use_values) + + self._assertCountEqual(collide_items, expected_items) + + def test_collidedictall__zero_sized_rects(self): + """Ensures collidedictall works correctly with zero sized rects. + + There should be no collisions with zero sized rects. + """ + zero_rect1 = Rect(2, 2, 0, 0) + zero_rect2 = Rect(2, 2, 2, 0) + zero_rect3 = Rect(2, 2, 0, 2) + zero_rect4 = Rect(2, 2, -2, 0) + zero_rect5 = Rect(2, 2, 0, -2) + + no_collide_item1 = ("no collide 1", zero_rect1.copy()) + no_collide_item2 = ("no collide 2", zero_rect2.copy()) + no_collide_item3 = ("no collide 3", zero_rect3.copy()) + no_collide_item4 = ("no collide 4", zero_rect4.copy()) + no_collide_item5 = ("no collide 5", zero_rect5.copy()) + no_collide_item6 = ("no collide 6", Rect(0, 0, 10, 10)) + no_collide_item7 = ("no collide 7", Rect(0, 0, 2, 2)) + + # Dict to check collisions with values. + rect_values = dict( + ( + no_collide_item1, + no_collide_item2, + no_collide_item3, + no_collide_item4, + no_collide_item5, + no_collide_item6, + no_collide_item7, + ) + ) + + # Dict to check collisions with keys. + rect_keys = {tuple(v): k for k, v in rect_values.items()} + + expected_items = [] + + for use_values in (True, False): + d = rect_values if use_values else rect_keys + + for zero_rect in ( + zero_rect1, + zero_rect2, + zero_rect3, + zero_rect4, + zero_rect5, + ): + collide_items = zero_rect.collidedictall(d, use_values) + + self._assertCountEqual(collide_items, expected_items) + + def test_collidedictall__zero_sized_rects_as_args(self): + """Ensures collidedictall works correctly with zero sized rects + as args. + + There should be no collisions with zero sized rects. + """ + rect = Rect(0, 0, 20, 20) + + no_collide_item1 = ("no collide 1", Rect(2, 2, 0, 0)) + no_collide_item2 = ("no collide 2", Rect(2, 2, 2, 0)) + no_collide_item3 = ("no collide 3", Rect(2, 2, 0, 2)) + + # Dict to check collisions with values. + rect_values = dict((no_collide_item1, no_collide_item2, no_collide_item3)) + + # Dict to check collisions with keys. + rect_keys = {tuple(v): k for k, v in rect_values.items()} + + expected_items = [] + + for use_values in (True, False): + d = rect_values if use_values else rect_keys + + collide_items = rect.collidedictall(d, use_values) + + self._assertCountEqual(collide_items, expected_items) + + def test_collidedictall__negative_sized_rects(self): + """Ensures collidedictall works correctly with negative sized rects.""" + neg_rect = Rect(2, 2, -2, -2) + + collide_item1 = ("collide 1", neg_rect.copy()) + collide_item2 = ("collide 2", Rect(0, 0, 20, 20)) + no_collide_item1 = ("no collide 1", Rect(2, 2, 20, 20)) + + # Dict to check collisions with values. + rect_values = dict((collide_item1, collide_item2, no_collide_item1)) + value_collide_items = [collide_item1, collide_item2] + + # Dict to check collisions with keys. + rect_keys = {tuple(v): k for k, v in rect_values.items()} + key_collide_items = [(tuple(v), k) for k, v in value_collide_items] + + for use_values in (True, False): + if use_values: + expected_items = value_collide_items + d = rect_values + else: + expected_items = key_collide_items + d = rect_keys + + collide_items = neg_rect.collidedictall(d, use_values) + + self._assertCountEqual(collide_items, expected_items) + + def test_collidedictall__negative_sized_rects_as_args(self): + """Ensures collidedictall works correctly with negative sized rect + args. + """ + rect = Rect(0, 0, 10, 10) + + collide_item1 = ("collide 1", Rect(1, 1, -1, -1)) + no_collide_item1 = ("no collide 1", Rect(1, 1, -1, 0)) + no_collide_item2 = ("no collide 2", Rect(1, 1, 0, -1)) + + # Dict to check collisions with values. + rect_values = dict((collide_item1, no_collide_item1, no_collide_item2)) + value_collide_items = [collide_item1] + + # Dict to check collisions with keys. + rect_keys = {tuple(v): k for k, v in rect_values.items()} + key_collide_items = [(tuple(v), k) for k, v in value_collide_items] + + for use_values in (True, False): + if use_values: + expected_items = value_collide_items + d = rect_values + else: + expected_items = key_collide_items + d = rect_keys + + collide_items = rect.collidedictall(d, use_values) + + self._assertCountEqual(collide_items, expected_items) + + def test_collidedictall__invalid_dict_format(self): + """Ensures collidedictall correctly handles invalid dict parameters.""" + rect = Rect(0, 0, 10, 10) + + invalid_value_dict = ("collide", rect.copy()) + invalid_key_dict = tuple(invalid_value_dict[1]), invalid_value_dict[0] + + for use_values in (True, False): + d = invalid_value_dict if use_values else invalid_key_dict + + with self.assertRaises(TypeError): + collide_item = rect.collidedictall(d, use_values) + + def test_collidedictall__invalid_dict_value_format(self): + """Ensures collidedictall correctly handles dicts with invalid values.""" + rect = Rect(0, 0, 10, 10) + rect_keys = {tuple(rect): "collide"} + + with self.assertRaises(TypeError): + collide_items = rect.collidedictall(rect_keys, 1) + + def test_collidedictall__invalid_dict_key_format(self): + """Ensures collidedictall correctly handles dicts with invalid keys.""" + rect = Rect(0, 0, 10, 10) + rect_values = {"collide": rect.copy()} + + with self.assertRaises(TypeError): + collide_items = rect.collidedictall(rect_values) + + def test_collidedictall__invalid_use_values_format(self): + """Ensures collidedictall correctly handles invalid use_values + parameters. + """ + rect = Rect(0, 0, 1, 1) + d = {} + + for invalid_param in (None, d, 1.1): + with self.assertRaises(TypeError): + collide_items = rect.collidedictall(d, invalid_param) + + def test_collidelist(self): + + # __doc__ (as of 2008-08-02) for pygame.rect.Rect.collidelist: + + # Rect.collidelist(list): return index + # test if one rectangle in a list intersects + # + # Test whether the rectangle collides with any in a sequence of + # rectangles. The index of the first collision found is returned. If + # no collisions are found an index of -1 is returned. + + r = Rect(1, 1, 10, 10) + l = [Rect(50, 50, 1, 1), Rect(5, 5, 10, 10), Rect(15, 15, 1, 1)] + + self.assertEqual(r.collidelist(l), 1) + + f = [Rect(50, 50, 1, 1), (100, 100, 4, 4)] + self.assertEqual(r.collidelist(f), -1) + + def test_collidelistall(self): + + # __doc__ (as of 2008-08-02) for pygame.rect.Rect.collidelistall: + + # Rect.collidelistall(list): return indices + # test if all rectangles in a list intersect + # + # Returns a list of all the indices that contain rectangles that + # collide with the Rect. If no intersecting rectangles are found, an + # empty list is returned. + + r = Rect(1, 1, 10, 10) + + l = [ + Rect(1, 1, 10, 10), + Rect(5, 5, 10, 10), + Rect(15, 15, 1, 1), + Rect(2, 2, 1, 1), + ] + self.assertEqual(r.collidelistall(l), [0, 1, 3]) + + f = [Rect(50, 50, 1, 1), Rect(20, 20, 5, 5)] + self.assertFalse(r.collidelistall(f)) + + def test_fit(self): + + # __doc__ (as of 2008-08-02) for pygame.rect.Rect.fit: + + # Rect.fit(Rect): return Rect + # resize and move a rectangle with aspect ratio + # + # Returns a new rectangle that is moved and resized to fit another. + # The aspect ratio of the original Rect is preserved, so the new + # rectangle may be smaller than the target in either width or height. + + r = Rect(10, 10, 30, 30) + + r2 = Rect(30, 30, 15, 10) + + f = r.fit(r2) + self.assertTrue(r2.contains(f)) + + f2 = r2.fit(r) + self.assertTrue(r.contains(f2)) + + def test_copy(self): + r = Rect(1, 2, 10, 20) + c = r.copy() + self.assertEqual(c, r) + + def test_subscript(self): + r = Rect(1, 2, 3, 4) + self.assertEqual(r[0], 1) + self.assertEqual(r[1], 2) + self.assertEqual(r[2], 3) + self.assertEqual(r[3], 4) + self.assertEqual(r[-1], 4) + self.assertEqual(r[-2], 3) + self.assertEqual(r[-4], 1) + self.assertRaises(IndexError, r.__getitem__, 5) + self.assertRaises(IndexError, r.__getitem__, -5) + self.assertEqual(r[0:2], [1, 2]) + self.assertEqual(r[0:4], [1, 2, 3, 4]) + self.assertEqual(r[0:-1], [1, 2, 3]) + self.assertEqual(r[:], [1, 2, 3, 4]) + self.assertEqual(r[...], [1, 2, 3, 4]) + self.assertEqual(r[0:4:2], [1, 3]) + self.assertEqual(r[0:4:3], [1, 4]) + self.assertEqual(r[3::-1], [4, 3, 2, 1]) + self.assertRaises(TypeError, r.__getitem__, None) + + def test_ass_subscript(self): + r = Rect(0, 0, 0, 0) + r[...] = 1, 2, 3, 4 + self.assertEqual(r, [1, 2, 3, 4]) + self.assertRaises(TypeError, r.__setitem__, None, 0) + self.assertEqual(r, [1, 2, 3, 4]) + self.assertRaises(TypeError, r.__setitem__, 0, "") + self.assertEqual(r, [1, 2, 3, 4]) + self.assertRaises(IndexError, r.__setitem__, 4, 0) + self.assertEqual(r, [1, 2, 3, 4]) + self.assertRaises(IndexError, r.__setitem__, -5, 0) + self.assertEqual(r, [1, 2, 3, 4]) + r[0] = 10 + self.assertEqual(r, [10, 2, 3, 4]) + r[3] = 40 + self.assertEqual(r, [10, 2, 3, 40]) + r[-1] = 400 + self.assertEqual(r, [10, 2, 3, 400]) + r[-4] = 100 + self.assertEqual(r, [100, 2, 3, 400]) + r[1:3] = 0 + self.assertEqual(r, [100, 0, 0, 400]) + r[...] = 0 + self.assertEqual(r, [0, 0, 0, 0]) + r[:] = 9 + self.assertEqual(r, [9, 9, 9, 9]) + r[:] = 11, 12, 13, 14 + self.assertEqual(r, [11, 12, 13, 14]) + r[::-1] = r + self.assertEqual(r, [14, 13, 12, 11]) + + +@unittest.skipIf(IS_PYPY, "fails on pypy") +class SubclassTest(unittest.TestCase): + class MyRect(Rect): + def __init__(self, *args, **kwds): + super(SubclassTest.MyRect, self).__init__(*args, **kwds) + self.an_attribute = True + + def test_copy(self): + mr1 = self.MyRect(1, 2, 10, 20) + self.assertTrue(mr1.an_attribute) + mr2 = mr1.copy() + self.assertTrue(isinstance(mr2, self.MyRect)) + self.assertRaises(AttributeError, getattr, mr2, "an_attribute") + + def test_move(self): + mr1 = self.MyRect(1, 2, 10, 20) + self.assertTrue(mr1.an_attribute) + mr2 = mr1.move(1, 2) + self.assertTrue(isinstance(mr2, self.MyRect)) + self.assertRaises(AttributeError, getattr, mr2, "an_attribute") + + def test_inflate(self): + mr1 = self.MyRect(1, 2, 10, 20) + self.assertTrue(mr1.an_attribute) + mr2 = mr1.inflate(2, 4) + self.assertTrue(isinstance(mr2, self.MyRect)) + self.assertRaises(AttributeError, getattr, mr2, "an_attribute") + + def test_clamp(self): + mr1 = self.MyRect(19, 12, 5, 5) + self.assertTrue(mr1.an_attribute) + mr2 = mr1.clamp(Rect(10, 10, 10, 10)) + self.assertTrue(isinstance(mr2, self.MyRect)) + self.assertRaises(AttributeError, getattr, mr2, "an_attribute") + + def test_clip(self): + mr1 = self.MyRect(1, 2, 3, 4) + self.assertTrue(mr1.an_attribute) + mr2 = mr1.clip(Rect(0, 0, 3, 4)) + self.assertTrue(isinstance(mr2, self.MyRect)) + self.assertRaises(AttributeError, getattr, mr2, "an_attribute") + + def test_union(self): + mr1 = self.MyRect(1, 1, 1, 2) + self.assertTrue(mr1.an_attribute) + mr2 = mr1.union(Rect(-2, -2, 1, 2)) + self.assertTrue(isinstance(mr2, self.MyRect)) + self.assertRaises(AttributeError, getattr, mr2, "an_attribute") + + def test_unionall(self): + mr1 = self.MyRect(0, 0, 1, 1) + self.assertTrue(mr1.an_attribute) + mr2 = mr1.unionall([Rect(-2, -2, 1, 1), Rect(2, 2, 1, 1)]) + self.assertTrue(isinstance(mr2, self.MyRect)) + self.assertRaises(AttributeError, getattr, mr2, "an_attribute") + + def test_fit(self): + mr1 = self.MyRect(10, 10, 30, 30) + self.assertTrue(mr1.an_attribute) + mr2 = mr1.fit(Rect(30, 30, 15, 10)) + self.assertTrue(isinstance(mr2, self.MyRect)) + self.assertRaises(AttributeError, getattr, mr2, "an_attribute") + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/__init__.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/__init__.py new file mode 100644 index 0000000..1bb8bf6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/__init__.py @@ -0,0 +1 @@ +# empty diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/__init__.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/__init__.py new file mode 100644 index 0000000..1bb8bf6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/__init__.py @@ -0,0 +1 @@ +# empty diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/fake_2_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/fake_2_test.py new file mode 100644 index 0000000..3be92e1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/fake_2_test.py @@ -0,0 +1,39 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/fake_3_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/fake_3_test.py new file mode 100644 index 0000000..3be92e1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/fake_3_test.py @@ -0,0 +1,39 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/fake_4_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/fake_4_test.py new file mode 100644 index 0000000..3be92e1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/fake_4_test.py @@ -0,0 +1,39 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/fake_5_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/fake_5_test.py new file mode 100644 index 0000000..3be92e1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/fake_5_test.py @@ -0,0 +1,39 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/fake_6_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/fake_6_test.py new file mode 100644 index 0000000..3be92e1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/fake_6_test.py @@ -0,0 +1,39 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/no_assertions__ret_code_of_1__test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/no_assertions__ret_code_of_1__test.py new file mode 100644 index 0000000..0ba0e94 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/no_assertions__ret_code_of_1__test.py @@ -0,0 +1,39 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + pass + + def test_get_mods(self): + pass + + def test_get_pressed(self): + pass + + def test_name(self): + pass + + def test_set_mods(self): + pass + + def test_set_repeat(self): + pass + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/zero_tests_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/zero_tests_test.py new file mode 100644 index 0000000..649055a --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/all_ok/zero_tests_test.py @@ -0,0 +1,23 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + pass + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/everything/__init__.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/everything/__init__.py new file mode 100644 index 0000000..1bb8bf6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/everything/__init__.py @@ -0,0 +1 @@ +# empty diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/everything/fake_2_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/everything/fake_2_test.py new file mode 100644 index 0000000..3be92e1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/everything/fake_2_test.py @@ -0,0 +1,39 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/everything/incomplete_todo_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/everything/incomplete_todo_test.py new file mode 100644 index 0000000..bdd8a3b --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/everything/incomplete_todo_test.py @@ -0,0 +1,39 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def todo_test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def todo_test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/everything/magic_tag_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/everything/magic_tag_test.py new file mode 100644 index 0000000..126bc2b --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/everything/magic_tag_test.py @@ -0,0 +1,38 @@ +__tags__ = ["magic"] + +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/everything/sleep_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/everything/sleep_test.py new file mode 100644 index 0000000..468c75f --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/everything/sleep_test.py @@ -0,0 +1,29 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + +import time + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + stop_time = time.time() + 10.0 + while time.time() < stop_time: + time.sleep(1) + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/exclude/__init__.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/exclude/__init__.py new file mode 100644 index 0000000..1bb8bf6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/exclude/__init__.py @@ -0,0 +1 @@ +# empty diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/exclude/fake_2_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/exclude/fake_2_test.py new file mode 100644 index 0000000..3be92e1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/exclude/fake_2_test.py @@ -0,0 +1,39 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/exclude/invisible_tag_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/exclude/invisible_tag_test.py new file mode 100644 index 0000000..3ef959a --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/exclude/invisible_tag_test.py @@ -0,0 +1,41 @@ +__tags__ = ["invisible"] + +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/exclude/magic_tag_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/exclude/magic_tag_test.py new file mode 100644 index 0000000..126bc2b --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/exclude/magic_tag_test.py @@ -0,0 +1,38 @@ +__tags__ = ["magic"] + +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/failures1/__init__.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/failures1/__init__.py new file mode 100644 index 0000000..1bb8bf6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/failures1/__init__.py @@ -0,0 +1 @@ +# empty diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/failures1/fake_2_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/failures1/fake_2_test.py new file mode 100644 index 0000000..3be92e1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/failures1/fake_2_test.py @@ -0,0 +1,39 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/failures1/fake_3_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/failures1/fake_3_test.py new file mode 100644 index 0000000..3be92e1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/failures1/fake_3_test.py @@ -0,0 +1,39 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/failures1/fake_4_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/failures1/fake_4_test.py new file mode 100644 index 0000000..1e75fea --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/failures1/fake_4_test.py @@ -0,0 +1,41 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(False, "Some Jibberish") + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + if 1: + if 1: + assert False + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/incomplete/__init__.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/incomplete/__init__.py new file mode 100644 index 0000000..1bb8bf6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/incomplete/__init__.py @@ -0,0 +1 @@ +# empty diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/incomplete/fake_2_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/incomplete/fake_2_test.py new file mode 100644 index 0000000..b88f1ae --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/incomplete/fake_2_test.py @@ -0,0 +1,39 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def todo_test_get_pressed(self): + self.fail() + + def test_name(self): + self.assertTrue(True) + + def todo_test_set_mods(self): + self.fail() + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/incomplete/fake_3_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/incomplete/fake_3_test.py new file mode 100644 index 0000000..3be92e1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/incomplete/fake_3_test.py @@ -0,0 +1,39 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/incomplete_todo/__init__.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/incomplete_todo/__init__.py new file mode 100644 index 0000000..1bb8bf6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/incomplete_todo/__init__.py @@ -0,0 +1 @@ +# empty diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/incomplete_todo/fake_2_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/incomplete_todo/fake_2_test.py new file mode 100644 index 0000000..bdd8a3b --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/incomplete_todo/fake_2_test.py @@ -0,0 +1,39 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def todo_test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def todo_test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/incomplete_todo/fake_3_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/incomplete_todo/fake_3_test.py new file mode 100644 index 0000000..3be92e1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/incomplete_todo/fake_3_test.py @@ -0,0 +1,39 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/infinite_loop/__init__.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/infinite_loop/__init__.py new file mode 100644 index 0000000..1bb8bf6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/infinite_loop/__init__.py @@ -0,0 +1 @@ +# empty diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/infinite_loop/fake_1_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/infinite_loop/fake_1_test.py new file mode 100644 index 0000000..3e9e936 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/infinite_loop/fake_1_test.py @@ -0,0 +1,40 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + while True: + pass + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/infinite_loop/fake_2_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/infinite_loop/fake_2_test.py new file mode 100644 index 0000000..3be92e1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/infinite_loop/fake_2_test.py @@ -0,0 +1,39 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stderr/__init__.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stderr/__init__.py new file mode 100644 index 0000000..1bb8bf6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stderr/__init__.py @@ -0,0 +1 @@ +# empty diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stderr/fake_2_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stderr/fake_2_test.py new file mode 100644 index 0000000..3be92e1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stderr/fake_2_test.py @@ -0,0 +1,39 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stderr/fake_3_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stderr/fake_3_test.py new file mode 100644 index 0000000..f59ad40 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stderr/fake_3_test.py @@ -0,0 +1,41 @@ +import sys + +if __name__ == "__main__": + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + sys.stderr.write("jibberish messes things up\n") + self.assertTrue(False) + + def test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stderr/fake_4_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stderr/fake_4_test.py new file mode 100644 index 0000000..1e75fea --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stderr/fake_4_test.py @@ -0,0 +1,41 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(False, "Some Jibberish") + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + if 1: + if 1: + assert False + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stdout/__init__.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stdout/__init__.py new file mode 100644 index 0000000..1bb8bf6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stdout/__init__.py @@ -0,0 +1 @@ +# empty diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stdout/fake_2_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stdout/fake_2_test.py new file mode 100644 index 0000000..3be92e1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stdout/fake_2_test.py @@ -0,0 +1,39 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stdout/fake_3_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stdout/fake_3_test.py new file mode 100644 index 0000000..467c725 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stdout/fake_3_test.py @@ -0,0 +1,42 @@ +import sys + +if __name__ == "__main__": + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + sys.stdout.write("jibberish ruins everything\n") + self.assertTrue(False) + + def test_name(self): + sys.stdout.write("forgot to remove debug crap\n") + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stdout/fake_4_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stdout/fake_4_test.py new file mode 100644 index 0000000..1e75fea --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/print_stdout/fake_4_test.py @@ -0,0 +1,41 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(False, "Some Jibberish") + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + if 1: + if 1: + assert False + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/run_tests__test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/run_tests__test.py new file mode 100644 index 0000000..533f7a0 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/run_tests__test.py @@ -0,0 +1,145 @@ +################################################################################ + +import subprocess, os, sys, re, difflib + +################################################################################ + +IGNORE = (".svn", "infinite_loop") +NORMALIZERS = ( + (r"Ran (\d+) tests in (\d+\.\d+)s", "Ran \\1 tests in X.XXXs"), + (r'File ".*?([^/\\.]+\.py)"', 'File "\\1"'), +) + +################################################################################ + + +def norm_result(result): + "normalize differences, such as timing between output" + for normalizer, replacement in NORMALIZERS: + if hasattr(normalizer, "__call__"): + result = normalizer(result) + else: + result = re.sub(normalizer, replacement, result) + + return result + + +def call_proc(cmd, cd=None): + proc = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + cwd=cd, + universal_newlines=True, + ) + if proc.wait(): + print("%s %s" % (cmd, proc.wait())) + raise Exception(proc.stdout.read()) + + return proc.stdout.read() + + +################################################################################ + +unnormed_diff = "-u" in sys.argv +verbose = "-v" in sys.argv or unnormed_diff +if "-h" in sys.argv or "--help" in sys.argv: + sys.exit( + "\nCOMPARES OUTPUT OF SINGLE VS SUBPROCESS MODE OF RUN_TESTS.PY\n\n" + "-v, to output diffs even on success\n" + "-u, to output diffs of unnormalized tests\n\n" + "Each line of a Differ delta begins with a two-letter code:\n\n" + " '- ' line unique to sequence 1\n" + " '+ ' line unique to sequence 2\n" + " ' ' line common to both sequences\n" + " '? ' line not present in either input sequence\n" + ) + +main_dir = os.path.split(os.path.abspath(sys.argv[0]))[0] +trunk_dir = os.path.normpath(os.path.join(main_dir, "../../")) + +test_suite_dirs = [ + x + for x in os.listdir(main_dir) + if os.path.isdir(os.path.join(main_dir, x)) and x not in IGNORE +] + + +################################################################################ + + +def assert_on_results(suite, single, sub): + test = globals().get("%s_test" % suite) + if hasattr(test, "__call_"): + test(suite, single, sub) + print("assertions on %s OK" % (suite,)) + + +# Don't modify tests in suites below. These assertions are in place to make sure +# that tests are actually being ran + + +def all_ok_test(uite, *args): + for results in args: + assert "Ran 36 tests" in results # some tests are runing + assert "OK" in results # OK + + +def failures1_test(suite, *args): + for results in args: + assert "FAILED (failures=2)" in results + assert "Ran 18 tests" in results + + +################################################################################ +# Test that output is the same in single process and subprocess modes +# + +base_cmd = [sys.executable, "run_tests.py", "-i"] + +cmd = base_cmd + ["-n", "-f"] +sub_cmd = base_cmd + ["-f"] +time_out_cmd = base_cmd + ["-t", "4", "-f", "infinite_loop"] + +passes = 0 +failed = False + +for suite in test_suite_dirs: + single = call_proc(cmd + [suite], trunk_dir) + subs = call_proc(sub_cmd + [suite], trunk_dir) + + normed_single, normed_subs = map(norm_result, (single, subs)) + + failed = normed_single != normed_subs + if failed: + print("%s suite comparison FAILED\n" % (suite,)) + else: + passes += 1 + print("%s suite comparison OK" % (suite,)) + + assert_on_results(suite, single, subs) + + if verbose or failed: + print("difflib.Differ().compare(single, suprocessed):\n") + print( + "".join( + list( + difflib.Differ().compare( + (unnormed_diff and single or normed_single).splitlines(1), + (unnormed_diff and subs or normed_subs).splitlines(1), + ) + ) + ) + ) + +sys.stdout.write("infinite_loop suite (subprocess mode timeout) ") +loop_test = call_proc(time_out_cmd, trunk_dir) +assert "successfully terminated" in loop_test +passes += 1 +print("OK") + +print("\n%s/%s suites pass" % (passes, len(test_suite_dirs) + 1)) + +print("\n-h for help") + +################################################################################ diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/timeout/__init__.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/timeout/__init__.py new file mode 100644 index 0000000..1bb8bf6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/timeout/__init__.py @@ -0,0 +1 @@ +# empty diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/timeout/fake_2_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/timeout/fake_2_test.py new file mode 100644 index 0000000..3be92e1 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/timeout/fake_2_test.py @@ -0,0 +1,39 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + self.assertTrue(True) + + def test_get_mods(self): + self.assertTrue(True) + + def test_get_pressed(self): + self.assertTrue(True) + + def test_name(self): + self.assertTrue(True) + + def test_set_mods(self): + self.assertTrue(True) + + def test_set_repeat(self): + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/run_tests__tests/timeout/sleep_test.py b/venv/Lib/site-packages/pygame/tests/run_tests__tests/timeout/sleep_test.py new file mode 100644 index 0000000..bab528a --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/run_tests__tests/timeout/sleep_test.py @@ -0,0 +1,30 @@ +if __name__ == "__main__": + import sys + import os + + pkg_dir = os.path.split( + os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + )[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest + +import time + + +class KeyModuleTest(unittest.TestCase): + def test_get_focused(self): + stop_time = time.time() + 10.0 + while time.time() < stop_time: + time.sleep(1) + + self.assertTrue(True) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/rwobject_test.py b/venv/Lib/site-packages/pygame/tests/rwobject_test.py new file mode 100644 index 0000000..31723ae --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/rwobject_test.py @@ -0,0 +1,139 @@ +import pathlib +import unittest + +from pygame import encode_string, encode_file_path + + +class RWopsEncodeStringTest(unittest.TestCase): + global getrefcount + + def test_obj_None(self): + encoded_string = encode_string(None) + + self.assertIsNone(encoded_string) + + def test_returns_bytes(self): + u = "Hello" + encoded_string = encode_string(u) + + self.assertIsInstance(encoded_string, bytes) + + def test_obj_bytes(self): + b = b"encyclop\xE6dia" + encoded_string = encode_string(b, "ascii", "strict") + + self.assertIs(encoded_string, b) + + def test_encode_unicode(self): + u = "\u00DEe Olde Komp\u00FCter Shoppe" + b = u.encode("utf-8") + self.assertEqual(encode_string(u, "utf-8"), b) + + def test_error_fowarding(self): + self.assertRaises(SyntaxError, encode_string) + + def test_errors(self): + u = "abc\u0109defg\u011Dh\u0125ij\u0135klmnoprs\u015Dtu\u016Dvz" + b = u.encode("ascii", "ignore") + self.assertEqual(encode_string(u, "ascii", "ignore"), b) + + def test_encoding_error(self): + u = "a\x80b" + encoded_string = encode_string(u, "ascii", "strict") + + self.assertIsNone(encoded_string) + + def test_check_defaults(self): + u = "a\u01F7b" + b = u.encode("unicode_escape", "backslashreplace") + encoded_string = encode_string(u) + + self.assertEqual(encoded_string, b) + + def test_etype(self): + u = "a\x80b" + self.assertRaises(SyntaxError, encode_string, u, "ascii", "strict", SyntaxError) + + def test_etype__invalid(self): + """Ensures invalid etypes are properly handled.""" + + for etype in ("SyntaxError", self): + self.assertRaises(TypeError, encode_string, "test", etype=etype) + + def test_string_with_null_bytes(self): + b = b"a\x00b\x00c" + encoded_string = encode_string(b, etype=SyntaxError) + encoded_decode_string = encode_string(b.decode(), "ascii", "strict") + + self.assertIs(encoded_string, b) + self.assertEqual(encoded_decode_string, b) + + try: + from sys import getrefcount as _g + + getrefcount = _g # This nonsense is for Python 3.x + except ImportError: + pass + else: + + def test_refcount(self): + bpath = b" This is a string that is not cached."[1:] + upath = bpath.decode("ascii") + before = getrefcount(bpath) + bpath = encode_string(bpath) + self.assertEqual(getrefcount(bpath), before) + bpath = encode_string(upath) + self.assertEqual(getrefcount(bpath), before) + + def test_smp(self): + utf_8 = b"a\xF0\x93\x82\xA7b" + u = "a\U000130A7b" + b = encode_string(u, "utf-8", "strict", AssertionError) + self.assertEqual(b, utf_8) + + def test_pathlib_obj(self): + """Test loading string representation of pathlib object""" + """ + We do this because pygame functions internally use pg_EncodeString + to decode the filenames passed to them. So if we test that here, we + can safely assume that all those functions do not have any issues + with pathlib objects + """ + encoded = encode_string(pathlib.PurePath("foo"), "utf-8") + self.assertEqual(encoded, b"foo") + + encoded = encode_string(pathlib.Path("baz")) + self.assertEqual(encoded, b"baz") + + +class RWopsEncodeFilePathTest(unittest.TestCase): + # Most tests can be skipped since RWopsEncodeFilePath wraps + # RWopsEncodeString + def test_encoding(self): + u = "Hello" + encoded_file_path = encode_file_path(u) + + self.assertIsInstance(encoded_file_path, bytes) + + def test_error_fowarding(self): + self.assertRaises(SyntaxError, encode_file_path) + + def test_path_with_null_bytes(self): + b = b"a\x00b\x00c" + encoded_file_path = encode_file_path(b) + + self.assertIsNone(encoded_file_path) + + def test_etype(self): + b = b"a\x00b\x00c" + self.assertRaises(TypeError, encode_file_path, b, TypeError) + + def test_etype__invalid(self): + """Ensures invalid etypes are properly handled.""" + + for etype in ("SyntaxError", self): + self.assertRaises(TypeError, encode_file_path, "test", etype) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/scrap_tags.py b/venv/Lib/site-packages/pygame/tests/scrap_tags.py new file mode 100644 index 0000000..17a82ff --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/scrap_tags.py @@ -0,0 +1,26 @@ +__tags__ = ["ignore", "subprocess_ignore"] + +# TODO: make scrap_test.py work +# This test used to work only on linux and windows. +# Currently it only work in windows, and in linux it throws: +# `pygame.error: content could not be placed in clipboard.` +# The old test and tags kept here for reference when fixing. + +# import sys +# +# exclude = False +# +# if sys.platform == "win32" or sys.platform.startswith("linux"): +# try: +# import pygame +# +# pygame.scrap._NOT_IMPLEMENTED_ +# except AttributeError: +# pass +# else: +# exclude = True +# else: +# exclude = True +# +# if exclude: +# __tags__.extend(["ignore", "subprocess_ignore"]) diff --git a/venv/Lib/site-packages/pygame/tests/scrap_test.py b/venv/Lib/site-packages/pygame/tests/scrap_test.py new file mode 100644 index 0000000..6b7f6fa --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/scrap_test.py @@ -0,0 +1,301 @@ +import os +import sys + +if os.environ.get("SDL_VIDEODRIVER") == "dummy": + __tags__ = ("ignore", "subprocess_ignore") +import unittest +from pygame.tests.test_utils import trunk_relative_path + +import pygame +from pygame import scrap + + +class ScrapModuleTest(unittest.TestCase): + @classmethod + def setUpClass(cls): + pygame.display.init() + pygame.display.set_mode((1, 1)) + scrap.init() + + @classmethod + def tearDownClass(cls): + # scrap.quit() # Does not exist! + pygame.display.quit() + + def test_init(self): + """Ensures scrap module still initialized after multiple init calls.""" + scrap.init() + scrap.init() + + self.assertTrue(scrap.get_init()) + + def test_init__reinit(self): + """Ensures reinitializing the scrap module doesn't clear its data.""" + data_type = pygame.SCRAP_TEXT + expected_data = b"test_init__reinit" + scrap.put(data_type, expected_data) + + scrap.init() + + self.assertEqual(scrap.get(data_type), expected_data) + + def test_get_init(self): + """Ensures get_init gets the init state.""" + self.assertTrue(scrap.get_init()) + + def todo_test_contains(self): + """Ensures contains works as expected.""" + self.fail() + + def todo_test_get(self): + """Ensures get works as expected.""" + self.fail() + + def test_get__owned_empty_type(self): + """Ensures get works when there is no data of the requested type + in the clipboard and the clipboard is owned by the pygame application. + """ + # Use a unique data type identifier to ensure there is no preexisting + # data. + DATA_TYPE = "test_get__owned_empty_type" + + if scrap.lost(): + # Try to acquire the clipboard. + scrap.put(pygame.SCRAP_TEXT, b"text to clipboard") + + if scrap.lost(): + self.skipTest("requires the pygame application to own the clipboard") + + data = scrap.get(DATA_TYPE) + + self.assertIsNone(data) + + def todo_test_get_types(self): + """Ensures get_types works as expected.""" + self.fail() + + def todo_test_lost(self): + """Ensures lost works as expected.""" + self.fail() + + def test_set_mode(self): + """Ensures set_mode works as expected.""" + scrap.set_mode(pygame.SCRAP_SELECTION) + scrap.set_mode(pygame.SCRAP_CLIPBOARD) + + self.assertRaises(ValueError, scrap.set_mode, 1099) + + def test_put__text(self): + """Ensures put can place text into the clipboard.""" + scrap.put(pygame.SCRAP_TEXT, b"Hello world") + + self.assertEqual(scrap.get(pygame.SCRAP_TEXT), b"Hello world") + + scrap.put(pygame.SCRAP_TEXT, b"Another String") + + self.assertEqual(scrap.get(pygame.SCRAP_TEXT), b"Another String") + + @unittest.skipIf("pygame.image" not in sys.modules, "requires pygame.image module") + def test_put__bmp_image(self): + """Ensures put can place a BMP image into the clipboard.""" + sf = pygame.image.load(trunk_relative_path("examples/data/asprite.bmp")) + expected_string = pygame.image.tostring(sf, "RGBA") + scrap.put(pygame.SCRAP_BMP, expected_string) + + self.assertEqual(scrap.get(pygame.SCRAP_BMP), expected_string) + + def test_put(self): + """Ensures put can place data into the clipboard + when using a user defined type identifier. + """ + DATA_TYPE = "arbitrary buffer" + + scrap.put(DATA_TYPE, b"buf") + r = scrap.get(DATA_TYPE) + + self.assertEqual(r, b"buf") + + +class ScrapModuleClipboardNotOwnedTest(unittest.TestCase): + """Test the scrap module's functionality when the pygame application is + not the current owner of the clipboard. + + A separate class is used to prevent tests that acquire the clipboard from + interfering with these tests. + """ + + @classmethod + def setUpClass(cls): + pygame.display.init() + pygame.display.set_mode((1, 1)) + scrap.init() + + @classmethod + def tearDownClass(cls): + # scrap.quit() # Does not exist! + pygame.quit() + pygame.display.quit() + + def _skip_if_clipboard_owned(self): + # Skip test if the pygame application owns the clipboard. Currently, + # there is no way to give up ownership. + if not scrap.lost(): + self.skipTest("requires the pygame application to not own the clipboard") + + def test_get__not_owned(self): + """Ensures get works when there is no data of the requested type + in the clipboard and the clipboard is not owned by the pygame + application. + """ + self._skip_if_clipboard_owned() + + # Use a unique data type identifier to ensure there is no preexisting + # data. + DATA_TYPE = "test_get__not_owned" + + data = scrap.get(DATA_TYPE) + + self.assertIsNone(data) + + def test_get_types__not_owned(self): + """Ensures get_types works when the clipboard is not owned + by the pygame application. + """ + self._skip_if_clipboard_owned() + + data_types = scrap.get_types() + + self.assertIsInstance(data_types, list) + + def test_contains__not_owned(self): + """Ensures contains works when the clipboard is not owned + by the pygame application. + """ + self._skip_if_clipboard_owned() + + # Use a unique data type identifier to ensure there is no preexisting + # data. + DATA_TYPE = "test_contains__not_owned" + + contains = scrap.contains(DATA_TYPE) + + self.assertFalse(contains) + + def test_lost__not_owned(self): + """Ensures lost works when the clipboard is not owned + by the pygame application. + """ + self._skip_if_clipboard_owned() + + lost = scrap.lost() + + self.assertTrue(lost) + + +class X11InteractiveTest(unittest.TestCase): + __tags__ = ["ignore", "subprocess_ignore"] + try: + pygame.display.init() + except Exception: + pass + else: + if pygame.display.get_driver() == "x11": + __tags__ = ["interactive"] + pygame.display.quit() + + def test_issue_208(self): + """PATCH: pygame.scrap on X11, fix copying into PRIMARY selection + + Copying into theX11 PRIMARY selection (mouse copy/paste) would not + work due to a confusion between content type and clipboard type. + + """ + + from pygame import display, event, freetype + from pygame.locals import SCRAP_SELECTION, SCRAP_TEXT + from pygame.locals import KEYDOWN, K_y, QUIT + + success = False + freetype.init() + font = freetype.Font(None, 24) + display.init() + display.set_caption("Interactive X11 Paste Test") + screen = display.set_mode((600, 200)) + screen.fill(pygame.Color("white")) + text = "Scrap put() succeeded." + msg = ( + "Some text has been placed into the X11 clipboard." + " Please click the center mouse button in an open" + " text window to retrieve it." + '\n\nDid you get "{}"? (y/n)' + ).format(text) + word_wrap(screen, msg, font, 6) + display.flip() + event.pump() + scrap.init() + scrap.set_mode(SCRAP_SELECTION) + scrap.put(SCRAP_TEXT, text.encode("UTF-8")) + while True: + e = event.wait() + if e.type == QUIT: + break + if e.type == KEYDOWN: + success = e.key == K_y + break + pygame.display.quit() + self.assertTrue(success) + + +def word_wrap(surf, text, font, margin=0, color=(0, 0, 0)): + font.origin = True + surf_width, surf_height = surf.get_size() + width = surf_width - 2 * margin + height = surf_height - 2 * margin + line_spacing = int(1.25 * font.get_sized_height()) + x, y = margin, margin + line_spacing + space = font.get_rect(" ") + for word in iwords(text): + if word == "\n": + x, y = margin, y + line_spacing + else: + bounds = font.get_rect(word) + if x + bounds.width + bounds.x >= width: + x, y = margin, y + line_spacing + if x + bounds.width + bounds.x >= width: + raise ValueError("word too wide for the surface") + if y + bounds.height - bounds.y >= height: + raise ValueError("text to long for the surface") + font.render_to(surf, (x, y), None, color) + x += bounds.width + space.width + return x, y + + +def iwords(text): + # r"\n|[^ ]+" + # + head = 0 + tail = head + end = len(text) + while head < end: + if text[head] == " ": + head += 1 + tail = head + 1 + elif text[head] == "\n": + head += 1 + yield "\n" + tail = head + 1 + elif tail == end: + yield text[head:] + head = end + elif text[tail] == "\n": + yield text[head:tail] + head = tail + elif text[tail] == " ": + yield text[head:tail] + head = tail + else: + tail += 1 + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/sndarray_tags.py b/venv/Lib/site-packages/pygame/tests/sndarray_tags.py new file mode 100644 index 0000000..68fa7a5 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/sndarray_tags.py @@ -0,0 +1,12 @@ +__tags__ = ["array"] + +exclude = False + +try: + import pygame.mixer + import numpy +except ImportError: + exclude = True + +if exclude: + __tags__.extend(("ignore", "subprocess_ignore")) diff --git a/venv/Lib/site-packages/pygame/tests/sndarray_test.py b/venv/Lib/site-packages/pygame/tests/sndarray_test.py new file mode 100644 index 0000000..afa94ec --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/sndarray_test.py @@ -0,0 +1,155 @@ +import unittest + +from numpy import int8, int16, uint8, uint16, float32, array, alltrue + +import pygame +import pygame.sndarray + + +class SndarrayTest(unittest.TestCase): + array_dtypes = {8: uint8, -8: int8, 16: uint16, -16: int16, 32: float32} + + def _assert_compatible(self, arr, size): + dtype = self.array_dtypes[size] + self.assertEqual(arr.dtype, dtype) + + def test_array(self): + def check_array(size, channels, test_data): + try: + pygame.mixer.init(22050, size, channels, allowedchanges=0) + except pygame.error: + # Not all sizes are supported on all systems. + return + try: + __, sz, __ = pygame.mixer.get_init() + if sz == size: + srcarr = array(test_data, self.array_dtypes[size]) + snd = pygame.sndarray.make_sound(srcarr) + arr = pygame.sndarray.array(snd) + self._assert_compatible(arr, size) + self.assertTrue( + alltrue(arr == srcarr), + "size: %i\n%s\n%s" % (size, arr, test_data), + ) + finally: + pygame.mixer.quit() + + check_array(8, 1, [0, 0x0F, 0xF0, 0xFF]) + check_array(8, 2, [[0, 0x80], [0x2D, 0x41], [0x64, 0xA1], [0xFF, 0x40]]) + check_array(16, 1, [0, 0x00FF, 0xFF00, 0xFFFF]) + check_array( + 16, 2, [[0, 0xFFFF], [0xFFFF, 0], [0x00FF, 0xFF00], [0x0F0F, 0xF0F0]] + ) + check_array(-8, 1, [0, -0x80, 0x7F, 0x64]) + check_array(-8, 2, [[0, -0x80], [-0x64, 0x64], [0x25, -0x50], [0xFF, 0]]) + check_array(-16, 1, [0, 0x7FFF, -0x7FFF, -1]) + check_array(-16, 2, [[0, -0x7FFF], [-0x7FFF, 0], [0x7FFF, 0], [0, 0x7FFF]]) + + def test_get_arraytype(self): + array_type = pygame.sndarray.get_arraytype() + + self.assertEqual(array_type, "numpy", "unknown array type %s" % array_type) + + def test_get_arraytypes(self): + arraytypes = pygame.sndarray.get_arraytypes() + self.assertIn("numpy", arraytypes) + + for atype in arraytypes: + self.assertEqual(atype, "numpy", "unknown array type %s" % atype) + + def test_make_sound(self): + def check_sound(size, channels, test_data): + try: + pygame.mixer.init(22050, size, channels, allowedchanges=0) + except pygame.error: + # Not all sizes are supported on all systems. + return + try: + __, sz, __ = pygame.mixer.get_init() + if sz == size: + srcarr = array(test_data, self.array_dtypes[size]) + snd = pygame.sndarray.make_sound(srcarr) + arr = pygame.sndarray.samples(snd) + self.assertTrue( + alltrue(arr == srcarr), + "size: %i\n%s\n%s" % (size, arr, test_data), + ) + finally: + pygame.mixer.quit() + + check_sound(8, 1, [0, 0x0F, 0xF0, 0xFF]) + check_sound(8, 2, [[0, 0x80], [0x2D, 0x41], [0x64, 0xA1], [0xFF, 0x40]]) + check_sound(16, 1, [0, 0x00FF, 0xFF00, 0xFFFF]) + check_sound( + 16, 2, [[0, 0xFFFF], [0xFFFF, 0], [0x00FF, 0xFF00], [0x0F0F, 0xF0F0]] + ) + check_sound(-8, 1, [0, -0x80, 0x7F, 0x64]) + check_sound(-8, 2, [[0, -0x80], [-0x64, 0x64], [0x25, -0x50], [0xFF, 0]]) + check_sound(-16, 1, [0, 0x7FFF, -0x7FFF, -1]) + check_sound(-16, 2, [[0, -0x7FFF], [-0x7FFF, 0], [0x7FFF, 0], [0, 0x7FFF]]) + check_sound(32, 2, [[0.0, -1.0], [-1.0, 0], [1.0, 0], [0, 1.0]]) + + def test_samples(self): + + null_byte = b"\x00" + + def check_sample(size, channels, test_data): + try: + pygame.mixer.init(22050, size, channels, allowedchanges=0) + except pygame.error: + # Not all sizes are supported on all systems. + return + try: + __, sz, __ = pygame.mixer.get_init() + if sz == size: + zeroed = null_byte * ((abs(size) // 8) * len(test_data) * channels) + snd = pygame.mixer.Sound(buffer=zeroed) + samples = pygame.sndarray.samples(snd) + self._assert_compatible(samples, size) + ##print ('X %s' % (samples.shape,)) + ##print ('Y %s' % (test_data,)) + samples[...] = test_data + arr = pygame.sndarray.array(snd) + self.assertTrue( + alltrue(samples == arr), + "size: %i\n%s\n%s" % (size, arr, test_data), + ) + finally: + pygame.mixer.quit() + + check_sample(8, 1, [0, 0x0F, 0xF0, 0xFF]) + check_sample(8, 2, [[0, 0x80], [0x2D, 0x41], [0x64, 0xA1], [0xFF, 0x40]]) + check_sample(16, 1, [0, 0x00FF, 0xFF00, 0xFFFF]) + check_sample( + 16, 2, [[0, 0xFFFF], [0xFFFF, 0], [0x00FF, 0xFF00], [0x0F0F, 0xF0F0]] + ) + check_sample(-8, 1, [0, -0x80, 0x7F, 0x64]) + check_sample(-8, 2, [[0, -0x80], [-0x64, 0x64], [0x25, -0x50], [0xFF, 0]]) + check_sample(-16, 1, [0, 0x7FFF, -0x7FFF, -1]) + check_sample(-16, 2, [[0, -0x7FFF], [-0x7FFF, 0], [0x7FFF, 0], [0, 0x7FFF]]) + check_sample(32, 2, [[0.0, -1.0], [-1.0, 0], [1.0, 0], [0, 1.0]]) + + def test_use_arraytype(self): + def do_use_arraytype(atype): + pygame.sndarray.use_arraytype(atype) + + pygame.sndarray.use_arraytype("numpy") + self.assertEqual(pygame.sndarray.get_arraytype(), "numpy") + + self.assertRaises(ValueError, do_use_arraytype, "not an option") + + def test_float32(self): + """sized arrays work with Sounds and 32bit float arrays.""" + try: + pygame.mixer.init(22050, 32, 2, allowedchanges=0) + except pygame.error: + # Not all sizes are supported on all systems. + self.skipTest("unsupported mixer configuration") + + arr = array([[0.0, -1.0], [-1.0, 0], [1.0, 0], [0, 1.0]], float32) + newsound = pygame.mixer.Sound(array=arr) + pygame.mixer.quit() + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/sprite_test.py b/venv/Lib/site-packages/pygame/tests/sprite_test.py new file mode 100644 index 0000000..b0b099a --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/sprite_test.py @@ -0,0 +1,1403 @@ +#################################### IMPORTS ################################### +# -*- encoding: utf-8 -*- + + +import unittest + +import pygame +from pygame import sprite + + +################################# MODULE LEVEL ################################# + + +class SpriteModuleTest(unittest.TestCase): + pass + + +######################### SPRITECOLLIDE FUNCTIONS TEST ######################### + + +class SpriteCollideTest(unittest.TestCase): + def setUp(self): + self.ag = sprite.AbstractGroup() + self.ag2 = sprite.AbstractGroup() + self.s1 = sprite.Sprite(self.ag) + self.s2 = sprite.Sprite(self.ag2) + self.s3 = sprite.Sprite(self.ag2) + + self.s1.image = pygame.Surface((50, 10), pygame.SRCALPHA, 32) + self.s2.image = pygame.Surface((10, 10), pygame.SRCALPHA, 32) + self.s3.image = pygame.Surface((10, 10), pygame.SRCALPHA, 32) + + self.s1.rect = self.s1.image.get_rect() + self.s2.rect = self.s2.image.get_rect() + self.s3.rect = self.s3.image.get_rect() + self.s2.rect.move_ip(40, 0) + self.s3.rect.move_ip(100, 100) + + def test_spritecollide__works_if_collided_cb_is_None(self): + # Test that sprites collide without collided function. + self.assertEqual( + sprite.spritecollide(self.s1, self.ag2, dokill=False, collided=None), + [self.s2], + ) + + def test_spritecollide__works_if_collided_cb_not_passed(self): + # Should also work when collided function isn't passed at all. + self.assertEqual( + sprite.spritecollide(self.s1, self.ag2, dokill=False), [self.s2] + ) + + def test_spritecollide__collided_must_be_a_callable(self): + # Need to pass a callable. + self.assertRaises( + TypeError, sprite.spritecollide, self.s1, self.ag2, dokill=False, collided=1 + ) + + def test_spritecollide__collided_defaults_to_collide_rect(self): + # collide_rect should behave the same as default. + self.assertEqual( + sprite.spritecollide( + self.s1, self.ag2, dokill=False, collided=sprite.collide_rect + ), + [self.s2], + ) + + def test_collide_rect_ratio__ratio_of_one_like_default(self): + # collide_rect_ratio should behave the same as default at a 1.0 ratio. + self.assertEqual( + sprite.spritecollide( + self.s1, self.ag2, dokill=False, collided=sprite.collide_rect_ratio(1.0) + ), + [self.s2], + ) + + def test_collide_rect_ratio__collides_all_at_ratio_of_twenty(self): + # collide_rect_ratio should collide all at a 20.0 ratio. + collided_func = sprite.collide_rect_ratio(20.0) + expected_sprites = sorted(self.ag2.sprites(), key=id) + + collided_sprites = sorted( + sprite.spritecollide( + self.s1, self.ag2, dokill=False, collided=collided_func + ), + key=id, + ) + + self.assertListEqual(collided_sprites, expected_sprites) + + def test_collide_circle__no_radius_set(self): + # collide_circle with no radius set. + self.assertEqual( + sprite.spritecollide( + self.s1, self.ag2, dokill=False, collided=sprite.collide_circle + ), + [self.s2], + ) + + def test_collide_circle_ratio__no_radius_and_ratio_of_one(self): + # collide_circle_ratio with no radius set, at a 1.0 ratio. + self.assertEqual( + sprite.spritecollide( + self.s1, + self.ag2, + dokill=False, + collided=sprite.collide_circle_ratio(1.0), + ), + [self.s2], + ) + + def test_collide_circle_ratio__no_radius_and_ratio_of_twenty(self): + # collide_circle_ratio with no radius set, at a 20.0 ratio. + collided_func = sprite.collide_circle_ratio(20.0) + expected_sprites = sorted(self.ag2.sprites(), key=id) + + collided_sprites = sorted( + sprite.spritecollide( + self.s1, self.ag2, dokill=False, collided=collided_func + ), + key=id, + ) + + self.assertListEqual(expected_sprites, collided_sprites) + + def test_collide_circle__radius_set_by_collide_circle_ratio(self): + # Call collide_circle_ratio with no radius set, at a 20.0 ratio. + # That should return group ag2 AND set the radius attribute of the + # sprites in such a way that collide_circle would give same result as + # if it had been called without the radius being set. + collided_func = sprite.collide_circle_ratio(20.0) + + sprite.spritecollide(self.s1, self.ag2, dokill=False, collided=collided_func) + + self.assertEqual( + sprite.spritecollide( + self.s1, self.ag2, dokill=False, collided=sprite.collide_circle + ), + [self.s2], + ) + + def test_collide_circle_ratio__no_radius_and_ratio_of_two_twice(self): + # collide_circle_ratio with no radius set, at a 2.0 ratio, + # called twice to check if the bug where the calculated radius + # is not stored correctly in the radius attribute of each sprite. + collided_func = sprite.collide_circle_ratio(2.0) + + # Calling collide_circle_ratio will set the radius attribute of the + # sprites. If an incorrect value is stored then we will not get the + # same result next time it is called: + expected_sprites = sorted( + sprite.spritecollide( + self.s1, self.ag2, dokill=False, collided=collided_func + ), + key=id, + ) + collided_sprites = sorted( + sprite.spritecollide( + self.s1, self.ag2, dokill=False, collided=collided_func + ), + key=id, + ) + + self.assertListEqual(expected_sprites, collided_sprites) + + def test_collide_circle__with_radii_set(self): + # collide_circle with a radius set. + self.s1.radius = 50 + self.s2.radius = 10 + self.s3.radius = 400 + collided_func = sprite.collide_circle + expected_sprites = sorted(self.ag2.sprites(), key=id) + + collided_sprites = sorted( + sprite.spritecollide( + self.s1, self.ag2, dokill=False, collided=collided_func + ), + key=id, + ) + + self.assertListEqual(expected_sprites, collided_sprites) + + def test_collide_circle_ratio__with_radii_set(self): + # collide_circle_ratio with a radius set. + self.s1.radius = 50 + self.s2.radius = 10 + self.s3.radius = 400 + collided_func = sprite.collide_circle_ratio(0.5) + expected_sprites = sorted(self.ag2.sprites(), key=id) + + collided_sprites = sorted( + sprite.spritecollide( + self.s1, self.ag2, dokill=False, collided=collided_func + ), + key=id, + ) + + self.assertListEqual(expected_sprites, collided_sprites) + + def test_collide_mask__opaque(self): + # make some fully opaque sprites that will collide with masks. + self.s1.image.fill((255, 255, 255, 255)) + self.s2.image.fill((255, 255, 255, 255)) + self.s3.image.fill((255, 255, 255, 255)) + + # masks should be autogenerated from image if they don't exist. + self.assertEqual( + sprite.spritecollide( + self.s1, self.ag2, dokill=False, collided=sprite.collide_mask + ), + [self.s2], + ) + + self.s1.mask = pygame.mask.from_surface(self.s1.image) + self.s2.mask = pygame.mask.from_surface(self.s2.image) + self.s3.mask = pygame.mask.from_surface(self.s3.image) + + # with set masks. + self.assertEqual( + sprite.spritecollide( + self.s1, self.ag2, dokill=False, collided=sprite.collide_mask + ), + [self.s2], + ) + + def test_collide_mask__transparent(self): + # make some sprites that are fully transparent, so they won't collide. + self.s1.image.fill((255, 255, 255, 0)) + self.s2.image.fill((255, 255, 255, 0)) + self.s3.image.fill((255, 255, 255, 0)) + + self.s1.mask = pygame.mask.from_surface(self.s1.image, 255) + self.s2.mask = pygame.mask.from_surface(self.s2.image, 255) + self.s3.mask = pygame.mask.from_surface(self.s3.image, 255) + + self.assertFalse( + sprite.spritecollide( + self.s1, self.ag2, dokill=False, collided=sprite.collide_mask + ) + ) + + def test_spritecollideany__without_collided_callback(self): + + # pygame.sprite.spritecollideany(sprite, group) -> sprite + # finds any sprites that collide + + # if collided is not passed, all + # sprites must have a "rect" value, which is a + # rectangle of the sprite area, which will be used + # to calculate the collision. + + # s2 in, s3 out + expected_sprite = self.s2 + collided_sprite = sprite.spritecollideany(self.s1, self.ag2) + + self.assertEqual(collided_sprite, expected_sprite) + + # s2 and s3 out + self.s2.rect.move_ip(0, 10) + collided_sprite = sprite.spritecollideany(self.s1, self.ag2) + + self.assertIsNone(collided_sprite) + + # s2 out, s3 in + self.s3.rect.move_ip(-105, -105) + expected_sprite = self.s3 + collided_sprite = sprite.spritecollideany(self.s1, self.ag2) + + self.assertEqual(collided_sprite, expected_sprite) + + # s2 and s3 in + self.s2.rect.move_ip(0, -10) + expected_sprite_choices = self.ag2.sprites() + collided_sprite = sprite.spritecollideany(self.s1, self.ag2) + + self.assertIn(collided_sprite, expected_sprite_choices) + + def test_spritecollideany__with_collided_callback(self): + + # pygame.sprite.spritecollideany(sprite, group) -> sprite + # finds any sprites that collide + + # collided is a callback function used to calculate if + # two sprites are colliding. it should take two sprites + # as values, and return a bool value indicating if + # they are colliding. + + # This collision test can be faster than pygame.sprite.spritecollide() + # since it has less work to do. + + arg_dict_a = {} + arg_dict_b = {} + return_container = [True] + + # This function is configurable using the mutable default arguments! + def collided_callback( + spr_a, + spr_b, + arg_dict_a=arg_dict_a, + arg_dict_b=arg_dict_b, + return_container=return_container, + ): + + count = arg_dict_a.get(spr_a, 0) + arg_dict_a[spr_a] = 1 + count + + count = arg_dict_b.get(spr_b, 0) + arg_dict_b[spr_b] = 1 + count + + return return_container[0] + + # This should return a sprite from self.ag2 because the callback + # function (collided_callback()) currently returns True. + expected_sprite_choices = self.ag2.sprites() + collided_sprite = sprite.spritecollideany(self.s1, self.ag2, collided_callback) + + self.assertIn(collided_sprite, expected_sprite_choices) + + # The callback function should have been called only once, so self.s1 + # should have only been passed as an argument once + self.assertEqual(len(arg_dict_a), 1) + self.assertEqual(arg_dict_a[self.s1], 1) + + # The callback function should have been called only once, so self.s2 + # exclusive-or self.s3 should have only been passed as an argument + # once + self.assertEqual(len(arg_dict_b), 1) + self.assertEqual(list(arg_dict_b.values())[0], 1) + self.assertTrue(self.s2 in arg_dict_b or self.s3 in arg_dict_b) + + arg_dict_a.clear() + arg_dict_b.clear() + return_container[0] = False + + # This should return None because the callback function + # (collided_callback()) currently returns False. + collided_sprite = sprite.spritecollideany(self.s1, self.ag2, collided_callback) + + self.assertIsNone(collided_sprite) + + # The callback function should have been called as many times as + # there are sprites in self.ag2 + self.assertEqual(len(arg_dict_a), 1) + self.assertEqual(arg_dict_a[self.s1], len(self.ag2)) + self.assertEqual(len(arg_dict_b), len(self.ag2)) + + # Each sprite in self.ag2 should be called once. + for s in self.ag2: + self.assertEqual(arg_dict_b[s], 1) + + def test_groupcollide__without_collided_callback(self): + + # pygame.sprite.groupcollide(groupa, groupb, dokilla, dokillb) -> dict + # collision detection between group and group + + # test no kill + expected_dict = {self.s1: [self.s2]} + crashed = pygame.sprite.groupcollide(self.ag, self.ag2, False, False) + + self.assertDictEqual(expected_dict, crashed) + + crashed = pygame.sprite.groupcollide(self.ag, self.ag2, False, False) + + self.assertDictEqual(expected_dict, crashed) + + # Test dokill2=True (kill colliding sprites in second group). + crashed = pygame.sprite.groupcollide(self.ag, self.ag2, False, True) + + self.assertDictEqual(expected_dict, crashed) + + expected_dict = {} + crashed = pygame.sprite.groupcollide(self.ag, self.ag2, False, False) + + self.assertDictEqual(expected_dict, crashed) + + # Test dokill1=True (kill colliding sprites in first group). + self.s3.rect.move_ip(-100, -100) + expected_dict = {self.s1: [self.s3]} + crashed = pygame.sprite.groupcollide(self.ag, self.ag2, True, False) + + self.assertDictEqual(expected_dict, crashed) + + expected_dict = {} + crashed = pygame.sprite.groupcollide(self.ag, self.ag2, False, False) + + self.assertDictEqual(expected_dict, crashed) + + def test_groupcollide__with_collided_callback(self): + + collided_callback_true = lambda spr_a, spr_b: True + collided_callback_false = lambda spr_a, spr_b: False + + # test no kill + expected_dict = {} + crashed = pygame.sprite.groupcollide( + self.ag, self.ag2, False, False, collided_callback_false + ) + + self.assertDictEqual(expected_dict, crashed) + + expected_dict = {self.s1: sorted(self.ag2.sprites(), key=id)} + crashed = pygame.sprite.groupcollide( + self.ag, self.ag2, False, False, collided_callback_true + ) + for value in crashed.values(): + value.sort(key=id) + + self.assertDictEqual(expected_dict, crashed) + + # expected_dict is the same again for this collide + crashed = pygame.sprite.groupcollide( + self.ag, self.ag2, False, False, collided_callback_true + ) + for value in crashed.values(): + value.sort(key=id) + + self.assertDictEqual(expected_dict, crashed) + + # Test dokill2=True (kill colliding sprites in second group). + expected_dict = {} + crashed = pygame.sprite.groupcollide( + self.ag, self.ag2, False, True, collided_callback_false + ) + + self.assertDictEqual(expected_dict, crashed) + + expected_dict = {self.s1: sorted(self.ag2.sprites(), key=id)} + crashed = pygame.sprite.groupcollide( + self.ag, self.ag2, False, True, collided_callback_true + ) + for value in crashed.values(): + value.sort(key=id) + + self.assertDictEqual(expected_dict, crashed) + + expected_dict = {} + crashed = pygame.sprite.groupcollide( + self.ag, self.ag2, False, True, collided_callback_true + ) + + self.assertDictEqual(expected_dict, crashed) + + # Test dokill1=True (kill colliding sprites in first group). + self.ag.add(self.s2) + self.ag2.add(self.s3) + expected_dict = {} + crashed = pygame.sprite.groupcollide( + self.ag, self.ag2, True, False, collided_callback_false + ) + + self.assertDictEqual(expected_dict, crashed) + + expected_dict = {self.s1: [self.s3], self.s2: [self.s3]} + crashed = pygame.sprite.groupcollide( + self.ag, self.ag2, True, False, collided_callback_true + ) + + self.assertDictEqual(expected_dict, crashed) + + expected_dict = {} + crashed = pygame.sprite.groupcollide( + self.ag, self.ag2, True, False, collided_callback_true + ) + + self.assertDictEqual(expected_dict, crashed) + + def test_collide_rect(self): + # Test colliding - some edges touching + self.assertTrue(pygame.sprite.collide_rect(self.s1, self.s2)) + self.assertTrue(pygame.sprite.collide_rect(self.s2, self.s1)) + + # Test colliding - all edges touching + self.s2.rect.center = self.s3.rect.center + + self.assertTrue(pygame.sprite.collide_rect(self.s2, self.s3)) + self.assertTrue(pygame.sprite.collide_rect(self.s3, self.s2)) + + # Test colliding - no edges touching + self.s2.rect.inflate_ip(10, 10) + + self.assertTrue(pygame.sprite.collide_rect(self.s2, self.s3)) + self.assertTrue(pygame.sprite.collide_rect(self.s3, self.s2)) + + # Test colliding - some edges intersecting + self.s2.rect.center = (self.s1.rect.right, self.s1.rect.bottom) + + self.assertTrue(pygame.sprite.collide_rect(self.s1, self.s2)) + self.assertTrue(pygame.sprite.collide_rect(self.s2, self.s1)) + + # Test not colliding + self.assertFalse(pygame.sprite.collide_rect(self.s1, self.s3)) + self.assertFalse(pygame.sprite.collide_rect(self.s3, self.s1)) + + +################################################################################ + + +class AbstractGroupTypeTest(unittest.TestCase): + def setUp(self): + self.ag = sprite.AbstractGroup() + self.ag2 = sprite.AbstractGroup() + self.s1 = sprite.Sprite(self.ag) + self.s2 = sprite.Sprite(self.ag) + self.s3 = sprite.Sprite(self.ag2) + self.s4 = sprite.Sprite(self.ag2) + + self.s1.image = pygame.Surface((10, 10)) + self.s1.image.fill(pygame.Color("red")) + self.s1.rect = self.s1.image.get_rect() + + self.s2.image = pygame.Surface((10, 10)) + self.s2.image.fill(pygame.Color("green")) + self.s2.rect = self.s2.image.get_rect() + self.s2.rect.left = 10 + + self.s3.image = pygame.Surface((10, 10)) + self.s3.image.fill(pygame.Color("blue")) + self.s3.rect = self.s3.image.get_rect() + self.s3.rect.top = 10 + + self.s4.image = pygame.Surface((10, 10)) + self.s4.image.fill(pygame.Color("white")) + self.s4.rect = self.s4.image.get_rect() + self.s4.rect.left = 10 + self.s4.rect.top = 10 + + self.bg = pygame.Surface((20, 20)) + self.scr = pygame.Surface((20, 20)) + self.scr.fill(pygame.Color("grey")) + + def test_has(self): + "See if AbstractGroup.has() works as expected." + + self.assertEqual(True, self.s1 in self.ag) + + self.assertEqual(True, self.ag.has(self.s1)) + + self.assertEqual(True, self.ag.has([self.s1, self.s2])) + + # see if one of them not being in there. + self.assertNotEqual(True, self.ag.has([self.s1, self.s2, self.s3])) + self.assertNotEqual(True, self.ag.has(self.s1, self.s2, self.s3)) + self.assertNotEqual(True, self.ag.has(self.s1, sprite.Group(self.s2, self.s3))) + self.assertNotEqual(True, self.ag.has(self.s1, [self.s2, self.s3])) + + # test empty list processing + self.assertFalse(self.ag.has(*[])) + self.assertFalse(self.ag.has([])) + self.assertFalse(self.ag.has([[]])) + + # see if a second AbstractGroup works. + self.assertEqual(True, self.ag2.has(self.s3)) + + def test_add(self): + ag3 = sprite.AbstractGroup() + sprites = (self.s1, self.s2, self.s3, self.s4) + + for s in sprites: + self.assertNotIn(s, ag3) + + ag3.add(self.s1, [self.s2], self.ag2) + + for s in sprites: + self.assertIn(s, ag3) + + def test_add_internal(self): + self.assertNotIn(self.s1, self.ag2) + + self.ag2.add_internal(self.s1) + + self.assertIn(self.s1, self.ag2) + + def test_clear(self): + + self.ag.draw(self.scr) + self.ag.clear(self.scr, self.bg) + self.assertEqual((0, 0, 0, 255), self.scr.get_at((5, 5))) + self.assertEqual((0, 0, 0, 255), self.scr.get_at((15, 5))) + + def test_draw(self): + + self.ag.draw(self.scr) + self.assertEqual((255, 0, 0, 255), self.scr.get_at((5, 5))) + self.assertEqual((0, 255, 0, 255), self.scr.get_at((15, 5))) + + self.assertEqual(self.ag.spritedict[self.s1], pygame.Rect(0, 0, 10, 10)) + self.assertEqual(self.ag.spritedict[self.s2], pygame.Rect(10, 0, 10, 10)) + + def test_empty(self): + + self.ag.empty() + self.assertFalse(self.s1 in self.ag) + self.assertFalse(self.s2 in self.ag) + + def test_has_internal(self): + self.assertTrue(self.ag.has_internal(self.s1)) + self.assertFalse(self.ag.has_internal(self.s3)) + + def test_remove(self): + + # Test removal of 1 sprite + self.ag.remove(self.s1) + self.assertFalse(self.ag in self.s1.groups()) + self.assertFalse(self.ag.has(self.s1)) + + # Test removal of 2 sprites as 2 arguments + self.ag2.remove(self.s3, self.s4) + self.assertFalse(self.ag2 in self.s3.groups()) + self.assertFalse(self.ag2 in self.s4.groups()) + self.assertFalse(self.ag2.has(self.s3, self.s4)) + + # Test removal of 4 sprites as a list containing a sprite and a group + # containing a sprite and another group containing 2 sprites. + self.ag.add(self.s1, self.s3, self.s4) + self.ag2.add(self.s3, self.s4) + g = sprite.Group(self.s2) + self.ag.remove([self.s1, g], self.ag2) + self.assertFalse(self.ag in self.s1.groups()) + self.assertFalse(self.ag in self.s2.groups()) + self.assertFalse(self.ag in self.s3.groups()) + self.assertFalse(self.ag in self.s4.groups()) + self.assertFalse(self.ag.has(self.s1, self.s2, self.s3, self.s4)) + + def test_remove_internal(self): + + self.ag.remove_internal(self.s1) + self.assertFalse(self.ag.has_internal(self.s1)) + + def test_sprites(self): + expected_sprites = sorted((self.s1, self.s2), key=id) + sprite_list = sorted(self.ag.sprites(), key=id) + + self.assertListEqual(sprite_list, expected_sprites) + + def test_update(self): + class test_sprite(pygame.sprite.Sprite): + sink = [] + + def __init__(self, *groups): + pygame.sprite.Sprite.__init__(self, *groups) + + def update(self, *args): + self.sink += args + + s = test_sprite(self.ag) + self.ag.update(1, 2, 3) + + self.assertEqual(test_sprite.sink, [1, 2, 3]) + + def test_update_with_kwargs(self): + class test_sprite(pygame.sprite.Sprite): + sink = [] + sink_kwargs = {} + + def __init__(self, *groups): + pygame.sprite.Sprite.__init__(self, *groups) + + def update(self, *args, **kwargs): + self.sink += args + self.sink_kwargs.update(kwargs) + + s = test_sprite(self.ag) + self.ag.update(1, 2, 3, foo=4, bar=5) + + self.assertEqual(test_sprite.sink, [1, 2, 3]) + self.assertEqual(test_sprite.sink_kwargs, {"foo": 4, "bar": 5}) + + +################################################################################ + +# A base class to share tests between similar classes + + +class LayeredGroupBase: + def test_get_layer_of_sprite(self): + expected_layer = 666 + spr = self.sprite() + self.LG.add(spr, layer=expected_layer) + layer = self.LG.get_layer_of_sprite(spr) + + self.assertEqual(len(self.LG._spritelist), 1) + self.assertEqual(layer, self.LG.get_layer_of_sprite(spr)) + self.assertEqual(layer, expected_layer) + self.assertEqual(layer, self.LG._spritelayers[spr]) + + def test_add(self): + expected_layer = self.LG._default_layer + spr = self.sprite() + self.LG.add(spr) + layer = self.LG.get_layer_of_sprite(spr) + + self.assertEqual(len(self.LG._spritelist), 1) + self.assertEqual(layer, expected_layer) + + def test_add__sprite_with_layer_attribute(self): + expected_layer = 100 + spr = self.sprite() + spr._layer = expected_layer + self.LG.add(spr) + layer = self.LG.get_layer_of_sprite(spr) + + self.assertEqual(len(self.LG._spritelist), 1) + self.assertEqual(layer, expected_layer) + + def test_add__passing_layer_keyword(self): + expected_layer = 100 + spr = self.sprite() + self.LG.add(spr, layer=expected_layer) + layer = self.LG.get_layer_of_sprite(spr) + + self.assertEqual(len(self.LG._spritelist), 1) + self.assertEqual(layer, expected_layer) + + def test_add__overriding_sprite_layer_attr(self): + expected_layer = 200 + spr = self.sprite() + spr._layer = 100 + self.LG.add(spr, layer=expected_layer) + layer = self.LG.get_layer_of_sprite(spr) + + self.assertEqual(len(self.LG._spritelist), 1) + self.assertEqual(layer, expected_layer) + + def test_add__adding_sprite_on_init(self): + spr = self.sprite() + lrg2 = sprite.LayeredUpdates(spr) + expected_layer = lrg2._default_layer + layer = lrg2._spritelayers[spr] + + self.assertEqual(len(lrg2._spritelist), 1) + self.assertEqual(layer, expected_layer) + + def test_add__sprite_init_layer_attr(self): + expected_layer = 20 + spr = self.sprite() + spr._layer = expected_layer + lrg2 = sprite.LayeredUpdates(spr) + layer = lrg2._spritelayers[spr] + + self.assertEqual(len(lrg2._spritelist), 1) + self.assertEqual(layer, expected_layer) + + def test_add__sprite_init_passing_layer(self): + expected_layer = 33 + spr = self.sprite() + lrg2 = sprite.LayeredUpdates(spr, layer=expected_layer) + layer = lrg2._spritelayers[spr] + + self.assertEqual(len(lrg2._spritelist), 1) + self.assertEqual(layer, expected_layer) + + def test_add__sprite_init_overiding_layer(self): + expected_layer = 33 + spr = self.sprite() + spr._layer = 55 + lrg2 = sprite.LayeredUpdates(spr, layer=expected_layer) + layer = lrg2._spritelayers[spr] + + self.assertEqual(len(lrg2._spritelist), 1) + self.assertEqual(layer, expected_layer) + + def test_add__spritelist(self): + expected_layer = self.LG._default_layer + sprite_count = 10 + sprites = [self.sprite() for _ in range(sprite_count)] + + self.LG.add(sprites) + + self.assertEqual(len(self.LG._spritelist), sprite_count) + + for i in range(sprite_count): + layer = self.LG.get_layer_of_sprite(sprites[i]) + + self.assertEqual(layer, expected_layer) + + def test_add__spritelist_with_layer_attr(self): + sprites = [] + sprite_and_layer_count = 10 + for i in range(sprite_and_layer_count): + sprites.append(self.sprite()) + sprites[-1]._layer = i + + self.LG.add(sprites) + + self.assertEqual(len(self.LG._spritelist), sprite_and_layer_count) + + for i in range(sprite_and_layer_count): + layer = self.LG.get_layer_of_sprite(sprites[i]) + + self.assertEqual(layer, i) + + def test_add__spritelist_passing_layer(self): + expected_layer = 33 + sprite_count = 10 + sprites = [self.sprite() for _ in range(sprite_count)] + + self.LG.add(sprites, layer=expected_layer) + + self.assertEqual(len(self.LG._spritelist), sprite_count) + + for i in range(sprite_count): + layer = self.LG.get_layer_of_sprite(sprites[i]) + + self.assertEqual(layer, expected_layer) + + def test_add__spritelist_overriding_layer(self): + expected_layer = 33 + sprites = [] + sprite_and_layer_count = 10 + for i in range(sprite_and_layer_count): + sprites.append(self.sprite()) + sprites[-1].layer = i + + self.LG.add(sprites, layer=expected_layer) + + self.assertEqual(len(self.LG._spritelist), sprite_and_layer_count) + + for i in range(sprite_and_layer_count): + layer = self.LG.get_layer_of_sprite(sprites[i]) + + self.assertEqual(layer, expected_layer) + + def test_add__spritelist_init(self): + sprite_count = 10 + sprites = [self.sprite() for _ in range(sprite_count)] + + lrg2 = sprite.LayeredUpdates(sprites) + expected_layer = lrg2._default_layer + + self.assertEqual(len(lrg2._spritelist), sprite_count) + + for i in range(sprite_count): + layer = lrg2.get_layer_of_sprite(sprites[i]) + + self.assertEqual(layer, expected_layer) + + def test_remove__sprite(self): + sprites = [] + sprite_count = 10 + for i in range(sprite_count): + sprites.append(self.sprite()) + sprites[-1].rect = pygame.Rect((0, 0, 0, 0)) + + self.LG.add(sprites) + + self.assertEqual(len(self.LG._spritelist), sprite_count) + + for i in range(sprite_count): + self.LG.remove(sprites[i]) + + self.assertEqual(len(self.LG._spritelist), 0) + + def test_sprites(self): + sprites = [] + sprite_and_layer_count = 10 + for i in range(sprite_and_layer_count, 0, -1): + sprites.append(self.sprite()) + sprites[-1]._layer = i + + self.LG.add(sprites) + + self.assertEqual(len(self.LG._spritelist), sprite_and_layer_count) + + # Sprites should be ordered based on their layer (bottom to top), + # which is the reverse order of the sprites list. + expected_sprites = list(reversed(sprites)) + actual_sprites = self.LG.sprites() + + self.assertListEqual(actual_sprites, expected_sprites) + + def test_layers(self): + sprites = [] + expected_layers = [] + layer_count = 10 + for i in range(layer_count): + expected_layers.append(i) + for j in range(5): + sprites.append(self.sprite()) + sprites[-1]._layer = i + self.LG.add(sprites) + + layers = self.LG.layers() + + self.assertListEqual(layers, expected_layers) + + def test_add__layers_are_correct(self): + layers = [1, 4, 6, 8, 3, 6, 2, 6, 4, 5, 6, 1, 0, 9, 7, 6, 54, 8, 2, 43, 6, 1] + for lay in layers: + self.LG.add(self.sprite(), layer=lay) + layers.sort() + + for idx, spr in enumerate(self.LG.sprites()): + layer = self.LG.get_layer_of_sprite(spr) + + self.assertEqual(layer, layers[idx]) + + def test_change_layer(self): + expected_layer = 99 + spr = self.sprite() + self.LG.add(spr, layer=expected_layer) + + self.assertEqual(self.LG._spritelayers[spr], expected_layer) + + expected_layer = 44 + self.LG.change_layer(spr, expected_layer) + + self.assertEqual(self.LG._spritelayers[spr], expected_layer) + + expected_layer = 77 + spr2 = self.sprite() + spr2.layer = 55 + self.LG.add(spr2) + self.LG.change_layer(spr2, expected_layer) + + self.assertEqual(spr2.layer, expected_layer) + + def test_get_sprites_at(self): + sprites = [] + expected_sprites = [] + for i in range(3): + spr = self.sprite() + spr.rect = pygame.Rect(i * 50, i * 50, 100, 100) + sprites.append(spr) + if i < 2: + expected_sprites.append(spr) + self.LG.add(sprites) + result = self.LG.get_sprites_at((50, 50)) + self.assertEqual(result, expected_sprites) + + def test_get_top_layer(self): + layers = [1, 5, 2, 8, 4, 5, 3, 88, 23, 0] + for i in layers: + self.LG.add(self.sprite(), layer=i) + top_layer = self.LG.get_top_layer() + + self.assertEqual(top_layer, self.LG.get_top_layer()) + self.assertEqual(top_layer, max(layers)) + self.assertEqual(top_layer, max(self.LG._spritelayers.values())) + self.assertEqual(top_layer, self.LG._spritelayers[self.LG._spritelist[-1]]) + + def test_get_bottom_layer(self): + layers = [1, 5, 2, 8, 4, 5, 3, 88, 23, 0] + for i in layers: + self.LG.add(self.sprite(), layer=i) + bottom_layer = self.LG.get_bottom_layer() + + self.assertEqual(bottom_layer, self.LG.get_bottom_layer()) + self.assertEqual(bottom_layer, min(layers)) + self.assertEqual(bottom_layer, min(self.LG._spritelayers.values())) + self.assertEqual(bottom_layer, self.LG._spritelayers[self.LG._spritelist[0]]) + + def test_move_to_front(self): + layers = [1, 5, 2, 8, 4, 5, 3, 88, 23, 0] + for i in layers: + self.LG.add(self.sprite(), layer=i) + spr = self.sprite() + self.LG.add(spr, layer=3) + + self.assertNotEqual(spr, self.LG._spritelist[-1]) + + self.LG.move_to_front(spr) + + self.assertEqual(spr, self.LG._spritelist[-1]) + + def test_move_to_back(self): + layers = [1, 5, 2, 8, 4, 5, 3, 88, 23, 0] + for i in layers: + self.LG.add(self.sprite(), layer=i) + spr = self.sprite() + self.LG.add(spr, layer=55) + + self.assertNotEqual(spr, self.LG._spritelist[0]) + + self.LG.move_to_back(spr) + + self.assertEqual(spr, self.LG._spritelist[0]) + + def test_get_top_sprite(self): + layers = [1, 5, 2, 8, 4, 5, 3, 88, 23, 0] + for i in layers: + self.LG.add(self.sprite(), layer=i) + expected_layer = self.LG.get_top_layer() + layer = self.LG.get_layer_of_sprite(self.LG.get_top_sprite()) + + self.assertEqual(layer, expected_layer) + + def test_get_sprites_from_layer(self): + sprites = {} + layers = [ + 1, + 4, + 5, + 6, + 3, + 7, + 8, + 2, + 1, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 0, + 1, + 6, + 5, + 4, + 3, + 2, + ] + for lay in layers: + spr = self.sprite() + spr._layer = lay + self.LG.add(spr) + if lay not in sprites: + sprites[lay] = [] + sprites[lay].append(spr) + + for lay in self.LG.layers(): + for spr in self.LG.get_sprites_from_layer(lay): + self.assertIn(spr, sprites[lay]) + + sprites[lay].remove(spr) + if len(sprites[lay]) == 0: + del sprites[lay] + + self.assertEqual(len(sprites.values()), 0) + + def test_switch_layer(self): + sprites1 = [] + sprites2 = [] + layers = [3, 2, 3, 2, 3, 3, 2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 2, 2, 3, 2, 3] + for lay in layers: + spr = self.sprite() + spr._layer = lay + self.LG.add(spr) + if lay == 2: + sprites1.append(spr) + else: + sprites2.append(spr) + + sprites1.sort(key=id) + sprites2.sort(key=id) + layer2_sprites = sorted(self.LG.get_sprites_from_layer(2), key=id) + layer3_sprites = sorted(self.LG.get_sprites_from_layer(3), key=id) + + self.assertListEqual(sprites1, layer2_sprites) + self.assertListEqual(sprites2, layer3_sprites) + self.assertEqual(len(self.LG), len(sprites1) + len(sprites2)) + + self.LG.switch_layer(2, 3) + layer2_sprites = sorted(self.LG.get_sprites_from_layer(2), key=id) + layer3_sprites = sorted(self.LG.get_sprites_from_layer(3), key=id) + + self.assertListEqual(sprites1, layer3_sprites) + self.assertListEqual(sprites2, layer2_sprites) + self.assertEqual(len(self.LG), len(sprites1) + len(sprites2)) + + def test_copy(self): + self.LG.add(self.sprite()) + spr = self.LG.sprites()[0] + lg_copy = self.LG.copy() + + self.assertIsInstance(lg_copy, type(self.LG)) + self.assertIn(spr, lg_copy) + self.assertIn(lg_copy, spr.groups()) + + +########################## LAYERED RENDER GROUP TESTS ########################## + + +class LayeredUpdatesTypeTest__SpriteTest(LayeredGroupBase, unittest.TestCase): + sprite = sprite.Sprite + + def setUp(self): + self.LG = sprite.LayeredUpdates() + + +class LayeredUpdatesTypeTest__DirtySprite(LayeredGroupBase, unittest.TestCase): + sprite = sprite.DirtySprite + + def setUp(self): + self.LG = sprite.LayeredUpdates() + + +class LayeredDirtyTypeTest__DirtySprite(LayeredGroupBase, unittest.TestCase): + sprite = sprite.DirtySprite + + def setUp(self): + self.LG = sprite.LayeredDirty() + + def test_repaint_rect(self): + group = self.LG + surface = pygame.Surface((100, 100)) + + group.repaint_rect(pygame.Rect(0, 0, 100, 100)) + group.draw(surface) + + def test_repaint_rect_with_clip(self): + group = self.LG + surface = pygame.Surface((100, 100)) + + group.set_clip(pygame.Rect(0, 0, 100, 100)) + group.repaint_rect(pygame.Rect(0, 0, 100, 100)) + group.draw(surface) + + def _nondirty_intersections_redrawn(self, use_source_rect=False): + # Helper method to ensure non-dirty sprites are redrawn correctly. + # + # Parameters: + # use_source_rect - allows non-dirty sprites to be tested + # with (True) and without (False) a source_rect + # + # This test was written to reproduce the behavior seen in issue #898. + # A non-dirty sprite (using source_rect) was being redrawn incorrectly + # after a dirty sprite intersected with it. + # + # This test does the following. + # 1. Creates a surface filled with white. Also creates an image_source + # with a default fill color of yellow and adds 2 images to it + # (red and blue rectangles). + # 2. Creates 2 DirtySprites (red_sprite and blue_sprite) using the + # image_source and adds them to a LayeredDirty group. + # 3. Moves the red_sprite and calls LayeredDirty.draw(surface) a few + # times. + # 4. Checks to make sure the sprites were redrawn correctly. + RED = pygame.Color("red") + BLUE = pygame.Color("blue") + WHITE = pygame.Color("white") + YELLOW = pygame.Color("yellow") + + surface = pygame.Surface((60, 80)) + surface.fill(WHITE) + start_pos = (10, 10) + + # These rects define each sprite's image area in the image_source. + red_sprite_source = pygame.Rect((45, 0), (5, 4)) + blue_sprite_source = pygame.Rect((0, 40), (20, 10)) + + # Create a source image/surface. + image_source = pygame.Surface((50, 50)) + image_source.fill(YELLOW) + image_source.fill(RED, red_sprite_source) + image_source.fill(BLUE, blue_sprite_source) + + # The blue_sprite is stationary and will not reset its dirty flag. It + # will be the non-dirty sprite in this test. Its values are dependent + # on the use_source_rect flag. + blue_sprite = pygame.sprite.DirtySprite(self.LG) + + if use_source_rect: + blue_sprite.image = image_source + # The rect is a bit smaller than the source_rect to make sure + # LayeredDirty.draw() is using the correct dimensions. + blue_sprite.rect = pygame.Rect( + start_pos, (blue_sprite_source.w - 7, blue_sprite_source.h - 7) + ) + blue_sprite.source_rect = blue_sprite_source + start_x, start_y = blue_sprite.rect.topleft + end_x = start_x + blue_sprite.source_rect.w + end_y = start_y + blue_sprite.source_rect.h + else: + blue_sprite.image = image_source.subsurface(blue_sprite_source) + blue_sprite.rect = pygame.Rect(start_pos, blue_sprite_source.size) + start_x, start_y = blue_sprite.rect.topleft + end_x, end_y = blue_sprite.rect.bottomright + + # The red_sprite is moving and will always be dirty. + red_sprite = pygame.sprite.DirtySprite(self.LG) + red_sprite.image = image_source + red_sprite.rect = pygame.Rect(start_pos, red_sprite_source.size) + red_sprite.source_rect = red_sprite_source + red_sprite.dirty = 2 + + # Draw the red_sprite as it moves a few steps. + for _ in range(4): + red_sprite.rect.move_ip(2, 1) + + # This is the method being tested. + self.LG.draw(surface) + + # Check colors where the blue_sprite is drawn. We expect red where the + # red_sprite is drawn over the blue_sprite, but the rest should be + # blue. + surface.lock() # Lock surface for possible speed up. + try: + for y in range(start_y, end_y): + for x in range(start_x, end_x): + if red_sprite.rect.collidepoint(x, y): + expected_color = RED + else: + expected_color = BLUE + + color = surface.get_at((x, y)) + + self.assertEqual(color, expected_color, "pos=({}, {})".format(x, y)) + finally: + surface.unlock() + + def test_nondirty_intersections_redrawn(self): + """Ensure non-dirty sprites are correctly redrawn + when dirty sprites intersect with them. + """ + self._nondirty_intersections_redrawn() + + def test_nondirty_intersections_redrawn__with_source_rect(self): + """Ensure non-dirty sprites using source_rects are correctly redrawn + when dirty sprites intersect with them. + + Related to issue #898. + """ + self._nondirty_intersections_redrawn(True) + + +############################### SPRITE BASE CLASS ############################## +# +# tests common between sprite classes + + +class SpriteBase: + def setUp(self): + self.groups = [] + for Group in self.Groups: + self.groups.append(Group()) + + self.sprite = self.Sprite() + + def test_add_internal(self): + + for g in self.groups: + self.sprite.add_internal(g) + + for g in self.groups: + self.assertIn(g, self.sprite.groups()) + + def test_remove_internal(self): + + for g in self.groups: + self.sprite.add_internal(g) + + for g in self.groups: + self.sprite.remove_internal(g) + + for g in self.groups: + self.assertFalse(g in self.sprite.groups()) + + def test_update(self): + class test_sprite(pygame.sprite.Sprite): + sink = [] + + def __init__(self, *groups): + pygame.sprite.Sprite.__init__(self, *groups) + + def update(self, *args): + self.sink += args + + s = test_sprite() + s.update(1, 2, 3) + + self.assertEqual(test_sprite.sink, [1, 2, 3]) + + def test_update_with_kwargs(self): + class test_sprite(pygame.sprite.Sprite): + sink = [] + sink_dict = {} + + def __init__(self, *groups): + pygame.sprite.Sprite.__init__(self, *groups) + + def update(self, *args, **kwargs): + self.sink += args + self.sink_dict.update(kwargs) + + s = test_sprite() + s.update(1, 2, 3, foo=4, bar=5) + + self.assertEqual(test_sprite.sink, [1, 2, 3]) + self.assertEqual(test_sprite.sink_dict, {"foo": 4, "bar": 5}) + + def test___init____added_to_groups_passed(self): + expected_groups = sorted(self.groups, key=id) + sprite = self.Sprite(self.groups) + groups = sorted(sprite.groups(), key=id) + + self.assertListEqual(groups, expected_groups) + + def test_add(self): + expected_groups = sorted(self.groups, key=id) + self.sprite.add(self.groups) + groups = sorted(self.sprite.groups(), key=id) + + self.assertListEqual(groups, expected_groups) + + def test_alive(self): + self.assertFalse( + self.sprite.alive(), "Sprite should not be alive if in no groups" + ) + + self.sprite.add(self.groups) + + self.assertTrue(self.sprite.alive()) + + def test_groups(self): + for i, g in enumerate(self.groups): + expected_groups = sorted(self.groups[: i + 1], key=id) + self.sprite.add(g) + groups = sorted(self.sprite.groups(), key=id) + + self.assertListEqual(groups, expected_groups) + + def test_kill(self): + self.sprite.add(self.groups) + + self.assertTrue(self.sprite.alive()) + + self.sprite.kill() + + self.assertListEqual(self.sprite.groups(), []) + self.assertFalse(self.sprite.alive()) + + def test_remove(self): + self.sprite.add(self.groups) + self.sprite.remove(self.groups) + + self.assertListEqual(self.sprite.groups(), []) + + +############################## SPRITE CLASS TESTS ############################## + + +class SpriteTypeTest(SpriteBase, unittest.TestCase): + Sprite = sprite.Sprite + + Groups = [ + sprite.Group, + sprite.LayeredUpdates, + sprite.RenderUpdates, + sprite.OrderedUpdates, + ] + + +class DirtySpriteTypeTest(SpriteBase, unittest.TestCase): + Sprite = sprite.DirtySprite + + Groups = [ + sprite.Group, + sprite.LayeredUpdates, + sprite.RenderUpdates, + sprite.OrderedUpdates, + sprite.LayeredDirty, + ] + + +############################## BUG TESTS ####################################### + + +class SingleGroupBugsTest(unittest.TestCase): + def test_memoryleak_bug(self): + # For memoryleak bug posted to mailing list by Tobias Steinrücken on 16/11/10. + # Fixed in revision 2953. + + import weakref + import gc + + class MySprite(sprite.Sprite): + def __init__(self, *args, **kwargs): + sprite.Sprite.__init__(self, *args, **kwargs) + self.image = pygame.Surface((2, 4), 0, 24) + self.rect = self.image.get_rect() + + g = sprite.GroupSingle() + screen = pygame.Surface((4, 8), 0, 24) + s = MySprite() + r = weakref.ref(s) + g.sprite = s + del s + gc.collect() + + self.assertIsNotNone(r()) + + g.update() + g.draw(screen) + g.sprite = MySprite() + gc.collect() + + self.assertIsNone(r()) + + +################################################################################ + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/surface_test.py b/venv/Lib/site-packages/pygame/tests/surface_test.py new file mode 100644 index 0000000..ab9b0e6 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/surface_test.py @@ -0,0 +1,4015 @@ +import os +import unittest +from pygame.tests import test_utils +from pygame.tests.test_utils import ( + example_path, + AssertRaisesRegexMixin, + SurfaceSubclass, +) + +try: + from pygame.tests.test_utils.arrinter import * +except (ImportError, NameError): + pass +import pygame +from pygame.locals import * +from pygame.bufferproxy import BufferProxy + +import platform +import gc +import weakref +import ctypes + +IS_PYPY = "PyPy" == platform.python_implementation() + + +class SurfaceTypeTest(AssertRaisesRegexMixin, unittest.TestCase): + def test_surface__pixel_format_as_surface_subclass(self): + """Ensure a subclassed surface can be used for pixel format + when creating a new surface.""" + expected_depth = 16 + expected_flags = SRCALPHA + expected_size = (13, 37) + depth_surface = SurfaceSubclass((11, 21), expected_flags, expected_depth) + + surface = pygame.Surface(expected_size, expected_flags, depth_surface) + + self.assertIsNot(surface, depth_surface) + self.assertIsInstance(surface, pygame.Surface) + self.assertNotIsInstance(surface, SurfaceSubclass) + self.assertEqual(surface.get_size(), expected_size) + self.assertEqual(surface.get_flags(), expected_flags) + self.assertEqual(surface.get_bitsize(), expected_depth) + + def test_set_clip(self): + """see if surface.set_clip(None) works correctly.""" + s = pygame.Surface((800, 600)) + r = pygame.Rect(10, 10, 10, 10) + s.set_clip(r) + r.move_ip(10, 0) + s.set_clip(None) + res = s.get_clip() + # this was garbled before. + self.assertEqual(res[0], 0) + self.assertEqual(res[2], 800) + + def test_print(self): + surf = pygame.Surface((70, 70), 0, 32) + self.assertEqual(repr(surf), "") + + def test_keyword_arguments(self): + surf = pygame.Surface((70, 70), flags=SRCALPHA, depth=32) + self.assertEqual(surf.get_flags() & SRCALPHA, SRCALPHA) + self.assertEqual(surf.get_bitsize(), 32) + + # sanity check to make sure the check below is valid + surf_16 = pygame.Surface((70, 70), 0, 16) + self.assertEqual(surf_16.get_bytesize(), 2) + + # try again with an argument list + surf_16 = pygame.Surface((70, 70), depth=16) + self.assertEqual(surf_16.get_bytesize(), 2) + + def test_set_at(self): + + # 24bit surfaces + s = pygame.Surface((100, 100), 0, 24) + s.fill((0, 0, 0)) + + # set it with a tuple. + s.set_at((0, 0), (10, 10, 10, 255)) + r = s.get_at((0, 0)) + self.assertIsInstance(r, pygame.Color) + self.assertEqual(r, (10, 10, 10, 255)) + + # try setting a color with a single integer. + s.fill((0, 0, 0, 255)) + s.set_at((10, 1), 0x0000FF) + r = s.get_at((10, 1)) + self.assertEqual(r, (0, 0, 255, 255)) + + def test_set_at__big_endian(self): + """png files are loaded in big endian format (BGR rather than RGB)""" + pygame.display.init() + try: + image = pygame.image.load(example_path(os.path.join("data", "BGR.png"))) + # Check they start red, green and blue + self.assertEqual(image.get_at((10, 10)), pygame.Color(255, 0, 0)) + self.assertEqual(image.get_at((10, 20)), pygame.Color(0, 255, 0)) + self.assertEqual(image.get_at((10, 40)), pygame.Color(0, 0, 255)) + # Set three pixels that are already red, green, blue + # to red, green and, blue with set_at: + image.set_at((10, 10), pygame.Color(255, 0, 0)) + image.set_at((10, 20), pygame.Color(0, 255, 0)) + image.set_at((10, 40), pygame.Color(0, 0, 255)) + + # Check they still are + self.assertEqual(image.get_at((10, 10)), pygame.Color(255, 0, 0)) + self.assertEqual(image.get_at((10, 20)), pygame.Color(0, 255, 0)) + self.assertEqual(image.get_at((10, 40)), pygame.Color(0, 0, 255)) + + finally: + pygame.display.quit() + + def test_SRCALPHA(self): + # has the flag been passed in ok? + surf = pygame.Surface((70, 70), SRCALPHA, 32) + self.assertEqual(surf.get_flags() & SRCALPHA, SRCALPHA) + + # 24bit surfaces can not have SRCALPHA. + self.assertRaises(ValueError, pygame.Surface, (100, 100), pygame.SRCALPHA, 24) + + # if we have a 32 bit surface, the SRCALPHA should have worked too. + surf2 = pygame.Surface((70, 70), SRCALPHA) + if surf2.get_bitsize() == 32: + self.assertEqual(surf2.get_flags() & SRCALPHA, SRCALPHA) + + def test_flags_default0_nodisplay(self): + """is set to zero, and SRCALPH is not set by default with no display initialized.""" + pygame.display.quit() + surf = pygame.Surface((70, 70)) + self.assertEqual(surf.get_flags() & SRCALPHA, 0) + + def test_flags_default0_display(self): + """is set to zero, and SRCALPH is not set by default even when the display is initialized.""" + pygame.display.set_mode((320, 200)) + try: + surf = pygame.Surface((70, 70)) + self.assertEqual(surf.get_flags() & SRCALPHA, 0) + finally: + pygame.display.quit() + + def test_masks(self): + def make_surf(bpp, flags, masks): + pygame.Surface((10, 10), flags, bpp, masks) + + # With some masks SDL_CreateRGBSurface does not work properly. + masks = (0xFF000000, 0xFF0000, 0xFF00, 0) + self.assertEqual(make_surf(32, 0, masks), None) + # For 24 and 32 bit surfaces Pygame assumes no losses. + masks = (0x7F0000, 0xFF00, 0xFF, 0) + self.assertRaises(ValueError, make_surf, 24, 0, masks) + self.assertRaises(ValueError, make_surf, 32, 0, masks) + # What contiguous bits in a mask. + masks = (0x6F0000, 0xFF00, 0xFF, 0) + self.assertRaises(ValueError, make_surf, 32, 0, masks) + + def test_get_bounding_rect(self): + surf = pygame.Surface((70, 70), SRCALPHA, 32) + surf.fill((0, 0, 0, 0)) + bound_rect = surf.get_bounding_rect() + self.assertEqual(bound_rect.width, 0) + self.assertEqual(bound_rect.height, 0) + surf.set_at((30, 30), (255, 255, 255, 1)) + bound_rect = surf.get_bounding_rect() + self.assertEqual(bound_rect.left, 30) + self.assertEqual(bound_rect.top, 30) + self.assertEqual(bound_rect.width, 1) + self.assertEqual(bound_rect.height, 1) + surf.set_at((29, 29), (255, 255, 255, 1)) + bound_rect = surf.get_bounding_rect() + self.assertEqual(bound_rect.left, 29) + self.assertEqual(bound_rect.top, 29) + self.assertEqual(bound_rect.width, 2) + self.assertEqual(bound_rect.height, 2) + + surf = pygame.Surface((70, 70), 0, 24) + surf.fill((0, 0, 0)) + bound_rect = surf.get_bounding_rect() + self.assertEqual(bound_rect.width, surf.get_width()) + self.assertEqual(bound_rect.height, surf.get_height()) + + surf.set_colorkey((0, 0, 0)) + bound_rect = surf.get_bounding_rect() + self.assertEqual(bound_rect.width, 0) + self.assertEqual(bound_rect.height, 0) + surf.set_at((30, 30), (255, 255, 255)) + bound_rect = surf.get_bounding_rect() + self.assertEqual(bound_rect.left, 30) + self.assertEqual(bound_rect.top, 30) + self.assertEqual(bound_rect.width, 1) + self.assertEqual(bound_rect.height, 1) + surf.set_at((60, 60), (255, 255, 255)) + bound_rect = surf.get_bounding_rect() + self.assertEqual(bound_rect.left, 30) + self.assertEqual(bound_rect.top, 30) + self.assertEqual(bound_rect.width, 31) + self.assertEqual(bound_rect.height, 31) + + # Issue #180 + pygame.display.init() + try: + surf = pygame.Surface((4, 1), 0, 8) + surf.fill((255, 255, 255)) + surf.get_bounding_rect() # Segfault. + finally: + pygame.display.quit() + + def test_copy(self): + """Ensure a surface can be copied.""" + color = (25, 25, 25, 25) + s1 = pygame.Surface((32, 32), pygame.SRCALPHA, 32) + s1.fill(color) + + s2 = s1.copy() + + s1rect = s1.get_rect() + s2rect = s2.get_rect() + + self.assertEqual(s1rect.size, s2rect.size) + self.assertEqual(s2.get_at((10, 10)), color) + + def test_fill(self): + """Ensure a surface can be filled.""" + color = (25, 25, 25, 25) + fill_rect = pygame.Rect(0, 0, 16, 16) + s1 = pygame.Surface((32, 32), pygame.SRCALPHA, 32) + s1.fill(color, fill_rect) + + for pt in test_utils.rect_area_pts(fill_rect): + self.assertEqual(s1.get_at(pt), color) + + for pt in test_utils.rect_outer_bounds(fill_rect): + self.assertNotEqual(s1.get_at(pt), color) + + def test_fill_rle(self): + """Test RLEACCEL flag with fill()""" + color = (250, 25, 25, 255) + + surf = pygame.Surface((32, 32)) + blit_surf = pygame.Surface((32, 32)) + + blit_surf.set_colorkey((255, 0, 255), pygame.RLEACCEL) + self.assertTrue(blit_surf.get_flags() & pygame.RLEACCELOK) + surf.blit(blit_surf, (0, 0)) + blit_surf.fill(color) + self.assertEqual( + blit_surf.mustlock(), (blit_surf.get_flags() & pygame.RLEACCEL) != 0 + ) + self.assertTrue(blit_surf.get_flags() & pygame.RLEACCEL) + + def test_mustlock_rle(self): + """Test RLEACCEL flag with mustlock()""" + surf = pygame.Surface((100, 100)) + blit_surf = pygame.Surface((100, 100)) + blit_surf.set_colorkey((0, 0, 255), pygame.RLEACCEL) + self.assertTrue(blit_surf.get_flags() & pygame.RLEACCELOK) + surf.blit(blit_surf, (0, 0)) + self.assertTrue(blit_surf.get_flags() & pygame.RLEACCEL) + self.assertTrue(blit_surf.mustlock()) + + def test_mustlock_surf_alpha_rle(self): + """Test RLEACCEL flag with mustlock() on a surface + with per pixel alpha - new feature in SDL2""" + surf = pygame.Surface((100, 100)) + blit_surf = pygame.Surface((100, 100), depth=32, flags=pygame.SRCALPHA) + blit_surf.set_colorkey((192, 191, 192, 255), pygame.RLEACCEL) + self.assertTrue(blit_surf.get_flags() & pygame.RLEACCELOK) + surf.blit(blit_surf, (0, 0)) + self.assertTrue(blit_surf.get_flags() & pygame.RLEACCEL) + self.assertTrue(blit_surf.get_flags() & pygame.SRCALPHA) + self.assertTrue(blit_surf.mustlock()) + + def test_copy_rle(self): + """Test copying a surface set to use run length encoding""" + s1 = pygame.Surface((32, 32), 24) + s1.set_colorkey((255, 0, 255), pygame.RLEACCEL) + self.assertTrue(s1.get_flags() & pygame.RLEACCELOK) + + newsurf = s1.copy() + self.assertTrue(s1.get_flags() & pygame.RLEACCELOK) + self.assertTrue(newsurf.get_flags() & pygame.RLEACCELOK) + + def test_subsurface_rle(self): + """Ensure an RLE sub-surface works independently of its parent.""" + color = (250, 25, 25, 255) + color2 = (200, 200, 250, 255) + sub_rect = pygame.Rect(16, 16, 16, 16) + s0 = pygame.Surface((32, 32), 24) + s1 = pygame.Surface((32, 32), 24) + s1.set_colorkey((255, 0, 255), pygame.RLEACCEL) + s1.fill(color) + s2 = s1.subsurface(sub_rect) + s2.fill(color2) + s0.blit(s1, (0, 0)) + self.assertTrue(s1.get_flags() & pygame.RLEACCEL) + self.assertTrue(not s2.get_flags() & pygame.RLEACCEL) + + def test_subsurface_rle2(self): + """Ensure an RLE sub-surface works independently of its parent.""" + color = (250, 25, 25, 255) + color2 = (200, 200, 250, 255) + sub_rect = pygame.Rect(16, 16, 16, 16) + + s0 = pygame.Surface((32, 32), 24) + s1 = pygame.Surface((32, 32), 24) + s1.set_colorkey((255, 0, 255), pygame.RLEACCEL) + s1.fill(color) + s2 = s1.subsurface(sub_rect) + s2.fill(color2) + s0.blit(s2, (0, 0)) + self.assertTrue(s1.get_flags() & pygame.RLEACCELOK) + self.assertTrue(not s2.get_flags() & pygame.RLEACCELOK) + + def test_solarwolf_rle_usage(self): + """Test for error/crash when calling set_colorkey() followed + by convert twice in succession. Code originally taken + from solarwolf.""" + + def optimize(img): + clear = img.get_colorkey() + img.set_colorkey(clear, RLEACCEL) + self.assertEqual(img.get_colorkey(), clear) + return img.convert() + + pygame.display.init() + try: + pygame.display.set_mode((640, 480)) + + image = pygame.image.load(example_path(os.path.join("data", "alien1.png"))) + image = image.convert() + orig_colorkey = image.get_colorkey() + + image = optimize(image) + image = optimize(image) + self.assertTrue(image.get_flags() & pygame.RLEACCELOK) + self.assertTrue(not image.get_flags() & pygame.RLEACCEL) + self.assertEqual(image.get_colorkey(), orig_colorkey) + self.assertTrue(isinstance(image, pygame.Surface)) + finally: + pygame.display.quit() + + def test_solarwolf_rle_usage_2(self): + """Test for RLE status after setting alpha""" + + pygame.display.init() + try: + pygame.display.set_mode((640, 480), depth=32) + blit_to_surf = pygame.Surface((100, 100)) + + image = pygame.image.load(example_path(os.path.join("data", "alien1.png"))) + image = image.convert() + orig_colorkey = image.get_colorkey() + + # set the colorkey with RLEACCEL, should add the RLEACCELOK flag + image.set_colorkey(orig_colorkey, RLEACCEL) + self.assertTrue(image.get_flags() & pygame.RLEACCELOK) + self.assertTrue(not image.get_flags() & pygame.RLEACCEL) + + # now blit the surface - should add the RLEACCEL flag + blit_to_surf.blit(image, (0, 0)) + self.assertTrue(image.get_flags() & pygame.RLEACCELOK) + self.assertTrue(image.get_flags() & pygame.RLEACCEL) + + # Now set the alpha, without RLE acceleration - should strip all + # RLE flags + image.set_alpha(90) + self.assertTrue(not image.get_flags() & pygame.RLEACCELOK) + self.assertTrue(not image.get_flags() & pygame.RLEACCEL) + + finally: + pygame.display.quit() + + def test_set_alpha__set_colorkey_rle(self): + pygame.display.init() + try: + pygame.display.set_mode((640, 480)) + blit_to_surf = pygame.Surface((80, 71)) + blit_to_surf.fill((255, 255, 255)) + + image = pygame.image.load(example_path(os.path.join("data", "alien1.png"))) + image = image.convert() + orig_colorkey = image.get_colorkey() + + # Add the RLE flag while setting alpha for the whole surface + image.set_alpha(90, RLEACCEL) + blit_to_surf.blit(image, (0, 0)) + sample_pixel_rle = blit_to_surf.get_at((50, 50)) + + # Now reset the colorkey to the original value with RLE + self.assertEqual(image.get_colorkey(), orig_colorkey) + image.set_colorkey(orig_colorkey, RLEACCEL) + blit_to_surf.fill((255, 255, 255)) + blit_to_surf.blit(image, (0, 0)) + sample_pixel_no_rle = blit_to_surf.get_at((50, 50)) + + self.assertAlmostEqual(sample_pixel_rle.r, sample_pixel_no_rle.r, delta=2) + self.assertAlmostEqual(sample_pixel_rle.g, sample_pixel_no_rle.g, delta=2) + self.assertAlmostEqual(sample_pixel_rle.b, sample_pixel_no_rle.b, delta=2) + + finally: + pygame.display.quit() + + def test_fill_negative_coordinates(self): + + # negative coordinates should be clipped by fill, and not draw outside the surface. + color = (25, 25, 25, 25) + color2 = (20, 20, 20, 25) + fill_rect = pygame.Rect(-10, -10, 16, 16) + + s1 = pygame.Surface((32, 32), pygame.SRCALPHA, 32) + r1 = s1.fill(color, fill_rect) + c = s1.get_at((0, 0)) + self.assertEqual(c, color) + + # make subsurface in the middle to test it doesn't over write. + s2 = s1.subsurface((5, 5, 5, 5)) + r2 = s2.fill(color2, (-3, -3, 5, 5)) + c2 = s1.get_at((4, 4)) + self.assertEqual(c, color) + + # rect returns the area we actually fill. + r3 = s2.fill(color2, (-30, -30, 5, 5)) + # since we are using negative coords, it should be an zero sized rect. + self.assertEqual(tuple(r3), (0, 0, 0, 0)) + + def test_fill_keyword_args(self): + """Ensure fill() accepts keyword arguments.""" + color = (1, 2, 3, 255) + area = (1, 1, 2, 2) + s1 = pygame.Surface((4, 4), 0, 32) + s1.fill(special_flags=pygame.BLEND_ADD, color=color, rect=area) + + self.assertEqual(s1.get_at((0, 0)), (0, 0, 0, 255)) + self.assertEqual(s1.get_at((1, 1)), color) + + ######################################################################## + + def test_get_alpha(self): + """Ensure a surface's alpha value can be retrieved.""" + s1 = pygame.Surface((32, 32), pygame.SRCALPHA, 32) + + self.assertEqual(s1.get_alpha(), 255) + + for alpha in (0, 32, 127, 255): + s1.set_alpha(alpha) + for t in range(4): + s1.set_alpha(s1.get_alpha()) + + self.assertEqual(s1.get_alpha(), alpha) + + ######################################################################## + + def test_get_bytesize(self): + """Ensure a surface's bit and byte sizes can be retrieved.""" + pygame.display.init() + try: + depth = 32 + depth_bytes = 4 + s1 = pygame.Surface((32, 32), pygame.SRCALPHA, depth) + + self.assertEqual(s1.get_bytesize(), depth_bytes) + self.assertEqual(s1.get_bitsize(), depth) + + depth = 15 + depth_bytes = 2 + s1 = pygame.Surface((32, 32), 0, depth) + + self.assertEqual(s1.get_bytesize(), depth_bytes) + self.assertEqual(s1.get_bitsize(), depth) + + depth = 12 + depth_bytes = 2 + s1 = pygame.Surface((32, 32), 0, depth) + + self.assertEqual(s1.get_bytesize(), depth_bytes) + self.assertEqual(s1.get_bitsize(), depth) + + with self.assertRaises(pygame.error): + surface = pygame.display.set_mode() + pygame.display.quit() + surface.get_bytesize() + finally: + pygame.display.quit() + + ######################################################################## + + def test_get_flags(self): + """Ensure a surface's flags can be retrieved.""" + s1 = pygame.Surface((32, 32), pygame.SRCALPHA, 32) + + self.assertEqual(s1.get_flags(), pygame.SRCALPHA) + + @unittest.skipIf( + os.environ.get("SDL_VIDEODRIVER") == "dummy", + 'requires a non-"dummy" SDL_VIDEODRIVER', + ) + def test_get_flags__display_surf(self): + pygame.display.init() + try: + # FULLSCREEN + screen_surf = pygame.display.set_mode((600, 400), flags=0) + self.assertFalse(screen_surf.get_flags() & pygame.FULLSCREEN) + + screen_surf = pygame.display.set_mode((600, 400), flags=pygame.FULLSCREEN) + self.assertTrue(screen_surf.get_flags() & pygame.FULLSCREEN) + + # NOFRAME + screen_surf = pygame.display.set_mode((600, 400), flags=0) + self.assertFalse(screen_surf.get_flags() & pygame.NOFRAME) + + screen_surf = pygame.display.set_mode((600, 400), flags=pygame.NOFRAME) + self.assertTrue(screen_surf.get_flags() & pygame.NOFRAME) + + # RESIZABLE + screen_surf = pygame.display.set_mode((600, 400), flags=0) + self.assertFalse(screen_surf.get_flags() & pygame.RESIZABLE) + + screen_surf = pygame.display.set_mode((600, 400), flags=pygame.RESIZABLE) + self.assertTrue(screen_surf.get_flags() & pygame.RESIZABLE) + + # OPENGL + screen_surf = pygame.display.set_mode((600, 400), flags=0) + # it can have an OPENGL flag by default on Macos? + if not (screen_surf.get_flags() & pygame.OPENGL): + self.assertFalse(screen_surf.get_flags() & pygame.OPENGL) + + try: + pygame.display.set_mode((200, 200), pygame.OPENGL, 32) + except pygame.error: + pass # If we can't create OPENGL surface don't try this test + else: + self.assertTrue(screen_surf.get_flags() & pygame.OPENGL) + finally: + pygame.display.quit() + + ######################################################################## + + def test_get_parent(self): + """Ensure a surface's parent can be retrieved.""" + pygame.display.init() + try: + parent = pygame.Surface((16, 16)) + child = parent.subsurface((0, 0, 5, 5)) + + self.assertIs(child.get_parent(), parent) + + with self.assertRaises(pygame.error): + surface = pygame.display.set_mode() + pygame.display.quit() + surface.get_parent() + finally: + pygame.display.quit() + + ######################################################################## + + def test_get_rect(self): + """Ensure a surface's rect can be retrieved.""" + size = (16, 16) + surf = pygame.Surface(size) + rect = surf.get_rect() + + self.assertEqual(rect.size, size) + + ######################################################################## + + def test_get_width__size_and_height(self): + """Ensure a surface's size, width and height can be retrieved.""" + for w in range(0, 255, 32): + for h in range(0, 127, 15): + s = pygame.Surface((w, h)) + self.assertEqual(s.get_width(), w) + self.assertEqual(s.get_height(), h) + self.assertEqual(s.get_size(), (w, h)) + + def test_get_view(self): + """Ensure a buffer view of the surface's pixels can be retrieved.""" + # Check that BufferProxys are returned when array depth is supported, + # ValueErrors returned otherwise. + Error = ValueError + s = pygame.Surface((5, 7), 0, 8) + v2 = s.get_view("2") + + self.assertRaises(Error, s.get_view, "0") + self.assertRaises(Error, s.get_view, "1") + self.assertIsInstance(v2, BufferProxy) + self.assertRaises(Error, s.get_view, "3") + + s = pygame.Surface((8, 7), 0, 8) + length = s.get_bytesize() * s.get_width() * s.get_height() + v0 = s.get_view("0") + v1 = s.get_view("1") + + self.assertIsInstance(v0, BufferProxy) + self.assertEqual(v0.length, length) + self.assertIsInstance(v1, BufferProxy) + self.assertEqual(v1.length, length) + + s = pygame.Surface((5, 7), 0, 16) + v2 = s.get_view("2") + + self.assertRaises(Error, s.get_view, "0") + self.assertRaises(Error, s.get_view, "1") + self.assertIsInstance(v2, BufferProxy) + self.assertRaises(Error, s.get_view, "3") + + s = pygame.Surface((8, 7), 0, 16) + length = s.get_bytesize() * s.get_width() * s.get_height() + v0 = s.get_view("0") + v1 = s.get_view("1") + + self.assertIsInstance(v0, BufferProxy) + self.assertEqual(v0.length, length) + self.assertIsInstance(v1, BufferProxy) + self.assertEqual(v1.length, length) + + s = pygame.Surface((5, 7), pygame.SRCALPHA, 16) + v2 = s.get_view("2") + + self.assertIsInstance(v2, BufferProxy) + self.assertRaises(Error, s.get_view, "3") + + s = pygame.Surface((5, 7), 0, 24) + v2 = s.get_view("2") + v3 = s.get_view("3") + + self.assertRaises(Error, s.get_view, "0") + self.assertRaises(Error, s.get_view, "1") + self.assertIsInstance(v2, BufferProxy) + self.assertIsInstance(v3, BufferProxy) + + s = pygame.Surface((8, 7), 0, 24) + length = s.get_bytesize() * s.get_width() * s.get_height() + v0 = s.get_view("0") + v1 = s.get_view("1") + + self.assertIsInstance(v0, BufferProxy) + self.assertEqual(v0.length, length) + self.assertIsInstance(v1, BufferProxy) + self.assertEqual(v1.length, length) + + s = pygame.Surface((5, 7), 0, 32) + length = s.get_bytesize() * s.get_width() * s.get_height() + v0 = s.get_view("0") + v1 = s.get_view("1") + v2 = s.get_view("2") + v3 = s.get_view("3") + + self.assertIsInstance(v0, BufferProxy) + self.assertEqual(v0.length, length) + self.assertIsInstance(v1, BufferProxy) + self.assertEqual(v1.length, length) + self.assertIsInstance(v2, BufferProxy) + self.assertIsInstance(v3, BufferProxy) + + s2 = s.subsurface((0, 0, 4, 7)) + + self.assertRaises(Error, s2.get_view, "0") + self.assertRaises(Error, s2.get_view, "1") + + s2 = None + s = pygame.Surface((5, 7), pygame.SRCALPHA, 32) + + for kind in ("2", "3", "a", "A", "r", "R", "g", "G", "b", "B"): + self.assertIsInstance(s.get_view(kind), BufferProxy) + + # Check default argument value: '2' + s = pygame.Surface((2, 4), 0, 32) + v = s.get_view() + if not IS_PYPY: + ai = ArrayInterface(v) + self.assertEqual(ai.nd, 2) + + # Check locking. + s = pygame.Surface((2, 4), 0, 32) + + self.assertFalse(s.get_locked()) + + v = s.get_view("2") + + self.assertFalse(s.get_locked()) + + c = v.__array_interface__ + + self.assertTrue(s.get_locked()) + + c = None + gc.collect() + + self.assertTrue(s.get_locked()) + + v = None + gc.collect() + + self.assertFalse(s.get_locked()) + + # Check invalid view kind values. + s = pygame.Surface((2, 4), pygame.SRCALPHA, 32) + self.assertRaises(TypeError, s.get_view, "") + self.assertRaises(TypeError, s.get_view, "9") + self.assertRaises(TypeError, s.get_view, "RGBA") + self.assertRaises(TypeError, s.get_view, 2) + + # Both unicode and bytes strings are allowed for kind. + s = pygame.Surface((2, 4), 0, 32) + s.get_view("2") + s.get_view(b"2") + + # Garbage collection + s = pygame.Surface((2, 4), 0, 32) + weak_s = weakref.ref(s) + v = s.get_view("3") + weak_v = weakref.ref(v) + gc.collect() + self.assertTrue(weak_s() is s) + self.assertTrue(weak_v() is v) + del v + gc.collect() + self.assertTrue(weak_s() is s) + self.assertTrue(weak_v() is None) + del s + gc.collect() + self.assertTrue(weak_s() is None) + + def test_get_buffer(self): + # Check that get_buffer works for all pixel sizes and for a subsurface. + + # Check for all pixel sizes + for bitsize in [8, 16, 24, 32]: + s = pygame.Surface((5, 7), 0, bitsize) + length = s.get_pitch() * s.get_height() + v = s.get_buffer() + + self.assertIsInstance(v, BufferProxy) + self.assertEqual(v.length, length) + self.assertEqual(repr(v), "") + + # Check for a subsurface (not contiguous) + s = pygame.Surface((7, 10), 0, 32) + s2 = s.subsurface((1, 2, 5, 7)) + length = s2.get_pitch() * s2.get_height() + v = s2.get_buffer() + + self.assertIsInstance(v, BufferProxy) + self.assertEqual(v.length, length) + + # Check locking. + s = pygame.Surface((2, 4), 0, 32) + v = s.get_buffer() + self.assertTrue(s.get_locked()) + v = None + gc.collect() + self.assertFalse(s.get_locked()) + + OLDBUF = hasattr(pygame.bufferproxy, "get_segcount") + + @unittest.skipIf(not OLDBUF, "old buffer not available") + def test_get_buffer_oldbuf(self): + from pygame.bufferproxy import get_segcount, get_write_buffer + + s = pygame.Surface((2, 4), pygame.SRCALPHA, 32) + v = s.get_buffer() + segcount, buflen = get_segcount(v) + self.assertEqual(segcount, 1) + self.assertEqual(buflen, s.get_pitch() * s.get_height()) + seglen, segaddr = get_write_buffer(v, 0) + self.assertEqual(segaddr, s._pixels_address) + self.assertEqual(seglen, buflen) + + @unittest.skipIf(not OLDBUF, "old buffer not available") + def test_get_view_oldbuf(self): + from pygame.bufferproxy import get_segcount, get_write_buffer + + s = pygame.Surface((2, 4), pygame.SRCALPHA, 32) + v = s.get_view("1") + segcount, buflen = get_segcount(v) + self.assertEqual(segcount, 8) + self.assertEqual(buflen, s.get_pitch() * s.get_height()) + seglen, segaddr = get_write_buffer(v, 7) + self.assertEqual(segaddr, s._pixels_address + s.get_bytesize() * 7) + self.assertEqual(seglen, s.get_bytesize()) + + def test_set_colorkey(self): + + # __doc__ (as of 2008-06-25) for pygame.surface.Surface.set_colorkey: + + # Surface.set_colorkey(Color, flags=0): return None + # Surface.set_colorkey(None): return None + # Set the transparent colorkey + + s = pygame.Surface((16, 16), pygame.SRCALPHA, 32) + + colorkeys = ((20, 189, 20, 255), (128, 50, 50, 255), (23, 21, 255, 255)) + + for colorkey in colorkeys: + s.set_colorkey(colorkey) + + for t in range(4): + s.set_colorkey(s.get_colorkey()) + + self.assertEqual(s.get_colorkey(), colorkey) + + def test_set_masks(self): + s = pygame.Surface((32, 32)) + r, g, b, a = s.get_masks() + self.assertRaises(TypeError, s.set_masks, (b, g, r, a)) + + def test_set_shifts(self): + s = pygame.Surface((32, 32)) + r, g, b, a = s.get_shifts() + self.assertRaises(TypeError, s.set_shifts, (b, g, r, a)) + + def test_blit_keyword_args(self): + color = (1, 2, 3, 255) + s1 = pygame.Surface((4, 4), 0, 32) + s2 = pygame.Surface((2, 2), 0, 32) + s2.fill((1, 2, 3)) + s1.blit(special_flags=BLEND_ADD, source=s2, dest=(1, 1), area=s2.get_rect()) + self.assertEqual(s1.get_at((0, 0)), (0, 0, 0, 255)) + self.assertEqual(s1.get_at((1, 1)), color) + + def test_blit_big_rects(self): + """SDL2 can have more than 16 bits for x, y, width, height.""" + big_surf = pygame.Surface((100, 68000), 0, 32) + big_surf_color = (255, 0, 0) + big_surf.fill(big_surf_color) + + background = pygame.Surface((500, 500), 0, 32) + background_color = (0, 255, 0) + background.fill(background_color) + + # copy parts of the big_surf using more than 16bit parts. + background.blit(big_surf, (100, 100), area=(0, 16000, 100, 100)) + background.blit(big_surf, (200, 200), area=(0, 32000, 100, 100)) + background.blit(big_surf, (300, 300), area=(0, 66000, 100, 100)) + + # check that all three areas are drawn. + self.assertEqual(background.get_at((101, 101)), big_surf_color) + self.assertEqual(background.get_at((201, 201)), big_surf_color) + self.assertEqual(background.get_at((301, 301)), big_surf_color) + + # areas outside the 3 blitted areas not covered by those blits. + self.assertEqual(background.get_at((400, 301)), background_color) + self.assertEqual(background.get_at((400, 201)), background_color) + self.assertEqual(background.get_at((100, 201)), background_color) + self.assertEqual(background.get_at((99, 99)), background_color) + self.assertEqual(background.get_at((450, 450)), background_color) + + +class TestSurfaceBlit(unittest.TestCase): + """Tests basic blitting functionality and options.""" + + # __doc__ (as of 2008-08-02) for pygame.surface.Surface.blit: + + # Surface.blit(source, dest, area=None, special_flags = 0): return Rect + # draw one image onto another + # + # Draws a source Surface onto this Surface. The draw can be positioned + # with the dest argument. Dest can either be pair of coordinates + # representing the upper left corner of the source. A Rect can also be + # passed as the destination and the topleft corner of the rectangle + # will be used as the position for the blit. The size of the + # destination rectangle does not effect the blit. + # + # An optional area rectangle can be passed as well. This represents a + # smaller portion of the source Surface to draw. + # + # An optional special flags is for passing in new in 1.8.0: BLEND_ADD, + # BLEND_SUB, BLEND_MULT, BLEND_MIN, BLEND_MAX new in 1.8.1: + # BLEND_RGBA_ADD, BLEND_RGBA_SUB, BLEND_RGBA_MULT, BLEND_RGBA_MIN, + # BLEND_RGBA_MAX BLEND_RGB_ADD, BLEND_RGB_SUB, BLEND_RGB_MULT, + # BLEND_RGB_MIN, BLEND_RGB_MAX With other special blitting flags + # perhaps added in the future. + # + # The return rectangle is the area of the affected pixels, excluding + # any pixels outside the destination Surface, or outside the clipping + # area. + # + # Pixel alphas will be ignored when blitting to an 8 bit Surface. + # special_flags new in pygame 1.8. + + def setUp(self): + """Resets starting surfaces.""" + self.src_surface = pygame.Surface((256, 256), 32) + self.src_surface.fill(pygame.Color(255, 255, 255)) + self.dst_surface = pygame.Surface((64, 64), 32) + self.dst_surface.fill(pygame.Color(0, 0, 0)) + + def test_blit_overflow_coord(self): + """Full coverage w/ overflow, specified with Coordinate""" + result = self.dst_surface.blit(self.src_surface, (0, 0)) + self.assertIsInstance(result, pygame.Rect) + self.assertEqual(result.size, (64, 64)) + for k in [(x, x) for x in range(64)]: + self.assertEqual(self.dst_surface.get_at(k), (255, 255, 255)) + + def test_blit_overflow_rect(self): + """Full coverage w/ overflow, specified with a Rect""" + result = self.dst_surface.blit(self.src_surface, pygame.Rect(-1, -1, 300, 300)) + self.assertIsInstance(result, pygame.Rect) + self.assertEqual(result.size, (64, 64)) + for k in [(x, x) for x in range(64)]: + self.assertEqual(self.dst_surface.get_at(k), (255, 255, 255)) + + def test_blit_overflow_nonorigin(self): + """Test Rectange Dest, with overflow but with starting rect with top-left at (1,1)""" + result = self.dst_surface.blit(self.src_surface, dest=pygame.Rect((1, 1, 1, 1))) + self.assertIsInstance(result, pygame.Rect) + self.assertEqual(result.size, (63, 63)) + self.assertEqual(self.dst_surface.get_at((0, 0)), (0, 0, 0)) + self.assertEqual(self.dst_surface.get_at((63, 0)), (0, 0, 0)) + self.assertEqual(self.dst_surface.get_at((0, 63)), (0, 0, 0)) + self.assertEqual(self.dst_surface.get_at((1, 1)), (255, 255, 255)) + self.assertEqual(self.dst_surface.get_at((63, 63)), (255, 255, 255)) + + def test_blit_area_contraint(self): + """Testing area constraint""" + result = self.dst_surface.blit( + self.src_surface, + dest=pygame.Rect((1, 1, 1, 1)), + area=pygame.Rect((2, 2, 2, 2)), + ) + self.assertIsInstance(result, pygame.Rect) + self.assertEqual(result.size, (2, 2)) + self.assertEqual(self.dst_surface.get_at((0, 0)), (0, 0, 0)) # Corners + self.assertEqual(self.dst_surface.get_at((63, 0)), (0, 0, 0)) + self.assertEqual(self.dst_surface.get_at((0, 63)), (0, 0, 0)) + self.assertEqual(self.dst_surface.get_at((63, 63)), (0, 0, 0)) + self.assertEqual( + self.dst_surface.get_at((1, 1)), (255, 255, 255) + ) # Blitted Area + self.assertEqual(self.dst_surface.get_at((2, 2)), (255, 255, 255)) + self.assertEqual(self.dst_surface.get_at((3, 3)), (0, 0, 0)) + # Should stop short of filling in (3,3) + + def test_blit_zero_overlap(self): + """Testing zero-overlap condition.""" + result = self.dst_surface.blit( + self.src_surface, + dest=pygame.Rect((-256, -256, 1, 1)), + area=pygame.Rect((2, 2, 256, 256)), + ) + self.assertIsInstance(result, pygame.Rect) + self.assertEqual(result.size, (0, 0)) # No blitting expected + for k in [(x, x) for x in range(64)]: + self.assertEqual(self.dst_surface.get_at(k), (0, 0, 0)) # Diagonal + self.assertEqual( + self.dst_surface.get_at((63, 0)), (0, 0, 0) + ) # Remaining corners + self.assertEqual(self.dst_surface.get_at((0, 63)), (0, 0, 0)) + + def test_blit__SRCALPHA_opaque_source(self): + src = pygame.Surface((256, 256), SRCALPHA, 32) + dst = src.copy() + + for i, j in test_utils.rect_area_pts(src.get_rect()): + dst.set_at((i, j), (i, 0, 0, j)) + src.set_at((i, j), (0, i, 0, 255)) + + dst.blit(src, (0, 0)) + + for pt in test_utils.rect_area_pts(src.get_rect()): + self.assertEqual(dst.get_at(pt)[1], src.get_at(pt)[1]) + + def test_blit__blit_to_self(self): + """Test that blit operation works on self, alpha value is + correct, and that no RGB distortion occurs.""" + test_surface = pygame.Surface((128, 128), SRCALPHA, 32) + area = test_surface.get_rect() + + for pt, test_color in test_utils.gradient(area.width, area.height): + test_surface.set_at(pt, test_color) + + reference_surface = test_surface.copy() + + test_surface.blit(test_surface, (0, 0)) + + for x in range(area.width): + for y in range(area.height): + (r, g, b, a) = reference_color = reference_surface.get_at((x, y)) + expected_color = (r, g, b, (a + (a * ((256 - a) // 256)))) + self.assertEqual(reference_color, expected_color) + + self.assertEqual(reference_surface.get_rect(), test_surface.get_rect()) + + def test_blit__SRCALPHA_to_SRCALPHA_non_zero(self): + """Tests blitting a nonzero alpha surface to another nonzero alpha surface + both straight alpha compositing method. Test is fuzzy (+/- 1/256) to account for + different implementations in SDL1 and SDL2. + """ + + size = (32, 32) + + def check_color_diff(color1, color2): + """Returns True if two colors are within (1, 1, 1, 1) of each other.""" + for val in color1 - color2: + if abs(val) > 1: + return False + return True + + def high_a_onto_low(high, low): + """Tests straight alpha case. Source is low alpha, destination is high alpha""" + high_alpha_surface = pygame.Surface(size, pygame.SRCALPHA, 32) + low_alpha_surface = high_alpha_surface.copy() + high_alpha_color = Color( + (high, high, low, high) + ) # Injecting some RGB variance. + low_alpha_color = Color((high, low, low, low)) + high_alpha_surface.fill(high_alpha_color) + low_alpha_surface.fill(low_alpha_color) + + high_alpha_surface.blit(low_alpha_surface, (0, 0)) + + expected_color = low_alpha_color + Color( + tuple( + ((x * (255 - low_alpha_color.a)) // 255) for x in high_alpha_color + ) + ) + self.assertTrue( + check_color_diff(high_alpha_surface.get_at((0, 0)), expected_color) + ) + + def low_a_onto_high(high, low): + """Tests straight alpha case. Source is high alpha, destination is low alpha""" + high_alpha_surface = pygame.Surface(size, pygame.SRCALPHA, 32) + low_alpha_surface = high_alpha_surface.copy() + high_alpha_color = Color( + (high, high, low, high) + ) # Injecting some RGB variance. + low_alpha_color = Color((high, low, low, low)) + high_alpha_surface.fill(high_alpha_color) + low_alpha_surface.fill(low_alpha_color) + + low_alpha_surface.blit(high_alpha_surface, (0, 0)) + + expected_color = high_alpha_color + Color( + tuple( + ((x * (255 - high_alpha_color.a)) // 255) for x in low_alpha_color + ) + ) + self.assertTrue( + check_color_diff(low_alpha_surface.get_at((0, 0)), expected_color) + ) + + for low_a in range(0, 128): + for high_a in range(128, 256): + high_a_onto_low(high_a, low_a) + low_a_onto_high(high_a, low_a) + + def test_blit__SRCALPHA32_to_8(self): + # Bug: fatal + # SDL_DisplayConvert segfaults when video is uninitialized. + target = pygame.Surface((11, 8), 0, 8) + test_color = target.get_palette_at(2) + source = pygame.Surface((1, 1), pygame.SRCALPHA, 32) + source.set_at((0, 0), test_color) + target.blit(source, (0, 0)) + + +class GeneralSurfaceTests(AssertRaisesRegexMixin, unittest.TestCase): + @unittest.skipIf( + os.environ.get("SDL_VIDEODRIVER") == "dummy", + 'requires a non-"dummy" SDL_VIDEODRIVER', + ) + def test_image_convert_bug_131(self): + # Bitbucket bug #131: Unable to Surface.convert(32) some 1-bit images. + # https://bitbucket.org/pygame/pygame/issue/131/unable-to-surfaceconvert-32-some-1-bit + + pygame.display.init() + try: + pygame.display.set_mode((640, 480)) + + im = pygame.image.load(example_path(os.path.join("data", "city.png"))) + im2 = pygame.image.load(example_path(os.path.join("data", "brick.png"))) + + self.assertEqual(im.get_palette(), ((0, 0, 0, 255), (255, 255, 255, 255))) + self.assertEqual(im2.get_palette(), ((0, 0, 0, 255), (0, 0, 0, 255))) + + self.assertEqual(repr(im.convert(32)), "") + self.assertEqual(repr(im2.convert(32)), "") + + # Ensure a palette format to palette format works. + im3 = im.convert(8) + self.assertEqual(repr(im3), "") + self.assertEqual(im3.get_palette(), im.get_palette()) + + finally: + pygame.display.quit() + + def test_convert_init(self): + """Ensure initialization exceptions are raised + for surf.convert().""" + pygame.display.quit() + surf = pygame.Surface((1, 1)) + + self.assertRaisesRegex(pygame.error, "display initialized", surf.convert) + + pygame.display.init() + try: + if os.environ.get("SDL_VIDEODRIVER") != "dummy": + try: + surf.convert(32) + surf.convert(pygame.Surface((1, 1))) + except pygame.error: + self.fail("convert() should not raise an exception here.") + + self.assertRaisesRegex(pygame.error, "No video mode", surf.convert) + + pygame.display.set_mode((640, 480)) + try: + surf.convert() + except pygame.error: + self.fail("convert() should not raise an exception here.") + finally: + pygame.display.quit() + + def test_convert_alpha_init(self): + """Ensure initialization exceptions are raised + for surf.convert_alpha().""" + pygame.display.quit() + surf = pygame.Surface((1, 1)) + + self.assertRaisesRegex(pygame.error, "display initialized", surf.convert_alpha) + + pygame.display.init() + try: + self.assertRaisesRegex(pygame.error, "No video mode", surf.convert_alpha) + + pygame.display.set_mode((640, 480)) + try: + surf.convert_alpha() + except pygame.error: + self.fail("convert_alpha() should not raise an exception here.") + finally: + pygame.display.quit() + + def test_convert_alpha_SRCALPHA(self): + """Ensure that the surface returned by surf.convert_alpha() + has alpha blending enabled""" + pygame.display.init() + try: + pygame.display.set_mode((640, 480)) + + s1 = pygame.Surface((100, 100), 0, 32) + # s2=pygame.Surface((100,100), pygame.SRCALPHA, 32) + s1_alpha = s1.convert_alpha() + self.assertEqual(s1_alpha.get_flags() & SRCALPHA, SRCALPHA) + self.assertEqual(s1_alpha.get_alpha(), 255) + finally: + pygame.display.quit() + + def test_src_alpha_issue_1289(self): + """blit should be white.""" + surf1 = pygame.Surface((1, 1), pygame.SRCALPHA, 32) + surf1.fill((255, 255, 255, 100)) + + surf2 = pygame.Surface((1, 1), pygame.SRCALPHA, 32) + self.assertEqual(surf2.get_at((0, 0)), (0, 0, 0, 0)) + surf2.blit(surf1, (0, 0)) + + self.assertEqual(surf1.get_at((0, 0)), (255, 255, 255, 100)) + self.assertEqual(surf2.get_at((0, 0)), (255, 255, 255, 100)) + + def test_src_alpha_compatible(self): + """ "What pygame 1.9.x did". Is the alpha blitter as before?""" + + # The table below was generated with the SDL1 blit. + # def print_table(): + # nums = [0, 1, 65, 126, 127, 199, 254, 255] + # results = {} + # for dest_r, dest_b, dest_a in zip(nums, reversed(nums), reversed(nums)): + # for src_r, src_b, src_a in zip(nums, reversed(nums), nums): + # src_surf = pygame.Surface((66, 66), pygame.SRCALPHA, 32) + # src_surf.fill((src_r, 255, src_b, src_a)) + # dest_surf = pygame.Surface((66, 66), pygame.SRCALPHA, 32) + # dest_surf.fill((dest_r, 255, dest_b, dest_a)) + # dest_surf.blit(src_surf, (0, 0)) + # key = ((dest_r, dest_b, dest_a), (src_r, src_b, src_a)) + # results[key] = dest_surf.get_at((65, 33)) + # print("(dest_r, dest_b, dest_a), (src_r, src_b, src_a): color") + # pprint(results) + + results_expected = { + ((0, 255, 255), (0, 255, 0)): (0, 255, 255, 255), + ((0, 255, 255), (1, 254, 1)): (0, 255, 255, 255), + ((0, 255, 255), (65, 199, 65)): (16, 255, 241, 255), + ((0, 255, 255), (126, 127, 126)): (62, 255, 192, 255), + ((0, 255, 255), (127, 126, 127)): (63, 255, 191, 255), + ((0, 255, 255), (199, 65, 199)): (155, 255, 107, 255), + ((0, 255, 255), (254, 1, 254)): (253, 255, 2, 255), + ((0, 255, 255), (255, 0, 255)): (255, 255, 0, 255), + ((1, 254, 254), (0, 255, 0)): (1, 255, 254, 254), + ((1, 254, 254), (1, 254, 1)): (1, 255, 254, 255), + ((1, 254, 254), (65, 199, 65)): (17, 255, 240, 255), + ((1, 254, 254), (126, 127, 126)): (63, 255, 191, 255), + ((1, 254, 254), (127, 126, 127)): (64, 255, 190, 255), + ((1, 254, 254), (199, 65, 199)): (155, 255, 107, 255), + ((1, 254, 254), (254, 1, 254)): (253, 255, 2, 255), + ((1, 254, 254), (255, 0, 255)): (255, 255, 0, 255), + ((65, 199, 199), (0, 255, 0)): (65, 255, 199, 199), + ((65, 199, 199), (1, 254, 1)): (64, 255, 200, 200), + ((65, 199, 199), (65, 199, 65)): (65, 255, 199, 214), + ((65, 199, 199), (126, 127, 126)): (95, 255, 164, 227), + ((65, 199, 199), (127, 126, 127)): (96, 255, 163, 227), + ((65, 199, 199), (199, 65, 199)): (169, 255, 95, 243), + ((65, 199, 199), (254, 1, 254)): (253, 255, 2, 255), + ((65, 199, 199), (255, 0, 255)): (255, 255, 0, 255), + ((126, 127, 127), (0, 255, 0)): (126, 255, 127, 127), + ((126, 127, 127), (1, 254, 1)): (125, 255, 128, 128), + ((126, 127, 127), (65, 199, 65)): (110, 255, 146, 160), + ((126, 127, 127), (126, 127, 126)): (126, 255, 127, 191), + ((126, 127, 127), (127, 126, 127)): (126, 255, 126, 191), + ((126, 127, 127), (199, 65, 199)): (183, 255, 79, 227), + ((126, 127, 127), (254, 1, 254)): (253, 255, 1, 255), + ((126, 127, 127), (255, 0, 255)): (255, 255, 0, 255), + ((127, 126, 126), (0, 255, 0)): (127, 255, 126, 126), + ((127, 126, 126), (1, 254, 1)): (126, 255, 127, 127), + ((127, 126, 126), (65, 199, 65)): (111, 255, 145, 159), + ((127, 126, 126), (126, 127, 126)): (127, 255, 126, 190), + ((127, 126, 126), (127, 126, 127)): (127, 255, 126, 191), + ((127, 126, 126), (199, 65, 199)): (183, 255, 78, 227), + ((127, 126, 126), (254, 1, 254)): (254, 255, 1, 255), + ((127, 126, 126), (255, 0, 255)): (255, 255, 0, 255), + ((199, 65, 65), (0, 255, 0)): (199, 255, 65, 65), + ((199, 65, 65), (1, 254, 1)): (198, 255, 66, 66), + ((199, 65, 65), (65, 199, 65)): (165, 255, 99, 114), + ((199, 65, 65), (126, 127, 126)): (163, 255, 96, 159), + ((199, 65, 65), (127, 126, 127)): (163, 255, 95, 160), + ((199, 65, 65), (199, 65, 199)): (199, 255, 65, 214), + ((199, 65, 65), (254, 1, 254)): (254, 255, 1, 255), + ((199, 65, 65), (255, 0, 255)): (255, 255, 0, 255), + ((254, 1, 1), (0, 255, 0)): (254, 255, 1, 1), + ((254, 1, 1), (1, 254, 1)): (253, 255, 2, 2), + ((254, 1, 1), (65, 199, 65)): (206, 255, 52, 66), + ((254, 1, 1), (126, 127, 126)): (191, 255, 63, 127), + ((254, 1, 1), (127, 126, 127)): (191, 255, 63, 128), + ((254, 1, 1), (199, 65, 199)): (212, 255, 51, 200), + ((254, 1, 1), (254, 1, 254)): (254, 255, 1, 255), + ((254, 1, 1), (255, 0, 255)): (255, 255, 0, 255), + ((255, 0, 0), (0, 255, 0)): (0, 255, 255, 0), + ((255, 0, 0), (1, 254, 1)): (1, 255, 254, 1), + ((255, 0, 0), (65, 199, 65)): (65, 255, 199, 65), + ((255, 0, 0), (126, 127, 126)): (126, 255, 127, 126), + ((255, 0, 0), (127, 126, 127)): (127, 255, 126, 127), + ((255, 0, 0), (199, 65, 199)): (199, 255, 65, 199), + ((255, 0, 0), (254, 1, 254)): (254, 255, 1, 254), + ((255, 0, 0), (255, 0, 255)): (255, 255, 0, 255), + } + + # chosen because they contain edge cases. + nums = [0, 1, 65, 126, 127, 199, 254, 255] + results = {} + for dst_r, dst_b, dst_a in zip(nums, reversed(nums), reversed(nums)): + for src_r, src_b, src_a in zip(nums, reversed(nums), nums): + with self.subTest( + src_r=src_r, + src_b=src_b, + src_a=src_a, + dest_r=dst_r, + dest_b=dst_b, + dest_a=dst_a, + ): + src_surf = pygame.Surface((66, 66), pygame.SRCALPHA, 32) + src_surf.fill((src_r, 255, src_b, src_a)) + dest_surf = pygame.Surface((66, 66), pygame.SRCALPHA, 32) + dest_surf.fill((dst_r, 255, dst_b, dst_a)) + + dest_surf.blit(src_surf, (0, 0)) + key = ((dst_r, dst_b, dst_a), (src_r, src_b, src_a)) + results[key] = dest_surf.get_at((65, 33)) + self.assertEqual(results[key], results_expected[key]) + + self.assertEqual(results, results_expected) + + def test_src_alpha_compatible_16bit(self): + """ "What pygame 1.9.x did". Is the alpha blitter as before?""" + + # The table below was generated with the SDL1 blit. + # def print_table(): + # nums = [0, 1, 65, 126, 127, 199, 254, 255] + # results = {} + # for dest_r, dest_b, dest_a in zip(nums, reversed(nums), reversed(nums)): + # for src_r, src_b, src_a in zip(nums, reversed(nums), nums): + # src_surf = pygame.Surface((66, 66), pygame.SRCALPHA, 16) + # src_surf.fill((src_r, 255, src_b, src_a)) + # dest_surf = pygame.Surface((66, 66), pygame.SRCALPHA, 16) + # dest_surf.fill((dest_r, 255, dest_b, dest_a)) + # dest_surf.blit(src_surf, (0, 0)) + # key = ((dest_r, dest_b, dest_a), (src_r, src_b, src_a)) + # results[key] = dest_surf.get_at((65, 33)) + # print("(dest_r, dest_b, dest_a), (src_r, src_b, src_a): color") + # pprint(results) + + results_expected = { + ((0, 255, 255), (0, 255, 0)): (0, 255, 255, 255), + ((0, 255, 255), (1, 254, 1)): (0, 255, 255, 255), + ((0, 255, 255), (65, 199, 65)): (17, 255, 255, 255), + ((0, 255, 255), (126, 127, 126)): (51, 255, 204, 255), + ((0, 255, 255), (127, 126, 127)): (51, 255, 204, 255), + ((0, 255, 255), (199, 65, 199)): (170, 255, 102, 255), + ((0, 255, 255), (254, 1, 254)): (255, 255, 0, 255), + ((0, 255, 255), (255, 0, 255)): (255, 255, 0, 255), + ((1, 254, 254), (0, 255, 0)): (0, 255, 255, 255), + ((1, 254, 254), (1, 254, 1)): (0, 255, 255, 255), + ((1, 254, 254), (65, 199, 65)): (17, 255, 255, 255), + ((1, 254, 254), (126, 127, 126)): (51, 255, 204, 255), + ((1, 254, 254), (127, 126, 127)): (51, 255, 204, 255), + ((1, 254, 254), (199, 65, 199)): (170, 255, 102, 255), + ((1, 254, 254), (254, 1, 254)): (255, 255, 0, 255), + ((1, 254, 254), (255, 0, 255)): (255, 255, 0, 255), + ((65, 199, 199), (0, 255, 0)): (68, 255, 204, 204), + ((65, 199, 199), (1, 254, 1)): (68, 255, 204, 204), + ((65, 199, 199), (65, 199, 65)): (68, 255, 204, 221), + ((65, 199, 199), (126, 127, 126)): (85, 255, 170, 238), + ((65, 199, 199), (127, 126, 127)): (85, 255, 170, 238), + ((65, 199, 199), (199, 65, 199)): (187, 255, 85, 255), + ((65, 199, 199), (254, 1, 254)): (255, 255, 0, 255), + ((65, 199, 199), (255, 0, 255)): (255, 255, 0, 255), + ((126, 127, 127), (0, 255, 0)): (119, 255, 119, 119), + ((126, 127, 127), (1, 254, 1)): (119, 255, 119, 119), + ((126, 127, 127), (65, 199, 65)): (102, 255, 136, 153), + ((126, 127, 127), (126, 127, 126)): (119, 255, 119, 187), + ((126, 127, 127), (127, 126, 127)): (119, 255, 119, 187), + ((126, 127, 127), (199, 65, 199)): (187, 255, 68, 238), + ((126, 127, 127), (254, 1, 254)): (255, 255, 0, 255), + ((126, 127, 127), (255, 0, 255)): (255, 255, 0, 255), + ((127, 126, 126), (0, 255, 0)): (119, 255, 119, 119), + ((127, 126, 126), (1, 254, 1)): (119, 255, 119, 119), + ((127, 126, 126), (65, 199, 65)): (102, 255, 136, 153), + ((127, 126, 126), (126, 127, 126)): (119, 255, 119, 187), + ((127, 126, 126), (127, 126, 127)): (119, 255, 119, 187), + ((127, 126, 126), (199, 65, 199)): (187, 255, 68, 238), + ((127, 126, 126), (254, 1, 254)): (255, 255, 0, 255), + ((127, 126, 126), (255, 0, 255)): (255, 255, 0, 255), + ((199, 65, 65), (0, 255, 0)): (204, 255, 68, 68), + ((199, 65, 65), (1, 254, 1)): (204, 255, 68, 68), + ((199, 65, 65), (65, 199, 65)): (170, 255, 102, 119), + ((199, 65, 65), (126, 127, 126)): (170, 255, 85, 153), + ((199, 65, 65), (127, 126, 127)): (170, 255, 85, 153), + ((199, 65, 65), (199, 65, 199)): (204, 255, 68, 221), + ((199, 65, 65), (254, 1, 254)): (255, 255, 0, 255), + ((199, 65, 65), (255, 0, 255)): (255, 255, 0, 255), + ((254, 1, 1), (0, 255, 0)): (0, 255, 255, 0), + ((254, 1, 1), (1, 254, 1)): (0, 255, 255, 0), + ((254, 1, 1), (65, 199, 65)): (68, 255, 204, 68), + ((254, 1, 1), (126, 127, 126)): (119, 255, 119, 119), + ((254, 1, 1), (127, 126, 127)): (119, 255, 119, 119), + ((254, 1, 1), (199, 65, 199)): (204, 255, 68, 204), + ((254, 1, 1), (254, 1, 254)): (255, 255, 0, 255), + ((254, 1, 1), (255, 0, 255)): (255, 255, 0, 255), + ((255, 0, 0), (0, 255, 0)): (0, 255, 255, 0), + ((255, 0, 0), (1, 254, 1)): (0, 255, 255, 0), + ((255, 0, 0), (65, 199, 65)): (68, 255, 204, 68), + ((255, 0, 0), (126, 127, 126)): (119, 255, 119, 119), + ((255, 0, 0), (127, 126, 127)): (119, 255, 119, 119), + ((255, 0, 0), (199, 65, 199)): (204, 255, 68, 204), + ((255, 0, 0), (254, 1, 254)): (255, 255, 0, 255), + ((255, 0, 0), (255, 0, 255)): (255, 255, 0, 255), + } + + # chosen because they contain edge cases. + nums = [0, 1, 65, 126, 127, 199, 254, 255] + results = {} + for dst_r, dst_b, dst_a in zip(nums, reversed(nums), reversed(nums)): + for src_r, src_b, src_a in zip(nums, reversed(nums), nums): + with self.subTest( + src_r=src_r, + src_b=src_b, + src_a=src_a, + dest_r=dst_r, + dest_b=dst_b, + dest_a=dst_a, + ): + src_surf = pygame.Surface((66, 66), pygame.SRCALPHA, 16) + src_surf.fill((src_r, 255, src_b, src_a)) + dest_surf = pygame.Surface((66, 66), pygame.SRCALPHA, 16) + dest_surf.fill((dst_r, 255, dst_b, dst_a)) + + dest_surf.blit(src_surf, (0, 0)) + key = ((dst_r, dst_b, dst_a), (src_r, src_b, src_a)) + results[key] = dest_surf.get_at((65, 33)) + self.assertEqual(results[key], results_expected[key]) + + self.assertEqual(results, results_expected) + + def test_sdl1_mimic_blitter_with_set_alpha(self): + """does the SDL 1 style blitter in pygame 2 work with set_alpha(), + this feature only exists in pygame 2/SDL2 SDL1 did not support + combining surface and pixel alpha""" + + results_expected = { + ((0, 255, 255), (0, 255, 0)): (0, 255, 255, 255), + ((0, 255, 255), (1, 254, 1)): (0, 255, 255, 255), + ((0, 255, 255), (65, 199, 65)): (16, 255, 241, 255), + ((0, 255, 255), (126, 127, 126)): (62, 255, 192, 255), + ((0, 255, 255), (127, 126, 127)): (63, 255, 191, 255), + ((0, 255, 255), (199, 65, 199)): (155, 255, 107, 255), + ((0, 255, 255), (254, 1, 254)): (253, 255, 2, 255), + ((0, 255, 255), (255, 0, 255)): (255, 255, 0, 255), + ((1, 254, 254), (0, 255, 0)): (1, 255, 254, 254), + ((1, 254, 254), (1, 254, 1)): (1, 255, 254, 255), + ((1, 254, 254), (65, 199, 65)): (17, 255, 240, 255), + ((1, 254, 254), (126, 127, 126)): (63, 255, 191, 255), + ((1, 254, 254), (127, 126, 127)): (64, 255, 190, 255), + ((1, 254, 254), (199, 65, 199)): (155, 255, 107, 255), + ((1, 254, 254), (254, 1, 254)): (253, 255, 2, 255), + ((1, 254, 254), (255, 0, 255)): (255, 255, 0, 255), + ((65, 199, 199), (0, 255, 0)): (65, 255, 199, 199), + ((65, 199, 199), (1, 254, 1)): (64, 255, 200, 200), + ((65, 199, 199), (65, 199, 65)): (65, 255, 199, 214), + ((65, 199, 199), (126, 127, 126)): (95, 255, 164, 227), + ((65, 199, 199), (127, 126, 127)): (96, 255, 163, 227), + ((65, 199, 199), (199, 65, 199)): (169, 255, 95, 243), + ((65, 199, 199), (254, 1, 254)): (253, 255, 2, 255), + ((65, 199, 199), (255, 0, 255)): (255, 255, 0, 255), + ((126, 127, 127), (0, 255, 0)): (126, 255, 127, 127), + ((126, 127, 127), (1, 254, 1)): (125, 255, 128, 128), + ((126, 127, 127), (65, 199, 65)): (110, 255, 146, 160), + ((126, 127, 127), (126, 127, 126)): (126, 255, 127, 191), + ((126, 127, 127), (127, 126, 127)): (126, 255, 126, 191), + ((126, 127, 127), (199, 65, 199)): (183, 255, 79, 227), + ((126, 127, 127), (254, 1, 254)): (253, 255, 1, 255), + ((126, 127, 127), (255, 0, 255)): (255, 255, 0, 255), + ((127, 126, 126), (0, 255, 0)): (127, 255, 126, 126), + ((127, 126, 126), (1, 254, 1)): (126, 255, 127, 127), + ((127, 126, 126), (65, 199, 65)): (111, 255, 145, 159), + ((127, 126, 126), (126, 127, 126)): (127, 255, 126, 190), + ((127, 126, 126), (127, 126, 127)): (127, 255, 126, 191), + ((127, 126, 126), (199, 65, 199)): (183, 255, 78, 227), + ((127, 126, 126), (254, 1, 254)): (254, 255, 1, 255), + ((127, 126, 126), (255, 0, 255)): (255, 255, 0, 255), + ((199, 65, 65), (0, 255, 0)): (199, 255, 65, 65), + ((199, 65, 65), (1, 254, 1)): (198, 255, 66, 66), + ((199, 65, 65), (65, 199, 65)): (165, 255, 99, 114), + ((199, 65, 65), (126, 127, 126)): (163, 255, 96, 159), + ((199, 65, 65), (127, 126, 127)): (163, 255, 95, 160), + ((199, 65, 65), (199, 65, 199)): (199, 255, 65, 214), + ((199, 65, 65), (254, 1, 254)): (254, 255, 1, 255), + ((199, 65, 65), (255, 0, 255)): (255, 255, 0, 255), + ((254, 1, 1), (0, 255, 0)): (254, 255, 1, 1), + ((254, 1, 1), (1, 254, 1)): (253, 255, 2, 2), + ((254, 1, 1), (65, 199, 65)): (206, 255, 52, 66), + ((254, 1, 1), (126, 127, 126)): (191, 255, 63, 127), + ((254, 1, 1), (127, 126, 127)): (191, 255, 63, 128), + ((254, 1, 1), (199, 65, 199)): (212, 255, 51, 200), + ((254, 1, 1), (254, 1, 254)): (254, 255, 1, 255), + ((254, 1, 1), (255, 0, 255)): (255, 255, 0, 255), + ((255, 0, 0), (0, 255, 0)): (0, 255, 255, 0), + ((255, 0, 0), (1, 254, 1)): (1, 255, 254, 1), + ((255, 0, 0), (65, 199, 65)): (65, 255, 199, 65), + ((255, 0, 0), (126, 127, 126)): (126, 255, 127, 126), + ((255, 0, 0), (127, 126, 127)): (127, 255, 126, 127), + ((255, 0, 0), (199, 65, 199)): (199, 255, 65, 199), + ((255, 0, 0), (254, 1, 254)): (254, 255, 1, 254), + ((255, 0, 0), (255, 0, 255)): (255, 255, 0, 255), + } + + # chosen because they contain edge cases. + nums = [0, 1, 65, 126, 127, 199, 254, 255] + results = {} + for dst_r, dst_b, dst_a in zip(nums, reversed(nums), reversed(nums)): + for src_r, src_b, src_a in zip(nums, reversed(nums), nums): + with self.subTest( + src_r=src_r, + src_b=src_b, + src_a=src_a, + dest_r=dst_r, + dest_b=dst_b, + dest_a=dst_a, + ): + src_surf = pygame.Surface((66, 66), pygame.SRCALPHA, 32) + src_surf.fill((src_r, 255, src_b, 255)) + src_surf.set_alpha(src_a) + dest_surf = pygame.Surface((66, 66), pygame.SRCALPHA, 32) + dest_surf.fill((dst_r, 255, dst_b, dst_a)) + + dest_surf.blit(src_surf, (0, 0)) + key = ((dst_r, dst_b, dst_a), (src_r, src_b, src_a)) + results[key] = dest_surf.get_at((65, 33)) + self.assertEqual(results[key], results_expected[key]) + + self.assertEqual(results, results_expected) + + @unittest.skipIf( + "arm" in platform.machine() or "aarch64" in platform.machine(), + "sdl2 blitter produces different results on arm", + ) + def test_src_alpha_sdl2_blitter(self): + """Checking that the BLEND_ALPHA_SDL2 flag works - this feature + only exists when using SDL2""" + + results_expected = { + ((0, 255, 255), (0, 255, 0)): (0, 255, 255, 255), + ((0, 255, 255), (1, 254, 1)): (0, 253, 253, 253), + ((0, 255, 255), (65, 199, 65)): (16, 253, 239, 253), + ((0, 255, 255), (126, 127, 126)): (62, 253, 190, 253), + ((0, 255, 255), (127, 126, 127)): (63, 253, 189, 253), + ((0, 255, 255), (199, 65, 199)): (154, 253, 105, 253), + ((0, 255, 255), (254, 1, 254)): (252, 253, 0, 253), + ((0, 255, 255), (255, 0, 255)): (255, 255, 0, 255), + ((1, 254, 254), (0, 255, 0)): (1, 255, 254, 254), + ((1, 254, 254), (1, 254, 1)): (0, 253, 252, 252), + ((1, 254, 254), (65, 199, 65)): (16, 253, 238, 252), + ((1, 254, 254), (126, 127, 126)): (62, 253, 189, 252), + ((1, 254, 254), (127, 126, 127)): (63, 253, 189, 253), + ((1, 254, 254), (199, 65, 199)): (154, 253, 105, 253), + ((1, 254, 254), (254, 1, 254)): (252, 253, 0, 253), + ((1, 254, 254), (255, 0, 255)): (255, 255, 0, 255), + ((65, 199, 199), (0, 255, 0)): (65, 255, 199, 199), + ((65, 199, 199), (1, 254, 1)): (64, 253, 197, 197), + ((65, 199, 199), (65, 199, 65)): (64, 253, 197, 211), + ((65, 199, 199), (126, 127, 126)): (94, 253, 162, 225), + ((65, 199, 199), (127, 126, 127)): (95, 253, 161, 225), + ((65, 199, 199), (199, 65, 199)): (168, 253, 93, 241), + ((65, 199, 199), (254, 1, 254)): (252, 253, 0, 253), + ((65, 199, 199), (255, 0, 255)): (255, 255, 0, 255), + ((126, 127, 127), (0, 255, 0)): (126, 255, 127, 127), + ((126, 127, 127), (1, 254, 1)): (125, 253, 126, 126), + ((126, 127, 127), (65, 199, 65)): (109, 253, 144, 158), + ((126, 127, 127), (126, 127, 126)): (125, 253, 125, 188), + ((126, 127, 127), (127, 126, 127)): (126, 253, 125, 189), + ((126, 127, 127), (199, 65, 199)): (181, 253, 77, 225), + ((126, 127, 127), (254, 1, 254)): (252, 253, 0, 253), + ((126, 127, 127), (255, 0, 255)): (255, 255, 0, 255), + ((127, 126, 126), (0, 255, 0)): (127, 255, 126, 126), + ((127, 126, 126), (1, 254, 1)): (126, 253, 125, 125), + ((127, 126, 126), (65, 199, 65)): (110, 253, 143, 157), + ((127, 126, 126), (126, 127, 126)): (125, 253, 125, 188), + ((127, 126, 126), (127, 126, 127)): (126, 253, 125, 189), + ((127, 126, 126), (199, 65, 199)): (181, 253, 77, 225), + ((127, 126, 126), (254, 1, 254)): (252, 253, 0, 253), + ((127, 126, 126), (255, 0, 255)): (255, 255, 0, 255), + ((199, 65, 65), (0, 255, 0)): (199, 255, 65, 65), + ((199, 65, 65), (1, 254, 1)): (197, 253, 64, 64), + ((199, 65, 65), (65, 199, 65)): (163, 253, 98, 112), + ((199, 65, 65), (126, 127, 126)): (162, 253, 94, 157), + ((199, 65, 65), (127, 126, 127)): (162, 253, 94, 158), + ((199, 65, 65), (199, 65, 199)): (197, 253, 64, 212), + ((199, 65, 65), (254, 1, 254)): (252, 253, 0, 253), + ((199, 65, 65), (255, 0, 255)): (255, 255, 0, 255), + ((254, 1, 1), (0, 255, 0)): (254, 255, 1, 1), + ((254, 1, 1), (1, 254, 1)): (252, 253, 0, 0), + ((254, 1, 1), (65, 199, 65)): (204, 253, 50, 64), + ((254, 1, 1), (126, 127, 126)): (189, 253, 62, 125), + ((254, 1, 1), (127, 126, 127)): (190, 253, 62, 126), + ((254, 1, 1), (199, 65, 199)): (209, 253, 50, 198), + ((254, 1, 1), (254, 1, 254)): (252, 253, 0, 253), + ((254, 1, 1), (255, 0, 255)): (255, 255, 0, 255), + ((255, 0, 0), (0, 255, 0)): (255, 255, 0, 0), + ((255, 0, 0), (1, 254, 1)): (253, 253, 0, 0), + ((255, 0, 0), (65, 199, 65)): (205, 253, 50, 64), + ((255, 0, 0), (126, 127, 126)): (190, 253, 62, 125), + ((255, 0, 0), (127, 126, 127)): (190, 253, 62, 126), + ((255, 0, 0), (199, 65, 199)): (209, 253, 50, 198), + ((255, 0, 0), (254, 1, 254)): (252, 253, 0, 253), + ((255, 0, 0), (255, 0, 255)): (255, 255, 0, 255), + } + + # chosen because they contain edge cases. + nums = [0, 1, 65, 126, 127, 199, 254, 255] + results = {} + for dst_r, dst_b, dst_a in zip(nums, reversed(nums), reversed(nums)): + for src_r, src_b, src_a in zip(nums, reversed(nums), nums): + with self.subTest( + src_r=src_r, + src_b=src_b, + src_a=src_a, + dest_r=dst_r, + dest_b=dst_b, + dest_a=dst_a, + ): + src_surf = pygame.Surface((66, 66), pygame.SRCALPHA, 32) + src_surf.fill((src_r, 255, src_b, src_a)) + dest_surf = pygame.Surface((66, 66), pygame.SRCALPHA, 32) + dest_surf.fill((dst_r, 255, dst_b, dst_a)) + + dest_surf.blit( + src_surf, (0, 0), special_flags=pygame.BLEND_ALPHA_SDL2 + ) + key = ((dst_r, dst_b, dst_a), (src_r, src_b, src_a)) + results[key] = dest_surf.get_at((65, 33)) + self.assertEqual(results[key], results_expected[key]) + + # print("(dest_r, dest_b, dest_a), (src_r, src_b, src_a): color") + # pprint(results) + self.assertEqual(results, results_expected) + + def test_opaque_destination_blit_with_set_alpha(self): + # no set_alpha() + src_surf = pygame.Surface((32, 32), pygame.SRCALPHA, 32) + src_surf.fill((255, 255, 255, 200)) + dest_surf = pygame.Surface((32, 32)) + dest_surf.fill((100, 100, 100)) + + dest_surf.blit(src_surf, (0, 0)) + + no_surf_alpha_col = dest_surf.get_at((0, 0)) + + dest_surf.fill((100, 100, 100)) + dest_surf.set_alpha(200) + dest_surf.blit(src_surf, (0, 0)) + + surf_alpha_col = dest_surf.get_at((0, 0)) + + self.assertEqual(no_surf_alpha_col, surf_alpha_col) + + def todo_test_convert(self): + + # __doc__ (as of 2008-08-02) for pygame.surface.Surface.convert: + + # Surface.convert(Surface): return Surface + # Surface.convert(depth, flags=0): return Surface + # Surface.convert(masks, flags=0): return Surface + # Surface.convert(): return Surface + # change the pixel format of an image + # + # Creates a new copy of the Surface with the pixel format changed. The + # new pixel format can be determined from another existing Surface. + # Otherwise depth, flags, and masks arguments can be used, similar to + # the pygame.Surface() call. + # + # If no arguments are passed the new Surface will have the same pixel + # format as the display Surface. This is always the fastest format for + # blitting. It is a good idea to convert all Surfaces before they are + # blitted many times. + # + # The converted Surface will have no pixel alphas. They will be + # stripped if the original had them. See Surface.convert_alpha() for + # preserving or creating per-pixel alphas. + # + + self.fail() + + def test_convert__pixel_format_as_surface_subclass(self): + """Ensure convert accepts a Surface subclass argument.""" + expected_size = (23, 17) + convert_surface = SurfaceSubclass(expected_size, 0, 32) + depth_surface = SurfaceSubclass((31, 61), 0, 32) + + pygame.display.init() + try: + surface = convert_surface.convert(depth_surface) + + self.assertIsNot(surface, depth_surface) + self.assertIsNot(surface, convert_surface) + self.assertIsInstance(surface, pygame.Surface) + self.assertIsInstance(surface, SurfaceSubclass) + self.assertEqual(surface.get_size(), expected_size) + finally: + pygame.display.quit() + + def test_convert_alpha(self): + """Ensure the surface returned by surf.convert_alpha + has alpha values added""" + pygame.display.init() + try: + pygame.display.set_mode((640, 480)) + + s1 = pygame.Surface((100, 100), 0, 32) + s1_alpha = pygame.Surface.convert_alpha(s1) + + s2 = pygame.Surface((100, 100), 0, 32) + s2_alpha = s2.convert_alpha() + + s3 = pygame.Surface((100, 100), 0, 8) + s3_alpha = s3.convert_alpha() + + s4 = pygame.Surface((100, 100), 0, 12) + s4_alpha = s4.convert_alpha() + + s5 = pygame.Surface((100, 100), 0, 15) + s5_alpha = s5.convert_alpha() + + s6 = pygame.Surface((100, 100), 0, 16) + s6_alpha = s6.convert_alpha() + + s7 = pygame.Surface((100, 100), 0, 24) + s7_alpha = s7.convert_alpha() + + self.assertEqual(s1_alpha.get_alpha(), 255) + self.assertEqual(s2_alpha.get_alpha(), 255) + self.assertEqual(s3_alpha.get_alpha(), 255) + self.assertEqual(s4_alpha.get_alpha(), 255) + self.assertEqual(s5_alpha.get_alpha(), 255) + self.assertEqual(s6_alpha.get_alpha(), 255) + self.assertEqual(s7_alpha.get_alpha(), 255) + + self.assertEqual(s1_alpha.get_bitsize(), 32) + self.assertEqual(s2_alpha.get_bitsize(), 32) + self.assertEqual(s3_alpha.get_bitsize(), 32) + self.assertEqual(s4_alpha.get_bitsize(), 32) + self.assertEqual(s5_alpha.get_bitsize(), 32) + self.assertEqual(s6_alpha.get_bitsize(), 32) + self.assertEqual(s6_alpha.get_bitsize(), 32) + + with self.assertRaises(pygame.error): + surface = pygame.display.set_mode() + pygame.display.quit() + surface.convert_alpha() + + finally: + pygame.display.quit() + + def test_convert_alpha__pixel_format_as_surface_subclass(self): + """Ensure convert_alpha accepts a Surface subclass argument.""" + expected_size = (23, 17) + convert_surface = SurfaceSubclass(expected_size, SRCALPHA, 32) + depth_surface = SurfaceSubclass((31, 57), SRCALPHA, 32) + + pygame.display.init() + try: + pygame.display.set_mode((60, 60)) + + # This is accepted as an argument, but its values are ignored. + # See issue #599. + surface = convert_surface.convert_alpha(depth_surface) + + self.assertIsNot(surface, depth_surface) + self.assertIsNot(surface, convert_surface) + self.assertIsInstance(surface, pygame.Surface) + self.assertIsInstance(surface, SurfaceSubclass) + self.assertEqual(surface.get_size(), expected_size) + finally: + pygame.display.quit() + + def test_get_abs_offset(self): + pygame.display.init() + try: + parent = pygame.Surface((64, 64), SRCALPHA, 32) + + # Stack bunch of subsurfaces + sub_level_1 = parent.subsurface((2, 2), (34, 37)) + sub_level_2 = sub_level_1.subsurface((0, 0), (30, 29)) + sub_level_3 = sub_level_2.subsurface((3, 7), (20, 21)) + sub_level_4 = sub_level_3.subsurface((6, 1), (14, 14)) + sub_level_5 = sub_level_4.subsurface((5, 6), (3, 4)) + + # Parent is always (0, 0) + self.assertEqual(parent.get_abs_offset(), (0, 0)) + # Total offset: (0+2, 0+2) = (2, 2) + self.assertEqual(sub_level_1.get_abs_offset(), (2, 2)) + # Total offset: (0+2+0, 0+2+0) = (2, 2) + self.assertEqual(sub_level_2.get_abs_offset(), (2, 2)) + # Total offset: (0+2+0+3, 0+2+0+7) = (5, 9) + self.assertEqual(sub_level_3.get_abs_offset(), (5, 9)) + # Total offset: (0+2+0+3+6, 0+2+0+7+1) = (11, 10) + self.assertEqual(sub_level_4.get_abs_offset(), (11, 10)) + # Total offset: (0+2+0+3+6+5, 0+2+0+7+1+6) = (16, 16) + self.assertEqual(sub_level_5.get_abs_offset(), (16, 16)) + + with self.assertRaises(pygame.error): + surface = pygame.display.set_mode() + pygame.display.quit() + surface.get_abs_offset() + finally: + pygame.display.quit() + + def test_get_abs_parent(self): + pygame.display.init() + try: + parent = pygame.Surface((32, 32), SRCALPHA, 32) + + # Stack bunch of subsurfaces + sub_level_1 = parent.subsurface((1, 1), (15, 15)) + sub_level_2 = sub_level_1.subsurface((1, 1), (12, 12)) + sub_level_3 = sub_level_2.subsurface((1, 1), (9, 9)) + sub_level_4 = sub_level_3.subsurface((1, 1), (8, 8)) + sub_level_5 = sub_level_4.subsurface((2, 2), (3, 4)) + sub_level_6 = sub_level_5.subsurface((0, 0), (2, 1)) + + # Can't have subsurfaces bigger than parents + self.assertRaises(ValueError, parent.subsurface, (5, 5), (100, 100)) + self.assertRaises(ValueError, sub_level_3.subsurface, (0, 0), (11, 5)) + self.assertRaises(ValueError, sub_level_6.subsurface, (0, 0), (5, 5)) + + # Calling get_abs_parent on parent should return itself + self.assertEqual(parent.get_abs_parent(), parent) + + # On subclass "depth" of 1, get_abs_parent and get_parent should return the same + self.assertEqual(sub_level_1.get_abs_parent(), sub_level_1.get_parent()) + self.assertEqual(sub_level_2.get_abs_parent(), parent) + self.assertEqual(sub_level_3.get_abs_parent(), parent) + self.assertEqual(sub_level_4.get_abs_parent(), parent) + self.assertEqual(sub_level_5.get_abs_parent(), parent) + self.assertEqual( + sub_level_6.get_abs_parent(), sub_level_6.get_parent().get_abs_parent() + ) + + with self.assertRaises(pygame.error): + surface = pygame.display.set_mode() + pygame.display.quit() + surface.get_abs_parent() + finally: + pygame.display.quit() + + def test_get_at(self): + surf = pygame.Surface((2, 2), 0, 24) + c00 = pygame.Color(1, 2, 3) + c01 = pygame.Color(5, 10, 15) + c10 = pygame.Color(100, 50, 0) + c11 = pygame.Color(4, 5, 6) + surf.set_at((0, 0), c00) + surf.set_at((0, 1), c01) + surf.set_at((1, 0), c10) + surf.set_at((1, 1), c11) + c = surf.get_at((0, 0)) + self.assertIsInstance(c, pygame.Color) + self.assertEqual(c, c00) + self.assertEqual(surf.get_at((0, 1)), c01) + self.assertEqual(surf.get_at((1, 0)), c10) + self.assertEqual(surf.get_at((1, 1)), c11) + for p in [(-1, 0), (0, -1), (2, 0), (0, 2)]: + self.assertRaises(IndexError, surf.get_at, p) + + def test_get_at_mapped(self): + color = pygame.Color(10, 20, 30) + for bitsize in [8, 16, 24, 32]: + surf = pygame.Surface((2, 2), 0, bitsize) + surf.fill(color) + pixel = surf.get_at_mapped((0, 0)) + self.assertEqual( + pixel, + surf.map_rgb(color), + "%i != %i, bitsize: %i" % (pixel, surf.map_rgb(color), bitsize), + ) + + def test_get_bitsize(self): + pygame.display.init() + try: + expected_size = (11, 21) + + # Check that get_bitsize returns passed depth + expected_depth = 32 + surface = pygame.Surface(expected_size, pygame.SRCALPHA, expected_depth) + self.assertEqual(surface.get_size(), expected_size) + self.assertEqual(surface.get_bitsize(), expected_depth) + + expected_depth = 16 + surface = pygame.Surface(expected_size, pygame.SRCALPHA, expected_depth) + self.assertEqual(surface.get_size(), expected_size) + self.assertEqual(surface.get_bitsize(), expected_depth) + + expected_depth = 15 + surface = pygame.Surface(expected_size, 0, expected_depth) + self.assertEqual(surface.get_size(), expected_size) + self.assertEqual(surface.get_bitsize(), expected_depth) + # Check for invalid depths + expected_depth = -1 + self.assertRaises( + ValueError, pygame.Surface, expected_size, 0, expected_depth + ) + expected_depth = 11 + self.assertRaises( + ValueError, pygame.Surface, expected_size, 0, expected_depth + ) + expected_depth = 1024 + self.assertRaises( + ValueError, pygame.Surface, expected_size, 0, expected_depth + ) + + with self.assertRaises(pygame.error): + surface = pygame.display.set_mode() + pygame.display.quit() + surface.get_bitsize() + finally: + pygame.display.quit() + + def test_get_clip(self): + s = pygame.Surface((800, 600)) + rectangle = s.get_clip() + self.assertEqual(rectangle, (0, 0, 800, 600)) + + def test_get_colorkey(self): + pygame.display.init() + try: + # if set_colorkey is not used + s = pygame.Surface((800, 600), 0, 32) + self.assertIsNone(s.get_colorkey()) + + # if set_colorkey is used + s.set_colorkey(None) + self.assertIsNone(s.get_colorkey()) + + # setting up remainder of tests... + r, g, b, a = 20, 40, 60, 12 + colorkey = pygame.Color(r, g, b) + s.set_colorkey(colorkey) + + # test for ideal case + self.assertEqual(s.get_colorkey(), (r, g, b, 255)) + + # test for if the color_key is set using pygame.RLEACCEL + s.set_colorkey(colorkey, pygame.RLEACCEL) + self.assertEqual(s.get_colorkey(), (r, g, b, 255)) + + # test for if the color key is not what's expected + s.set_colorkey(pygame.Color(r + 1, g + 1, b + 1)) + self.assertNotEqual(s.get_colorkey(), (r, g, b, 255)) + + s.set_colorkey(pygame.Color(r, g, b, a)) + # regardless of whether alpha is not 255 + # colorkey returned from surface is always 255 + self.assertEqual(s.get_colorkey(), (r, g, b, 255)) + finally: + # test for using method after display.quit() is called... + s = pygame.display.set_mode((200, 200), 0, 32) + pygame.display.quit() + with self.assertRaises(pygame.error): + s.get_colorkey() + + def test_get_height(self): + sizes = ((1, 1), (119, 10), (10, 119), (1, 1000), (1000, 1), (1000, 1000)) + for width, height in sizes: + surf = pygame.Surface((width, height)) + found_height = surf.get_height() + self.assertEqual(height, found_height) + + def test_get_locked(self): + def blit_locked_test(surface): + newSurf = pygame.Surface((10, 10)) + try: + newSurf.blit(surface, (0, 0)) + except pygame.error: + return True + else: + return False + + surf = pygame.Surface((100, 100)) + + self.assertIs(surf.get_locked(), blit_locked_test(surf)) # Unlocked + # Surface should lock + surf.lock() + self.assertIs(surf.get_locked(), blit_locked_test(surf)) # Locked + # Surface should unlock + surf.unlock() + self.assertIs(surf.get_locked(), blit_locked_test(surf)) # Unlocked + + # Check multiple locks + surf = pygame.Surface((100, 100)) + surf.lock() + surf.lock() + self.assertIs(surf.get_locked(), blit_locked_test(surf)) # Locked + surf.unlock() + self.assertIs(surf.get_locked(), blit_locked_test(surf)) # Locked + surf.unlock() + self.assertIs(surf.get_locked(), blit_locked_test(surf)) # Unlocked + + # Check many locks + surf = pygame.Surface((100, 100)) + for i in range(1000): + surf.lock() + self.assertIs(surf.get_locked(), blit_locked_test(surf)) # Locked + for i in range(1000): + surf.unlock() + self.assertFalse(surf.get_locked()) # Unlocked + + # Unlocking an unlocked surface + surf = pygame.Surface((100, 100)) + surf.unlock() + self.assertIs(surf.get_locked(), blit_locked_test(surf)) # Unlocked + surf.unlock() + self.assertIs(surf.get_locked(), blit_locked_test(surf)) # Unlocked + + def test_get_locks(self): + + # __doc__ (as of 2008-08-02) for pygame.surface.Surface.get_locks: + + # Surface.get_locks(): return tuple + # Gets the locks for the Surface + # + # Returns the currently existing locks for the Surface. + + # test on a surface that is not initially locked + surface = pygame.Surface((100, 100)) + self.assertEqual(surface.get_locks(), ()) + + # test on the same surface after it has been locked + surface.lock() + self.assertEqual(surface.get_locks(), (surface,)) + + # test on the same surface after it has been unlocked + surface.unlock() + self.assertEqual(surface.get_locks(), ()) + + # test with PixelArray initialization: locks surface + pxarray = pygame.PixelArray(surface) + self.assertNotEqual(surface.get_locks(), ()) + + # closing the PixelArray releases the surface lock + pxarray.close() + self.assertEqual(surface.get_locks(), ()) + + # AttributeError raised when called on invalid object type (i.e. not a pygame.Surface object) + with self.assertRaises(AttributeError): + "DUMMY".get_locks() + + # test multiple locks and unlocks on the same surface + surface.lock() + surface.lock() + surface.lock() + self.assertEqual(surface.get_locks(), (surface, surface, surface)) + + surface.unlock() + surface.unlock() + self.assertEqual(surface.get_locks(), (surface,)) + surface.unlock() + self.assertEqual(surface.get_locks(), ()) + + def test_get_losses(self): + """Ensure a surface's losses can be retrieved""" + pygame.display.init() + try: + # Masks for different color component configurations + mask8 = (224, 28, 3, 0) + mask15 = (31744, 992, 31, 0) + mask16 = (63488, 2016, 31, 0) + mask24 = (4278190080, 16711680, 65280, 0) + mask32 = (4278190080, 16711680, 65280, 255) + + # Surfaces with standard depths and masks + display_surf = pygame.display.set_mode((100, 100)) + surf = pygame.Surface((100, 100)) + surf_8bit = pygame.Surface((100, 100), depth=8, masks=mask8) + surf_15bit = pygame.Surface((100, 100), depth=15, masks=mask15) + surf_16bit = pygame.Surface((100, 100), depth=16, masks=mask16) + surf_24bit = pygame.Surface((100, 100), depth=24, masks=mask24) + surf_32bit = pygame.Surface((100, 100), depth=32, masks=mask32) + + # Test output is correct type, length, and value range + losses = surf.get_losses() + self.assertIsInstance(losses, tuple) + self.assertEqual(len(losses), 4) + for loss in losses: + self.assertIsInstance(loss, int) + self.assertGreaterEqual(loss, 0) + self.assertLessEqual(loss, 8) + + # Test each surface for correct losses + # Display surface losses gives idea of default surface losses + if display_surf.get_losses() == (0, 0, 0, 8): + self.assertEqual(losses, (0, 0, 0, 8)) + elif display_surf.get_losses() == (8, 8, 8, 8): + self.assertEqual(losses, (8, 8, 8, 8)) + + self.assertEqual(surf_8bit.get_losses(), (5, 5, 6, 8)) + self.assertEqual(surf_15bit.get_losses(), (3, 3, 3, 8)) + self.assertEqual(surf_16bit.get_losses(), (3, 2, 3, 8)) + self.assertEqual(surf_24bit.get_losses(), (0, 0, 0, 8)) + self.assertEqual(surf_32bit.get_losses(), (0, 0, 0, 0)) + + # Method should fail when display is not initialized + with self.assertRaises(pygame.error): + surface = pygame.display.set_mode((100, 100)) + pygame.display.quit() + surface.get_losses() + finally: + pygame.display.quit() + + def test_get_masks__rgba(self): + """ + Ensure that get_mask can return RGBA mask. + """ + masks = [ + (0x0F00, 0x00F0, 0x000F, 0xF000), + (0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000), + ] + depths = [16, 32] + for expected, depth in list(zip(masks, depths)): + surface = pygame.Surface((10, 10), pygame.SRCALPHA, depth) + self.assertEqual(expected, surface.get_masks()) + + def test_get_masks__rgb(self): + """ + Ensure that get_mask can return RGB mask. + """ + masks = [ + (0x60, 0x1C, 0x03, 0x00), + (0xF00, 0x0F0, 0x00F, 0x000), + (0x7C00, 0x03E0, 0x001F, 0x0000), + (0xF800, 0x07E0, 0x001F, 0x0000), + (0xFF0000, 0x00FF00, 0x0000FF, 0x000000), + (0xFF0000, 0x00FF00, 0x0000FF, 0x000000), + ] + depths = [8, 12, 15, 16, 24, 32] + for expected, depth in list(zip(masks, depths)): + surface = pygame.Surface((10, 10), 0, depth) + if depth == 8: + expected = (0x00, 0x00, 0x00, 0x00) + self.assertEqual(expected, surface.get_masks()) + + def test_get_masks__no_surface(self): + """ + Ensure that after display.quit, calling get_masks raises pygame.error. + """ + with self.assertRaises(pygame.error): + surface = pygame.display.set_mode((10, 10)) + pygame.display.quit() + surface.get_masks() + + def test_get_offset(self): + """get_offset returns the (0,0) if surface is not a child + returns the position of child subsurface inside of parent + """ + pygame.display.init() + try: + surf = pygame.Surface((100, 100)) + self.assertEqual(surf.get_offset(), (0, 0)) + + # subsurface offset test + subsurf = surf.subsurface(1, 1, 10, 10) + self.assertEqual(subsurf.get_offset(), (1, 1)) + + with self.assertRaises(pygame.error): + surface = pygame.display.set_mode() + pygame.display.quit() + surface.get_offset() + finally: + pygame.display.quit() + + def test_get_palette(self): + pygame.display.init() + try: + palette = [Color(i, i, i) for i in range(256)] + pygame.display.set_mode((100, 50)) + surf = pygame.Surface((2, 2), 0, 8) + surf.set_palette(palette) + palette2 = surf.get_palette() + r, g, b = palette2[0] + + self.assertEqual(len(palette2), len(palette)) + for c2, c in zip(palette2, palette): + self.assertEqual(c2, c) + for c in palette2: + self.assertIsInstance(c, pygame.Color) + finally: + pygame.display.quit() + + def test_get_palette_at(self): + # See also test_get_palette + pygame.display.init() + try: + pygame.display.set_mode((100, 50)) + surf = pygame.Surface((2, 2), 0, 8) + color = pygame.Color(1, 2, 3, 255) + surf.set_palette_at(0, color) + color2 = surf.get_palette_at(0) + self.assertIsInstance(color2, pygame.Color) + self.assertEqual(color2, color) + self.assertRaises(IndexError, surf.get_palette_at, -1) + self.assertRaises(IndexError, surf.get_palette_at, 256) + finally: + pygame.display.quit() + + def test_get_pitch(self): + # Test get_pitch() on several surfaces of varying size/depth + sizes = ((2, 2), (7, 33), (33, 7), (2, 734), (734, 2), (734, 734)) + depths = [8, 24, 32] + for width, height in sizes: + for depth in depths: + # Test get_pitch() on parent surface + surf = pygame.Surface((width, height), depth=depth) + buff = surf.get_buffer() + pitch = buff.length / surf.get_height() + test_pitch = surf.get_pitch() + self.assertEqual(pitch, test_pitch) + # Test get_pitch() on subsurface with same rect as parent + rect1 = surf.get_rect() + subsurf1 = surf.subsurface(rect1) + sub_buff1 = subsurf1.get_buffer() + sub_pitch1 = sub_buff1.length / subsurf1.get_height() + test_sub_pitch1 = subsurf1.get_pitch() + self.assertEqual(sub_pitch1, test_sub_pitch1) + # Test get_pitch on subsurface with modified rect + rect2 = rect1.inflate(-width / 2, -height / 2) + subsurf2 = surf.subsurface(rect2) + sub_buff2 = subsurf2.get_buffer() + sub_pitch2 = sub_buff2.length / float(subsurf2.get_height()) + test_sub_pitch2 = subsurf2.get_pitch() + self.assertEqual(sub_pitch2, test_sub_pitch2) + + def test_get_shifts(self): + """ + Tests whether Surface.get_shifts returns proper + RGBA shifts under various conditions. + """ + # __doc__ (as of 2008-08-02) for pygame.surface.Surface.get_shifts: + # Surface.get_shifts(): return (R, G, B, A) + # the bit shifts needed to convert between color and mapped integer. + # Returns the pixel shifts need to convert between each color and a + # mapped integer. + # This value is not needed for normal Pygame usage. + + # Test for SDL2 on surfaces with various depths and alpha on/off + depths = [8, 24, 32] + alpha = 128 + off = None + for bit_depth in depths: + surface = pygame.Surface((32, 32), depth=bit_depth) + surface.set_alpha(alpha) + r1, g1, b1, a1 = surface.get_shifts() + surface.set_alpha(off) + r2, g2, b2, a2 = surface.get_shifts() + self.assertEqual((r1, g1, b1, a1), (r2, g2, b2, a2)) + + def test_get_size(self): + sizes = ((1, 1), (119, 10), (1000, 1000), (1, 5000), (1221, 1), (99, 999)) + for width, height in sizes: + surf = pygame.Surface((width, height)) + found_size = surf.get_size() + self.assertEqual((width, height), found_size) + + def test_lock(self): + + # __doc__ (as of 2008-08-02) for pygame.surface.Surface.lock: + + # Surface.lock(): return None + # lock the Surface memory for pixel access + # + # Lock the pixel data of a Surface for access. On accelerated + # Surfaces, the pixel data may be stored in volatile video memory or + # nonlinear compressed forms. When a Surface is locked the pixel + # memory becomes available to access by regular software. Code that + # reads or writes pixel values will need the Surface to be locked. + # + # Surfaces should not remain locked for more than necessary. A locked + # Surface can often not be displayed or managed by Pygame. + # + # Not all Surfaces require locking. The Surface.mustlock() method can + # determine if it is actually required. There is no performance + # penalty for locking and unlocking a Surface that does not need it. + # + # All pygame functions will automatically lock and unlock the Surface + # data as needed. If a section of code is going to make calls that + # will repeatedly lock and unlock the Surface many times, it can be + # helpful to wrap the block inside a lock and unlock pair. + # + # It is safe to nest locking and unlocking calls. The surface will + # only be unlocked after the final lock is released. + # + + # Basic + surf = pygame.Surface((100, 100)) + surf.lock() + self.assertTrue(surf.get_locked()) + + # Nested + surf = pygame.Surface((100, 100)) + surf.lock() + surf.lock() + surf.unlock() + self.assertTrue(surf.get_locked()) + surf.unlock() + surf.lock() + surf.lock() + self.assertTrue(surf.get_locked()) + surf.unlock() + self.assertTrue(surf.get_locked()) + surf.unlock() + self.assertFalse(surf.get_locked()) + + # Already Locked + surf = pygame.Surface((100, 100)) + surf.lock() + surf.lock() + self.assertTrue(surf.get_locked()) + surf.unlock() + self.assertTrue(surf.get_locked()) + surf.unlock() + self.assertFalse(surf.get_locked()) + + def test_map_rgb(self): + color = Color(0, 128, 255, 64) + surf = pygame.Surface((5, 5), SRCALPHA, 32) + c = surf.map_rgb(color) + self.assertEqual(surf.unmap_rgb(c), color) + + self.assertEqual(surf.get_at((0, 0)), (0, 0, 0, 0)) + surf.fill(c) + self.assertEqual(surf.get_at((0, 0)), color) + + surf.fill((0, 0, 0, 0)) + self.assertEqual(surf.get_at((0, 0)), (0, 0, 0, 0)) + surf.set_at((0, 0), c) + self.assertEqual(surf.get_at((0, 0)), color) + + def test_mustlock(self): + # Test that subsurfaces mustlock + surf = pygame.Surface((1024, 1024)) + subsurf = surf.subsurface((0, 0, 1024, 1024)) + self.assertTrue(subsurf.mustlock()) + self.assertFalse(surf.mustlock()) + # Tests nested subsurfaces + rects = ((0, 0, 512, 512), (0, 0, 256, 256), (0, 0, 128, 128)) + surf_stack = [] + surf_stack.append(surf) + surf_stack.append(subsurf) + for rect in rects: + surf_stack.append(surf_stack[-1].subsurface(rect)) + self.assertTrue(surf_stack[-1].mustlock()) + self.assertTrue(surf_stack[-2].mustlock()) + + def test_set_alpha_none(self): + """surf.set_alpha(None) disables blending""" + s = pygame.Surface((1, 1), SRCALPHA, 32) + s.fill((0, 255, 0, 128)) + s.set_alpha(None) + self.assertEqual(None, s.get_alpha()) + + s2 = pygame.Surface((1, 1), SRCALPHA, 32) + s2.fill((255, 0, 0, 255)) + s2.blit(s, (0, 0)) + self.assertEqual(s2.get_at((0, 0))[0], 0, "the red component should be 0") + + def test_set_alpha_value(self): + """surf.set_alpha(x), where x != None, enables blending""" + s = pygame.Surface((1, 1), SRCALPHA, 32) + s.fill((0, 255, 0, 128)) + s.set_alpha(255) + + s2 = pygame.Surface((1, 1), SRCALPHA, 32) + s2.fill((255, 0, 0, 255)) + s2.blit(s, (0, 0)) + self.assertGreater( + s2.get_at((0, 0))[0], 0, "the red component should be above 0" + ) + + def test_palette_colorkey(self): + """test bug discovered by robertpfeiffer + https://github.com/pygame/pygame/issues/721 + """ + surf = pygame.image.load(example_path(os.path.join("data", "alien2.png"))) + key = surf.get_colorkey() + self.assertEqual(surf.get_palette()[surf.map_rgb(key)], key) + + def test_palette_colorkey_set_px(self): + surf = pygame.image.load(example_path(os.path.join("data", "alien2.png"))) + key = surf.get_colorkey() + surf.set_at((0, 0), key) + self.assertEqual(surf.get_at((0, 0)), key) + + def test_palette_colorkey_fill(self): + surf = pygame.image.load(example_path(os.path.join("data", "alien2.png"))) + key = surf.get_colorkey() + surf.fill(key) + self.assertEqual(surf.get_at((0, 0)), key) + + def test_set_palette(self): + palette = [pygame.Color(i, i, i) for i in range(256)] + palette[10] = tuple(palette[10]) # 4 element tuple + palette[11] = tuple(palette[11])[0:3] # 3 element tuple + + surf = pygame.Surface((2, 2), 0, 8) + pygame.display.init() + try: + pygame.display.set_mode((100, 50)) + surf.set_palette(palette) + for i in range(256): + self.assertEqual(surf.map_rgb(palette[i]), i, "palette color %i" % (i,)) + c = palette[i] + surf.fill(c) + self.assertEqual(surf.get_at((0, 0)), c, "palette color %i" % (i,)) + for i in range(10): + palette[i] = pygame.Color(255 - i, 0, 0) + surf.set_palette(palette[0:10]) + for i in range(256): + self.assertEqual(surf.map_rgb(palette[i]), i, "palette color %i" % (i,)) + c = palette[i] + surf.fill(c) + self.assertEqual(surf.get_at((0, 0)), c, "palette color %i" % (i,)) + self.assertRaises(ValueError, surf.set_palette, [Color(1, 2, 3, 254)]) + self.assertRaises(ValueError, surf.set_palette, (1, 2, 3, 254)) + finally: + pygame.display.quit() + + def test_set_palette__fail(self): + pygame.init() + palette = 256 * [(10, 20, 30)] + surf = pygame.Surface((2, 2), 0, 32) + self.assertRaises(pygame.error, surf.set_palette, palette) + pygame.quit() + + def test_set_palette_at(self): + pygame.display.init() + try: + pygame.display.set_mode((100, 50)) + surf = pygame.Surface((2, 2), 0, 8) + original = surf.get_palette_at(10) + replacement = Color(1, 1, 1, 255) + if replacement == original: + replacement = Color(2, 2, 2, 255) + surf.set_palette_at(10, replacement) + self.assertEqual(surf.get_palette_at(10), replacement) + next = tuple(original) + surf.set_palette_at(10, next) + self.assertEqual(surf.get_palette_at(10), next) + next = tuple(original)[0:3] + surf.set_palette_at(10, next) + self.assertEqual(surf.get_palette_at(10), next) + self.assertRaises(IndexError, surf.set_palette_at, 256, replacement) + self.assertRaises(IndexError, surf.set_palette_at, -1, replacement) + finally: + pygame.display.quit() + + def test_subsurface(self): + + # __doc__ (as of 2008-08-02) for pygame.surface.Surface.subsurface: + + # Surface.subsurface(Rect): return Surface + # create a new surface that references its parent + # + # Returns a new Surface that shares its pixels with its new parent. + # The new Surface is considered a child of the original. Modifications + # to either Surface pixels will effect each other. Surface information + # like clipping area and color keys are unique to each Surface. + # + # The new Surface will inherit the palette, color key, and alpha + # settings from its parent. + # + # It is possible to have any number of subsurfaces and subsubsurfaces + # on the parent. It is also possible to subsurface the display Surface + # if the display mode is not hardware accelerated. + # + # See the Surface.get_offset(), Surface.get_parent() to learn more + # about the state of a subsurface. + # + + surf = pygame.Surface((16, 16)) + s = surf.subsurface(0, 0, 1, 1) + s = surf.subsurface((0, 0, 1, 1)) + + # s = surf.subsurface((0,0,1,1), 1) + # This form is not acceptable. + # s = surf.subsurface(0,0,10,10, 1) + + self.assertRaises(ValueError, surf.subsurface, (0, 0, 1, 1, 666)) + + self.assertEqual(s.get_shifts(), surf.get_shifts()) + self.assertEqual(s.get_masks(), surf.get_masks()) + self.assertEqual(s.get_losses(), surf.get_losses()) + + # Issue 2 at Bitbucket.org/pygame/pygame + surf = pygame.Surface.__new__(pygame.Surface) + self.assertRaises(pygame.error, surf.subsurface, (0, 0, 0, 0)) + + def test_unlock(self): + # Basic + surf = pygame.Surface((100, 100)) + surf.lock() + surf.unlock() + self.assertFalse(surf.get_locked()) + + # Nested + surf = pygame.Surface((100, 100)) + surf.lock() + surf.lock() + surf.unlock() + self.assertTrue(surf.get_locked()) + surf.unlock() + self.assertFalse(surf.get_locked()) + + # Already Unlocked + surf = pygame.Surface((100, 100)) + surf.unlock() + self.assertFalse(surf.get_locked()) + surf.unlock() + self.assertFalse(surf.get_locked()) + + # Surface can be relocked + surf = pygame.Surface((100, 100)) + surf.lock() + surf.unlock() + self.assertFalse(surf.get_locked()) + surf.lock() + surf.unlock() + self.assertFalse(surf.get_locked()) + + def test_unmap_rgb(self): + # Special case, 8 bit-per-pixel surface (has a palette). + surf = pygame.Surface((2, 2), 0, 8) + c = (1, 1, 1) # Unlikely to be in a default palette. + i = 67 + pygame.display.init() + try: + pygame.display.set_mode((100, 50)) + surf.set_palette_at(i, c) + unmapped_c = surf.unmap_rgb(i) + self.assertEqual(unmapped_c, c) + # Confirm it is a Color instance + self.assertIsInstance(unmapped_c, pygame.Color) + finally: + pygame.display.quit() + + # Remaining, non-pallete, cases. + c = (128, 64, 12, 255) + formats = [(0, 16), (0, 24), (0, 32), (SRCALPHA, 16), (SRCALPHA, 32)] + for flags, bitsize in formats: + surf = pygame.Surface((2, 2), flags, bitsize) + unmapped_c = surf.unmap_rgb(surf.map_rgb(c)) + surf.fill(c) + comparison_c = surf.get_at((0, 0)) + self.assertEqual( + unmapped_c, + comparison_c, + "%s != %s, flags: %i, bitsize: %i" + % (unmapped_c, comparison_c, flags, bitsize), + ) + # Confirm it is a Color instance + self.assertIsInstance(unmapped_c, pygame.Color) + + def test_scroll(self): + scrolls = [ + (8, 2, 3), + (16, 2, 3), + (24, 2, 3), + (32, 2, 3), + (32, -1, -3), + (32, 0, 0), + (32, 11, 0), + (32, 0, 11), + (32, -11, 0), + (32, 0, -11), + (32, -11, 2), + (32, 2, -11), + ] + for bitsize, dx, dy in scrolls: + surf = pygame.Surface((10, 10), 0, bitsize) + surf.fill((255, 0, 0)) + surf.fill((0, 255, 0), (2, 2, 2, 2)) + comp = surf.copy() + comp.blit(surf, (dx, dy)) + surf.scroll(dx, dy) + w, h = surf.get_size() + for x in range(w): + for y in range(h): + with self.subTest(x=x, y=y): + self.assertEqual( + surf.get_at((x, y)), + comp.get_at((x, y)), + "%s != %s, bpp:, %i, x: %i, y: %i" + % ( + surf.get_at((x, y)), + comp.get_at((x, y)), + bitsize, + dx, + dy, + ), + ) + # Confirm clip rect containment + surf = pygame.Surface((20, 13), 0, 32) + surf.fill((255, 0, 0)) + surf.fill((0, 255, 0), (7, 1, 6, 6)) + comp = surf.copy() + clip = Rect(3, 1, 8, 14) + surf.set_clip(clip) + comp.set_clip(clip) + comp.blit(surf, (clip.x + 2, clip.y + 3), surf.get_clip()) + surf.scroll(2, 3) + w, h = surf.get_size() + for x in range(w): + for y in range(h): + self.assertEqual(surf.get_at((x, y)), comp.get_at((x, y))) + # Confirm keyword arguments and per-pixel alpha + spot_color = (0, 255, 0, 128) + surf = pygame.Surface((4, 4), pygame.SRCALPHA, 32) + surf.fill((255, 0, 0, 255)) + surf.set_at((1, 1), spot_color) + surf.scroll(dx=1) + self.assertEqual(surf.get_at((2, 1)), spot_color) + surf.scroll(dy=1) + self.assertEqual(surf.get_at((2, 2)), spot_color) + surf.scroll(dy=1, dx=1) + self.assertEqual(surf.get_at((3, 3)), spot_color) + surf.scroll(dx=-3, dy=-3) + self.assertEqual(surf.get_at((0, 0)), spot_color) + + +class SurfaceSubtypeTest(unittest.TestCase): + """Issue #280: Methods that return a new Surface preserve subclasses""" + + def setUp(self): + pygame.display.init() + + def tearDown(self): + pygame.display.quit() + + def test_copy(self): + """Ensure method copy() preserves the surface's class + + When Surface is subclassed, the inherited copy() method will return + instances of the subclass. Non Surface fields are uncopied, however. + This includes instance attributes. + """ + expected_size = (32, 32) + ms1 = SurfaceSubclass(expected_size, SRCALPHA, 32) + ms2 = ms1.copy() + + self.assertIsNot(ms1, ms2) + self.assertIsInstance(ms1, pygame.Surface) + self.assertIsInstance(ms2, pygame.Surface) + self.assertIsInstance(ms1, SurfaceSubclass) + self.assertIsInstance(ms2, SurfaceSubclass) + self.assertTrue(ms1.test_attribute) + self.assertRaises(AttributeError, getattr, ms2, "test_attribute") + self.assertEqual(ms2.get_size(), expected_size) + + def test_convert(self): + """Ensure method convert() preserves the surface's class + + When Surface is subclassed, the inherited convert() method will return + instances of the subclass. Non Surface fields are omitted, however. + This includes instance attributes. + """ + expected_size = (32, 32) + ms1 = SurfaceSubclass(expected_size, 0, 24) + ms2 = ms1.convert(24) + + self.assertIsNot(ms1, ms2) + self.assertIsInstance(ms1, pygame.Surface) + self.assertIsInstance(ms2, pygame.Surface) + self.assertIsInstance(ms1, SurfaceSubclass) + self.assertIsInstance(ms2, SurfaceSubclass) + self.assertTrue(ms1.test_attribute) + self.assertRaises(AttributeError, getattr, ms2, "test_attribute") + self.assertEqual(ms2.get_size(), expected_size) + + def test_convert_alpha(self): + """Ensure method convert_alpha() preserves the surface's class + + When Surface is subclassed, the inherited convert_alpha() method will + return instances of the subclass. Non Surface fields are omitted, + however. This includes instance attributes. + """ + pygame.display.set_mode((40, 40)) + expected_size = (32, 32) + s = pygame.Surface(expected_size, SRCALPHA, 16) + ms1 = SurfaceSubclass(expected_size, SRCALPHA, 32) + ms2 = ms1.convert_alpha(s) + + self.assertIsNot(ms1, ms2) + self.assertIsInstance(ms1, pygame.Surface) + self.assertIsInstance(ms2, pygame.Surface) + self.assertIsInstance(ms1, SurfaceSubclass) + self.assertIsInstance(ms2, SurfaceSubclass) + self.assertTrue(ms1.test_attribute) + self.assertRaises(AttributeError, getattr, ms2, "test_attribute") + self.assertEqual(ms2.get_size(), expected_size) + + def test_subsurface(self): + """Ensure method subsurface() preserves the surface's class + + When Surface is subclassed, the inherited subsurface() method will + return instances of the subclass. Non Surface fields are uncopied, + however. This includes instance attributes. + """ + expected_size = (10, 12) + ms1 = SurfaceSubclass((32, 32), SRCALPHA, 32) + ms2 = ms1.subsurface((4, 5), expected_size) + + self.assertIsNot(ms1, ms2) + self.assertIsInstance(ms1, pygame.Surface) + self.assertIsInstance(ms2, pygame.Surface) + self.assertIsInstance(ms1, SurfaceSubclass) + self.assertIsInstance(ms2, SurfaceSubclass) + self.assertTrue(ms1.test_attribute) + self.assertRaises(AttributeError, getattr, ms2, "test_attribute") + self.assertEqual(ms2.get_size(), expected_size) + + +class SurfaceGetBufferTest(unittest.TestCase): + # These tests requires ctypes. They are disabled if ctypes + # is not installed. + try: + ArrayInterface + except NameError: + __tags__ = ("ignore", "subprocess_ignore") + + lilendian = pygame.get_sdl_byteorder() == pygame.LIL_ENDIAN + + def _check_interface_2D(self, s): + s_w, s_h = s.get_size() + s_bytesize = s.get_bytesize() + s_pitch = s.get_pitch() + s_pixels = s._pixels_address + + # check the array interface structure fields. + v = s.get_view("2") + if not IS_PYPY: + flags = PAI_ALIGNED | PAI_NOTSWAPPED | PAI_WRITEABLE + if s.get_pitch() == s_w * s_bytesize: + flags |= PAI_FORTRAN + + inter = ArrayInterface(v) + + self.assertEqual(inter.two, 2) + self.assertEqual(inter.nd, 2) + self.assertEqual(inter.typekind, "u") + self.assertEqual(inter.itemsize, s_bytesize) + self.assertEqual(inter.shape[0], s_w) + self.assertEqual(inter.shape[1], s_h) + self.assertEqual(inter.strides[0], s_bytesize) + self.assertEqual(inter.strides[1], s_pitch) + self.assertEqual(inter.flags, flags) + self.assertEqual(inter.data, s_pixels) + + def _check_interface_3D(self, s): + s_w, s_h = s.get_size() + s_bytesize = s.get_bytesize() + s_pitch = s.get_pitch() + s_pixels = s._pixels_address + s_shifts = list(s.get_shifts()) + + # Check for RGB or BGR surface. + if s_shifts[0:3] == [0, 8, 16]: + if self.lilendian: + # RGB + offset = 0 + step = 1 + else: + # BGR + offset = s_bytesize - 1 + step = -1 + elif s_shifts[0:3] == [8, 16, 24]: + if self.lilendian: + # xRGB + offset = 1 + step = 1 + else: + # BGRx + offset = s_bytesize - 2 + step = -1 + elif s_shifts[0:3] == [16, 8, 0]: + if self.lilendian: + # BGR + offset = 2 + step = -1 + else: + # RGB + offset = s_bytesize - 3 + step = 1 + elif s_shifts[0:3] == [24, 16, 8]: + if self.lilendian: + # BGRx + offset = 2 + step = -1 + else: + # RGBx + offset = s_bytesize - 4 + step = -1 + else: + return + + # check the array interface structure fields. + v = s.get_view("3") + if not IS_PYPY: + inter = ArrayInterface(v) + flags = PAI_ALIGNED | PAI_NOTSWAPPED | PAI_WRITEABLE + self.assertEqual(inter.two, 2) + self.assertEqual(inter.nd, 3) + self.assertEqual(inter.typekind, "u") + self.assertEqual(inter.itemsize, 1) + self.assertEqual(inter.shape[0], s_w) + self.assertEqual(inter.shape[1], s_h) + self.assertEqual(inter.shape[2], 3) + self.assertEqual(inter.strides[0], s_bytesize) + self.assertEqual(inter.strides[1], s_pitch) + self.assertEqual(inter.strides[2], step) + self.assertEqual(inter.flags, flags) + self.assertEqual(inter.data, s_pixels + offset) + + def _check_interface_rgba(self, s, plane): + s_w, s_h = s.get_size() + s_bytesize = s.get_bytesize() + s_pitch = s.get_pitch() + s_pixels = s._pixels_address + s_shifts = s.get_shifts() + s_masks = s.get_masks() + + # Find the color plane position within the pixel. + if not s_masks[plane]: + return + alpha_shift = s_shifts[plane] + offset = alpha_shift // 8 + if not self.lilendian: + offset = s_bytesize - offset - 1 + + # check the array interface structure fields. + v = s.get_view("rgba"[plane]) + if not IS_PYPY: + inter = ArrayInterface(v) + flags = PAI_ALIGNED | PAI_NOTSWAPPED | PAI_WRITEABLE + self.assertEqual(inter.two, 2) + self.assertEqual(inter.nd, 2) + self.assertEqual(inter.typekind, "u") + self.assertEqual(inter.itemsize, 1) + self.assertEqual(inter.shape[0], s_w) + self.assertEqual(inter.shape[1], s_h) + self.assertEqual(inter.strides[0], s_bytesize) + self.assertEqual(inter.strides[1], s_pitch) + self.assertEqual(inter.flags, flags) + self.assertEqual(inter.data, s_pixels + offset) + + def test_array_interface(self): + self._check_interface_2D(pygame.Surface((5, 7), 0, 8)) + self._check_interface_2D(pygame.Surface((5, 7), 0, 16)) + self._check_interface_2D(pygame.Surface((5, 7), pygame.SRCALPHA, 16)) + self._check_interface_3D(pygame.Surface((5, 7), 0, 24)) + self._check_interface_3D(pygame.Surface((8, 4), 0, 24)) # No gaps + self._check_interface_2D(pygame.Surface((5, 7), 0, 32)) + self._check_interface_3D(pygame.Surface((5, 7), 0, 32)) + self._check_interface_2D(pygame.Surface((5, 7), pygame.SRCALPHA, 32)) + self._check_interface_3D(pygame.Surface((5, 7), pygame.SRCALPHA, 32)) + + def test_array_interface_masks(self): + """Test non-default color byte orders on 3D views""" + + sz = (5, 7) + # Reversed RGB byte order + s = pygame.Surface(sz, 0, 32) + s_masks = list(s.get_masks()) + masks = [0xFF, 0xFF00, 0xFF0000] + if s_masks[0:3] == masks or s_masks[0:3] == masks[::-1]: + masks = s_masks[2::-1] + s_masks[3:4] + self._check_interface_3D(pygame.Surface(sz, 0, 32, masks)) + s = pygame.Surface(sz, 0, 24) + s_masks = list(s.get_masks()) + masks = [0xFF, 0xFF00, 0xFF0000] + if s_masks[0:3] == masks or s_masks[0:3] == masks[::-1]: + masks = s_masks[2::-1] + s_masks[3:4] + self._check_interface_3D(pygame.Surface(sz, 0, 24, masks)) + + masks = [0xFF00, 0xFF0000, 0xFF000000, 0] + self._check_interface_3D(pygame.Surface(sz, 0, 32, masks)) + + def test_array_interface_alpha(self): + for shifts in [[0, 8, 16, 24], [8, 16, 24, 0], [24, 16, 8, 0], [16, 8, 0, 24]]: + masks = [0xFF << s for s in shifts] + s = pygame.Surface((4, 2), pygame.SRCALPHA, 32, masks) + self._check_interface_rgba(s, 3) + + def test_array_interface_rgb(self): + for shifts in [[0, 8, 16, 24], [8, 16, 24, 0], [24, 16, 8, 0], [16, 8, 0, 24]]: + masks = [0xFF << s for s in shifts] + masks[3] = 0 + for plane in range(3): + s = pygame.Surface((4, 2), 0, 24) + self._check_interface_rgba(s, plane) + s = pygame.Surface((4, 2), 0, 32) + self._check_interface_rgba(s, plane) + + @unittest.skipIf(not pygame.HAVE_NEWBUF, "newbuf not implemented") + def test_newbuf_PyBUF_flags_bytes(self): + from pygame.tests.test_utils import buftools + + Importer = buftools.Importer + s = pygame.Surface((10, 6), 0, 32) + a = s.get_buffer() + b = Importer(a, buftools.PyBUF_SIMPLE) + self.assertEqual(b.ndim, 0) + self.assertTrue(b.format is None) + self.assertEqual(b.len, a.length) + self.assertEqual(b.itemsize, 1) + self.assertTrue(b.shape is None) + self.assertTrue(b.strides is None) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, s._pixels_address) + b = Importer(a, buftools.PyBUF_WRITABLE) + self.assertEqual(b.ndim, 0) + self.assertTrue(b.format is None) + self.assertFalse(b.readonly) + b = Importer(a, buftools.PyBUF_FORMAT) + self.assertEqual(b.ndim, 0) + self.assertEqual(b.format, "B") + b = Importer(a, buftools.PyBUF_ND) + self.assertEqual(b.ndim, 1) + self.assertTrue(b.format is None) + self.assertEqual(b.len, a.length) + self.assertEqual(b.itemsize, 1) + self.assertEqual(b.shape, (a.length,)) + self.assertTrue(b.strides is None) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, s._pixels_address) + b = Importer(a, buftools.PyBUF_STRIDES) + self.assertEqual(b.ndim, 1) + self.assertTrue(b.format is None) + self.assertEqual(b.strides, (1,)) + s2 = s.subsurface((1, 1, 7, 4)) # Not contiguous + a = s2.get_buffer() + b = Importer(a, buftools.PyBUF_SIMPLE) + self.assertEqual(b.ndim, 0) + self.assertTrue(b.format is None) + self.assertEqual(b.len, a.length) + self.assertEqual(b.itemsize, 1) + self.assertTrue(b.shape is None) + self.assertTrue(b.strides is None) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, s2._pixels_address) + b = Importer(a, buftools.PyBUF_C_CONTIGUOUS) + self.assertEqual(b.ndim, 1) + self.assertEqual(b.strides, (1,)) + b = Importer(a, buftools.PyBUF_F_CONTIGUOUS) + self.assertEqual(b.ndim, 1) + self.assertEqual(b.strides, (1,)) + b = Importer(a, buftools.PyBUF_ANY_CONTIGUOUS) + self.assertEqual(b.ndim, 1) + self.assertEqual(b.strides, (1,)) + + @unittest.skipIf(not pygame.HAVE_NEWBUF, "newbuf not implemented") + def test_newbuf_PyBUF_flags_0D(self): + # This is the same handler as used by get_buffer(), so just + # confirm that it succeeds for one case. + from pygame.tests.test_utils import buftools + + Importer = buftools.Importer + s = pygame.Surface((10, 6), 0, 32) + a = s.get_view("0") + b = Importer(a, buftools.PyBUF_SIMPLE) + self.assertEqual(b.ndim, 0) + self.assertTrue(b.format is None) + self.assertEqual(b.len, a.length) + self.assertEqual(b.itemsize, 1) + self.assertTrue(b.shape is None) + self.assertTrue(b.strides is None) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, s._pixels_address) + + @unittest.skipIf(not pygame.HAVE_NEWBUF, "newbuf not implemented") + def test_newbuf_PyBUF_flags_1D(self): + from pygame.tests.test_utils import buftools + + Importer = buftools.Importer + s = pygame.Surface((10, 6), 0, 32) + a = s.get_view("1") + b = Importer(a, buftools.PyBUF_SIMPLE) + self.assertEqual(b.ndim, 0) + self.assertTrue(b.format is None) + self.assertEqual(b.len, a.length) + self.assertEqual(b.itemsize, s.get_bytesize()) + self.assertTrue(b.shape is None) + self.assertTrue(b.strides is None) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, s._pixels_address) + b = Importer(a, buftools.PyBUF_WRITABLE) + self.assertEqual(b.ndim, 0) + self.assertTrue(b.format is None) + self.assertFalse(b.readonly) + b = Importer(a, buftools.PyBUF_FORMAT) + self.assertEqual(b.ndim, 0) + self.assertEqual(b.format, "=I") + b = Importer(a, buftools.PyBUF_ND) + self.assertEqual(b.ndim, 1) + self.assertTrue(b.format is None) + self.assertEqual(b.len, a.length) + self.assertEqual(b.itemsize, s.get_bytesize()) + self.assertEqual(b.shape, (s.get_width() * s.get_height(),)) + self.assertTrue(b.strides is None) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, s._pixels_address) + b = Importer(a, buftools.PyBUF_STRIDES) + self.assertEqual(b.ndim, 1) + self.assertTrue(b.format is None) + self.assertEqual(b.strides, (s.get_bytesize(),)) + + @unittest.skipIf(not pygame.HAVE_NEWBUF, "newbuf not implemented") + def test_newbuf_PyBUF_flags_2D(self): + from pygame.tests.test_utils import buftools + + Importer = buftools.Importer + s = pygame.Surface((10, 6), 0, 32) + a = s.get_view("2") + # Non dimensional requests, no PyDEF_ND, are handled by the + # 1D surface buffer code, so only need to confirm a success. + b = Importer(a, buftools.PyBUF_SIMPLE) + self.assertEqual(b.ndim, 0) + self.assertTrue(b.format is None) + self.assertEqual(b.len, a.length) + self.assertEqual(b.itemsize, s.get_bytesize()) + self.assertTrue(b.shape is None) + self.assertTrue(b.strides is None) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, s._pixels_address) + # Uniquely 2D + b = Importer(a, buftools.PyBUF_STRIDES) + self.assertEqual(b.ndim, 2) + self.assertTrue(b.format is None) + self.assertEqual(b.len, a.length) + self.assertEqual(b.itemsize, s.get_bytesize()) + self.assertEqual(b.shape, s.get_size()) + self.assertEqual(b.strides, (s.get_bytesize(), s.get_pitch())) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, s._pixels_address) + b = Importer(a, buftools.PyBUF_RECORDS_RO) + self.assertEqual(b.ndim, 2) + self.assertEqual(b.format, "=I") + self.assertEqual(b.strides, (s.get_bytesize(), s.get_pitch())) + b = Importer(a, buftools.PyBUF_RECORDS) + self.assertEqual(b.ndim, 2) + self.assertEqual(b.format, "=I") + self.assertEqual(b.strides, (s.get_bytesize(), s.get_pitch())) + b = Importer(a, buftools.PyBUF_F_CONTIGUOUS) + self.assertEqual(b.ndim, 2) + self.assertEqual(b.format, None) + self.assertEqual(b.strides, (s.get_bytesize(), s.get_pitch())) + b = Importer(a, buftools.PyBUF_ANY_CONTIGUOUS) + self.assertEqual(b.ndim, 2) + self.assertEqual(b.format, None) + self.assertEqual(b.strides, (s.get_bytesize(), s.get_pitch())) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ND) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_C_CONTIGUOUS) + s2 = s.subsurface((1, 1, 7, 4)) # Not contiguous + a = s2.get_view("2") + b = Importer(a, buftools.PyBUF_STRIDES) + self.assertEqual(b.ndim, 2) + self.assertTrue(b.format is None) + self.assertEqual(b.len, a.length) + self.assertEqual(b.itemsize, s2.get_bytesize()) + self.assertEqual(b.shape, s2.get_size()) + self.assertEqual(b.strides, (s2.get_bytesize(), s.get_pitch())) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, s2._pixels_address) + b = Importer(a, buftools.PyBUF_RECORDS) + self.assertEqual(b.ndim, 2) + self.assertEqual(b.format, "=I") + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_SIMPLE) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_FORMAT) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_WRITABLE) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ND) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_C_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_F_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ANY_CONTIGUOUS) + + @unittest.skipIf(not pygame.HAVE_NEWBUF, "newbuf not implemented") + def test_newbuf_PyBUF_flags_3D(self): + from pygame.tests.test_utils import buftools + + Importer = buftools.Importer + s = pygame.Surface((12, 6), 0, 24) + rmask, gmask, bmask, amask = s.get_masks() + if self.lilendian: + if rmask == 0x0000FF: + color_step = 1 + addr_offset = 0 + else: + color_step = -1 + addr_offset = 2 + else: + if rmask == 0xFF0000: + color_step = 1 + addr_offset = 0 + else: + color_step = -1 + addr_offset = 2 + a = s.get_view("3") + b = Importer(a, buftools.PyBUF_STRIDES) + w, h = s.get_size() + shape = w, h, 3 + strides = 3, s.get_pitch(), color_step + self.assertEqual(b.ndim, 3) + self.assertTrue(b.format is None) + self.assertEqual(b.len, a.length) + self.assertEqual(b.itemsize, 1) + self.assertEqual(b.shape, shape) + self.assertEqual(b.strides, strides) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, s._pixels_address + addr_offset) + b = Importer(a, buftools.PyBUF_RECORDS_RO) + self.assertEqual(b.ndim, 3) + self.assertEqual(b.format, "B") + self.assertEqual(b.strides, strides) + b = Importer(a, buftools.PyBUF_RECORDS) + self.assertEqual(b.ndim, 3) + self.assertEqual(b.format, "B") + self.assertEqual(b.strides, strides) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_SIMPLE) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_FORMAT) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_WRITABLE) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ND) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_C_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_F_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ANY_CONTIGUOUS) + + @unittest.skipIf(not pygame.HAVE_NEWBUF, "newbuf not implemented") + def test_newbuf_PyBUF_flags_rgba(self): + # All color plane views are handled by the same routine, + # so only one plane need be checked. + from pygame.tests.test_utils import buftools + + Importer = buftools.Importer + s = pygame.Surface((12, 6), 0, 24) + rmask, gmask, bmask, amask = s.get_masks() + if self.lilendian: + if rmask == 0x0000FF: + addr_offset = 0 + else: + addr_offset = 2 + else: + if rmask == 0xFF0000: + addr_offset = 0 + else: + addr_offset = 2 + a = s.get_view("R") + b = Importer(a, buftools.PyBUF_STRIDES) + w, h = s.get_size() + shape = w, h + strides = s.get_bytesize(), s.get_pitch() + self.assertEqual(b.ndim, 2) + self.assertTrue(b.format is None) + self.assertEqual(b.len, a.length) + self.assertEqual(b.itemsize, 1) + self.assertEqual(b.shape, shape) + self.assertEqual(b.strides, strides) + self.assertTrue(b.suboffsets is None) + self.assertFalse(b.readonly) + self.assertEqual(b.buf, s._pixels_address + addr_offset) + b = Importer(a, buftools.PyBUF_RECORDS_RO) + self.assertEqual(b.ndim, 2) + self.assertEqual(b.format, "B") + self.assertEqual(b.strides, strides) + b = Importer(a, buftools.PyBUF_RECORDS) + self.assertEqual(b.ndim, 2) + self.assertEqual(b.format, "B") + self.assertEqual(b.strides, strides) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_SIMPLE) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_FORMAT) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_WRITABLE) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ND) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_C_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_F_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ANY_CONTIGUOUS) + + +class SurfaceBlendTest(unittest.TestCase): + def setUp(self): + # Needed for 8 bits-per-pixel color palette surface tests. + pygame.display.init() + + def tearDown(self): + pygame.display.quit() + + _test_palette = [ + (0, 0, 0, 255), + (10, 30, 60, 0), + (25, 75, 100, 128), + (200, 150, 100, 200), + (0, 100, 200, 255), + ] + surf_size = (10, 12) + _test_points = [ + ((0, 0), 1), + ((4, 5), 1), + ((9, 0), 2), + ((5, 5), 2), + ((0, 11), 3), + ((4, 6), 3), + ((9, 11), 4), + ((5, 6), 4), + ] + + def _make_surface(self, bitsize, srcalpha=False, palette=None): + if palette is None: + palette = self._test_palette + flags = 0 + if srcalpha: + flags |= SRCALPHA + surf = pygame.Surface(self.surf_size, flags, bitsize) + if bitsize == 8: + surf.set_palette([c[:3] for c in palette]) + return surf + + def _fill_surface(self, surf, palette=None): + if palette is None: + palette = self._test_palette + surf.fill(palette[1], (0, 0, 5, 6)) + surf.fill(palette[2], (5, 0, 5, 6)) + surf.fill(palette[3], (0, 6, 5, 6)) + surf.fill(palette[4], (5, 6, 5, 6)) + + def _make_src_surface(self, bitsize, srcalpha=False, palette=None): + surf = self._make_surface(bitsize, srcalpha, palette) + self._fill_surface(surf, palette) + return surf + + def _assert_surface(self, surf, palette=None, msg=""): + if palette is None: + palette = self._test_palette + if surf.get_bitsize() == 16: + palette = [surf.unmap_rgb(surf.map_rgb(c)) for c in palette] + for posn, i in self._test_points: + self.assertEqual( + surf.get_at(posn), + palette[i], + "%s != %s: flags: %i, bpp: %i, posn: %s%s" + % ( + surf.get_at(posn), + palette[i], + surf.get_flags(), + surf.get_bitsize(), + posn, + msg, + ), + ) + + def test_blit_blend(self): + sources = [ + self._make_src_surface(8), + self._make_src_surface(16), + self._make_src_surface(16, srcalpha=True), + self._make_src_surface(24), + self._make_src_surface(32), + self._make_src_surface(32, srcalpha=True), + ] + destinations = [ + self._make_surface(8), + self._make_surface(16), + self._make_surface(16, srcalpha=True), + self._make_surface(24), + self._make_surface(32), + self._make_surface(32, srcalpha=True), + ] + blend = [ + ("BLEND_ADD", (0, 25, 100, 255), lambda a, b: min(a + b, 255)), + ("BLEND_SUB", (100, 25, 0, 100), lambda a, b: max(a - b, 0)), + ("BLEND_MULT", (100, 200, 0, 0), lambda a, b: (a * b) // 256), + ("BLEND_MIN", (255, 0, 0, 255), min), + ("BLEND_MAX", (0, 255, 0, 255), max), + ] + + for src in sources: + src_palette = [src.unmap_rgb(src.map_rgb(c)) for c in self._test_palette] + for dst in destinations: + for blend_name, dst_color, op in blend: + dc = dst.unmap_rgb(dst.map_rgb(dst_color)) + p = [] + for sc in src_palette: + c = [op(dc[i], sc[i]) for i in range(3)] + if dst.get_masks()[3]: + c.append(dc[3]) + else: + c.append(255) + c = dst.unmap_rgb(dst.map_rgb(c)) + p.append(c) + dst.fill(dst_color) + dst.blit(src, (0, 0), special_flags=getattr(pygame, blend_name)) + self._assert_surface( + dst, + p, + ( + ", op: %s, src bpp: %i" + ", src flags: %i" + % (blend_name, src.get_bitsize(), src.get_flags()) + ), + ) + + src = self._make_src_surface(32) + masks = src.get_masks() + dst = pygame.Surface( + src.get_size(), 0, 32, [masks[2], masks[1], masks[0], masks[3]] + ) + for blend_name, dst_color, op in blend: + p = [] + for src_color in self._test_palette: + c = [op(dst_color[i], src_color[i]) for i in range(3)] + c.append(255) + p.append(tuple(c)) + dst.fill(dst_color) + dst.blit(src, (0, 0), special_flags=getattr(pygame, blend_name)) + self._assert_surface(dst, p, ", %s" % blend_name) + + # Blend blits are special cased for 32 to 32 bit surfaces. + # + # Confirm that it works when the rgb bytes are not the + # least significant bytes. + pat = self._make_src_surface(32) + masks = pat.get_masks() + if min(masks) == 0xFF000000: + masks = [m >> 8 for m in masks] + else: + masks = [m << 8 for m in masks] + src = pygame.Surface(pat.get_size(), 0, 32, masks) + self._fill_surface(src) + dst = pygame.Surface(src.get_size(), 0, 32, masks) + for blend_name, dst_color, op in blend: + p = [] + for src_color in self._test_palette: + c = [op(dst_color[i], src_color[i]) for i in range(3)] + c.append(255) + p.append(tuple(c)) + dst.fill(dst_color) + dst.blit(src, (0, 0), special_flags=getattr(pygame, blend_name)) + self._assert_surface(dst, p, ", %s" % blend_name) + + def test_blit_blend_rgba(self): + sources = [ + self._make_src_surface(8), + self._make_src_surface(16), + self._make_src_surface(16, srcalpha=True), + self._make_src_surface(24), + self._make_src_surface(32), + self._make_src_surface(32, srcalpha=True), + ] + destinations = [ + self._make_surface(8), + self._make_surface(16), + self._make_surface(16, srcalpha=True), + self._make_surface(24), + self._make_surface(32), + self._make_surface(32, srcalpha=True), + ] + blend = [ + ("BLEND_RGBA_ADD", (0, 25, 100, 255), lambda a, b: min(a + b, 255)), + ("BLEND_RGBA_SUB", (0, 25, 100, 255), lambda a, b: max(a - b, 0)), + ("BLEND_RGBA_MULT", (0, 7, 100, 255), lambda a, b: (a * b) // 256), + ("BLEND_RGBA_MIN", (0, 255, 0, 255), min), + ("BLEND_RGBA_MAX", (0, 255, 0, 255), max), + ] + + for src in sources: + src_palette = [src.unmap_rgb(src.map_rgb(c)) for c in self._test_palette] + for dst in destinations: + for blend_name, dst_color, op in blend: + dc = dst.unmap_rgb(dst.map_rgb(dst_color)) + p = [] + for sc in src_palette: + c = [op(dc[i], sc[i]) for i in range(4)] + if not dst.get_masks()[3]: + c[3] = 255 + c = dst.unmap_rgb(dst.map_rgb(c)) + p.append(c) + dst.fill(dst_color) + dst.blit(src, (0, 0), special_flags=getattr(pygame, blend_name)) + self._assert_surface( + dst, + p, + ( + ", op: %s, src bpp: %i" + ", src flags: %i" + % (blend_name, src.get_bitsize(), src.get_flags()) + ), + ) + + # Blend blits are special cased for 32 to 32 bit surfaces + # with per-pixel alpha. + # + # Confirm the general case is used instead when the formats differ. + src = self._make_src_surface(32, srcalpha=True) + masks = src.get_masks() + dst = pygame.Surface( + src.get_size(), SRCALPHA, 32, (masks[2], masks[1], masks[0], masks[3]) + ) + for blend_name, dst_color, op in blend: + p = [ + tuple([op(dst_color[i], src_color[i]) for i in range(4)]) + for src_color in self._test_palette + ] + dst.fill(dst_color) + dst.blit(src, (0, 0), special_flags=getattr(pygame, blend_name)) + self._assert_surface(dst, p, ", %s" % blend_name) + + # Confirm this special case handles subsurfaces. + src = pygame.Surface((8, 10), SRCALPHA, 32) + dst = pygame.Surface((8, 10), SRCALPHA, 32) + tst = pygame.Surface((8, 10), SRCALPHA, 32) + src.fill((1, 2, 3, 4)) + dst.fill((40, 30, 20, 10)) + subsrc = src.subsurface((2, 3, 4, 4)) + subdst = dst.subsurface((2, 3, 4, 4)) + subdst.blit(subsrc, (0, 0), special_flags=BLEND_RGBA_ADD) + tst.fill((40, 30, 20, 10)) + tst.fill((41, 32, 23, 14), (2, 3, 4, 4)) + for x in range(8): + for y in range(10): + self.assertEqual( + dst.get_at((x, y)), + tst.get_at((x, y)), + "%s != %s at (%i, %i)" + % (dst.get_at((x, y)), tst.get_at((x, y)), x, y), + ) + + def test_blit_blend_premultiplied(self): + def test_premul_surf( + src_col, + dst_col, + src_size=(16, 16), + dst_size=(16, 16), + src_bit_depth=32, + dst_bit_depth=32, + src_has_alpha=True, + dst_has_alpha=True, + ): + if src_bit_depth == 8: + src = pygame.Surface(src_size, 0, src_bit_depth) + palette = [src_col, dst_col] + src.set_palette(palette) + src.fill(palette[0]) + elif src_has_alpha: + src = pygame.Surface(src_size, SRCALPHA, src_bit_depth) + src.fill(src_col) + else: + src = pygame.Surface(src_size, 0, src_bit_depth) + src.fill(src_col) + + if dst_bit_depth == 8: + dst = pygame.Surface(dst_size, 0, dst_bit_depth) + palette = [src_col, dst_col] + dst.set_palette(palette) + dst.fill(palette[1]) + elif dst_has_alpha: + dst = pygame.Surface(dst_size, SRCALPHA, dst_bit_depth) + dst.fill(dst_col) + else: + dst = pygame.Surface(dst_size, 0, dst_bit_depth) + dst.fill(dst_col) + + dst.blit(src, (0, 0), special_flags=BLEND_PREMULTIPLIED) + + actual_col = dst.get_at( + (int(float(src_size[0] / 2.0)), int(float(src_size[0] / 2.0))) + ) + + # This is the blend pre-multiplied formula + if src_col.a == 0: + expected_col = dst_col + elif src_col.a == 255: + expected_col = src_col + else: + # sC + dC - (((dC + 1) * sA >> 8) + expected_col = pygame.Color( + (src_col.r + dst_col.r - ((dst_col.r + 1) * src_col.a >> 8)), + (src_col.g + dst_col.g - ((dst_col.g + 1) * src_col.a >> 8)), + (src_col.b + dst_col.b - ((dst_col.b + 1) * src_col.a >> 8)), + (src_col.a + dst_col.a - ((dst_col.a + 1) * src_col.a >> 8)), + ) + if not dst_has_alpha: + expected_col.a = 255 + + return (expected_col, actual_col) + + # # Colour Tests + self.assertEqual( + *test_premul_surf(pygame.Color(40, 20, 0, 51), pygame.Color(40, 20, 0, 51)) + ) + + self.assertEqual( + *test_premul_surf(pygame.Color(0, 0, 0, 0), pygame.Color(40, 20, 0, 51)) + ) + + self.assertEqual( + *test_premul_surf(pygame.Color(40, 20, 0, 51), pygame.Color(0, 0, 0, 0)) + ) + + self.assertEqual( + *test_premul_surf(pygame.Color(0, 0, 0, 0), pygame.Color(0, 0, 0, 0)) + ) + + self.assertEqual( + *test_premul_surf(pygame.Color(2, 2, 2, 2), pygame.Color(40, 20, 0, 51)) + ) + + self.assertEqual( + *test_premul_surf(pygame.Color(40, 20, 0, 51), pygame.Color(2, 2, 2, 2)) + ) + + self.assertEqual( + *test_premul_surf(pygame.Color(2, 2, 2, 2), pygame.Color(2, 2, 2, 2)) + ) + + self.assertEqual( + *test_premul_surf(pygame.Color(9, 9, 9, 9), pygame.Color(40, 20, 0, 51)) + ) + + self.assertEqual( + *test_premul_surf(pygame.Color(40, 20, 0, 51), pygame.Color(9, 9, 9, 9)) + ) + + self.assertEqual( + *test_premul_surf(pygame.Color(9, 9, 9, 9), pygame.Color(9, 9, 9, 9)) + ) + + self.assertEqual( + *test_premul_surf( + pygame.Color(127, 127, 127, 127), pygame.Color(40, 20, 0, 51) + ) + ) + + self.assertEqual( + *test_premul_surf( + pygame.Color(40, 20, 0, 51), pygame.Color(127, 127, 127, 127) + ) + ) + + self.assertEqual( + *test_premul_surf( + pygame.Color(127, 127, 127, 127), pygame.Color(127, 127, 127, 127) + ) + ) + + self.assertEqual( + *test_premul_surf( + pygame.Color(200, 200, 200, 200), pygame.Color(40, 20, 0, 51) + ) + ) + + self.assertEqual( + *test_premul_surf( + pygame.Color(40, 20, 0, 51), pygame.Color(200, 200, 200, 200) + ) + ) + + self.assertEqual( + *test_premul_surf( + pygame.Color(200, 200, 200, 200), pygame.Color(200, 200, 200, 200) + ) + ) + + self.assertEqual( + *test_premul_surf( + pygame.Color(255, 255, 255, 255), pygame.Color(40, 20, 0, 51) + ) + ) + + self.assertEqual( + *test_premul_surf( + pygame.Color(40, 20, 0, 51), pygame.Color(255, 255, 255, 255) + ) + ) + + self.assertEqual( + *test_premul_surf( + pygame.Color(255, 255, 255, 255), pygame.Color(255, 255, 255, 255) + ) + ) + + # Surface format tests + self.assertRaises( + IndexError, + test_premul_surf, + pygame.Color(255, 255, 255, 255), + pygame.Color(255, 255, 255, 255), + src_size=(0, 0), + dst_size=(0, 0), + ) + + self.assertEqual( + *test_premul_surf( + pygame.Color(40, 20, 0, 51), + pygame.Color(30, 20, 0, 51), + src_size=(4, 4), + dst_size=(9, 9), + ) + ) + + self.assertEqual( + *test_premul_surf( + pygame.Color(30, 20, 0, 51), + pygame.Color(40, 20, 0, 51), + src_size=(17, 67), + dst_size=(69, 69), + ) + ) + + self.assertEqual( + *test_premul_surf( + pygame.Color(30, 20, 0, 255), + pygame.Color(40, 20, 0, 51), + src_size=(17, 67), + dst_size=(69, 69), + src_has_alpha=True, + ) + ) + self.assertEqual( + *test_premul_surf( + pygame.Color(30, 20, 0, 51), + pygame.Color(40, 20, 0, 255), + src_size=(17, 67), + dst_size=(69, 69), + dst_has_alpha=False, + ) + ) + + self.assertEqual( + *test_premul_surf( + pygame.Color(30, 20, 0, 255), + pygame.Color(40, 20, 0, 255), + src_size=(17, 67), + dst_size=(69, 69), + src_has_alpha=False, + dst_has_alpha=False, + ) + ) + + self.assertEqual( + *test_premul_surf( + pygame.Color(30, 20, 0, 255), + pygame.Color(40, 20, 0, 255), + src_size=(17, 67), + dst_size=(69, 69), + dst_bit_depth=24, + src_has_alpha=True, + dst_has_alpha=False, + ) + ) + + self.assertEqual( + *test_premul_surf( + pygame.Color(30, 20, 0, 255), + pygame.Color(40, 20, 0, 255), + src_size=(17, 67), + dst_size=(69, 69), + src_bit_depth=24, + src_has_alpha=False, + dst_has_alpha=True, + ) + ) + + self.assertEqual( + *test_premul_surf( + pygame.Color(30, 20, 0, 255), + pygame.Color(40, 20, 0, 255), + src_size=(17, 67), + dst_size=(69, 69), + src_bit_depth=24, + dst_bit_depth=24, + src_has_alpha=False, + dst_has_alpha=False, + ) + ) + + self.assertEqual( + *test_premul_surf( + pygame.Color(30, 20, 0, 255), + pygame.Color(40, 20, 0, 255), + src_size=(17, 67), + dst_size=(69, 69), + src_bit_depth=8, + ) + ) + + self.assertEqual( + *test_premul_surf( + pygame.Color(30, 20, 0, 255), + pygame.Color(40, 20, 0, 255), + src_size=(17, 67), + dst_size=(69, 69), + dst_bit_depth=8, + ) + ) + + self.assertEqual( + *test_premul_surf( + pygame.Color(30, 20, 0, 255), + pygame.Color(40, 20, 0, 255), + src_size=(17, 67), + dst_size=(69, 69), + src_bit_depth=8, + dst_bit_depth=8, + ) + ) + + def test_blit_blend_big_rect(self): + """test that an oversized rect works ok.""" + color = (1, 2, 3, 255) + area = (1, 1, 30, 30) + s1 = pygame.Surface((4, 4), 0, 32) + r = s1.fill(special_flags=pygame.BLEND_ADD, color=color, rect=area) + + self.assertEqual(pygame.Rect((1, 1, 3, 3)), r) + self.assertEqual(s1.get_at((0, 0)), (0, 0, 0, 255)) + self.assertEqual(s1.get_at((1, 1)), color) + + black = pygame.Color("black") + red = pygame.Color("red") + self.assertNotEqual(black, red) + + surf = pygame.Surface((10, 10), 0, 32) + surf.fill(black) + subsurf = surf.subsurface(pygame.Rect(0, 1, 10, 8)) + self.assertEqual(surf.get_at((0, 0)), black) + self.assertEqual(surf.get_at((0, 9)), black) + + subsurf.fill(red, (0, -1, 10, 1), pygame.BLEND_RGB_ADD) + self.assertEqual(surf.get_at((0, 0)), black) + self.assertEqual(surf.get_at((0, 9)), black) + + subsurf.fill(red, (0, 8, 10, 1), pygame.BLEND_RGB_ADD) + self.assertEqual(surf.get_at((0, 0)), black) + self.assertEqual(surf.get_at((0, 9)), black) + + def test_GET_PIXELVALS(self): + # surface.h GET_PIXELVALS bug regarding whether of not + # a surface has per-pixel alpha. Looking at the Amask + # is not enough. The surface's SRCALPHA flag must also + # be considered. Fix rev. 1923. + src = self._make_surface(32, srcalpha=True) + src.fill((0, 0, 0, 128)) + src.set_alpha(None) # Clear SRCALPHA flag. + dst = self._make_surface(32, srcalpha=True) + dst.blit(src, (0, 0), special_flags=BLEND_RGBA_ADD) + self.assertEqual(dst.get_at((0, 0)), (0, 0, 0, 255)) + + def test_fill_blend(self): + destinations = [ + self._make_surface(8), + self._make_surface(16), + self._make_surface(16, srcalpha=True), + self._make_surface(24), + self._make_surface(32), + self._make_surface(32, srcalpha=True), + ] + blend = [ + ("BLEND_ADD", (0, 25, 100, 255), lambda a, b: min(a + b, 255)), + ("BLEND_SUB", (0, 25, 100, 255), lambda a, b: max(a - b, 0)), + ("BLEND_MULT", (0, 7, 100, 255), lambda a, b: (a * b) // 256), + ("BLEND_MIN", (0, 255, 0, 255), min), + ("BLEND_MAX", (0, 255, 0, 255), max), + ] + + for dst in destinations: + dst_palette = [dst.unmap_rgb(dst.map_rgb(c)) for c in self._test_palette] + for blend_name, fill_color, op in blend: + fc = dst.unmap_rgb(dst.map_rgb(fill_color)) + self._fill_surface(dst) + p = [] + for dc in dst_palette: + c = [op(dc[i], fc[i]) for i in range(3)] + if dst.get_masks()[3]: + c.append(dc[3]) + else: + c.append(255) + c = dst.unmap_rgb(dst.map_rgb(c)) + p.append(c) + dst.fill(fill_color, special_flags=getattr(pygame, blend_name)) + self._assert_surface(dst, p, ", %s" % blend_name) + + def test_fill_blend_rgba(self): + destinations = [ + self._make_surface(8), + self._make_surface(16), + self._make_surface(16, srcalpha=True), + self._make_surface(24), + self._make_surface(32), + self._make_surface(32, srcalpha=True), + ] + blend = [ + ("BLEND_RGBA_ADD", (0, 25, 100, 255), lambda a, b: min(a + b, 255)), + ("BLEND_RGBA_SUB", (0, 25, 100, 255), lambda a, b: max(a - b, 0)), + ("BLEND_RGBA_MULT", (0, 7, 100, 255), lambda a, b: (a * b) // 256), + ("BLEND_RGBA_MIN", (0, 255, 0, 255), min), + ("BLEND_RGBA_MAX", (0, 255, 0, 255), max), + ] + + for dst in destinations: + dst_palette = [dst.unmap_rgb(dst.map_rgb(c)) for c in self._test_palette] + for blend_name, fill_color, op in blend: + fc = dst.unmap_rgb(dst.map_rgb(fill_color)) + self._fill_surface(dst) + p = [] + for dc in dst_palette: + c = [op(dc[i], fc[i]) for i in range(4)] + if not dst.get_masks()[3]: + c[3] = 255 + c = dst.unmap_rgb(dst.map_rgb(c)) + p.append(c) + dst.fill(fill_color, special_flags=getattr(pygame, blend_name)) + self._assert_surface(dst, p, ", %s" % blend_name) + + +class SurfaceSelfBlitTest(unittest.TestCase): + """Blit to self tests. + + This test case is in response to MotherHamster Bugzilla Bug 19. + """ + + def setUp(self): + # Needed for 8 bits-per-pixel color palette surface tests. + pygame.display.init() + + def tearDown(self): + pygame.display.quit() + + _test_palette = [(0, 0, 0, 255), (255, 0, 0, 0), (0, 255, 0, 255)] + surf_size = (9, 6) + + def _fill_surface(self, surf, palette=None): + if palette is None: + palette = self._test_palette + surf.fill(palette[1]) + surf.fill(palette[2], (1, 2, 1, 2)) + + def _make_surface(self, bitsize, srcalpha=False, palette=None): + if palette is None: + palette = self._test_palette + flags = 0 + if srcalpha: + flags |= SRCALPHA + surf = pygame.Surface(self.surf_size, flags, bitsize) + if bitsize == 8: + surf.set_palette([c[:3] for c in palette]) + self._fill_surface(surf, palette) + return surf + + def _assert_same(self, a, b): + w, h = a.get_size() + for x in range(w): + for y in range(h): + self.assertEqual( + a.get_at((x, y)), + b.get_at((x, y)), + ( + "%s != %s, bpp: %i" + % (a.get_at((x, y)), b.get_at((x, y)), a.get_bitsize()) + ), + ) + + def test_overlap_check(self): + # Ensure overlapping blits are properly detected. There are two + # places where this is done, within SoftBlitPyGame() in alphablit.c + # and PySurface_Blit() in surface.c. SoftBlitPyGame should catch the + # per-pixel alpha surface, PySurface_Blit the colorkey and blanket + # alpha surface. per-pixel alpha and blanket alpha self blits are + # not properly handled by SDL 1.2.13, so Pygame does them. + bgc = (0, 0, 0, 255) + rectc_left = (128, 64, 32, 255) + rectc_right = (255, 255, 255, 255) + colors = [(255, 255, 255, 255), (128, 64, 32, 255)] + overlaps = [ + (0, 0, 1, 0, (50, 0)), + (0, 0, 49, 1, (98, 2)), + (0, 0, 49, 49, (98, 98)), + (49, 0, 0, 1, (0, 2)), + (49, 0, 0, 49, (0, 98)), + ] + surfs = [pygame.Surface((100, 100), SRCALPHA, 32)] + surf = pygame.Surface((100, 100), 0, 32) + surf.set_alpha(255) + surfs.append(surf) + surf = pygame.Surface((100, 100), 0, 32) + surf.set_colorkey((0, 1, 0)) + surfs.append(surf) + for surf in surfs: + for s_x, s_y, d_x, d_y, test_posn in overlaps: + surf.fill(bgc) + surf.fill(rectc_right, (25, 0, 25, 50)) + surf.fill(rectc_left, (0, 0, 25, 50)) + surf.blit(surf, (d_x, d_y), (s_x, s_y, 50, 50)) + self.assertEqual(surf.get_at(test_posn), rectc_right) + + # https://github.com/pygame/pygame/issues/370#issuecomment-364625291 + @unittest.skipIf("ppc64le" in platform.uname(), "known ppc64le issue") + def test_colorkey(self): + # Check a workaround for an SDL 1.2.13 surface self-blit problem + # (MotherHamster Bugzilla bug 19). + pygame.display.set_mode((100, 50)) # Needed for 8bit surface + bitsizes = [8, 16, 24, 32] + for bitsize in bitsizes: + surf = self._make_surface(bitsize) + surf.set_colorkey(self._test_palette[1]) + surf.blit(surf, (3, 0)) + p = [] + for c in self._test_palette: + c = surf.unmap_rgb(surf.map_rgb(c)) + p.append(c) + p[1] = (p[1][0], p[1][1], p[1][2], 0) + tmp = self._make_surface(32, srcalpha=True, palette=p) + tmp.blit(tmp, (3, 0)) + tmp.set_alpha(None) + comp = self._make_surface(bitsize) + comp.blit(tmp, (0, 0)) + self._assert_same(surf, comp) + + # https://github.com/pygame/pygame/issues/370#issuecomment-364625291 + @unittest.skipIf("ppc64le" in platform.uname(), "known ppc64le issue") + def test_blanket_alpha(self): + # Check a workaround for an SDL 1.2.13 surface self-blit problem + # (MotherHamster Bugzilla bug 19). + pygame.display.set_mode((100, 50)) # Needed for 8bit surface + bitsizes = [8, 16, 24, 32] + for bitsize in bitsizes: + surf = self._make_surface(bitsize) + surf.set_alpha(128) + surf.blit(surf, (3, 0)) + p = [] + for c in self._test_palette: + c = surf.unmap_rgb(surf.map_rgb(c)) + p.append((c[0], c[1], c[2], 128)) + tmp = self._make_surface(32, srcalpha=True, palette=p) + tmp.blit(tmp, (3, 0)) + tmp.set_alpha(None) + comp = self._make_surface(bitsize) + comp.blit(tmp, (0, 0)) + self._assert_same(surf, comp) + + def test_pixel_alpha(self): + bitsizes = [16, 32] + for bitsize in bitsizes: + surf = self._make_surface(bitsize, srcalpha=True) + comp = self._make_surface(bitsize, srcalpha=True) + comp.blit(surf, (3, 0)) + surf.blit(surf, (3, 0)) + self._assert_same(surf, comp) + + def test_blend(self): + bitsizes = [8, 16, 24, 32] + blends = ["BLEND_ADD", "BLEND_SUB", "BLEND_MULT", "BLEND_MIN", "BLEND_MAX"] + for bitsize in bitsizes: + surf = self._make_surface(bitsize) + comp = self._make_surface(bitsize) + for blend in blends: + self._fill_surface(surf) + self._fill_surface(comp) + comp.blit(surf, (3, 0), special_flags=getattr(pygame, blend)) + surf.blit(surf, (3, 0), special_flags=getattr(pygame, blend)) + self._assert_same(surf, comp) + + def test_blend_rgba(self): + bitsizes = [16, 32] + blends = [ + "BLEND_RGBA_ADD", + "BLEND_RGBA_SUB", + "BLEND_RGBA_MULT", + "BLEND_RGBA_MIN", + "BLEND_RGBA_MAX", + ] + for bitsize in bitsizes: + surf = self._make_surface(bitsize, srcalpha=True) + comp = self._make_surface(bitsize, srcalpha=True) + for blend in blends: + self._fill_surface(surf) + self._fill_surface(comp) + comp.blit(surf, (3, 0), special_flags=getattr(pygame, blend)) + surf.blit(surf, (3, 0), special_flags=getattr(pygame, blend)) + self._assert_same(surf, comp) + + def test_subsurface(self): + # Blitting a surface to its subsurface is allowed. + surf = self._make_surface(32, srcalpha=True) + comp = surf.copy() + comp.blit(surf, (3, 0)) + sub = surf.subsurface((3, 0, 6, 6)) + sub.blit(surf, (0, 0)) + del sub + self._assert_same(surf, comp) + + # Blitting a subsurface to its owner is forbidden because of + # lock conficts. This limitation allows the overlap check + # in PySurface_Blit of alphablit.c to be simplified. + def do_blit(d, s): + d.blit(s, (0, 0)) + + sub = surf.subsurface((1, 1, 2, 2)) + self.assertRaises(pygame.error, do_blit, surf, sub) + + def test_copy_alpha(self): + """issue 581: alpha of surface copy with SRCALPHA is set to 0.""" + surf = pygame.Surface((16, 16), pygame.SRCALPHA, 32) + self.assertEqual(surf.get_alpha(), 255) + surf2 = surf.copy() + self.assertEqual(surf2.get_alpha(), 255) + + +class SurfaceFillTest(unittest.TestCase): + def setUp(self): + pygame.display.init() + + def tearDown(self): + pygame.display.quit() + + def test_fill(self): + screen = pygame.display.set_mode((640, 480)) + + # Green and blue test pattern + screen.fill((0, 255, 0), (0, 0, 320, 240)) + screen.fill((0, 255, 0), (320, 240, 320, 240)) + screen.fill((0, 0, 255), (320, 0, 320, 240)) + screen.fill((0, 0, 255), (0, 240, 320, 240)) + + # Now apply a clip rect, such that only the left side of the + # screen should be effected by blit operations. + screen.set_clip((0, 0, 320, 480)) + + # Test fills with each special flag, and additionally without any. + screen.fill((255, 0, 0, 127), (160, 0, 320, 30), 0) + screen.fill((255, 0, 0, 127), (160, 30, 320, 30), pygame.BLEND_ADD) + screen.fill((0, 127, 127, 127), (160, 60, 320, 30), pygame.BLEND_SUB) + screen.fill((0, 63, 63, 127), (160, 90, 320, 30), pygame.BLEND_MULT) + screen.fill((0, 127, 127, 127), (160, 120, 320, 30), pygame.BLEND_MIN) + screen.fill((127, 0, 0, 127), (160, 150, 320, 30), pygame.BLEND_MAX) + screen.fill((255, 0, 0, 127), (160, 180, 320, 30), pygame.BLEND_RGBA_ADD) + screen.fill((0, 127, 127, 127), (160, 210, 320, 30), pygame.BLEND_RGBA_SUB) + screen.fill((0, 63, 63, 127), (160, 240, 320, 30), pygame.BLEND_RGBA_MULT) + screen.fill((0, 127, 127, 127), (160, 270, 320, 30), pygame.BLEND_RGBA_MIN) + screen.fill((127, 0, 0, 127), (160, 300, 320, 30), pygame.BLEND_RGBA_MAX) + screen.fill((255, 0, 0, 127), (160, 330, 320, 30), pygame.BLEND_RGB_ADD) + screen.fill((0, 127, 127, 127), (160, 360, 320, 30), pygame.BLEND_RGB_SUB) + screen.fill((0, 63, 63, 127), (160, 390, 320, 30), pygame.BLEND_RGB_MULT) + screen.fill((0, 127, 127, 127), (160, 420, 320, 30), pygame.BLEND_RGB_MIN) + screen.fill((255, 0, 0, 127), (160, 450, 320, 30), pygame.BLEND_RGB_MAX) + + # Update the display so we can see the results + pygame.display.flip() + + # Compare colors on both sides of window + for y in range(5, 480, 10): + self.assertEqual(screen.get_at((10, y)), screen.get_at((330, 480 - y))) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/surfarray_tags.py b/venv/Lib/site-packages/pygame/tests/surfarray_tags.py new file mode 100644 index 0000000..baa535c --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/surfarray_tags.py @@ -0,0 +1,16 @@ +__tags__ = ["array"] + +exclude = False + +try: + import numpy +except ImportError: + exclude = True +else: + try: + import pygame.pixelcopy + except ImportError: + exclude = True + +if exclude: + __tags__.extend(("ignore", "subprocess_ignore")) diff --git a/venv/Lib/site-packages/pygame/tests/surfarray_test.py b/venv/Lib/site-packages/pygame/tests/surfarray_test.py new file mode 100644 index 0000000..246da82 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/surfarray_test.py @@ -0,0 +1,754 @@ +import unittest +import platform + +from numpy import ( + uint8, + uint16, + uint32, + uint64, + zeros, + float32, + float64, + alltrue, + rint, + arange, +) + +import pygame +from pygame.locals import * + +import pygame.surfarray + + +IS_PYPY = "PyPy" == platform.python_implementation() + + +@unittest.skipIf(IS_PYPY, "pypy skip known failure") # TODO +class SurfarrayModuleTest(unittest.TestCase): + pixels2d = {8: True, 16: True, 24: False, 32: True} + pixels3d = {8: False, 16: False, 24: True, 32: True} + array2d = {8: True, 16: True, 24: True, 32: True} + array3d = {8: False, 16: False, 24: True, 32: True} + + test_palette = [ + (0, 0, 0, 255), + (10, 30, 60, 255), + (25, 75, 100, 255), + (100, 150, 200, 255), + (0, 100, 200, 255), + ] + surf_size = (10, 12) + test_points = [ + ((0, 0), 1), + ((4, 5), 1), + ((9, 0), 2), + ((5, 5), 2), + ((0, 11), 3), + ((4, 6), 3), + ((9, 11), 4), + ((5, 6), 4), + ] + + @classmethod + def setUpClass(cls): + # Needed for 8 bits-per-pixel color palette surface tests. + pygame.init() + + @classmethod + def tearDownClass(cls): + pygame.quit() + + def setUp(cls): + # This makes sure pygame is always initialized before each test (in + # case a test calls pygame.quit()). + if not pygame.get_init(): + pygame.init() + + def _make_surface(self, bitsize, srcalpha=False, palette=None): + if palette is None: + palette = self.test_palette + flags = 0 + if srcalpha: + flags |= SRCALPHA + surf = pygame.Surface(self.surf_size, flags, bitsize) + if bitsize == 8: + surf.set_palette([c[:3] for c in palette]) + return surf + + def _fill_surface(self, surf, palette=None): + if palette is None: + palette = self.test_palette + surf.fill(palette[1], (0, 0, 5, 6)) + surf.fill(palette[2], (5, 0, 5, 6)) + surf.fill(palette[3], (0, 6, 5, 6)) + surf.fill(palette[4], (5, 6, 5, 6)) + + def _make_src_surface(self, bitsize, srcalpha=False, palette=None): + surf = self._make_surface(bitsize, srcalpha, palette) + self._fill_surface(surf, palette) + return surf + + def _assert_surface(self, surf, palette=None, msg=""): + if palette is None: + palette = self.test_palette + if surf.get_bitsize() == 16: + palette = [surf.unmap_rgb(surf.map_rgb(c)) for c in palette] + for posn, i in self.test_points: + self.assertEqual( + surf.get_at(posn), + palette[i], + "%s != %s: flags: %i, bpp: %i, posn: %s%s" + % ( + surf.get_at(posn), + palette[i], + surf.get_flags(), + surf.get_bitsize(), + posn, + msg, + ), + ) + + def _make_array3d(self, dtype): + return zeros((self.surf_size[0], self.surf_size[1], 3), dtype) + + def _fill_array2d(self, arr, surf): + palette = self.test_palette + arr[:5, :6] = surf.map_rgb(palette[1]) + arr[5:, :6] = surf.map_rgb(palette[2]) + arr[:5, 6:] = surf.map_rgb(palette[3]) + arr[5:, 6:] = surf.map_rgb(palette[4]) + + def _fill_array3d(self, arr): + palette = self.test_palette + arr[:5, :6] = palette[1][:3] + arr[5:, :6] = palette[2][:3] + arr[:5, 6:] = palette[3][:3] + arr[5:, 6:] = palette[4][:3] + + def _make_src_array3d(self, dtype): + arr = self._make_array3d(dtype) + self._fill_array3d(arr) + return arr + + def _make_array2d(self, dtype): + return zeros(self.surf_size, dtype) + + def test_array2d(self): + + sources = [ + self._make_src_surface(8), + self._make_src_surface(16), + self._make_src_surface(16, srcalpha=True), + self._make_src_surface(24), + self._make_src_surface(32), + self._make_src_surface(32, srcalpha=True), + ] + palette = self.test_palette + alpha_color = (0, 0, 0, 128) + + for surf in sources: + arr = pygame.surfarray.array2d(surf) + for posn, i in self.test_points: + self.assertEqual( + arr[posn], + surf.get_at_mapped(posn), + "%s != %s: flags: %i, bpp: %i, posn: %s" + % ( + arr[posn], + surf.get_at_mapped(posn), + surf.get_flags(), + surf.get_bitsize(), + posn, + ), + ) + + if surf.get_masks()[3]: + surf.fill(alpha_color) + arr = pygame.surfarray.array2d(surf) + posn = (0, 0) + self.assertEqual( + arr[posn], + surf.get_at_mapped(posn), + "%s != %s: bpp: %i" + % (arr[posn], surf.get_at_mapped(posn), surf.get_bitsize()), + ) + + def test_array3d(self): + + sources = [ + self._make_src_surface(16), + self._make_src_surface(16, srcalpha=True), + self._make_src_surface(24), + self._make_src_surface(32), + self._make_src_surface(32, srcalpha=True), + ] + palette = self.test_palette + + for surf in sources: + arr = pygame.surfarray.array3d(surf) + + def same_color(ac, sc): + return ac[0] == sc[0] and ac[1] == sc[1] and ac[2] == sc[2] + + for posn, i in self.test_points: + self.assertTrue( + same_color(arr[posn], surf.get_at(posn)), + "%s != %s: flags: %i, bpp: %i, posn: %s" + % ( + tuple(arr[posn]), + surf.get_at(posn), + surf.get_flags(), + surf.get_bitsize(), + posn, + ), + ) + + def test_array_alpha(self): + + palette = [ + (0, 0, 0, 0), + (10, 50, 100, 255), + (60, 120, 240, 130), + (64, 128, 255, 0), + (255, 128, 0, 65), + ] + targets = [ + self._make_src_surface(8, palette=palette), + self._make_src_surface(16, palette=palette), + self._make_src_surface(16, palette=palette, srcalpha=True), + self._make_src_surface(24, palette=palette), + self._make_src_surface(32, palette=palette), + self._make_src_surface(32, palette=palette, srcalpha=True), + ] + + for surf in targets: + p = palette + if surf.get_bitsize() == 16: + p = [surf.unmap_rgb(surf.map_rgb(c)) for c in p] + arr = pygame.surfarray.array_alpha(surf) + if surf.get_masks()[3]: + for (x, y), i in self.test_points: + self.assertEqual( + arr[x, y], + p[i][3], + ( + "%i != %i, posn: (%i, %i), " + "bitsize: %i" + % (arr[x, y], p[i][3], x, y, surf.get_bitsize()) + ), + ) + else: + self.assertTrue(alltrue(arr == 255)) + + # No per-pixel alpha when blanket alpha is None. + for surf in targets: + blanket_alpha = surf.get_alpha() + surf.set_alpha(None) + arr = pygame.surfarray.array_alpha(surf) + self.assertTrue( + alltrue(arr == 255), + "All alpha values should be 255 when" + " surf.set_alpha(None) has been set." + " bitsize: %i, flags: %i" % (surf.get_bitsize(), surf.get_flags()), + ) + surf.set_alpha(blanket_alpha) + + # Bug for per-pixel alpha surface when blanket alpha 0. + for surf in targets: + blanket_alpha = surf.get_alpha() + surf.set_alpha(0) + arr = pygame.surfarray.array_alpha(surf) + if surf.get_masks()[3]: + self.assertFalse( + alltrue(arr == 255), + "bitsize: %i, flags: %i" % (surf.get_bitsize(), surf.get_flags()), + ) + else: + self.assertTrue( + alltrue(arr == 255), + "bitsize: %i, flags: %i" % (surf.get_bitsize(), surf.get_flags()), + ) + surf.set_alpha(blanket_alpha) + + def test_array_colorkey(self): + + palette = [ + (0, 0, 0, 0), + (10, 50, 100, 255), + (60, 120, 240, 130), + (64, 128, 255, 0), + (255, 128, 0, 65), + ] + targets = [ + self._make_src_surface(8, palette=palette), + self._make_src_surface(16, palette=palette), + self._make_src_surface(16, palette=palette, srcalpha=True), + self._make_src_surface(24, palette=palette), + self._make_src_surface(32, palette=palette), + self._make_src_surface(32, palette=palette, srcalpha=True), + ] + + for surf in targets: + p = palette + if surf.get_bitsize() == 16: + p = [surf.unmap_rgb(surf.map_rgb(c)) for c in p] + surf.set_colorkey(None) + arr = pygame.surfarray.array_colorkey(surf) + self.assertTrue(alltrue(arr == 255)) + + for i in range(1, len(palette)): + surf.set_colorkey(p[i]) + alphas = [255] * len(p) + alphas[i] = 0 + arr = pygame.surfarray.array_colorkey(surf) + for (x, y), j in self.test_points: + self.assertEqual( + arr[x, y], + alphas[j], + ( + "%i != %i, posn: (%i, %i), " + "bitsize: %i" + % (arr[x, y], alphas[j], x, y, surf.get_bitsize()) + ), + ) + + def test_array_red(self): + self._test_array_rgb("red", 0) + + def test_array_green(self): + self._test_array_rgb("green", 1) + + def test_array_blue(self): + self._test_array_rgb("blue", 2) + + def _test_array_rgb(self, operation, mask_posn): + method_name = "array_" + operation + + array_rgb = getattr(pygame.surfarray, method_name) + palette = [ + (0, 0, 0, 255), + (5, 13, 23, 255), + (29, 31, 37, 255), + (131, 157, 167, 255), + (179, 191, 251, 255), + ] + plane = [c[mask_posn] for c in palette] + + targets = [ + self._make_src_surface(24, palette=palette), + self._make_src_surface(32, palette=palette), + self._make_src_surface(32, palette=palette, srcalpha=True), + ] + + for surf in targets: + self.assertFalse(surf.get_locked()) + for (x, y), i in self.test_points: + surf.fill(palette[i]) + arr = array_rgb(surf) + self.assertEqual(arr[x, y], plane[i]) + surf.fill((100, 100, 100, 250)) + self.assertEqual(arr[x, y], plane[i]) + self.assertFalse(surf.get_locked()) + del arr + + def test_blit_array(self): + + s = pygame.Surface((10, 10), 0, 24) + a = pygame.surfarray.array3d(s) + pygame.surfarray.blit_array(s, a) + + # target surfaces + targets = [ + self._make_surface(8), + self._make_surface(16), + self._make_surface(16, srcalpha=True), + self._make_surface(24), + self._make_surface(32), + self._make_surface(32, srcalpha=True), + ] + + # source arrays + arrays3d = [] + dtypes = [(8, uint8), (16, uint16), (32, uint32)] + try: + dtypes.append((64, uint64)) + except NameError: + pass + arrays3d = [(self._make_src_array3d(dtype), None) for __, dtype in dtypes] + for bitsize in [8, 16, 24, 32]: + palette = None + if bitsize == 16: + s = pygame.Surface((1, 1), 0, 16) + palette = [s.unmap_rgb(s.map_rgb(c)) for c in self.test_palette] + if self.pixels3d[bitsize]: + surf = self._make_src_surface(bitsize) + arr = pygame.surfarray.pixels3d(surf) + arrays3d.append((arr, palette)) + if self.array3d[bitsize]: + surf = self._make_src_surface(bitsize) + arr = pygame.surfarray.array3d(surf) + arrays3d.append((arr, palette)) + for sz, dtype in dtypes: + arrays3d.append((arr.astype(dtype), palette)) + + # tests on arrays + def do_blit(surf, arr): + pygame.surfarray.blit_array(surf, arr) + + for surf in targets: + bitsize = surf.get_bitsize() + for arr, palette in arrays3d: + surf.fill((0, 0, 0, 0)) + if bitsize == 8: + self.assertRaises(ValueError, do_blit, surf, arr) + else: + pygame.surfarray.blit_array(surf, arr) + self._assert_surface(surf, palette) + + if self.pixels2d[bitsize]: + surf.fill((0, 0, 0, 0)) + s = self._make_src_surface(bitsize, surf.get_flags() & SRCALPHA) + arr = pygame.surfarray.pixels2d(s) + pygame.surfarray.blit_array(surf, arr) + self._assert_surface(surf) + + if self.array2d[bitsize]: + s = self._make_src_surface(bitsize, surf.get_flags() & SRCALPHA) + arr = pygame.surfarray.array2d(s) + for sz, dtype in dtypes: + surf.fill((0, 0, 0, 0)) + if sz >= bitsize: + pygame.surfarray.blit_array(surf, arr.astype(dtype)) + self._assert_surface(surf) + else: + self.assertRaises( + ValueError, do_blit, surf, self._make_array2d(dtype) + ) + + # Check alpha for 2D arrays + surf = self._make_surface(16, srcalpha=True) + arr = zeros(surf.get_size(), uint16) + arr[...] = surf.map_rgb((0, 128, 255, 64)) + color = surf.unmap_rgb(arr[0, 0]) + pygame.surfarray.blit_array(surf, arr) + self.assertEqual(surf.get_at((5, 5)), color) + + surf = self._make_surface(32, srcalpha=True) + arr = zeros(surf.get_size(), uint32) + color = (0, 111, 255, 63) + arr[...] = surf.map_rgb(color) + pygame.surfarray.blit_array(surf, arr) + self.assertEqual(surf.get_at((5, 5)), color) + + # Check shifts + arr3d = self._make_src_array3d(uint8) + + shift_tests = [ + (16, [12, 0, 8, 4], [0xF000, 0xF, 0xF00, 0xF0]), + (24, [16, 0, 8, 0], [0xFF0000, 0xFF, 0xFF00, 0]), + (32, [0, 16, 24, 8], [0xFF, 0xFF0000, 0xFF000000, 0xFF00]), + ] + + for bitsize, shifts, masks in shift_tests: + surf = self._make_surface(bitsize, srcalpha=(shifts[3] != 0)) + palette = None + if bitsize == 16: + palette = [surf.unmap_rgb(surf.map_rgb(c)) for c in self.test_palette] + + self.assertRaises(TypeError, surf.set_shifts, shifts) + self.assertRaises(TypeError, surf.set_masks, masks) + + # Invalid arrays + surf = pygame.Surface((1, 1), 0, 32) + t = "abcd" + self.assertRaises(ValueError, do_blit, surf, t) + + surf_size = self.surf_size + surf = pygame.Surface(surf_size, 0, 32) + arr = zeros([surf_size[0], surf_size[1] + 1, 3], uint32) + self.assertRaises(ValueError, do_blit, surf, arr) + arr = zeros([surf_size[0] + 1, surf_size[1], 3], uint32) + self.assertRaises(ValueError, do_blit, surf, arr) + + surf = pygame.Surface((1, 4), 0, 32) + arr = zeros((4,), uint32) + self.assertRaises(ValueError, do_blit, surf, arr) + arr.shape = (1, 1, 1, 4) + self.assertRaises(ValueError, do_blit, surf, arr) + + # Issue #81: round from float to int + try: + rint + except NameError: + pass + else: + surf = pygame.Surface((10, 10), pygame.SRCALPHA, 32) + w, h = surf.get_size() + length = w * h + for dtype in [float32, float64]: + surf.fill((255, 255, 255, 0)) + farr = arange(0, length, dtype=dtype) + farr.shape = w, h + pygame.surfarray.blit_array(surf, farr) + for x in range(w): + for y in range(h): + self.assertEqual( + surf.get_at_mapped((x, y)), int(rint(farr[x, y])) + ) + + # this test should be removed soon, when the function is deleted + def test_get_arraytype(self): + array_type = pygame.surfarray.get_arraytype() + + self.assertEqual(array_type, "numpy", "unknown array type %s" % array_type) + + # this test should be removed soon, when the function is deleted + def test_get_arraytypes(self): + + arraytypes = pygame.surfarray.get_arraytypes() + self.assertIn("numpy", arraytypes) + + for atype in arraytypes: + self.assertEqual(atype, "numpy", "unknown array type %s" % atype) + + def test_make_surface(self): + + # How does one properly test this with 2d arrays. It makes no sense + # since the pixel format is not entirely dependent on element size. + # Just make sure the surface pixel size is at least as large as the + # array element size I guess. + # + for bitsize, dtype in [(8, uint8), (16, uint16), (24, uint32)]: + ## Even this simple assertion fails for 2d arrays. Where's the problem? + ## surf = pygame.surfarray.make_surface(self._make_array2d(dtype)) + ## self.assertGreaterEqual(surf.get_bitsize(), bitsize, + ## "not %i >= %i)" % (surf.get_bitsize(), bitsize)) + ## + surf = pygame.surfarray.make_surface(self._make_src_array3d(dtype)) + self._assert_surface(surf) + + # Issue #81: round from float to int + try: + rint + except NameError: + pass + else: + w = 9 + h = 11 + length = w * h + for dtype in [float32, float64]: + farr = arange(0, length, dtype=dtype) + farr.shape = w, h + surf = pygame.surfarray.make_surface(farr) + for x in range(w): + for y in range(h): + self.assertEqual( + surf.get_at_mapped((x, y)), int(rint(farr[x, y])) + ) + + def test_map_array(self): + + arr3d = self._make_src_array3d(uint8) + targets = [ + self._make_surface(8), + self._make_surface(16), + self._make_surface(16, srcalpha=True), + self._make_surface(24), + self._make_surface(32), + self._make_surface(32, srcalpha=True), + ] + palette = self.test_palette + + for surf in targets: + arr2d = pygame.surfarray.map_array(surf, arr3d) + for posn, i in self.test_points: + self.assertEqual( + arr2d[posn], + surf.map_rgb(palette[i]), + "%i != %i, bitsize: %i, flags: %i" + % ( + arr2d[posn], + surf.map_rgb(palette[i]), + surf.get_bitsize(), + surf.get_flags(), + ), + ) + + # Exception checks + self.assertRaises( + ValueError, + pygame.surfarray.map_array, + self._make_surface(32), + self._make_array2d(uint8), + ) + + def test_pixels2d(self): + + sources = [ + self._make_surface(8), + self._make_surface(16, srcalpha=True), + self._make_surface(32, srcalpha=True), + ] + + for surf in sources: + self.assertFalse(surf.get_locked()) + arr = pygame.surfarray.pixels2d(surf) + self.assertTrue(surf.get_locked()) + self._fill_array2d(arr, surf) + surf.unlock() + self.assertTrue(surf.get_locked()) + del arr + self.assertFalse(surf.get_locked()) + self.assertEqual(surf.get_locks(), ()) + self._assert_surface(surf) + + # Error checks + self.assertRaises(ValueError, pygame.surfarray.pixels2d, self._make_surface(24)) + + def test_pixels3d(self): + + sources = [self._make_surface(24), self._make_surface(32)] + + for surf in sources: + self.assertFalse(surf.get_locked()) + arr = pygame.surfarray.pixels3d(surf) + self.assertTrue(surf.get_locked()) + self._fill_array3d(arr) + surf.unlock() + self.assertTrue(surf.get_locked()) + del arr + self.assertFalse(surf.get_locked()) + self.assertEqual(surf.get_locks(), ()) + self._assert_surface(surf) + + # Alpha check + color = (1, 2, 3, 0) + surf = self._make_surface(32, srcalpha=True) + arr = pygame.surfarray.pixels3d(surf) + arr[0, 0] = color[:3] + self.assertEqual(surf.get_at((0, 0)), color) + + # Error checks + def do_pixels3d(surf): + pygame.surfarray.pixels3d(surf) + + self.assertRaises(ValueError, do_pixels3d, self._make_surface(8)) + self.assertRaises(ValueError, do_pixels3d, self._make_surface(16)) + + def test_pixels_alpha(self): + + palette = [ + (0, 0, 0, 0), + (127, 127, 127, 0), + (127, 127, 127, 85), + (127, 127, 127, 170), + (127, 127, 127, 255), + ] + alphas = [0, 45, 86, 99, 180] + + surf = self._make_src_surface(32, srcalpha=True, palette=palette) + + self.assertFalse(surf.get_locked()) + arr = pygame.surfarray.pixels_alpha(surf) + self.assertTrue(surf.get_locked()) + surf.unlock() + self.assertTrue(surf.get_locked()) + + for (x, y), i in self.test_points: + self.assertEqual(arr[x, y], palette[i][3]) + + for (x, y), i in self.test_points: + alpha = alphas[i] + arr[x, y] = alpha + color = (127, 127, 127, alpha) + self.assertEqual(surf.get_at((x, y)), color, "posn: (%i, %i)" % (x, y)) + + del arr + self.assertFalse(surf.get_locked()) + self.assertEqual(surf.get_locks(), ()) + + # Check exceptions. + def do_pixels_alpha(surf): + pygame.surfarray.pixels_alpha(surf) + + targets = [(8, False), (16, False), (16, True), (24, False), (32, False)] + + for bitsize, srcalpha in targets: + self.assertRaises( + ValueError, do_pixels_alpha, self._make_surface(bitsize, srcalpha) + ) + + def test_pixels_red(self): + self._test_pixels_rgb("red", 0) + + def test_pixels_green(self): + self._test_pixels_rgb("green", 1) + + def test_pixels_blue(self): + self._test_pixels_rgb("blue", 2) + + def _test_pixels_rgb(self, operation, mask_posn): + method_name = "pixels_" + operation + + pixels_rgb = getattr(pygame.surfarray, method_name) + palette = [ + (0, 0, 0, 255), + (5, 13, 23, 255), + (29, 31, 37, 255), + (131, 157, 167, 255), + (179, 191, 251, 255), + ] + plane = [c[mask_posn] for c in palette] + + surf24 = self._make_src_surface(24, srcalpha=False, palette=palette) + surf32 = self._make_src_surface(32, srcalpha=False, palette=palette) + surf32a = self._make_src_surface(32, srcalpha=True, palette=palette) + + for surf in [surf24, surf32, surf32a]: + self.assertFalse(surf.get_locked()) + arr = pixels_rgb(surf) + self.assertTrue(surf.get_locked()) + surf.unlock() + self.assertTrue(surf.get_locked()) + + for (x, y), i in self.test_points: + self.assertEqual(arr[x, y], plane[i]) + + del arr + self.assertFalse(surf.get_locked()) + self.assertEqual(surf.get_locks(), ()) + + # Check exceptions. + targets = [(8, False), (16, False), (16, True)] + + for bitsize, srcalpha in targets: + self.assertRaises( + ValueError, pixels_rgb, self._make_surface(bitsize, srcalpha) + ) + + def test_use_arraytype(self): + def do_use_arraytype(atype): + pygame.surfarray.use_arraytype(atype) + + pygame.surfarray.use_arraytype("numpy") + self.assertEqual(pygame.surfarray.get_arraytype(), "numpy") + self.assertRaises(ValueError, do_use_arraytype, "not an option") + + def test_surf_lock(self): + sf = pygame.Surface((5, 5), 0, 32) + for atype in pygame.surfarray.get_arraytypes(): + pygame.surfarray.use_arraytype(atype) + + ar = pygame.surfarray.pixels2d(sf) + self.assertTrue(sf.get_locked()) + + sf.unlock() + self.assertTrue(sf.get_locked()) + + del ar + self.assertFalse(sf.get_locked()) + self.assertEqual(sf.get_locks(), ()) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/surflock_test.py b/venv/Lib/site-packages/pygame/tests/surflock_test.py new file mode 100644 index 0000000..19f354b --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/surflock_test.py @@ -0,0 +1,144 @@ +import unittest +import sys +import platform + +import pygame + +IS_PYPY = "PyPy" == platform.python_implementation() + + +@unittest.skipIf(IS_PYPY, "pypy skip known failure") # TODO +class SurfaceLockTest(unittest.TestCase): + def test_lock(self): + sf = pygame.Surface((5, 5)) + + sf.lock() + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (sf,)) + + sf.lock() + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (sf, sf)) + + sf.unlock() + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (sf,)) + + sf.unlock() + self.assertEqual(sf.get_locked(), False) + self.assertEqual(sf.get_locks(), ()) + + def test_subsurface_lock(self): + sf = pygame.Surface((5, 5)) + subsf = sf.subsurface((1, 1, 2, 2)) + sf2 = pygame.Surface((5, 5)) + + # Simple blits, nothing should happen here. + sf2.blit(subsf, (0, 0)) + sf2.blit(sf, (0, 0)) + + # Test blitting on self: + self.assertRaises(pygame.error, sf.blit, subsf, (0, 0)) + # self.assertRaises(pygame.error, subsf.blit, sf, (0, 0)) + # ^ Fails although it should not in my opinion. If I cannot + # blit the subsurface to the surface, it should not be allowed + # the other way around as well. + + # Test additional locks. + sf.lock() + sf2.blit(subsf, (0, 0)) + self.assertRaises(pygame.error, sf2.blit, sf, (0, 0)) + + subsf.lock() + self.assertRaises(pygame.error, sf2.blit, subsf, (0, 0)) + self.assertRaises(pygame.error, sf2.blit, sf, (0, 0)) + + # sf and subsf are now explicitly locked. Unlock sf, so we can + # (assume) to blit it. + # It will fail though as the subsurface still has a lock around, + # which is okay and correct behaviour. + sf.unlock() + self.assertRaises(pygame.error, sf2.blit, subsf, (0, 0)) + self.assertRaises(pygame.error, sf2.blit, sf, (0, 0)) + + # Run a second unlock on the surface. This should ideally have + # no effect as the subsurface is the locking reason! + sf.unlock() + self.assertRaises(pygame.error, sf2.blit, sf, (0, 0)) + self.assertRaises(pygame.error, sf2.blit, subsf, (0, 0)) + subsf.unlock() + + sf.lock() + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (sf,)) + self.assertEqual(subsf.get_locked(), False) + self.assertEqual(subsf.get_locks(), ()) + + subsf.lock() + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (sf, subsf)) + self.assertEqual(subsf.get_locked(), True) + self.assertEqual(subsf.get_locks(), (subsf,)) + + sf.unlock() + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (subsf,)) + self.assertEqual(subsf.get_locked(), True) + self.assertEqual(subsf.get_locks(), (subsf,)) + + subsf.unlock() + self.assertEqual(sf.get_locked(), False) + self.assertEqual(sf.get_locks(), ()) + self.assertEqual(subsf.get_locked(), False) + self.assertEqual(subsf.get_locks(), ()) + + subsf.lock() + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (subsf,)) + self.assertEqual(subsf.get_locked(), True) + self.assertEqual(subsf.get_locks(), (subsf,)) + + subsf.lock() + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (subsf, subsf)) + self.assertEqual(subsf.get_locked(), True) + self.assertEqual(subsf.get_locks(), (subsf, subsf)) + + def test_pxarray_ref(self): + sf = pygame.Surface((5, 5)) + ar = pygame.PixelArray(sf) + ar2 = pygame.PixelArray(sf) + + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (ar, ar2)) + + del ar + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (ar2,)) + + ar = ar2[:] + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (ar2,)) + + del ar + self.assertEqual(sf.get_locked(), True) + self.assertEqual(len(sf.get_locks()), 1) + + def test_buffer(self): + sf = pygame.Surface((5, 5)) + buf = sf.get_buffer() + + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (buf,)) + + sf.unlock() + self.assertEqual(sf.get_locked(), True) + self.assertEqual(sf.get_locks(), (buf,)) + + del buf + self.assertEqual(sf.get_locked(), False) + self.assertEqual(sf.get_locks(), ()) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/sysfont_test.py b/venv/Lib/site-packages/pygame/tests/sysfont_test.py new file mode 100644 index 0000000..0ae380a --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/sysfont_test.py @@ -0,0 +1,51 @@ +import unittest +import platform + + +class SysfontModuleTest(unittest.TestCase): + def test_create_aliases(self): + import pygame.sysfont + + pygame.sysfont.initsysfonts() + pygame.sysfont.create_aliases() + self.assertTrue(len(pygame.sysfont.Sysalias) > 0) + + def test_initsysfonts(self): + import pygame.sysfont + + pygame.sysfont.initsysfonts() + self.assertTrue(len(pygame.sysfont.get_fonts()) > 0) + + @unittest.skipIf("Darwin" not in platform.platform(), "Not mac we skip.") + def test_initsysfonts_darwin(self): + import pygame.sysfont + + self.assertTrue(len(pygame.sysfont.get_fonts()) > 10) + + def test_sysfont(self): + import pygame.font + + pygame.font.init() + arial = pygame.font.SysFont("Arial", 40) + self.assertTrue(isinstance(arial, pygame.font.Font)) + + @unittest.skipIf( + ("Darwin" in platform.platform() or "Windows" in platform.platform()), + "Not unix we skip.", + ) + def test_initsysfonts_unix(self): + import pygame.sysfont + + self.assertTrue(len(pygame.sysfont.get_fonts()) > 0) + + @unittest.skipIf("Windows" not in platform.platform(), "Not windows we skip.") + def test_initsysfonts_win32(self): + import pygame.sysfont + + self.assertTrue(len(pygame.sysfont.get_fonts()) > 10) + + +############################################################################### + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/test_test_.py b/venv/Lib/site-packages/pygame/tests/test_test_.py new file mode 100644 index 0000000..0880e7e --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/test_test_.py @@ -0,0 +1,2 @@ +while True: + pass diff --git a/venv/Lib/site-packages/pygame/tests/test_utils/__init__.py b/venv/Lib/site-packages/pygame/tests/test_utils/__init__.py new file mode 100644 index 0000000..f8013ca --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/test_utils/__init__.py @@ -0,0 +1,227 @@ +import os +import pygame +import sys +import tempfile +import time + +is_pygame_pkg = __name__.startswith("pygame.tests.") + +############################################################################### + + +def tostring(row): + """Convert row of bytes to string. Expects `row` to be an + ``array``. + """ + return row.tobytes() + + +def geterror(): + return sys.exc_info()[1] + + +class AssertRaisesRegexMixin(object): + """Provides a way to prevent DeprecationWarnings in python >= 3.2. + + For this mixin to override correctly it needs to be before the + unittest.TestCase in the multiple inheritance hierarchy. + e.g. class TestClass(AssertRaisesRegexMixin, unittest.TestCase) + + This class/mixin and its usage can be removed when pygame no longer + supports python < 3.2. + """ + + def assertRaisesRegex(self, *args, **kwargs): + try: + return super(AssertRaisesRegexMixin, self).assertRaisesRegex( + *args, **kwargs + ) + except AttributeError: + try: + return super(AssertRaisesRegexMixin, self).assertRaisesRegexp( + *args, **kwargs + ) + except AttributeError: + self.skipTest("No assertRaisesRegex/assertRaisesRegexp method") + + +############################################################################### + +this_dir = os.path.dirname(os.path.abspath(__file__)) +trunk_dir = os.path.split(os.path.split(this_dir)[0])[0] +if is_pygame_pkg: + test_module = "tests" +else: + test_module = "test" + + +def trunk_relative_path(relative): + return os.path.normpath(os.path.join(trunk_dir, relative)) + + +def fixture_path(path): + return trunk_relative_path(os.path.join(test_module, "fixtures", path)) + + +def example_path(path): + return trunk_relative_path(os.path.join("examples", path)) + + +sys.path.insert(0, trunk_relative_path(".")) + + +################################## TEMP FILES ################################# + + +def get_tmp_dir(): + return tempfile.mkdtemp() + + +############################################################################### + + +def question(q): + return input("\n%s (y/n): " % q.rstrip(" ")).lower().strip() == "y" + + +def prompt(p): + return input("\n%s (press enter to continue): " % p.rstrip(" ")) + + +#################################### HELPERS ################################## + + +def rgba_between(value, minimum=0, maximum=255): + if value < minimum: + return minimum + elif value > maximum: + return maximum + else: + return value + + +def combinations(seqs): + """ + + Recipe 496807 from ActiveState Python CookBook + + Non recursive technique for getting all possible combinations of a sequence + of sequences. + + """ + + r = [[]] + for x in seqs: + r = [i + [y] for y in x for i in r] + return r + + +def gradient(width, height): + """ + + Yields a pt and corresponding RGBA tuple, for every (width, height) combo. + Useful for generating gradients. + + Actual gradient may be changed, no tests rely on specific values. + + Used in transform.rotate lossless tests to generate a fixture. + + """ + + for l in range(width): + for t in range(height): + yield (l, t), tuple(map(rgba_between, (l, t, l, l + t))) + + +def rect_area_pts(rect): + for l in range(rect.left, rect.right): + for t in range(rect.top, rect.bottom): + yield l, t + + +def rect_perimeter_pts(rect): + """ + + Returns pts ((L, T) tuples) encompassing the perimeter of a rect. + + The order is clockwise: + + topleft to topright + topright to bottomright + bottomright to bottomleft + bottomleft to topleft + + Duplicate pts are not returned + + """ + clock_wise_from_top_left = ( + [(l, rect.top) for l in range(rect.left, rect.right)], + [(rect.right - 1, t) for t in range(rect.top + 1, rect.bottom)], + [(l, rect.bottom - 1) for l in range(rect.right - 2, rect.left - 1, -1)], + [(rect.left, t) for t in range(rect.bottom - 2, rect.top, -1)], + ) + + for line in clock_wise_from_top_left: + for pt in line: + yield pt + + +def rect_outer_bounds(rect): + """ + + Returns topleft outerbound if possible and then the other pts, that are + "exclusive" bounds of the rect + + ?------O + |RECT| ?|0)uterbound + |----| + O O + + """ + return ([(rect.left - 1, rect.top)] if rect.left else []) + [ + rect.topright, + rect.bottomleft, + rect.bottomright, + ] + + +def import_submodule(module): + m = __import__(module) + for n in module.split(".")[1:]: + m = getattr(m, n) + return m + + +class SurfaceSubclass(pygame.Surface): + """A subclassed Surface to test inheritance.""" + + def __init__(self, *args, **kwargs): + super(SurfaceSubclass, self).__init__(*args, **kwargs) + self.test_attribute = True + + +def test(): + """ + + Lightweight test for helpers + + """ + + r = pygame.Rect(0, 0, 10, 10) + assert rect_outer_bounds(r) == [(10, 0), (0, 10), (10, 10)] # tr # bl # br + + assert len(list(rect_area_pts(r))) == 100 + + r = pygame.Rect(0, 0, 3, 3) + assert list(rect_perimeter_pts(r)) == [ + (0, 0), + (1, 0), + (2, 0), # tl -> tr + (2, 1), + (2, 2), # tr -> br + (1, 2), + (0, 2), # br -> bl + (0, 1), # bl -> tl + ] + + print("Tests: OK") diff --git a/venv/Lib/site-packages/pygame/tests/test_utils/arrinter.py b/venv/Lib/site-packages/pygame/tests/test_utils/arrinter.py new file mode 100644 index 0000000..3883b45 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/test_utils/arrinter.py @@ -0,0 +1,441 @@ +import sys +import ctypes +from ctypes import * +import unittest + +__all__ = [ + "PAI_CONTIGUOUS", + "PAI_FORTRAN", + "PAI_ALIGNED", + "PAI_NOTSWAPPED", + "PAI_WRITEABLE", + "PAI_ARR_HAS_DESCR", + "ArrayInterface", +] + +try: + c_ssize_t # Undefined in early Python versions +except NameError: + if sizeof(c_uint) == sizeof(c_void_p): + c_size_t = c_uint + c_ssize_t = c_int + elif sizeof(c_ulong) == sizeof(c_void_p): + c_size_t = c_ulong + c_ssize_t = c_long + elif sizeof(c_ulonglong) == sizeof(c_void_p): + c_size_t = c_ulonglong + c_ssize_t = c_longlong + + +SIZEOF_VOID_P = sizeof(c_void_p) +if SIZEOF_VOID_P <= sizeof(c_int): + Py_intptr_t = c_int +elif SIZEOF_VOID_P <= sizeof(c_long): + Py_intptr_t = c_long +elif "c_longlong" in globals() and SIZEOF_VOID_P <= sizeof(c_longlong): + Py_intptr_t = c_longlong +else: + raise RuntimeError("Unrecognized pointer size %i" % (pointer_size,)) + + +class PyArrayInterface(Structure): + _fields_ = [ + ("two", c_int), + ("nd", c_int), + ("typekind", c_char), + ("itemsize", c_int), + ("flags", c_int), + ("shape", POINTER(Py_intptr_t)), + ("strides", POINTER(Py_intptr_t)), + ("data", c_void_p), + ("descr", py_object), + ] + + +PAI_Ptr = POINTER(PyArrayInterface) + +try: + PyCObject_AsVoidPtr = pythonapi.PyCObject_AsVoidPtr +except AttributeError: + + def PyCObject_AsVoidPtr(o): + raise TypeError("Not available") + +else: + PyCObject_AsVoidPtr.restype = c_void_p + PyCObject_AsVoidPtr.argtypes = [py_object] + PyCObject_GetDesc = pythonapi.PyCObject_GetDesc + PyCObject_GetDesc.restype = c_void_p + PyCObject_GetDesc.argtypes = [py_object] + +try: + PyCapsule_IsValid = pythonapi.PyCapsule_IsValid +except AttributeError: + + def PyCapsule_IsValid(capsule, name): + return 0 + +else: + PyCapsule_IsValid.restype = c_int + PyCapsule_IsValid.argtypes = [py_object, c_char_p] + PyCapsule_GetPointer = pythonapi.PyCapsule_GetPointer + PyCapsule_GetPointer.restype = c_void_p + PyCapsule_GetPointer.argtypes = [py_object, c_char_p] + PyCapsule_GetContext = pythonapi.PyCapsule_GetContext + PyCapsule_GetContext.restype = c_void_p + PyCapsule_GetContext.argtypes = [py_object] + +PyCapsule_Destructor = CFUNCTYPE(None, py_object) +PyCapsule_New = pythonapi.PyCapsule_New +PyCapsule_New.restype = py_object +PyCapsule_New.argtypes = [c_void_p, c_char_p, POINTER(PyCapsule_Destructor)] + + +def capsule_new(p): + return PyCapsule_New(addressof(p), None, None) + + +PAI_CONTIGUOUS = 0x01 +PAI_FORTRAN = 0x02 +PAI_ALIGNED = 0x100 +PAI_NOTSWAPPED = 0x200 +PAI_WRITEABLE = 0x400 +PAI_ARR_HAS_DESCR = 0x800 + + +class ArrayInterface(object): + def __init__(self, arr): + try: + self._cobj = arr.__array_struct__ + except AttributeError: + raise TypeError("The array object lacks an array structure") + if not self._cobj: + raise TypeError("The array object has a NULL array structure value") + try: + vp = PyCObject_AsVoidPtr(self._cobj) + except TypeError: + if PyCapsule_IsValid(self._cobj, None): + vp = PyCapsule_GetPointer(self._cobj, None) + else: + raise TypeError("The array object has an invalid array structure") + self.desc = PyCapsule_GetContext(self._cobj) + else: + self.desc = PyCObject_GetDesc(self._cobj) + self._inter = cast(vp, PAI_Ptr)[0] + + def __getattr__(self, name): + if name == "typekind": + return self._inter.typekind.decode("latin-1") + return getattr(self._inter, name) + + def __str__(self): + if isinstance(self.desc, tuple): + ver = self.desc[0] + else: + ver = "N/A" + return ( + "nd: %i\n" + "typekind: %s\n" + "itemsize: %i\n" + "flags: %s\n" + "shape: %s\n" + "strides: %s\n" + "ver: %s\n" + % ( + self.nd, + self.typekind, + self.itemsize, + format_flags(self.flags), + format_shape(self.nd, self.shape), + format_strides(self.nd, self.strides), + ver, + ) + ) + + +def format_flags(flags): + names = [] + for flag, name in [ + (PAI_CONTIGUOUS, "CONTIGUOUS"), + (PAI_FORTRAN, "FORTRAN"), + (PAI_ALIGNED, "ALIGNED"), + (PAI_NOTSWAPPED, "NOTSWAPPED"), + (PAI_WRITEABLE, "WRITEABLE"), + (PAI_ARR_HAS_DESCR, "ARR_HAS_DESCR"), + ]: + if flag & flags: + names.append(name) + return ", ".join(names) + + +def format_shape(nd, shape): + return ", ".join([str(shape[i]) for i in range(nd)]) + + +def format_strides(nd, strides): + return ", ".join([str(strides[i]) for i in range(nd)]) + + +class Exporter(object): + def __init__( + self, shape, typekind=None, itemsize=None, strides=None, descr=None, flags=None + ): + if typekind is None: + typekind = "u" + if itemsize is None: + itemsize = 1 + if flags is None: + flags = PAI_WRITEABLE | PAI_ALIGNED | PAI_NOTSWAPPED + if descr is not None: + flags |= PAI_ARR_HAS_DESCR + if len(typekind) != 1: + raise ValueError("Argument 'typekind' must be length 1 string") + nd = len(shape) + self.typekind = typekind + self.itemsize = itemsize + self.nd = nd + self.shape = tuple(shape) + self._shape = (c_ssize_t * self.nd)(*self.shape) + if strides is None: + self._strides = (c_ssize_t * self.nd)() + self._strides[self.nd - 1] = self.itemsize + for i in range(self.nd - 1, 0, -1): + self._strides[i - 1] = self.shape[i] * self._strides[i] + strides = tuple(self._strides) + self.strides = strides + elif len(strides) == nd: + self.strides = tuple(strides) + self._strides = (c_ssize_t * self.nd)(*self.strides) + else: + raise ValueError("Mismatch in length of strides and shape") + self.descr = descr + if self.is_contiguous("C"): + flags |= PAI_CONTIGUOUS + if self.is_contiguous("F"): + flags |= PAI_FORTRAN + self.flags = flags + sz = max(shape[i] * strides[i] for i in range(nd)) + self._data = (c_ubyte * sz)() + self.data = addressof(self._data) + self._inter = PyArrayInterface( + 2, + nd, + typekind.encode("latin_1"), + itemsize, + flags, + self._shape, + self._strides, + self.data, + descr, + ) + self.len = itemsize + for i in range(nd): + self.len *= self.shape[i] + + __array_struct__ = property(lambda self: capsule_new(self._inter)) + + def is_contiguous(self, fortran): + if fortran in "CA": + if self.strides[-1] == self.itemsize: + for i in range(self.nd - 1, 0, -1): + if self.strides[i - 1] != self.shape[i] * self.strides[i]: + break + else: + return True + if fortran in "FA": + if self.strides[0] == self.itemsize: + for i in range(0, self.nd - 1): + if self.strides[i + 1] != self.shape[i] * self.strides[i]: + break + else: + return True + return False + + +class Array(Exporter): + _ctypes = { + ("u", 1): c_uint8, + ("u", 2): c_uint16, + ("u", 4): c_uint32, + ("u", 8): c_uint64, + ("i", 1): c_int8, + ("i", 2): c_int16, + ("i", 4): c_int32, + ("i", 8): c_int64, + } + + def __init__(self, *args, **kwds): + super(Array, self).__init__(*args, **kwds) + try: + if self.flags & PAI_NOTSWAPPED: + ct = self._ctypes[self.typekind, self.itemsize] + elif c_int.__ctype_le__ is c_int: + ct = self._ctypes[self.typekind, self.itemsize].__ctype_be__ + else: + ct = self._ctypes[self.typekind, self.itemsize].__ctype_le__ + except KeyError: + ct = c_uint8 * self.itemsize + self._ctype = ct + self._ctype_p = POINTER(ct) + + def __getitem__(self, key): + return cast(self._addr_at(key), self._ctype_p)[0] + + def __setitem__(self, key, value): + cast(self._addr_at(key), self._ctype_p)[0] = value + + def _addr_at(self, key): + if not isinstance(key, tuple): + key = (key,) + if len(key) != self.nd: + raise ValueError("wrong number of indexes") + for i in range(self.nd): + if not (0 <= key[i] < self.shape[i]): + raise IndexError("index {} out of range".format(i)) + return self.data + sum(i * s for i, s in zip(key, self.strides)) + + +class ExporterTest(unittest.TestCase): + def test_strides(self): + self.check_args(0, (10,), "u", (2,), 20, 20, 2) + self.check_args(0, (5, 3), "u", (6, 2), 30, 30, 2) + self.check_args(0, (7, 3, 5), "u", (30, 10, 2), 210, 210, 2) + self.check_args(0, (13, 5, 11, 3), "u", (330, 66, 6, 2), 4290, 4290, 2) + self.check_args(3, (7, 3, 5), "i", (2, 14, 42), 210, 210, 2) + self.check_args(3, (7, 3, 5), "x", (2, 16, 48), 210, 240, 2) + self.check_args(3, (13, 5, 11, 3), "%", (440, 88, 8, 2), 4290, 5720, 2) + self.check_args(3, (7, 5), "-", (15, 3), 105, 105, 3) + self.check_args(3, (7, 5), "*", (3, 21), 105, 105, 3) + self.check_args(3, (7, 5), " ", (3, 24), 105, 120, 3) + + def test_is_contiguous(self): + a = Exporter((10,), itemsize=2) + self.assertTrue(a.is_contiguous("C")) + self.assertTrue(a.is_contiguous("F")) + self.assertTrue(a.is_contiguous("A")) + a = Exporter((10, 4), itemsize=2) + self.assertTrue(a.is_contiguous("C")) + self.assertTrue(a.is_contiguous("A")) + self.assertFalse(a.is_contiguous("F")) + a = Exporter((13, 5, 11, 3), itemsize=2, strides=(330, 66, 6, 2)) + self.assertTrue(a.is_contiguous("C")) + self.assertTrue(a.is_contiguous("A")) + self.assertFalse(a.is_contiguous("F")) + a = Exporter((10, 4), itemsize=2, strides=(2, 20)) + self.assertTrue(a.is_contiguous("F")) + self.assertTrue(a.is_contiguous("A")) + self.assertFalse(a.is_contiguous("C")) + a = Exporter((13, 5, 11, 3), itemsize=2, strides=(2, 26, 130, 1430)) + self.assertTrue(a.is_contiguous("F")) + self.assertTrue(a.is_contiguous("A")) + self.assertFalse(a.is_contiguous("C")) + a = Exporter((2, 11, 6, 4), itemsize=2, strides=(576, 48, 8, 2)) + self.assertFalse(a.is_contiguous("A")) + a = Exporter((2, 11, 6, 4), itemsize=2, strides=(2, 4, 48, 288)) + self.assertFalse(a.is_contiguous("A")) + a = Exporter((3, 2, 2), itemsize=2, strides=(16, 8, 4)) + self.assertFalse(a.is_contiguous("A")) + a = Exporter((3, 2, 2), itemsize=2, strides=(4, 12, 24)) + self.assertFalse(a.is_contiguous("A")) + + def check_args( + self, call_flags, shape, typekind, strides, length, bufsize, itemsize, offset=0 + ): + if call_flags & 1: + typekind_arg = typekind + else: + typekind_arg = None + if call_flags & 2: + strides_arg = strides + else: + strides_arg = None + a = Exporter(shape, itemsize=itemsize, strides=strides_arg) + self.assertEqual(sizeof(a._data), bufsize) + self.assertEqual(a.data, ctypes.addressof(a._data) + offset) + m = ArrayInterface(a) + self.assertEqual(m.data, a.data) + self.assertEqual(m.itemsize, itemsize) + self.assertEqual(tuple(m.shape[0 : m.nd]), shape) + self.assertEqual(tuple(m.strides[0 : m.nd]), strides) + + +class ArrayTest(unittest.TestCase): + def __init__(self, *args, **kwds): + unittest.TestCase.__init__(self, *args, **kwds) + self.a = Array((20, 15), "i", 4) + + def setUp(self): + # Every test starts with a zeroed array. + memset(self.a.data, 0, sizeof(self.a._data)) + + def test__addr_at(self): + a = self.a + self.assertEqual(a._addr_at((0, 0)), a.data) + self.assertEqual(a._addr_at((0, 1)), a.data + 4) + self.assertEqual(a._addr_at((1, 0)), a.data + 60) + self.assertEqual(a._addr_at((1, 1)), a.data + 64) + + def test_indices(self): + a = self.a + self.assertEqual(a[0, 0], 0) + self.assertEqual(a[19, 0], 0) + self.assertEqual(a[0, 14], 0) + self.assertEqual(a[19, 14], 0) + self.assertEqual(a[5, 8], 0) + a[0, 0] = 12 + a[5, 8] = 99 + self.assertEqual(a[0, 0], 12) + self.assertEqual(a[5, 8], 99) + self.assertRaises(IndexError, a.__getitem__, (-1, 0)) + self.assertRaises(IndexError, a.__getitem__, (0, -1)) + self.assertRaises(IndexError, a.__getitem__, (20, 0)) + self.assertRaises(IndexError, a.__getitem__, (0, 15)) + self.assertRaises(ValueError, a.__getitem__, 0) + self.assertRaises(ValueError, a.__getitem__, (0, 0, 0)) + a = Array((3,), "i", 4) + a[1] = 333 + self.assertEqual(a[1], 333) + + def test_typekind(self): + a = Array((1,), "i", 4) + self.assertTrue(a._ctype is c_int32) + self.assertTrue(a._ctype_p is POINTER(c_int32)) + a = Array((1,), "u", 4) + self.assertTrue(a._ctype is c_uint32) + self.assertTrue(a._ctype_p is POINTER(c_uint32)) + a = Array((1,), "f", 4) # float types unsupported: size system dependent + ct = a._ctype + self.assertTrue(issubclass(ct, ctypes.Array)) + self.assertEqual(sizeof(ct), 4) + + def test_itemsize(self): + for size in [1, 2, 4, 8]: + a = Array((1,), "i", size) + ct = a._ctype + self.assertTrue(issubclass(ct, ctypes._SimpleCData)) + self.assertEqual(sizeof(ct), size) + + def test_oddball_itemsize(self): + for size in [3, 5, 6, 7, 9]: + a = Array((1,), "i", size) + ct = a._ctype + self.assertTrue(issubclass(ct, ctypes.Array)) + self.assertEqual(sizeof(ct), size) + + def test_byteswapped(self): + a = Array((1,), "u", 4, flags=(PAI_ALIGNED | PAI_WRITEABLE)) + ct = a._ctype + self.assertTrue(ct is not c_uint32) + if sys.byteorder == "little": + self.assertTrue(ct is c_uint32.__ctype_be__) + else: + self.assertTrue(ct is c_uint32.__ctype_le__) + i = 0xA0B0C0D + n = c_uint32(i) + a[0] = i + self.assertEqual(a[0], i) + self.assertEqual(a._data[0:4], cast(addressof(n), POINTER(c_uint8))[3:-1:-1]) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/test_utils/async_sub.py b/venv/Lib/site-packages/pygame/tests/test_utils/async_sub.py new file mode 100644 index 0000000..4adc760 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/test_utils/async_sub.py @@ -0,0 +1,301 @@ +################################################################################ +""" + +Modification of http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554 + +""" + +#################################### IMPORTS ################################### + +import os +import platform +import subprocess +import errno +import time +import sys +import unittest +import tempfile + + +def geterror(): + return sys.exc_info()[1] + + +null_byte = "\x00".encode("ascii") + +if platform.system() == "Windows": + + def encode(s): + return s.encode("ascii") + + def decode(b): + return b.decode("ascii") + + try: + import ctypes + from ctypes.wintypes import DWORD + + kernel32 = ctypes.windll.kernel32 + TerminateProcess = ctypes.windll.kernel32.TerminateProcess + + def WriteFile(handle, data, ol=None): + c_written = DWORD() + success = ctypes.windll.kernel32.WriteFile( + handle, + ctypes.create_string_buffer(encode(data)), + len(data), + ctypes.byref(c_written), + ol, + ) + return ctypes.windll.kernel32.GetLastError(), c_written.value + + def ReadFile(handle, desired_bytes, ol=None): + c_read = DWORD() + buffer = ctypes.create_string_buffer(desired_bytes + 1) + success = ctypes.windll.kernel32.ReadFile( + handle, buffer, desired_bytes, ctypes.byref(c_read), ol + ) + buffer[c_read.value] = null_byte + return ctypes.windll.kernel32.GetLastError(), decode(buffer.value) + + def PeekNamedPipe(handle, desired_bytes): + c_avail = DWORD() + c_message = DWORD() + if desired_bytes > 0: + c_read = DWORD() + buffer = ctypes.create_string_buffer(desired_bytes + 1) + success = ctypes.windll.kernel32.PeekNamedPipe( + handle, + buffer, + desired_bytes, + ctypes.byref(c_read), + ctypes.byref(c_avail), + ctypes.byref(c_message), + ) + buffer[c_read.value] = null_byte + return decode(buffer.value), c_avail.value, c_message.value + else: + success = ctypes.windll.kernel32.PeekNamedPipe( + handle, + None, + desired_bytes, + None, + ctypes.byref(c_avail), + ctypes.byref(c_message), + ) + return "", c_avail.value, c_message.value + + except ImportError: + from win32file import ReadFile, WriteFile + from win32pipe import PeekNamedPipe + from win32api import TerminateProcess + import msvcrt + +else: + from signal import SIGINT, SIGTERM, SIGKILL + import select + import fcntl + +################################### CONSTANTS ################################## + +PIPE = subprocess.PIPE + +################################################################################ + + +class Popen(subprocess.Popen): + def recv(self, maxsize=None): + return self._recv("stdout", maxsize) + + def recv_err(self, maxsize=None): + return self._recv("stderr", maxsize) + + def send_recv(self, input="", maxsize=None): + return self.send(input), self.recv(maxsize), self.recv_err(maxsize) + + def read_async(self, wait=0.1, e=1, tr=5, stderr=0): + if tr < 1: + tr = 1 + x = time.time() + wait + y = [] + r = "" + pr = self.recv + if stderr: + pr = self.recv_err + while time.time() < x or r: + r = pr() + if r is None: + if e: + raise Exception("Other end disconnected!") + else: + break + elif r: + y.append(r) + else: + time.sleep(max((x - time.time()) / tr, 0)) + return "".join(y) + + def send_all(self, data): + while len(data): + sent = self.send(data) + if sent is None: + raise Exception("Other end disconnected!") + data = buffer(data, sent) + + def get_conn_maxsize(self, which, maxsize): + if maxsize is None: + maxsize = 1024 + elif maxsize < 1: + maxsize = 1 + return getattr(self, which), maxsize + + def _close(self, which): + getattr(self, which).close() + setattr(self, which, None) + + if platform.system() == "Windows": + + def kill(self): + # Recipes + # http://me.in-berlin.de/doc/python/faq/windows.html#how-do-i-emulate-os-kill-in-windows + # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/347462 + + """kill function for Win32""" + TerminateProcess(int(self._handle), 0) # returns None + + def send(self, input): + if not self.stdin: + return None + + try: + x = msvcrt.get_osfhandle(self.stdin.fileno()) + (errCode, written) = WriteFile(x, input) + except ValueError: + return self._close("stdin") + except (subprocess.pywintypes.error, Exception): + if geterror()[0] in (109, errno.ESHUTDOWN): + return self._close("stdin") + raise + + return written + + def _recv(self, which, maxsize): + conn, maxsize = self.get_conn_maxsize(which, maxsize) + if conn is None: + return None + + try: + x = msvcrt.get_osfhandle(conn.fileno()) + (read, nAvail, nMessage) = PeekNamedPipe(x, 0) + if maxsize < nAvail: + nAvail = maxsize + if nAvail > 0: + (errCode, read) = ReadFile(x, nAvail, None) + except ValueError: + return self._close(which) + except (subprocess.pywintypes.error, Exception): + if geterror()[0] in (109, errno.ESHUTDOWN): + return self._close(which) + raise + + if self.universal_newlines: + # Translate newlines. For Python 3.x assume read is text. + # If bytes then another solution is needed. + read = read.replace("\r\n", "\n").replace("\r", "\n") + return read + + else: + + def kill(self): + for i, sig in enumerate([SIGTERM, SIGKILL] * 2): + if i % 2 == 0: + os.kill(self.pid, sig) + time.sleep((i * (i % 2) / 5.0) + 0.01) + + killed_pid, stat = os.waitpid(self.pid, os.WNOHANG) + if killed_pid != 0: + return + + def send(self, input): + if not self.stdin: + return None + + if not select.select([], [self.stdin], [], 0)[1]: + return 0 + + try: + written = os.write(self.stdin.fileno(), input) + except OSError: + if geterror()[0] == errno.EPIPE: # broken pipe + return self._close("stdin") + raise + + return written + + def _recv(self, which, maxsize): + conn, maxsize = self.get_conn_maxsize(which, maxsize) + if conn is None: + return None + + if not select.select([conn], [], [], 0)[0]: + return "" + + r = conn.read(maxsize) + if not r: + return self._close(which) + + if self.universal_newlines: + r = r.replace("\r\n", "\n").replace("\r", "\n") + return r + + +################################################################################ + + +def proc_in_time_or_kill(cmd, time_out, wd=None, env=None): + proc = Popen( + cmd, + cwd=wd, + env=env, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + universal_newlines=1, + ) + + ret_code = None + response = [] + + t = time.time() + while ret_code is None and ((time.time() - t) < time_out): + ret_code = proc.poll() + response += [proc.read_async(wait=0.1, e=0)] + + if ret_code is None: + ret_code = '"Process timed out (time_out = %s secs) ' % time_out + try: + proc.kill() + ret_code += 'and was successfully terminated"' + except Exception: + ret_code += 'and termination failed (exception: %s)"' % (geterror(),) + + return ret_code, "".join(response) + + +################################################################################ + + +class AsyncTest(unittest.TestCase): + def test_proc_in_time_or_kill(self): + ret_code, response = proc_in_time_or_kill( + [sys.executable, "-c", "while 1: pass"], time_out=1 + ) + + self.assertIn("rocess timed out", ret_code) + self.assertIn("successfully terminated", ret_code) + + +################################################################################ + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/test_utils/buftools.py b/venv/Lib/site-packages/pygame/tests/test_utils/buftools.py new file mode 100644 index 0000000..2d2112a --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/test_utils/buftools.py @@ -0,0 +1,613 @@ +"""Module pygame.tests.test_utils.array + +Export the Exporter and Importer classes. + +Class Exporter has configurable shape and strides. Exporter objects +provide a convient target for unit tests on Pygame objects and functions that +import a new buffer interface. + +Class Importer imports a buffer interface with the given PyBUF_* flags. +It returns NULL Py_buffer fields as None. The shape, strides, and suboffsets +arrays are returned as tuples of ints. All Py_buffer field properties are +read-only. This class is useful in comparing exported buffer interfaces +with the actual request. The simular Python builtin memoryview currently +does not support configurable PyBUF_* flags. + +This module contains its own unit tests. When Pygame is installed, these tests +can be run with the following command line statement: + +python -m pygame.tests.test_utils.array + +""" +import pygame + +if not pygame.HAVE_NEWBUF: + emsg = "This Pygame build does not support the new buffer protocol" + raise ImportError(emsg) +import pygame.newbuffer +from pygame.newbuffer import ( + PyBUF_SIMPLE, + PyBUF_FORMAT, + PyBUF_ND, + PyBUF_WRITABLE, + PyBUF_STRIDES, + PyBUF_C_CONTIGUOUS, + PyBUF_F_CONTIGUOUS, + PyBUF_ANY_CONTIGUOUS, + PyBUF_INDIRECT, + PyBUF_STRIDED, + PyBUF_STRIDED_RO, + PyBUF_RECORDS, + PyBUF_RECORDS_RO, + PyBUF_FULL, + PyBUF_FULL_RO, + PyBUF_CONTIG, + PyBUF_CONTIG_RO, +) + +import unittest +import sys +import ctypes +import operator + +try: + reduce +except NameError: + from functools import reduce + +__all__ = ["Exporter", "Importer"] + +try: + ctypes.c_ssize_t +except AttributeError: + void_p_sz = ctypes.sizeof(ctypes.c_void_p) + if ctypes.sizeof(ctypes.c_short) == void_p_sz: + ctypes.c_ssize_t = ctypes.c_short + elif ctypes.sizeof(ctypes.c_int) == void_p_sz: + ctypes.c_ssize_t = ctypes.c_int + elif ctypes.sizeof(ctypes.c_long) == void_p_sz: + ctypes.c_ssize_t = ctypes.c_long + elif ctypes.sizeof(ctypes.c_longlong) == void_p_sz: + ctypes.c_ssize_t = ctypes.c_longlong + else: + raise RuntimeError("Cannot set c_ssize_t: sizeof(void *) is %i" % void_p_sz) + + +def _prop_get(fn): + return property(fn) + + +class Exporter(pygame.newbuffer.BufferMixin): + """An object that exports a multi-dimension new buffer interface + + The only array operation this type supports is to export a buffer. + """ + + prefixes = { + "@": "", + "=": "=", + "<": "=", + ">": "=", + "!": "=", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7", + "8": "8", + "9": "9", + } + types = { + "c": ctypes.c_char, + "b": ctypes.c_byte, + "B": ctypes.c_ubyte, + "=c": ctypes.c_int8, + "=b": ctypes.c_int8, + "=B": ctypes.c_uint8, + "?": ctypes.c_bool, + "=?": ctypes.c_int8, + "h": ctypes.c_short, + "H": ctypes.c_ushort, + "=h": ctypes.c_int16, + "=H": ctypes.c_uint16, + "i": ctypes.c_int, + "I": ctypes.c_uint, + "=i": ctypes.c_int32, + "=I": ctypes.c_uint32, + "l": ctypes.c_long, + "L": ctypes.c_ulong, + "=l": ctypes.c_int32, + "=L": ctypes.c_uint32, + "q": ctypes.c_longlong, + "Q": ctypes.c_ulonglong, + "=q": ctypes.c_int64, + "=Q": ctypes.c_uint64, + "f": ctypes.c_float, + "d": ctypes.c_double, + "P": ctypes.c_void_p, + "x": ctypes.c_ubyte * 1, + "2x": ctypes.c_ubyte * 2, + "3x": ctypes.c_ubyte * 3, + "4x": ctypes.c_ubyte * 4, + "5x": ctypes.c_ubyte * 5, + "6x": ctypes.c_ubyte * 6, + "7x": ctypes.c_ubyte * 7, + "8x": ctypes.c_ubyte * 8, + "9x": ctypes.c_ubyte * 9, + } + + def __init__(self, shape, format=None, strides=None, readonly=None, itemsize=None): + if format is None: + format = "B" + if readonly is None: + readonly = False + prefix = "" + typecode = "" + i = 0 + if i < len(format): + try: + prefix = self.prefixes[format[i]] + i += 1 + except LookupError: + pass + if i < len(format) and format[i] == "1": + i += 1 + if i == len(format) - 1: + typecode = format[i] + if itemsize is None: + try: + itemsize = ctypes.sizeof(self.types[prefix + typecode]) + except KeyError: + raise ValueError("Unknown item format '" + format + "'") + self.readonly = bool(readonly) + self.format = format + self._format = ctypes.create_string_buffer(format.encode("latin_1")) + self.ndim = len(shape) + self.itemsize = itemsize + self.len = reduce(operator.mul, shape, 1) * self.itemsize + self.shape = tuple(shape) + self._shape = (ctypes.c_ssize_t * self.ndim)(*self.shape) + if strides is None: + self._strides = (ctypes.c_ssize_t * self.ndim)() + self._strides[self.ndim - 1] = itemsize + for i in range(self.ndim - 1, 0, -1): + self._strides[i - 1] = self.shape[i] * self._strides[i] + self.strides = tuple(self._strides) + elif len(strides) == self.ndim: + self.strides = tuple(strides) + self._strides = (ctypes.c_ssize_t * self.ndim)(*self.strides) + else: + raise ValueError("Mismatch in length of strides and shape") + buflen = max(d * abs(s) for d, s in zip(self.shape, self.strides)) + self.buflen = buflen + self._buf = (ctypes.c_ubyte * buflen)() + offset = sum( + (d - 1) * abs(s) for d, s in zip(self.shape, self.strides) if s < 0 + ) + self.buf = ctypes.addressof(self._buf) + offset + + def buffer_info(self): + return (addressof(self.buffer), self.shape[0]) + + def tobytes(self): + return cast(self.buffer, POINTER(c_char))[0 : self._len] + + def __len__(self): + return self.shape[0] + + def _get_buffer(self, view, flags): + from ctypes import addressof + + if (flags & PyBUF_WRITABLE) == PyBUF_WRITABLE and self.readonly: + raise BufferError("buffer is read-only") + if ( + flags & PyBUF_C_CONTIGUOUS + ) == PyBUF_C_CONTIGUOUS and not self.is_contiguous("C"): + raise BufferError("data is not C contiguous") + if ( + flags & PyBUF_F_CONTIGUOUS + ) == PyBUF_F_CONTIGUOUS and not self.is_contiguous("F"): + raise BufferError("data is not F contiguous") + if ( + flags & PyBUF_ANY_CONTIGUOUS + ) == PyBUF_ANY_CONTIGUOUS and not self.is_contiguous("A"): + raise BufferError("data is not contiguous") + view.buf = self.buf + view.readonly = self.readonly + view.len = self.len + if flags | PyBUF_WRITABLE == PyBUF_WRITABLE: + view.ndim = 0 + else: + view.ndim = self.ndim + view.itemsize = self.itemsize + if (flags & PyBUF_FORMAT) == PyBUF_FORMAT: + view.format = addressof(self._format) + else: + view.format = None + if (flags & PyBUF_ND) == PyBUF_ND: + view.shape = addressof(self._shape) + elif self.is_contiguous("C"): + view.shape = None + else: + raise BufferError( + "shape required for {} dimensional data".format(self.ndim) + ) + if (flags & PyBUF_STRIDES) == PyBUF_STRIDES: + view.strides = ctypes.addressof(self._strides) + elif view.shape is None or self.is_contiguous("C"): + view.strides = None + else: + raise BufferError("strides required for none C contiguous data") + view.suboffsets = None + view.internal = None + view.obj = self + + def is_contiguous(self, fortran): + if fortran in "CA": + if self.strides[-1] == self.itemsize: + for i in range(self.ndim - 1, 0, -1): + if self.strides[i - 1] != self.shape[i] * self.strides[i]: + break + else: + return True + if fortran in "FA": + if self.strides[0] == self.itemsize: + for i in range(0, self.ndim - 1): + if self.strides[i + 1] != self.shape[i] * self.strides[i]: + break + else: + return True + return False + + +class Importer(object): + """An object that imports a new buffer interface + + The fields of the Py_buffer C struct are exposed by identically + named Importer read-only properties. + """ + + def __init__(self, obj, flags): + self._view = pygame.newbuffer.Py_buffer() + self._view.get_buffer(obj, flags) + + @property + def obj(self): + """return object or None for NULL field""" + return self._view.obj + + @property + def buf(self): + """return int or None for NULL field""" + return self._view.buf + + @property + def len(self): + """return int""" + return self._view.len + + @property + def readonly(self): + """return bool""" + return self._view.readonly + + @property + def format(self): + """return bytes or None for NULL field""" + format_addr = self._view.format + if format_addr is None: + return None + return ctypes.cast(format_addr, ctypes.c_char_p).value.decode("ascii") + + @property + def itemsize(self): + """return int""" + return self._view.itemsize + + @property + def ndim(self): + """return int""" + return self._view.ndim + + @property + def shape(self): + """return int tuple or None for NULL field""" + return self._to_ssize_tuple(self._view.shape) + + @property + def strides(self): + """return int tuple or None for NULL field""" + return self._to_ssize_tuple(self._view.strides) + + @property + def suboffsets(self): + """return int tuple or None for NULL field""" + return self._to_ssize_tuple(self._view.suboffsets) + + @property + def internal(self): + """return int or None for NULL field""" + return self._view.internal + + def _to_ssize_tuple(self, addr): + from ctypes import cast, POINTER, c_ssize_t + + if addr is None: + return None + return tuple(cast(addr, POINTER(c_ssize_t))[0 : self._view.ndim]) + + +class ExporterTest(unittest.TestCase): + """Class Exporter unit tests""" + + def test_formats(self): + char_sz = ctypes.sizeof(ctypes.c_char) + short_sz = ctypes.sizeof(ctypes.c_short) + int_sz = ctypes.sizeof(ctypes.c_int) + long_sz = ctypes.sizeof(ctypes.c_long) + longlong_sz = ctypes.sizeof(ctypes.c_longlong) + float_sz = ctypes.sizeof(ctypes.c_float) + double_sz = ctypes.sizeof(ctypes.c_double) + voidp_sz = ctypes.sizeof(ctypes.c_void_p) + bool_sz = ctypes.sizeof(ctypes.c_bool) + + self.check_args(0, (1,), "B", (1,), 1, 1, 1) + self.check_args(1, (1,), "b", (1,), 1, 1, 1) + self.check_args(1, (1,), "B", (1,), 1, 1, 1) + self.check_args(1, (1,), "c", (char_sz,), char_sz, char_sz, char_sz) + self.check_args(1, (1,), "h", (short_sz,), short_sz, short_sz, short_sz) + self.check_args(1, (1,), "H", (short_sz,), short_sz, short_sz, short_sz) + self.check_args(1, (1,), "i", (int_sz,), int_sz, int_sz, int_sz) + self.check_args(1, (1,), "I", (int_sz,), int_sz, int_sz, int_sz) + self.check_args(1, (1,), "l", (long_sz,), long_sz, long_sz, long_sz) + self.check_args(1, (1,), "L", (long_sz,), long_sz, long_sz, long_sz) + self.check_args( + 1, (1,), "q", (longlong_sz,), longlong_sz, longlong_sz, longlong_sz + ) + self.check_args( + 1, (1,), "Q", (longlong_sz,), longlong_sz, longlong_sz, longlong_sz + ) + self.check_args(1, (1,), "f", (float_sz,), float_sz, float_sz, float_sz) + self.check_args(1, (1,), "d", (double_sz,), double_sz, double_sz, double_sz) + self.check_args(1, (1,), "x", (1,), 1, 1, 1) + self.check_args(1, (1,), "P", (voidp_sz,), voidp_sz, voidp_sz, voidp_sz) + self.check_args(1, (1,), "?", (bool_sz,), bool_sz, bool_sz, bool_sz) + self.check_args(1, (1,), "@b", (1,), 1, 1, 1) + self.check_args(1, (1,), "@B", (1,), 1, 1, 1) + self.check_args(1, (1,), "@c", (char_sz,), char_sz, char_sz, char_sz) + self.check_args(1, (1,), "@h", (short_sz,), short_sz, short_sz, short_sz) + self.check_args(1, (1,), "@H", (short_sz,), short_sz, short_sz, short_sz) + self.check_args(1, (1,), "@i", (int_sz,), int_sz, int_sz, int_sz) + self.check_args(1, (1,), "@I", (int_sz,), int_sz, int_sz, int_sz) + self.check_args(1, (1,), "@l", (long_sz,), long_sz, long_sz, long_sz) + self.check_args(1, (1,), "@L", (long_sz,), long_sz, long_sz, long_sz) + self.check_args( + 1, (1,), "@q", (longlong_sz,), longlong_sz, longlong_sz, longlong_sz + ) + self.check_args( + 1, (1,), "@Q", (longlong_sz,), longlong_sz, longlong_sz, longlong_sz + ) + self.check_args(1, (1,), "@f", (float_sz,), float_sz, float_sz, float_sz) + self.check_args(1, (1,), "@d", (double_sz,), double_sz, double_sz, double_sz) + self.check_args(1, (1,), "@?", (bool_sz,), bool_sz, bool_sz, bool_sz) + self.check_args(1, (1,), "=b", (1,), 1, 1, 1) + self.check_args(1, (1,), "=B", (1,), 1, 1, 1) + self.check_args(1, (1,), "=c", (1,), 1, 1, 1) + self.check_args(1, (1,), "=h", (2,), 2, 2, 2) + self.check_args(1, (1,), "=H", (2,), 2, 2, 2) + self.check_args(1, (1,), "=i", (4,), 4, 4, 4) + self.check_args(1, (1,), "=I", (4,), 4, 4, 4) + self.check_args(1, (1,), "=l", (4,), 4, 4, 4) + self.check_args(1, (1,), "=L", (4,), 4, 4, 4) + self.check_args(1, (1,), "=q", (8,), 8, 8, 8) + self.check_args(1, (1,), "=Q", (8,), 8, 8, 8) + self.check_args(1, (1,), "=?", (1,), 1, 1, 1) + self.check_args(1, (1,), "h", (2,), 2, 2, 2) + self.check_args(1, (1,), "!h", (2,), 2, 2, 2) + self.check_args(1, (1,), "q", (8,), 8, 8, 8) + self.check_args(1, (1,), "!q", (8,), 8, 8, 8) + self.check_args(1, (1,), "1x", (1,), 1, 1, 1) + self.check_args(1, (1,), "2x", (2,), 2, 2, 2) + self.check_args(1, (1,), "3x", (3,), 3, 3, 3) + self.check_args(1, (1,), "4x", (4,), 4, 4, 4) + self.check_args(1, (1,), "5x", (5,), 5, 5, 5) + self.check_args(1, (1,), "6x", (6,), 6, 6, 6) + self.check_args(1, (1,), "7x", (7,), 7, 7, 7) + self.check_args(1, (1,), "8x", (8,), 8, 8, 8) + self.check_args(1, (1,), "9x", (9,), 9, 9, 9) + self.check_args(1, (1,), "1h", (2,), 2, 2, 2) + self.check_args(1, (1,), "=1h", (2,), 2, 2, 2) + self.assertRaises(ValueError, Exporter, (2, 1), "") + self.assertRaises(ValueError, Exporter, (2, 1), "W") + self.assertRaises(ValueError, Exporter, (2, 1), "^Q") + self.assertRaises(ValueError, Exporter, (2, 1), "=W") + self.assertRaises(ValueError, Exporter, (2, 1), "=f") + self.assertRaises(ValueError, Exporter, (2, 1), "=d") + self.assertRaises(ValueError, Exporter, (2, 1), "f") + self.assertRaises(ValueError, Exporter, (2, 1), ">d") + self.assertRaises(ValueError, Exporter, (2, 1), "!f") + self.assertRaises(ValueError, Exporter, (2, 1), "!d") + self.assertRaises(ValueError, Exporter, (2, 1), "0x") + self.assertRaises(ValueError, Exporter, (2, 1), "11x") + self.assertRaises(ValueError, Exporter, (2, 1), "BB") + + def test_strides(self): + self.check_args(1, (10,), "=h", (2,), 20, 20, 2) + self.check_args(1, (5, 3), "=h", (6, 2), 30, 30, 2) + self.check_args(1, (7, 3, 5), "=h", (30, 10, 2), 210, 210, 2) + self.check_args(1, (13, 5, 11, 3), "=h", (330, 66, 6, 2), 4290, 4290, 2) + self.check_args(3, (7, 3, 5), "=h", (2, 14, 42), 210, 210, 2) + self.check_args(3, (7, 3, 5), "=h", (2, 16, 48), 210, 240, 2) + self.check_args(3, (13, 5, 11, 3), "=h", (440, 88, 8, 2), 4290, 5720, 2) + self.check_args(3, (7, 5), "3x", (15, 3), 105, 105, 3) + self.check_args(3, (7, 5), "3x", (3, 21), 105, 105, 3) + self.check_args(3, (7, 5), "3x", (3, 24), 105, 120, 3) + + def test_readonly(self): + a = Exporter((2,), "h", readonly=True) + self.assertTrue(a.readonly) + b = Importer(a, PyBUF_STRIDED_RO) + self.assertRaises(BufferError, Importer, a, PyBUF_STRIDED) + b = Importer(a, PyBUF_STRIDED_RO) + + def test_is_contiguous(self): + a = Exporter((10,), "=h") + self.assertTrue(a.is_contiguous("C")) + self.assertTrue(a.is_contiguous("F")) + self.assertTrue(a.is_contiguous("A")) + a = Exporter((10, 4), "=h") + self.assertTrue(a.is_contiguous("C")) + self.assertTrue(a.is_contiguous("A")) + self.assertFalse(a.is_contiguous("F")) + a = Exporter((13, 5, 11, 3), "=h", (330, 66, 6, 2)) + self.assertTrue(a.is_contiguous("C")) + self.assertTrue(a.is_contiguous("A")) + self.assertFalse(a.is_contiguous("F")) + a = Exporter((10, 4), "=h", (2, 20)) + self.assertTrue(a.is_contiguous("F")) + self.assertTrue(a.is_contiguous("A")) + self.assertFalse(a.is_contiguous("C")) + a = Exporter((13, 5, 11, 3), "=h", (2, 26, 130, 1430)) + self.assertTrue(a.is_contiguous("F")) + self.assertTrue(a.is_contiguous("A")) + self.assertFalse(a.is_contiguous("C")) + a = Exporter((2, 11, 6, 4), "=h", (576, 48, 8, 2)) + self.assertFalse(a.is_contiguous("A")) + a = Exporter((2, 11, 6, 4), "=h", (2, 4, 48, 288)) + self.assertFalse(a.is_contiguous("A")) + a = Exporter((3, 2, 2), "=h", (16, 8, 4)) + self.assertFalse(a.is_contiguous("A")) + a = Exporter((3, 2, 2), "=h", (4, 12, 24)) + self.assertFalse(a.is_contiguous("A")) + + def test_PyBUF_flags(self): + a = Exporter((10, 2), "d") + b = Importer(a, PyBUF_SIMPLE) + self.assertTrue(b.obj is a) + self.assertTrue(b.format is None) + self.assertEqual(b.len, a.len) + self.assertEqual(b.itemsize, a.itemsize) + self.assertTrue(b.shape is None) + self.assertTrue(b.strides is None) + self.assertTrue(b.suboffsets is None) + self.assertTrue(b.internal is None) + self.assertFalse(b.readonly) + b = Importer(a, PyBUF_WRITABLE) + self.assertTrue(b.obj is a) + self.assertTrue(b.format is None) + self.assertEqual(b.len, a.len) + self.assertEqual(b.itemsize, a.itemsize) + self.assertTrue(b.shape is None) + self.assertTrue(b.strides is None) + self.assertTrue(b.suboffsets is None) + self.assertTrue(b.internal is None) + self.assertFalse(b.readonly) + b = Importer(a, PyBUF_ND) + self.assertTrue(b.obj is a) + self.assertTrue(b.format is None) + self.assertEqual(b.len, a.len) + self.assertEqual(b.itemsize, a.itemsize) + self.assertEqual(b.shape, a.shape) + self.assertTrue(b.strides is None) + self.assertTrue(b.suboffsets is None) + self.assertTrue(b.internal is None) + self.assertFalse(b.readonly) + a = Exporter((5, 10), "=h", (24, 2)) + b = Importer(a, PyBUF_STRIDES) + self.assertTrue(b.obj is a) + self.assertTrue(b.format is None) + self.assertEqual(b.len, a.len) + self.assertEqual(b.itemsize, a.itemsize) + self.assertEqual(b.shape, a.shape) + self.assertEqual(b.strides, a.strides) + self.assertTrue(b.suboffsets is None) + self.assertTrue(b.internal is None) + self.assertFalse(b.readonly) + b = Importer(a, PyBUF_FULL) + self.assertTrue(b.obj is a) + self.assertEqual(b.format, "=h") + self.assertEqual(b.len, a.len) + self.assertEqual(b.itemsize, a.itemsize) + self.assertEqual(b.shape, a.shape) + self.assertEqual(b.strides, a.strides) + self.assertTrue(b.suboffsets is None) + self.assertTrue(b.internal is None) + self.assertFalse(b.readonly) + self.assertRaises(BufferError, Importer, a, PyBUF_SIMPLE) + self.assertRaises(BufferError, Importer, a, PyBUF_WRITABLE) + self.assertRaises(BufferError, Importer, a, PyBUF_ND) + self.assertRaises(BufferError, Importer, a, PyBUF_C_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, PyBUF_F_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, PyBUF_ANY_CONTIGUOUS) + self.assertRaises(BufferError, Importer, a, PyBUF_CONTIG) + + def test_negative_strides(self): + self.check_args(3, (3, 5, 4), "B", (20, 4, -1), 60, 60, 1, 3) + self.check_args(3, (3, 5, 3), "B", (20, 4, -1), 45, 60, 1, 2) + self.check_args(3, (3, 5, 4), "B", (20, -4, 1), 60, 60, 1, 16) + self.check_args(3, (3, 5, 4), "B", (-20, -4, -1), 60, 60, 1, 59) + self.check_args(3, (3, 5, 3), "B", (-20, -4, -1), 45, 60, 1, 58) + + def test_attributes(self): + a = Exporter((13, 5, 11, 3), "=h", (440, 88, 8, 2)) + self.assertEqual(a.ndim, 4) + self.assertEqual(a.itemsize, 2) + self.assertFalse(a.readonly) + self.assertEqual(a.shape, (13, 5, 11, 3)) + self.assertEqual(a.format, "=h") + self.assertEqual(a.strides, (440, 88, 8, 2)) + self.assertEqual(a.len, 4290) + self.assertEqual(a.buflen, 5720) + self.assertEqual(a.buf, ctypes.addressof(a._buf)) + a = Exporter((8,)) + self.assertEqual(a.ndim, 1) + self.assertEqual(a.itemsize, 1) + self.assertFalse(a.readonly) + self.assertEqual(a.shape, (8,)) + self.assertEqual(a.format, "B") + self.assertTrue(isinstance(a.strides, tuple)) + self.assertEqual(a.strides, (1,)) + self.assertEqual(a.len, 8) + self.assertEqual(a.buflen, 8) + a = Exporter([13, 5, 11, 3], "=h", [440, 88, 8, 2]) + self.assertTrue(isinstance(a.shape, tuple)) + self.assertTrue(isinstance(a.strides, tuple)) + self.assertEqual(a.shape, (13, 5, 11, 3)) + self.assertEqual(a.strides, (440, 88, 8, 2)) + + def test_itemsize(self): + exp = Exporter((4, 5), format="B", itemsize=8) + imp = Importer(exp, PyBUF_RECORDS) + self.assertEqual(imp.itemsize, 8) + self.assertEqual(imp.format, "B") + self.assertEqual(imp.strides, (40, 8)) + exp = Exporter((4, 5), format="weird", itemsize=5) + imp = Importer(exp, PyBUF_RECORDS) + self.assertEqual(imp.itemsize, 5) + self.assertEqual(imp.format, "weird") + self.assertEqual(imp.strides, (25, 5)) + + def check_args( + self, call_flags, shape, format, strides, length, bufsize, itemsize, offset=0 + ): + format_arg = format if call_flags & 1 else None + strides_arg = strides if call_flags & 2 else None + a = Exporter(shape, format_arg, strides_arg) + self.assertEqual(a.buflen, bufsize) + self.assertEqual(a.buf, ctypes.addressof(a._buf) + offset) + m = Importer(a, PyBUF_RECORDS_RO) + self.assertEqual(m.buf, a.buf) + self.assertEqual(m.len, length) + self.assertEqual(m.format, format) + self.assertEqual(m.itemsize, itemsize) + self.assertEqual(m.shape, shape) + self.assertEqual(m.strides, strides) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/test_utils/endian.py b/venv/Lib/site-packages/pygame/tests/test_utils/endian.py new file mode 100644 index 0000000..64ba1b3 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/test_utils/endian.py @@ -0,0 +1,20 @@ +# Module pygame.tests.test_utils.endian +# +# Machine independent conversion to little-endian and big-endian Python +# integer values. + +import struct + + +def little_endian_uint32(i): + """Return the 32 bit unsigned integer little-endian representation of i""" + + s = struct.pack("I", i) + return struct.unpack("=I", s)[0] diff --git a/venv/Lib/site-packages/pygame/tests/test_utils/png.py b/venv/Lib/site-packages/pygame/tests/test_utils/png.py new file mode 100644 index 0000000..74df9fd --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/test_utils/png.py @@ -0,0 +1,4001 @@ +#!/usr/bin/env python + +# $URL: http://pypng.googlecode.com/svn/trunk/code/png.py $ +# $Rev: 228 $ + +# png.py - PNG encoder/decoder in pure Python +# +# Modified for Pygame in Oct., 2012 to work with Python 3.x. +# +# Copyright (C) 2006 Johann C. Rocholl +# Portions Copyright (C) 2009 David Jones +# And probably portions Copyright (C) 2006 Nicko van Someren +# +# Original concept by Johann C. Rocholl. +# +# LICENSE (The MIT License) +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Changelog (recent first): +# 2009-03-11 David: interlaced bit depth < 8 (writing). +# 2009-03-10 David: interlaced bit depth < 8 (reading). +# 2009-03-04 David: Flat and Boxed pixel formats. +# 2009-02-26 David: Palette support (writing). +# 2009-02-23 David: Bit-depths < 8; better PNM support. +# 2006-06-17 Nicko: Reworked into a class, faster interlacing. +# 2006-06-17 Johann: Very simple prototype PNG decoder. +# 2006-06-17 Nicko: Test suite with various image generators. +# 2006-06-17 Nicko: Alpha-channel, grey-scale, 16-bit/plane support. +# 2006-06-15 Johann: Scanline iterator interface for large input files. +# 2006-06-09 Johann: Very simple prototype PNG encoder. + +# Incorporated into Bangai-O Development Tools by drj on 2009-02-11 from +# http://trac.browsershots.org/browser/trunk/pypng/lib/png.py?rev=2885 + +# Incorporated into pypng by drj on 2009-03-12 from +# //depot/prj/bangaio/master/code/png.py#67 + + +""" +Pure Python PNG Reader/Writer + +This Python module implements support for PNG images (see PNG +specification at http://www.w3.org/TR/2003/REC-PNG-20031110/ ). It reads +and writes PNG files with all allowable bit depths (1/2/4/8/16/24/32/48/64 +bits per pixel) and colour combinations: greyscale (1/2/4/8/16 bit); RGB, +RGBA, LA (greyscale with alpha) with 8/16 bits per channel; colour mapped +images (1/2/4/8 bit). Adam7 interlacing is supported for reading and +writing. A number of optional chunks can be specified (when writing) +and understood (when reading): ``tRNS``, ``bKGD``, ``gAMA``. + +For help, type ``import png; help(png)`` in your python interpreter. + +A good place to start is the :class:`Reader` and :class:`Writer` classes. + +This file can also be used as a command-line utility to convert +`Netpbm `_ PNM files to PNG, and the reverse conversion from PNG to +PNM. The interface is similar to that of the ``pnmtopng`` program from +Netpbm. Type ``python png.py --help`` at the shell prompt +for usage and a list of options. + +A note on spelling and terminology +---------------------------------- + +Generally British English spelling is used in the documentation. So +that's "greyscale" and "colour". This not only matches the author's +native language, it's also used by the PNG specification. + +The major colour models supported by PNG (and hence by PyPNG) are: +greyscale, RGB, greyscale--alpha, RGB--alpha. These are sometimes +referred to using the abbreviations: L, RGB, LA, RGBA. In this case +each letter abbreviates a single channel: *L* is for Luminance or Luma or +Lightness which is the channel used in greyscale images; *R*, *G*, *B* stand +for Red, Green, Blue, the components of a colour image; *A* stands for +Alpha, the opacity channel (used for transparency effects, but higher +values are more opaque, so it makes sense to call it opacity). + +A note on formats +----------------- + +When getting pixel data out of this module (reading) and presenting +data to this module (writing) there are a number of ways the data could +be represented as a Python value. Generally this module uses one of +three formats called "flat row flat pixel", "boxed row flat pixel", and +"boxed row boxed pixel". Basically the concern is whether each pixel +and each row comes in its own little tuple (box), or not. + +Consider an image that is 3 pixels wide by 2 pixels high, and each pixel +has RGB components: + +Boxed row flat pixel:: + + list([R,G,B, R,G,B, R,G,B], + [R,G,B, R,G,B, R,G,B]) + +Each row appears as its own list, but the pixels are flattened so that +three values for one pixel simply follow the three values for the previous +pixel. This is the most common format used, because it provides a good +compromise between space and convenience. PyPNG regards itself as +at liberty to replace any sequence type with any sufficiently compatible +other sequence type; in practice each row is an array (from the array +module), and the outer list is sometimes an iterator rather than an +explicit list (so that streaming is possible). + +Flat row flat pixel:: + + [R,G,B, R,G,B, R,G,B, + R,G,B, R,G,B, R,G,B] + +The entire image is one single giant sequence of colour values. +Generally an array will be used (to save space), not a list. + +Boxed row boxed pixel:: + + list([ (R,G,B), (R,G,B), (R,G,B) ], + [ (R,G,B), (R,G,B), (R,G,B) ]) + +Each row appears in its own list, but each pixel also appears in its own +tuple. A serious memory burn in Python. + +In all cases the top row comes first, and for each row the pixels are +ordered from left-to-right. Within a pixel the values appear in the +order, R-G-B-A (or L-A for greyscale--alpha). + +There is a fourth format, mentioned because it is used internally, +is close to what lies inside a PNG file itself, and has some support +from the public API. This format is called packed. When packed, +each row is a sequence of bytes (integers from 0 to 255), just as +it is before PNG scanline filtering is applied. When the bit depth +is 8 this is essentially the same as boxed row flat pixel; when the +bit depth is less than 8, several pixels are packed into each byte; +when the bit depth is 16 (the only value more than 8 that is supported +by the PNG image format) each pixel value is decomposed into 2 bytes +(and `packed` is a misnomer). This format is used by the +:meth:`Writer.write_packed` method. It isn't usually a convenient +format, but may be just right if the source data for the PNG image +comes from something that uses a similar format (for example, 1-bit +BMPs, or another PNG file). + +And now, my famous members +-------------------------- +""" + +__version__ = "$URL: http://pypng.googlecode.com/svn/trunk/code/png.py $ $Rev: 228 $" + +from array import array +from pygame.tests.test_utils import tostring +import itertools +import math +import operator +import struct +import sys +import zlib +import warnings + +__all__ = ["Image", "Reader", "Writer", "write_chunks", "from_array"] + + +# The PNG signature. +# http://www.w3.org/TR/PNG/#5PNG-file-signature +_signature = struct.pack("8B", 137, 80, 78, 71, 13, 10, 26, 10) + +_adam7 = ( + (0, 0, 8, 8), + (4, 0, 8, 8), + (0, 4, 4, 8), + (2, 0, 4, 4), + (0, 2, 2, 4), + (1, 0, 2, 2), + (0, 1, 1, 2), +) + + +def group(s, n): + # See + # http://www.python.org/doc/2.6/library/functions.html#zip + return zip(*[iter(s)] * n) + + +def isarray(x): + """Same as ``isinstance(x, array)``.""" + return isinstance(x, array) + + +# Conditionally convert to bytes. Works on Python 2 and Python 3. +try: + bytes("", "ascii") + + def strtobytes(x): + return bytes(x, "iso8859-1") + + def bytestostr(x): + return str(x, "iso8859-1") + +except: + strtobytes = str + bytestostr = str + + +def interleave_planes(ipixels, apixels, ipsize, apsize): + """ + Interleave (colour) planes, e.g. RGB + A = RGBA. + + Return an array of pixels consisting of the `ipsize` elements of data + from each pixel in `ipixels` followed by the `apsize` elements of data + from each pixel in `apixels`. Conventionally `ipixels` and + `apixels` are byte arrays so the sizes are bytes, but it actually + works with any arrays of the same type. The returned array is the + same type as the input arrays which should be the same type as each other. + """ + + itotal = len(ipixels) + atotal = len(apixels) + newtotal = itotal + atotal + newpsize = ipsize + apsize + # Set up the output buffer + # See http://www.python.org/doc/2.4.4/lib/module-array.html#l2h-1356 + out = array(ipixels.typecode) + # It's annoying that there is no cheap way to set the array size :-( + out.extend(ipixels) + out.extend(apixels) + # Interleave in the pixel data + for i in range(ipsize): + out[i:newtotal:newpsize] = ipixels[i:itotal:ipsize] + for i in range(apsize): + out[i + ipsize : newtotal : newpsize] = apixels[i:atotal:apsize] + return out + + +def check_palette(palette): + """Check a palette argument (to the :class:`Writer` class) for validity. + Returns the palette as a list if okay; raises an exception otherwise. + """ + + # None is the default and is allowed. + if palette is None: + return None + + p = list(palette) + if not (0 < len(p) <= 256): + raise ValueError("a palette must have between 1 and 256 entries") + seen_triple = False + for i, t in enumerate(p): + if len(t) not in (3, 4): + raise ValueError("palette entry %d: entries must be 3- or 4-tuples." % i) + if len(t) == 3: + seen_triple = True + if seen_triple and len(t) == 4: + raise ValueError( + "palette entry %d: all 4-tuples must precede all 3-tuples" % i + ) + for x in t: + if int(x) != x or not (0 <= x <= 255): + raise ValueError( + "palette entry %d: values must be integer: 0 <= x <= 255" % i + ) + return p + + +class Error(Exception): + prefix = "Error" + + def __str__(self): + return self.prefix + ": " + " ".join(self.args) + + +class FormatError(Error): + """Problem with input file format. In other words, PNG file does + not conform to the specification in some way and is invalid. + """ + + prefix = "FormatError" + + +class ChunkError(FormatError): + prefix = "ChunkError" + + +class Writer: + """ + PNG encoder in pure Python. + """ + + def __init__( + self, + width=None, + height=None, + size=None, + greyscale=False, + alpha=False, + bitdepth=8, + palette=None, + transparent=None, + background=None, + gamma=None, + compression=None, + interlace=False, + bytes_per_sample=None, # deprecated + planes=None, + colormap=None, + maxval=None, + chunk_limit=2 ** 20, + ): + """ + Create a PNG encoder object. + + Arguments: + + width, height + Image size in pixels, as two separate arguments. + size + Image size (w,h) in pixels, as single argument. + greyscale + Input data is greyscale, not RGB. + alpha + Input data has alpha channel (RGBA or LA). + bitdepth + Bit depth: from 1 to 16. + palette + Create a palette for a colour mapped image (colour type 3). + transparent + Specify a transparent colour (create a ``tRNS`` chunk). + background + Specify a default background colour (create a ``bKGD`` chunk). + gamma + Specify a gamma value (create a ``gAMA`` chunk). + compression + zlib compression level (1-9). + interlace + Create an interlaced image. + chunk_limit + Write multiple ``IDAT`` chunks to save memory. + + The image size (in pixels) can be specified either by using the + `width` and `height` arguments, or with the single `size` + argument. If `size` is used it should be a pair (*width*, + *height*). + + `greyscale` and `alpha` are booleans that specify whether + an image is greyscale (or colour), and whether it has an + alpha channel (or not). + + `bitdepth` specifies the bit depth of the source pixel values. + Each source pixel value must be an integer between 0 and + ``2**bitdepth-1``. For example, 8-bit images have values + between 0 and 255. PNG only stores images with bit depths of + 1,2,4,8, or 16. When `bitdepth` is not one of these values, + the next highest valid bit depth is selected, and an ``sBIT`` + (significant bits) chunk is generated that specifies the original + precision of the source image. In this case the supplied pixel + values will be rescaled to fit the range of the selected bit depth. + + The details of which bit depth / colour model combinations the + PNG file format supports directly, are somewhat arcane + (refer to the PNG specification for full details). Briefly: + "small" bit depths (1,2,4) are only allowed with greyscale and + colour mapped images; colour mapped images cannot have bit depth + 16. + + For colour mapped images (in other words, when the `palette` + argument is specified) the `bitdepth` argument must match one of + the valid PNG bit depths: 1, 2, 4, or 8. (It is valid to have a + PNG image with a palette and an ``sBIT`` chunk, but the meaning + is slightly different; it would be awkward to press the + `bitdepth` argument into service for this.) + + The `palette` option, when specified, causes a colour mapped image + to be created: the PNG colour type is set to 3; greyscale + must not be set; alpha must not be set; transparent must + not be set; the bit depth must be 1,2,4, or 8. When a colour + mapped image is created, the pixel values are palette indexes + and the `bitdepth` argument specifies the size of these indexes + (not the size of the colour values in the palette). + + The palette argument value should be a sequence of 3- or + 4-tuples. 3-tuples specify RGB palette entries; 4-tuples + specify RGBA palette entries. If both 4-tuples and 3-tuples + appear in the sequence then all the 4-tuples must come + before all the 3-tuples. A ``PLTE`` chunk is created; if there + are 4-tuples then a ``tRNS`` chunk is created as well. The + ``PLTE`` chunk will contain all the RGB triples in the same + sequence; the ``tRNS`` chunk will contain the alpha channel for + all the 4-tuples, in the same sequence. Palette entries + are always 8-bit. + + If specified, the `transparent` and `background` parameters must + be a tuple with three integer values for red, green, blue, or + a simple integer (or singleton tuple) for a greyscale image. + + If specified, the `gamma` parameter must be a positive number + (generally, a float). A ``gAMA`` chunk will be created. Note that + this will not change the values of the pixels as they appear in + the PNG file, they are assumed to have already been converted + appropriately for the gamma specified. + + The `compression` argument specifies the compression level + to be used by the ``zlib`` module. Higher values are likely + to compress better, but will be slower to compress. The + default for this argument is ``None``; this does not mean + no compression, rather it means that the default from the + ``zlib`` module is used (which is generally acceptable). + + If `interlace` is true then an interlaced image is created + (using PNG's so far only interlace method, *Adam7*). This does not + affect how the pixels should be presented to the encoder, rather + it changes how they are arranged into the PNG file. On slow + connexions interlaced images can be partially decoded by the + browser to give a rough view of the image that is successively + refined as more image data appears. + + .. note :: + + Enabling the `interlace` option requires the entire image + to be processed in working memory. + + `chunk_limit` is used to limit the amount of memory used whilst + compressing the image. In order to avoid using large amounts of + memory, multiple ``IDAT`` chunks may be created. + """ + + # At the moment the `planes` argument is ignored; + # its purpose is to act as a dummy so that + # ``Writer(x, y, **info)`` works, where `info` is a dictionary + # returned by Reader.read and friends. + # Ditto for `colormap`. + + # A couple of helper functions come first. Best skipped if you + # are reading through. + + def isinteger(x): + try: + return int(x) == x + except: + return False + + def check_color(c, which): + """Checks that a colour argument for transparent or + background options is the right form. Also "corrects" bare + integers to 1-tuples. + """ + + if c is None: + return c + if greyscale: + try: + l = len(c) + except TypeError: + c = (c,) + if len(c) != 1: + raise ValueError("%s for greyscale must be 1-tuple" % which) + if not isinteger(c[0]): + raise ValueError("%s colour for greyscale must be integer" % which) + else: + if not ( + len(c) == 3 + and isinteger(c[0]) + and isinteger(c[1]) + and isinteger(c[2]) + ): + raise ValueError("%s colour must be a triple of integers" % which) + return c + + if size: + if len(size) != 2: + raise ValueError("size argument should be a pair (width, height)") + if width is not None and width != size[0]: + raise ValueError( + "size[0] (%r) and width (%r) should match when both are used." + % (size[0], width) + ) + if height is not None and height != size[1]: + raise ValueError( + "size[1] (%r) and height (%r) should match when both are used." + % (size[1], height) + ) + width, height = size + del size + + if width <= 0 or height <= 0: + raise ValueError("width and height must be greater than zero") + if not isinteger(width) or not isinteger(height): + raise ValueError("width and height must be integers") + # http://www.w3.org/TR/PNG/#7Integers-and-byte-order + if width > 2 ** 32 - 1 or height > 2 ** 32 - 1: + raise ValueError("width and height cannot exceed 2**32-1") + + if alpha and transparent is not None: + raise ValueError("transparent colour not allowed with alpha channel") + + if bytes_per_sample is not None: + warnings.warn( + "please use bitdepth instead of bytes_per_sample", DeprecationWarning + ) + if bytes_per_sample not in (0.125, 0.25, 0.5, 1, 2): + raise ValueError("bytes per sample must be .125, .25, .5, 1, or 2") + bitdepth = int(8 * bytes_per_sample) + del bytes_per_sample + if not isinteger(bitdepth) or bitdepth < 1 or 16 < bitdepth: + raise ValueError( + "bitdepth (%r) must be a positive integer <= 16" % bitdepth + ) + + self.rescale = None + if palette: + if bitdepth not in (1, 2, 4, 8): + raise ValueError("with palette, bitdepth must be 1, 2, 4, or 8") + if transparent is not None: + raise ValueError("transparent and palette not compatible") + if alpha: + raise ValueError("alpha and palette not compatible") + if greyscale: + raise ValueError("greyscale and palette not compatible") + else: + # No palette, check for sBIT chunk generation. + if alpha or not greyscale: + if bitdepth not in (8, 16): + targetbitdepth = (8, 16)[bitdepth > 8] + self.rescale = (bitdepth, targetbitdepth) + bitdepth = targetbitdepth + del targetbitdepth + else: + assert greyscale + assert not alpha + if bitdepth not in (1, 2, 4, 8, 16): + if bitdepth > 8: + targetbitdepth = 16 + elif bitdepth == 3: + targetbitdepth = 4 + else: + assert bitdepth in (5, 6, 7) + targetbitdepth = 8 + self.rescale = (bitdepth, targetbitdepth) + bitdepth = targetbitdepth + del targetbitdepth + + if bitdepth < 8 and (alpha or not greyscale and not palette): + raise ValueError("bitdepth < 8 only permitted with greyscale or palette") + if bitdepth > 8 and palette: + raise ValueError("bit depth must be 8 or less for images with palette") + + transparent = check_color(transparent, "transparent") + background = check_color(background, "background") + + # It's important that the true boolean values (greyscale, alpha, + # colormap, interlace) are converted to bool because Iverson's + # convention is relied upon later on. + self.width = width + self.height = height + self.transparent = transparent + self.background = background + self.gamma = gamma + self.greyscale = bool(greyscale) + self.alpha = bool(alpha) + self.colormap = bool(palette) + self.bitdepth = int(bitdepth) + self.compression = compression + self.chunk_limit = chunk_limit + self.interlace = bool(interlace) + self.palette = check_palette(palette) + + self.color_type = 4 * self.alpha + 2 * (not greyscale) + 1 * self.colormap + assert self.color_type in (0, 2, 3, 4, 6) + + self.color_planes = (3, 1)[self.greyscale or self.colormap] + self.planes = self.color_planes + self.alpha + # :todo: fix for bitdepth < 8 + self.psize = (self.bitdepth / 8) * self.planes + + def make_palette(self): + """Create the byte sequences for a ``PLTE`` and if necessary a + ``tRNS`` chunk. Returned as a pair (*p*, *t*). *t* will be + ``None`` if no ``tRNS`` chunk is necessary. + """ + + p = array("B") + t = array("B") + + for x in self.palette: + p.extend(x[0:3]) + if len(x) > 3: + t.append(x[3]) + p = tostring(p) + t = tostring(t) + if t: + return p, t + return p, None + + def write(self, outfile, rows): + """Write a PNG image to the output file. `rows` should be + an iterable that yields each row in boxed row flat pixel format. + The rows should be the rows of the original image, so there + should be ``self.height`` rows of ``self.width * self.planes`` values. + If `interlace` is specified (when creating the instance), then + an interlaced PNG file will be written. Supply the rows in the + normal image order; the interlacing is carried out internally. + + .. note :: + + Interlacing will require the entire image to be in working memory. + """ + + if self.interlace: + fmt = "BH"[self.bitdepth > 8] + a = array(fmt, itertools.chain(*rows)) + return self.write_array(outfile, a) + else: + nrows = self.write_passes(outfile, rows) + if nrows != self.height: + raise ValueError( + "rows supplied (%d) does not match height (%d)" + % (nrows, self.height) + ) + + def write_passes(self, outfile, rows, packed=False): + """ + Write a PNG image to the output file. + + Most users are expected to find the :meth:`write` or + :meth:`write_array` method more convenient. + + The rows should be given to this method in the order that + they appear in the output file. For straightlaced images, + this is the usual top to bottom ordering, but for interlaced + images the rows should have already been interlaced before + passing them to this function. + + `rows` should be an iterable that yields each row. When + `packed` is ``False`` the rows should be in boxed row flat pixel + format; when `packed` is ``True`` each row should be a packed + sequence of bytes. + + """ + + # http://www.w3.org/TR/PNG/#5PNG-file-signature + outfile.write(_signature) + + # http://www.w3.org/TR/PNG/#11IHDR + write_chunk( + outfile, + "IHDR", + struct.pack( + "!2I5B", + self.width, + self.height, + self.bitdepth, + self.color_type, + 0, + 0, + self.interlace, + ), + ) + + # See :chunk:order + # http://www.w3.org/TR/PNG/#11gAMA + if self.gamma is not None: + write_chunk( + outfile, "gAMA", struct.pack("!L", int(round(self.gamma * 1e5))) + ) + + # See :chunk:order + # http://www.w3.org/TR/PNG/#11sBIT + if self.rescale: + write_chunk( + outfile, + "sBIT", + struct.pack("%dB" % self.planes, *[self.rescale[0]] * self.planes), + ) + + # :chunk:order: Without a palette (PLTE chunk), ordering is + # relatively relaxed. With one, gAMA chunk must precede PLTE + # chunk which must precede tRNS and bKGD. + # See http://www.w3.org/TR/PNG/#5ChunkOrdering + if self.palette: + p, t = self.make_palette() + write_chunk(outfile, "PLTE", p) + if t: + # tRNS chunk is optional. Only needed if palette entries + # have alpha. + write_chunk(outfile, "tRNS", t) + + # http://www.w3.org/TR/PNG/#11tRNS + if self.transparent is not None: + if self.greyscale: + write_chunk(outfile, "tRNS", struct.pack("!1H", *self.transparent)) + else: + write_chunk(outfile, "tRNS", struct.pack("!3H", *self.transparent)) + + # http://www.w3.org/TR/PNG/#11bKGD + if self.background is not None: + if self.greyscale: + write_chunk(outfile, "bKGD", struct.pack("!1H", *self.background)) + else: + write_chunk(outfile, "bKGD", struct.pack("!3H", *self.background)) + + # http://www.w3.org/TR/PNG/#11IDAT + if self.compression is not None: + compressor = zlib.compressobj(self.compression) + else: + compressor = zlib.compressobj() + + # Choose an extend function based on the bitdepth. The extend + # function packs/decomposes the pixel values into bytes and + # stuffs them onto the data array. + data = array("B") + if self.bitdepth == 8 or packed: + extend = data.extend + elif self.bitdepth == 16: + # Decompose into bytes + def extend(sl): + fmt = "!%dH" % len(sl) + data.extend(array("B", struct.pack(fmt, *sl))) + + else: + # Pack into bytes + assert self.bitdepth < 8 + # samples per byte + spb = int(8 / self.bitdepth) + + def extend(sl): + a = array("B", sl) + # Adding padding bytes so we can group into a whole + # number of spb-tuples. + l = float(len(a)) + extra = math.ceil(l / float(spb)) * spb - l + a.extend([0] * int(extra)) + # Pack into bytes + l = group(a, spb) + l = map(lambda e: reduce(lambda x, y: (x << self.bitdepth) + y, e), l) + data.extend(l) + + if self.rescale: + oldextend = extend + factor = float(2 ** self.rescale[1] - 1) / float(2 ** self.rescale[0] - 1) + + def extend(sl): + oldextend(map(lambda x: int(round(factor * x)), sl)) + + # Build the first row, testing mostly to see if we need to + # changed the extend function to cope with NumPy integer types + # (they cause our ordinary definition of extend to fail, so we + # wrap it). See + # http://code.google.com/p/pypng/issues/detail?id=44 + enumrows = enumerate(rows) + del rows + + # First row's filter type. + data.append(0) + # :todo: Certain exceptions in the call to ``.next()`` or the + # following try would indicate no row data supplied. + # Should catch. + i, row = next(enumrows) + try: + # If this fails... + extend(row) + except: + # ... try a version that converts the values to int first. + # Not only does this work for the (slightly broken) NumPy + # types, there are probably lots of other, unknown, "nearly" + # int types it works for. + def wrapmapint(f): + return lambda sl: f(map(int, sl)) + + extend = wrapmapint(extend) + del wrapmapint + extend(row) + + for i, row in enumrows: + # Add "None" filter type. Currently, it's essential that + # this filter type be used for every scanline as we do not + # mark the first row of a reduced pass image; that means we + # could accidentally compute the wrong filtered scanline if + # we used "up", "average", or "paeth" on such a line. + data.append(0) + extend(row) + if len(data) > self.chunk_limit: + compressed = compressor.compress(tostring(data)) + if len(compressed): + # print >> sys.stderr, len(data), len(compressed) + write_chunk(outfile, "IDAT", compressed) + # Because of our very witty definition of ``extend``, + # above, we must re-use the same ``data`` object. Hence + # we use ``del`` to empty this one, rather than create a + # fresh one (which would be my natural FP instinct). + del data[:] + if len(data): + compressed = compressor.compress(tostring(data)) + else: + compressed = "" + flushed = compressor.flush() + if len(compressed) or len(flushed): + # print >> sys.stderr, len(data), len(compressed), len(flushed) + write_chunk(outfile, "IDAT", compressed + flushed) + # http://www.w3.org/TR/PNG/#11IEND + write_chunk(outfile, "IEND") + return i + 1 + + def write_array(self, outfile, pixels): + """ + Write an array in flat row flat pixel format as a PNG file on + the output file. See also :meth:`write` method. + """ + + if self.interlace: + self.write_passes(outfile, self.array_scanlines_interlace(pixels)) + else: + self.write_passes(outfile, self.array_scanlines(pixels)) + + def write_packed(self, outfile, rows): + """ + Write PNG file to `outfile`. The pixel data comes from `rows` + which should be in boxed row packed format. Each row should be + a sequence of packed bytes. + + Technically, this method does work for interlaced images but it + is best avoided. For interlaced images, the rows should be + presented in the order that they appear in the file. + + This method should not be used when the source image bit depth + is not one naturally supported by PNG; the bit depth should be + 1, 2, 4, 8, or 16. + """ + + if self.rescale: + raise Error( + "write_packed method not suitable for bit depth %d" % self.rescale[0] + ) + return self.write_passes(outfile, rows, packed=True) + + def convert_pnm(self, infile, outfile): + """ + Convert a PNM file containing raw pixel data into a PNG file + with the parameters set in the writer object. Works for + (binary) PGM, PPM, and PAM formats. + """ + + if self.interlace: + pixels = array("B") + pixels.fromfile( + infile, + (self.bitdepth / 8) * self.color_planes * self.width * self.height, + ) + self.write_passes(outfile, self.array_scanlines_interlace(pixels)) + else: + self.write_passes(outfile, self.file_scanlines(infile)) + + def convert_ppm_and_pgm(self, ppmfile, pgmfile, outfile): + """ + Convert a PPM and PGM file containing raw pixel data into a + PNG outfile with the parameters set in the writer object. + """ + pixels = array("B") + pixels.fromfile( + ppmfile, (self.bitdepth / 8) * self.color_planes * self.width * self.height + ) + apixels = array("B") + apixels.fromfile(pgmfile, (self.bitdepth / 8) * self.width * self.height) + pixels = interleave_planes( + pixels, + apixels, + (self.bitdepth / 8) * self.color_planes, + (self.bitdepth / 8), + ) + if self.interlace: + self.write_passes(outfile, self.array_scanlines_interlace(pixels)) + else: + self.write_passes(outfile, self.array_scanlines(pixels)) + + def file_scanlines(self, infile): + """ + Generates boxed rows in flat pixel format, from the input file + `infile`. It assumes that the input file is in a "Netpbm-like" + binary format, and is positioned at the beginning of the first + pixel. The number of pixels to read is taken from the image + dimensions (`width`, `height`, `planes`) and the number of bytes + per value is implied by the image `bitdepth`. + """ + + # Values per row + vpr = self.width * self.planes + row_bytes = vpr + if self.bitdepth > 8: + assert self.bitdepth == 16 + row_bytes *= 2 + fmt = ">%dH" % vpr + + def line(): + return array("H", struct.unpack(fmt, infile.read(row_bytes))) + + else: + + def line(): + scanline = array("B", infile.read(row_bytes)) + return scanline + + for y in range(self.height): + yield line() + + def array_scanlines(self, pixels): + """ + Generates boxed rows (flat pixels) from flat rows (flat pixels) + in an array. + """ + + # Values per row + vpr = self.width * self.planes + stop = 0 + for y in range(self.height): + start = stop + stop = start + vpr + yield pixels[start:stop] + + def array_scanlines_interlace(self, pixels): + """ + Generator for interlaced scanlines from an array. `pixels` is + the full source image in flat row flat pixel format. The + generator yields each scanline of the reduced passes in turn, in + boxed row flat pixel format. + """ + + # http://www.w3.org/TR/PNG/#8InterlaceMethods + # Array type. + fmt = "BH"[self.bitdepth > 8] + # Value per row + vpr = self.width * self.planes + for xstart, ystart, xstep, ystep in _adam7: + if xstart >= self.width: + continue + # Pixels per row (of reduced image) + ppr = int(math.ceil((self.width - xstart) / float(xstep))) + # number of values in reduced image row. + row_len = ppr * self.planes + for y in range(ystart, self.height, ystep): + if xstep == 1: + offset = y * vpr + yield pixels[offset : offset + vpr] + else: + row = array(fmt) + # There's no easier way to set the length of an array + row.extend(pixels[0:row_len]) + offset = y * vpr + xstart * self.planes + end_offset = (y + 1) * vpr + skip = self.planes * xstep + for i in range(self.planes): + row[i :: self.planes] = pixels[offset + i : end_offset : skip] + yield row + + +def write_chunk(outfile, tag, data=strtobytes("")): + """ + Write a PNG chunk to the output file, including length and + checksum. + """ + + # http://www.w3.org/TR/PNG/#5Chunk-layout + outfile.write(struct.pack("!I", len(data))) + tag = strtobytes(tag) + outfile.write(tag) + outfile.write(data) + checksum = zlib.crc32(tag) + checksum = zlib.crc32(data, checksum) + checksum &= 2 ** 32 - 1 + outfile.write(struct.pack("!I", checksum)) + + +def write_chunks(out, chunks): + """Create a PNG file by writing out the chunks.""" + + out.write(_signature) + for chunk in chunks: + write_chunk(out, *chunk) + + +def filter_scanline(type, line, fo, prev=None): + """Apply a scanline filter to a scanline. `type` specifies the + filter type (0 to 4); `line` specifies the current (unfiltered) + scanline as a sequence of bytes; `prev` specifies the previous + (unfiltered) scanline as a sequence of bytes. `fo` specifies the + filter offset; normally this is size of a pixel in bytes (the number + of bytes per sample times the number of channels), but when this is + < 1 (for bit depths < 8) then the filter offset is 1. + """ + + assert 0 <= type < 5 + + # The output array. Which, pathetically, we extend one-byte at a + # time (fortunately this is linear). + out = array("B", [type]) + + def sub(): + ai = -fo + for x in line: + if ai >= 0: + x = (x - line[ai]) & 0xFF + out.append(x) + ai += 1 + + def up(): + for i, x in enumerate(line): + x = (x - prev[i]) & 0xFF + out.append(x) + + def average(): + ai = -fo + for i, x in enumerate(line): + if ai >= 0: + x = (x - ((line[ai] + prev[i]) >> 1)) & 0xFF + else: + x = (x - (prev[i] >> 1)) & 0xFF + out.append(x) + ai += 1 + + def paeth(): + # http://www.w3.org/TR/PNG/#9Filter-type-4-Paeth + ai = -fo # also used for ci + for i, x in enumerate(line): + a = 0 + b = prev[i] + c = 0 + + if ai >= 0: + a = line[ai] + c = prev[ai] + p = a + b - c + pa = abs(p - a) + pb = abs(p - b) + pc = abs(p - c) + if pa <= pb and pa <= pc: + Pr = a + elif pb <= pc: + Pr = b + else: + Pr = c + + x = (x - Pr) & 0xFF + out.append(x) + ai += 1 + + if not prev: + # We're on the first line. Some of the filters can be reduced + # to simpler cases which makes handling the line "off the top" + # of the image simpler. "up" becomes "none"; "paeth" becomes + # "left" (non-trivial, but true). "average" needs to be handled + # specially. + if type == 2: # "up" + return line # type = 0 + elif type == 3: + prev = [0] * len(line) + elif type == 4: # "paeth" + type = 1 + if type == 0: + out.extend(line) + elif type == 1: + sub() + elif type == 2: + up() + elif type == 3: + average() + else: # type == 4 + paeth() + return out + + +def from_array(a, mode=None, info={}): + """Create a PNG :class:`Image` object from a 2- or 3-dimensional array. + One application of this function is easy PIL-style saving: + ``png.from_array(pixels, 'L').save('foo.png')``. + + .. note : + + The use of the term *3-dimensional* is for marketing purposes + only. It doesn't actually work. Please bear with us. Meanwhile + enjoy the complimentary snacks (on request) and please use a + 2-dimensional array. + + Unless they are specified using the *info* parameter, the PNG's + height and width are taken from the array size. For a 3 dimensional + array the first axis is the height; the second axis is the width; + and the third axis is the channel number. Thus an RGB image that is + 16 pixels high and 8 wide will use an array that is 16x8x3. For 2 + dimensional arrays the first axis is the height, but the second axis + is ``width*channels``, so an RGB image that is 16 pixels high and 8 + wide will use a 2-dimensional array that is 16x24 (each row will be + 8*3==24 sample values). + + *mode* is a string that specifies the image colour format in a + PIL-style mode. It can be: + + ``'L'`` + greyscale (1 channel) + ``'LA'`` + greyscale with alpha (2 channel) + ``'RGB'`` + colour image (3 channel) + ``'RGBA'`` + colour image with alpha (4 channel) + + The mode string can also specify the bit depth (overriding how this + function normally derives the bit depth, see below). Appending + ``';16'`` to the mode will cause the PNG to be 16 bits per channel; + any decimal from 1 to 16 can be used to specify the bit depth. + + When a 2-dimensional array is used *mode* determines how many + channels the image has, and so allows the width to be derived from + the second array dimension. + + The array is expected to be a ``numpy`` array, but it can be any + suitable Python sequence. For example, a list of lists can be used: + ``png.from_array([[0, 255, 0], [255, 0, 255]], 'L')``. The exact + rules are: ``len(a)`` gives the first dimension, height; + ``len(a[0])`` gives the second dimension; ``len(a[0][0])`` gives the + third dimension, unless an exception is raised in which case a + 2-dimensional array is assumed. It's slightly more complicated than + that because an iterator of rows can be used, and it all still + works. Using an iterator allows data to be streamed efficiently. + + The bit depth of the PNG is normally taken from the array element's + datatype (but if *mode* specifies a bitdepth then that is used + instead). The array element's datatype is determined in a way which + is supposed to work both for ``numpy`` arrays and for Python + ``array.array`` objects. A 1 byte datatype will give a bit depth of + 8, a 2 byte datatype will give a bit depth of 16. If the datatype + does not have an implicit size, for example it is a plain Python + list of lists, as above, then a default of 8 is used. + + The *info* parameter is a dictionary that can be used to specify + metadata (in the same style as the arguments to the + :class:``png.Writer`` class). For this function the keys that are + useful are: + + height + overrides the height derived from the array dimensions and allows + *a* to be an iterable. + width + overrides the width derived from the array dimensions. + bitdepth + overrides the bit depth derived from the element datatype (but + must match *mode* if that also specifies a bit depth). + + Generally anything specified in the + *info* dictionary will override any implicit choices that this + function would otherwise make, but must match any explicit ones. + For example, if the *info* dictionary has a ``greyscale`` key then + this must be true when mode is ``'L'`` or ``'LA'`` and false when + mode is ``'RGB'`` or ``'RGBA'``. + """ + + # We abuse the *info* parameter by modifying it. Take a copy here. + # (Also typechecks *info* to some extent). + info = dict(info) + + # Syntax check mode string. + bitdepth = None + try: + mode = mode.split(";") + if len(mode) not in (1, 2): + raise Error() + if mode[0] not in ("L", "LA", "RGB", "RGBA"): + raise Error() + if len(mode) == 2: + try: + bitdepth = int(mode[1]) + except: + raise Error() + except Error: + raise Error("mode string should be 'RGB' or 'L;16' or similar.") + mode = mode[0] + + # Get bitdepth from *mode* if possible. + if bitdepth: + if info.get("bitdepth") and bitdepth != info["bitdepth"]: + raise Error( + "mode bitdepth (%d) should match info bitdepth (%d)." + % (bitdepth, info["bitdepth"]) + ) + info["bitdepth"] = bitdepth + + # Fill in and/or check entries in *info*. + # Dimensions. + if "size" in info: + # Check width, height, size all match where used. + for dimension, axis in [("width", 0), ("height", 1)]: + if dimension in info: + if info[dimension] != info["size"][axis]: + raise Error( + "info[%r] should match info['size'][%r]." % (dimension, axis) + ) + info["width"], info["height"] = info["size"] + if "height" not in info: + try: + l = len(a) + except: + raise Error("len(a) does not work, supply info['height'] instead.") + info["height"] = l + # Colour format. + if "greyscale" in info: + if bool(info["greyscale"]) != ("L" in mode): + raise Error("info['greyscale'] should match mode.") + info["greyscale"] = "L" in mode + if "alpha" in info: + if bool(info["alpha"]) != ("A" in mode): + raise Error("info['alpha'] should match mode.") + info["alpha"] = "A" in mode + + planes = len(mode) + if "planes" in info: + if info["planes"] != planes: + raise Error("info['planes'] should match mode.") + + # In order to work out whether we the array is 2D or 3D we need its + # first row, which requires that we take a copy of its iterator. + # We may also need the first row to derive width and bitdepth. + a, t = itertools.tee(a) + row = next(t) + del t + try: + row[0][0] + threed = True + testelement = row[0] + except: + threed = False + testelement = row + if "width" not in info: + if threed: + width = len(row) + else: + width = len(row) // planes + info["width"] = width + + # Not implemented yet + assert not threed + + if "bitdepth" not in info: + try: + dtype = testelement.dtype + # goto the "else:" clause. Sorry. + except: + try: + # Try a Python array.array. + bitdepth = 8 * testelement.itemsize + except: + # We can't determine it from the array element's + # datatype, use a default of 8. + bitdepth = 8 + else: + # If we got here without exception, we now assume that + # the array is a numpy array. + if dtype.kind == "b": + bitdepth = 1 + else: + bitdepth = 8 * dtype.itemsize + info["bitdepth"] = bitdepth + + for thing in "width height bitdepth greyscale alpha".split(): + assert thing in info + return Image(a, info) + + +# So that refugee's from PIL feel more at home. Not documented. +fromarray = from_array + + +class Image: + """A PNG image. + You can create an :class:`Image` object from an array of pixels by calling + :meth:`png.from_array`. It can be saved to disk with the + :meth:`save` method.""" + + def __init__(self, rows, info): + """ + .. note :: + + The constructor is not public. Please do not call it. + """ + + self.rows = rows + self.info = info + + def save(self, file): + """Save the image to *file*. If *file* looks like an open file + descriptor then it is used, otherwise it is treated as a + filename and a fresh file is opened. + + In general, you can only call this method once; after it has + been called the first time and the PNG image has been saved, the + source data will have been streamed, and cannot be streamed + again. + """ + + w = Writer(**self.info) + + try: + file.write + + def close(): + pass + + except: + file = open(file, "wb") + + def close(): + file.close() + + try: + w.write(file, self.rows) + finally: + close() + + +class _readable: + """ + A simple file-like interface for strings and arrays. + """ + + def __init__(self, buf): + self.buf = buf + self.offset = 0 + + def read(self, n): + r = self.buf[self.offset : self.offset + n] + if isarray(r): + r = tostring(r) + self.offset += n + return r + + +class Reader: + """ + PNG decoder in pure Python. + """ + + def __init__(self, _guess=None, **kw): + """ + Create a PNG decoder object. + + The constructor expects exactly one keyword argument. If you + supply a positional argument instead, it will guess the input + type. You can choose among the following keyword arguments: + + filename + Name of input file (a PNG file). + file + A file-like object (object with a read() method). + bytes + ``array`` or ``string`` with PNG data. + + """ + if (_guess is not None and len(kw) != 0) or (_guess is None and len(kw) != 1): + raise TypeError("Reader() takes exactly 1 argument") + + # Will be the first 8 bytes, later on. See validate_signature. + self.signature = None + self.transparent = None + # A pair of (len,type) if a chunk has been read but its data and + # checksum have not (in other words the file position is just + # past the 4 bytes that specify the chunk type). See preamble + # method for how this is used. + self.atchunk = None + + if _guess is not None: + if isarray(_guess): + kw["bytes"] = _guess + elif isinstance(_guess, str): + kw["filename"] = _guess + elif isinstance(_guess, file): + kw["file"] = _guess + + if "filename" in kw: + self.file = open(kw["filename"], "rb") + elif "file" in kw: + self.file = kw["file"] + elif "bytes" in kw: + self.file = _readable(kw["bytes"]) + else: + raise TypeError("expecting filename, file or bytes array") + + def chunk(self, seek=None): + """ + Read the next PNG chunk from the input file; returns a + (*type*,*data*) tuple. *type* is the chunk's type as a string + (all PNG chunk types are 4 characters long). *data* is the + chunk's data content, as a string. + + If the optional `seek` argument is + specified then it will keep reading chunks until it either runs + out of file or finds the type specified by the argument. Note + that in general the order of chunks in PNGs is unspecified, so + using `seek` can cause you to miss chunks. + """ + + self.validate_signature() + + while True: + # http://www.w3.org/TR/PNG/#5Chunk-layout + if not self.atchunk: + self.atchunk = self.chunklentype() + length, type = self.atchunk + self.atchunk = None + data = self.file.read(length) + if len(data) != length: + raise ChunkError( + "Chunk %s too short for required %i octets." % (type, length) + ) + checksum = self.file.read(4) + if len(checksum) != 4: + raise ValueError("Chunk %s too short for checksum.", tag) + if seek and type != seek: + continue + verify = zlib.crc32(strtobytes(type)) + verify = zlib.crc32(data, verify) + # Whether the output from zlib.crc32 is signed or not varies + # according to hideous implementation details, see + # http://bugs.python.org/issue1202 . + # We coerce it to be positive here (in a way which works on + # Python 2.3 and older). + verify &= 2 ** 32 - 1 + verify = struct.pack("!I", verify) + if checksum != verify: + # print repr(checksum) + (a,) = struct.unpack("!I", checksum) + (b,) = struct.unpack("!I", verify) + raise ChunkError( + "Checksum error in %s chunk: 0x%08X != 0x%08X." % (type, a, b) + ) + return type, data + + def chunks(self): + """Return an iterator that will yield each chunk as a + (*chunktype*, *content*) pair. + """ + + while True: + t, v = self.chunk() + yield t, v + if t == "IEND": + break + + def undo_filter(self, filter_type, scanline, previous): + """Undo the filter for a scanline. `scanline` is a sequence of + bytes that does not include the initial filter type byte. + `previous` is decoded previous scanline (for straightlaced + images this is the previous pixel row, but for interlaced + images, it is the previous scanline in the reduced image, which + in general is not the previous pixel row in the final image). + When there is no previous scanline (the first row of a + straightlaced image, or the first row in one of the passes in an + interlaced image), then this argument should be ``None``. + + The scanline will have the effects of filtering removed, and the + result will be returned as a fresh sequence of bytes. + """ + + # :todo: Would it be better to update scanline in place? + + # Create the result byte array. It seems that the best way to + # create the array to be the right size is to copy from an + # existing sequence. *sigh* + # If we fill the result with scanline, then this allows a + # micro-optimisation in the "null" and "sub" cases. + result = array("B", scanline) + + if filter_type == 0: + # And here, we _rely_ on filling the result with scanline, + # above. + return result + + if filter_type not in (1, 2, 3, 4): + raise FormatError( + "Invalid PNG Filter Type." + " See http://www.w3.org/TR/2003/REC-PNG-20031110/#9Filters ." + ) + + # Filter unit. The stride from one pixel to the corresponding + # byte from the previous previous. Normally this is the pixel + # size in bytes, but when this is smaller than 1, the previous + # byte is used instead. + fu = max(1, self.psize) + + # For the first line of a pass, synthesize a dummy previous + # line. An alternative approach would be to observe that on the + # first line 'up' is the same as 'null', 'paeth' is the same + # as 'sub', with only 'average' requiring any special case. + if not previous: + previous = array("B", [0] * len(scanline)) + + def sub(): + """Undo sub filter.""" + + ai = 0 + # Loops starts at index fu. Observe that the initial part + # of the result is already filled in correctly with + # scanline. + for i in range(fu, len(result)): + x = scanline[i] + a = result[ai] + result[i] = (x + a) & 0xFF + ai += 1 + + def up(): + """Undo up filter.""" + for i in range(len(result)): # pylint: disable=consider-using-enumerate + x = scanline[i] + b = previous[i] + result[i] = (x + b) & 0xFF + + def average(): + """Undo average filter.""" + + ai = -fu + for i in range(len(result)): # pylint: disable=consider-using-enumerate + x = scanline[i] + if ai < 0: + a = 0 + else: + a = result[ai] + b = previous[i] + result[i] = (x + ((a + b) >> 1)) & 0xFF + ai += 1 + + def paeth(): + """Undo Paeth filter.""" + + # Also used for ci. + ai = -fu + for i in range(len(result)): # pylint: disable=consider-using-enumerate + x = scanline[i] + if ai < 0: + a = c = 0 + else: + a = result[ai] + c = previous[ai] + b = previous[i] + p = a + b - c + pa = abs(p - a) + pb = abs(p - b) + pc = abs(p - c) + if pa <= pb and pa <= pc: + pr = a + elif pb <= pc: + pr = b + else: + pr = c + result[i] = (x + pr) & 0xFF + ai += 1 + + # Call appropriate filter algorithm. Note that 0 has already + # been dealt with. + (None, sub, up, average, paeth)[filter_type]() + return result + + def deinterlace(self, raw): + """ + Read raw pixel data, undo filters, deinterlace, and flatten. + Return in flat row flat pixel format. + """ + + # print >> sys.stderr, ("Reading interlaced, w=%s, r=%s, planes=%s," + + # " bpp=%s") % (self.width, self.height, self.planes, self.bps) + # Values per row (of the target image) + vpr = self.width * self.planes + + # Make a result array, and make it big enough. Interleaving + # writes to the output array randomly (well, not quite), so the + # entire output array must be in memory. + fmt = "BH"[self.bitdepth > 8] + a = array(fmt, [0] * vpr * self.height) + source_offset = 0 + + for xstart, ystart, xstep, ystep in _adam7: + # print >> sys.stderr, "Adam7: start=%s,%s step=%s,%s" % ( + # xstart, ystart, xstep, ystep) + if xstart >= self.width: + continue + # The previous (reconstructed) scanline. None at the + # beginning of a pass to indicate that there is no previous + # line. + recon = None + # Pixels per row (reduced pass image) + ppr = int(math.ceil((self.width - xstart) / float(xstep))) + # Row size in bytes for this pass. + row_size = int(math.ceil(self.psize * ppr)) + for y in range(ystart, self.height, ystep): + filter_type = raw[source_offset] + source_offset += 1 + scanline = raw[source_offset : source_offset + row_size] + source_offset += row_size + recon = self.undo_filter(filter_type, scanline, recon) + # Convert so that there is one element per pixel value + flat = self.serialtoflat(recon, ppr) + if xstep == 1: + assert xstart == 0 + offset = y * vpr + a[offset : offset + vpr] = flat + else: + offset = y * vpr + xstart * self.planes + end_offset = (y + 1) * vpr + skip = self.planes * xstep + for i in range(self.planes): + a[offset + i : end_offset : skip] = flat[i :: self.planes] + return a + + def iterboxed(self, rows): + """Iterator that yields each scanline in boxed row flat pixel + format. `rows` should be an iterator that yields the bytes of + each row in turn. + """ + + def asvalues(raw): + """Convert a row of raw bytes into a flat row. Result may + or may not share with argument""" + + if self.bitdepth == 8: + return raw + if self.bitdepth == 16: + raw = tostring(raw) + return array("H", struct.unpack("!%dH" % (len(raw) // 2), raw)) + assert self.bitdepth < 8 + width = self.width + # Samples per byte + spb = 8 // self.bitdepth + out = array("B") + mask = 2 ** self.bitdepth - 1 + shifts = map(self.bitdepth.__mul__, reversed(range(spb))) + for o in raw: + out.extend(map(lambda i: mask & (o >> i), shifts)) + return out[:width] + + return map(asvalues, rows) + + def serialtoflat(self, bytes, width=None): + """Convert serial format (byte stream) pixel data to flat row + flat pixel. + """ + + if self.bitdepth == 8: + return bytes + if self.bitdepth == 16: + bytes = tostring(bytes) + return array("H", struct.unpack("!%dH" % (len(bytes) // 2), bytes)) + assert self.bitdepth < 8 + if width is None: + width = self.width + # Samples per byte + spb = 8 // self.bitdepth + out = array("B") + mask = 2 ** self.bitdepth - 1 + shifts = map(self.bitdepth.__mul__, reversed(range(spb))) + l = width + for o in bytes: + out.extend([(mask & (o >> s)) for s in shifts][:l]) + l -= spb + if l <= 0: + l = width + return out + + def iterstraight(self, raw): + """Iterator that undoes the effect of filtering, and yields each + row in serialised format (as a sequence of bytes). Assumes input + is straightlaced. `raw` should be an iterable that yields the + raw bytes in chunks of arbitrary size.""" + + # length of row, in bytes + rb = self.row_bytes + a = array("B") + # The previous (reconstructed) scanline. None indicates first + # line of image. + recon = None + for some in raw: + a.extend(some) + while len(a) >= rb + 1: + filter_type = a[0] + scanline = a[1 : rb + 1] + del a[: rb + 1] + recon = self.undo_filter(filter_type, scanline, recon) + yield recon + if len(a) != 0: + # :file:format We get here with a file format error: when the + # available bytes (after decompressing) do not pack into exact + # rows. + raise FormatError("Wrong size for decompressed IDAT chunk.") + assert len(a) == 0 + + def validate_signature(self): + """If signature (header) has not been read then read and + validate it; otherwise do nothing. + """ + + if self.signature: + return + self.signature = self.file.read(8) + if self.signature != _signature: + raise FormatError("PNG file has invalid signature.") + + def preamble(self): + """ + Extract the image metadata by reading the initial part of the PNG + file up to the start of the ``IDAT`` chunk. All the chunks that + precede the ``IDAT`` chunk are read and either processed for + metadata or discarded. + """ + + self.validate_signature() + + while True: + if not self.atchunk: + self.atchunk = self.chunklentype() + if self.atchunk is None: + raise FormatError("This PNG file has no IDAT chunks.") + if self.atchunk[1] == "IDAT": + return + self.process_chunk() + + def chunklentype(self): + """Reads just enough of the input to determine the next + chunk's length and type, returned as a (*length*, *type*) pair + where *type* is a string. If there are no more chunks, ``None`` + is returned. + """ + + x = self.file.read(8) + if not x: + return None + if len(x) != 8: + raise FormatError("End of file whilst reading chunk length and type.") + length, type = struct.unpack("!I4s", x) + type = bytestostr(type) + if length > 2 ** 31 - 1: + raise FormatError("Chunk %s is too large: %d." % (type, length)) + return length, type + + def process_chunk(self): + """Process the next chunk and its data. This only processes the + following chunk types, all others are ignored: ``IHDR``, + ``PLTE``, ``bKGD``, ``tRNS``, ``gAMA``, ``sBIT``. + """ + + type, data = self.chunk() + if type == "IHDR": + # http://www.w3.org/TR/PNG/#11IHDR + if len(data) != 13: + raise FormatError("IHDR chunk has incorrect length.") + ( + self.width, + self.height, + self.bitdepth, + self.color_type, + self.compression, + self.filter, + self.interlace, + ) = struct.unpack("!2I5B", data) + + # Check that the header specifies only valid combinations. + if self.bitdepth not in (1, 2, 4, 8, 16): + raise Error("invalid bit depth %d" % self.bitdepth) + if self.color_type not in (0, 2, 3, 4, 6): + raise Error("invalid colour type %d" % self.color_type) + # Check indexed (palettized) images have 8 or fewer bits + # per pixel; check only indexed or greyscale images have + # fewer than 8 bits per pixel. + if (self.color_type & 1 and self.bitdepth > 8) or ( + self.bitdepth < 8 and self.color_type not in (0, 3) + ): + raise FormatError( + "Illegal combination of bit depth (%d)" + " and colour type (%d)." + " See http://www.w3.org/TR/2003/REC-PNG-20031110/#table111 ." + % (self.bitdepth, self.color_type) + ) + if self.compression != 0: + raise Error("unknown compression method %d" % self.compression) + if self.filter != 0: + raise FormatError( + "Unknown filter method %d," + " see http://www.w3.org/TR/2003/REC-PNG-20031110/#9Filters ." + % self.filter + ) + if self.interlace not in (0, 1): + raise FormatError( + "Unknown interlace method %d," + " see http://www.w3.org/TR/2003/REC-PNG-20031110/#8InterlaceMethods ." + % self.interlace + ) + + # Derived values + # http://www.w3.org/TR/PNG/#6Colour-values + colormap = bool(self.color_type & 1) + greyscale = not (self.color_type & 2) + alpha = bool(self.color_type & 4) + color_planes = (3, 1)[greyscale or colormap] + planes = color_planes + alpha + + self.colormap = colormap + self.greyscale = greyscale + self.alpha = alpha + self.color_planes = color_planes + self.planes = planes + self.psize = float(self.bitdepth) / float(8) * planes + if int(self.psize) == self.psize: + self.psize = int(self.psize) + self.row_bytes = int(math.ceil(self.width * self.psize)) + # Stores PLTE chunk if present, and is used to check + # chunk ordering constraints. + self.plte = None + # Stores tRNS chunk if present, and is used to check chunk + # ordering constraints. + self.trns = None + # Stores sbit chunk if present. + self.sbit = None + elif type == "PLTE": + # http://www.w3.org/TR/PNG/#11PLTE + if self.plte: + warnings.warn("Multiple PLTE chunks present.") + self.plte = data + if len(data) % 3 != 0: + raise FormatError("PLTE chunk's length should be a multiple of 3.") + if len(data) > (2 ** self.bitdepth) * 3: + raise FormatError("PLTE chunk is too long.") + if len(data) == 0: + raise FormatError("Empty PLTE is not allowed.") + elif type == "bKGD": + try: + if self.colormap: + if not self.plte: + warnings.warn("PLTE chunk is required before bKGD chunk.") + self.background = struct.unpack("B", data) + else: + self.background = struct.unpack("!%dH" % self.color_planes, data) + except struct.error: + raise FormatError("bKGD chunk has incorrect length.") + elif type == "tRNS": + # http://www.w3.org/TR/PNG/#11tRNS + self.trns = data + if self.colormap: + if not self.plte: + warnings.warn("PLTE chunk is required before tRNS chunk.") + else: + if len(data) > len(self.plte) / 3: + # Was warning, but promoted to Error as it + # would otherwise cause pain later on. + raise FormatError("tRNS chunk is too long.") + else: + if self.alpha: + raise FormatError( + "tRNS chunk is not valid with colour type %d." % self.color_type + ) + try: + self.transparent = struct.unpack("!%dH" % self.color_planes, data) + except struct.error: + raise FormatError("tRNS chunk has incorrect length.") + elif type == "gAMA": + try: + self.gamma = struct.unpack("!L", data)[0] / 100000.0 + except struct.error: + raise FormatError("gAMA chunk has incorrect length.") + elif type == "sBIT": + self.sbit = data + if ( + self.colormap + and len(data) != 3 + or not self.colormap + and len(data) != self.planes + ): + raise FormatError("sBIT chunk has incorrect length.") + + def read(self): + """ + Read the PNG file and decode it. Returns (`width`, `height`, + `pixels`, `metadata`). + + May use excessive memory. + + `pixels` are returned in boxed row flat pixel format. + """ + + def iteridat(): + """Iterator that yields all the ``IDAT`` chunks as strings.""" + while True: + try: + type, data = self.chunk() + except ValueError as e: + raise ChunkError(e.args[0]) + if type == "IEND": + # http://www.w3.org/TR/PNG/#11IEND + break + if type != "IDAT": + continue + # type == 'IDAT' + # http://www.w3.org/TR/PNG/#11IDAT + if self.colormap and not self.plte: + warnings.warn("PLTE chunk is required before IDAT chunk") + yield data + + def iterdecomp(idat): + """Iterator that yields decompressed strings. `idat` should + be an iterator that yields the ``IDAT`` chunk data. + """ + + # Currently, with no max_length parameter to decompress, this + # routine will do one yield per IDAT chunk. So not very + # incremental. + d = zlib.decompressobj() + # Each IDAT chunk is passed to the decompressor, then any + # remaining state is decompressed out. + for data in idat: + # :todo: add a max_length argument here to limit output + # size. + yield array("B", d.decompress(data)) + yield array("B", d.flush()) + + self.preamble() + raw = iterdecomp(iteridat()) + + if self.interlace: + raw = array("B", itertools.chain(*raw)) + arraycode = "BH"[self.bitdepth > 8] + # Like :meth:`group` but producing an array.array object for + # each row. + pixels = map( + lambda *row: array(arraycode, row), + *[iter(self.deinterlace(raw))] * self.width * self.planes + ) + else: + pixels = self.iterboxed(self.iterstraight(raw)) + meta = dict() + for attr in "greyscale alpha planes bitdepth interlace".split(): + meta[attr] = getattr(self, attr) + meta["size"] = (self.width, self.height) + for attr in "gamma transparent background".split(): + a = getattr(self, attr, None) + if a is not None: + meta[attr] = a + return self.width, self.height, pixels, meta + + def read_flat(self): + """ + Read a PNG file and decode it into flat row flat pixel format. + Returns (*width*, *height*, *pixels*, *metadata*). + + May use excessive memory. + + `pixels` are returned in flat row flat pixel format. + + See also the :meth:`read` method which returns pixels in the + more stream-friendly boxed row flat pixel format. + """ + + x, y, pixel, meta = self.read() + arraycode = "BH"[meta["bitdepth"] > 8] + pixel = array(arraycode, itertools.chain(*pixel)) + return x, y, pixel, meta + + def palette(self, alpha="natural"): + """Returns a palette that is a sequence of 3-tuples or 4-tuples, + synthesizing it from the ``PLTE`` and ``tRNS`` chunks. These + chunks should have already been processed (for example, by + calling the :meth:`preamble` method). All the tuples are the + same size: 3-tuples if there is no ``tRNS`` chunk, 4-tuples when + there is a ``tRNS`` chunk. Assumes that the image is colour type + 3 and therefore a ``PLTE`` chunk is required. + + If the `alpha` argument is ``'force'`` then an alpha channel is + always added, forcing the result to be a sequence of 4-tuples. + """ + + if not self.plte: + raise FormatError("Required PLTE chunk is missing in colour type 3 image.") + plte = group(array("B", self.plte), 3) + if self.trns or alpha == "force": + trns = array("B", self.trns or "") + trns.extend([255] * (len(plte) - len(trns))) + plte = map(operator.add, plte, group(trns, 1)) + return plte + + def asDirect(self): + """Returns the image data as a direct representation of an + ``x * y * planes`` array. This method is intended to remove the + need for callers to deal with palettes and transparency + themselves. Images with a palette (colour type 3) + are converted to RGB or RGBA; images with transparency (a + ``tRNS`` chunk) are converted to LA or RGBA as appropriate. + When returned in this format the pixel values represent the + colour value directly without needing to refer to palettes or + transparency information. + + Like the :meth:`read` method this method returns a 4-tuple: + + (*width*, *height*, *pixels*, *meta*) + + This method normally returns pixel values with the bit depth + they have in the source image, but when the source PNG has an + ``sBIT`` chunk it is inspected and can reduce the bit depth of + the result pixels; pixel values will be reduced according to + the bit depth specified in the ``sBIT`` chunk (PNG nerds should + note a single result bit depth is used for all channels; the + maximum of the ones specified in the ``sBIT`` chunk. An RGB565 + image will be rescaled to 6-bit RGB666). + + The *meta* dictionary that is returned reflects the `direct` + format and not the original source image. For example, an RGB + source image with a ``tRNS`` chunk to represent a transparent + colour, will have ``planes=3`` and ``alpha=False`` for the + source image, but the *meta* dictionary returned by this method + will have ``planes=4`` and ``alpha=True`` because an alpha + channel is synthesized and added. + + *pixels* is the pixel data in boxed row flat pixel format (just + like the :meth:`read` method). + + All the other aspects of the image data are not changed. + """ + + self.preamble() + + # Simple case, no conversion necessary. + if not self.colormap and not self.trns and not self.sbit: + return self.read() + + x, y, pixels, meta = self.read() + + if self.colormap: + meta["colormap"] = False + meta["alpha"] = bool(self.trns) + meta["bitdepth"] = 8 + meta["planes"] = 3 + bool(self.trns) + plte = self.palette() + + def iterpal(pixels): + for row in pixels: + row = map(plte.__getitem__, row) + yield array("B", itertools.chain(*row)) + + pixels = iterpal(pixels) + elif self.trns: + # It would be nice if there was some reasonable way of doing + # this without generating a whole load of intermediate tuples. + # But tuples does seem like the easiest way, with no other way + # clearly much simpler or much faster. (Actually, the L to LA + # conversion could perhaps go faster (all those 1-tuples!), but + # I still wonder whether the code proliferation is worth it) + it = self.transparent + maxval = 2 ** meta["bitdepth"] - 1 + planes = meta["planes"] + meta["alpha"] = True + meta["planes"] += 1 + typecode = "BH"[meta["bitdepth"] > 8] + + def itertrns(pixels): + for row in pixels: + # For each row we group it into pixels, then form a + # characterisation vector that says whether each pixel + # is opaque or not. Then we convert True/False to + # 0/maxval (by multiplication), and add it as the extra + # channel. + row = group(row, planes) + opa = map(it.__ne__, row) + opa = map(maxval.__mul__, opa) + opa = zip(opa) # convert to 1-tuples + yield array(typecode, itertools.chain(*map(operator.add, row, opa))) + + pixels = itertrns(pixels) + targetbitdepth = None + if self.sbit: + sbit = struct.unpack("%dB" % len(self.sbit), self.sbit) + targetbitdepth = max(sbit) + if targetbitdepth > meta["bitdepth"]: + raise Error("sBIT chunk %r exceeds bitdepth %d" % (sbit, self.bitdepth)) + if min(sbit) <= 0: + raise Error("sBIT chunk %r has a 0-entry" % sbit) + if targetbitdepth == meta["bitdepth"]: + targetbitdepth = None + if targetbitdepth: + shift = meta["bitdepth"] - targetbitdepth + meta["bitdepth"] = targetbitdepth + + def itershift(pixels): + for row in pixels: + yield map(shift.__rrshift__, row) + + pixels = itershift(pixels) + return x, y, pixels, meta + + def asFloat(self, maxval=1.0): + """Return image pixels as per :meth:`asDirect` method, but scale + all pixel values to be floating point values between 0.0 and + *maxval*. + """ + + x, y, pixels, info = self.asDirect() + sourcemaxval = 2 ** info["bitdepth"] - 1 + del info["bitdepth"] + info["maxval"] = float(maxval) + factor = float(maxval) / float(sourcemaxval) + + def iterfloat(): + for row in pixels: + yield map(factor.__mul__, row) + + return x, y, iterfloat(), info + + def _as_rescale(self, get, targetbitdepth): + """Helper used by :meth:`asRGB8` and :meth:`asRGBA8`.""" + + width, height, pixels, meta = get() + maxval = 2 ** meta["bitdepth"] - 1 + targetmaxval = 2 ** targetbitdepth - 1 + factor = float(targetmaxval) / float(maxval) + meta["bitdepth"] = targetbitdepth + + def iterscale(): + for row in pixels: + yield map(lambda x: int(round(x * factor)), row) + + return width, height, iterscale(), meta + + def asRGB8(self): + """Return the image data as an RGB pixels with 8-bits per + sample. This is like the :meth:`asRGB` method except that + this method additionally rescales the values so that they + are all between 0 and 255 (8-bit). In the case where the + source image has a bit depth < 8 the transformation preserves + all the information; where the source image has bit depth + > 8, then rescaling to 8-bit values loses precision. No + dithering is performed. Like :meth:`asRGB`, an alpha channel + in the source image will raise an exception. + + This function returns a 4-tuple: + (*width*, *height*, *pixels*, *metadata*). + *width*, *height*, *metadata* are as per the :meth:`read` method. + + *pixels* is the pixel data in boxed row flat pixel format. + """ + + return self._as_rescale(self.asRGB, 8) + + def asRGBA8(self): + """Return the image data as RGBA pixels with 8-bits per + sample. This method is similar to :meth:`asRGB8` and + :meth:`asRGBA`: The result pixels have an alpha channel, *and* + values are rescaled to the range 0 to 255. The alpha channel is + synthesized if necessary (with a small speed penalty). + """ + + return self._as_rescale(self.asRGBA, 8) + + def asRGB(self): + """Return image as RGB pixels. RGB colour images are passed + through unchanged; greyscales are expanded into RGB + triplets (there is a small speed overhead for doing this). + + An alpha channel in the source image will raise an + exception. + + The return values are as for the :meth:`read` method + except that the *metadata* reflect the returned pixels, not the + source image. In particular, for this method + ``metadata['greyscale']`` will be ``False``. + """ + + width, height, pixels, meta = self.asDirect() + if meta["alpha"]: + raise Error("will not convert image with alpha channel to RGB") + if not meta["greyscale"]: + return width, height, pixels, meta + meta["greyscale"] = False + typecode = "BH"[meta["bitdepth"] > 8] + + def iterrgb(): + for row in pixels: + a = array(typecode, [0]) * 3 * width + for i in range(3): + a[i::3] = row + yield a + + return width, height, iterrgb(), meta + + def asRGBA(self): + """Return image as RGBA pixels. Greyscales are expanded into + RGB triplets; an alpha channel is synthesized if necessary. + The return values are as for the :meth:`read` method + except that the *metadata* reflect the returned pixels, not the + source image. In particular, for this method + ``metadata['greyscale']`` will be ``False``, and + ``metadata['alpha']`` will be ``True``. + """ + + width, height, pixels, meta = self.asDirect() + if meta["alpha"] and not meta["greyscale"]: + return width, height, pixels, meta + typecode = "BH"[meta["bitdepth"] > 8] + maxval = 2 ** meta["bitdepth"] - 1 + + def newarray(): + return array(typecode, [0]) * 4 * width + + if meta["alpha"] and meta["greyscale"]: + # LA to RGBA + def convert(): + for row in pixels: + # Create a fresh target row, then copy L channel + # into first three target channels, and A channel + # into fourth channel. + a = newarray() + for i in range(3): + a[i::4] = row[0::2] + a[3::4] = row[1::2] + yield a + + elif meta["greyscale"]: + # L to RGBA + def convert(): + for row in pixels: + a = newarray() + for i in range(3): + a[i::4] = row + a[3::4] = array(typecode, [maxval]) * width + yield a + + else: + assert not meta["alpha"] and not meta["greyscale"] + # RGB to RGBA + def convert(): + for row in pixels: + a = newarray() + for i in range(3): + a[i::4] = row[i::3] + a[3::4] = array(typecode, [maxval]) * width + yield a + + meta["alpha"] = True + meta["greyscale"] = False + return width, height, convert(), meta + + +# === Internal Test Support === + +# This section comprises the tests that are internally validated (as +# opposed to tests which produce output files that are externally +# validated). Primarily they are unittests. + +# Note that it is difficult to internally validate the results of +# writing a PNG file. The only thing we can do is read it back in +# again, which merely checks consistency, not that the PNG file we +# produce is valid. + +# Run the tests from the command line: +# python -c 'import png;png.test()' + +# (For an in-memory binary file IO object) We use BytesIO where +# available, otherwise we use StringIO, but name it BytesIO. +try: + from io import BytesIO +except: + from StringIO import StringIO as BytesIO +import tempfile +import unittest + + +def test(): + unittest.main(__name__) + + +def topngbytes(name, rows, x, y, **k): + """Convenience function for creating a PNG file "in memory" as a + string. Creates a :class:`Writer` instance using the keyword arguments, + then passes `rows` to its :meth:`Writer.write` method. The resulting + PNG file is returned as a string. `name` is used to identify the file for + debugging. + """ + + import os + + print(name) + f = BytesIO() + w = Writer(x, y, **k) + w.write(f, rows) + if os.environ.get("PYPNG_TEST_TMP"): + w = open(name, "wb") + w.write(f.getvalue()) + w.close() + return f.getvalue() + + +def testWithIO(inp, out, f): + """Calls the function `f` with ``sys.stdin`` changed to `inp` + and ``sys.stdout`` changed to `out`. They are restored when `f` + returns. This function returns whatever `f` returns. + """ + + import os + + try: + oldin, sys.stdin = sys.stdin, inp + oldout, sys.stdout = sys.stdout, out + x = f() + finally: + sys.stdin = oldin + sys.stdout = oldout + if os.environ.get("PYPNG_TEST_TMP") and hasattr(out, "getvalue"): + name = mycallersname() + if name: + w = open(name + ".png", "wb") + w.write(out.getvalue()) + w.close() + return x + + +def mycallersname(): + """Returns the name of the caller of the caller of this function + (hence the name of the caller of the function in which + "mycallersname()" textually appears). Returns None if this cannot + be determined.""" + + # http://docs.python.org/library/inspect.html#the-interpreter-stack + import inspect + + frame = inspect.currentframe() + if not frame: + return None + frame_, filename_, lineno_, funname, linelist_, listi_ = inspect.getouterframes( + frame + )[2] + return funname + + +def seqtobytes(s): + """Convert a sequence of integers to a *bytes* instance. Good for + plastering over Python 2 / Python 3 cracks. + """ + + return strtobytes("".join(chr(x) for x in s)) + + +class Test(unittest.TestCase): + # This member is used by the superclass. If we don't define a new + # class here then when we use self.assertRaises() and the PyPNG code + # raises an assertion then we get no proper traceback. I can't work + # out why, but defining a new class here means we get a proper + # traceback. + class failureException(Exception): + pass + + def helperLN(self, n): + mask = (1 << n) - 1 + # Use small chunk_limit so that multiple chunk writing is + # tested. Making it a test for Issue 20. + w = Writer(15, 17, greyscale=True, bitdepth=n, chunk_limit=99) + f = BytesIO() + w.write_array(f, array("B", map(mask.__and__, range(1, 256)))) + r = Reader(bytes=f.getvalue()) + x, y, pixels, meta = r.read() + self.assertEqual(x, 15) + self.assertEqual(y, 17) + self.assertEqual( + list(itertools.chain(*pixels)), map(mask.__and__, range(1, 256)) + ) + + def testL8(self): + return self.helperLN(8) + + def testL4(self): + return self.helperLN(4) + + def testL2(self): + "Also tests asRGB8." + w = Writer(1, 4, greyscale=True, bitdepth=2) + f = BytesIO() + w.write_array(f, array("B", range(4))) + r = Reader(bytes=f.getvalue()) + x, y, pixels, meta = r.asRGB8() + self.assertEqual(x, 1) + self.assertEqual(y, 4) + for i, row in enumerate(pixels): + self.assertEqual(len(row), 3) + self.assertEqual(list(row), [0x55 * i] * 3) + + def testP2(self): + "2-bit palette." + a = (255, 255, 255) + b = (200, 120, 120) + c = (50, 99, 50) + w = Writer(1, 4, bitdepth=2, palette=[a, b, c]) + f = BytesIO() + w.write_array(f, array("B", (0, 1, 1, 2))) + r = Reader(bytes=f.getvalue()) + x, y, pixels, meta = r.asRGB8() + self.assertEqual(x, 1) + self.assertEqual(y, 4) + self.assertEqual(list(pixels), map(list, [a, b, b, c])) + + def testPtrns(self): + "Test colour type 3 and tRNS chunk (and 4-bit palette)." + a = (50, 99, 50, 50) + b = (200, 120, 120, 80) + c = (255, 255, 255) + d = (200, 120, 120) + e = (50, 99, 50) + w = Writer(3, 3, bitdepth=4, palette=[a, b, c, d, e]) + f = BytesIO() + w.write_array(f, array("B", (4, 3, 2, 3, 2, 0, 2, 0, 1))) + r = Reader(bytes=f.getvalue()) + x, y, pixels, meta = r.asRGBA8() + self.assertEqual(x, 3) + self.assertEqual(y, 3) + c = c + (255,) + d = d + (255,) + e = e + (255,) + boxed = [(e, d, c), (d, c, a), (c, a, b)] + flat = map(lambda row: itertools.chain(*row), boxed) + self.assertEqual(map(list, pixels), map(list, flat)) + + def testRGBtoRGBA(self): + "asRGBA8() on colour type 2 source." "" + # Test for Issue 26 + r = Reader(bytes=_pngsuite["basn2c08"]) + x, y, pixels, meta = r.asRGBA8() + # Test the pixels at row 9 columns 0 and 1. + row9 = list(pixels)[9] + self.assertEqual(row9[0:8], [0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xDE, 0xFF, 0xFF]) + + def testLtoRGBA(self): + "asRGBA() on grey source." "" + # Test for Issue 60 + r = Reader(bytes=_pngsuite["basi0g08"]) + x, y, pixels, meta = r.asRGBA() + row9 = list(list(pixels)[9]) + self.assertEqual(row9[0:8], [222, 222, 222, 255, 221, 221, 221, 255]) + + def testCtrns(self): + "Test colour type 2 and tRNS chunk." + # Test for Issue 25 + r = Reader(bytes=_pngsuite["tbrn2c08"]) + x, y, pixels, meta = r.asRGBA8() + # I just happen to know that the first pixel is transparent. + # In particular it should be #7f7f7f00 + row0 = list(pixels)[0] + self.assertEqual(tuple(row0[0:4]), (0x7F, 0x7F, 0x7F, 0x00)) + + def testAdam7read(self): + """Adam7 interlace reading. + Specifically, test that for images in the PngSuite that + have both an interlaced and straightlaced pair that both + images from the pair produce the same array of pixels.""" + for candidate in _pngsuite: + if not candidate.startswith("basn"): + continue + candi = candidate.replace("n", "i") + if candi not in _pngsuite: + continue + print("adam7 read %s" % (candidate,)) + straight = Reader(bytes=_pngsuite[candidate]) + adam7 = Reader(bytes=_pngsuite[candi]) + # Just compare the pixels. Ignore x,y (because they're + # likely to be correct?); metadata is ignored because the + # "interlace" member differs. Lame. + straight = straight.read()[2] + adam7 = adam7.read()[2] + self.assertEqual(map(list, straight), map(list, adam7)) + + def testAdam7write(self): + """Adam7 interlace writing. + For each test image in the PngSuite, write an interlaced + and a straightlaced version. Decode both, and compare results. + """ + # Not such a great test, because the only way we can check what + # we have written is to read it back again. + + for name, bytes in _pngsuite.items(): + # Only certain colour types supported for this test. + if name[3:5] not in ["n0", "n2", "n4", "n6"]: + continue + it = Reader(bytes=bytes) + x, y, pixels, meta = it.read() + pngi = topngbytes( + "adam7wn" + name + ".png", + pixels, + x=x, + y=y, + bitdepth=it.bitdepth, + greyscale=it.greyscale, + alpha=it.alpha, + transparent=it.transparent, + interlace=False, + ) + x, y, ps, meta = Reader(bytes=pngi).read() + it = Reader(bytes=bytes) + x, y, pixels, meta = it.read() + pngs = topngbytes( + "adam7wi" + name + ".png", + pixels, + x=x, + y=y, + bitdepth=it.bitdepth, + greyscale=it.greyscale, + alpha=it.alpha, + transparent=it.transparent, + interlace=True, + ) + x, y, pi, meta = Reader(bytes=pngs).read() + self.assertEqual(map(list, ps), map(list, pi)) + + def testPGMin(self): + """Test that the command line tool can read PGM files.""" + + def do(): + return _main(["testPGMin"]) + + s = BytesIO() + s.write(strtobytes("P5 2 2 3\n")) + s.write(strtobytes("\x00\x01\x02\x03")) + s.flush() + s.seek(0) + o = BytesIO() + testWithIO(s, o, do) + r = Reader(bytes=o.getvalue()) + x, y, pixels, meta = r.read() + self.assertTrue(r.greyscale) + self.assertEqual(r.bitdepth, 2) + + def testPAMin(self): + """Test that the command line tool can read PAM file.""" + + def do(): + return _main(["testPAMin"]) + + s = BytesIO() + s.write( + strtobytes( + "P7\nWIDTH 3\nHEIGHT 1\nDEPTH 4\nMAXVAL 255\n" + "TUPLTYPE RGB_ALPHA\nENDHDR\n" + ) + ) + # The pixels in flat row flat pixel format + flat = [255, 0, 0, 255, 0, 255, 0, 120, 0, 0, 255, 30] + asbytes = seqtobytes(flat) + s.write(asbytes) + s.flush() + s.seek(0) + o = BytesIO() + testWithIO(s, o, do) + r = Reader(bytes=o.getvalue()) + x, y, pixels, meta = r.read() + self.assertTrue(r.alpha) + self.assertTrue(not r.greyscale) + self.assertEqual(list(itertools.chain(*pixels)), flat) + + def testLA4(self): + """Create an LA image with bitdepth 4.""" + bytes = topngbytes( + "la4.png", [[5, 12]], 1, 1, greyscale=True, alpha=True, bitdepth=4 + ) + sbit = Reader(bytes=bytes).chunk("sBIT")[1] + self.assertEqual(sbit, strtobytes("\x04\x04")) + + def testPNMsbit(self): + """Test that PNM files can generates sBIT chunk.""" + + def do(): + return _main(["testPNMsbit"]) + + s = BytesIO() + s.write(strtobytes("P6 8 1 1\n")) + for pixel in range(8): + s.write(struct.pack(" 255: + a = array("H") + else: + a = array("B") + fw = float(width) + fh = float(height) + pfun = test_patterns[pattern] + for y in range(height): + fy = float(y) / fh + for x in range(width): + a.append(int(round(pfun(float(x) / fw, fy) * maxval))) + return a + + def test_rgba(size=256, bitdepth=8, red="GTB", green="GLR", blue="RTL", alpha=None): + """ + Create a test image. Each channel is generated from the + specified pattern; any channel apart from red can be set to + None, which will cause it not to be in the image. It + is possible to create all PNG channel types (L, RGB, LA, RGBA), + as well as non PNG channel types (RGA, and so on). + """ + + i = test_pattern(size, size, bitdepth, red) + psize = 1 + for channel in (green, blue, alpha): + if channel: + c = test_pattern(size, size, bitdepth, channel) + i = interleave_planes(i, c, psize, 1) + psize += 1 + return i + + def pngsuite_image(name): + """ + Create a test image by reading an internal copy of the files + from the PngSuite. Returned in flat row flat pixel format. + """ + + if name not in _pngsuite: + raise NotImplementedError( + "cannot find PngSuite file %s (use -L for a list)" % name + ) + r = Reader(bytes=_pngsuite[name]) + w, h, pixels, meta = r.asDirect() + assert w == h + # LAn for n < 8 is a special case for which we need to rescale + # the data. + if meta["greyscale"] and meta["alpha"] and meta["bitdepth"] < 8: + factor = 255 // (2 ** meta["bitdepth"] - 1) + + def rescale(data): + for row in data: + yield map(factor.__mul__, row) + + pixels = rescale(pixels) + meta["bitdepth"] = 8 + arraycode = "BH"[meta["bitdepth"] > 8] + return w, array(arraycode, itertools.chain(*pixels)), meta + + # The body of test_suite() + size = 256 + if options.test_size: + size = options.test_size + options.bitdepth = options.test_depth + options.greyscale = bool(options.test_black) + + kwargs = {} + if options.test_red: + kwargs["red"] = options.test_red + if options.test_green: + kwargs["green"] = options.test_green + if options.test_blue: + kwargs["blue"] = options.test_blue + if options.test_alpha: + kwargs["alpha"] = options.test_alpha + if options.greyscale: + if options.test_red or options.test_green or options.test_blue: + raise ValueError( + "cannot specify colours (R, G, B) when greyscale image (black channel, K) is specified" + ) + kwargs["red"] = options.test_black + kwargs["green"] = None + kwargs["blue"] = None + options.alpha = bool(options.test_alpha) + if not args: + pixels = test_rgba(size, options.bitdepth, **kwargs) + else: + size, pixels, meta = pngsuite_image(args[0]) + for k in ["bitdepth", "alpha", "greyscale"]: + setattr(options, k, meta[k]) + + writer = Writer( + size, + size, + bitdepth=options.bitdepth, + transparent=options.transparent, + background=options.background, + gamma=options.gamma, + greyscale=options.greyscale, + alpha=options.alpha, + compression=options.compression, + interlace=options.interlace, + ) + writer.write_array(sys.stdout, pixels) + + +def read_pam_header(infile): + """ + Read (the rest of a) PAM header. `infile` should be positioned + immediately after the initial 'P7' line (at the beginning of the + second line). Returns are as for `read_pnm_header`. + """ + + # Unlike PBM, PGM, and PPM, we can read the header a line at a time. + header = dict() + while True: + l = infile.readline().strip() + if l == strtobytes("ENDHDR"): + break + if not l: + raise EOFError("PAM ended prematurely") + if l[0] == strtobytes("#"): + continue + l = l.split(None, 1) + if l[0] not in header: + header[l[0]] = l[1] + else: + header[l[0]] += strtobytes(" ") + l[1] + + required = ["WIDTH", "HEIGHT", "DEPTH", "MAXVAL"] + required = [strtobytes(x) for x in required] + WIDTH, HEIGHT, DEPTH, MAXVAL = required + present = [x for x in required if x in header] + if len(present) != len(required): + raise Error("PAM file must specify WIDTH, HEIGHT, DEPTH, and MAXVAL") + width = int(header[WIDTH]) + height = int(header[HEIGHT]) + depth = int(header[DEPTH]) + maxval = int(header[MAXVAL]) + if width <= 0 or height <= 0 or depth <= 0 or maxval <= 0: + raise Error("WIDTH, HEIGHT, DEPTH, MAXVAL must all be positive integers") + return "P7", width, height, depth, maxval + + +def read_pnm_header(infile, supported=("P5", "P6")): + """ + Read a PNM header, returning (format,width,height,depth,maxval). + `width` and `height` are in pixels. `depth` is the number of + channels in the image; for PBM and PGM it is synthesized as 1, for + PPM as 3; for PAM images it is read from the header. `maxval` is + synthesized (as 1) for PBM images. + """ + + # Generally, see http://netpbm.sourceforge.net/doc/ppm.html + # and http://netpbm.sourceforge.net/doc/pam.html + + supported = [strtobytes(x) for x in supported] + + # Technically 'P7' must be followed by a newline, so by using + # rstrip() we are being liberal in what we accept. I think this + # is acceptable. + type = infile.read(3).rstrip() + if type not in supported: + raise NotImplementedError("file format %s not supported" % type) + if type == strtobytes("P7"): + # PAM header parsing is completely different. + return read_pam_header(infile) + # Expected number of tokens in header (3 for P4, 4 for P6) + expected = 4 + pbm = ("P1", "P4") + if type in pbm: + expected = 3 + header = [type] + + # We have to read the rest of the header byte by byte because the + # final whitespace character (immediately following the MAXVAL in + # the case of P6) may not be a newline. Of course all PNM files in + # the wild use a newline at this point, so it's tempting to use + # readline; but it would be wrong. + def getc(): + c = infile.read(1) + if not c: + raise Error("premature EOF reading PNM header") + return c + + c = getc() + while True: + # Skip whitespace that precedes a token. + while c.isspace(): + c = getc() + # Skip comments. + while c == "#": + while c not in "\n\r": + c = getc() + if not c.isdigit(): + raise Error("unexpected character %s found in header" % c) + # According to the specification it is legal to have comments + # that appear in the middle of a token. + # This is bonkers; I've never seen it; and it's a bit awkward to + # code good lexers in Python (no goto). So we break on such + # cases. + token = strtobytes("") + while c.isdigit(): + token += c + c = getc() + # Slight hack. All "tokens" are decimal integers, so convert + # them here. + header.append(int(token)) + if len(header) == expected: + break + # Skip comments (again) + while c == "#": + while c not in "\n\r": + c = getc() + if not c.isspace(): + raise Error("expected header to end with whitespace, not %s" % c) + + if type in pbm: + # synthesize a MAXVAL + header.append(1) + depth = (1, 3)[type == strtobytes("P6")] + return header[0], header[1], header[2], depth, header[3] + + +def write_pnm(file, width, height, pixels, meta): + """Write a Netpbm PNM/PAM file.""" + + bitdepth = meta["bitdepth"] + maxval = 2 ** bitdepth - 1 + # Rudely, the number of image planes can be used to determine + # whether we are L (PGM), LA (PAM), RGB (PPM), or RGBA (PAM). + planes = meta["planes"] + # Can be an assert as long as we assume that pixels and meta came + # from a PNG file. + assert planes in (1, 2, 3, 4) + if planes in (1, 3): + if 1 == planes: + # PGM + # Could generate PBM if maxval is 1, but we don't (for one + # thing, we'd have to convert the data, not just blat it + # out). + fmt = "P5" + else: + # PPM + fmt = "P6" + file.write("%s %d %d %d\n" % (fmt, width, height, maxval)) + if planes in (2, 4): + # PAM + # See http://netpbm.sourceforge.net/doc/pam.html + if 2 == planes: + tupltype = "GRAYSCALE_ALPHA" + else: + tupltype = "RGB_ALPHA" + file.write( + "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\n" + "TUPLTYPE %s\nENDHDR\n" % (width, height, planes, maxval, tupltype) + ) + # Values per row + vpr = planes * width + # struct format + fmt = ">%d" % vpr + if maxval > 0xFF: + fmt = fmt + "H" + else: + fmt = fmt + "B" + for row in pixels: + file.write(struct.pack(fmt, *row)) + file.flush() + + +def color_triple(color): + """ + Convert a command line colour value to a RGB triple of integers. + FIXME: Somewhere we need support for greyscale backgrounds etc. + """ + if color.startswith("#") and len(color) == 4: + return (int(color[1], 16), int(color[2], 16), int(color[3], 16)) + if color.startswith("#") and len(color) == 7: + return (int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16)) + elif color.startswith("#") and len(color) == 13: + return (int(color[1:5], 16), int(color[5:9], 16), int(color[9:13], 16)) + + +def _main(argv): + """ + Run the PNG encoder with options from the command line. + """ + + # Parse command line arguments + from optparse import OptionParser + import re + + version = "%prog " + re.sub(r"( ?\$|URL: |Rev:)", "", __version__) + parser = OptionParser(version=version) + parser.set_usage("%prog [options] [imagefile]") + parser.add_option( + "-r", + "--read-png", + default=False, + action="store_true", + help="Read PNG, write PNM", + ) + parser.add_option( + "-i", + "--interlace", + default=False, + action="store_true", + help="create an interlaced PNG file (Adam7)", + ) + parser.add_option( + "-t", + "--transparent", + action="store", + type="string", + metavar="color", + help="mark the specified colour (#RRGGBB) as transparent", + ) + parser.add_option( + "-b", + "--background", + action="store", + type="string", + metavar="color", + help="save the specified background colour", + ) + parser.add_option( + "-a", + "--alpha", + action="store", + type="string", + metavar="pgmfile", + help="alpha channel transparency (RGBA)", + ) + parser.add_option( + "-g", + "--gamma", + action="store", + type="float", + metavar="value", + help="save the specified gamma value", + ) + parser.add_option( + "-c", + "--compression", + action="store", + type="int", + metavar="level", + help="zlib compression level (0-9)", + ) + parser.add_option( + "-T", + "--test", + default=False, + action="store_true", + help="create a test image (a named PngSuite image if an argument is supplied)", + ) + parser.add_option( + "-L", + "--list", + default=False, + action="store_true", + help="print list of named test images", + ) + parser.add_option( + "-R", + "--test-red", + action="store", + type="string", + metavar="pattern", + help="test pattern for the red image layer", + ) + parser.add_option( + "-G", + "--test-green", + action="store", + type="string", + metavar="pattern", + help="test pattern for the green image layer", + ) + parser.add_option( + "-B", + "--test-blue", + action="store", + type="string", + metavar="pattern", + help="test pattern for the blue image layer", + ) + parser.add_option( + "-A", + "--test-alpha", + action="store", + type="string", + metavar="pattern", + help="test pattern for the alpha image layer", + ) + parser.add_option( + "-K", + "--test-black", + action="store", + type="string", + metavar="pattern", + help="test pattern for greyscale image", + ) + parser.add_option( + "-d", + "--test-depth", + default=8, + action="store", + type="int", + metavar="NBITS", + help="create test PNGs that are NBITS bits per channel", + ) + parser.add_option( + "-S", + "--test-size", + action="store", + type="int", + metavar="size", + help="width and height of the test image", + ) + (options, args) = parser.parse_args(args=argv[1:]) + + # Convert options + if options.transparent is not None: + options.transparent = color_triple(options.transparent) + if options.background is not None: + options.background = color_triple(options.background) + + if options.list: + names = list(_pngsuite) + names.sort() + for name in names: + print(name) + return + + # Run regression tests + if options.test: + return test_suite(options, args) + + # Prepare input and output files + if len(args) == 0: + infilename = "-" + infile = sys.stdin + elif len(args) == 1: + infilename = args[0] + infile = open(infilename, "rb") + else: + parser.error("more than one input file") + outfile = sys.stdout + + if options.read_png: + # Encode PNG to PPM + png = Reader(file=infile) + width, height, pixels, meta = png.asDirect() + write_pnm(outfile, width, height, pixels, meta) + else: + # Encode PNM to PNG + format, width, height, depth, maxval = read_pnm_header( + infile, ("P5", "P6", "P7") + ) + # When it comes to the variety of input formats, we do something + # rather rude. Observe that L, LA, RGB, RGBA are the 4 colour + # types supported by PNG and that they correspond to 1, 2, 3, 4 + # channels respectively. So we use the number of channels in + # the source image to determine which one we have. We do not + # care about TUPLTYPE. + greyscale = depth <= 2 + pamalpha = depth in (2, 4) + supported = map(lambda x: 2 ** x - 1, range(1, 17)) + try: + mi = supported.index(maxval) + except ValueError: + raise NotImplementedError( + "your maxval (%s) not in supported list %s" % (maxval, str(supported)) + ) + bitdepth = mi + 1 + writer = Writer( + width, + height, + greyscale=greyscale, + bitdepth=bitdepth, + interlace=options.interlace, + transparent=options.transparent, + background=options.background, + alpha=bool(pamalpha or options.alpha), + gamma=options.gamma, + compression=options.compression, + ) + if options.alpha: + pgmfile = open(options.alpha, "rb") + format, awidth, aheight, adepth, amaxval = read_pnm_header(pgmfile, "P5") + if amaxval != "255": + raise NotImplementedError( + "maxval %s not supported for alpha channel" % amaxval + ) + if (awidth, aheight) != (width, height): + raise ValueError( + "alpha channel image size mismatch" + " (%s has %sx%s but %s has %sx%s)" + % (infilename, width, height, options.alpha, awidth, aheight) + ) + writer.convert_ppm_and_pgm(infile, pgmfile, outfile) + else: + writer.convert_pnm(infile, outfile) + + +if __name__ == "__main__": + try: + _main(sys.argv) + except Error as e: + sys.stderr.write("%s\n" % (e,)) diff --git a/venv/Lib/site-packages/pygame/tests/test_utils/run_tests.py b/venv/Lib/site-packages/pygame/tests/test_utils/run_tests.py new file mode 100644 index 0000000..a193e23 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/test_utils/run_tests.py @@ -0,0 +1,350 @@ +import sys + +if __name__ == "__main__": + sys.exit("This module is for import only") + +test_pkg_name = ".".join(__name__.split(".")[0:-2]) +is_pygame_pkg = test_pkg_name == "pygame.tests" +test_runner_mod = test_pkg_name + ".test_utils.test_runner" + +if is_pygame_pkg: + from pygame.tests.test_utils import import_submodule + from pygame.tests.test_utils.test_runner import ( + prepare_test_env, + run_test, + combine_results, + get_test_results, + TEST_RESULTS_START, + ) +else: + from test.test_utils import import_submodule + from test.test_utils.test_runner import ( + prepare_test_env, + run_test, + combine_results, + get_test_results, + TEST_RESULTS_START, + ) +import pygame +import pygame.threads + +import os +import re +import shutil +import tempfile +import time +import random +from pprint import pformat + +was_run = False + + +def run(*args, **kwds): + """Run the Pygame unit test suite and return (total tests run, fails dict) + + Positional arguments (optional): + The names of tests to include. If omitted then all tests are run. Test + names need not include the trailing '_test'. + + Keyword arguments: + incomplete - fail incomplete tests (default False) + usesubprocess - run all test suites in the current process + (default False, use separate subprocesses) + dump - dump failures/errors as dict ready to eval (default False) + file - if provided, the name of a file into which to dump failures/errors + timings - if provided, the number of times to run each individual test to + get an average run time (default is run each test once) + exclude - A list of TAG names to exclude from the run. The items may be + comma or space separated. + show_output - show silenced stderr/stdout on errors (default False) + all - dump all results, not just errors (default False) + randomize - randomize order of tests (default False) + seed - if provided, a seed randomizer integer + multi_thread - if provided, the number of THREADS in which to run + subprocessed tests + time_out - if subprocess is True then the time limit in seconds before + killing a test (default 30) + fake - if provided, the name of the fake tests package in the + run_tests__tests subpackage to run instead of the normal + Pygame tests + python - the path to a python executable to run subprocessed tests + (default sys.executable) + interative - allow tests tagged 'interative'. + + Return value: + A tuple of total number of tests run, dictionary of error information. The + dictionary is empty if no errors were recorded. + + By default individual test modules are run in separate subprocesses. This + recreates normal Pygame usage where pygame.init() and pygame.quit() are + called only once per program execution, and avoids unfortunate + interactions between test modules. Also, a time limit is placed on test + execution, so frozen tests are killed when there time allotment expired. + Use the single process option if threading is not working properly or if + tests are taking too long. It is not guaranteed that all tests will pass + in single process mode. + + Tests are run in a randomized order if the randomize argument is True or a + seed argument is provided. If no seed integer is provided then the system + time is used. + + Individual test modules may have a corresponding *_tags.py module, + defining a __tags__ attribute, a list of tag strings used to selectively + omit modules from a run. By default only the 'interactive', 'ignore', and + 'subprocess_ignore' tags are ignored. 'interactive' is for modules that + take user input, like cdrom_test.py. 'ignore' and 'subprocess_ignore' for + for disabling modules for foreground and subprocess modes respectively. + These are for disabling tests on optional modules or for experimental + modules with known problems. These modules can be run from the console as + a Python program. + + This function can only be called once per Python session. It is not + reentrant. + + """ + + global was_run + + if was_run: + raise RuntimeError("run() was already called this session") + was_run = True + + options = kwds.copy() + option_usesubprocess = options.get("usesubprocess", False) + option_dump = options.pop("dump", False) + option_file = options.pop("file", None) + option_randomize = options.get("randomize", False) + option_seed = options.get("seed", None) + option_multi_thread = options.pop("multi_thread", 1) + option_time_out = options.pop("time_out", 120) + option_fake = options.pop("fake", None) + option_python = options.pop("python", sys.executable) + option_exclude = options.pop("exclude", ()) + option_interactive = options.pop("interactive", False) + + if not option_interactive and "interactive" not in option_exclude: + option_exclude += ("interactive",) + if option_usesubprocess and "subprocess_ignore" not in option_exclude: + option_exclude += ("subprocess_ignore",) + elif "ignore" not in option_exclude: + option_exclude += ("ignore",) + + option_exclude += ("python3_ignore",) + option_exclude += ("SDL2_ignore",) + + main_dir, test_subdir, fake_test_subdir = prepare_test_env() + + ########################################################################### + # Compile a list of test modules. If fake, then compile list of fake + # xxxx_test.py from run_tests__tests + + TEST_MODULE_RE = re.compile(r"^(.+_test)\.py$") + + test_mods_pkg_name = test_pkg_name + + working_dir_temp = tempfile.mkdtemp() + + if option_fake is not None: + test_mods_pkg_name = ".".join( + [test_mods_pkg_name, "run_tests__tests", option_fake] + ) + test_subdir = os.path.join(fake_test_subdir, option_fake) + working_dir = test_subdir + else: + working_dir = working_dir_temp + + # Added in because some machines will need os.environ else there will be + # false failures in subprocess mode. Same issue as python2.6. Needs some + # env vars. + + test_env = os.environ + + fmt1 = "%s.%%s" % test_mods_pkg_name + fmt2 = "%s.%%s_test" % test_mods_pkg_name + if args: + test_modules = [m.endswith("_test") and (fmt1 % m) or (fmt2 % m) for m in args] + else: + test_modules = [] + for f in sorted(os.listdir(test_subdir)): + for match in TEST_MODULE_RE.findall(f): + test_modules.append(fmt1 % (match,)) + + ########################################################################### + # Remove modules to be excluded. + + tmp = test_modules + test_modules = [] + for name in tmp: + tag_module_name = "%s_tags" % (name[0:-5],) + try: + tag_module = import_submodule(tag_module_name) + except ImportError: + test_modules.append(name) + else: + try: + tags = tag_module.__tags__ + except AttributeError: + print("%s has no tags: ignoring" % (tag_module_name,)) + test_modules.append(name) + else: + for tag in tags: + if tag in option_exclude: + print("skipping %s (tag '%s')" % (name, tag)) + break + else: + test_modules.append(name) + del tmp, tag_module_name, name + + ########################################################################### + # Meta results + + results = {} + meta_results = {"__meta__": {}} + meta = meta_results["__meta__"] + + ########################################################################### + # Randomization + + if option_randomize or option_seed is not None: + if option_seed is None: + option_seed = time.time() + meta["random_seed"] = option_seed + print("\nRANDOM SEED USED: %s\n" % option_seed) + random.seed(option_seed) + random.shuffle(test_modules) + + ########################################################################### + # Single process mode + + if not option_usesubprocess: + options["exclude"] = option_exclude + t = time.time() + for module in test_modules: + results.update(run_test(module, **options)) + t = time.time() - t + + ########################################################################### + # Subprocess mode + # + + else: + if is_pygame_pkg: + from pygame.tests.test_utils.async_sub import proc_in_time_or_kill + else: + from test.test_utils.async_sub import proc_in_time_or_kill + + pass_on_args = ["--exclude", ",".join(option_exclude)] + for field in ["randomize", "incomplete", "unbuffered", "verbosity"]: + if kwds.get(field, False): + pass_on_args.append("--" + field) + + def sub_test(module): + print("loading %s" % module) + + cmd = [option_python, "-m", test_runner_mod, module] + pass_on_args + + return ( + module, + (cmd, test_env, working_dir), + proc_in_time_or_kill( + cmd, option_time_out, env=test_env, wd=working_dir + ), + ) + + if option_multi_thread > 1: + + def tmap(f, args): + return pygame.threads.tmap( + f, args, stop_on_error=False, num_workers=option_multi_thread + ) + + else: + tmap = map + + t = time.time() + + for module, cmd, (return_code, raw_return) in tmap(sub_test, test_modules): + test_file = "%s.py" % os.path.join(test_subdir, module) + cmd, test_env, working_dir = cmd + + test_results = get_test_results(raw_return) + if test_results: + results.update(test_results) + else: + results[module] = {} + + results[module].update( + dict( + return_code=return_code, + raw_return=raw_return, + cmd=cmd, + test_file=test_file, + test_env=test_env, + working_dir=working_dir, + module=module, + ) + ) + + t = time.time() - t + + ########################################################################### + # Output Results + # + + untrusty_total, combined = combine_results(results, t) + total, n_errors, n_failures = count_results(results) + + meta["total_tests"] = total + meta["combined"] = combined + meta["total_errors"] = n_errors + meta["total_failures"] = n_failures + results.update(meta_results) + + if not option_usesubprocess and total != untrusty_total: + raise AssertionError( + "Something went wrong in the Test Machinery:\n" + "total: %d != untrusty_total: %d" % (total, untrusty_total) + ) + + if not option_dump: + print(combined) + else: + print(TEST_RESULTS_START) + print(pformat(results)) + + if option_file is not None: + results_file = open(option_file, "w") + try: + results_file.write(pformat(results)) + finally: + results_file.close() + + shutil.rmtree(working_dir_temp) + + return total, n_errors + n_failures + + +def count_results(results): + total = errors = failures = 0 + for result in results.values(): + if result.get("return_code", 0): + total += 1 + errors += 1 + else: + total += result["num_tests"] + errors += result["num_errors"] + failures += result["num_failures"] + + return total, errors, failures + + +def run_and_exit(*args, **kwargs): + """Run the tests, and if there are failures, exit with a return code of 1. + + This is needed for various buildbots to recognise that the tests have + failed. + """ + total, fails = run(*args, **kwargs) + if fails: + sys.exit(1) + sys.exit(0) diff --git a/venv/Lib/site-packages/pygame/tests/test_utils/test_machinery.py b/venv/Lib/site-packages/pygame/tests/test_utils/test_machinery.py new file mode 100644 index 0000000..114c281 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/test_utils/test_machinery.py @@ -0,0 +1,89 @@ +import inspect +import random +import re +import unittest + +try: + from StringIO import StringIO +except ImportError: + from io import StringIO + +from . import import_submodule + + +class PygameTestLoader(unittest.TestLoader): + def __init__( + self, randomize_tests=False, include_incomplete=False, exclude=("interactive",) + ): + super(PygameTestLoader, self).__init__() + self.randomize_tests = randomize_tests + + if exclude is None: + self.exclude = set() + else: + self.exclude = set(exclude) + + if include_incomplete: + self.testMethodPrefix = ("test", "todo_") + + def getTestCaseNames(self, testCaseClass): + res = [] + for name in super(PygameTestLoader, self).getTestCaseNames(testCaseClass): + tags = get_tags(testCaseClass, getattr(testCaseClass, name)) + if self.exclude.isdisjoint(tags): + res.append(name) + + if self.randomize_tests: + random.shuffle(res) + + return res + + +# Exclude by tags: + +TAGS_RE = re.compile(r"\|[tT]ags:(-?[ a-zA-Z,0-9_\n]+)\|", re.M) + + +class TestTags: + def __init__(self): + self.memoized = {} + self.parent_modules = {} + + def get_parent_module(self, class_): + if class_ not in self.parent_modules: + self.parent_modules[class_] = import_submodule(class_.__module__) + return self.parent_modules[class_] + + def __call__(self, parent_class, meth): + key = (parent_class, meth.__name__) + if key not in self.memoized: + parent_module = self.get_parent_module(parent_class) + + module_tags = getattr(parent_module, "__tags__", []) + class_tags = getattr(parent_class, "__tags__", []) + + tags = TAGS_RE.search(inspect.getdoc(meth) or "") + if tags: + test_tags = [t.strip() for t in tags.group(1).split(",")] + else: + test_tags = [] + + combined = set() + for tags in (module_tags, class_tags, test_tags): + if not tags: + continue + + add = set([t for t in tags if not t.startswith("-")]) + remove = set([t[1:] for t in tags if t not in add]) + + if add: + combined.update(add) + if remove: + combined.difference_update(remove) + + self.memoized[key] = combined + + return self.memoized[key] + + +get_tags = TestTags() diff --git a/venv/Lib/site-packages/pygame/tests/test_utils/test_runner.py b/venv/Lib/site-packages/pygame/tests/test_utils/test_runner.py new file mode 100644 index 0000000..4c35221 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/test_utils/test_runner.py @@ -0,0 +1,330 @@ +import sys +import os + +if __name__ == "__main__": + pkg_dir = os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + parent_dir, pkg_name = os.path.split(pkg_dir) + is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame" + if not is_pygame_pkg: + sys.path.insert(0, parent_dir) +else: + is_pygame_pkg = __name__.startswith("pygame.tests.") + +import unittest +from .test_machinery import PygameTestLoader + +import re + +try: + import StringIO +except ImportError: + import io as StringIO + +import optparse +from pprint import pformat + + +def prepare_test_env(): + test_subdir = os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] + main_dir = os.path.split(test_subdir)[0] + sys.path.insert(0, test_subdir) + fake_test_subdir = os.path.join(test_subdir, "run_tests__tests") + return main_dir, test_subdir, fake_test_subdir + + +main_dir, test_subdir, fake_test_subdir = prepare_test_env() + +################################################################################ +# Set the command line options +# +# options are shared with run_tests.py so make sure not to conflict +# in time more will be added here + +TAG_PAT = r"-?[a-zA-Z0-9_]+" +TAG_RE = re.compile(TAG_PAT) +EXCLUDE_RE = re.compile(r"(%s,?\s*)+$" % (TAG_PAT,)) + + +def exclude_callback(option, opt, value, parser): + if EXCLUDE_RE.match(value) is None: + raise optparse.OptionValueError("%s argument has invalid value" % (opt,)) + parser.values.exclude = TAG_RE.findall(value) + + +opt_parser = optparse.OptionParser() + +opt_parser.add_option( + "-i", "--incomplete", action="store_true", help="fail incomplete tests" +) + +opt_parser.add_option( + "-s", + "--usesubprocess", + action="store_true", + help="run everything in a single process " " (default: use no subprocesses)", +) + +opt_parser.add_option( + "-e", + "--exclude", + action="callback", + type="string", + help="exclude tests containing any of TAGS", + callback=exclude_callback, +) + +opt_parser.add_option( + "-u", + "--unbuffered", + action="store_true", + help="Show stdout/stderr as tests run, rather than storing it and showing on failures", +) + +opt_parser.add_option( + "-v", + "--verbose", + dest="verbosity", + action="store_const", + const=2, + help="Verbose output", +) +opt_parser.add_option( + "-q", + "--quiet", + dest="verbosity", + action="store_const", + const=0, + help="Quiet output", +) + +opt_parser.add_option( + "-r", "--randomize", action="store_true", help="randomize order of tests" +) + +################################################################################ +# If an xxxx_test.py takes longer than TIME_OUT seconds it will be killed +# This is only the default, can be over-ridden on command line + +TIME_OUT = 30 + +# DEFAULTS + +################################################################################ +# Human readable output +# + +COMPLETE_FAILURE_TEMPLATE = """ +====================================================================== +ERROR: all_tests_for (%(module)s.AllTestCases) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "test/%(module)s.py", line 1, in all_tests_for +subprocess completely failed with return code of %(return_code)s +cmd: %(cmd)s +test_env: %(test_env)s +working_dir: %(working_dir)s +return (first 10 and last 10 lines): +%(raw_return)s + +""" # Leave that last empty line else build page regex won't match +# Text also needs to be vertically compressed + + +RAN_TESTS_DIV = (70 * "-") + "\nRan" + +DOTS = re.compile("^([FE.sux]*)$", re.MULTILINE) + + +def extract_tracebacks(output): + """from test runner output return the tracebacks.""" + verbose_mode = " ..." in output + + if verbose_mode: + if "ERROR" in output or "FAILURE" in output: + return "\n\n==".join(output.split("\n\n==")[1:]) + else: + dots = DOTS.search(output).group(1) + if "E" in dots or "F" in dots: + return output[len(dots) + 1 :].split(RAN_TESTS_DIV)[0] + return "" + + +def output_into_dots(output): + """convert the test runner output into dots.""" + # verbose_mode = ") ..." in output + verbose_mode = " ..." in output + + if verbose_mode: + # a map from the verbose output to the dots output. + reasons = { + "... ERROR": "E", + "... unexpected success": "u", + "... skipped": "s", + "... expected failure": "x", + "... ok": ".", + "... FAIL": "F", + } + results = output.split("\n\n==")[0] + lines = [l for l in results.split("\n") if l and "..." in l] + dotlist = [] + for l in lines: + found = False + for reason in reasons: + if reason in l: + dotlist.append(reasons[reason]) + found = True + break + if not found: + raise ValueError("Not sure what this is. Add to reasons. :%s" % l) + + return "".join(dotlist) + dots = DOTS.search(output).group(1) + return dots + + +def combine_results(all_results, t): + """ + + Return pieced together results in a form fit for human consumption. Don't + rely on results if piecing together subprocessed results (single process + mode is fine). Was originally meant for that purpose but was found to be + unreliable. See the dump option for reliable results. + + """ + + all_dots = "" + failures = [] + + for module, results in sorted(all_results.items()): + output, return_code, raw_return = map( + results.get, ("output", "return_code", "raw_return") + ) + + if not output or (return_code and RAN_TESTS_DIV not in output): + # would this effect the original dict? TODO + output_lines = raw_return.splitlines() + if len(output_lines) > 20: + results["raw_return"] = "\n".join( + output_lines[:10] + ["..."] + output_lines[-10:] + ) + failures.append(COMPLETE_FAILURE_TEMPLATE % results) + all_dots += "E" + continue + + dots = output_into_dots(output) + all_dots += dots + tracebacks = extract_tracebacks(output) + if tracebacks: + failures.append(tracebacks) + + total_fails, total_errors = map(all_dots.count, "FE") + total_tests = len(all_dots) + + combined = [all_dots] + if failures: + combined += ["".join(failures).lstrip("\n")[:-1]] + combined += ["%s %s tests in %.3fs\n" % (RAN_TESTS_DIV, total_tests, t)] + + if failures: + infos = (["failures=%s" % total_fails] if total_fails else []) + ( + ["errors=%s" % total_errors] if total_errors else [] + ) + combined += ["FAILED (%s)\n" % ", ".join(infos)] + else: + combined += ["OK\n"] + + return total_tests, "\n".join(combined) + + +################################################################################ + +TEST_RESULTS_START = "<--!! TEST RESULTS START HERE !!-->" +TEST_RESULTS_END = "<--!! TEST RESULTS END HERE !!-->" +_test_re_str = "%s\n(.*)%s" % (TEST_RESULTS_START, TEST_RESULTS_END) +TEST_RESULTS_RE = re.compile(_test_re_str, re.DOTALL | re.M) + + +def get_test_results(raw_return): + test_results = TEST_RESULTS_RE.search(raw_return) + if test_results: + try: + return eval(test_results.group(1)) + except: + print("BUGGY TEST RESULTS EVAL:\n %s" % test_results.group(1)) + raise + + +################################################################################ + + +def run_test( + module, + incomplete=False, + usesubprocess=True, + randomize=False, + exclude=("interactive",), + buffer=True, + unbuffered=None, + verbosity=1, +): + """Run a unit test module""" + suite = unittest.TestSuite() + + if verbosity is None: + verbosity = 1 + + if verbosity: + print("loading %s" % module) + + loader = PygameTestLoader( + randomize_tests=randomize, include_incomplete=incomplete, exclude=exclude + ) + suite.addTest(loader.loadTestsFromName(module)) + + output = StringIO.StringIO() + runner = unittest.TextTestRunner(stream=output, buffer=buffer, verbosity=verbosity) + results = runner.run(suite) + + if verbosity == 2: + output.seek(0) + print(output.read()) + output.seek(0) + + results = { + module: { + "output": output.getvalue(), + "num_tests": results.testsRun, + "num_errors": len(results.errors), + "num_failures": len(results.failures), + } + } + + if usesubprocess: + print(TEST_RESULTS_START) + print(pformat(results)) + print(TEST_RESULTS_END) + else: + return results + + +################################################################################ + +if __name__ == "__main__": + options, args = opt_parser.parse_args() + if not args: + + if is_pygame_pkg: + run_from = "pygame.tests.go" + else: + run_from = os.path.join(main_dir, "run_tests.py") + sys.exit("No test module provided; consider using %s instead" % run_from) + run_test( + args[0], + incomplete=options.incomplete, + usesubprocess=options.usesubprocess, + randomize=options.randomize, + exclude=options.exclude, + buffer=(not options.unbuffered), + ) + +################################################################################ diff --git a/venv/Lib/site-packages/pygame/tests/threads_test.py b/venv/Lib/site-packages/pygame/tests/threads_test.py new file mode 100644 index 0000000..5f55eac --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/threads_test.py @@ -0,0 +1,240 @@ +import unittest +from pygame.threads import FuncResult, tmap, WorkerQueue, Empty, STOP +from pygame import threads, Surface, transform + + +import time + + +class WorkerQueueTypeTest(unittest.TestCase): + def test_usage_with_different_functions(self): + def f(x): + return x + 1 + + def f2(x): + return x + 2 + + wq = WorkerQueue() + fr = FuncResult(f) + fr2 = FuncResult(f2) + wq.do(fr, 1) + wq.do(fr2, 1) + wq.wait() + wq.stop() + + self.assertEqual(fr.result, 2) + self.assertEqual(fr2.result, 3) + + def test_do(self): + """Tests function placement on queue and execution after blocking function completion.""" + # __doc__ (as of 2008-06-28) for pygame.threads.WorkerQueue.do: + + # puts a function on a queue for running _later_. + + # TODO: This tests needs refactoring to avoid sleep. + # sleep is slow and unreliable (especially on VMs). + + # def sleep_test(): + # time.sleep(0.5) + + # def calc_test(x): + # return x + 1 + + # worker_queue = WorkerQueue(num_workers=1) + # sleep_return = FuncResult(sleep_test) + # calc_return = FuncResult(calc_test) + # init_time = time.time() + # worker_queue.do(sleep_return) + # worker_queue.do(calc_return, 1) + # worker_queue.wait() + # worker_queue.stop() + # time_diff = time.time() - init_time + + # self.assertEqual(sleep_return.result, None) + # self.assertEqual(calc_return.result, 2) + # self.assertGreaterEqual(time_diff, 0.5) + + def test_stop(self): + """Ensure stop() stops the worker queue""" + wq = WorkerQueue() + + self.assertGreater(len(wq.pool), 0) + + for t in wq.pool: + self.assertTrue(t.is_alive()) + + for i in range(200): + wq.do(lambda x: x + 1, i) + + wq.stop() + + for t in wq.pool: + self.assertFalse(t.is_alive()) + + self.assertIs(wq.queue.get(), STOP) + + def test_threadloop(self): + + # __doc__ (as of 2008-06-28) for pygame.threads.WorkerQueue.threadloop: + + # Loops until all of the tasks are finished. + + # Make a worker queue with only one thread + wq = WorkerQueue(1) + + # Ocuppy the one worker with the threadloop + # wq threads are just threadloop, so this makes an embedded threadloop + wq.do(wq.threadloop) + + # Make sure wq can still do work + # If wq can still do work, threadloop works + l = [] + wq.do(l.append, 1) + # Wait won't work because the primary thread is in an infinite loop + time.sleep(0.5) + self.assertEqual(l[0], 1) + + # Kill the embedded threadloop by sending stop onto the stack + # Threadloop puts STOP back onto the queue when it STOPs so this kills both loops + wq.stop() + + # Make sure wq has stopped + self.assertFalse(wq.pool[0].is_alive()) + + def test_wait(self): + + # __doc__ (as of 2008-06-28) for pygame.threads.WorkerQueue.wait: + + # waits until all tasks are complete. + + wq = WorkerQueue() + + for i in range(2000): + wq.do(lambda x: x + 1, i) + wq.wait() + + self.assertRaises(Empty, wq.queue.get_nowait) + + wq.stop() + + +class ThreadsModuleTest(unittest.TestCase): + def test_benchmark_workers(self): + """Ensure benchmark_workers performance measure functions properly with both default and specified inputs""" + "tags:long_running" + + # __doc__ (as of 2008-06-28) for pygame.threads.benchmark_workers: + + # does a little test to see if workers are at all faster. + # Returns the number of workers which works best. + # Takes a little bit of time to run, so you should only really call + # it once. + # You can pass in benchmark data, and functions if you want. + # a_bench_func - f(data) + # the_data - data to work on. + optimal_workers = threads.benchmark_workers() + self.assertIsInstance(optimal_workers, int) + self.assertTrue(0 <= optimal_workers < 64) + + # Test passing benchmark data and function explicitly + def smooth_scale_bench(data): + transform.smoothscale(data, (128, 128)) + + surf_data = [Surface((x, x), 0, 32) for x in range(12, 64, 12)] + best_num_workers = threads.benchmark_workers(smooth_scale_bench, surf_data) + self.assertIsInstance(best_num_workers, int) + + def test_init(self): + """Ensure init() sets up the worker queue""" + threads.init(8) + + self.assertIsInstance(threads._wq, WorkerQueue) + + threads.quit() + + def test_quit(self): + """Ensure quit() cleans up the worker queue""" + threads.init(8) + threads.quit() + + self.assertIsNone(threads._wq) + + def test_tmap(self): + # __doc__ (as of 2008-06-28) for pygame.threads.tmap: + + # like map, but uses a thread pool to execute. + # num_workers - the number of worker threads that will be used. If pool + # is passed in, then the num_workers arg is ignored. + # worker_queue - you can optionally pass in an existing WorkerQueue. + # wait - True means that the results are returned when everything is finished. + # False means that we return the [worker_queue, results] right away instead. + # results, is returned as a list of FuncResult instances. + # stop_on_error - + + ## test that the outcomes of map and tmap are the same + func, data = lambda x: x + 1, range(100) + + tmapped = list(tmap(func, data)) + mapped = list(map(func, data)) + + self.assertEqual(tmapped, mapped) + + ## Test that setting tmap to not stop on errors produces the expected result + data2 = range(100) + always_excepts = lambda x: 1 / 0 + + tmapped2 = list(tmap(always_excepts, data2, stop_on_error=False)) + + # Use list comprehension to check all entries are None as all function + # calls made by tmap will have thrown an exception (ZeroDivisionError) + # Condense to single bool with `all`, which will return true if all + # entries are true + self.assertTrue(all([x is None for x in tmapped2])) + + def todo_test_tmap__None_func_and_multiple_sequences(self): + """Using a None as func and multiple sequences""" + self.fail() + + res = tmap(None, [1, 2, 3, 4]) + res2 = tmap(None, [1, 2, 3, 4], [22, 33, 44, 55]) + res3 = tmap(None, [1, 2, 3, 4], [22, 33, 44, 55, 66]) + res4 = tmap(None, [1, 2, 3, 4, 5], [22, 33, 44, 55]) + + self.assertEqual([1, 2, 3, 4], res) + self.assertEqual([(1, 22), (2, 33), (3, 44), (4, 55)], res2) + self.assertEqual([(1, 22), (2, 33), (3, 44), (4, 55), (None, 66)], res3) + self.assertEqual([(1, 22), (2, 33), (3, 44), (4, 55), (5, None)], res4) + + def test_tmap__wait(self): + r = range(1000) + wq, results = tmap(lambda x: x, r, num_workers=5, wait=False) + wq.wait() + r2 = map(lambda x: x.result, results) + self.assertEqual(list(r), list(r2)) + + def test_FuncResult(self): + """Ensure FuncResult sets its result and exception attributes""" + # Results are stored in result attribute + fr = FuncResult(lambda x: x + 1) + fr(2) + + self.assertEqual(fr.result, 3) + + # Exceptions are store in exception attribute + self.assertIsNone(fr.exception, "no exception should be raised") + + exception = ValueError("rast") + + def x(sdf): + raise exception + + fr = FuncResult(x) + fr(None) + + self.assertIs(fr.exception, exception) + + +################################################################################ + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/time_test.py b/venv/Lib/site-packages/pygame/tests/time_test.py new file mode 100644 index 0000000..e428508 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/time_test.py @@ -0,0 +1,392 @@ +import unittest +import pygame +import time + +Clock = pygame.time.Clock + + +class ClockTypeTest(unittest.TestCase): + __tags__ = ["timing"] + + def test_construction(self): + """Ensure a Clock object can be created""" + c = Clock() + + self.assertTrue(c, "Clock cannot be constructed") + + def test_get_fps(self): + """test_get_fps tests pygame.time.get_fps()""" + # Initialization check, first call should return 0 fps + c = Clock() + self.assertEqual(c.get_fps(), 0) + # Type check get_fps should return float + self.assertTrue(type(c.get_fps()) == float) + # Allowable margin of error in percentage + delta = 0.30 + # Test fps correctness for 100, 60 and 30 fps + self._fps_test(c, 100, delta) + self._fps_test(c, 60, delta) + self._fps_test(c, 30, delta) + + def _fps_test(self, clock, fps, delta): + """ticks fps times each second, hence get_fps() should return fps""" + delay_per_frame = 1.0 / fps + for f in range(fps): # For one second tick and sleep + clock.tick() + time.sleep(delay_per_frame) + # We should get around fps (+- fps*delta -- delta % of fps) + self.assertAlmostEqual(clock.get_fps(), fps, delta=fps * delta) + + def test_get_rawtime(self): + + iterations = 10 + delay = 0.1 + delay_miliseconds = delay * (10 ** 3) # actual time difference between ticks + framerate_limit = 5 + delta = 50 # allowable error in milliseconds + + # Testing Clock Initialization + c = Clock() + self.assertEqual(c.get_rawtime(), 0) + + # Testing Raw Time with Frame Delay + for f in range(iterations): + time.sleep(delay) + c.tick(framerate_limit) + c1 = c.get_rawtime() + self.assertAlmostEqual(delay_miliseconds, c1, delta=delta) + + # Testing get_rawtime() = get_time() + for f in range(iterations): + time.sleep(delay) + c.tick() + c1 = c.get_rawtime() + c2 = c.get_time() + self.assertAlmostEqual(c1, c2, delta=delta) + + def test_get_time(self): + # Testing parameters + delay = 0.1 # seconds + delay_miliseconds = delay * (10 ** 3) + iterations = 10 + delta = 50 # milliseconds + + # Testing Clock Initialization + c = Clock() + self.assertEqual(c.get_time(), 0) + + # Testing within delay parameter range + for i in range(iterations): + time.sleep(delay) + c.tick() + c1 = c.get_time() + self.assertAlmostEqual(delay_miliseconds, c1, delta=delta) + + # Comparing get_time() results with the 'time' module + for i in range(iterations): + t0 = time.time() + time.sleep(delay) + c.tick() + t1 = time.time() + c1 = c.get_time() # elapsed time in milliseconds + d0 = (t1 - t0) * ( + 10 ** 3 + ) #'time' module elapsed time converted to milliseconds + self.assertAlmostEqual(d0, c1, delta=delta) + + def test_tick(self): + """Tests time.Clock.tick()""" + """ + Loops with a set delay a few times then checks what tick reports to + verify its accuracy. Then calls tick with a desired frame-rate and + verifies it is not faster than the desired frame-rate nor is it taking + a dramatically long time to complete + """ + + # Adjust this value to increase the acceptable sleep jitter + epsilon = 1.5 + # Adjust this value to increase the acceptable locked frame-rate jitter + epsilon2 = 0.3 + # adjust this value to increase the acceptable frame-rate margin + epsilon3 = 20 + testing_framerate = 60 + milliseconds = 5.0 + + collection = [] + c = Clock() + + # verify time.Clock.tick() will measure the time correctly + c.tick() + for i in range(100): + time.sleep(milliseconds / 1000) # convert to seconds + collection.append(c.tick()) + + # removes the first highest and lowest value + for outlier in [min(collection), max(collection)]: + if outlier != milliseconds: + collection.remove(outlier) + + average_time = float(sum(collection)) / len(collection) + + # assert the deviation from the intended frame-rate is within the + # acceptable amount (the delay is not taking a dramatically long time) + self.assertAlmostEqual(average_time, milliseconds, delta=epsilon) + + # verify tick will control the frame-rate + + c = Clock() + collection = [] + + start = time.time() + + for i in range(testing_framerate): + collection.append(c.tick(testing_framerate)) + + # remove the highest and lowest outliers + for outlier in [min(collection), max(collection)]: + if outlier != round(1000 / testing_framerate): + collection.remove(outlier) + + end = time.time() + + # Since calling tick with a desired fps will prevent the program from + # running at greater than the given fps, 100 iterations at 100 fps + # should last no less than 1 second + self.assertAlmostEqual(end - start, 1, delta=epsilon2) + + average_tick_time = float(sum(collection)) / len(collection) + self.assertAlmostEqual( + 1000 / average_tick_time, testing_framerate, delta=epsilon3 + ) + + def test_tick_busy_loop(self): + """Test tick_busy_loop""" + + c = Clock() + + # Test whether the return value of tick_busy_loop is equal to + # (FPS is accurate) or greater than (slower than the set FPS) + # with a small margin for error based on differences in how this + # test runs in practise - it either sometimes runs slightly fast + # or seems to based on a rounding error. + second_length = 1000 + shortfall_tolerance = 1 # (ms) The amount of time a tick is allowed to run short of, to account for underlying rounding errors + sample_fps = 40 + + self.assertGreaterEqual( + c.tick_busy_loop(sample_fps), + (second_length / sample_fps) - shortfall_tolerance, + ) + pygame.time.wait(10) # incur delay between ticks that's faster than sample_fps + self.assertGreaterEqual( + c.tick_busy_loop(sample_fps), + (second_length / sample_fps) - shortfall_tolerance, + ) + pygame.time.wait(200) # incur delay between ticks that's slower than sample_fps + self.assertGreaterEqual( + c.tick_busy_loop(sample_fps), + (second_length / sample_fps) - shortfall_tolerance, + ) + + high_fps = 500 + self.assertGreaterEqual( + c.tick_busy_loop(high_fps), (second_length / high_fps) - shortfall_tolerance + ) + + low_fps = 1 + self.assertGreaterEqual( + c.tick_busy_loop(low_fps), (second_length / low_fps) - shortfall_tolerance + ) + + low_non_factor_fps = 35 # 1000/35 makes 28.5714285714 + frame_length_without_decimal_places = int( + second_length / low_non_factor_fps + ) # Same result as math.floor + self.assertGreaterEqual( + c.tick_busy_loop(low_non_factor_fps), + frame_length_without_decimal_places - shortfall_tolerance, + ) + + high_non_factor_fps = 750 # 1000/750 makes 1.3333... + frame_length_without_decimal_places_2 = int( + second_length / high_non_factor_fps + ) # Same result as math.floor + self.assertGreaterEqual( + c.tick_busy_loop(high_non_factor_fps), + frame_length_without_decimal_places_2 - shortfall_tolerance, + ) + + zero_fps = 0 + self.assertEqual(c.tick_busy_loop(zero_fps), 0) + + # Check behaviour of unexpected values + + negative_fps = -1 + self.assertEqual(c.tick_busy_loop(negative_fps), 0) + + fractional_fps = 32.75 + frame_length_without_decimal_places_3 = int(second_length / fractional_fps) + self.assertGreaterEqual( + c.tick_busy_loop(fractional_fps), + frame_length_without_decimal_places_3 - shortfall_tolerance, + ) + + bool_fps = True + self.assertGreaterEqual( + c.tick_busy_loop(bool_fps), (second_length / bool_fps) - shortfall_tolerance + ) + + +class TimeModuleTest(unittest.TestCase): + __tags__ = ["timing"] + + def test_delay(self): + """Tests time.delay() function.""" + millis = 50 # millisecond to wait on each iteration + iterations = 20 # number of iterations + delta = 150 # Represents acceptable margin of error for wait in ms + # Call checking function + self._wait_delay_check(pygame.time.delay, millis, iterations, delta) + # After timing behaviour, check argument type exceptions + self._type_error_checks(pygame.time.delay) + + def test_get_ticks(self): + """Tests time.get_ticks()""" + """ + Iterates and delays for arbitrary amount of time for each iteration, + check get_ticks to equal correct gap time + """ + iterations = 20 + millis = 50 + delta = 15 # Acceptable margin of error in ms + # Assert return type to be int + self.assertTrue(type(pygame.time.get_ticks()) == int) + for i in range(iterations): + curr_ticks = pygame.time.get_ticks() # Save current tick count + curr_time = time.time() # Save current time + pygame.time.delay(millis) # Delay for millis + # Time and Ticks difference from start of the iteration + time_diff = round((time.time() - curr_time) * 1000) + ticks_diff = pygame.time.get_ticks() - curr_ticks + # Assert almost equality of the ticking time and time difference + self.assertAlmostEqual(ticks_diff, time_diff, delta=delta) + + def test_set_timer(self): + """Tests time.set_timer()""" + """ + Tests if a timer will post the correct amount of eventid events in + the specified delay. Test is posting event objects work. + Also tests if setting milliseconds to 0 stops the timer and if + the once argument and repeat arguments work. + """ + pygame.init() + TIMER_EVENT_TYPE = pygame.event.custom_type() + timer_event = pygame.event.Event(TIMER_EVENT_TYPE) + delta = 50 + timer_delay = 100 + test_number = 8 # Number of events to read for the test + events = 0 # Events read + + pygame.event.clear() + pygame.time.set_timer(TIMER_EVENT_TYPE, timer_delay) + + # Test that 'test_number' events are posted in the right amount of time + t1 = pygame.time.get_ticks() + max_test_time = t1 + timer_delay * test_number + delta + while events < test_number: + for event in pygame.event.get(): + if event == timer_event: + events += 1 + + # The test takes too much time + if pygame.time.get_ticks() > max_test_time: + break + + pygame.time.set_timer(TIMER_EVENT_TYPE, 0) + t2 = pygame.time.get_ticks() + # Is the number ef events and the timing right? + self.assertEqual(events, test_number) + self.assertAlmostEqual(timer_delay * test_number, t2 - t1, delta=delta) + + # Test that the timer stopped when set with 0ms delay. + pygame.time.delay(200) + self.assertNotIn(timer_event, pygame.event.get()) + + # Test that the old timer for an event is deleted when a new timer is set + pygame.time.set_timer(TIMER_EVENT_TYPE, timer_delay) + pygame.time.delay(int(timer_delay * 3.5)) + self.assertEqual(pygame.event.get().count(timer_event), 3) + pygame.time.set_timer(TIMER_EVENT_TYPE, timer_delay * 10) # long wait time + pygame.time.delay(timer_delay * 5) + self.assertNotIn(timer_event, pygame.event.get()) + pygame.time.set_timer(TIMER_EVENT_TYPE, timer_delay * 3) + pygame.time.delay(timer_delay * 7) + self.assertEqual(pygame.event.get().count(timer_event), 2) + pygame.time.set_timer(TIMER_EVENT_TYPE, timer_delay) + pygame.time.delay(int(timer_delay * 5.5)) + self.assertEqual(pygame.event.get().count(timer_event), 5) + + # Test that the loops=True works + pygame.time.set_timer(TIMER_EVENT_TYPE, 10, True) + pygame.time.delay(40) + self.assertEqual(pygame.event.get().count(timer_event), 1) + + # Test a variety of event objects, test loops argument + events_to_test = [ + pygame.event.Event(TIMER_EVENT_TYPE), + pygame.event.Event( + TIMER_EVENT_TYPE, foo="9gwz5", baz=12, lol=[124, (34, "")] + ), + pygame.event.Event(pygame.KEYDOWN, key=pygame.K_a, unicode="a"), + ] + repeat = 3 + millis = 50 + for e in events_to_test: + pygame.time.set_timer(e, millis, loops=repeat) + pygame.time.delay(2 * millis * repeat) + self.assertEqual(pygame.event.get().count(e), repeat) + pygame.quit() + + def test_wait(self): + """Tests time.wait() function.""" + millis = 100 # millisecond to wait on each iteration + iterations = 10 # number of iterations + delta = 50 # Represents acceptable margin of error for wait in ms + # Call checking function + self._wait_delay_check(pygame.time.wait, millis, iterations, delta) + # After timing behaviour, check argument type exceptions + self._type_error_checks(pygame.time.wait) + + def _wait_delay_check(self, func_to_check, millis, iterations, delta): + """ " + call func_to_check(millis) "iterations" times and check each time if + function "waited" for given millisecond (+- delta). At the end, take + average time for each call (whole_duration/iterations), which should + be equal to millis (+- delta - acceptable margin of error). + *Created to avoid code duplication during delay and wait tests + """ + # take starting time for duration calculation + start_time = time.time() + for i in range(iterations): + wait_time = func_to_check(millis) + # Check equality of wait_time and millis with margin of error delta + self.assertAlmostEqual(wait_time, millis, delta=delta) + stop_time = time.time() + # Cycle duration in millisecond + duration = round((stop_time - start_time) * 1000) + # Duration/Iterations should be (almost) equal to predefined millis + self.assertAlmostEqual(duration / iterations, millis, delta=delta) + + def _type_error_checks(self, func_to_check): + """Checks 3 TypeError (float, tuple, string) for the func_to_check""" + """Intended for time.delay and time.wait functions""" + # Those methods throw no exceptions on negative integers + self.assertRaises(TypeError, func_to_check, 0.1) # check float + self.assertRaises(TypeError, pygame.time.delay, (0, 1)) # check tuple + self.assertRaises(TypeError, pygame.time.delay, "10") # check string + + +############################################################################### + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/touch_test.py b/venv/Lib/site-packages/pygame/tests/touch_test.py new file mode 100644 index 0000000..3f63cae --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/touch_test.py @@ -0,0 +1,98 @@ +import unittest +import os +import pygame +from pygame._sdl2 import touch +from pygame.tests.test_utils import question + + +has_touchdevice = touch.get_num_devices() > 0 + + +class TouchTest(unittest.TestCase): + @classmethod + def setUpClass(cls): + pygame.display.init() + + @classmethod + def tearDownClass(cls): + pygame.display.quit() + + def test_num_devices(self): + touch.get_num_devices() + + @unittest.skipIf(not has_touchdevice, "no touch devices found") + def test_get_device(self): + touch.get_device(0) + + def test_num_fingers__invalid(self): + self.assertRaises(pygame.error, touch.get_device, -1234) + self.assertRaises(TypeError, touch.get_device, "test") + + @unittest.skipIf(not has_touchdevice, "no touch devices found") + def test_num_fingers(self): + touch.get_num_fingers(touch.get_device(0)) + + def test_num_fingers__invalid(self): + self.assertRaises(TypeError, touch.get_num_fingers, "test") + self.assertRaises(pygame.error, touch.get_num_fingers, -1234) + + +class TouchInteractiveTest(unittest.TestCase): + + __tags__ = ["interactive"] + + @unittest.skipIf(not has_touchdevice, "no touch devices found") + def test_get_finger(self): + """ask for touch input and check the dict""" + + pygame.display.init() + pygame.font.init() + + os.environ["SDL_VIDEO_WINDOW_POS"] = "50,50" + screen = pygame.display.set_mode((800, 600)) + screen.fill((255, 255, 255)) + + font = pygame.font.Font(None, 32) + instructions_str_1 = "Please place some fingers on your touch device" + instructions_str_2 = ( + "Close the window when finished, " "and answer the question" + ) + inst_1_render = font.render(instructions_str_1, True, pygame.Color("#000000")) + inst_2_render = font.render(instructions_str_2, True, pygame.Color("#000000")) + + running = True + while running: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + + finger_data_renders = [] + num_devices = pygame._sdl2.touch.get_num_devices() + if num_devices > 0: + first_device = pygame._sdl2.touch.get_device(0) + num_fingers = pygame._sdl2.touch.get_num_fingers(first_device) + if num_fingers > 0: + for finger_index in range(0, num_fingers): + data = pygame._sdl2.touch.get_finger(first_device, finger_index) + render = font.render( + "finger - " + str(data), True, pygame.Color("#000000") + ) + + finger_data_renders.append(render) + + screen.fill((255, 255, 255)) + screen.blit(inst_1_render, (5, 5)) + screen.blit(inst_2_render, (5, 40)) + for index, finger in enumerate(finger_data_renders): + screen.blit(finger, (5, 80 + (index * 40))) + + pygame.display.update() + + response = question("Does the finger data seem correct?") + self.assertTrue(response) + + pygame.display.quit() + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/transform_test.py b/venv/Lib/site-packages/pygame/tests/transform_test.py new file mode 100644 index 0000000..1484817 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/transform_test.py @@ -0,0 +1,1316 @@ +import unittest +import os +import platform + +from pygame.tests import test_utils +from pygame.tests.test_utils import example_path + +import pygame +import pygame.transform +from pygame.locals import * + + +def show_image(s, images=[]): + # pygame.display.init() + size = s.get_rect()[2:] + screen = pygame.display.set_mode(size) + screen.blit(s, (0, 0)) + pygame.display.flip() + pygame.event.pump() + going = True + idx = 0 + while going: + events = pygame.event.get() + for e in events: + if e.type == QUIT: + going = False + if e.type == KEYDOWN: + if e.key in [K_s, K_a]: + if e.key == K_s: + idx += 1 + if e.key == K_a: + idx -= 1 + s = images[idx] + screen.blit(s, (0, 0)) + pygame.display.flip() + pygame.event.pump() + elif e.key in [K_ESCAPE]: + going = False + pygame.display.quit() + pygame.display.init() + + +def threshold( + return_surf, + surf, + color, + threshold=(0, 0, 0), + diff_color=(0, 0, 0), + change_return=True, +): + """given the color it makes return_surf only have areas with the given colour.""" + + width, height = surf.get_width(), surf.get_height() + + if change_return: + return_surf.fill(diff_color) + + try: + r, g, b = color + except ValueError: + r, g, b, a = color + + try: + tr, tg, tb = color + except ValueError: + tr, tg, tb, ta = color + + similar = 0 + for y in range(height): + for x in range(width): + c1 = surf.get_at((x, y)) + + if (abs(c1[0] - r) < tr) & (abs(c1[1] - g) < tg) & (abs(c1[2] - b) < tb): + # this pixel is within the threshold. + if change_return: + return_surf.set_at((x, y), c1) + similar += 1 + # else: + # print c1, c2 + + return similar + + +class TransformModuleTest(unittest.TestCase): + def test_scale__alpha(self): + """see if set_alpha information is kept.""" + + s = pygame.Surface((32, 32)) + s.set_alpha(55) + self.assertEqual(s.get_alpha(), 55) + + s = pygame.Surface((32, 32)) + s.set_alpha(55) + s2 = pygame.transform.scale(s, (64, 64)) + s3 = s.copy() + self.assertEqual(s.get_alpha(), s3.get_alpha()) + self.assertEqual(s.get_alpha(), s2.get_alpha()) + + def test_scale__destination(self): + """see if the destination surface can be passed in to use.""" + + s = pygame.Surface((32, 32)) + s2 = pygame.transform.scale(s, (64, 64)) + s3 = s2.copy() + + # Also validate keyword arguments + s3 = pygame.transform.scale(surface=s, size=(64, 64), dest_surface=s3) + pygame.transform.scale(s, (64, 64), s2) + + # the wrong size surface is past in. Should raise an error. + self.assertRaises(ValueError, pygame.transform.scale, s, (33, 64), s3) + + s = pygame.Surface((32, 32)) + s2 = pygame.transform.smoothscale(s, (64, 64)) + s3 = s2.copy() + + # Also validate keyword arguments + s3 = pygame.transform.smoothscale(surface=s, size=(64, 64), dest_surface=s3) + + # the wrong size surface is past in. Should raise an error. + self.assertRaises(ValueError, pygame.transform.smoothscale, s, (33, 64), s3) + + def test_scale__vector2(self): + s = pygame.Surface((32, 32)) + s2 = pygame.transform.scale(s, pygame.Vector2(64, 64)) + s3 = pygame.transform.smoothscale(s, pygame.Vector2(64, 64)) + + self.assertEqual((64, 64), s2.get_size()) + self.assertEqual((64, 64), s3.get_size()) + + def test_scale__zero_surface_transform(self): + tmp_surface = pygame.transform.scale(pygame.Surface((128, 128)), (0, 0)) + self.assertEqual(tmp_surface.get_size(), (0, 0)) + tmp_surface = pygame.transform.scale(tmp_surface, (128, 128)) + self.assertEqual(tmp_surface.get_size(), (128, 128)) + + def test_threshold__honors_third_surface(self): + # __doc__ for threshold as of Tue 07/15/2008 + + # pygame.transform.threshold(DestSurface, Surface, color, threshold = + # (0,0,0,0), diff_color = (0,0,0,0), change_return = True, Surface = + # None): return num_threshold_pixels + + # When given the optional third + # surface, it would use the colors in that rather than the "color" + # specified in the function to check against. + + # New in pygame 1.8 + + ################################################################ + # Sizes + (w, h) = size = (32, 32) + + # the original_color is within the threshold of the threshold_color + threshold = (20, 20, 20, 20) + + original_color = (25, 25, 25, 25) + threshold_color = (10, 10, 10, 10) + + # Surfaces + original_surface = pygame.Surface(size, pygame.SRCALPHA, 32) + dest_surface = pygame.Surface(size, pygame.SRCALPHA, 32) + + # Third surface is used in lieu of 3rd position arg color + third_surface = pygame.Surface(size, pygame.SRCALPHA, 32) + + # Color filling + original_surface.fill(original_color) + third_surface.fill(threshold_color) + + ################################################################ + # All pixels for color should be within threshold + # + pixels_within_threshold = pygame.transform.threshold( + dest_surface=None, + surface=original_surface, + search_color=threshold_color, + threshold=threshold, + set_color=None, + set_behavior=0, + ) + + self.assertEqual(w * h, pixels_within_threshold) + + ################################################################ + # This should respect third_surface colors in place of 3rd arg + # color Should be the same as: surface.fill(threshold_color) + # all within threshold + + pixels_within_threshold = pygame.transform.threshold( + dest_surface=None, + surface=original_surface, + search_color=None, + threshold=threshold, + set_color=None, + set_behavior=0, + search_surf=third_surface, + ) + self.assertEqual(w * h, pixels_within_threshold) + + def test_threshold_dest_surf_not_change(self): + """the pixels within the threshold. + + All pixels not within threshold are changed to set_color. + So there should be none changed in this test. + """ + (w, h) = size = (32, 32) + threshold = (20, 20, 20, 20) + original_color = (25, 25, 25, 25) + original_dest_color = (65, 65, 65, 55) + threshold_color = (10, 10, 10, 10) + set_color = (255, 10, 10, 10) + + surf = pygame.Surface(size, pygame.SRCALPHA, 32) + dest_surf = pygame.Surface(size, pygame.SRCALPHA, 32) + search_surf = pygame.Surface(size, pygame.SRCALPHA, 32) + + surf.fill(original_color) + search_surf.fill(threshold_color) + dest_surf.fill(original_dest_color) + + # set_behavior=1, set dest_surface from set_color. + # all within threshold of third_surface, so no color is set. + + THRESHOLD_BEHAVIOR_FROM_SEARCH_COLOR = 1 + pixels_within_threshold = pygame.transform.threshold( + dest_surface=dest_surf, + surface=surf, + search_color=None, + threshold=threshold, + set_color=set_color, + set_behavior=THRESHOLD_BEHAVIOR_FROM_SEARCH_COLOR, + search_surf=search_surf, + ) + + # # Return, of pixels within threshold is correct + self.assertEqual(w * h, pixels_within_threshold) + + # # Size of dest surface is correct + dest_rect = dest_surf.get_rect() + dest_size = dest_rect.size + self.assertEqual(size, dest_size) + + # The color is not the change_color specified for every pixel As all + # pixels are within threshold + + for pt in test_utils.rect_area_pts(dest_rect): + self.assertNotEqual(dest_surf.get_at(pt), set_color) + self.assertEqual(dest_surf.get_at(pt), original_dest_color) + + def test_threshold_dest_surf_all_changed(self): + """Lowering the threshold, expecting changed surface""" + + (w, h) = size = (32, 32) + threshold = (20, 20, 20, 20) + original_color = (25, 25, 25, 25) + original_dest_color = (65, 65, 65, 55) + threshold_color = (10, 10, 10, 10) + set_color = (255, 10, 10, 10) + + surf = pygame.Surface(size, pygame.SRCALPHA, 32) + dest_surf = pygame.Surface(size, pygame.SRCALPHA, 32) + search_surf = pygame.Surface(size, pygame.SRCALPHA, 32) + + surf.fill(original_color) + search_surf.fill(threshold_color) + dest_surf.fill(original_dest_color) + + THRESHOLD_BEHAVIOR_FROM_SEARCH_COLOR = 1 + pixels_within_threshold = pygame.transform.threshold( + dest_surf, + surf, + search_color=None, + set_color=set_color, + set_behavior=THRESHOLD_BEHAVIOR_FROM_SEARCH_COLOR, + search_surf=search_surf, + ) + + self.assertEqual(0, pixels_within_threshold) + + dest_rect = dest_surf.get_rect() + dest_size = dest_rect.size + self.assertEqual(size, dest_size) + + # The color is the set_color specified for every pixel As all + # pixels are not within threshold + for pt in test_utils.rect_area_pts(dest_rect): + self.assertEqual(dest_surf.get_at(pt), set_color) + + def test_threshold_count(self): + """counts the colors, and not changes them.""" + surf_size = (32, 32) + surf = pygame.Surface(surf_size, pygame.SRCALPHA, 32) + search_surf = pygame.Surface(surf_size, pygame.SRCALPHA, 32) + search_color = (55, 55, 55, 255) + original_color = (10, 10, 10, 255) + + surf.fill(original_color) + # set 2 pixels to the color we are searching for. + surf.set_at((0, 0), search_color) + surf.set_at((12, 5), search_color) + + # There is no destination surface, but we ask to change it. + # This should be an error. + self.assertRaises( + TypeError, pygame.transform.threshold, None, surf, search_color + ) + # from pygame.transform import THRESHOLD_BEHAVIOR_COUNT + THRESHOLD_BEHAVIOR_FROM_SEARCH_SURF = 2 + self.assertRaises( + TypeError, + pygame.transform.threshold, + None, + surf, + search_color, + set_behavior=THRESHOLD_BEHAVIOR_FROM_SEARCH_SURF, + ) + + THRESHOLD_BEHAVIOR_COUNT = 0 + num_threshold_pixels = pygame.transform.threshold( + dest_surface=None, + surface=surf, + search_color=search_color, + set_behavior=THRESHOLD_BEHAVIOR_COUNT, + ) + self.assertEqual(num_threshold_pixels, 2) + + def test_threshold_search_surf(self): + surf_size = (32, 32) + surf = pygame.Surface(surf_size, pygame.SRCALPHA, 32) + search_surf = pygame.Surface(surf_size, pygame.SRCALPHA, 32) + dest_surf = pygame.Surface(surf_size, pygame.SRCALPHA, 32) + + original_color = (10, 10, 10, 255) + search_color = (55, 55, 55, 255) + + surf.fill(original_color) + dest_surf.fill(original_color) + # set 2 pixels to the color we are searching for. + surf.set_at((0, 0), search_color) + surf.set_at((12, 5), search_color) + + search_surf.fill(search_color) + + # We look in the other surface for matching colors. + # Change it in dest_surf + THRESHOLD_BEHAVIOR_FROM_SEARCH_SURF = 2 + + # TypeError: if search_surf is used, search_color should be None + self.assertRaises( + TypeError, + pygame.transform.threshold, + dest_surf, + surf, + search_color, + set_behavior=THRESHOLD_BEHAVIOR_FROM_SEARCH_SURF, + search_surf=search_surf, + ) + + # surf, dest_surf, and search_surf should all be the same size. + # Check surface sizes are the same size. + different_sized_surf = pygame.Surface((22, 33), pygame.SRCALPHA, 32) + self.assertRaises( + TypeError, + pygame.transform.threshold, + different_sized_surf, + surf, + search_color=None, + set_color=None, + set_behavior=THRESHOLD_BEHAVIOR_FROM_SEARCH_SURF, + search_surf=search_surf, + ) + + self.assertRaises( + TypeError, + pygame.transform.threshold, + dest_surf, + surf, + search_color=None, + set_color=None, + set_behavior=THRESHOLD_BEHAVIOR_FROM_SEARCH_SURF, + search_surf=different_sized_surf, + ) + + # We look to see if colors in search_surf are in surf. + num_threshold_pixels = pygame.transform.threshold( + dest_surface=dest_surf, + surface=surf, + search_color=None, + set_color=None, + set_behavior=THRESHOLD_BEHAVIOR_FROM_SEARCH_SURF, + search_surf=search_surf, + ) + + num_pixels_within = 2 + self.assertEqual(num_threshold_pixels, num_pixels_within) + + dest_surf.fill(original_color) + num_threshold_pixels = pygame.transform.threshold( + dest_surf, + surf, + search_color=None, + set_color=None, + set_behavior=THRESHOLD_BEHAVIOR_FROM_SEARCH_SURF, + search_surf=search_surf, + inverse_set=True, + ) + + self.assertEqual(num_threshold_pixels, 2) + + def test_threshold_inverse_set(self): + """changes the pixels within the threshold, and not outside.""" + surf_size = (32, 32) + _dest_surf = pygame.Surface(surf_size, pygame.SRCALPHA, 32) + _surf = pygame.Surface(surf_size, pygame.SRCALPHA, 32) + + dest_surf = _dest_surf # surface we are changing. + surf = _surf # surface we are looking at + search_color = (55, 55, 55, 255) # color we are searching for. + threshold = (0, 0, 0, 0) # within this distance from search_color. + set_color = (245, 245, 245, 255) # color we set. + inverse_set = 1 # pixels within threshold are changed to 'set_color' + + original_color = (10, 10, 10, 255) + surf.fill(original_color) + # set 2 pixels to the color we are searching for. + surf.set_at((0, 0), search_color) + surf.set_at((12, 5), search_color) + + dest_surf.fill(original_color) + # set 2 pixels to the color we are searching for. + dest_surf.set_at((0, 0), search_color) + dest_surf.set_at((12, 5), search_color) + + THRESHOLD_BEHAVIOR_FROM_SEARCH_COLOR = 1 + num_threshold_pixels = pygame.transform.threshold( + dest_surf, + surf, + search_color=search_color, + threshold=threshold, + set_color=set_color, + set_behavior=THRESHOLD_BEHAVIOR_FROM_SEARCH_COLOR, + inverse_set=1, + ) + + self.assertEqual(num_threshold_pixels, 2) + # only two pixels changed to diff_color. + self.assertEqual(dest_surf.get_at((0, 0)), set_color) + self.assertEqual(dest_surf.get_at((12, 5)), set_color) + + # other pixels should be the same as they were before. + # We just check one other pixel, not all of them. + self.assertEqual(dest_surf.get_at((2, 2)), original_color) + + # XXX + def test_threshold_non_src_alpha(self): + + result = pygame.Surface((10, 10)) + s1 = pygame.Surface((10, 10)) + s2 = pygame.Surface((10, 10)) + s3 = pygame.Surface((10, 10)) + s4 = pygame.Surface((10, 10)) + + x = s1.fill((0, 0, 0)) + s1.set_at((0, 0), (32, 20, 0)) + + x = s2.fill((0, 20, 0)) + x = s3.fill((0, 0, 0)) + x = s4.fill((0, 0, 0)) + s2.set_at((0, 0), (33, 21, 0)) + s2.set_at((3, 0), (63, 61, 0)) + s3.set_at((0, 0), (112, 31, 0)) + s4.set_at((0, 0), (11, 31, 0)) + s4.set_at((1, 1), (12, 31, 0)) + + self.assertEqual(s1.get_at((0, 0)), (32, 20, 0, 255)) + self.assertEqual(s2.get_at((0, 0)), (33, 21, 0, 255)) + self.assertEqual((0, 0), (s1.get_flags(), s2.get_flags())) + + similar_color = (255, 255, 255, 255) + diff_color = (222, 0, 0, 255) + threshold_color = (20, 20, 20, 255) + + THRESHOLD_BEHAVIOR_FROM_SEARCH_COLOR = 1 + num_threshold_pixels = pygame.transform.threshold( + dest_surface=result, + surface=s1, + search_color=similar_color, + threshold=threshold_color, + set_color=diff_color, + set_behavior=THRESHOLD_BEHAVIOR_FROM_SEARCH_COLOR, + ) + self.assertEqual(num_threshold_pixels, 0) + + num_threshold_pixels = pygame.transform.threshold( + dest_surface=result, + surface=s1, + search_color=(40, 40, 0), + threshold=threshold_color, + set_color=diff_color, + set_behavior=THRESHOLD_BEHAVIOR_FROM_SEARCH_COLOR, + ) + self.assertEqual(num_threshold_pixels, 1) + + self.assertEqual(result.get_at((0, 0)), diff_color) + + def test_threshold__uneven_colors(self): + (w, h) = size = (16, 16) + + original_surface = pygame.Surface(size, pygame.SRCALPHA, 32) + dest_surface = pygame.Surface(size, pygame.SRCALPHA, 32) + + original_surface.fill(0) + + threshold_color_template = [5, 5, 5, 5] + threshold_template = [6, 6, 6, 6] + + ################################################################ + + for pos in range(len("rgb")): + threshold_color = threshold_color_template[:] + threshold = threshold_template[:] + + threshold_color[pos] = 45 + threshold[pos] = 50 + + pixels_within_threshold = pygame.transform.threshold( + None, + original_surface, + threshold_color, + threshold, + set_color=None, + set_behavior=0, + ) + + self.assertEqual(w * h, pixels_within_threshold) + + ################################################################ + + def test_threshold_set_behavior2(self): + """raises an error when set_behavior=2 and set_color is not None.""" + from pygame.transform import threshold + + s1 = pygame.Surface((32, 32), SRCALPHA, 32) + s2 = pygame.Surface((32, 32), SRCALPHA, 32) + THRESHOLD_BEHAVIOR_FROM_SEARCH_SURF = 2 + self.assertRaises( + TypeError, + threshold, + dest_surface=s2, + surface=s1, + search_color=(30, 30, 30), + threshold=(11, 11, 11), + set_color=(255, 0, 0), + set_behavior=THRESHOLD_BEHAVIOR_FROM_SEARCH_SURF, + ) + + def test_threshold_set_behavior0(self): + """raises an error when set_behavior=1 + and set_color is not None, + and dest_surf is not None. + """ + from pygame.transform import threshold + + s1 = pygame.Surface((32, 32), SRCALPHA, 32) + s2 = pygame.Surface((32, 32), SRCALPHA, 32) + THRESHOLD_BEHAVIOR_COUNT = 0 + + self.assertRaises( + TypeError, + threshold, + dest_surface=None, + surface=s2, + search_color=(30, 30, 30), + threshold=(11, 11, 11), + set_color=(0, 0, 0), + set_behavior=THRESHOLD_BEHAVIOR_COUNT, + ) + + self.assertRaises( + TypeError, + threshold, + dest_surface=s1, + surface=s2, + search_color=(30, 30, 30), + threshold=(11, 11, 11), + set_color=None, + set_behavior=THRESHOLD_BEHAVIOR_COUNT, + ) + + threshold( + dest_surface=None, + surface=s2, + search_color=(30, 30, 30), + threshold=(11, 11, 11), + set_color=None, + set_behavior=THRESHOLD_BEHAVIOR_COUNT, + ) + + def test_threshold_from_surface(self): + """Set similar pixels in 'dest_surf' to color in the 'surf'.""" + from pygame.transform import threshold + + surf = pygame.Surface((32, 32), SRCALPHA, 32) + dest_surf = pygame.Surface((32, 32), SRCALPHA, 32) + surf_color = (40, 40, 40, 255) + dest_color = (255, 255, 255) + surf.fill(surf_color) + dest_surf.fill(dest_color) + THRESHOLD_BEHAVIOR_FROM_SEARCH_SURF = 2 + + num_threshold_pixels = threshold( + dest_surface=dest_surf, + surface=surf, + search_color=(30, 30, 30), + threshold=(11, 11, 11), + set_color=None, + set_behavior=THRESHOLD_BEHAVIOR_FROM_SEARCH_SURF, + inverse_set=1, + ) + + self.assertEqual( + num_threshold_pixels, dest_surf.get_height() * dest_surf.get_width() + ) + self.assertEqual(dest_surf.get_at((0, 0)), surf_color) + + def test_threshold__surface(self): + """ """ + from pygame.transform import threshold + + s1 = pygame.Surface((32, 32), SRCALPHA, 32) + s2 = pygame.Surface((32, 32), SRCALPHA, 32) + s3 = pygame.Surface((1, 1), SRCALPHA, 32) + THRESHOLD_BEHAVIOR_FROM_SEARCH_SURF = 2 + + # # only one pixel should not be changed. + # s1.fill((40,40,40)) + # s2.fill((255,255,255)) + # s1.set_at( (0,0), (170, 170, 170) ) + # # set the similar pixels in destination surface to the color + # # in the first surface. + # num_threshold_pixels = threshold( + # dest_surface=s2, + # surface=s1, + # search_color=(30,30,30), + # threshold=(11,11,11), + # set_color=None, + # set_behavior=THRESHOLD_BEHAVIOR_FROM_SEARCH_SURF) + + # #num_threshold_pixels = threshold(s2, s1, (30,30,30)) + # self.assertEqual(num_threshold_pixels, (s1.get_height() * s1.get_width()) -1) + # self.assertEqual(s2.get_at((0,0)), (0,0,0, 255)) + # self.assertEqual(s2.get_at((0,1)), (40, 40, 40, 255)) + # self.assertEqual(s2.get_at((17,1)), (40, 40, 40, 255)) + + # # abs(40 - 255) < 100 + # #(abs(c1[0] - r) < tr) + + # s1.fill((160,160,160)) + # s2.fill((255,255,255)) + # num_threshold_pixels = threshold(s2, s1, (255,255,255), (100,100,100), (0,0,0), True) + + # self.assertEqual(num_threshold_pixels, (s1.get_height() * s1.get_width())) + + # only one pixel should not be changed. + s1.fill((40, 40, 40)) + s1.set_at((0, 0), (170, 170, 170)) + THRESHOLD_BEHAVIOR_COUNT = 0 + + num_threshold_pixels = threshold( + dest_surface=None, + surface=s1, + search_color=(30, 30, 30), + threshold=(11, 11, 11), + set_color=None, + set_behavior=THRESHOLD_BEHAVIOR_COUNT, + ) + + # num_threshold_pixels = threshold(s2, s1, (30,30,30)) + self.assertEqual(num_threshold_pixels, (s1.get_height() * s1.get_width()) - 1) + + # test end markers. 0, and 255 + + # the pixels are different by 1. + s1.fill((254, 254, 254)) + s2.fill((255, 255, 255)) + s3.fill((255, 255, 255)) + s1.set_at((0, 0), (170, 170, 170)) + num_threshold_pixels = threshold( + None, s1, (254, 254, 254), (1, 1, 1), None, THRESHOLD_BEHAVIOR_COUNT + ) + self.assertEqual(num_threshold_pixels, (s1.get_height() * s1.get_width()) - 1) + + # compare the two surfaces. Should be all but one matching. + num_threshold_pixels = threshold( + None, s1, None, (1, 1, 1), None, THRESHOLD_BEHAVIOR_COUNT, s2 + ) + self.assertEqual(num_threshold_pixels, (s1.get_height() * s1.get_width()) - 1) + + # within (0,0,0) threshold? Should match no pixels. + num_threshold_pixels = threshold( + None, s1, (253, 253, 253), (0, 0, 0), None, THRESHOLD_BEHAVIOR_COUNT + ) + self.assertEqual(num_threshold_pixels, 0) + + # other surface within (0,0,0) threshold? Should match no pixels. + num_threshold_pixels = threshold( + None, s1, None, (0, 0, 0), None, THRESHOLD_BEHAVIOR_COUNT, s2 + ) + self.assertEqual(num_threshold_pixels, 0) + + def test_threshold__subclassed_surface(self): + """Ensure threshold accepts subclassed surfaces.""" + expected_size = (13, 11) + expected_flags = 0 + expected_depth = 32 + expected_color = (90, 80, 70, 255) + expected_count = 0 + surface = test_utils.SurfaceSubclass( + expected_size, expected_flags, expected_depth + ) + dest_surface = test_utils.SurfaceSubclass( + expected_size, expected_flags, expected_depth + ) + search_surface = test_utils.SurfaceSubclass( + expected_size, expected_flags, expected_depth + ) + surface.fill((10, 10, 10)) + dest_surface.fill((255, 255, 255)) + search_surface.fill((20, 20, 20)) + + count = pygame.transform.threshold( + dest_surface=dest_surface, + surface=surface, + threshold=(1, 1, 1), + set_color=expected_color, + search_color=None, + search_surf=search_surface, + ) + + self.assertIsInstance(dest_surface, pygame.Surface) + self.assertIsInstance(dest_surface, test_utils.SurfaceSubclass) + self.assertEqual(count, expected_count) + self.assertEqual(dest_surface.get_at((0, 0)), expected_color) + self.assertEqual(dest_surface.get_bitsize(), expected_depth) + self.assertEqual(dest_surface.get_size(), expected_size) + self.assertEqual(dest_surface.get_flags(), expected_flags) + + def test_laplacian(self): + """ """ + + SIZE = 32 + s1 = pygame.Surface((SIZE, SIZE)) + s2 = pygame.Surface((SIZE, SIZE)) + s1.fill((10, 10, 70)) + pygame.draw.line(s1, (255, 0, 0), (3, 10), (20, 20)) + + # a line at the last row of the image. + pygame.draw.line(s1, (255, 0, 0), (0, 31), (31, 31)) + + pygame.transform.laplacian(s1, s2) + + # show_image(s1) + # show_image(s2) + + self.assertEqual(s2.get_at((0, 0)), (0, 0, 0, 255)) + self.assertEqual(s2.get_at((3, 10)), (255, 0, 0, 255)) + self.assertEqual(s2.get_at((0, 31)), (255, 0, 0, 255)) + self.assertEqual(s2.get_at((31, 31)), (255, 0, 0, 255)) + + # here we create the return surface. + s2 = pygame.transform.laplacian(s1) + + self.assertEqual(s2.get_at((0, 0)), (0, 0, 0, 255)) + self.assertEqual(s2.get_at((3, 10)), (255, 0, 0, 255)) + self.assertEqual(s2.get_at((0, 31)), (255, 0, 0, 255)) + self.assertEqual(s2.get_at((31, 31)), (255, 0, 0, 255)) + + def test_laplacian__24_big_endian(self): + """ """ + pygame.display.init() + try: + surf_1 = pygame.image.load( + example_path(os.path.join("data", "laplacian.png")) + ) + SIZE = 32 + surf_2 = pygame.Surface((SIZE, SIZE), 0, 24) + # s1.fill((10, 10, 70)) + # pygame.draw.line(s1, (255, 0, 0), (3, 10), (20, 20)) + + # a line at the last row of the image. + # pygame.draw.line(s1, (255, 0, 0), (0, 31), (31, 31)) + + # Also validate keyword arguments + pygame.transform.laplacian(surface=surf_1, dest_surface=surf_2) + + # show_image(s1) + # show_image(s2) + + self.assertEqual(surf_2.get_at((0, 0)), (0, 0, 0, 255)) + self.assertEqual(surf_2.get_at((3, 10)), (255, 0, 0, 255)) + self.assertEqual(surf_2.get_at((0, 31)), (255, 0, 0, 255)) + self.assertEqual(surf_2.get_at((31, 31)), (255, 0, 0, 255)) + + # here we create the return surface. + surf_2 = pygame.transform.laplacian(surf_1) + + self.assertEqual(surf_2.get_at((0, 0)), (0, 0, 0, 255)) + self.assertEqual(surf_2.get_at((3, 10)), (255, 0, 0, 255)) + self.assertEqual(surf_2.get_at((0, 31)), (255, 0, 0, 255)) + self.assertEqual(surf_2.get_at((31, 31)), (255, 0, 0, 255)) + finally: + pygame.display.quit() + + def test_average_surfaces(self): + """ """ + + SIZE = 32 + s1 = pygame.Surface((SIZE, SIZE)) + s2 = pygame.Surface((SIZE, SIZE)) + s3 = pygame.Surface((SIZE, SIZE)) + s1.fill((10, 10, 70)) + s2.fill((10, 20, 70)) + s3.fill((10, 130, 10)) + + surfaces = [s1, s2, s3] + surfaces = [s1, s2] + sr = pygame.transform.average_surfaces(surfaces) + + self.assertEqual(sr.get_at((0, 0)), (10, 15, 70, 255)) + + self.assertRaises(TypeError, pygame.transform.average_surfaces, 1) + self.assertRaises(TypeError, pygame.transform.average_surfaces, []) + + self.assertRaises(TypeError, pygame.transform.average_surfaces, [1]) + self.assertRaises(TypeError, pygame.transform.average_surfaces, [s1, 1]) + self.assertRaises(TypeError, pygame.transform.average_surfaces, [1, s1]) + self.assertRaises(TypeError, pygame.transform.average_surfaces, [s1, s2, 1]) + + self.assertRaises( + TypeError, pygame.transform.average_surfaces, (s for s in [s1, s2, s3]) + ) + + def test_average_surfaces__24(self): + + SIZE = 32 + depth = 24 + s1 = pygame.Surface((SIZE, SIZE), 0, depth) + s2 = pygame.Surface((SIZE, SIZE), 0, depth) + s3 = pygame.Surface((SIZE, SIZE), 0, depth) + s1.fill((10, 10, 70, 255)) + s2.fill((10, 20, 70, 255)) + s3.fill((10, 130, 10, 255)) + + surfaces = [s1, s2, s3] + sr = pygame.transform.average_surfaces(surfaces) + self.assertEqual(sr.get_masks(), s1.get_masks()) + self.assertEqual(sr.get_flags(), s1.get_flags()) + self.assertEqual(sr.get_losses(), s1.get_losses()) + + if 0: + print(sr, s1) + print(sr.get_masks(), s1.get_masks()) + print(sr.get_flags(), s1.get_flags()) + print(sr.get_losses(), s1.get_losses()) + print(sr.get_shifts(), s1.get_shifts()) + + self.assertEqual(sr.get_at((0, 0)), (10, 53, 50, 255)) + + def test_average_surfaces__24_big_endian(self): + pygame.display.init() + try: + surf_1 = pygame.image.load(example_path(os.path.join("data", "BGR.png"))) + + surf_2 = surf_1.copy() + + surfaces = [surf_1, surf_2] + self.assertEqual(surf_1.get_at((0, 0)), (255, 0, 0, 255)) + self.assertEqual(surf_2.get_at((0, 0)), (255, 0, 0, 255)) + + surf_av = pygame.transform.average_surfaces(surfaces) + self.assertEqual(surf_av.get_masks(), surf_1.get_masks()) + self.assertEqual(surf_av.get_flags(), surf_1.get_flags()) + self.assertEqual(surf_av.get_losses(), surf_1.get_losses()) + + self.assertEqual(surf_av.get_at((0, 0)), (255, 0, 0, 255)) + finally: + pygame.display.quit() + + def test_average_surfaces__subclassed_surfaces(self): + """Ensure average_surfaces accepts subclassed surfaces.""" + expected_size = (23, 17) + expected_flags = 0 + expected_depth = 32 + expected_color = (50, 50, 50, 255) + surfaces = [] + + for color in ((40, 60, 40), (60, 40, 60)): + s = test_utils.SurfaceSubclass( + expected_size, expected_flags, expected_depth + ) + s.fill(color) + surfaces.append(s) + + surface = pygame.transform.average_surfaces(surfaces) + + self.assertIsInstance(surface, pygame.Surface) + self.assertNotIsInstance(surface, test_utils.SurfaceSubclass) + self.assertEqual(surface.get_at((0, 0)), expected_color) + self.assertEqual(surface.get_bitsize(), expected_depth) + self.assertEqual(surface.get_size(), expected_size) + self.assertEqual(surface.get_flags(), expected_flags) + + def test_average_surfaces__subclassed_destination_surface(self): + """Ensure average_surfaces accepts a destination subclassed surface.""" + expected_size = (13, 27) + expected_flags = 0 + expected_depth = 32 + expected_color = (15, 15, 15, 255) + surfaces = [] + + for color in ((10, 10, 20), (20, 20, 10), (30, 30, 30)): + s = test_utils.SurfaceSubclass( + expected_size, expected_flags, expected_depth + ) + s.fill(color) + surfaces.append(s) + expected_dest_surface = surfaces.pop() + + # Also validate keyword arguments + dest_surface = pygame.transform.average_surfaces( + surfaces=surfaces, dest_surface=expected_dest_surface + ) + + self.assertIsInstance(dest_surface, pygame.Surface) + self.assertIsInstance(dest_surface, test_utils.SurfaceSubclass) + self.assertIs(dest_surface, expected_dest_surface) + self.assertEqual(dest_surface.get_at((0, 0)), expected_color) + self.assertEqual(dest_surface.get_bitsize(), expected_depth) + self.assertEqual(dest_surface.get_size(), expected_size) + self.assertEqual(dest_surface.get_flags(), expected_flags) + + def test_average_color(self): + """ """ + for i in (24, 32): + with self.subTest(f"Testing {i}-bit surface"): + s = pygame.Surface((32, 32), 0, i) + s.fill((0, 100, 200)) + s.fill((10, 50, 100), (0, 0, 16, 32)) + + self.assertEqual(pygame.transform.average_color(s), (5, 75, 150, 0)) + + # Also validate keyword arguments + avg_color = pygame.transform.average_color( + surface=s, rect=(16, 0, 16, 32) + ) + self.assertEqual(avg_color, (0, 100, 200, 0)) + + def test_rotate(self): + # setting colors and canvas + blue = (0, 0, 255, 255) + red = (255, 0, 0, 255) + black = (0, 0, 0) + canvas = pygame.Surface((3, 3)) + rotation = 0 + + canvas.set_at((2, 0), blue) + canvas.set_at((0, 2), red) + + self.assertEqual(canvas.get_at((0, 0)), black) + self.assertEqual(canvas.get_at((2, 0)), blue) + self.assertEqual(canvas.get_at((0, 2)), red) + + for i in range(0, 4): + if i % 2 == 0: + self.assertEqual(canvas.get_at((0, 0)), black) + elif i == 1: + self.assertEqual(canvas.get_at((0, 0)), blue) + elif i == 3: + self.assertEqual(canvas.get_at((0, 0)), red) + + rotation += 90 + # Also validate keyword arguments + canvas = pygame.transform.rotate(surface=canvas, angle=90) + + self.assertEqual(canvas.get_at((0, 0)), black) + + def test_rotate_of_0_sized_surface(self): + # This function just tests possible Segmentation Fault + canvas1 = pygame.Surface((0, 1)) + canvas2 = pygame.Surface((1, 0)) + pygame.transform.rotate(canvas1, 42) + pygame.transform.rotate(canvas2, 42) + + def test_rotate__lossless_at_90_degrees(self): + w, h = 32, 32 + s = pygame.Surface((w, h), pygame.SRCALPHA) + + gradient = list(test_utils.gradient(w, h)) + + for pt, color in gradient: + s.set_at(pt, color) + + for rotation in (90, -90): + s = pygame.transform.rotate(s, rotation) + + for pt, color in gradient: + self.assertTrue(s.get_at(pt) == color) + + def test_scale2x(self): + + # __doc__ (as of 2008-06-25) for pygame.transform.scale2x: + + # pygame.transform.scale2x(Surface, DestSurface = None): Surface + # specialized image doubler + + w, h = 32, 32 + s = pygame.Surface((w, h), pygame.SRCALPHA, 32) + + # s.set_at((0,0), (20, 20, 20, 255)) + + s1 = pygame.transform.scale2x(s) + # Also validate keyword arguments + s2 = pygame.transform.scale2x(surface=s) + self.assertEqual(s1.get_rect().size, (64, 64)) + self.assertEqual(s2.get_rect().size, (64, 64)) + + def test_scale2xraw(self): + w, h = 32, 32 + s = pygame.Surface((w, h), pygame.SRCALPHA, 32) + s.fill((0, 0, 0)) + pygame.draw.circle(s, (255, 0, 0), (w // 2, h // 2), (w // 3)) + + s2 = pygame.transform.scale(s, (w * 2, h * 2)) + s2_2 = pygame.transform.scale(s2, (w * 4, h * 4)) + s4 = pygame.transform.scale(s, (w * 4, h * 4)) + + self.assertEqual(s2_2.get_rect().size, (128, 128)) + + for pt in test_utils.rect_area_pts(s2_2.get_rect()): + self.assertEqual(s2_2.get_at(pt), s4.get_at(pt)) + + def test_get_smoothscale_backend(self): + filter_type = pygame.transform.get_smoothscale_backend() + self.assertTrue(filter_type in ["GENERIC", "MMX", "SSE"]) + # It would be nice to test if a non-generic type corresponds to an x86 + # processor. But there is no simple test for this. platform.machine() + # returns process version specific information, like 'i686'. + + def test_set_smoothscale_backend(self): + # All machines should allow 'GENERIC'. + original_type = pygame.transform.get_smoothscale_backend() + pygame.transform.set_smoothscale_backend("GENERIC") + filter_type = pygame.transform.get_smoothscale_backend() + self.assertEqual(filter_type, "GENERIC") + # All machines should allow returning to original value. + # Also check that keyword argument works. + pygame.transform.set_smoothscale_backend(backend=original_type) + # Something invalid. + def change(): + pygame.transform.set_smoothscale_backend("mmx") + + self.assertRaises(ValueError, change) + # Invalid argument keyword. + def change(): + pygame.transform.set_smoothscale_backend(t="GENERIC") + + self.assertRaises(TypeError, change) + # Invalid argument type. + def change(): + pygame.transform.set_smoothscale_backend(1) + + self.assertRaises(TypeError, change) + # Unsupported type, if possible. + if original_type != "SSE": + + def change(): + pygame.transform.set_smoothscale_backend("SSE") + + self.assertRaises(ValueError, change) + # Should be back where we started. + filter_type = pygame.transform.get_smoothscale_backend() + self.assertEqual(filter_type, original_type) + + def test_chop(self): + original_surface = pygame.Surface((20, 20)) + pygame.draw.rect(original_surface, (255, 0, 0), (0, 0, 10, 10)) + pygame.draw.rect(original_surface, (0, 255, 0), (0, 10, 10, 10)) + pygame.draw.rect(original_surface, (0, 0, 255), (10, 0, 10, 10)) + pygame.draw.rect(original_surface, (255, 255, 0), (10, 10, 10, 10)) + # Test chopping the corner of image + rect = pygame.Rect(0, 0, 5, 15) + test_surface = pygame.transform.chop(original_surface, rect) + # Check the size of chopped image + self.assertEqual(test_surface.get_size(), (15, 5)) + # Check if the colors of the chopped image are correct + for x in range(15): + for y in range(5): + if x < 5: + self.assertEqual(test_surface.get_at((x, y)), (0, 255, 0)) + else: + self.assertEqual(test_surface.get_at((x, y)), (255, 255, 0)) + # Check if the original image stayed the same + self.assertEqual(original_surface.get_size(), (20, 20)) + for x in range(20): + for y in range(20): + if x < 10 and y < 10: + self.assertEqual(original_surface.get_at((x, y)), (255, 0, 0)) + if x < 10 < y: + self.assertEqual(original_surface.get_at((x, y)), (0, 255, 0)) + if x > 10 > y: + self.assertEqual(original_surface.get_at((x, y)), (0, 0, 255)) + if x > 10 and y > 10: + self.assertEqual(original_surface.get_at((x, y)), (255, 255, 0)) + # Test chopping the center of the surface: + rect = pygame.Rect(0, 0, 10, 10) + rect.center = original_surface.get_rect().center + # Also validate keyword arguments + test_surface = pygame.transform.chop(surface=original_surface, rect=rect) + self.assertEqual(test_surface.get_size(), (10, 10)) + for x in range(10): + for y in range(10): + if x < 5 and y < 5: + self.assertEqual(test_surface.get_at((x, y)), (255, 0, 0)) + if x < 5 < y: + self.assertEqual(test_surface.get_at((x, y)), (0, 255, 0)) + if x > 5 > y: + self.assertEqual(test_surface.get_at((x, y)), (0, 0, 255)) + if x > 5 and y > 5: + self.assertEqual(test_surface.get_at((x, y)), (255, 255, 0)) + # Test chopping with the empty rect + rect = pygame.Rect(10, 10, 0, 0) + test_surface = pygame.transform.chop(original_surface, rect) + self.assertEqual(test_surface.get_size(), (20, 20)) + # Test chopping the entire surface + rect = pygame.Rect(0, 0, 20, 20) + test_surface = pygame.transform.chop(original_surface, rect) + self.assertEqual(test_surface.get_size(), (0, 0)) + # Test chopping outside of surface + rect = pygame.Rect(5, 15, 20, 20) + test_surface = pygame.transform.chop(original_surface, rect) + self.assertEqual(test_surface.get_size(), (5, 15)) + rect = pygame.Rect(400, 400, 10, 10) + test_surface = pygame.transform.chop(original_surface, rect) + self.assertEqual(test_surface.get_size(), (20, 20)) + + def test_rotozoom(self): + + # __doc__ (as of 2008-08-02) for pygame.transform.rotozoom: + + # pygame.transform.rotozoom(Surface, angle, scale): return Surface + # filtered scale and rotation + # + # This is a combined scale and rotation transform. The resulting + # Surface will be a filtered 32-bit Surface. The scale argument is a + # floating point value that will be multiplied by the current + # resolution. The angle argument is a floating point value that + # represents the counterclockwise degrees to rotate. A negative + # rotation angle will rotate clockwise. + + s = pygame.Surface((10, 0)) + pygame.transform.scale(s, (10, 2)) + s1 = pygame.transform.rotozoom(s, 30, 1) + # Also validate keyword arguments + s2 = pygame.transform.rotozoom(surface=s, angle=30, scale=1) + + self.assertEqual(s1.get_rect(), pygame.Rect(0, 0, 0, 0)) + self.assertEqual(s2.get_rect(), pygame.Rect(0, 0, 0, 0)) + + def test_smoothscale(self): + """Tests the stated boundaries, sizing, and color blending of smoothscale function""" + # __doc__ (as of 2008-08-02) for pygame.transform.smoothscale: + + # pygame.transform.smoothscale(Surface, (width, height), DestSurface = + # None): return Surface + # + # scale a surface to an arbitrary size smoothly + # + # Uses one of two different algorithms for scaling each dimension of + # the input surface as required. For shrinkage, the output pixels are + # area averages of the colors they cover. For expansion, a bilinear + # filter is used. For the amd64 and i686 architectures, optimized MMX + # routines are included and will run much faster than other machine + # types. The size is a 2 number sequence for (width, height). This + # function only works for 24-bit or 32-bit surfaces. An exception + # will be thrown if the input surface bit depth is less than 24. + # + # New in pygame 1.8 + + # check stated exceptions + def smoothscale_low_bpp(): + starting_surface = pygame.Surface((20, 20), depth=12) + smoothscaled_surface = pygame.transform.smoothscale( + starting_surface, (10, 10) + ) + + self.assertRaises(ValueError, smoothscale_low_bpp) + + def smoothscale_high_bpp(): + starting_surface = pygame.Surface((20, 20), depth=48) + smoothscaled_surface = pygame.transform.smoothscale( + starting_surface, (10, 10) + ) + + self.assertRaises(ValueError, smoothscale_high_bpp) + + def smoothscale_invalid_scale(): + starting_surface = pygame.Surface((20, 20), depth=32) + smoothscaled_surface = pygame.transform.smoothscale( + starting_surface, (-1, -1) + ) + + self.assertRaises(ValueError, smoothscale_invalid_scale) + + # Test Color Blending Scaling-Up + two_pixel_surface = pygame.Surface((2, 1), depth=32) + two_pixel_surface.fill(pygame.Color(0, 0, 0), pygame.Rect(0, 0, 1, 1)) + two_pixel_surface.fill(pygame.Color(255, 255, 255), pygame.Rect(1, 0, 1, 1)) + for k in [2 ** x for x in range(5, 8)]: # Enlarge to targets 32, 64...256 + bigger_surface = pygame.transform.smoothscale(two_pixel_surface, (k, 1)) + self.assertEqual( + bigger_surface.get_at((k // 2, 0)), pygame.Color(127, 127, 127) + ) + self.assertEqual(bigger_surface.get_size(), (k, 1)) + # Test Color Blending Scaling-Down + two_five_six_surf = pygame.Surface((256, 1), depth=32) + two_five_six_surf.fill(pygame.Color(0, 0, 0), pygame.Rect(0, 0, 128, 1)) + two_five_six_surf.fill(pygame.Color(255, 255, 255), pygame.Rect(128, 0, 128, 1)) + for k in range(3, 11, 2): # Shrink to targets 3, 5...11 pixels wide + smaller_surface = pygame.transform.smoothscale(two_five_six_surf, (k, 1)) + self.assertEqual( + smaller_surface.get_at(((k // 2), 0)), pygame.Color(127, 127, 127) + ) + self.assertEqual(smaller_surface.get_size(), (k, 1)) + + +class TransformDisplayModuleTest(unittest.TestCase): + def setUp(self): + pygame.display.init() + pygame.display.set_mode((320, 200)) + + def tearDown(self): + pygame.display.quit() + + def test_flip(self): + """honors the set_color key on the returned surface from flip.""" + image_loaded = pygame.image.load(example_path("data/chimp.png")) + + image = pygame.Surface(image_loaded.get_size(), 0, 32) + image.blit(image_loaded, (0, 0)) + + image_converted = image_loaded.convert() + + self.assertFalse(image.get_flags() & pygame.SRCALPHA) + self.assertFalse(image_converted.get_flags() & pygame.SRCALPHA) + + surf = pygame.Surface(image.get_size(), 0, 32) + surf2 = pygame.Surface(image.get_size(), 0, 32) + + surf.fill((255, 255, 255)) + surf2.fill((255, 255, 255)) + + colorkey = image.get_at((0, 0)) + image.set_colorkey(colorkey, RLEACCEL) + timage = pygame.transform.flip(image, 1, 0) + + colorkey = image_converted.get_at((0, 0)) + image_converted.set_colorkey(colorkey, RLEACCEL) + # Also validate keyword arguments + timage_converted = pygame.transform.flip( + surface=image_converted, flip_x=1, flip_y=0 + ) + + # blit the flipped surface, and non flipped surface. + surf.blit(timage, (0, 0)) + surf2.blit(image, (0, 0)) + + # the results should be the same. + self.assertEqual(surf.get_at((0, 0)), surf2.get_at((0, 0))) + self.assertEqual(surf2.get_at((0, 0)), (255, 255, 255, 255)) + + # now we test the convert() ed image also works. + surf.fill((255, 255, 255)) + surf2.fill((255, 255, 255)) + surf.blit(timage_converted, (0, 0)) + surf2.blit(image_converted, (0, 0)) + self.assertEqual(surf.get_at((0, 0)), surf2.get_at((0, 0))) + + def test_flip_alpha(self): + """returns a surface with the same properties as the input.""" + image_loaded = pygame.image.load(example_path("data/chimp.png")) + + image_alpha = pygame.Surface(image_loaded.get_size(), pygame.SRCALPHA, 32) + image_alpha.blit(image_loaded, (0, 0)) + + surf = pygame.Surface(image_loaded.get_size(), 0, 32) + surf2 = pygame.Surface(image_loaded.get_size(), 0, 32) + + colorkey = image_alpha.get_at((0, 0)) + image_alpha.set_colorkey(colorkey, RLEACCEL) + timage_alpha = pygame.transform.flip(image_alpha, 1, 0) + + self.assertTrue(image_alpha.get_flags() & pygame.SRCALPHA) + self.assertTrue(timage_alpha.get_flags() & pygame.SRCALPHA) + + # now we test the alpha image works. + surf.fill((255, 255, 255)) + surf2.fill((255, 255, 255)) + surf.blit(timage_alpha, (0, 0)) + surf2.blit(image_alpha, (0, 0)) + self.assertEqual(surf.get_at((0, 0)), surf2.get_at((0, 0))) + self.assertEqual(surf2.get_at((0, 0)), (255, 0, 0, 255)) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/version_test.py b/venv/Lib/site-packages/pygame/tests/version_test.py new file mode 100644 index 0000000..ba0bb3d --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/version_test.py @@ -0,0 +1,48 @@ +import os +import unittest + + +pg_header = os.path.join("src_c", "include", "_pygame.h") + + +class VersionTest(unittest.TestCase): + @unittest.skipIf( + not os.path.isfile(pg_header), "Skipping because we cannot find _pygame.h" + ) + def test_pg_version_consistency(self): + from pygame import version + + pgh_major = -1 + pgh_minor = -1 + pgh_patch = -1 + import re + + major_exp_search = re.compile(r"define\s+PG_MAJOR_VERSION\s+([0-9]+)").search + minor_exp_search = re.compile(r"define\s+PG_MINOR_VERSION\s+([0-9]+)").search + patch_exp_search = re.compile(r"define\s+PG_PATCH_VERSION\s+([0-9]+)").search + with open(pg_header) as f: + for line in f: + if pgh_major == -1: + m = major_exp_search(line) + if m: + pgh_major = int(m.group(1)) + if pgh_minor == -1: + m = minor_exp_search(line) + if m: + pgh_minor = int(m.group(1)) + if pgh_patch == -1: + m = patch_exp_search(line) + if m: + pgh_patch = int(m.group(1)) + self.assertEqual(pgh_major, version.vernum[0]) + self.assertEqual(pgh_minor, version.vernum[1]) + self.assertEqual(pgh_patch, version.vernum[2]) + + def test_sdl_version(self): + from pygame import version + + self.assertEqual(len(version.SDL), 3) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/tests/video_test.py b/venv/Lib/site-packages/pygame/tests/video_test.py new file mode 100644 index 0000000..a6a6473 --- /dev/null +++ b/venv/Lib/site-packages/pygame/tests/video_test.py @@ -0,0 +1,26 @@ +import unittest +import sys +import pygame + +from pygame._sdl2 import video + + +class VideoModuleTest(unittest.TestCase): + default_caption = "pygame window" + + @unittest.skipIf( + not (sys.maxsize > 2 ** 32), + "32 bit SDL 2.0.16 has an issue.", + ) + def test_renderer_set_viewport(self): + """works.""" + window = video.Window(title=self.default_caption, size=(800, 600)) + renderer = video.Renderer(window=window) + renderer.logical_size = (1920, 1080) + rect = pygame.Rect(0, 0, 1920, 1080) + renderer.set_viewport(rect) + self.assertEqual(renderer.get_viewport(), (0, 0, 1920, 1080)) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/pygame/threads/__init__.py b/venv/Lib/site-packages/pygame/threads/__init__.py new file mode 100644 index 0000000..89db392 --- /dev/null +++ b/venv/Lib/site-packages/pygame/threads/__init__.py @@ -0,0 +1,272 @@ +""" +* Experimental * + +Like the map function, but can use a pool of threads. + +Really easy to use threads. eg. tmap(f, alist) + +If you know how to use the map function, you can use threads. +""" + +__author__ = "Rene Dudfield" +__version__ = "0.3.0" +__license__ = "Python license" + +from queue import Queue, Empty +import threading + + +Thread = threading.Thread + +STOP = object() +FINISH = object() + +# DONE_ONE = object() +# DONE_TWO = object() + +# a default worker queue. +_wq = None + +# if we are using threads or not. This is the number of workers. +_use_workers = 0 + +# Set this to the maximum for the amount of Cores/CPUs +# Note, that the tests early out. +# So it should only test the best number of workers +2 +MAX_WORKERS_TO_TEST = 64 + + +def init(number_of_workers=0): + """Does a little test to see if threading is worth it. + Sets up a global worker queue if it's worth it. + + Calling init() is not required, but is generally better to do. + """ + global _wq, _use_workers + + if number_of_workers: + _use_workers = number_of_workers + else: + _use_workers = benchmark_workers() + + # if it is best to use zero workers, then use that. + _wq = WorkerQueue(_use_workers) + + +def quit(): + """cleans up everything.""" + global _wq, _use_workers + _wq.stop() + _wq = None + _use_workers = False + + +def benchmark_workers(a_bench_func=None, the_data=None): + """does a little test to see if workers are at all faster. + Returns the number of workers which works best. + Takes a little bit of time to run, so you should only really call + it once. + You can pass in benchmark data, and functions if you want. + a_bench_func - f(data) + the_data - data to work on. + """ + # TODO: try and make this scale better with slower/faster cpus. + # first find some variables so that using 0 workers takes about 1.0 seconds. + # then go from there. + + # note, this will only work with pygame 1.8rc3+ + # replace the doit() and the_data with something that releases the GIL + + import pygame + import pygame.transform + import time + + if not a_bench_func: + + def doit(x): + return pygame.transform.scale(x, (544, 576)) + + else: + doit = a_bench_func + + if not the_data: + thedata = [pygame.Surface((155, 155), 0, 32) for x in range(10)] + else: + thedata = the_data + + best = time.time() + 100000000 + best_number = 0 + # last_best = -1 + + for num_workers in range(0, MAX_WORKERS_TO_TEST): + + wq = WorkerQueue(num_workers) + t1 = time.time() + for _ in range(20): + print(f"active count:{threading.activeCount()}") + tmap(doit, thedata, worker_queue=wq) + t2 = time.time() + + wq.stop() + + total_time = t2 - t1 + print(f"total time num_workers:{num_workers}: time:{total_time}:") + + if total_time < best: + # last_best = best_number + best_number = num_workers + best = total_time + + if num_workers - best_number > 1: + # We tried to add more, but it didn't like it. + # so we stop with testing at this number. + break + + return best_number + + +class WorkerQueue(object): + def __init__(self, num_workers=20): + self.queue = Queue() + self.pool = [] + self._setup_workers(num_workers) + + def _setup_workers(self, num_workers): + """Sets up the worker threads + NOTE: undefined behaviour if you call this again. + """ + self.pool = [] + + for _ in range(num_workers): + self.pool.append(Thread(target=self.threadloop)) + + for a_thread in self.pool: + a_thread.setDaemon(True) + a_thread.start() + + def do(self, f, *args, **kwArgs): + """puts a function on a queue for running later.""" + self.queue.put((f, args, kwArgs)) + + def stop(self): + """Stops the WorkerQueue, waits for all of the threads to finish up.""" + self.queue.put(STOP) + for thread in self.pool: + thread.join() + + def threadloop(self): # , finish=False): + """Loops until all of the tasks are finished.""" + while True: + args = self.queue.get() + if args is STOP: + self.queue.put(STOP) + self.queue.task_done() + break + try: + args[0](*args[1], **args[2]) + finally: + # clean up the queue, raise the exception. + self.queue.task_done() + # raise + + def wait(self): + """waits until all tasks are complete.""" + self.queue.join() + + +class FuncResult: + """Used for wrapping up a function call so that the results are stored + inside the instances result attribute. + """ + + def __init__(self, f, callback=None, errback=None): + """f - is the function we that we call + callback(result) - this is called when the function(f) returns + errback(exception) - this is called when the function(f) raises + an exception. + """ + self.f = f + self.exception = None + self.result = None + self.callback = callback + self.errback = errback + + def __call__(self, *args, **kwargs): + # we try to call the function here. If it fails we store the exception. + try: + self.result = self.f(*args, **kwargs) + if self.callback: + self.callback(self.result) + except Exception as e: + self.exception = e + if self.errback: + self.errback(self.exception) + + +def tmap(f, seq_args, num_workers=20, worker_queue=None, wait=True, stop_on_error=True): + """like map, but uses a thread pool to execute. + num_workers - the number of worker threads that will be used. If pool + is passed in, then the num_workers arg is ignored. + worker_queue - you can optionally pass in an existing WorkerQueue. + wait - True means that the results are returned when everything is finished. + False means that we return the [worker_queue, results] right away instead. + results, is returned as a list of FuncResult instances. + stop_on_error - + """ + + if worker_queue: + wq = worker_queue + else: + # see if we have a global queue to work with. + if _wq: + wq = _wq + else: + if num_workers == 0: + return map(f, seq_args) + + wq = WorkerQueue(num_workers) + + # we short cut it here if the number of workers is 0. + # normal map should be faster in this case. + if len(wq.pool) == 0: + return map(f, seq_args) + + # print ("queue size:%s" % wq.queue.qsize()) + + # TODO: divide the data (seq_args) into even chunks and + # then pass each thread a map(f, equal_part(seq_args)) + # That way there should be less locking, and overhead. + + results = [] + for sa in seq_args: + results.append(FuncResult(f)) + wq.do(results[-1], sa) + + # wq.stop() + + if wait: + # print ("wait") + wq.wait() + # print ("after wait") + # print ("queue size:%s" % wq.queue.qsize()) + if wq.queue.qsize(): + raise Exception("buggy threadmap") + # if we created a worker queue, we need to stop it. + if not worker_queue and not _wq: + # print ("stoping") + wq.stop() + if wq.queue.qsize(): + um = wq.queue.get() + if not um is STOP: + raise Exception("buggy threadmap") + + # see if there were any errors. If so raise the first one. This matches map behaviour. + # TODO: the traceback doesn't show up nicely. + # NOTE: TODO: we might want to return the results anyway? This should be an option. + if stop_on_error: + error_ones = list(filter(lambda x: x.exception, results)) + if error_ones: + raise error_ones[0].exception + + return map(lambda x: x.result, results) + return [wq, results] diff --git a/venv/Lib/site-packages/pygame/time.pyi b/venv/Lib/site-packages/pygame/time.pyi new file mode 100644 index 0000000..f938442 --- /dev/null +++ b/venv/Lib/site-packages/pygame/time.pyi @@ -0,0 +1,15 @@ +from typing import Union + +from pygame.event import Event + +def get_ticks() -> int: ... +def wait(milliseconds: int) -> int: ... +def delay(milliseconds: int) -> int: ... +def set_timer(event: Union[int, Event], millis: int, loops: int = 0) -> None: ... + +class Clock: + def tick(self, framerate: int = 0) -> int: ... + def tick_busy_loop(self, framerate: int = 0) -> int: ... + def get_time(self) -> int: ... + def get_rawtime(self) -> int: ... + def get_fps(self) -> float: ... diff --git a/venv/Lib/site-packages/pygame/transform.pyi b/venv/Lib/site-packages/pygame/transform.pyi new file mode 100644 index 0000000..4fe8e91 --- /dev/null +++ b/venv/Lib/site-packages/pygame/transform.pyi @@ -0,0 +1,41 @@ +from typing import Optional, Sequence, Union + +from pygame.color import Color +from pygame.surface import Surface + +from ._common import _ColorValue, _Coordinate, _RectValue + +def flip(surface: Surface, flip_x: bool, flip_y: bool) -> Surface: ... +def scale( + surface: Surface, + size: _Coordinate, + dest_surface: Optional[Surface] = None, +) -> Surface: ... +def rotate(surface: Surface, angle: float) -> Surface: ... +def rotozoom(surface: Surface, angle: float, scale: float) -> Surface: ... +def scale2x(surface: Surface, dest_surface: Optional[Surface] = None) -> Surface: ... +def smoothscale( + surface: Surface, + size: _Coordinate, + dest_surface: Optional[Surface] = None, +) -> Surface: ... +def get_smoothscale_backend() -> str: ... +def set_smoothscale_backend(backend: str) -> None: ... +def chop(surface: Surface, rect: _RectValue) -> Surface: ... +def laplacian(surface: Surface, dest_surface: Optional[Surface] = None) -> Surface: ... +def average_surfaces( + surfaces: Sequence[Surface], + dest_surface: Optional[Surface] = None, + palette_colors: Union[bool, int] = 1, +) -> Surface: ... +def average_color(surface: Surface, rect: Optional[_RectValue] = None) -> Color: ... +def threshold( + dest_surface: Optional[Surface], + surface: Surface, + search_color: Optional[_ColorValue], + threshold: Optional[_ColorValue] = (0, 0, 0, 0), + set_color: Optional[_ColorValue] = (0, 0, 0, 0), + set_behavior: Optional[int] = 1, + search_surf: Optional[Surface] = None, + inverse_set: Optional[bool] = False, +) -> int: ... diff --git a/venv/Lib/site-packages/pygame/version.py b/venv/Lib/site-packages/pygame/version.py new file mode 100644 index 0000000..b287dba --- /dev/null +++ b/venv/Lib/site-packages/pygame/version.py @@ -0,0 +1,72 @@ +## pygame - Python Game Library +## Copyright (C) 2000-2003 Pete Shinners +## +## This library is free software; you can redistribute it and/or +## modify it under the terms of the GNU Library General Public +## License as published by the Free Software Foundation; either +## version 2 of the License, or (at your option) any later version. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## Library General Public License for more details. +## +## You should have received a copy of the GNU Library General Public +## License along with this library; if not, write to the Free +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +## +## Pete Shinners +## pete@shinners.org + +"""Simply the current installed pygame version. The version information is +stored in the regular pygame module as 'pygame.ver'. Keeping the version +information also available in a separate module allows you to test the +pygame version without importing the main pygame module. + +The python version information should always compare greater than any previous +releases. (hmm, until we get to versions > 10) +""" +from pygame.base import get_sdl_version + +############### +# This file is generated with version.py.in +## + +class SoftwareVersion(tuple): + """ + A class for storing data about software versions. + """ + __slots__ = () + fields = "major", "minor", "patch" + + def __new__(cls, major, minor, patch): + return tuple.__new__(cls, (major, minor, patch)) + + def __repr__(self): + fields = (f"{fld}={val}" for fld, val in zip(self.fields, self)) + return f"{str(self.__class__.__name__)}({', '.join(fields)})" + + def __str__(self): + return f"{self.major}.{self.minor}.{self.patch}" + + major = property(lambda self: self[0]) + minor = property(lambda self: self[1]) + patch = property(lambda self: self[2]) + +class PygameVersion(SoftwareVersion): + """ + Pygame Version class. + """ + +class SDLVersion(SoftwareVersion): + """ + SDL Version class. + """ + +_sdl_tuple = get_sdl_version() +SDL = SDLVersion(_sdl_tuple[0], _sdl_tuple[1], _sdl_tuple[2]) +ver = "2.1.2" # pylint: disable=invalid-name +vernum = PygameVersion(2, 1, 2) +rev = "" # pylint: disable=invalid-name + +__all__ = ["SDL", "ver", "vernum", "rev"] diff --git a/venv/Lib/site-packages/pygame/version.pyi b/venv/Lib/site-packages/pygame/version.pyi new file mode 100644 index 0000000..41f2132 --- /dev/null +++ b/venv/Lib/site-packages/pygame/version.pyi @@ -0,0 +1,17 @@ +from typing import Tuple + +class SoftwareVersion(Tuple[int, int, int]): + def __new__(cls, major: int, minor: int, patch: int) -> PygameVersion: ... + def __repr__(self) -> str: ... + def __str__(self) -> str: ... + major: int + minor: int + patch: int + +class PygameVersion(SoftwareVersion): ... +class SDLVersion(SoftwareVersion): ... + +SDL: SDLVersion +ver: str +vernum: PygameVersion +rev: str diff --git a/venv/Lib/site-packages/pygame/zlib1.dll b/venv/Lib/site-packages/pygame/zlib1.dll new file mode 100644 index 0000000..e7493de Binary files /dev/null and b/venv/Lib/site-packages/pygame/zlib1.dll differ diff --git a/venv/Lib/site-packages/pylint-2.6.0.dist-info/COPYING b/venv/Lib/site-packages/pylint-2.6.0.dist-info/COPYING new file mode 100644 index 0000000..8c4c849 --- /dev/null +++ b/venv/Lib/site-packages/pylint-2.6.0.dist-info/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/venv/Lib/site-packages/pylint-2.6.0.dist-info/INSTALLER b/venv/Lib/site-packages/pylint-2.6.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/pylint-2.6.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/pylint-2.6.0.dist-info/METADATA b/venv/Lib/site-packages/pylint-2.6.0.dist-info/METADATA new file mode 100644 index 0000000..f2a3785 --- /dev/null +++ b/venv/Lib/site-packages/pylint-2.6.0.dist-info/METADATA @@ -0,0 +1,205 @@ +Metadata-Version: 2.1 +Name: pylint +Version: 2.6.0 +Summary: python code static checker +Home-page: https://github.com/PyCQA/pylint +Author: Python Code Quality Authority +Author-email: code-quality@python.org +License: GPL +Project-URL: What's New, https://pylint.pycqa.org/en/latest/whatsnew/ +Platform: UNKNOWN +Classifier: Development Status :: 6 - Mature +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: GNU General Public License (GPL) +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Software Development :: Debuggers +Classifier: Topic :: Software Development :: Quality Assurance +Classifier: Topic :: Software Development :: Testing +Requires-Python: >=3.5.* +Requires-Dist: astroid (<=2.5,>=2.4.0) +Requires-Dist: isort (<6,>=4.2.5) +Requires-Dist: mccabe (<0.7,>=0.6) +Requires-Dist: toml (>=0.7.1) +Requires-Dist: colorama ; sys_platform=="win32" + + +README for Pylint - https://pylint.pycqa.org/ +============================================= + +.. image:: https://travis-ci.org/PyCQA/pylint.svg?branch=master + :target: https://travis-ci.org/PyCQA/pylint + +.. image:: https://ci.appveyor.com/api/projects/status/rbvwhakyj1y09atb/branch/master?svg=true + :alt: AppVeyor Build Status + :target: https://ci.appveyor.com/project/PCManticore/pylint + +.. image:: https://coveralls.io/repos/github/PyCQA/pylint/badge.svg?branch=master + :target: https://coveralls.io/github/PyCQA/pylint?branch=master + + +.. image:: https://img.shields.io/pypi/v/pylint.svg + :alt: Pypi Package version + :target: https://pypi.python.org/pypi/pylint + +.. image:: https://readthedocs.org/projects/pylint/badge/?version=latest + :target: https://pylint.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status + +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/ambv/black + +.. |tideliftlogo| image:: doc/media/Tidelift_Logos_RGB_Tidelift_Shorthand_On-White_small.png + :width: 75 + :height: 60 + :alt: Tidelift + +.. list-table:: + :widths: 10 100 + + * - |tideliftlogo| + - Professional support for pylint is available as part of the `Tidelift + Subscription`_. Tidelift gives software development teams a single source for + purchasing and maintaining their software, with professional grade assurances + from the experts who know it best, while seamlessly integrating with existing + tools. + +.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-pylint?utm_source=pypi-pylint&utm_medium=referral&utm_campaign=readme + + +====== +Pylint +====== + +**It's not just a linter that annoys you!** + +Pylint is a Python static code analysis tool which looks for programming errors, +helps enforcing a coding standard, sniffs for code smells and offers simple refactoring +suggestions. + +It's highly configurable, having special pragmas to control its errors and warnings +from within your code, as well as from an extensive configuration file. +It is also possible to write your own plugins for adding your own checks or for +extending pylint in one way or another. + +It's a free software distributed under the GNU General Public Licence unless +otherwise specified. + +Development is hosted on GitHub: https://github.com/PyCQA/pylint/ + +You can use the code-quality@python.org mailing list to discuss about +Pylint. Subscribe at https://mail.python.org/mailman/listinfo/code-quality/ +or read the archives at https://mail.python.org/pipermail/code-quality/ + +Pull requests are amazing and most welcome. + +Install +------- + +Pylint can be simply installed by running:: + + pip install pylint + +If you are using Python 3.6+, upgrade to get full support for your version:: + + pip install pylint --upgrade + +If you want to install from a source distribution, extract the tarball and run +the following command :: + + python setup.py install + + +Do make sure to do the same for astroid, which is used internally by pylint. + +For debian and rpm packages, use your usual tools according to your Linux distribution. + +More information about installation and available distribution format +can be found here_. + +Documentation +------------- + +The documentation lives at https://pylint.pycqa.org/. + +Pylint is shipped with following additional commands: + +* pyreverse: an UML diagram generator +* symilar: an independent similarities checker +* epylint: Emacs and Flymake compatible Pylint + + +Testing +------- + +We use tox_ for running the test suite. You should be able to install it with:: + + pip install tox pytest + + +To run the test suite for a particular Python version, you can do:: + + tox -e py37 + + +To run individual tests with ``tox``, you can do:: + + tox -e py37 -- -k name_of_the_test + + +We use pytest_ for testing ``pylint``, which you can use without using ``tox`` for a faster development cycle. + +If you want to run tests on a specific portion of the code with pytest_, (pytest-cov_) and your local python version:: + + # ( pip install pytest-cov ) + # Everything: + python3 -m pytest tests/ + # Everything in tests/message with coverage for the relevant code: + python3 -m pytest tests/message/ --cov=pylint.message + coverage html + # Only the functional test "missing_kwoa_py3": + python3 -m pytest "tests/test_functional.py::test_functional[missing_kwoa_py3]" + + +Do not forget to clone astroid_ and install the last version:: + + + git clone https://github.com/PyCQA/astroid.git + + # From source + python3 astroid/setup.py build sdist + pip3 install astroid/dist/astroid*.tar.gz + + # Using an editable installation + cd astroid + python3 -m pip install -e . + + +For more detailed information, check the documentation. + +.. _here: https://pylint.pycqa.org/en/latest/user_guide/installation.html +.. _tox: https://tox.readthedocs.io/en/latest/ +.. _pytest: https://docs.pytest.org/en/latest/ +.. _pytest-cov: https://pypi.org/project/pytest-cov/ +.. _astroid: https://github.com/PyCQA/astroid + +License +------- + +pylint is, with a few exceptions listed below, `GPLv2 `_. + +The icon files are licensed under the `CC BY-SA 4.0 `_ license: + +- `doc/logo.png `_ +- `doc/logo.svg `_ + + diff --git a/venv/Lib/site-packages/pylint-2.6.0.dist-info/RECORD b/venv/Lib/site-packages/pylint-2.6.0.dist-info/RECORD new file mode 100644 index 0000000..8e62612 --- /dev/null +++ b/venv/Lib/site-packages/pylint-2.6.0.dist-info/RECORD @@ -0,0 +1,188 @@ +../../Scripts/epylint.exe,sha256=YE0PGAB8RTEcr1J2wvlRum47E5YlU7OfTdy5lbr8jJ8,108423 +../../Scripts/pylint.exe,sha256=9bHuYufGxkHDUE47M9IViidGopJRf4gSRsoy1hlIpG0,108421 +../../Scripts/pyreverse.exe,sha256=XcEwAbOv7-D4G9YV4FVKqO2xfJNxpGKsS_gXxSpPHmc,108427 +../../Scripts/symilar.exe,sha256=nVl25hOIJKQOry_ECLoq_PRtAH91AeQIUHaECom3aGU,108423 +pylint-2.6.0.data/scripts/epylint,sha256=ebDphNeMoKus049k5MQbxN1JYsHUsOXZxws0Do6gCG0,51 +pylint-2.6.0.data/scripts/pylint,sha256=wXf1V2_-AB_S1uuYztSS90GiTeCkJ4eBOGEQ7CO2Nmc,53 +pylint-2.6.0.data/scripts/pyreverse,sha256=4UQf7-hfOAx6Ux8d5g0d2KIjpUPRMwFhBdsKsu0gWg0,59 +pylint-2.6.0.data/scripts/symilar,sha256=iz6DGtePyfs0haoFobDfsRsMjaFOizh7E3vsevB2Ipw,55 +pylint-2.6.0.dist-info/COPYING,sha256=-XsUCA3ouEkNYOs9Yg68QZlD4HeUZtHdDV1vaP4ZXc0,17984 +pylint-2.6.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pylint-2.6.0.dist-info/METADATA,sha256=tyNZytHzEEwcJ9VzfKzbveXToNRzjOdN0XDpdJfsk14,6705 +pylint-2.6.0.dist-info/RECORD,, +pylint-2.6.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pylint-2.6.0.dist-info/WHEEL,sha256=EVRjI69F5qVjm_YgqcTXPnTAv3BfSUr0WVAHuSP3Xoo,92 +pylint-2.6.0.dist-info/entry_points.txt,sha256=WUTwHM2ZcExO-VSvss18AMFsQL-XcWg6O3_MwobWfmw,137 +pylint-2.6.0.dist-info/top_level.txt,sha256=j6Z9i__pIuaiCka6Ul9YIy6yI5aw5QbCtldLvZlMksE,7 +pylint/__init__.py,sha256=v4P6u-dsxp2oq7QRVH29e7BT4M5bdn-8YZbwjebaWe0,1159 +pylint/__main__.py,sha256=HRja-2If7jX6FMF5dY7uMVUO2kJ3I0Y0uflK2ckDA5s,585 +pylint/__pkginfo__.py,sha256=3JpKkNXffks0hqvIVBZDhr5bPzHAOPBi-VWcCq7GtU4,4121 +pylint/__pycache__/__init__.cpython-39.pyc,, +pylint/__pycache__/__main__.cpython-39.pyc,, +pylint/__pycache__/__pkginfo__.cpython-39.pyc,, +pylint/__pycache__/constants.cpython-39.pyc,, +pylint/__pycache__/epylint.cpython-39.pyc,, +pylint/__pycache__/exceptions.cpython-39.pyc,, +pylint/__pycache__/graph.cpython-39.pyc,, +pylint/__pycache__/interfaces.cpython-39.pyc,, +pylint/__pycache__/testutils.cpython-39.pyc,, +pylint/checkers/__init__.py,sha256=Xs6vVoNtulCm3eLzOKZXzLydO3CkZoo-LCUi02V9DSw,2203 +pylint/checkers/__pycache__/__init__.cpython-39.pyc,, +pylint/checkers/__pycache__/async.cpython-39.pyc,, +pylint/checkers/__pycache__/base.cpython-39.pyc,, +pylint/checkers/__pycache__/base_checker.cpython-39.pyc,, +pylint/checkers/__pycache__/classes.cpython-39.pyc,, +pylint/checkers/__pycache__/design_analysis.cpython-39.pyc,, +pylint/checkers/__pycache__/exceptions.cpython-39.pyc,, +pylint/checkers/__pycache__/format.cpython-39.pyc,, +pylint/checkers/__pycache__/imports.cpython-39.pyc,, +pylint/checkers/__pycache__/logging.cpython-39.pyc,, +pylint/checkers/__pycache__/misc.cpython-39.pyc,, +pylint/checkers/__pycache__/newstyle.cpython-39.pyc,, +pylint/checkers/__pycache__/python3.cpython-39.pyc,, +pylint/checkers/__pycache__/raw_metrics.cpython-39.pyc,, +pylint/checkers/__pycache__/refactoring.cpython-39.pyc,, +pylint/checkers/__pycache__/similar.cpython-39.pyc,, +pylint/checkers/__pycache__/spelling.cpython-39.pyc,, +pylint/checkers/__pycache__/stdlib.cpython-39.pyc,, +pylint/checkers/__pycache__/strings.cpython-39.pyc,, +pylint/checkers/__pycache__/typecheck.cpython-39.pyc,, +pylint/checkers/__pycache__/utils.cpython-39.pyc,, +pylint/checkers/__pycache__/variables.cpython-39.pyc,, +pylint/checkers/async.py,sha256=JsT7Tz40BzExCxOM1lxOazq8a5U5Qt30NVH7skaVVeg,3524 +pylint/checkers/base.py,sha256=k6S26UCUdr2KhKibI4Py_DXZsVP72oEgJVQSbdu8m5c,96488 +pylint/checkers/base_checker.py,sha256=6EiWxqNjJ69sQYbLNobRY--GDByqH-HUfivDc2EUC6Y,7664 +pylint/checkers/classes.py,sha256=RAiGs_3bN7fLpSq9DE8jwVTfFpQzIEQ7sv5NrzUoTsw,79023 +pylint/checkers/design_analysis.py,sha256=CHrofelHlAVPMx_NzDlLAU4A7lh_F5tOTa47BSEiCBE,16861 +pylint/checkers/exceptions.py,sha256=28OsFP9Qka-WIJEBwSj0058REHMkCt7jTM7sLPVO4Q4,23729 +pylint/checkers/format.py,sha256=HMAD_0DRrLOLHV2vl6dzEpF96FocYlIxbc0EDxyvXGo,28135 +pylint/checkers/imports.py,sha256=XC9a9KhVg3wUT2bytUbDeoQPZX3DUX3Wn_ebD-21nvc,38230 +pylint/checkers/logging.py,sha256=t_EM5pASCXB4ZLpgVm1O4WEXCP08K8ZzyFCqSTfz33M,15919 +pylint/checkers/misc.py,sha256=gVe__qHnXK1RDHXXrByndQd6_VSnWnZcObWKNgViiqE,7241 +pylint/checkers/newstyle.py,sha256=BRTLrHos8vvfB5vnmK2q_XHrDHPlImM6e1ykybq_5_o,5067 +pylint/checkers/python3.py,sha256=qSnqN2HBpELbFDBJ6VOShoUoMyvWhvbHu7ln2vg9rAM,53095 +pylint/checkers/raw_metrics.py,sha256=bi52QkvDD8rBH1tM5wh15-T9KdAXeM_rrSzwdDFJ73s,4040 +pylint/checkers/refactoring.py,sha256=ToWYmRszGgmNfln_eqeqCh_KKjxCPpvhxLvtMtn75tQ,63239 +pylint/checkers/similar.py,sha256=xbPADFB8VPBu4XrVj1LBB1FOMQpg0jQyGJWCw16TXpc,15458 +pylint/checkers/spelling.py,sha256=Dx1ruls8wi0yIqMDb2kJ2kh2tO3_cAGieGDn8Y-dx8k,13867 +pylint/checkers/stdlib.py,sha256=-5laS4-VByRWyD5uJsP7ijHUELdLWT8o4v5FB_ptK44,17690 +pylint/checkers/strings.py,sha256=CIjSzGeyGbNbxsJ86UMKLHZKBtGIodOUMQsPyYV9_MU,38113 +pylint/checkers/typecheck.py,sha256=FgD4diwuE6OXtQBpyPV-8Xl4AFtsX5a5gpWzeMt4LQQ,71732 +pylint/checkers/utils.py,sha256=5j4dc1NEpZywEG1loQ2pe5qlFdJH2I9P1-mhjTEKrn8,45213 +pylint/checkers/variables.py,sha256=cDH63Hwj2l7_nejxVBsn7rtv5S7Bgm23vNWITVJBa48,80398 +pylint/config/__init__.py,sha256=3USGhpgN7m5H7VqsLPjOJsRyjIQswaUv5z1rY1dyBiM,4459 +pylint/config/__pycache__/__init__.cpython-39.pyc,, +pylint/config/__pycache__/configuration_mixin.cpython-39.pyc,, +pylint/config/__pycache__/find_default_config_files.cpython-39.pyc,, +pylint/config/__pycache__/man_help_formatter.cpython-39.pyc,, +pylint/config/__pycache__/option.cpython-39.pyc,, +pylint/config/__pycache__/option_manager_mixin.cpython-39.pyc,, +pylint/config/__pycache__/option_parser.cpython-39.pyc,, +pylint/config/__pycache__/options_provider_mixin.cpython-39.pyc,, +pylint/config/configuration_mixin.py,sha256=2gvNKg1LZBtlnAUqO2OOHFZvgdigfZLswAFO58CzO1Q,1105 +pylint/config/find_default_config_files.py,sha256=sPIxomIQUXvvh-11Ygc-NiBYIrK5wQO_7LMkzqxfo4Y,2103 +pylint/config/man_help_formatter.py,sha256=JZEeNKvjSpdYTY0jV5_PahKqSP8Ei489JH7Uk4oPkkI,3777 +pylint/config/option.py,sha256=jWXPFt3YCALhgmuo5T87TZQ5EbochLAGAj7nArllxrc,5406 +pylint/config/option_manager_mixin.py,sha256=Z2yMMhjb4oUOSuzs7xYYxN__F0Sa9hCha80DeqF2UD8,14470 +pylint/config/option_parser.py,sha256=7-PmG8r5i5N4r5tgRUq1A45sq_pRz8lFMtw33nRST4Y,1689 +pylint/config/options_provider_mixin.py,sha256=vXWVrsnz-zDLW6YlHflJTtvI_QqvqusajJy_YxK8iZg,4176 +pylint/constants.py,sha256=vnKjbOfqog3sjuSN48ZXO6VeQrb0sV43D028rVeZDss,1405 +pylint/epylint.py,sha256=kKt3on5YJw5vXLI9AeO9gIB3u9lH8fkE1ReGlyzPNJw,7240 +pylint/exceptions.py,sha256=WuVt9BlJW92g8fggqy7aCoC9GgSIy9AEpHsiCKo8psU,1153 +pylint/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pylint/extensions/__pycache__/__init__.cpython-39.pyc,, +pylint/extensions/__pycache__/_check_docs_utils.cpython-39.pyc,, +pylint/extensions/__pycache__/bad_builtin.cpython-39.pyc,, +pylint/extensions/__pycache__/broad_try_clause.cpython-39.pyc,, +pylint/extensions/__pycache__/check_docs.cpython-39.pyc,, +pylint/extensions/__pycache__/check_elif.cpython-39.pyc,, +pylint/extensions/__pycache__/comparetozero.cpython-39.pyc,, +pylint/extensions/__pycache__/docparams.cpython-39.pyc,, +pylint/extensions/__pycache__/docstyle.cpython-39.pyc,, +pylint/extensions/__pycache__/emptystring.cpython-39.pyc,, +pylint/extensions/__pycache__/mccabe.cpython-39.pyc,, +pylint/extensions/__pycache__/overlapping_exceptions.cpython-39.pyc,, +pylint/extensions/__pycache__/redefined_variable_type.cpython-39.pyc,, +pylint/extensions/_check_docs_utils.py,sha256=X-phX6z3Znthcuq4BpgMZR-3Z-cS3iRgIMHlwq4uIXM,23564 +pylint/extensions/bad_builtin.py,sha256=nCYJ4nGEvbTnB6AlPMx_IBjb2bWFu3rkz6ThW_pQ6Ac,2510 +pylint/extensions/broad_try_clause.py,sha256=nIOTZfOVGsM4fp50yyaes-z--iAlYvgQcbvlA_W5i3Q,2331 +pylint/extensions/check_docs.py,sha256=SJvB9OaaPeA5GsWZRofYuUlfP6u_Wny4Ugog0OqtzGs,796 +pylint/extensions/check_elif.py,sha256=rj3FgaXcCylZTb_PWraCCOnmzkPuA0hLc3CZo3lg8hA,2614 +pylint/extensions/comparetozero.py,sha256=MeVUIYTv4kFEHbBZHAjQXbIa1LbnHK9VncEoZKxHe5w,2469 +pylint/extensions/docparams.py,sha256=fCQC3z2gX6CbUCv6cGaIeF1ps_icrvIYI8Eu_ul32MY,20437 +pylint/extensions/docstyle.py,sha256=bG8V4n9fXjWrSyXl3ZKi5gNnVogEgcroJo9wxykKGEM,3035 +pylint/extensions/emptystring.py,sha256=kkk35STu_Bsm9Boi1sjVTCa7ZeB5duo3I1fbjWKjUfI,2568 +pylint/extensions/mccabe.py,sha256=7jupZPjE0a5SsfxhSj9O3al0j6vjR_J18q7cCSTzGLY,6278 +pylint/extensions/overlapping_exceptions.py,sha256=Qsi7qIF6sx36HYV8cjKjPcgYRZNPiFIg4NEcefjGFyg,3266 +pylint/extensions/redefined_variable_type.py,sha256=qopv8bgRcPOiQoa8c6btH0trTQEt2tCRm4sug6qOwjM,4333 +pylint/graph.py,sha256=jj1v2fqQrGAhjdPOLVAzOsqLFR9ce7LTVyyFKjaAhTQ,6528 +pylint/interfaces.py,sha256=jSpQ-c3PGqLZF7LsJue5gHz6IdYire9ki7cieG6xdfE,3235 +pylint/lint/__init__.py,sha256=FkrvfVY1gTb6syeGkvNDM37-0pXXOmR8qu0ig95CQ9M,4188 +pylint/lint/__pycache__/__init__.cpython-39.pyc,, +pylint/lint/__pycache__/check_parallel.cpython-39.pyc,, +pylint/lint/__pycache__/pylinter.cpython-39.pyc,, +pylint/lint/__pycache__/report_functions.cpython-39.pyc,, +pylint/lint/__pycache__/run.cpython-39.pyc,, +pylint/lint/__pycache__/utils.cpython-39.pyc,, +pylint/lint/check_parallel.py,sha256=Jov2r9_0_hjRBfOC0ZYSyU67dY99pv-idEIE5fBnN3I,3973 +pylint/lint/pylinter.py,sha256=ZRjQ7iSTbI6lC0HroM7urKdooqcfCpVN1ss05mjOzRo,45795 +pylint/lint/report_functions.py,sha256=4jB7bRHENFdvY4xXMamIC1VaQdrYdyp-629KujV-pI8,2750 +pylint/lint/run.py,sha256=lq3iu62kTYIIXXsHbDFnf8rIx7MxEMpKJ30fHNmYZA8,17223 +pylint/lint/utils.py,sha256=glQ5R9CNfpDL6Kj9lysnlUOOpOGuMP_sLA2gUpA1m2w,2308 +pylint/message/__init__.py,sha256=sgVx9YmL9b84Y6TgsfOKHJchXnxOd-EGV52wEKWLLe8,2807 +pylint/message/__pycache__/__init__.cpython-39.pyc,, +pylint/message/__pycache__/message.cpython-39.pyc,, +pylint/message/__pycache__/message_definition.cpython-39.pyc,, +pylint/message/__pycache__/message_definition_store.cpython-39.pyc,, +pylint/message/__pycache__/message_handler_mix_in.cpython-39.pyc,, +pylint/message/__pycache__/message_id_store.cpython-39.pyc,, +pylint/message/message.py,sha256=eJQ6x3SKMQpD6aLn4x2tYT4NSUy4qWzVhl_0Am5R5WI,1300 +pylint/message/message_definition.py,sha256=o7zckciMEunKoi3wz7U2m507HsXD4IeHuPJ-anURyi8,2993 +pylint/message/message_definition_store.py,sha256=aQi_4Z_tEw9lxQyn07-w_BapJLd04OcZIJ5A4tLgxho,3535 +pylint/message/message_handler_mix_in.py,sha256=BcHlarVGm-ySZOmMOKSmJ-jQlQhVXA6HYpFw4p1_ZYc,15208 +pylint/message/message_id_store.py,sha256=Nri4iRo9t5QefzJP9MU0phz66dBZ3ienVNRqQNQoDac,5291 +pylint/pyreverse/__init__.py,sha256=runafCn0veg0di-i8TztMGlKEJO3Qg01MICGqDgZ0c0,202 +pylint/pyreverse/__pycache__/__init__.cpython-39.pyc,, +pylint/pyreverse/__pycache__/diadefslib.cpython-39.pyc,, +pylint/pyreverse/__pycache__/diagrams.cpython-39.pyc,, +pylint/pyreverse/__pycache__/inspector.cpython-39.pyc,, +pylint/pyreverse/__pycache__/main.cpython-39.pyc,, +pylint/pyreverse/__pycache__/utils.cpython-39.pyc,, +pylint/pyreverse/__pycache__/vcgutils.cpython-39.pyc,, +pylint/pyreverse/__pycache__/writer.cpython-39.pyc,, +pylint/pyreverse/diadefslib.py,sha256=9y9COGVkaeWlMbuMh0PH0ka5FXuN5jvOjEZAPbtZAdI,8754 +pylint/pyreverse/diagrams.py,sha256=PAuxP25QXqEmQgFpJDHxCEKHo9EIpB7o8cYFITe3FGc,9035 +pylint/pyreverse/inspector.py,sha256=RyFmZ_8IEH59EpXOqkS1d3KsqTdn_LWu-_a3fNu08QU,12257 +pylint/pyreverse/main.py,sha256=FIrqeVfxM8fje0QprImOFLeiz4s7oawOMXoa5yJEPqA,6528 +pylint/pyreverse/utils.py,sha256=-pmBeypy9i6GRD4oBdaudBYCZfMoXXQUENWZBS9geU0,6351 +pylint/pyreverse/vcgutils.py,sha256=5IsM9m21JZ5n-1edmqi1EHFK2ZYy2IX1WzfI8Uoe4Ts,6584 +pylint/pyreverse/writer.py,sha256=10wgUZ-8ANHgCvI2c1ZkukcAeZ-dfbJ_MWL75MoRCuI,8003 +pylint/reporters/__init__.py,sha256=dVj9-p_ireGR0jF2qxsu54a-0H_jxDafNiMUUVuHWH4,1650 +pylint/reporters/__pycache__/__init__.cpython-39.pyc,, +pylint/reporters/__pycache__/base_reporter.cpython-39.pyc,, +pylint/reporters/__pycache__/collecting_reporter.cpython-39.pyc,, +pylint/reporters/__pycache__/json_reporter.cpython-39.pyc,, +pylint/reporters/__pycache__/reports_handler_mix_in.cpython-39.pyc,, +pylint/reporters/__pycache__/text.cpython-39.pyc,, +pylint/reporters/base_reporter.py,sha256=HilNSVW_QAG34uY73b01eLlK-RPMgA62O4gk19rVIm8,2031 +pylint/reporters/collecting_reporter.py,sha256=tFJ0rsTNz9h4C0U5lgbe1jlQAOy0Of0WLGrq2QO7Sug,478 +pylint/reporters/json_reporter.py,sha256=JzakpeEjYZVFjtkpjmiU_die-zSugOONpSb6UHW91Ls,1996 +pylint/reporters/reports_handler_mix_in.py,sha256=t4Ucmk5Wa2CagNbEbehlr1n6H-4zmRnrCEvI57qVuig,2704 +pylint/reporters/text.py,sha256=tAMiL676mppZonTqGGUK9EAXv9q7rT_Np8GE0L_phj4,8087 +pylint/reporters/ureports/__init__.py,sha256=UteHDRjY2qMHwLUpA3McgaBMTdQnMTKrVRZ5A_WZybA,3235 +pylint/reporters/ureports/__pycache__/__init__.cpython-39.pyc,, +pylint/reporters/ureports/__pycache__/nodes.cpython-39.pyc,, +pylint/reporters/ureports/__pycache__/text_writer.cpython-39.pyc,, +pylint/reporters/ureports/nodes.py,sha256=7ze_4YQHtNpx8wdsQHtU0sAMOSWVcIvaoKe4eVWnYJM,5193 +pylint/reporters/ureports/text_writer.py,sha256=SuKF0eKZcLvF457lXJyxFVk-M3epvAXCesKo6T2aBlU,3373 +pylint/testutils.py,sha256=bWQ0rsxptVTQRIEavbDahP_pzgy1Nbh4hYe5PicAu8w,20452 +pylint/utils/__init__.py,sha256=LR5PAyLJhLu7dDWCBkeCGN00MqPYz6pgkr_wFSrfqCA,2984 +pylint/utils/__pycache__/__init__.cpython-39.pyc,, +pylint/utils/__pycache__/ast_walker.cpython-39.pyc,, +pylint/utils/__pycache__/file_state.cpython-39.pyc,, +pylint/utils/__pycache__/pragma_parser.cpython-39.pyc,, +pylint/utils/__pycache__/utils.cpython-39.pyc,, +pylint/utils/ast_walker.py,sha256=6ewsiRTz1W4v9UFm-lXMZoBWEe8b89kZRrSN7bW3aiM,2907 +pylint/utils/file_state.py,sha256=zw-4J5JasNZPhmcTbDUwiqaXpPWCIpPdYizvyGlnvCo,5962 +pylint/utils/pragma_parser.py,sha256=FuAydaJb_O6RMbVVyZg83eACKVuWxurtc5n1Gxz6E3Q,4799 +pylint/utils/utils.py,sha256=ahZtvd-OXZfJA_4l9KWoBb5TIfx_6zHdKvdSqZeNtns,14497 diff --git a/venv/Lib/site-packages/pylint-2.6.0.dist-info/REQUESTED b/venv/Lib/site-packages/pylint-2.6.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/pylint-2.6.0.dist-info/WHEEL b/venv/Lib/site-packages/pylint-2.6.0.dist-info/WHEEL new file mode 100644 index 0000000..83ff02e --- /dev/null +++ b/venv/Lib/site-packages/pylint-2.6.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.35.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/pylint-2.6.0.dist-info/entry_points.txt b/venv/Lib/site-packages/pylint-2.6.0.dist-info/entry_points.txt new file mode 100644 index 0000000..063b5e4 --- /dev/null +++ b/venv/Lib/site-packages/pylint-2.6.0.dist-info/entry_points.txt @@ -0,0 +1,6 @@ +[console_scripts] +epylint = pylint:run_epylint +pylint = pylint:run_pylint +pyreverse = pylint:run_pyreverse +symilar = pylint:run_symilar + diff --git a/venv/Lib/site-packages/pylint-2.6.0.dist-info/top_level.txt b/venv/Lib/site-packages/pylint-2.6.0.dist-info/top_level.txt new file mode 100644 index 0000000..7fb0ea1 --- /dev/null +++ b/venv/Lib/site-packages/pylint-2.6.0.dist-info/top_level.txt @@ -0,0 +1 @@ +pylint diff --git a/venv/Lib/site-packages/pytest-6.0.1.dist-info/INSTALLER b/venv/Lib/site-packages/pytest-6.0.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/pytest-6.0.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/pytest-6.0.1.dist-info/LICENSE b/venv/Lib/site-packages/pytest-6.0.1.dist-info/LICENSE new file mode 100644 index 0000000..d14fb7f --- /dev/null +++ b/venv/Lib/site-packages/pytest-6.0.1.dist-info/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2004-2020 Holger Krekel and others + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/venv/Lib/site-packages/pytest-6.0.1.dist-info/METADATA b/venv/Lib/site-packages/pytest-6.0.1.dist-info/METADATA new file mode 100644 index 0000000..b193773 --- /dev/null +++ b/venv/Lib/site-packages/pytest-6.0.1.dist-info/METADATA @@ -0,0 +1,212 @@ +Metadata-Version: 2.1 +Name: pytest +Version: 6.0.1 +Summary: pytest: simple powerful testing with Python +Home-page: https://docs.pytest.org/en/latest/ +Author: Holger Krekel, Bruno Oliveira, Ronny Pfannschmidt, Floris Bruynooghe, Brianna Laugher, Florian Bruhin and others +License: MIT +Project-URL: Source, https://github.com/pytest-dev/pytest +Project-URL: Tracker, https://github.com/pytest-dev/pytest/issues +Keywords: test,unittest +Platform: unix +Platform: linux +Platform: osx +Platform: cygwin +Platform: win32 +Classifier: Development Status :: 6 - Mature +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: POSIX +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Software Development :: Testing +Classifier: Topic :: Utilities +Requires-Python: >=3.5 +Description-Content-Type: text/x-rst +Requires-Dist: attrs (>=17.4.0) +Requires-Dist: iniconfig +Requires-Dist: more-itertools (>=4.0.0) +Requires-Dist: packaging +Requires-Dist: pluggy (<1.0,>=0.12) +Requires-Dist: py (>=1.8.2) +Requires-Dist: toml +Requires-Dist: pathlib2 (>=2.2.0) ; python_version < "3.6" +Requires-Dist: importlib-metadata (>=0.12) ; python_version < "3.8" +Requires-Dist: atomicwrites (>=1.0) ; sys_platform == "win32" +Requires-Dist: colorama ; sys_platform == "win32" +Provides-Extra: checkqa_mypy +Requires-Dist: mypy (==0.780) ; extra == 'checkqa_mypy' +Provides-Extra: testing +Requires-Dist: argcomplete ; extra == 'testing' +Requires-Dist: hypothesis (>=3.56) ; extra == 'testing' +Requires-Dist: mock ; extra == 'testing' +Requires-Dist: nose ; extra == 'testing' +Requires-Dist: requests ; extra == 'testing' +Requires-Dist: xmlschema ; extra == 'testing' + +.. image:: https://docs.pytest.org/en/stable/_static/pytest1.png + :target: https://docs.pytest.org/en/stable/ + :align: center + :alt: pytest + + +------ + +.. image:: https://img.shields.io/pypi/v/pytest.svg + :target: https://pypi.org/project/pytest/ + +.. image:: https://img.shields.io/conda/vn/conda-forge/pytest.svg + :target: https://anaconda.org/conda-forge/pytest + +.. image:: https://img.shields.io/pypi/pyversions/pytest.svg + :target: https://pypi.org/project/pytest/ + +.. image:: https://codecov.io/gh/pytest-dev/pytest/branch/master/graph/badge.svg + :target: https://codecov.io/gh/pytest-dev/pytest + :alt: Code coverage Status + +.. image:: https://travis-ci.org/pytest-dev/pytest.svg?branch=master + :target: https://travis-ci.org/pytest-dev/pytest + +.. image:: https://dev.azure.com/pytest-dev/pytest/_apis/build/status/pytest-CI?branchName=master + :target: https://dev.azure.com/pytest-dev/pytest + +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/psf/black + +.. image:: https://www.codetriage.com/pytest-dev/pytest/badges/users.svg + :target: https://www.codetriage.com/pytest-dev/pytest + +.. image:: https://readthedocs.org/projects/pytest/badge/?version=latest + :target: https://pytest.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status + +The ``pytest`` framework makes it easy to write small tests, yet +scales to support complex functional testing for applications and libraries. + +An example of a simple test: + +.. code-block:: python + + # content of test_sample.py + def inc(x): + return x + 1 + + + def test_answer(): + assert inc(3) == 5 + + +To execute it:: + + $ pytest + ============================= test session starts ============================= + collected 1 items + + test_sample.py F + + ================================== FAILURES =================================== + _________________________________ test_answer _________________________________ + + def test_answer(): + > assert inc(3) == 5 + E assert 4 == 5 + E + where 4 = inc(3) + + test_sample.py:5: AssertionError + ========================== 1 failed in 0.04 seconds =========================== + + +Due to ``pytest``'s detailed assertion introspection, only plain ``assert`` statements are used. See `getting-started `_ for more examples. + + +Features +-------- + +- Detailed info on failing `assert statements `_ (no need to remember ``self.assert*`` names); + +- `Auto-discovery + `_ + of test modules and functions; + +- `Modular fixtures `_ for + managing small or parametrized long-lived test resources; + +- Can run `unittest `_ (or trial), + `nose `_ test suites out of the box; + +- Python 3.5+ and PyPy3; + +- Rich plugin architecture, with over 850+ `external plugins `_ and thriving community; + + +Documentation +------------- + +For full documentation, including installation, tutorials and PDF documents, please see https://docs.pytest.org/en/stable/. + + +Bugs/Requests +------------- + +Please use the `GitHub issue tracker `_ to submit bugs or request features. + + +Changelog +--------- + +Consult the `Changelog `__ page for fixes and enhancements of each version. + + +Support pytest +-------------- + +`Open Collective`_ is an online funding platform for open and transparent communities. +It provides tools to raise money and share your finances in full transparency. + +It is the platform of choice for individuals and companies that want to make one-time or +monthly donations directly to the project. + +See more details in the `pytest collective`_. + +.. _Open Collective: https://opencollective.com +.. _pytest collective: https://opencollective.com/pytest + + +pytest for enterprise +--------------------- + +Available as part of the Tidelift Subscription. + +The maintainers of pytest and thousands of other packages are working with Tidelift to deliver commercial support and +maintenance for the open source dependencies you use to build your applications. +Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. + +`Learn more. `_ + +Security +^^^^^^^^ + +pytest has never been associated with a security vulnerability, but in any case, to report a +security vulnerability please use the `Tidelift security contact `_. +Tidelift will coordinate the fix and disclosure. + + +License +------- + +Copyright Holger Krekel and others, 2004-2020. + +Distributed under the terms of the `MIT`_ license, pytest is free and open source software. + +.. _`MIT`: https://github.com/pytest-dev/pytest/blob/master/LICENSE + + diff --git a/venv/Lib/site-packages/pytest-6.0.1.dist-info/RECORD b/venv/Lib/site-packages/pytest-6.0.1.dist-info/RECORD new file mode 100644 index 0000000..6d31dc3 --- /dev/null +++ b/venv/Lib/site-packages/pytest-6.0.1.dist-info/RECORD @@ -0,0 +1,136 @@ +../../Scripts/py.test.exe,sha256=mFfxGJcXlZD-ghTgYRraN-R6-W2Th9JuX9skfgPphOA,108425 +../../Scripts/pytest.exe,sha256=mFfxGJcXlZD-ghTgYRraN-R6-W2Th9JuX9skfgPphOA,108425 +_pytest/__init__.py,sha256=6Ff5v_9CZKpy1l87AT5cIHOfMA9kdTtzhl2G3QjYC9Q,239 +_pytest/__pycache__/__init__.cpython-39.pyc,, +_pytest/__pycache__/_argcomplete.cpython-39.pyc,, +_pytest/__pycache__/_version.cpython-39.pyc,, +_pytest/__pycache__/cacheprovider.cpython-39.pyc,, +_pytest/__pycache__/capture.cpython-39.pyc,, +_pytest/__pycache__/compat.cpython-39.pyc,, +_pytest/__pycache__/debugging.cpython-39.pyc,, +_pytest/__pycache__/deprecated.cpython-39.pyc,, +_pytest/__pycache__/doctest.cpython-39.pyc,, +_pytest/__pycache__/faulthandler.cpython-39.pyc,, +_pytest/__pycache__/fixtures.cpython-39.pyc,, +_pytest/__pycache__/freeze_support.cpython-39.pyc,, +_pytest/__pycache__/helpconfig.cpython-39.pyc,, +_pytest/__pycache__/hookspec.cpython-39.pyc,, +_pytest/__pycache__/junitxml.cpython-39.pyc,, +_pytest/__pycache__/logging.cpython-39.pyc,, +_pytest/__pycache__/main.cpython-39.pyc,, +_pytest/__pycache__/monkeypatch.cpython-39.pyc,, +_pytest/__pycache__/nodes.cpython-39.pyc,, +_pytest/__pycache__/nose.cpython-39.pyc,, +_pytest/__pycache__/outcomes.cpython-39.pyc,, +_pytest/__pycache__/pastebin.cpython-39.pyc,, +_pytest/__pycache__/pathlib.cpython-39.pyc,, +_pytest/__pycache__/pytester.cpython-39.pyc,, +_pytest/__pycache__/python.cpython-39.pyc,, +_pytest/__pycache__/python_api.cpython-39.pyc,, +_pytest/__pycache__/recwarn.cpython-39.pyc,, +_pytest/__pycache__/reports.cpython-39.pyc,, +_pytest/__pycache__/resultlog.cpython-39.pyc,, +_pytest/__pycache__/runner.cpython-39.pyc,, +_pytest/__pycache__/setuponly.cpython-39.pyc,, +_pytest/__pycache__/setupplan.cpython-39.pyc,, +_pytest/__pycache__/skipping.cpython-39.pyc,, +_pytest/__pycache__/stepwise.cpython-39.pyc,, +_pytest/__pycache__/store.cpython-39.pyc,, +_pytest/__pycache__/terminal.cpython-39.pyc,, +_pytest/__pycache__/timing.cpython-39.pyc,, +_pytest/__pycache__/tmpdir.cpython-39.pyc,, +_pytest/__pycache__/unittest.cpython-39.pyc,, +_pytest/__pycache__/warning_types.cpython-39.pyc,, +_pytest/__pycache__/warnings.cpython-39.pyc,, +_pytest/_argcomplete.py,sha256=Wn2_xZnX5VnIzU6GS2gYS-1Z1Utrb2QnbTo_6LRqFGc,3840 +_pytest/_code/__init__.py,sha256=hRFEUoAI9vIqEAqJYoFe7bPJUAtdRAqwPDGuqRub0xs,481 +_pytest/_code/__pycache__/__init__.cpython-39.pyc,, +_pytest/_code/__pycache__/code.cpython-39.pyc,, +_pytest/_code/__pycache__/source.cpython-39.pyc,, +_pytest/_code/code.py,sha256=qB35L3JtbcdRwZJ4SRwo5JTcSUJKwT5x4SMvMkygDwI,43268 +_pytest/_code/source.py,sha256=CZLUpeKraP2Ha99S68fUUfhCUI_VkL95zmVWuS3PSiw,7164 +_pytest/_io/__init__.py,sha256=NWs125Ln6IqP5BZNw-V2iN_yYPwGM7vfrAP5ta6MhPA,154 +_pytest/_io/__pycache__/__init__.cpython-39.pyc,, +_pytest/_io/__pycache__/saferepr.cpython-39.pyc,, +_pytest/_io/__pycache__/terminalwriter.cpython-39.pyc,, +_pytest/_io/__pycache__/wcwidth.cpython-39.pyc,, +_pytest/_io/saferepr.py,sha256=xb5m9i75G1tR14jBqMi_cTSNBZMIyIISoEDqi7jHfC4,3777 +_pytest/_io/terminalwriter.py,sha256=spc1hwJ6P_Vm1oLKm1kiJF7w9qlJooE4A2QjGCpBAeE,7173 +_pytest/_io/wcwidth.py,sha256=YhE3To-vBI7udLtV4B-g-04S3l8VoRD5ki935QipmJA,1253 +_pytest/_version.py,sha256=Je-pWPIQApt-lxl-2rkm_V07IBA9GoZyAfM1pw3b3wM,116 +_pytest/assertion/__init__.py,sha256=KSp_iha7NXCI3Gefc38kaSfd0tlQkjfW1phDP-JjDVg,6413 +_pytest/assertion/__pycache__/__init__.cpython-39.pyc,, +_pytest/assertion/__pycache__/rewrite.cpython-39.pyc,, +_pytest/assertion/__pycache__/truncate.cpython-39.pyc,, +_pytest/assertion/__pycache__/util.cpython-39.pyc,, +_pytest/assertion/rewrite.py,sha256=lgU1lNdmlLagKEVbmGLWDXiGrr79hlF0neiuNB1mo7I,42695 +_pytest/assertion/truncate.py,sha256=7r9TPCE5bYxjthVe7NqwtQ-o29n1gqYnYpd-kbqIHjs,3490 +_pytest/assertion/util.py,sha256=sGV-g064RXO62AEYuB5RbBbPHJw4gS65FggzodELNd0,16091 +_pytest/cacheprovider.py,sha256=ktrn6AZhUts8fy9i827nC8mrQ5gRogaxc1YGzn3ttYU,19676 +_pytest/capture.py,sha256=2Vrd0rB6cHh5fOLGJ91xG7dpFJ3MTH5RI0xkZ6T1tJ4,29359 +_pytest/compat.py,sha256=c_xWOeOkApJcU2FKT0fpt35s-KEN0OKfg8wLYCfm3EI,13008 +_pytest/config/__init__.py,sha256=tlMzLq7xEqwo5RBlX42fXanp-PYOWYu-JKFYDx7hkdo,51092 +_pytest/config/__pycache__/__init__.cpython-39.pyc,, +_pytest/config/__pycache__/argparsing.cpython-39.pyc,, +_pytest/config/__pycache__/exceptions.cpython-39.pyc,, +_pytest/config/__pycache__/findpaths.cpython-39.pyc,, +_pytest/config/argparsing.py,sha256=U_eTy6h6Zv1hpDXDwX1XpPUs1I3Box8x0Sp4I7fJ7DM,20618 +_pytest/config/exceptions.py,sha256=FV9c9gokOPH9rgPJZVQbTrtMnuuoRMLRzcx9p7zpu7c,229 +_pytest/config/findpaths.py,sha256=zjN3vjrHJJC-qtPccNotcAflUxJIK40nWMr42lx6Sa8,7121 +_pytest/debugging.py,sha256=6xgWhxaWa4jZSDOfiPr9wVJwCB0HjlMgVoKCFtzLwvo,12990 +_pytest/deprecated.py,sha256=gzX7zk6cY_7DMskjd4aPDDPVD56RSBRdhf7qMJhr41o,3296 +_pytest/doctest.py,sha256=zpaprweprFPB_kxyZDJhtr2OcVYu0qQASo_W2WGIDnU,25395 +_pytest/faulthandler.py,sha256=wKJZznRjGGgS8N7I1mSsz1PkAgxBgQq_3WZ9TWYAggg,4177 +_pytest/fixtures.py,sha256=_HvoC7sTfIH-dnFCeNMJirxr-4XBMyzW_9G6cq9LG04,65720 +_pytest/freeze_support.py,sha256=IpSZqy0sAVtX0RRjcY8jxqpErJWwLWd-dBunHZtvxBk,1416 +_pytest/helpconfig.py,sha256=HOvT5LE7nX3Sn7sRQj-rxJwmYQdmPab6rWTjPcIwbow,8450 +_pytest/hookspec.py,sha256=Vxj9I8NdUmPSygKgW_ozoPiZlO6GTvFmqy7clqGKp08,30698 +_pytest/junitxml.py,sha256=tv8tnZhN8j1IUTc2cCCuefF0r2K9kK-HYkXGRQBsUYQ,25736 +_pytest/logging.py,sha256=r_WppEFOxahYVd3Aq-0hy7VNge45GsPKU0JNayTqYXw,30000 +_pytest/main.py,sha256=k7vGrDofkPJKQ88aSbRewjMVK2FxLKwE4XT9XAa-Ufo,28359 +_pytest/mark/__init__.py,sha256=eabvUZLDD2uRffGX7ZNtwi3JyDCrDfdknTdH18-zADM,8941 +_pytest/mark/__pycache__/__init__.cpython-39.pyc,, +_pytest/mark/__pycache__/expression.cpython-39.pyc,, +_pytest/mark/__pycache__/structures.cpython-39.pyc,, +_pytest/mark/expression.py,sha256=pD9mKPZiWMgL6zN9osAEiNQabK5Wn5pGPVYQaz8uhsE,6436 +_pytest/mark/structures.py,sha256=cUbfJKCKh38toKCswdFl8pAfEVnL57ibfbTvqhkj1po,19236 +_pytest/monkeypatch.py,sha256=j22OZWSvtFh3t82ABc01hn6vJWiFhY-dSTNWupT3eoU,13104 +_pytest/nodes.py,sha256=OEq86eJ5HnRkngPzgaXLPxQAGkTC0sc_FUCNYbLxhLs,22899 +_pytest/nose.py,sha256=rLAxQ98HX2z_EUx3pE-5LTFinaexa2iGfdi2SXgLQOk,1358 +_pytest/outcomes.py,sha256=pQSdBLffSSTOAZqExJDXyJCgv8agbhjIB4P7s2EhOjg,7441 +_pytest/pastebin.py,sha256=ibPjjMXhyDlYN1BdG3UBw6kakLVXFfBkiv-lnxc46jU,3980 +_pytest/pathlib.py,sha256=Mq9KZX1UI-AEUkbubDs428TO9iXtx769Fv7sS_KH0Xs,18348 +_pytest/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +_pytest/pytester.py,sha256=Ub_NOrZDi7tqyvpo0xLK4hNQnccW9tfxKy4MA_lq634,55813 +_pytest/python.py,sha256=DpiguAC7g5KTnQNVEVIZomV-rYE7WC4kydZXV4E70Hk,61927 +_pytest/python_api.py,sha256=B3R6IquxeN9Pn55a2MHB8RL3NmkKO_f2DQDZBtyLueQ,28612 +_pytest/recwarn.py,sha256=9DplrUPBBbxaA1Oi-A2L2fDaPtnzpozoOzE-m_NF1aY,10179 +_pytest/reports.py,sha256=CgxjpEtUv_Dd8EXDgLV6M9wANrW17Tn5PMN1KGD153w,18614 +_pytest/resultlog.py,sha256=Y8VUu7EZsx33WiA1QjlWRl_CmPpW1RRbeBrqs8NZuuY,3655 +_pytest/runner.py,sha256=lh8JGb19Y-bl65vq4FT3V0rwTZUKATIoxsJ9lVneAQs,15399 +_pytest/setuponly.py,sha256=14kzmupxytOIUEn4VZkrVgzcaV9umGkq1rGHdX2ZCIQ,3073 +_pytest/setupplan.py,sha256=xhQ8MevEtMyu0jlLpX2BiJi75snZZ6mio9gRTQvuN2Q,1207 +_pytest/skipping.py,sha256=6dORiX3sbaUhBIyZFH2LqiBgTNjI1zBoYlcYtdkUx5U,10871 +_pytest/stepwise.py,sha256=lBoDT806s2-9vAsmANaKsOzlFQYmg-2bfqnZDcBh608,4170 +_pytest/store.py,sha256=fgGhs4TdMZOzC6yuAkoQl4yBpTIo0aPUq3jo87RQIBE,3634 +_pytest/terminal.py,sha256=oY_2BRwRfUzEzH7uUcHZhHrOk5mG78Npnt0DqVO3Fqg,47769 +_pytest/timing.py,sha256=HB2rdn3WN2UWpzgSJIgwcAKB-D2O-aP0ImaEfW0r2Fg,377 +_pytest/tmpdir.py,sha256=TI0ow0AyizpeDpzPCrBMclppDUC0PCKZrzUdN_n9x1s,7068 +_pytest/unittest.py,sha256=UtH6xQhG7xzx1okmsouIE5ho4DXoIsFnS_5NC8JzL9w,12987 +_pytest/warning_types.py,sha256=uucma3tJTBA1yenPKkBAbGmWj1MSCzDGaF3hSblxvDE,2692 +_pytest/warnings.py,sha256=CqXzysc8KEmqadIpu6PlKTH6MJQQ2W0YyZoy_dYnKm4,7480 +pytest-6.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pytest-6.0.1.dist-info/LICENSE,sha256=eJi5sWTU-T_ZpWL9D1kpNVGLSMR0UwOWQRDrf3_mT68,1096 +pytest-6.0.1.dist-info/METADATA,sha256=kR0dzhkhEjuyMEYX6WDE2iebPsDk9Ty6rYO_kPhYDIg,7360 +pytest-6.0.1.dist-info/RECORD,, +pytest-6.0.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pytest-6.0.1.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92 +pytest-6.0.1.dist-info/entry_points.txt,sha256=0yUOQ7R7BVugNpBSSbTGBNaEtMvencuMKiBdK4s5c58,78 +pytest-6.0.1.dist-info/top_level.txt,sha256=ENE0IeZV1I1R61DOt8gs5KmSXwitaq2zstF0az5f9PA,15 +pytest/__init__.py,sha256=ZzRqNvKSigQKy8u8L2gBuZaT_2bGHVsk6i9cbW7c6qo,2884 +pytest/__main__.py,sha256=pIdBXDKPds2Har07zSjC3dGBfHq0a6f00wosDnHTjno,113 +pytest/__pycache__/__init__.cpython-39.pyc,, +pytest/__pycache__/__main__.cpython-39.pyc,, +pytest/__pycache__/collect.cpython-39.pyc,, +pytest/collect.py,sha256=BmtK2WcOwiR-0ZP42eWc_W9QoNqKH82GG8UZaGAX0A4,903 +pytest/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/venv/Lib/site-packages/pytest-6.0.1.dist-info/REQUESTED b/venv/Lib/site-packages/pytest-6.0.1.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/pytest-6.0.1.dist-info/WHEEL b/venv/Lib/site-packages/pytest-6.0.1.dist-info/WHEEL new file mode 100644 index 0000000..b552003 --- /dev/null +++ b/venv/Lib/site-packages/pytest-6.0.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/pytest-6.0.1.dist-info/entry_points.txt b/venv/Lib/site-packages/pytest-6.0.1.dist-info/entry_points.txt new file mode 100644 index 0000000..0267c75 --- /dev/null +++ b/venv/Lib/site-packages/pytest-6.0.1.dist-info/entry_points.txt @@ -0,0 +1,4 @@ +[console_scripts] +py.test = pytest:console_main +pytest = pytest:console_main + diff --git a/venv/Lib/site-packages/pytest-6.0.1.dist-info/top_level.txt b/venv/Lib/site-packages/pytest-6.0.1.dist-info/top_level.txt new file mode 100644 index 0000000..e94857a --- /dev/null +++ b/venv/Lib/site-packages/pytest-6.0.1.dist-info/top_level.txt @@ -0,0 +1,2 @@ +_pytest +pytest diff --git a/venv/Lib/site-packages/regex-2022.10.31.dist-info/INSTALLER b/venv/Lib/site-packages/regex-2022.10.31.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/regex-2022.10.31.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/regex-2022.10.31.dist-info/LICENSE.txt b/venv/Lib/site-packages/regex-2022.10.31.dist-info/LICENSE.txt new file mode 100644 index 0000000..99c19cf --- /dev/null +++ b/venv/Lib/site-packages/regex-2022.10.31.dist-info/LICENSE.txt @@ -0,0 +1,208 @@ +This work was derived from the 're' module of CPython 2.6 and CPython 3.1, +copyright (c) 1998-2001 by Secret Labs AB and licensed under CNRI's Python 1.6 +license. + +All additions and alterations are licensed under the Apache 2.0 License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 Matthew Barnett + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/venv/Lib/site-packages/regex-2022.10.31.dist-info/METADATA b/venv/Lib/site-packages/regex-2022.10.31.dist-info/METADATA new file mode 100644 index 0000000..8026fc8 --- /dev/null +++ b/venv/Lib/site-packages/regex-2022.10.31.dist-info/METADATA @@ -0,0 +1,1076 @@ +Metadata-Version: 2.1 +Name: regex +Version: 2022.10.31 +Summary: Alternative regular expression module, to replace re. +Home-page: https://github.com/mrabarnett/mrab-regex +Author: Matthew Barnett +Author-email: regex@mrabarnett.plus.com +License: Apache Software License +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Topic :: Scientific/Engineering :: Information Analysis +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing +Classifier: Topic :: Text Processing :: General +Requires-Python: >=3.6 +Description-Content-Type: text/x-rst +License-File: LICENSE.txt + +Introduction +------------ + +This regex implementation is backwards-compatible with the standard 're' module, but offers additional functionality. + +Note +---- + +The re module's behaviour with zero-width matches changed in Python 3.7, and this module follows that behaviour when compiled for Python 3.7. + +Python 2 +-------- + +Python 2 is no longer supported. The last release that supported Python 2 was 2021.11.10. + +PyPy +---- + +This module is targeted at CPython. It expects that all codepoints are the same width, so it won't behave properly with PyPy outside U+0000..U+007F because PyPy stores strings as UTF-8. + +Multithreading +-------------- + +The regex module releases the GIL during matching on instances of the built-in (immutable) string classes, enabling other Python threads to run concurrently. It is also possible to force the regex module to release the GIL during matching by calling the matching methods with the keyword argument ``concurrent=True``. The behaviour is undefined if the string changes during matching, so use it *only* when it is guaranteed that that won't happen. + +Unicode +------- + +This module supports Unicode 15.0.0. Full Unicode case-folding is supported. + +Flags +----- + +There are 2 kinds of flag: scoped and global. Scoped flags can apply to only part of a pattern and can be turned on or off; global flags apply to the entire pattern and can only be turned on. + +The scoped flags are: ``ASCII (?a)``, ``FULLCASE (?f)``, ``IGNORECASE (?i)``, ``LOCALE (?L)``, ``MULTILINE (?m)``, ``DOTALL (?s)``, ``UNICODE (?u)``, ``VERBOSE (?x)``, ``WORD (?w)``. + +The global flags are: ``BESTMATCH (?b)``, ``ENHANCEMATCH (?e)``, ``POSIX (?p)``, ``REVERSE (?r)``, ``VERSION0 (?V0)``, ``VERSION1 (?V1)``. + +If neither the ``ASCII``, ``LOCALE`` nor ``UNICODE`` flag is specified, it will default to ``UNICODE`` if the regex pattern is a Unicode string and ``ASCII`` if it's a bytestring. + +The ``ENHANCEMATCH`` flag makes fuzzy matching attempt to improve the fit of the next match that it finds. + +The ``BESTMATCH`` flag makes fuzzy matching search for the best match instead of the next match. + +Old vs new behaviour +-------------------- + +In order to be compatible with the re module, this module has 2 behaviours: + +* **Version 0** behaviour (old behaviour, compatible with the re module): + + Please note that the re module's behaviour may change over time, and I'll endeavour to match that behaviour in version 0. + + * Indicated by the ``VERSION0`` flag. + + * Zero-width matches are not handled correctly in the re module before Python 3.7. The behaviour in those earlier versions is: + + * ``.split`` won't split a string at a zero-width match. + + * ``.sub`` will advance by one character after a zero-width match. + + * Inline flags apply to the entire pattern, and they can't be turned off. + + * Only simple sets are supported. + + * Case-insensitive matches in Unicode use simple case-folding by default. + +* **Version 1** behaviour (new behaviour, possibly different from the re module): + + * Indicated by the ``VERSION1`` flag. + + * Zero-width matches are handled correctly. + + * Inline flags apply to the end of the group or pattern, and they can be turned off. + + * Nested sets and set operations are supported. + + * Case-insensitive matches in Unicode use full case-folding by default. + +If no version is specified, the regex module will default to ``regex.DEFAULT_VERSION``. + +Case-insensitive matches in Unicode +----------------------------------- + +The regex module supports both simple and full case-folding for case-insensitive matches in Unicode. Use of full case-folding can be turned on using the ``FULLCASE`` flag. Please note that this flag affects how the ``IGNORECASE`` flag works; the ``FULLCASE`` flag itself does not turn on case-insensitive matching. + +Version 0 behaviour: the flag is off by default. + +Version 1 behaviour: the flag is on by default. + +Nested sets and set operations +------------------------------ + +It's not possible to support both simple sets, as used in the re module, and nested sets at the same time because of a difference in the meaning of an unescaped ``"["`` in a set. + +For example, the pattern ``[[a-z]--[aeiou]]`` is treated in the version 0 behaviour (simple sets, compatible with the re module) as: + +* Set containing "[" and the letters "a" to "z" + +* Literal "--" + +* Set containing letters "a", "e", "i", "o", "u" + +* Literal "]" + +but in the version 1 behaviour (nested sets, enhanced behaviour) as: + +* Set which is: + + * Set containing the letters "a" to "z" + +* but excluding: + + * Set containing the letters "a", "e", "i", "o", "u" + +Version 0 behaviour: only simple sets are supported. + +Version 1 behaviour: nested sets and set operations are supported. + +Notes on named groups +--------------------- + +All groups have a group number, starting from 1. + +Groups with the same group name will have the same group number, and groups with a different group name will have a different group number. + +The same name can be used by more than one group, with later captures 'overwriting' earlier captures. All the captures of the group will be available from the ``captures`` method of the match object. + +Group numbers will be reused across different branches of a branch reset, eg. ``(?|(first)|(second))`` has only group 1. If groups have different group names then they will, of course, have different group numbers, eg. ``(?|(?Pfirst)|(?Psecond))`` has group 1 ("foo") and group 2 ("bar"). + +In the regex ``(\s+)(?|(?P[A-Z]+)|(\w+) (?P[0-9]+)`` there are 2 groups: + +* ``(\s+)`` is group 1. + +* ``(?P[A-Z]+)`` is group 2, also called "foo". + +* ``(\w+)`` is group 2 because of the branch reset. + +* ``(?P[0-9]+)`` is group 2 because it's called "foo". + +If you want to prevent ``(\w+)`` from being group 2, you need to name it (different name, different group number). + +Additional features +------------------- + +The issue numbers relate to the Python bug tracker, except where listed otherwise. + +Added ``\p{Horiz_Space}`` and ``\p{Vert_Space}`` (`GitHub issue 477 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``\p{Horiz_Space}`` or ``\p{H}`` matches horizontal whitespace and ``\p{Vert_Space}`` or ``\p{V}`` matches vertical whitespace. + +Added support for lookaround in conditional pattern (`Hg issue 163 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The test of a conditional pattern can be a lookaround. + +.. sourcecode:: python + + >>> regex.match(r'(?(?=\d)\d+|\w+)', '123abc') + + >>> regex.match(r'(?(?=\d)\d+|\w+)', 'abc123') + + +This is not quite the same as putting a lookaround in the first branch of a pair of alternatives. + +.. sourcecode:: python + + >>> print(regex.match(r'(?:(?=\d)\d+\b|\w+)', '123abc')) + + >>> print(regex.match(r'(?(?=\d)\d+\b|\w+)', '123abc')) + None + +In the first example, the lookaround matched, but the remainder of the first branch failed to match, and so the second branch was attempted, whereas in the second example, the lookaround matched, and the first branch failed to match, but the second branch was **not** attempted. + +Added POSIX matching (leftmost longest) (`Hg issue 150 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The POSIX standard for regex is to return the leftmost longest match. This can be turned on using the ``POSIX`` flag. + +.. sourcecode:: python + + >>> # Normal matching. + >>> regex.search(r'Mr|Mrs', 'Mrs') + + >>> regex.search(r'one(self)?(selfsufficient)?', 'oneselfsufficient') + + >>> # POSIX matching. + >>> regex.search(r'(?p)Mr|Mrs', 'Mrs') + + >>> regex.search(r'(?p)one(self)?(selfsufficient)?', 'oneselfsufficient') + + +Note that it will take longer to find matches because when it finds a match at a certain position, it won't return that immediately, but will keep looking to see if there's another longer match there. + +Added ``(?(DEFINE)...)`` (`Hg issue 152 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If there's no group called "DEFINE", then ... will be ignored except that any groups defined within it can be called and that the normal rules for numbering groups still apply. + +.. sourcecode:: python + + >>> regex.search(r'(?(DEFINE)(?P\d+)(?P\w+))(?&quant) (?&item)', '5 elephants') + + +Added ``(*PRUNE)``, ``(*SKIP)`` and ``(*FAIL)`` (`Hg issue 153 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``(*PRUNE)`` discards the backtracking info up to that point. When used in an atomic group or a lookaround, it won't affect the enclosing pattern. + +``(*SKIP)`` is similar to ``(*PRUNE)``, except that it also sets where in the text the next attempt to match will start. When used in an atomic group or a lookaround, it won't affect the enclosing pattern. + +``(*FAIL)`` causes immediate backtracking. ``(*F)`` is a permitted abbreviation. + +Added ``\K`` (`Hg issue 151 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Keeps the part of the entire match after the position where ``\K`` occurred; the part before it is discarded. + +It does not affect what groups return. + +.. sourcecode:: python + + >>> m = regex.search(r'(\w\w\K\w\w\w)', 'abcdef') + >>> m[0] + 'cde' + >>> m[1] + 'abcde' + >>> + >>> m = regex.search(r'(?r)(\w\w\K\w\w\w)', 'abcdef') + >>> m[0] + 'bc' + >>> m[1] + 'bcdef' + +Added capture subscripting for ``expandf`` and ``subf``/``subfn`` (`Hg issue 133 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You can use subscripting to get the captures of a repeated group. + +.. sourcecode:: python + + >>> m = regex.match(r"(\w)+", "abc") + >>> m.expandf("{1}") + 'c' + >>> m.expandf("{1[0]} {1[1]} {1[2]}") + 'a b c' + >>> m.expandf("{1[-1]} {1[-2]} {1[-3]}") + 'c b a' + >>> + >>> m = regex.match(r"(?P\w)+", "abc") + >>> m.expandf("{letter}") + 'c' + >>> m.expandf("{letter[0]} {letter[1]} {letter[2]}") + 'a b c' + >>> m.expandf("{letter[-1]} {letter[-2]} {letter[-3]}") + 'c b a' + +Added support for referring to a group by number using ``(?P=...)`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This is in addition to the existing ``\g<...>``. + +Fixed the handling of locale-sensitive regexes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``LOCALE`` flag is intended for legacy code and has limited support. You're still recommended to use Unicode instead. + +Added partial matches (`Hg issue 102 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A partial match is one that matches up to the end of string, but that string has been truncated and you want to know whether a complete match could be possible if the string had not been truncated. + +Partial matches are supported by ``match``, ``search``, ``fullmatch`` and ``finditer`` with the ``partial`` keyword argument. + +Match objects have a ``partial`` attribute, which is ``True`` if it's a partial match. + +For example, if you wanted a user to enter a 4-digit number and check it character by character as it was being entered: + +.. sourcecode:: python + + >>> pattern = regex.compile(r'\d{4}') + + >>> # Initially, nothing has been entered: + >>> print(pattern.fullmatch('', partial=True)) + + + >>> # An empty string is OK, but it's only a partial match. + >>> # The user enters a letter: + >>> print(pattern.fullmatch('a', partial=True)) + None + >>> # It'll never match. + + >>> # The user deletes that and enters a digit: + >>> print(pattern.fullmatch('1', partial=True)) + + >>> # It matches this far, but it's only a partial match. + + >>> # The user enters 2 more digits: + >>> print(pattern.fullmatch('123', partial=True)) + + >>> # It matches this far, but it's only a partial match. + + >>> # The user enters another digit: + >>> print(pattern.fullmatch('1234', partial=True)) + + >>> # It's a complete match. + + >>> # If the user enters another digit: + >>> print(pattern.fullmatch('12345', partial=True)) + None + >>> # It's no longer a match. + + >>> # This is a partial match: + >>> pattern.match('123', partial=True).partial + True + + >>> # This is a complete match: + >>> pattern.match('1233', partial=True).partial + False + +``*`` operator not working correctly with sub() (`Hg issue 106 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Sometimes it's not clear how zero-width matches should be handled. For example, should ``.*`` match 0 characters directly after matching >0 characters? + +.. sourcecode:: python + + # Python 3.7 and later + >>> regex.sub('.*', 'x', 'test') + 'xx' + >>> regex.sub('.*?', '|', 'test') + '|||||||||' + + # Python 3.6 and earlier + >>> regex.sub('(?V0).*', 'x', 'test') + 'x' + >>> regex.sub('(?V1).*', 'x', 'test') + 'xx' + >>> regex.sub('(?V0).*?', '|', 'test') + '|t|e|s|t|' + >>> regex.sub('(?V1).*?', '|', 'test') + '|||||||||' + +Added ``capturesdict`` (`Hg issue 86 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``capturesdict`` is a combination of ``groupdict`` and ``captures``: + +``groupdict`` returns a dict of the named groups and the last capture of those groups. + +``captures`` returns a list of all the captures of a group + +``capturesdict`` returns a dict of the named groups and lists of all the captures of those groups. + +.. sourcecode:: python + + >>> m = regex.match(r"(?:(?P\w+) (?P\d+)\n)+", "one 1\ntwo 2\nthree 3\n") + >>> m.groupdict() + {'word': 'three', 'digits': '3'} + >>> m.captures("word") + ['one', 'two', 'three'] + >>> m.captures("digits") + ['1', '2', '3'] + >>> m.capturesdict() + {'word': ['one', 'two', 'three'], 'digits': ['1', '2', '3']} + +Added ``allcaptures`` and ``allspans`` (`Git issue 474 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``allcaptures`` returns a list of all the captures of all the groups. + +``allspans`` returns a list of all the spans of the all captures of all the groups. + +.. sourcecode:: python + + >>> m = regex.match(r"(?:(?P\w+) (?P\d+)\n)+", "one 1\ntwo 2\nthree 3\n") + >>> m.allcaptures() + (['one 1\ntwo 2\nthree 3\n'], ['one', 'two', 'three'], ['1', '2', '3']) + >>> m.allspans() + ([(0, 20)], [(0, 3), (6, 9), (12, 17)], [(4, 5), (10, 11), (18, 19)]) + +Allow duplicate names of groups (`Hg issue 87 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Group names can be duplicated. + +.. sourcecode:: python + + >>> # With optional groups: + >>> + >>> # Both groups capture, the second capture 'overwriting' the first. + >>> m = regex.match(r"(?P\w+)? or (?P\w+)?", "first or second") + >>> m.group("item") + 'second' + >>> m.captures("item") + ['first', 'second'] + >>> # Only the second group captures. + >>> m = regex.match(r"(?P\w+)? or (?P\w+)?", " or second") + >>> m.group("item") + 'second' + >>> m.captures("item") + ['second'] + >>> # Only the first group captures. + >>> m = regex.match(r"(?P\w+)? or (?P\w+)?", "first or ") + >>> m.group("item") + 'first' + >>> m.captures("item") + ['first'] + >>> + >>> # With mandatory groups: + >>> + >>> # Both groups capture, the second capture 'overwriting' the first. + >>> m = regex.match(r"(?P\w*) or (?P\w*)?", "first or second") + >>> m.group("item") + 'second' + >>> m.captures("item") + ['first', 'second'] + >>> # Again, both groups capture, the second capture 'overwriting' the first. + >>> m = regex.match(r"(?P\w*) or (?P\w*)", " or second") + >>> m.group("item") + 'second' + >>> m.captures("item") + ['', 'second'] + >>> # And yet again, both groups capture, the second capture 'overwriting' the first. + >>> m = regex.match(r"(?P\w*) or (?P\w*)", "first or ") + >>> m.group("item") + '' + >>> m.captures("item") + ['first', ''] + +Added ``fullmatch`` (`issue #16203 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``fullmatch`` behaves like ``match``, except that it must match all of the string. + +.. sourcecode:: python + + >>> print(regex.fullmatch(r"abc", "abc").span()) + (0, 3) + >>> print(regex.fullmatch(r"abc", "abcx")) + None + >>> print(regex.fullmatch(r"abc", "abcx", endpos=3).span()) + (0, 3) + >>> print(regex.fullmatch(r"abc", "xabcy", pos=1, endpos=4).span()) + (1, 4) + >>> + >>> regex.match(r"a.*?", "abcd").group(0) + 'a' + >>> regex.fullmatch(r"a.*?", "abcd").group(0) + 'abcd' + +Added ``subf`` and ``subfn`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``subf`` and ``subfn`` are alternatives to ``sub`` and ``subn`` respectively. When passed a replacement string, they treat it as a format string. + +.. sourcecode:: python + + >>> regex.subf(r"(\w+) (\w+)", "{0} => {2} {1}", "foo bar") + 'foo bar => bar foo' + >>> regex.subf(r"(?P\w+) (?P\w+)", "{word2} {word1}", "foo bar") + 'bar foo' + +Added ``expandf`` to match object +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``expandf`` is an alternative to ``expand``. When passed a replacement string, it treats it as a format string. + +.. sourcecode:: python + + >>> m = regex.match(r"(\w+) (\w+)", "foo bar") + >>> m.expandf("{0} => {2} {1}") + 'foo bar => bar foo' + >>> + >>> m = regex.match(r"(?P\w+) (?P\w+)", "foo bar") + >>> m.expandf("{word2} {word1}") + 'bar foo' + +Detach searched string +^^^^^^^^^^^^^^^^^^^^^^ + +A match object contains a reference to the string that was searched, via its ``string`` attribute. The ``detach_string`` method will 'detach' that string, making it available for garbage collection, which might save valuable memory if that string is very large. + +.. sourcecode:: python + + >>> m = regex.search(r"\w+", "Hello world") + >>> print(m.group()) + Hello + >>> print(m.string) + Hello world + >>> m.detach_string() + >>> print(m.group()) + Hello + >>> print(m.string) + None + +Recursive patterns (`Hg issue 27 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Recursive and repeated patterns are supported. + +``(?R)`` or ``(?0)`` tries to match the entire regex recursively. ``(?1)``, ``(?2)``, etc, try to match the relevant group. + +``(?&name)`` tries to match the named group. + +.. sourcecode:: python + + >>> regex.match(r"(Tarzan|Jane) loves (?1)", "Tarzan loves Jane").groups() + ('Tarzan',) + >>> regex.match(r"(Tarzan|Jane) loves (?1)", "Jane loves Tarzan").groups() + ('Jane',) + + >>> m = regex.search(r"(\w)(?:(?R)|(\w?))\1", "kayak") + >>> m.group(0, 1, 2) + ('kayak', 'k', None) + +The first two examples show how the subpattern within the group is reused, but is _not_ itself a group. In other words, ``"(Tarzan|Jane) loves (?1)"`` is equivalent to ``"(Tarzan|Jane) loves (?:Tarzan|Jane)"``. + +It's possible to backtrack into a recursed or repeated group. + +You can't call a group if there is more than one group with that group name or group number (``"ambiguous group reference"``). + +The alternative forms ``(?P>name)`` and ``(?P&name)`` are also supported. + +Full Unicode case-folding is supported +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In version 1 behaviour, the regex module uses full case-folding when performing case-insensitive matches in Unicode. + +.. sourcecode:: python + + >>> regex.match(r"(?iV1)strasse", "stra\N{LATIN SMALL LETTER SHARP S}e").span() + (0, 6) + >>> regex.match(r"(?iV1)stra\N{LATIN SMALL LETTER SHARP S}e", "STRASSE").span() + (0, 7) + +In version 0 behaviour, it uses simple case-folding for backward compatibility with the re module. + +Approximate "fuzzy" matching (`Hg issue 12 `_, `Hg issue 41 `_, `Hg issue 109 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Regex usually attempts an exact match, but sometimes an approximate, or "fuzzy", match is needed, for those cases where the text being searched may contain errors in the form of inserted, deleted or substituted characters. + +A fuzzy regex specifies which types of errors are permitted, and, optionally, either the minimum and maximum or only the maximum permitted number of each type. (You cannot specify only a minimum.) + +The 3 types of error are: + +* Insertion, indicated by "i" + +* Deletion, indicated by "d" + +* Substitution, indicated by "s" + +In addition, "e" indicates any type of error. + +The fuzziness of a regex item is specified between "{" and "}" after the item. + +Examples: + +* ``foo`` match "foo" exactly + +* ``(?:foo){i}`` match "foo", permitting insertions + +* ``(?:foo){d}`` match "foo", permitting deletions + +* ``(?:foo){s}`` match "foo", permitting substitutions + +* ``(?:foo){i,s}`` match "foo", permitting insertions and substitutions + +* ``(?:foo){e}`` match "foo", permitting errors + +If a certain type of error is specified, then any type not specified will **not** be permitted. + +In the following examples I'll omit the item and write only the fuzziness: + +* ``{d<=3}`` permit at most 3 deletions, but no other types + +* ``{i<=1,s<=2}`` permit at most 1 insertion and at most 2 substitutions, but no deletions + +* ``{1<=e<=3}`` permit at least 1 and at most 3 errors + +* ``{i<=2,d<=2,e<=3}`` permit at most 2 insertions, at most 2 deletions, at most 3 errors in total, but no substitutions + +It's also possible to state the costs of each type of error and the maximum permitted total cost. + +Examples: + +* ``{2i+2d+1s<=4}`` each insertion costs 2, each deletion costs 2, each substitution costs 1, the total cost must not exceed 4 + +* ``{i<=1,d<=1,s<=1,2i+2d+1s<=4}`` at most 1 insertion, at most 1 deletion, at most 1 substitution; each insertion costs 2, each deletion costs 2, each substitution costs 1, the total cost must not exceed 4 + +You can also use "<" instead of "<=" if you want an exclusive minimum or maximum. + +You can add a test to perform on a character that's substituted or inserted. + +Examples: + +* ``{s<=2:[a-z]}`` at most 2 substitutions, which must be in the character set ``[a-z]``. + +* ``{s<=2,i<=3:\d}`` at most 2 substitutions, at most 3 insertions, which must be digits. + +By default, fuzzy matching searches for the first match that meets the given constraints. The ``ENHANCEMATCH`` flag will cause it to attempt to improve the fit (i.e. reduce the number of errors) of the match that it has found. + +The ``BESTMATCH`` flag will make it search for the best match instead. + +Further examples to note: + +* ``regex.search("(dog){e}", "cat and dog")[1]`` returns ``"cat"`` because that matches ``"dog"`` with 3 errors (an unlimited number of errors is permitted). + +* ``regex.search("(dog){e<=1}", "cat and dog")[1]`` returns ``" dog"`` (with a leading space) because that matches ``"dog"`` with 1 error, which is within the limit. + +* ``regex.search("(?e)(dog){e<=1}", "cat and dog")[1]`` returns ``"dog"`` (without a leading space) because the fuzzy search matches ``" dog"`` with 1 error, which is within the limit, and the ``(?e)`` then it attempts a better fit. + +In the first two examples there are perfect matches later in the string, but in neither case is it the first possible match. + +The match object has an attribute ``fuzzy_counts`` which gives the total number of substitutions, insertions and deletions. + +.. sourcecode:: python + + >>> # A 'raw' fuzzy match: + >>> regex.fullmatch(r"(?:cats|cat){e<=1}", "cat").fuzzy_counts + (0, 0, 1) + >>> # 0 substitutions, 0 insertions, 1 deletion. + + >>> # A better match might be possible if the ENHANCEMATCH flag used: + >>> regex.fullmatch(r"(?e)(?:cats|cat){e<=1}", "cat").fuzzy_counts + (0, 0, 0) + >>> # 0 substitutions, 0 insertions, 0 deletions. + +The match object also has an attribute ``fuzzy_changes`` which gives a tuple of the positions of the substitutions, insertions and deletions. + +.. sourcecode:: python + + >>> m = regex.search('(fuu){i<=2,d<=2,e<=5}', 'anaconda foo bar') + >>> m + + >>> m.fuzzy_changes + ([], [7, 8], [10, 11]) + +What this means is that if the matched part of the string had been: + +.. sourcecode:: python + + 'anacondfuuoo bar' + +it would've been an exact match. + +However, there were insertions at positions 7 and 8: + +.. sourcecode:: python + + 'anaconda fuuoo bar' + ^^ + +and deletions at positions 10 and 11: + +.. sourcecode:: python + + 'anaconda f~~oo bar' + ^^ + +So the actual string was: + +.. sourcecode:: python + + 'anaconda foo bar' + +Named lists ``\L`` (`Hg issue 11 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There are occasions where you may want to include a list (actually, a set) of options in a regex. + +One way is to build the pattern like this: + +.. sourcecode:: python + + >>> p = regex.compile(r"first|second|third|fourth|fifth") + +but if the list is large, parsing the resulting regex can take considerable time, and care must also be taken that the strings are properly escaped and properly ordered, for example, "cats" before "cat". + +The new alternative is to use a named list: + +.. sourcecode:: python + + >>> option_set = ["first", "second", "third", "fourth", "fifth"] + >>> p = regex.compile(r"\L", options=option_set) + +The order of the items is irrelevant, they are treated as a set. The named lists are available as the ``.named_lists`` attribute of the pattern object : + +.. sourcecode:: python + + >>> print(p.named_lists) + {'options': frozenset({'third', 'first', 'fifth', 'fourth', 'second'})} + +If there are any unused keyword arguments, ``ValueError`` will be raised unless you tell it otherwise: + +.. sourcecode:: python + + >>> option_set = ["first", "second", "third", "fourth", "fifth"] + >>> p = regex.compile(r"\L", options=option_set, other_options=[]) + Traceback (most recent call last): + File "", line 1, in + File "C:\Python310\lib\site-packages\regex\regex.py", line 353, in compile + return _compile(pattern, flags, ignore_unused, kwargs, cache_pattern) + File "C:\Python310\lib\site-packages\regex\regex.py", line 500, in _compile + complain_unused_args() + File "C:\Python310\lib\site-packages\regex\regex.py", line 483, in complain_unused_args + raise ValueError('unused keyword argument {!a}'.format(any_one)) + ValueError: unused keyword argument 'other_options' + >>> p = regex.compile(r"\L", options=option_set, other_options=[], ignore_unused=True) + >>> p = regex.compile(r"\L", options=option_set, other_options=[], ignore_unused=False) + Traceback (most recent call last): + File "", line 1, in + File "C:\Python310\lib\site-packages\regex\regex.py", line 353, in compile + return _compile(pattern, flags, ignore_unused, kwargs, cache_pattern) + File "C:\Python310\lib\site-packages\regex\regex.py", line 500, in _compile + complain_unused_args() + File "C:\Python310\lib\site-packages\regex\regex.py", line 483, in complain_unused_args + raise ValueError('unused keyword argument {!a}'.format(any_one)) + ValueError: unused keyword argument 'other_options' + >>> + +Start and end of word +^^^^^^^^^^^^^^^^^^^^^ + +``\m`` matches at the start of a word. + +``\M`` matches at the end of a word. + +Compare with ``\b``, which matches at the start or end of a word. + +Unicode line separators +^^^^^^^^^^^^^^^^^^^^^^^ + +Normally the only line separator is ``\n`` (``\x0A``), but if the ``WORD`` flag is turned on then the line separators are ``\x0D\x0A``, ``\x0A``, ``\x0B``, ``\x0C`` and ``\x0D``, plus ``\x85``, ``\u2028`` and ``\u2029`` when working with Unicode. + +This affects the regex dot ``"."``, which, with the ``DOTALL`` flag turned off, matches any character except a line separator. It also affects the line anchors ``^`` and ``$`` (in multiline mode). + +Set operators +^^^^^^^^^^^^^ + +**Version 1 behaviour only** + +Set operators have been added, and a set ``[...]`` can include nested sets. + +The operators, in order of increasing precedence, are: + +* ``||`` for union ("x||y" means "x or y") + +* ``~~`` (double tilde) for symmetric difference ("x~~y" means "x or y, but not both") + +* ``&&`` for intersection ("x&&y" means "x and y") + +* ``--`` (double dash) for difference ("x--y" means "x but not y") + +Implicit union, ie, simple juxtaposition like in ``[ab]``, has the highest precedence. Thus, ``[ab&&cd]`` is the same as ``[[a||b]&&[c||d]]``. + +Examples: + +* ``[ab]`` # Set containing 'a' and 'b' + +* ``[a-z]`` # Set containing 'a' .. 'z' + +* ``[[a-z]--[qw]]`` # Set containing 'a' .. 'z', but not 'q' or 'w' + +* ``[a-z--qw]`` # Same as above + +* ``[\p{L}--QW]`` # Set containing all letters except 'Q' and 'W' + +* ``[\p{N}--[0-9]]`` # Set containing all numbers except '0' .. '9' + +* ``[\p{ASCII}&&\p{Letter}]`` # Set containing all characters which are ASCII and letter + +regex.escape (`issue #2650 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +regex.escape has an additional keyword parameter ``special_only``. When True, only 'special' regex characters, such as '?', are escaped. + +.. sourcecode:: python + + >>> regex.escape("foo!?", special_only=False) + 'foo\\!\\?' + >>> regex.escape("foo!?", special_only=True) + 'foo!\\?' + +regex.escape (`Hg issue 249 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +regex.escape has an additional keyword parameter ``literal_spaces``. When True, spaces are not escaped. + +.. sourcecode:: python + + >>> regex.escape("foo bar!?", literal_spaces=False) + 'foo\\ bar!\\?' + >>> regex.escape("foo bar!?", literal_spaces=True) + 'foo bar!\\?' + +Repeated captures (`issue #7132 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A match object has additional methods which return information on all the successful matches of a repeated group. These methods are: + +* ``matchobject.captures([group1, ...])`` + + * Returns a list of the strings matched in a group or groups. Compare with ``matchobject.group([group1, ...])``. + +* ``matchobject.starts([group])`` + + * Returns a list of the start positions. Compare with ``matchobject.start([group])``. + +* ``matchobject.ends([group])`` + + * Returns a list of the end positions. Compare with ``matchobject.end([group])``. + +* ``matchobject.spans([group])`` + + * Returns a list of the spans. Compare with ``matchobject.span([group])``. + +.. sourcecode:: python + + >>> m = regex.search(r"(\w{3})+", "123456789") + >>> m.group(1) + '789' + >>> m.captures(1) + ['123', '456', '789'] + >>> m.start(1) + 6 + >>> m.starts(1) + [0, 3, 6] + >>> m.end(1) + 9 + >>> m.ends(1) + [3, 6, 9] + >>> m.span(1) + (6, 9) + >>> m.spans(1) + [(0, 3), (3, 6), (6, 9)] + +Atomic grouping ``(?>...)`` (`issue #433030 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If the following pattern subsequently fails, then the subpattern as a whole will fail. + +Possessive quantifiers +^^^^^^^^^^^^^^^^^^^^^^ + +``(?:...)?+`` ; ``(?:...)*+`` ; ``(?:...)++`` ; ``(?:...){min,max}+`` + +The subpattern is matched up to 'max' times. If the following pattern subsequently fails, then all the repeated subpatterns will fail as a whole. For example, ``(?:...)++`` is equivalent to ``(?>(?:...)+)``. + +Scoped flags (`issue #433028 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``(?flags-flags:...)`` + +The flags will apply only to the subpattern. Flags can be turned on or off. + +Definition of 'word' character (`issue #1693050 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The definition of a 'word' character has been expanded for Unicode. It conforms to the Unicode specification at ``http://www.unicode.org/reports/tr29/``. + +Variable-length lookbehind +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A lookbehind can match a variable-length string. + +Flags argument for regex.split, regex.sub and regex.subn (`issue #3482 `_) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``regex.split``, ``regex.sub`` and ``regex.subn`` support a 'flags' argument. + +Pos and endpos arguments for regex.sub and regex.subn +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``regex.sub`` and ``regex.subn`` support 'pos' and 'endpos' arguments. + +'Overlapped' argument for regex.findall and regex.finditer +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``regex.findall`` and ``regex.finditer`` support an 'overlapped' flag which permits overlapped matches. + +Splititer +^^^^^^^^^ + +``regex.splititer`` has been added. It's a generator equivalent of ``regex.split``. + +Subscripting match objects for groups +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A match object accepts access to the groups via subscripting and slicing: + +.. sourcecode:: python + + >>> m = regex.search(r"(?P.*?)(?P\d+)(?P.*)", "pqr123stu") + >>> print(m["before"]) + pqr + >>> print(len(m)) + 4 + >>> print(m[:]) + ('pqr123stu', 'pqr', '123', 'stu') + +Named groups +^^^^^^^^^^^^ + +Groups can be named with ``(?...)`` as well as the existing ``(?P...)``. + +Group references +^^^^^^^^^^^^^^^^ + +Groups can be referenced within a pattern with ``\g``. This also allows there to be more than 99 groups. + +Named characters ``\N{name}`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Named characters are supported. Note that only those known by Python's Unicode database will be recognised. + +Unicode codepoint properties, including scripts and blocks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``\p{property=value}``; ``\P{property=value}``; ``\p{value}`` ; ``\P{value}`` + +Many Unicode properties are supported, including blocks and scripts. ``\p{property=value}`` or ``\p{property:value}`` matches a character whose property ``property`` has value ``value``. The inverse of ``\p{property=value}`` is ``\P{property=value}`` or ``\p{^property=value}``. + +If the short form ``\p{value}`` is used, the properties are checked in the order: ``General_Category``, ``Script``, ``Block``, binary property: + +* ``Latin``, the 'Latin' script (``Script=Latin``). + +* ``BasicLatin``, the 'BasicLatin' block (``Block=BasicLatin``). + +* ``Alphabetic``, the 'Alphabetic' binary property (``Alphabetic=Yes``). + +A short form starting with ``Is`` indicates a script or binary property: + +* ``IsLatin``, the 'Latin' script (``Script=Latin``). + +* ``IsAlphabetic``, the 'Alphabetic' binary property (``Alphabetic=Yes``). + +A short form starting with ``In`` indicates a block property: + +* ``InBasicLatin``, the 'BasicLatin' block (``Block=BasicLatin``). + +POSIX character classes +^^^^^^^^^^^^^^^^^^^^^^^ + +``[[:alpha:]]``; ``[[:^alpha:]]`` + +POSIX character classes are supported. These are normally treated as an alternative form of ``\p{...}``. + +The exceptions are ``alnum``, ``digit``, ``punct`` and ``xdigit``, whose definitions are different from those of Unicode. + +``[[:alnum:]]`` is equivalent to ``\p{posix_alnum}``. + +``[[:digit:]]`` is equivalent to ``\p{posix_digit}``. + +``[[:punct:]]`` is equivalent to ``\p{posix_punct}``. + +``[[:xdigit:]]`` is equivalent to ``\p{posix_xdigit}``. + +Search anchor ``\G`` +^^^^^^^^^^^^^^^^^^^^ + +A search anchor has been added. It matches at the position where each search started/continued and can be used for contiguous matches or in negative variable-length lookbehinds to limit how far back the lookbehind goes: + +.. sourcecode:: python + + >>> regex.findall(r"\w{2}", "abcd ef") + ['ab', 'cd', 'ef'] + >>> regex.findall(r"\G\w{2}", "abcd ef") + ['ab', 'cd'] + +* The search starts at position 0 and matches 'ab'. + +* The search continues at position 2 and matches 'cd'. + +* The search continues at position 4 and fails to match any letters. + +* The anchor stops the search start position from being advanced, so there are no more results. + +Reverse searching +^^^^^^^^^^^^^^^^^ + +Searches can also work backwards: + +.. sourcecode:: python + + >>> regex.findall(r".", "abc") + ['a', 'b', 'c'] + >>> regex.findall(r"(?r).", "abc") + ['c', 'b', 'a'] + +Note that the result of a reverse search is not necessarily the reverse of a forward search: + +.. sourcecode:: python + + >>> regex.findall(r"..", "abcde") + ['ab', 'cd'] + >>> regex.findall(r"(?r)..", "abcde") + ['de', 'bc'] + +Matching a single grapheme ``\X`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The grapheme matcher is supported. It conforms to the Unicode specification at ``http://www.unicode.org/reports/tr29/``. + +Branch reset ``(?|...|...)`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Group numbers will be reused across the alternatives, but groups with different names will have different group numbers. + +.. sourcecode:: python + + >>> regex.match(r"(?|(first)|(second))", "first").groups() + ('first',) + >>> regex.match(r"(?|(first)|(second))", "second").groups() + ('second',) + +Note that there is only one group. + +Default Unicode word boundary +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``WORD`` flag changes the definition of a 'word boundary' to that of a default Unicode word boundary. This applies to ``\b`` and ``\B``. + +Timeout +^^^^^^^ + +The matching methods and functions support timeouts. The timeout (in seconds) applies to the entire operation: + +.. sourcecode:: python + + >>> from time import sleep + >>> + >>> def fast_replace(m): + ... return 'X' + ... + >>> def slow_replace(m): + ... sleep(0.5) + ... return 'X' + ... + >>> regex.sub(r'[a-z]', fast_replace, 'abcde', timeout=2) + 'XXXXX' + >>> regex.sub(r'[a-z]', slow_replace, 'abcde', timeout=2) + Traceback (most recent call last): + File "", line 1, in + File "C:\Python310\lib\site-packages\regex\regex.py", line 278, in sub + return pat.sub(repl, string, count, pos, endpos, concurrent, timeout) + TimeoutError: regex timed out diff --git a/venv/Lib/site-packages/regex-2022.10.31.dist-info/RECORD b/venv/Lib/site-packages/regex-2022.10.31.dist-info/RECORD new file mode 100644 index 0000000..107b564 --- /dev/null +++ b/venv/Lib/site-packages/regex-2022.10.31.dist-info/RECORD @@ -0,0 +1,15 @@ +regex-2022.10.31.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +regex-2022.10.31.dist-info/LICENSE.txt,sha256=PSIMBllLgmu6vxEDEvYPOF-Z5X5Sn6S55Tb3kJH4tMc,11792 +regex-2022.10.31.dist-info/METADATA,sha256=TuzicXp4GwGplyU90kgobim_H7bKvDLSDJKIyg-Zu8U,40896 +regex-2022.10.31.dist-info/RECORD,, +regex-2022.10.31.dist-info/WHEEL,sha256=fVcVlLzi8CGi_Ul8vjMdn8gER25dn5GBg9E6k9z41-Y,100 +regex-2022.10.31.dist-info/top_level.txt,sha256=aQmiDMhNTF26cCK4_7D-qaVvhbxClG0wyCTnEhkzYBs,6 +regex/__init__.py,sha256=6giZBSRLmTZfvQrcVoS6MaL5gKcwtfZlSXATBex49lU,68 +regex/__pycache__/__init__.cpython-39.pyc,, +regex/__pycache__/_regex_core.cpython-39.pyc,, +regex/__pycache__/regex.cpython-39.pyc,, +regex/__pycache__/test_regex.cpython-39.pyc,, +regex/_regex.cp39-win_amd64.pyd,sha256=0L_i8N4NXq8ta72cMxxGPVk-LoM0nVNgJFptGcMj7BQ,669696 +regex/_regex_core.py,sha256=-FK3CSneMb6pd2XCOnFA5Wb68gA1QjxBQx9YJKst7Lo,145648 +regex/regex.py,sha256=nG902rAL1i2EmZxAdnmKDZm42FHvTSpJVBNIlIErvj4,33561 +regex/test_regex.py,sha256=PGCPJyh5s4w6rUs3pOzD0D_mGe_E9u2UzGzpK79TB7g,223825 diff --git a/venv/Lib/site-packages/regex-2022.10.31.dist-info/WHEEL b/venv/Lib/site-packages/regex-2022.10.31.dist-info/WHEEL new file mode 100644 index 0000000..d5a9837 --- /dev/null +++ b/venv/Lib/site-packages/regex-2022.10.31.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: false +Tag: cp39-cp39-win_amd64 + diff --git a/venv/Lib/site-packages/regex-2022.10.31.dist-info/top_level.txt b/venv/Lib/site-packages/regex-2022.10.31.dist-info/top_level.txt new file mode 100644 index 0000000..4f9256d --- /dev/null +++ b/venv/Lib/site-packages/regex-2022.10.31.dist-info/top_level.txt @@ -0,0 +1 @@ +regex diff --git a/venv/Lib/site-packages/setuptools-66.0.0.dist-info/INSTALLER b/venv/Lib/site-packages/setuptools-66.0.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/setuptools-66.0.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/setuptools-66.0.0.dist-info/LICENSE b/venv/Lib/site-packages/setuptools-66.0.0.dist-info/LICENSE new file mode 100644 index 0000000..353924b --- /dev/null +++ b/venv/Lib/site-packages/setuptools-66.0.0.dist-info/LICENSE @@ -0,0 +1,19 @@ +Copyright Jason R. Coombs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/venv/Lib/site-packages/setuptools-66.0.0.dist-info/METADATA b/venv/Lib/site-packages/setuptools-66.0.0.dist-info/METADATA new file mode 100644 index 0000000..63bb375 --- /dev/null +++ b/venv/Lib/site-packages/setuptools-66.0.0.dist-info/METADATA @@ -0,0 +1,137 @@ +Metadata-Version: 2.1 +Name: setuptools +Version: 66.0.0 +Summary: Easily download, build, install, upgrade, and uninstall Python packages +Home-page: https://github.com/pypa/setuptools +Author: Python Packaging Authority +Author-email: distutils-sig@python.org +Project-URL: Documentation, https://setuptools.pypa.io/ +Project-URL: Changelog, https://setuptools.pypa.io/en/stable/history.html +Keywords: CPAN PyPI distutils eggs package management +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: System :: Archiving :: Packaging +Classifier: Topic :: System :: Systems Administration +Classifier: Topic :: Utilities +Requires-Python: >=3.7 +License-File: LICENSE +Provides-Extra: certs +Provides-Extra: docs +Requires-Dist: sphinx (>=3.5) ; extra == 'docs' +Requires-Dist: jaraco.packaging (>=9) ; extra == 'docs' +Requires-Dist: rst.linker (>=1.9) ; extra == 'docs' +Requires-Dist: furo ; extra == 'docs' +Requires-Dist: sphinx-lint ; extra == 'docs' +Requires-Dist: jaraco.tidelift (>=1.4) ; extra == 'docs' +Requires-Dist: pygments-github-lexers (==0.0.5) ; extra == 'docs' +Requires-Dist: sphinx-favicon ; extra == 'docs' +Requires-Dist: sphinx-inline-tabs ; extra == 'docs' +Requires-Dist: sphinx-reredirects ; extra == 'docs' +Requires-Dist: sphinxcontrib-towncrier ; extra == 'docs' +Requires-Dist: sphinx-notfound-page (==0.8.3) ; extra == 'docs' +Requires-Dist: sphinx-hoverxref (<2) ; extra == 'docs' +Provides-Extra: ssl +Provides-Extra: testing +Requires-Dist: pytest (>=6) ; extra == 'testing' +Requires-Dist: pytest-checkdocs (>=2.4) ; extra == 'testing' +Requires-Dist: flake8 (<5) ; extra == 'testing' +Requires-Dist: pytest-enabler (>=1.3) ; extra == 'testing' +Requires-Dist: pytest-perf ; extra == 'testing' +Requires-Dist: flake8-2020 ; extra == 'testing' +Requires-Dist: virtualenv (>=13.0.0) ; extra == 'testing' +Requires-Dist: wheel ; extra == 'testing' +Requires-Dist: pip (>=19.1) ; extra == 'testing' +Requires-Dist: jaraco.envs (>=2.2) ; extra == 'testing' +Requires-Dist: pytest-xdist ; extra == 'testing' +Requires-Dist: jaraco.path (>=3.2.0) ; extra == 'testing' +Requires-Dist: build[virtualenv] ; extra == 'testing' +Requires-Dist: filelock (>=3.4.0) ; extra == 'testing' +Requires-Dist: pip-run (>=8.8) ; extra == 'testing' +Requires-Dist: ini2toml[lite] (>=0.9) ; extra == 'testing' +Requires-Dist: tomli-w (>=1.0.0) ; extra == 'testing' +Requires-Dist: pytest-timeout ; extra == 'testing' +Provides-Extra: testing-integration +Requires-Dist: pytest ; extra == 'testing-integration' +Requires-Dist: pytest-xdist ; extra == 'testing-integration' +Requires-Dist: pytest-enabler ; extra == 'testing-integration' +Requires-Dist: virtualenv (>=13.0.0) ; extra == 'testing-integration' +Requires-Dist: tomli ; extra == 'testing-integration' +Requires-Dist: wheel ; extra == 'testing-integration' +Requires-Dist: jaraco.path (>=3.2.0) ; extra == 'testing-integration' +Requires-Dist: jaraco.envs (>=2.2) ; extra == 'testing-integration' +Requires-Dist: build[virtualenv] ; extra == 'testing-integration' +Requires-Dist: filelock (>=3.4.0) ; extra == 'testing-integration' +Requires-Dist: pytest-black (>=0.3.7) ; (platform_python_implementation != "PyPy") and extra == 'testing' +Requires-Dist: pytest-cov ; (platform_python_implementation != "PyPy") and extra == 'testing' +Requires-Dist: pytest-mypy (>=0.9.1) ; (platform_python_implementation != "PyPy") and extra == 'testing' +Requires-Dist: pytest-flake8 ; (python_version < "3.12") and extra == 'testing' + +.. image:: https://img.shields.io/pypi/v/setuptools.svg + :target: https://pypi.org/project/setuptools + +.. image:: https://img.shields.io/pypi/pyversions/setuptools.svg + +.. image:: https://github.com/pypa/setuptools/workflows/tests/badge.svg + :target: https://github.com/pypa/setuptools/actions?query=workflow%3A%22tests%22 + :alt: tests + +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/psf/black + :alt: Code style: Black + +.. image:: https://img.shields.io/readthedocs/setuptools/latest.svg + :target: https://setuptools.pypa.io + +.. image:: https://img.shields.io/badge/skeleton-2023-informational + :target: https://blog.jaraco.com/skeleton + +.. image:: https://img.shields.io/codecov/c/github/pypa/setuptools/master.svg?logo=codecov&logoColor=white + :target: https://codecov.io/gh/pypa/setuptools + +.. image:: https://tidelift.com/badges/github/pypa/setuptools?style=flat + :target: https://tidelift.com/subscription/pkg/pypi-setuptools?utm_source=pypi-setuptools&utm_medium=readme + +.. image:: https://img.shields.io/discord/803025117553754132 + :target: https://discord.com/channels/803025117553754132/815945031150993468 + :alt: Discord + +See the `Installation Instructions +`_ in the Python Packaging +User's Guide for instructions on installing, upgrading, and uninstalling +Setuptools. + +Questions and comments should be directed to `GitHub Discussions +`_. +Bug reports and especially tested patches may be +submitted directly to the `bug tracker +`_. + + +Code of Conduct +=============== + +Everyone interacting in the setuptools project's codebases, issue trackers, +chat rooms, and fora is expected to follow the +`PSF Code of Conduct `_. + + +For Enterprise +============== + +Available as part of the Tidelift Subscription. + +Setuptools and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use. + +`Learn more `_. + + +Security Contact +================ + +To report a security vulnerability, please use the +`Tidelift security contact `_. +Tidelift will coordinate the fix and disclosure. diff --git a/venv/Lib/site-packages/setuptools-66.0.0.dist-info/RECORD b/venv/Lib/site-packages/setuptools-66.0.0.dist-info/RECORD new file mode 100644 index 0000000..28d7259 --- /dev/null +++ b/venv/Lib/site-packages/setuptools-66.0.0.dist-info/RECORD @@ -0,0 +1,483 @@ +_distutils_hack/__init__.py,sha256=TSekhUW1fdE3rjU3b88ybSBkJxCEpIeWBob4cEuU3ko,6128 +_distutils_hack/__pycache__/__init__.cpython-39.pyc,, +_distutils_hack/__pycache__/override.cpython-39.pyc,, +_distutils_hack/override.py,sha256=Eu_s-NF6VIZ4Cqd0tbbA5wtWky2IZPNd8et6GLt1mzo,44 +distutils-precedence.pth,sha256=JjjOniUA5XKl4N5_rtZmHrVp0baW_LoHsN0iPaX10iQ,151 +pkg_resources/__init__.py,sha256=uVgcEUBDYk7DtaucDIAslI5VficzC_Sbcdq-fMybNbc,105958 +pkg_resources/__pycache__/__init__.cpython-39.pyc,, +pkg_resources/_vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pkg_resources/_vendor/__pycache__/__init__.cpython-39.pyc,, +pkg_resources/_vendor/__pycache__/typing_extensions.cpython-39.pyc,, +pkg_resources/_vendor/__pycache__/zipp.cpython-39.pyc,, +pkg_resources/_vendor/importlib_resources/__init__.py,sha256=evPm12kLgYqTm-pbzm60bOuumumT8IpBNWFp0uMyrzE,506 +pkg_resources/_vendor/importlib_resources/__pycache__/__init__.cpython-39.pyc,, +pkg_resources/_vendor/importlib_resources/__pycache__/_adapters.cpython-39.pyc,, +pkg_resources/_vendor/importlib_resources/__pycache__/_common.cpython-39.pyc,, +pkg_resources/_vendor/importlib_resources/__pycache__/_compat.cpython-39.pyc,, +pkg_resources/_vendor/importlib_resources/__pycache__/_itertools.cpython-39.pyc,, +pkg_resources/_vendor/importlib_resources/__pycache__/_legacy.cpython-39.pyc,, +pkg_resources/_vendor/importlib_resources/__pycache__/abc.cpython-39.pyc,, +pkg_resources/_vendor/importlib_resources/__pycache__/readers.cpython-39.pyc,, +pkg_resources/_vendor/importlib_resources/__pycache__/simple.cpython-39.pyc,, +pkg_resources/_vendor/importlib_resources/_adapters.py,sha256=o51tP2hpVtohP33gSYyAkGNpLfYDBqxxYsadyiRZi1E,4504 +pkg_resources/_vendor/importlib_resources/_common.py,sha256=iIxAaQhotSh6TLLUEfL_ynU2fzEeyHMz9JcL46mUhLg,2741 +pkg_resources/_vendor/importlib_resources/_compat.py,sha256=nFBCGMvImglrqgYkb9aPgOj68-h6xbw-ca94XOv1-zs,2706 +pkg_resources/_vendor/importlib_resources/_itertools.py,sha256=WCdJ1Gs_kNFwKENyIG7TO0Y434IWCu0zjVVSsSbZwU8,884 +pkg_resources/_vendor/importlib_resources/_legacy.py,sha256=TMLkx6aEM6U8xIREPXqGZrMbUhTiPUuPl6ESD7RdYj4,3494 +pkg_resources/_vendor/importlib_resources/abc.py,sha256=MvTJJXajbl74s36Gyeesf76egtbFnh-TMtzQMVhFWXo,3886 +pkg_resources/_vendor/importlib_resources/readers.py,sha256=_9QLGQ5AzrED3PY8S2Zf8V6yLR0-nqqYqtQmgleDJzY,3566 +pkg_resources/_vendor/importlib_resources/simple.py,sha256=xt0qhXbwt3bZ86zuaaKbTiE9A0mDbwu0saRjUq_pcY0,2836 +pkg_resources/_vendor/jaraco/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pkg_resources/_vendor/jaraco/__pycache__/__init__.cpython-39.pyc,, +pkg_resources/_vendor/jaraco/__pycache__/context.cpython-39.pyc,, +pkg_resources/_vendor/jaraco/__pycache__/functools.cpython-39.pyc,, +pkg_resources/_vendor/jaraco/context.py,sha256=NvdB7ArVCDrhtexOnOwSv4ScDuueGbf9LRiOSCqPn6Y,6488 +pkg_resources/_vendor/jaraco/functools.py,sha256=eLwPh8FWY7rQ_cj1YxCekUkibTuerwyoJ_41H7Q7oWM,13515 +pkg_resources/_vendor/jaraco/text/__init__.py,sha256=cN55bFcceW4wTHG5ruv5IuEDRarP-4hBYX8zl94_c30,15526 +pkg_resources/_vendor/jaraco/text/__pycache__/__init__.cpython-39.pyc,, +pkg_resources/_vendor/more_itertools/__init__.py,sha256=5PNQMpy400s5GB3jcWwzje0RCw8k0bvU9W_C49V0fd0,148 +pkg_resources/_vendor/more_itertools/__pycache__/__init__.cpython-39.pyc,, +pkg_resources/_vendor/more_itertools/__pycache__/more.cpython-39.pyc,, +pkg_resources/_vendor/more_itertools/__pycache__/recipes.cpython-39.pyc,, +pkg_resources/_vendor/more_itertools/more.py,sha256=NTUZ0P0n0gDy3qezmlR5xGtqA1LWMAockWvyHYLLuYQ,133344 +pkg_resources/_vendor/more_itertools/recipes.py,sha256=ZX4-2IfbZKlPIVaDITH2buX_fPuMDe1EVc6e2XSsCz8,22975 +pkg_resources/_vendor/packaging/__about__.py,sha256=ugASIO2w1oUyH8_COqQ2X_s0rDhjbhQC3yJocD03h2c,661 +pkg_resources/_vendor/packaging/__init__.py,sha256=b9Kk5MF7KxhhLgcDmiUWukN-LatWFxPdNug0joPhHSk,497 +pkg_resources/_vendor/packaging/__pycache__/__about__.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/__init__.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/_manylinux.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/_musllinux.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/_structures.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/markers.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/requirements.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/specifiers.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/tags.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/utils.cpython-39.pyc,, +pkg_resources/_vendor/packaging/__pycache__/version.cpython-39.pyc,, +pkg_resources/_vendor/packaging/_manylinux.py,sha256=XcbiXB-qcjv3bcohp6N98TMpOP4_j3m-iOA8ptK2GWY,11488 +pkg_resources/_vendor/packaging/_musllinux.py,sha256=_KGgY_qc7vhMGpoqss25n2hiLCNKRtvz9mCrS7gkqyc,4378 +pkg_resources/_vendor/packaging/_structures.py,sha256=q3eVNmbWJGG_S0Dit_S3Ao8qQqz_5PYTXFAKBZe5yr4,1431 +pkg_resources/_vendor/packaging/markers.py,sha256=gFSKoBTb0sKDw1v_apJy15lPr0v2mEvuEkfooTtcWx4,8496 +pkg_resources/_vendor/packaging/requirements.py,sha256=uJ4cjwm3_nrfHJLCcGU9mT5aw8SXfw8v1aBUD7OFuVs,4706 +pkg_resources/_vendor/packaging/specifiers.py,sha256=LRQ0kFsHrl5qfcFNEEJrIFYsnIHQUJXY9fIsakTrrqE,30110 +pkg_resources/_vendor/packaging/tags.py,sha256=lmsnGNiJ8C4D_Pf9PbM0qgbZvD9kmB9lpZBQUZa3R_Y,15699 +pkg_resources/_vendor/packaging/utils.py,sha256=dJjeat3BS-TYn1RrUFVwufUMasbtzLfYRoy_HXENeFQ,4200 +pkg_resources/_vendor/packaging/version.py,sha256=_fLRNrFrxYcHVfyo8vk9j8s6JM8N_xsSxVFr6RJyco8,14665 +pkg_resources/_vendor/platformdirs/__init__.py,sha256=edi2JSKpLCapqir0AW_CjpHtinRE3hf6aDk5-VHggLk,12806 +pkg_resources/_vendor/platformdirs/__main__.py,sha256=VsC0t5m-6f0YVr96PVks93G3EDF8MSNY4KpUMvPahDA,1164 +pkg_resources/_vendor/platformdirs/__pycache__/__init__.cpython-39.pyc,, +pkg_resources/_vendor/platformdirs/__pycache__/__main__.cpython-39.pyc,, +pkg_resources/_vendor/platformdirs/__pycache__/android.cpython-39.pyc,, +pkg_resources/_vendor/platformdirs/__pycache__/api.cpython-39.pyc,, +pkg_resources/_vendor/platformdirs/__pycache__/macos.cpython-39.pyc,, +pkg_resources/_vendor/platformdirs/__pycache__/unix.cpython-39.pyc,, +pkg_resources/_vendor/platformdirs/__pycache__/version.cpython-39.pyc,, +pkg_resources/_vendor/platformdirs/__pycache__/windows.cpython-39.pyc,, +pkg_resources/_vendor/platformdirs/android.py,sha256=GKizhyS7ESRiU67u8UnBJLm46goau9937EchXWbPBlk,4068 +pkg_resources/_vendor/platformdirs/api.py,sha256=MXKHXOL3eh_-trSok-JUTjAR_zjmmKF3rjREVABjP8s,4910 +pkg_resources/_vendor/platformdirs/macos.py,sha256=-3UXQewbT0yMhMdkzRXfXGAntmLIH7Qt4a9Hlf8I5_Y,2655 +pkg_resources/_vendor/platformdirs/unix.py,sha256=P-WQjSSieE38DXjMDa1t4XHnKJQ5idEaKT0PyXwm8KQ,6911 +pkg_resources/_vendor/platformdirs/version.py,sha256=qaN-fw_htIgKUVXoAuAEVgKxQu3tZ9qE2eiKkWIS7LA,160 +pkg_resources/_vendor/platformdirs/windows.py,sha256=LOrXLgI0CjQldDo2zhOZYGYZ6g4e_cJOCB_pF9aMRWQ,6596 +pkg_resources/_vendor/pyparsing/__init__.py,sha256=52QH3lgPbJhba0estckoGPHRH8JvQSSCGoWiEn2m0bU,9159 +pkg_resources/_vendor/pyparsing/__pycache__/__init__.cpython-39.pyc,, +pkg_resources/_vendor/pyparsing/__pycache__/actions.cpython-39.pyc,, +pkg_resources/_vendor/pyparsing/__pycache__/common.cpython-39.pyc,, +pkg_resources/_vendor/pyparsing/__pycache__/core.cpython-39.pyc,, +pkg_resources/_vendor/pyparsing/__pycache__/exceptions.cpython-39.pyc,, +pkg_resources/_vendor/pyparsing/__pycache__/helpers.cpython-39.pyc,, +pkg_resources/_vendor/pyparsing/__pycache__/results.cpython-39.pyc,, +pkg_resources/_vendor/pyparsing/__pycache__/testing.cpython-39.pyc,, +pkg_resources/_vendor/pyparsing/__pycache__/unicode.cpython-39.pyc,, +pkg_resources/_vendor/pyparsing/__pycache__/util.cpython-39.pyc,, +pkg_resources/_vendor/pyparsing/actions.py,sha256=wU9i32e0y1ymxKE3OUwSHO-SFIrt1h_wv6Ws0GQjpNU,6426 +pkg_resources/_vendor/pyparsing/common.py,sha256=lFL97ooIeR75CmW5hjURZqwDCTgruqltcTCZ-ulLO2Q,12936 +pkg_resources/_vendor/pyparsing/core.py,sha256=u8GptQE_H6wMkl8OZhxeK1aAPIDXXNgwdShORBwBVS4,213310 +pkg_resources/_vendor/pyparsing/diagram/__init__.py,sha256=f_EfxahqrdkRVahmTwLJXkZ9EEDKNd-O7lBbpJYlE1g,23668 +pkg_resources/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-39.pyc,, +pkg_resources/_vendor/pyparsing/exceptions.py,sha256=3LbSafD32NYb1Tzt85GHNkhEAU1eZkTtNSk24cPMemo,9023 +pkg_resources/_vendor/pyparsing/helpers.py,sha256=QpUOjW0-psvueMwWb9bQpU2noqKCv98_wnw1VSzSdVo,39129 +pkg_resources/_vendor/pyparsing/results.py,sha256=HgNvWVXBdQP-Q6PtJfoCEeOJk2nwEvG-2KVKC5sGA30,25341 +pkg_resources/_vendor/pyparsing/testing.py,sha256=7tu4Abp4uSeJV0N_yEPRmmNUhpd18ZQP3CrX41DM814,13402 +pkg_resources/_vendor/pyparsing/unicode.py,sha256=fwuhMj30SQ165Cv7HJpu-rSxGbRm93kN9L4Ei7VGc1Y,10787 +pkg_resources/_vendor/pyparsing/util.py,sha256=kq772O5YSeXOSdP-M31EWpbH_ayj7BMHImBYo9xPD5M,6805 +pkg_resources/_vendor/typing_extensions.py,sha256=ipqWiq5AHzrwczt6c26AP05Llh6a5_GaXRpOBqbogHA,80078 +pkg_resources/_vendor/zipp.py,sha256=ajztOH-9I7KA_4wqDYygtHa6xUBVZgFpmZ8FE74HHHI,8425 +pkg_resources/extern/__init__.py,sha256=E5tEMzbV1FK5GjJmYo_sxZBvOqgFhGC6pv6-FKcgnWY,2459 +pkg_resources/extern/__pycache__/__init__.cpython-39.pyc,, +setuptools-66.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +setuptools-66.0.0.dist-info/LICENSE,sha256=2z8CRrH5J48VhFuZ_sR4uLUG63ZIeZNyL4xuJUKF-vg,1050 +setuptools-66.0.0.dist-info/METADATA,sha256=FIqgZoY9k-oNvkoeXZj1Nz3oyz3n5vES_hDFsBhbSeg,6213 +setuptools-66.0.0.dist-info/RECORD,, +setuptools-66.0.0.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92 +setuptools-66.0.0.dist-info/entry_points.txt,sha256=3siAu4kYm1ybFJHJ7ooqpX5TAW70Gitp9dcdHC-7BFM,2740 +setuptools-66.0.0.dist-info/top_level.txt,sha256=d9yL39v_W7qmKDDSH6sT4bE0j_Ls1M3P161OGgdsm4g,41 +setuptools/__init__.py,sha256=DqL4WTwyXFp0OakiBKz0HfB0nH4Fm06b3PX8sJWUg88,8429 +setuptools/__pycache__/__init__.cpython-39.pyc,, +setuptools/__pycache__/_deprecation_warning.cpython-39.pyc,, +setuptools/__pycache__/_entry_points.cpython-39.pyc,, +setuptools/__pycache__/_imp.cpython-39.pyc,, +setuptools/__pycache__/_importlib.cpython-39.pyc,, +setuptools/__pycache__/_itertools.cpython-39.pyc,, +setuptools/__pycache__/_path.cpython-39.pyc,, +setuptools/__pycache__/_reqs.cpython-39.pyc,, +setuptools/__pycache__/archive_util.cpython-39.pyc,, +setuptools/__pycache__/build_meta.cpython-39.pyc,, +setuptools/__pycache__/dep_util.cpython-39.pyc,, +setuptools/__pycache__/depends.cpython-39.pyc,, +setuptools/__pycache__/discovery.cpython-39.pyc,, +setuptools/__pycache__/dist.cpython-39.pyc,, +setuptools/__pycache__/errors.cpython-39.pyc,, +setuptools/__pycache__/extension.cpython-39.pyc,, +setuptools/__pycache__/glob.cpython-39.pyc,, +setuptools/__pycache__/installer.cpython-39.pyc,, +setuptools/__pycache__/launch.cpython-39.pyc,, +setuptools/__pycache__/logging.cpython-39.pyc,, +setuptools/__pycache__/monkey.cpython-39.pyc,, +setuptools/__pycache__/msvc.cpython-39.pyc,, +setuptools/__pycache__/namespaces.cpython-39.pyc,, +setuptools/__pycache__/package_index.cpython-39.pyc,, +setuptools/__pycache__/py34compat.cpython-39.pyc,, +setuptools/__pycache__/sandbox.cpython-39.pyc,, +setuptools/__pycache__/unicode_utils.cpython-39.pyc,, +setuptools/__pycache__/version.cpython-39.pyc,, +setuptools/__pycache__/wheel.cpython-39.pyc,, +setuptools/__pycache__/windows_support.cpython-39.pyc,, +setuptools/_deprecation_warning.py,sha256=jU9-dtfv6cKmtQJOXN8nP1mm7gONw5kKEtiPtbwnZyI,218 +setuptools/_distutils/__init__.py,sha256=swqU6jm29LbH4slGa3UTxYAaMUCLOzPY1qTMa4tv7PE,359 +setuptools/_distutils/__pycache__/__init__.cpython-39.pyc,, +setuptools/_distutils/__pycache__/_collections.cpython-39.pyc,, +setuptools/_distutils/__pycache__/_functools.cpython-39.pyc,, +setuptools/_distutils/__pycache__/_log.cpython-39.pyc,, +setuptools/_distutils/__pycache__/_macos_compat.cpython-39.pyc,, +setuptools/_distutils/__pycache__/_msvccompiler.cpython-39.pyc,, +setuptools/_distutils/__pycache__/archive_util.cpython-39.pyc,, +setuptools/_distutils/__pycache__/bcppcompiler.cpython-39.pyc,, +setuptools/_distutils/__pycache__/ccompiler.cpython-39.pyc,, +setuptools/_distutils/__pycache__/cmd.cpython-39.pyc,, +setuptools/_distutils/__pycache__/config.cpython-39.pyc,, +setuptools/_distutils/__pycache__/core.cpython-39.pyc,, +setuptools/_distutils/__pycache__/cygwinccompiler.cpython-39.pyc,, +setuptools/_distutils/__pycache__/debug.cpython-39.pyc,, +setuptools/_distutils/__pycache__/dep_util.cpython-39.pyc,, +setuptools/_distutils/__pycache__/dir_util.cpython-39.pyc,, +setuptools/_distutils/__pycache__/dist.cpython-39.pyc,, +setuptools/_distutils/__pycache__/errors.cpython-39.pyc,, +setuptools/_distutils/__pycache__/extension.cpython-39.pyc,, +setuptools/_distutils/__pycache__/fancy_getopt.cpython-39.pyc,, +setuptools/_distutils/__pycache__/file_util.cpython-39.pyc,, +setuptools/_distutils/__pycache__/filelist.cpython-39.pyc,, +setuptools/_distutils/__pycache__/log.cpython-39.pyc,, +setuptools/_distutils/__pycache__/msvc9compiler.cpython-39.pyc,, +setuptools/_distutils/__pycache__/msvccompiler.cpython-39.pyc,, +setuptools/_distutils/__pycache__/py38compat.cpython-39.pyc,, +setuptools/_distutils/__pycache__/py39compat.cpython-39.pyc,, +setuptools/_distutils/__pycache__/spawn.cpython-39.pyc,, +setuptools/_distutils/__pycache__/sysconfig.cpython-39.pyc,, +setuptools/_distutils/__pycache__/text_file.cpython-39.pyc,, +setuptools/_distutils/__pycache__/unixccompiler.cpython-39.pyc,, +setuptools/_distutils/__pycache__/util.cpython-39.pyc,, +setuptools/_distutils/__pycache__/version.cpython-39.pyc,, +setuptools/_distutils/__pycache__/versionpredicate.cpython-39.pyc,, +setuptools/_distutils/_collections.py,sha256=MfGW9qk6SkMwIWYqdph95fvPGdhgriVCbMTFND2jQ1g,5305 +setuptools/_distutils/_functools.py,sha256=ABZ-Lyw-igKwBFoLF3QYtFmfutwZLiAdWcpRMbcacGU,411 +setuptools/_distutils/_log.py,sha256=zwFOk2ValRHMQa_kCqDXpHnwaqqZzhxGEwuR4zV-dEs,43 +setuptools/_distutils/_macos_compat.py,sha256=-v_Z0M1LEH5k-VhSBBbuz_pDp3nSZ4rzU9E7iIskPDc,239 +setuptools/_distutils/_msvccompiler.py,sha256=2BJnJ2xQFQZyftYi_kgz6DT1nVB-RxqEgd_pUz3qYO4,19641 +setuptools/_distutils/archive_util.py,sha256=JtMIta8JuFkCXVTHvZhmneAEdIMnpsdX84nOWKF24rk,8572 +setuptools/_distutils/bcppcompiler.py,sha256=claWCdHFRSgByxTJy3LG2LdqCGmgy9gtXGlhq-SInzQ,14752 +setuptools/_distutils/ccompiler.py,sha256=ZRMg5BKwFGfMd9hoRscEm-2JkEUVYG83ssaAFa9NZfI,47311 +setuptools/_distutils/cmd.py,sha256=pbvM1mE3KRK0pwu1JlKucLmTvsDZlTMklRNHCjxCP1U,17867 +setuptools/_distutils/command/__init__.py,sha256=fVUps4DJhvShMAod0y7xl02m46bd7r31irEhNofPrrs,430 +setuptools/_distutils/command/__pycache__/__init__.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/_framework_compat.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/bdist.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/bdist_dumb.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/bdist_rpm.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/build.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/build_clib.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/build_ext.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/build_py.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/build_scripts.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/check.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/clean.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/config.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/install.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/install_data.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/install_egg_info.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/install_headers.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/install_lib.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/install_scripts.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/py37compat.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/register.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/sdist.cpython-39.pyc,, +setuptools/_distutils/command/__pycache__/upload.cpython-39.pyc,, +setuptools/_distutils/command/_framework_compat.py,sha256=HW84Z1cWmg4b6aMJvlMI9o6sGZSEH_aWMTlDKstL8lY,1614 +setuptools/_distutils/command/bdist.py,sha256=Zzg5OBMzubEd7zcvm5YrtqS3N-0pAUj9VJCCWEBFa7g,5409 +setuptools/_distutils/command/bdist_dumb.py,sha256=OldkwJUb4oNzmacrPFfYuRbXK4saYg1cVt5K8UBjn7I,4666 +setuptools/_distutils/command/bdist_rpm.py,sha256=HvYKZCogAHRtwBYVpGxtMvfw7qfFb2-4443kc0WGJ_k,22016 +setuptools/_distutils/command/build.py,sha256=u5v5dE6F44KfPTdnERYpP0XKS0sScia8WA6RicJidpA,5585 +setuptools/_distutils/command/build_clib.py,sha256=1FWSWDWik2R-Dswms5S2fGt0ApahAfHzcRpSG4QKNUA,7693 +setuptools/_distutils/command/build_ext.py,sha256=fQfpwzP77lEtfQ7aZzAZ8sGTgXxocl2LgaZmk8Vfmj4,31514 +setuptools/_distutils/command/build_py.py,sha256=j9VIdUua3_ZSLEW6BWuWNxUIHWmV7brZDTZDtIzn5D4,16544 +setuptools/_distutils/command/build_scripts.py,sha256=6YpD8tuybY2p9msIXc0zG5CCJUX4J1WsFEuodhdmWtw,5605 +setuptools/_distutils/command/check.py,sha256=f7QOy4LkKUXiRyyti4orzCJX9Z8sY_uOyMYUADADG6g,4872 +setuptools/_distutils/command/clean.py,sha256=UvsVh_xrDx48CZC9ZM2gk8l_-FP65soHLsrh5nfENy0,2595 +setuptools/_distutils/command/config.py,sha256=0bV9VhyxrLs5f4gdXAA8Ulq8_X1hTffaIXqgobdeFu0,13078 +setuptools/_distutils/command/install.py,sha256=kbXnkHk7rv1xvHEN7b285ouKVsoYi3cNa2RsT1fkVoM,30165 +setuptools/_distutils/command/install_data.py,sha256=Xkyi69RZzeB0LZnA54s1lAXU_15oOlkaF9SiOhBhHlA,2763 +setuptools/_distutils/command/install_egg_info.py,sha256=Cv69kqrFORuwb1I1owe-IxyK0ZANirqGgiLyxcYSnBI,2788 +setuptools/_distutils/command/install_headers.py,sha256=H1JMCAYpuDzCUva2m1AkprHfnTiZqNSq_UHXEGaxzQo,1181 +setuptools/_distutils/command/install_lib.py,sha256=FwMicMNktfnr6kzqtD-10YbiCXng-W9DbTcyWggyD7o,8410 +setuptools/_distutils/command/install_scripts.py,sha256=c_kfAU7LKSKETupXr6kdE2K4S_pWc5jj7rqhEpO9fyY,1933 +setuptools/_distutils/command/py37compat.py,sha256=EoJC8gVYMIv2tA1NpVA2XDyCT1qGp4BEn7aX_5ve1gw,672 +setuptools/_distutils/command/register.py,sha256=1ZkaxvsQQeGy_VW42nJka0FeUMHu9pCdKfA7avspZqY,11818 +setuptools/_distutils/command/sdist.py,sha256=_1eV7GZYs2cYnDlab5OR4b3IgRs2WF9UdgMnSKoQoW8,19196 +setuptools/_distutils/command/upload.py,sha256=zn7ph7ft-L9zUw_UmNSTffBY90qRD8cFLixaDAXt_YQ,7492 +setuptools/_distutils/config.py,sha256=NrQjaUO9B88P-JtOfww3BMt9rSn1TirU4G7u0ut5FrM,4911 +setuptools/_distutils/core.py,sha256=td9vxB2oqIsyBCv-wnedZRWZrzYb3uIGilNtle2N2tg,9397 +setuptools/_distutils/cygwinccompiler.py,sha256=KGamMxV6dIb_IopimrVdN7Gqi5vCT1wrU0qgqrq6DFs,11942 +setuptools/_distutils/debug.py,sha256=N6MrTAqK6l9SVk6tWweR108PM8Ol7qNlfyV-nHcLhsY,139 +setuptools/_distutils/dep_util.py,sha256=9pqhyGw2q2HGGGXAOpbbezj024aAr_47xDfXz5Fas7U,3414 +setuptools/_distutils/dir_util.py,sha256=J4nOKIoP32yARHEYPIRxKDr5dDDDZ_9rUWwR79Fl6LI,8072 +setuptools/_distutils/dist.py,sha256=BWq3AXCfawVM6tz4rkglJIkwDSkby_Rq6NJYyWQpbiA,50190 +setuptools/_distutils/errors.py,sha256=ZtBwnhDpQA2bxIazPXNDQ25uNxM4p2omsaSRNpV3rpE,3589 +setuptools/_distutils/extension.py,sha256=F0TBNjYkMmte_Yg1bhKVHXSNWWNFEPIDUgwhuHdkox8,10270 +setuptools/_distutils/fancy_getopt.py,sha256=n4QHj6LtDTdBn4bqgZ_rqGVhtFw9tvpnI6k8HbepyiY,17901 +setuptools/_distutils/file_util.py,sha256=YCXV_p8yCNywx6wGdnfmBQx7aJPCt7vdcR6AXjL20GQ,8213 +setuptools/_distutils/filelist.py,sha256=rOKJPBvuLSjElfYuOwju95AzR3Ev5lvJoCJvI_XvZ9g,13715 +setuptools/_distutils/log.py,sha256=725W7ISJzoSYNtLnEP1FwZe_IMUn1Xq6NEYwFbXg63k,1201 +setuptools/_distutils/msvc9compiler.py,sha256=4wXPx2KlT4xcoLuM_RZ7O-LK9kwEm4OXpj72Fh6cTfQ,30204 +setuptools/_distutils/msvccompiler.py,sha256=4j7mR6JWMh9Xt9V0slOqNcu-BIbeqrd5mnxzOEYkxqM,23580 +setuptools/_distutils/py38compat.py,sha256=gZ-NQ5c6ufwVEkJ0BwkbrqG9TvWirVJIrVGqhgvaY-Q,217 +setuptools/_distutils/py39compat.py,sha256=vkxjv22H1bhToalClz3M0UUD8Xr21klbUBTQoVQxx20,639 +setuptools/_distutils/spawn.py,sha256=E6Il74CIINCRjakXUcWqSWjfC_sdp4Qtod0Bw5y_NNQ,3495 +setuptools/_distutils/sysconfig.py,sha256=i4rh3y4EyDk05eKa2wY0MmrmWZvDyz_b8Y149P4Imtg,18774 +setuptools/_distutils/text_file.py,sha256=tLjIJVBu7VMY2ZamSpQ9aBv0kbvX9_Abt26cjAAgHiQ,12096 +setuptools/_distutils/unixccompiler.py,sha256=7EpD-X7nAPYnnA8C12YdJaXezog2xtOegCjcFFMOGUc,15602 +setuptools/_distutils/util.py,sha256=Qx17Q8C68fT4FvaXeBfeY5Pzu76I6SlYneZAGCqXCtE,18097 +setuptools/_distutils/version.py,sha256=6HV4l0tHESXxMJMDwd5Fn8Y9_U8ivZIowFCNXhCSnRM,12952 +setuptools/_distutils/versionpredicate.py,sha256=mkg9LtyF3EWox-KnbBx08gKV8zu0ymIl1izIho2-f7k,5205 +setuptools/_entry_points.py,sha256=FL1tONMODSygpiA_3rN_46k-HSmKqf3LgoxJdUpvox8,2282 +setuptools/_imp.py,sha256=HmF91IbitRfsD5z-g4_wmcuH-RahyIONbPgiCOFgtzA,2392 +setuptools/_importlib.py,sha256=1RLRzpNCPKEJRbUPVIPU1-H9dzUXulyL6N_ryxnjEwc,1311 +setuptools/_itertools.py,sha256=pZAgXNz6tRPUFnHAaKJ90xAgD0gLPemcE1396Zgz73o,675 +setuptools/_path.py,sha256=9GdbEur6f_lWmokar-Y-DDyds-XmzYnXrcBy0DExwDw,749 +setuptools/_reqs.py,sha256=ApdTOmDFyK7hbHDnAH8VwhtVD5kvnOthyMNTmrUeFXs,501 +setuptools/_vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +setuptools/_vendor/__pycache__/__init__.cpython-39.pyc,, +setuptools/_vendor/__pycache__/ordered_set.cpython-39.pyc,, +setuptools/_vendor/__pycache__/typing_extensions.cpython-39.pyc,, +setuptools/_vendor/__pycache__/zipp.cpython-39.pyc,, +setuptools/_vendor/importlib_metadata/__init__.py,sha256=xRXwTtvg4EAYuBotYeGawbjraQD4GFIvKgMClxApCDY,30130 +setuptools/_vendor/importlib_metadata/__pycache__/__init__.cpython-39.pyc,, +setuptools/_vendor/importlib_metadata/__pycache__/_adapters.cpython-39.pyc,, +setuptools/_vendor/importlib_metadata/__pycache__/_collections.cpython-39.pyc,, +setuptools/_vendor/importlib_metadata/__pycache__/_compat.cpython-39.pyc,, +setuptools/_vendor/importlib_metadata/__pycache__/_functools.cpython-39.pyc,, +setuptools/_vendor/importlib_metadata/__pycache__/_itertools.cpython-39.pyc,, +setuptools/_vendor/importlib_metadata/__pycache__/_meta.cpython-39.pyc,, +setuptools/_vendor/importlib_metadata/__pycache__/_text.cpython-39.pyc,, +setuptools/_vendor/importlib_metadata/_adapters.py,sha256=B6fCi5-8mLVDFUZj3krI5nAo-mKp1dH_qIavyIyFrJs,1862 +setuptools/_vendor/importlib_metadata/_collections.py,sha256=CJ0OTCHIjWA0ZIVS4voORAsn2R4R2cQBEtPsZEJpASY,743 +setuptools/_vendor/importlib_metadata/_compat.py,sha256=cotBaMUB-2pIRZboQnWp9fEqm6Dwlypndn-EEn0bj5M,1828 +setuptools/_vendor/importlib_metadata/_functools.py,sha256=PsY2-4rrKX4RVeRC1oGp1lB1pmC9eKN88_f-bD9uOoA,2895 +setuptools/_vendor/importlib_metadata/_itertools.py,sha256=cvr_2v8BRbxcIl5x5ldfqdHjhI8Yi8s8yk50G_nm6jQ,2068 +setuptools/_vendor/importlib_metadata/_meta.py,sha256=_F48Hu_jFxkfKWz5wcYS8vO23qEygbVdF9r-6qh-hjE,1154 +setuptools/_vendor/importlib_metadata/_text.py,sha256=HCsFksZpJLeTP3NEk_ngrAeXVRRtTrtyh9eOABoRP4A,2166 +setuptools/_vendor/importlib_resources/__init__.py,sha256=evPm12kLgYqTm-pbzm60bOuumumT8IpBNWFp0uMyrzE,506 +setuptools/_vendor/importlib_resources/__pycache__/__init__.cpython-39.pyc,, +setuptools/_vendor/importlib_resources/__pycache__/_adapters.cpython-39.pyc,, +setuptools/_vendor/importlib_resources/__pycache__/_common.cpython-39.pyc,, +setuptools/_vendor/importlib_resources/__pycache__/_compat.cpython-39.pyc,, +setuptools/_vendor/importlib_resources/__pycache__/_itertools.cpython-39.pyc,, +setuptools/_vendor/importlib_resources/__pycache__/_legacy.cpython-39.pyc,, +setuptools/_vendor/importlib_resources/__pycache__/abc.cpython-39.pyc,, +setuptools/_vendor/importlib_resources/__pycache__/readers.cpython-39.pyc,, +setuptools/_vendor/importlib_resources/__pycache__/simple.cpython-39.pyc,, +setuptools/_vendor/importlib_resources/_adapters.py,sha256=o51tP2hpVtohP33gSYyAkGNpLfYDBqxxYsadyiRZi1E,4504 +setuptools/_vendor/importlib_resources/_common.py,sha256=iIxAaQhotSh6TLLUEfL_ynU2fzEeyHMz9JcL46mUhLg,2741 +setuptools/_vendor/importlib_resources/_compat.py,sha256=nFBCGMvImglrqgYkb9aPgOj68-h6xbw-ca94XOv1-zs,2706 +setuptools/_vendor/importlib_resources/_itertools.py,sha256=WCdJ1Gs_kNFwKENyIG7TO0Y434IWCu0zjVVSsSbZwU8,884 +setuptools/_vendor/importlib_resources/_legacy.py,sha256=TMLkx6aEM6U8xIREPXqGZrMbUhTiPUuPl6ESD7RdYj4,3494 +setuptools/_vendor/importlib_resources/abc.py,sha256=MvTJJXajbl74s36Gyeesf76egtbFnh-TMtzQMVhFWXo,3886 +setuptools/_vendor/importlib_resources/readers.py,sha256=_9QLGQ5AzrED3PY8S2Zf8V6yLR0-nqqYqtQmgleDJzY,3566 +setuptools/_vendor/importlib_resources/simple.py,sha256=xt0qhXbwt3bZ86zuaaKbTiE9A0mDbwu0saRjUq_pcY0,2836 +setuptools/_vendor/jaraco/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +setuptools/_vendor/jaraco/__pycache__/__init__.cpython-39.pyc,, +setuptools/_vendor/jaraco/__pycache__/context.cpython-39.pyc,, +setuptools/_vendor/jaraco/__pycache__/functools.cpython-39.pyc,, +setuptools/_vendor/jaraco/context.py,sha256=NvdB7ArVCDrhtexOnOwSv4ScDuueGbf9LRiOSCqPn6Y,6488 +setuptools/_vendor/jaraco/functools.py,sha256=ap1qoXaNABOx897366NTMEd2objrqAoSO1zuxZPjcmM,13512 +setuptools/_vendor/jaraco/text/__init__.py,sha256=KfFGMerrkN_0V0rgtJVx-9dHt3tW7i_uJypjwEcLtC0,15517 +setuptools/_vendor/jaraco/text/__pycache__/__init__.cpython-39.pyc,, +setuptools/_vendor/more_itertools/__init__.py,sha256=C7sXffHTXM3P-iaLPPfqfmDoxOflQMJLcM7ed9p3jak,82 +setuptools/_vendor/more_itertools/__pycache__/__init__.cpython-39.pyc,, +setuptools/_vendor/more_itertools/__pycache__/more.cpython-39.pyc,, +setuptools/_vendor/more_itertools/__pycache__/recipes.cpython-39.pyc,, +setuptools/_vendor/more_itertools/more.py,sha256=0rB_mibFR51sq33UlAI_bWfaNdsYNnJr1v6S0CaW7QA,117959 +setuptools/_vendor/more_itertools/recipes.py,sha256=UkNkrsZyqiwgLHANBTmvMhCvaNSvSNYhyOpz_Jc55DY,16256 +setuptools/_vendor/ordered_set.py,sha256=dbaCcs27dyN9gnMWGF5nA_BrVn6Q-NrjKYJpV9_fgBs,15130 +setuptools/_vendor/packaging/__about__.py,sha256=ugASIO2w1oUyH8_COqQ2X_s0rDhjbhQC3yJocD03h2c,661 +setuptools/_vendor/packaging/__init__.py,sha256=b9Kk5MF7KxhhLgcDmiUWukN-LatWFxPdNug0joPhHSk,497 +setuptools/_vendor/packaging/__pycache__/__about__.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/__init__.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/_manylinux.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/_musllinux.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/_structures.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/markers.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/requirements.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/specifiers.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/tags.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/utils.cpython-39.pyc,, +setuptools/_vendor/packaging/__pycache__/version.cpython-39.pyc,, +setuptools/_vendor/packaging/_manylinux.py,sha256=XcbiXB-qcjv3bcohp6N98TMpOP4_j3m-iOA8ptK2GWY,11488 +setuptools/_vendor/packaging/_musllinux.py,sha256=_KGgY_qc7vhMGpoqss25n2hiLCNKRtvz9mCrS7gkqyc,4378 +setuptools/_vendor/packaging/_structures.py,sha256=q3eVNmbWJGG_S0Dit_S3Ao8qQqz_5PYTXFAKBZe5yr4,1431 +setuptools/_vendor/packaging/markers.py,sha256=lihRgqpZjLM-JW-vxlLPqU3kmVe79g9vypy1kxmTRuQ,8493 +setuptools/_vendor/packaging/requirements.py,sha256=Opd0FjqgdEiWkzBLyo1oLU0Dj01uIFwTAnAJQrr6j2A,4700 +setuptools/_vendor/packaging/specifiers.py,sha256=LRQ0kFsHrl5qfcFNEEJrIFYsnIHQUJXY9fIsakTrrqE,30110 +setuptools/_vendor/packaging/tags.py,sha256=lmsnGNiJ8C4D_Pf9PbM0qgbZvD9kmB9lpZBQUZa3R_Y,15699 +setuptools/_vendor/packaging/utils.py,sha256=dJjeat3BS-TYn1RrUFVwufUMasbtzLfYRoy_HXENeFQ,4200 +setuptools/_vendor/packaging/version.py,sha256=_fLRNrFrxYcHVfyo8vk9j8s6JM8N_xsSxVFr6RJyco8,14665 +setuptools/_vendor/pyparsing/__init__.py,sha256=52QH3lgPbJhba0estckoGPHRH8JvQSSCGoWiEn2m0bU,9159 +setuptools/_vendor/pyparsing/__pycache__/__init__.cpython-39.pyc,, +setuptools/_vendor/pyparsing/__pycache__/actions.cpython-39.pyc,, +setuptools/_vendor/pyparsing/__pycache__/common.cpython-39.pyc,, +setuptools/_vendor/pyparsing/__pycache__/core.cpython-39.pyc,, +setuptools/_vendor/pyparsing/__pycache__/exceptions.cpython-39.pyc,, +setuptools/_vendor/pyparsing/__pycache__/helpers.cpython-39.pyc,, +setuptools/_vendor/pyparsing/__pycache__/results.cpython-39.pyc,, +setuptools/_vendor/pyparsing/__pycache__/testing.cpython-39.pyc,, +setuptools/_vendor/pyparsing/__pycache__/unicode.cpython-39.pyc,, +setuptools/_vendor/pyparsing/__pycache__/util.cpython-39.pyc,, +setuptools/_vendor/pyparsing/actions.py,sha256=wU9i32e0y1ymxKE3OUwSHO-SFIrt1h_wv6Ws0GQjpNU,6426 +setuptools/_vendor/pyparsing/common.py,sha256=lFL97ooIeR75CmW5hjURZqwDCTgruqltcTCZ-ulLO2Q,12936 +setuptools/_vendor/pyparsing/core.py,sha256=u8GptQE_H6wMkl8OZhxeK1aAPIDXXNgwdShORBwBVS4,213310 +setuptools/_vendor/pyparsing/diagram/__init__.py,sha256=f_EfxahqrdkRVahmTwLJXkZ9EEDKNd-O7lBbpJYlE1g,23668 +setuptools/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-39.pyc,, +setuptools/_vendor/pyparsing/exceptions.py,sha256=3LbSafD32NYb1Tzt85GHNkhEAU1eZkTtNSk24cPMemo,9023 +setuptools/_vendor/pyparsing/helpers.py,sha256=QpUOjW0-psvueMwWb9bQpU2noqKCv98_wnw1VSzSdVo,39129 +setuptools/_vendor/pyparsing/results.py,sha256=HgNvWVXBdQP-Q6PtJfoCEeOJk2nwEvG-2KVKC5sGA30,25341 +setuptools/_vendor/pyparsing/testing.py,sha256=7tu4Abp4uSeJV0N_yEPRmmNUhpd18ZQP3CrX41DM814,13402 +setuptools/_vendor/pyparsing/unicode.py,sha256=fwuhMj30SQ165Cv7HJpu-rSxGbRm93kN9L4Ei7VGc1Y,10787 +setuptools/_vendor/pyparsing/util.py,sha256=kq772O5YSeXOSdP-M31EWpbH_ayj7BMHImBYo9xPD5M,6805 +setuptools/_vendor/tomli/__init__.py,sha256=JhUwV66DB1g4Hvt1UQCVMdfCu-IgAV8FXmvDU9onxd4,396 +setuptools/_vendor/tomli/__pycache__/__init__.cpython-39.pyc,, +setuptools/_vendor/tomli/__pycache__/_parser.cpython-39.pyc,, +setuptools/_vendor/tomli/__pycache__/_re.cpython-39.pyc,, +setuptools/_vendor/tomli/__pycache__/_types.cpython-39.pyc,, +setuptools/_vendor/tomli/_parser.py,sha256=g9-ENaALS-B8dokYpCuzUFalWlog7T-SIYMjLZSWrtM,22633 +setuptools/_vendor/tomli/_re.py,sha256=dbjg5ChZT23Ka9z9DHOXfdtSpPwUfdgMXnj8NOoly-w,2943 +setuptools/_vendor/tomli/_types.py,sha256=-GTG2VUqkpxwMqzmVO4F7ybKddIbAnuAHXfmWQcTi3Q,254 +setuptools/_vendor/typing_extensions.py,sha256=1uqi_RSlI7gos4eJB_NEV3d5wQwzTUQHd3_jrkbTo8Q,87149 +setuptools/_vendor/zipp.py,sha256=ajztOH-9I7KA_4wqDYygtHa6xUBVZgFpmZ8FE74HHHI,8425 +setuptools/archive_util.py,sha256=6WShpDR_uGZOaORRfzBmJyTYtX9xtrhmXTFPqE8kL8s,7346 +setuptools/build_meta.py,sha256=gsOBREDts9wDiGUARQUQgINXnjZVeDmS74maDIqntCg,19595 +setuptools/cli-32.exe,sha256=dfEuovMNnA2HLa3jRfMPVi5tk4R7alCbpTvuxtCyw0Y,65536 +setuptools/cli-64.exe,sha256=KLABu5pyrnokJCv6skjXZ6GsXeyYHGcqOUT3oHI3Xpo,74752 +setuptools/cli-arm64.exe,sha256=o9amxowudZ98NvNWh_a2DRY8LhoIRqTAekxABqltiMc,137216 +setuptools/cli.exe,sha256=dfEuovMNnA2HLa3jRfMPVi5tk4R7alCbpTvuxtCyw0Y,65536 +setuptools/command/__init__.py,sha256=HZlSppOB8Vro73ffvP-xrORuMrh4GnVkOqJspFRG8Pg,396 +setuptools/command/__pycache__/__init__.cpython-39.pyc,, +setuptools/command/__pycache__/alias.cpython-39.pyc,, +setuptools/command/__pycache__/bdist_egg.cpython-39.pyc,, +setuptools/command/__pycache__/bdist_rpm.cpython-39.pyc,, +setuptools/command/__pycache__/build.cpython-39.pyc,, +setuptools/command/__pycache__/build_clib.cpython-39.pyc,, +setuptools/command/__pycache__/build_ext.cpython-39.pyc,, +setuptools/command/__pycache__/build_py.cpython-39.pyc,, +setuptools/command/__pycache__/develop.cpython-39.pyc,, +setuptools/command/__pycache__/dist_info.cpython-39.pyc,, +setuptools/command/__pycache__/easy_install.cpython-39.pyc,, +setuptools/command/__pycache__/editable_wheel.cpython-39.pyc,, +setuptools/command/__pycache__/egg_info.cpython-39.pyc,, +setuptools/command/__pycache__/install.cpython-39.pyc,, +setuptools/command/__pycache__/install_egg_info.cpython-39.pyc,, +setuptools/command/__pycache__/install_lib.cpython-39.pyc,, +setuptools/command/__pycache__/install_scripts.cpython-39.pyc,, +setuptools/command/__pycache__/py36compat.cpython-39.pyc,, +setuptools/command/__pycache__/register.cpython-39.pyc,, +setuptools/command/__pycache__/rotate.cpython-39.pyc,, +setuptools/command/__pycache__/saveopts.cpython-39.pyc,, +setuptools/command/__pycache__/sdist.cpython-39.pyc,, +setuptools/command/__pycache__/setopt.cpython-39.pyc,, +setuptools/command/__pycache__/test.cpython-39.pyc,, +setuptools/command/__pycache__/upload.cpython-39.pyc,, +setuptools/command/__pycache__/upload_docs.cpython-39.pyc,, +setuptools/command/alias.py,sha256=1sLQxZcNh6dDQpDmm4G7UGGTol83nY1NTPmNBbm2siI,2381 +setuptools/command/bdist_egg.py,sha256=QEIu1AkgS02j6ejonJY7kwGp6LNxfMeYZ3sxkd55ftA,16623 +setuptools/command/bdist_rpm.py,sha256=PxrgoHPNaw2Pw2qNjjHDPC-Ay_IaDbCqP3d_5N-cj2A,1182 +setuptools/command/build.py,sha256=cgkmzJhXFXw5lHMPgohJFyEByz8L7H9JurCnk2iRnFI,6589 +setuptools/command/build_clib.py,sha256=Rq4Q5OoyF19o25XQHF1kzTO4XrA_fS1VJGO7Pw5hztk,4423 +setuptools/command/build_ext.py,sha256=cYm4OvllPf6I9YE3cWlnjPqqE546Mc7nQTpdJ-yH3jg,15821 +setuptools/command/build_py.py,sha256=CMoD9Gxd5vs8KfPVNFFD1cmJsCd3l0NJS5kdDTlx4Y4,14115 +setuptools/command/develop.py,sha256=5_Ss7ENd1_B_jVMY1tF5UV_y1Xu6jbVzAPG8oKeluGA,7012 +setuptools/command/dist_info.py,sha256=VdcNHtbPFGdPD_t20wxcROa4uALbyz1RnJMJEHQmrQU,4800 +setuptools/command/easy_install.py,sha256=sx7_Rwpa2wUvPZZTa7jLpY3shEL4Ti2d2u1yIUMahHs,85662 +setuptools/command/editable_wheel.py,sha256=yUCwBNcS75sBqcEOkW9CvRypgQ0dsMTn9646yXftAhk,31188 +setuptools/command/egg_info.py,sha256=xhD6abfvvfLDXSX6lhLVLe0KwMiMyCtVQ0u-pe8gBdM,26983 +setuptools/command/install.py,sha256=CBdw9iITHAc0Zt1YE_8dSWY5BscuTJGrCe2jtEsnepk,5163 +setuptools/command/install_egg_info.py,sha256=pgZ64m_-kmtx3QISHN_kRtMiZC_Y8x1Nr1j38jXEbXQ,2226 +setuptools/command/install_lib.py,sha256=Uz42McsyHZAjrB6cw9E7Bz0xsaTbzxnM1PI9CBhiPtE,3875 +setuptools/command/install_scripts.py,sha256=APFFpt_lYUEo-viMtpXr-Hkwycwq8knTxSTNUu_TwHo,2612 +setuptools/command/launcher manifest.xml,sha256=xlLbjWrB01tKC0-hlVkOKkiSPbzMml2eOPtJ_ucCnbE,628 +setuptools/command/py36compat.py,sha256=7yLWzQj179Enx3pJ8V1cDDCzeLMFMd9XJXlK-iZTq5Y,4946 +setuptools/command/register.py,sha256=kk3DxXCb5lXTvqnhfwx2g6q7iwbUmgTyXUCaBooBOUk,468 +setuptools/command/rotate.py,sha256=SvsQPasezIojPjvMnfkqzh8P0U0tCj0daczF8uc3NQM,2128 +setuptools/command/saveopts.py,sha256=za7QCBcQimKKriWcoCcbhxPjUz30gSB74zuTL47xpP4,658 +setuptools/command/sdist.py,sha256=d8Ty0eCiUKfWh4VTjqV9e8g-02Zsy8L4BcMe1OzIIn8,7071 +setuptools/command/setopt.py,sha256=okxhqD1NM1nQlbSVDCNv6P7Y7g680sc2r-tUW7wPH1Y,5086 +setuptools/command/test.py,sha256=ZWoIUdm6u2Zv-WhvSC5If1rPouxm5JmygwsajNA8WWI,8102 +setuptools/command/upload.py,sha256=XT3YFVfYPAmA5qhGg0euluU98ftxRUW-PzKcODMLxUs,462 +setuptools/command/upload_docs.py,sha256=5lQkUAbSSwDac3_qjaSIogJstQ1Aujh746ZmPQORIjo,7470 +setuptools/config/__init__.py,sha256=Jg48Ac6C8AtdjkAFhe4Kh_xwNUfK6q04CJlJ5LbVMB0,1121 +setuptools/config/__pycache__/__init__.cpython-39.pyc,, +setuptools/config/__pycache__/_apply_pyprojecttoml.cpython-39.pyc,, +setuptools/config/__pycache__/expand.cpython-39.pyc,, +setuptools/config/__pycache__/pyprojecttoml.cpython-39.pyc,, +setuptools/config/__pycache__/setupcfg.cpython-39.pyc,, +setuptools/config/_apply_pyprojecttoml.py,sha256=Ev1RwtQbPiD2za3di5T7ExY8T7TAvMIFot0efIHYzAY,13398 +setuptools/config/_validate_pyproject/__init__.py,sha256=5YXPW1sabVn5jpZ25sUjeF6ij3_4odJiwUWi4nRD2Dc,1038 +setuptools/config/_validate_pyproject/__pycache__/__init__.cpython-39.pyc,, +setuptools/config/_validate_pyproject/__pycache__/error_reporting.cpython-39.pyc,, +setuptools/config/_validate_pyproject/__pycache__/extra_validations.cpython-39.pyc,, +setuptools/config/_validate_pyproject/__pycache__/fastjsonschema_exceptions.cpython-39.pyc,, +setuptools/config/_validate_pyproject/__pycache__/fastjsonschema_validations.cpython-39.pyc,, +setuptools/config/_validate_pyproject/__pycache__/formats.cpython-39.pyc,, +setuptools/config/_validate_pyproject/error_reporting.py,sha256=vWiDs0hjlCBjZ_g4Xszsh97lIP9M4_JaLQ6MCQ26W9U,11266 +setuptools/config/_validate_pyproject/extra_validations.py,sha256=wHzrgfdZUMRPBR1ke1lg5mhqRsBSbjEYOMsuFXQH9jY,1153 +setuptools/config/_validate_pyproject/fastjsonschema_exceptions.py,sha256=w749JgqKi8clBFcObdcbZVqsmF4oJ_QByhZ1SGbUFNw,1612 +setuptools/config/_validate_pyproject/fastjsonschema_validations.py,sha256=oqXSDfYecymwM2I40JGcTB-1P9vd7CtfSIW5kDxZQPM,269900 +setuptools/config/_validate_pyproject/formats.py,sha256=uMUnp4mLIjrQCTe6-LDjtqglmEFLfOW9E1ZZLqOzhMI,8736 +setuptools/config/expand.py,sha256=FQja-T8zG9bV_G1b7SBjWjsZNjvSbhg5vxFWhusSYoE,16319 +setuptools/config/pyprojecttoml.py,sha256=_7mGN0cTfQEvWGA417UKhJaU6yVGfCPX_M-7MF5eMh0,19310 +setuptools/config/setupcfg.py,sha256=aqXdUuB5llJz9hZmQUjganZAyo34lHrRsK6wV1NzX2M,25198 +setuptools/dep_util.py,sha256=BDx1BkzNQntvAB4alypHbW5UVBzjqths000PrUL4Zqc,949 +setuptools/depends.py,sha256=QYQIadr5DwLxPzkErhNt5hmRhvGhWxoXZMRXCm_jcQ0,5499 +setuptools/discovery.py,sha256=5l1rFH0XJB4zgh3hWD9O6ZRLCP9eiNumJ0LMDArPflQ,20818 +setuptools/dist.py,sha256=VXr5yqDtkSA_2FLAjWBS4CxAB_KqVX_EtMKrJaxcXtI,45252 +setuptools/errors.py,sha256=2uToNIRA7dG995pf8ox8a4r7nJtP62-hpLhzsRirnx0,2464 +setuptools/extension.py,sha256=jpsAdQvCBCkAuvmEXYI90TV4kNGO2Y13NqDr_PrvdhA,5591 +setuptools/extern/__init__.py,sha256=LYHS20uf-nl_zBPmrIzTxokYdiVMZNZBYVu6hd8c5zg,2512 +setuptools/extern/__pycache__/__init__.cpython-39.pyc,, +setuptools/glob.py,sha256=1oZjbfjAHSXbgdhSuR6YGU8jKob9L8NtEmBYqcPTLYk,4873 +setuptools/gui-32.exe,sha256=XBr0bHMA6Hpz2s9s9Bzjl-PwXfa9nH4ie0rFn4V2kWA,65536 +setuptools/gui-64.exe,sha256=aYKMhX1IJLn4ULHgWX0sE0yREUt6B3TEHf_jOw6yNyE,75264 +setuptools/gui-arm64.exe,sha256=TEFnOKDi-mq3ZszxqbCoCXTnM_lhUWjdIqBpr6fVs40,137728 +setuptools/gui.exe,sha256=XBr0bHMA6Hpz2s9s9Bzjl-PwXfa9nH4ie0rFn4V2kWA,65536 +setuptools/installer.py,sha256=s6DQfsoICBJxbUqbduhOJtl1oG0S4yegRCg3EAs0i3M,3824 +setuptools/launch.py,sha256=TyPT-Ic1T2EnYvGO26gfNRP4ysBlrhpbRjQxWsiO414,812 +setuptools/logging.py,sha256=WT1k7lH5hL-mOxsdVkrBjGV468QSpwAShlQ6pP09H6g,1232 +setuptools/monkey.py,sha256=t6To7LEhTyOWRRZLwiFv7Eeg2mjHZlVmTdHD1DC94QM,4857 +setuptools/msvc.py,sha256=x6jsjA9JdUew6VAfHapIHgEjAjy-T5dxqjPCZr0Tt04,47724 +setuptools/namespaces.py,sha256=PMqGVPXPYQgjUTvEg9bGccRAkIODrQ6NmsDg_fwErwI,3093 +setuptools/package_index.py,sha256=2KY3YjJf1BvDROl-8gG3IbYSsl6ZeI6nIZZwzK8sU2M,39682 +setuptools/py34compat.py,sha256=KYOd6ybRxjBW8NJmYD8t_UyyVmysppFXqHpFLdslGXU,245 +setuptools/sandbox.py,sha256=mR83i-mu-ZUU_7TaMgYCeRSyzkqv8loJ_GR9xhS2DDw,14348 +setuptools/script (dev).tmpl,sha256=RUzQzCQUaXtwdLtYHWYbIQmOaES5Brqq1FvUA_tu-5I,218 +setuptools/script.tmpl,sha256=WGTt5piezO27c-Dbx6l5Q4T3Ff20A5z7872hv3aAhYY,138 +setuptools/unicode_utils.py,sha256=aOOFo4JGwAsiBttGYDsqFS7YqWQeZ2j6DWiCuctR_00,941 +setuptools/version.py,sha256=og_cuZQb0QI6ukKZFfZWPlr1HgJBPPn2vO2m_bI9ZTE,144 +setuptools/wheel.py,sha256=6LphzUKYfdLnIp9kIUzLGPY-F7MTJr4hiabB5almLps,8376 +setuptools/windows_support.py,sha256=KXrFWrteXjhIou0gGwlfBy0ttAszHP52ETq-2pc0mes,718 diff --git a/venv/Lib/site-packages/setuptools-66.0.0.dist-info/WHEEL b/venv/Lib/site-packages/setuptools-66.0.0.dist-info/WHEEL new file mode 100644 index 0000000..57e3d84 --- /dev/null +++ b/venv/Lib/site-packages/setuptools-66.0.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.38.4) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/setuptools-66.0.0.dist-info/entry_points.txt b/venv/Lib/site-packages/setuptools-66.0.0.dist-info/entry_points.txt new file mode 100644 index 0000000..93df463 --- /dev/null +++ b/venv/Lib/site-packages/setuptools-66.0.0.dist-info/entry_points.txt @@ -0,0 +1,57 @@ +[distutils.commands] +alias = setuptools.command.alias:alias +bdist_egg = setuptools.command.bdist_egg:bdist_egg +bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm +build = setuptools.command.build:build +build_clib = setuptools.command.build_clib:build_clib +build_ext = setuptools.command.build_ext:build_ext +build_py = setuptools.command.build_py:build_py +develop = setuptools.command.develop:develop +dist_info = setuptools.command.dist_info:dist_info +easy_install = setuptools.command.easy_install:easy_install +editable_wheel = setuptools.command.editable_wheel:editable_wheel +egg_info = setuptools.command.egg_info:egg_info +install = setuptools.command.install:install +install_egg_info = setuptools.command.install_egg_info:install_egg_info +install_lib = setuptools.command.install_lib:install_lib +install_scripts = setuptools.command.install_scripts:install_scripts +rotate = setuptools.command.rotate:rotate +saveopts = setuptools.command.saveopts:saveopts +sdist = setuptools.command.sdist:sdist +setopt = setuptools.command.setopt:setopt +test = setuptools.command.test:test +upload_docs = setuptools.command.upload_docs:upload_docs + +[distutils.setup_keywords] +dependency_links = setuptools.dist:assert_string_list +eager_resources = setuptools.dist:assert_string_list +entry_points = setuptools.dist:check_entry_points +exclude_package_data = setuptools.dist:check_package_data +extras_require = setuptools.dist:check_extras +include_package_data = setuptools.dist:assert_bool +install_requires = setuptools.dist:check_requirements +namespace_packages = setuptools.dist:check_nsp +package_data = setuptools.dist:check_package_data +packages = setuptools.dist:check_packages +python_requires = setuptools.dist:check_specifier +setup_requires = setuptools.dist:check_requirements +test_loader = setuptools.dist:check_importable +test_runner = setuptools.dist:check_importable +test_suite = setuptools.dist:check_test_suite +tests_require = setuptools.dist:check_requirements +use_2to3 = setuptools.dist:invalid_unless_false +zip_safe = setuptools.dist:assert_bool + +[egg_info.writers] +PKG-INFO = setuptools.command.egg_info:write_pkg_info +dependency_links.txt = setuptools.command.egg_info:overwrite_arg +depends.txt = setuptools.command.egg_info:warn_depends_obsolete +eager_resources.txt = setuptools.command.egg_info:overwrite_arg +entry_points.txt = setuptools.command.egg_info:write_entries +namespace_packages.txt = setuptools.command.egg_info:overwrite_arg +requires.txt = setuptools.command.egg_info:write_requirements +top_level.txt = setuptools.command.egg_info:write_toplevel_names + +[setuptools.finalize_distribution_options] +keywords = setuptools.dist:Distribution._finalize_setup_keywords +parent_finalize = setuptools.dist:_Distribution.finalize_options diff --git a/venv/Lib/site-packages/setuptools-66.0.0.dist-info/top_level.txt b/venv/Lib/site-packages/setuptools-66.0.0.dist-info/top_level.txt new file mode 100644 index 0000000..b5ac107 --- /dev/null +++ b/venv/Lib/site-packages/setuptools-66.0.0.dist-info/top_level.txt @@ -0,0 +1,3 @@ +_distutils_hack +pkg_resources +setuptools diff --git a/venv/Lib/site-packages/setuptools/_distutils/_collections.py b/venv/Lib/site-packages/setuptools/_distutils/_collections.py new file mode 100644 index 0000000..0255661 --- /dev/null +++ b/venv/Lib/site-packages/setuptools/_distutils/_collections.py @@ -0,0 +1,194 @@ +import collections +import functools +import itertools +import operator + + +# from jaraco.collections 3.5.1 +class DictStack(list, collections.abc.Mapping): + """ + A stack of dictionaries that behaves as a view on those dictionaries, + giving preference to the last. + + >>> stack = DictStack([dict(a=1, c=2), dict(b=2, a=2)]) + >>> stack['a'] + 2 + >>> stack['b'] + 2 + >>> stack['c'] + 2 + >>> len(stack) + 3 + >>> stack.push(dict(a=3)) + >>> stack['a'] + 3 + >>> set(stack.keys()) == set(['a', 'b', 'c']) + True + >>> set(stack.items()) == set([('a', 3), ('b', 2), ('c', 2)]) + True + >>> dict(**stack) == dict(stack) == dict(a=3, c=2, b=2) + True + >>> d = stack.pop() + >>> stack['a'] + 2 + >>> d = stack.pop() + >>> stack['a'] + 1 + >>> stack.get('b', None) + >>> 'c' in stack + True + """ + + def __iter__(self): + dicts = list.__iter__(self) + return iter(set(itertools.chain.from_iterable(c.keys() for c in dicts))) + + def __getitem__(self, key): + for scope in reversed(tuple(list.__iter__(self))): + if key in scope: + return scope[key] + raise KeyError(key) + + push = list.append + + def __contains__(self, other): + return collections.abc.Mapping.__contains__(self, other) + + def __len__(self): + return len(list(iter(self))) + + +# from jaraco.collections 3.7 +class RangeMap(dict): + """ + A dictionary-like object that uses the keys as bounds for a range. + Inclusion of the value for that range is determined by the + key_match_comparator, which defaults to less-than-or-equal. + A value is returned for a key if it is the first key that matches in + the sorted list of keys. + + One may supply keyword parameters to be passed to the sort function used + to sort keys (i.e. key, reverse) as sort_params. + + Let's create a map that maps 1-3 -> 'a', 4-6 -> 'b' + + >>> r = RangeMap({3: 'a', 6: 'b'}) # boy, that was easy + >>> r[1], r[2], r[3], r[4], r[5], r[6] + ('a', 'a', 'a', 'b', 'b', 'b') + + Even float values should work so long as the comparison operator + supports it. + + >>> r[4.5] + 'b' + + But you'll notice that the way rangemap is defined, it must be open-ended + on one side. + + >>> r[0] + 'a' + >>> r[-1] + 'a' + + One can close the open-end of the RangeMap by using undefined_value + + >>> r = RangeMap({0: RangeMap.undefined_value, 3: 'a', 6: 'b'}) + >>> r[0] + Traceback (most recent call last): + ... + KeyError: 0 + + One can get the first or last elements in the range by using RangeMap.Item + + >>> last_item = RangeMap.Item(-1) + >>> r[last_item] + 'b' + + .last_item is a shortcut for Item(-1) + + >>> r[RangeMap.last_item] + 'b' + + Sometimes it's useful to find the bounds for a RangeMap + + >>> r.bounds() + (0, 6) + + RangeMap supports .get(key, default) + + >>> r.get(0, 'not found') + 'not found' + + >>> r.get(7, 'not found') + 'not found' + + One often wishes to define the ranges by their left-most values, + which requires use of sort params and a key_match_comparator. + + >>> r = RangeMap({1: 'a', 4: 'b'}, + ... sort_params=dict(reverse=True), + ... key_match_comparator=operator.ge) + >>> r[1], r[2], r[3], r[4], r[5], r[6] + ('a', 'a', 'a', 'b', 'b', 'b') + + That wasn't nearly as easy as before, so an alternate constructor + is provided: + + >>> r = RangeMap.left({1: 'a', 4: 'b', 7: RangeMap.undefined_value}) + >>> r[1], r[2], r[3], r[4], r[5], r[6] + ('a', 'a', 'a', 'b', 'b', 'b') + + """ + + def __init__(self, source, sort_params={}, key_match_comparator=operator.le): + dict.__init__(self, source) + self.sort_params = sort_params + self.match = key_match_comparator + + @classmethod + def left(cls, source): + return cls( + source, sort_params=dict(reverse=True), key_match_comparator=operator.ge + ) + + def __getitem__(self, item): + sorted_keys = sorted(self.keys(), **self.sort_params) + if isinstance(item, RangeMap.Item): + result = self.__getitem__(sorted_keys[item]) + else: + key = self._find_first_match_(sorted_keys, item) + result = dict.__getitem__(self, key) + if result is RangeMap.undefined_value: + raise KeyError(key) + return result + + def get(self, key, default=None): + """ + Return the value for key if key is in the dictionary, else default. + If default is not given, it defaults to None, so that this method + never raises a KeyError. + """ + try: + return self[key] + except KeyError: + return default + + def _find_first_match_(self, keys, item): + is_match = functools.partial(self.match, item) + matches = list(filter(is_match, keys)) + if matches: + return matches[0] + raise KeyError(item) + + def bounds(self): + sorted_keys = sorted(self.keys(), **self.sort_params) + return (sorted_keys[RangeMap.first_item], sorted_keys[RangeMap.last_item]) + + # some special values for the RangeMap + undefined_value = type(str('RangeValueUndefined'), (), {})() + + class Item(int): + "RangeMap Item" + + first_item = Item(0) + last_item = Item(-1) diff --git a/venv/Lib/site-packages/setuptools/_distutils/_functools.py b/venv/Lib/site-packages/setuptools/_distutils/_functools.py new file mode 100644 index 0000000..e7053ba --- /dev/null +++ b/venv/Lib/site-packages/setuptools/_distutils/_functools.py @@ -0,0 +1,20 @@ +import functools + + +# from jaraco.functools 3.5 +def pass_none(func): + """ + Wrap func so it's not called if its first param is None + + >>> print_text = pass_none(print) + >>> print_text('text') + text + >>> print_text(None) + """ + + @functools.wraps(func) + def wrapper(param, *args, **kwargs): + if param is not None: + return func(param, *args, **kwargs) + + return wrapper diff --git a/venv/Lib/site-packages/setuptools/_distutils/_log.py b/venv/Lib/site-packages/setuptools/_distutils/_log.py new file mode 100644 index 0000000..4a2ae0a --- /dev/null +++ b/venv/Lib/site-packages/setuptools/_distutils/_log.py @@ -0,0 +1,4 @@ +import logging + + +log = logging.getLogger() diff --git a/venv/Lib/site-packages/setuptools/_distutils/_macos_compat.py b/venv/Lib/site-packages/setuptools/_distutils/_macos_compat.py new file mode 100644 index 0000000..17769e9 --- /dev/null +++ b/venv/Lib/site-packages/setuptools/_distutils/_macos_compat.py @@ -0,0 +1,12 @@ +import sys +import importlib + + +def bypass_compiler_fixup(cmd, args): + return cmd + + +if sys.platform == 'darwin': + compiler_fixup = importlib.import_module('_osx_support').compiler_fixup +else: + compiler_fixup = bypass_compiler_fixup diff --git a/venv/Lib/site-packages/setuptools/_distutils/command/_framework_compat.py b/venv/Lib/site-packages/setuptools/_distutils/command/_framework_compat.py new file mode 100644 index 0000000..cffa27c --- /dev/null +++ b/venv/Lib/site-packages/setuptools/_distutils/command/_framework_compat.py @@ -0,0 +1,55 @@ +""" +Backward compatibility for homebrew builds on macOS. +""" + + +import sys +import os +import functools +import subprocess +import sysconfig + + +@functools.lru_cache() +def enabled(): + """ + Only enabled for Python 3.9 framework homebrew builds + except ensurepip and venv. + """ + PY39 = (3, 9) < sys.version_info < (3, 10) + framework = sys.platform == 'darwin' and sys._framework + homebrew = "Cellar" in sysconfig.get_config_var('projectbase') + venv = sys.prefix != sys.base_prefix + ensurepip = os.environ.get("ENSUREPIP_OPTIONS") + return PY39 and framework and homebrew and not venv and not ensurepip + + +schemes = dict( + osx_framework_library=dict( + stdlib='{installed_base}/{platlibdir}/python{py_version_short}', + platstdlib='{platbase}/{platlibdir}/python{py_version_short}', + purelib='{homebrew_prefix}/lib/python{py_version_short}/site-packages', + platlib='{homebrew_prefix}/{platlibdir}/python{py_version_short}/site-packages', + include='{installed_base}/include/python{py_version_short}{abiflags}', + platinclude='{installed_platbase}/include/python{py_version_short}{abiflags}', + scripts='{homebrew_prefix}/bin', + data='{homebrew_prefix}', + ) +) + + +@functools.lru_cache() +def vars(): + if not enabled(): + return {} + homebrew_prefix = subprocess.check_output(['brew', '--prefix'], text=True).strip() + return locals() + + +def scheme(name): + """ + Override the selected scheme for posix_prefix. + """ + if not enabled() or not name.endswith('_prefix'): + return name + return 'osx_framework_library' diff --git a/venv/Lib/site-packages/setuptools/_distutils/command/py37compat.py b/venv/Lib/site-packages/setuptools/_distutils/command/py37compat.py new file mode 100644 index 0000000..aa0c0a7 --- /dev/null +++ b/venv/Lib/site-packages/setuptools/_distutils/command/py37compat.py @@ -0,0 +1,31 @@ +import sys + + +def _pythonlib_compat(): + """ + On Python 3.7 and earlier, distutils would include the Python + library. See pypa/distutils#9. + """ + from distutils import sysconfig + + if not sysconfig.get_config_var('Py_ENABLED_SHARED'): + return + + yield 'python{}.{}{}'.format( + sys.hexversion >> 24, + (sys.hexversion >> 16) & 0xFF, + sysconfig.get_config_var('ABIFLAGS'), + ) + + +def compose(f1, f2): + return lambda *args, **kwargs: f1(f2(*args, **kwargs)) + + +pythonlib = ( + compose(list, _pythonlib_compat) + if sys.version_info < (3, 8) + and sys.platform != 'darwin' + and sys.platform[:3] != 'aix' + else list +) diff --git a/venv/Lib/site-packages/setuptools/_distutils/py38compat.py b/venv/Lib/site-packages/setuptools/_distutils/py38compat.py new file mode 100644 index 0000000..59224e7 --- /dev/null +++ b/venv/Lib/site-packages/setuptools/_distutils/py38compat.py @@ -0,0 +1,8 @@ +def aix_platform(osname, version, release): + try: + import _aix_support + + return _aix_support.aix_platform() + except ImportError: + pass + return "{}-{}.{}".format(osname, version, release) diff --git a/venv/Lib/site-packages/setuptools/_distutils/py39compat.py b/venv/Lib/site-packages/setuptools/_distutils/py39compat.py new file mode 100644 index 0000000..c43e5f1 --- /dev/null +++ b/venv/Lib/site-packages/setuptools/_distutils/py39compat.py @@ -0,0 +1,22 @@ +import sys +import platform + + +def add_ext_suffix_39(vars): + """ + Ensure vars contains 'EXT_SUFFIX'. pypa/distutils#130 + """ + import _imp + + ext_suffix = _imp.extension_suffixes()[0] + vars.update( + EXT_SUFFIX=ext_suffix, + # sysconfig sets SO to match EXT_SUFFIX, so maintain + # that expectation. + # https://github.com/python/cpython/blob/785cc6770588de087d09e89a69110af2542be208/Lib/sysconfig.py#L671-L673 + SO=ext_suffix, + ) + + +needs_ext_suffix = sys.version_info < (3, 10) and platform.system() == 'Windows' +add_ext_suffix = add_ext_suffix_39 if needs_ext_suffix else lambda vars: None diff --git a/venv/Lib/site-packages/setuptools/_entry_points.py b/venv/Lib/site-packages/setuptools/_entry_points.py new file mode 100644 index 0000000..a234634 --- /dev/null +++ b/venv/Lib/site-packages/setuptools/_entry_points.py @@ -0,0 +1,94 @@ +import functools +import operator +import itertools + +from .errors import OptionError +from .extern.jaraco.text import yield_lines +from .extern.jaraco.functools import pass_none +from ._importlib import metadata +from ._itertools import ensure_unique +from .extern.more_itertools import consume + + +def ensure_valid(ep): + """ + Exercise one of the dynamic properties to trigger + the pattern match. + """ + try: + ep.extras + except AttributeError as ex: + msg = ( + f"Problems to parse {ep}.\nPlease ensure entry-point follows the spec: " + "https://packaging.python.org/en/latest/specifications/entry-points/" + ) + raise OptionError(msg) from ex + + +def load_group(value, group): + """ + Given a value of an entry point or series of entry points, + return each as an EntryPoint. + """ + # normalize to a single sequence of lines + lines = yield_lines(value) + text = f'[{group}]\n' + '\n'.join(lines) + return metadata.EntryPoints._from_text(text) + + +def by_group_and_name(ep): + return ep.group, ep.name + + +def validate(eps: metadata.EntryPoints): + """ + Ensure entry points are unique by group and name and validate each. + """ + consume(map(ensure_valid, ensure_unique(eps, key=by_group_and_name))) + return eps + + +@functools.singledispatch +def load(eps): + """ + Given a Distribution.entry_points, produce EntryPoints. + """ + groups = itertools.chain.from_iterable( + load_group(value, group) + for group, value in eps.items()) + return validate(metadata.EntryPoints(groups)) + + +@load.register(str) +def _(eps): + r""" + >>> ep, = load('[console_scripts]\nfoo=bar') + >>> ep.group + 'console_scripts' + >>> ep.name + 'foo' + >>> ep.value + 'bar' + """ + return validate(metadata.EntryPoints(metadata.EntryPoints._from_text(eps))) + + +load.register(type(None), lambda x: x) + + +@pass_none +def render(eps: metadata.EntryPoints): + by_group = operator.attrgetter('group') + groups = itertools.groupby(sorted(eps, key=by_group), by_group) + + return '\n'.join( + f'[{group}]\n{render_items(items)}\n' + for group, items in groups + ) + + +def render_items(eps): + return '\n'.join( + f'{ep.name} = {ep.value}' + for ep in sorted(eps) + ) diff --git a/venv/Lib/site-packages/setuptools/_importlib.py b/venv/Lib/site-packages/setuptools/_importlib.py new file mode 100644 index 0000000..819bf5d --- /dev/null +++ b/venv/Lib/site-packages/setuptools/_importlib.py @@ -0,0 +1,47 @@ +import sys + + +def disable_importlib_metadata_finder(metadata): + """ + Ensure importlib_metadata doesn't provide older, incompatible + Distributions. + + Workaround for #3102. + """ + try: + import importlib_metadata + except ImportError: + return + except AttributeError: + import warnings + + msg = ( + "`importlib-metadata` version is incompatible with `setuptools`.\n" + "This problem is likely to be solved by installing an updated version of " + "`importlib-metadata`." + ) + warnings.warn(msg) # Ensure a descriptive message is shown. + raise # This exception can be suppressed by _distutils_hack + + if importlib_metadata is metadata: + return + to_remove = [ + ob + for ob in sys.meta_path + if isinstance(ob, importlib_metadata.MetadataPathFinder) + ] + for item in to_remove: + sys.meta_path.remove(item) + + +if sys.version_info < (3, 10): + from setuptools.extern import importlib_metadata as metadata + disable_importlib_metadata_finder(metadata) +else: + import importlib.metadata as metadata # noqa: F401 + + +if sys.version_info < (3, 9): + from setuptools.extern import importlib_resources as resources +else: + import importlib.resources as resources # noqa: F401 diff --git a/venv/Lib/site-packages/setuptools/_itertools.py b/venv/Lib/site-packages/setuptools/_itertools.py new file mode 100644 index 0000000..b8bf6d2 --- /dev/null +++ b/venv/Lib/site-packages/setuptools/_itertools.py @@ -0,0 +1,23 @@ +from setuptools.extern.more_itertools import consume # noqa: F401 + + +# copied from jaraco.itertools 6.1 +def ensure_unique(iterable, key=lambda x: x): + """ + Wrap an iterable to raise a ValueError if non-unique values are encountered. + + >>> list(ensure_unique('abc')) + ['a', 'b', 'c'] + >>> consume(ensure_unique('abca')) + Traceback (most recent call last): + ... + ValueError: Duplicate element 'a' encountered. + """ + seen = set() + seen_add = seen.add + for element in iterable: + k = key(element) + if k in seen: + raise ValueError(f"Duplicate element {element!r} encountered.") + seen_add(k) + yield element diff --git a/venv/Lib/site-packages/setuptools/_path.py b/venv/Lib/site-packages/setuptools/_path.py new file mode 100644 index 0000000..3767523 --- /dev/null +++ b/venv/Lib/site-packages/setuptools/_path.py @@ -0,0 +1,29 @@ +import os +from typing import Union + +_Path = Union[str, os.PathLike] + + +def ensure_directory(path): + """Ensure that the parent directory of `path` exists""" + dirname = os.path.dirname(path) + os.makedirs(dirname, exist_ok=True) + + +def same_path(p1: _Path, p2: _Path) -> bool: + """Differs from os.path.samefile because it does not require paths to exist. + Purely string based (no comparison between i-nodes). + >>> same_path("a/b", "./a/b") + True + >>> same_path("a/b", "a/./b") + True + >>> same_path("a/b", "././a/b") + True + >>> same_path("a/b", "./a/b/c/..") + True + >>> same_path("a/b", "../a/b/c") + False + >>> same_path("a", "a/b") + False + """ + return os.path.normpath(p1) == os.path.normpath(p2) diff --git a/venv/Lib/site-packages/setuptools/_reqs.py b/venv/Lib/site-packages/setuptools/_reqs.py new file mode 100644 index 0000000..ca72417 --- /dev/null +++ b/venv/Lib/site-packages/setuptools/_reqs.py @@ -0,0 +1,19 @@ +import setuptools.extern.jaraco.text as text + +from pkg_resources import Requirement + + +def parse_strings(strs): + """ + Yield requirement strings for each specification in `strs`. + + `strs` must be a string, or a (possibly-nested) iterable thereof. + """ + return text.join_continuation(map(text.drop_comment, text.yield_lines(strs))) + + +def parse(strs): + """ + Deprecated drop-in replacement for pkg_resources.parse_requirements. + """ + return map(Requirement, parse_strings(strs)) diff --git a/venv/Lib/site-packages/setuptools/_vendor/packaging/_manylinux.py b/venv/Lib/site-packages/setuptools/_vendor/packaging/_manylinux.py new file mode 100644 index 0000000..4c379aa --- /dev/null +++ b/venv/Lib/site-packages/setuptools/_vendor/packaging/_manylinux.py @@ -0,0 +1,301 @@ +import collections +import functools +import os +import re +import struct +import sys +import warnings +from typing import IO, Dict, Iterator, NamedTuple, Optional, Tuple + + +# Python does not provide platform information at sufficient granularity to +# identify the architecture of the running executable in some cases, so we +# determine it dynamically by reading the information from the running +# process. This only applies on Linux, which uses the ELF format. +class _ELFFileHeader: + # https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header + class _InvalidELFFileHeader(ValueError): + """ + An invalid ELF file header was found. + """ + + ELF_MAGIC_NUMBER = 0x7F454C46 + ELFCLASS32 = 1 + ELFCLASS64 = 2 + ELFDATA2LSB = 1 + ELFDATA2MSB = 2 + EM_386 = 3 + EM_S390 = 22 + EM_ARM = 40 + EM_X86_64 = 62 + EF_ARM_ABIMASK = 0xFF000000 + EF_ARM_ABI_VER5 = 0x05000000 + EF_ARM_ABI_FLOAT_HARD = 0x00000400 + + def __init__(self, file: IO[bytes]) -> None: + def unpack(fmt: str) -> int: + try: + data = file.read(struct.calcsize(fmt)) + result: Tuple[int, ...] = struct.unpack(fmt, data) + except struct.error: + raise _ELFFileHeader._InvalidELFFileHeader() + return result[0] + + self.e_ident_magic = unpack(">I") + if self.e_ident_magic != self.ELF_MAGIC_NUMBER: + raise _ELFFileHeader._InvalidELFFileHeader() + self.e_ident_class = unpack("B") + if self.e_ident_class not in {self.ELFCLASS32, self.ELFCLASS64}: + raise _ELFFileHeader._InvalidELFFileHeader() + self.e_ident_data = unpack("B") + if self.e_ident_data not in {self.ELFDATA2LSB, self.ELFDATA2MSB}: + raise _ELFFileHeader._InvalidELFFileHeader() + self.e_ident_version = unpack("B") + self.e_ident_osabi = unpack("B") + self.e_ident_abiversion = unpack("B") + self.e_ident_pad = file.read(7) + format_h = "H" + format_i = "I" + format_q = "Q" + format_p = format_i if self.e_ident_class == self.ELFCLASS32 else format_q + self.e_type = unpack(format_h) + self.e_machine = unpack(format_h) + self.e_version = unpack(format_i) + self.e_entry = unpack(format_p) + self.e_phoff = unpack(format_p) + self.e_shoff = unpack(format_p) + self.e_flags = unpack(format_i) + self.e_ehsize = unpack(format_h) + self.e_phentsize = unpack(format_h) + self.e_phnum = unpack(format_h) + self.e_shentsize = unpack(format_h) + self.e_shnum = unpack(format_h) + self.e_shstrndx = unpack(format_h) + + +def _get_elf_header() -> Optional[_ELFFileHeader]: + try: + with open(sys.executable, "rb") as f: + elf_header = _ELFFileHeader(f) + except (OSError, TypeError, _ELFFileHeader._InvalidELFFileHeader): + return None + return elf_header + + +def _is_linux_armhf() -> bool: + # hard-float ABI can be detected from the ELF header of the running + # process + # https://static.docs.arm.com/ihi0044/g/aaelf32.pdf + elf_header = _get_elf_header() + if elf_header is None: + return False + result = elf_header.e_ident_class == elf_header.ELFCLASS32 + result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB + result &= elf_header.e_machine == elf_header.EM_ARM + result &= ( + elf_header.e_flags & elf_header.EF_ARM_ABIMASK + ) == elf_header.EF_ARM_ABI_VER5 + result &= ( + elf_header.e_flags & elf_header.EF_ARM_ABI_FLOAT_HARD + ) == elf_header.EF_ARM_ABI_FLOAT_HARD + return result + + +def _is_linux_i686() -> bool: + elf_header = _get_elf_header() + if elf_header is None: + return False + result = elf_header.e_ident_class == elf_header.ELFCLASS32 + result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB + result &= elf_header.e_machine == elf_header.EM_386 + return result + + +def _have_compatible_abi(arch: str) -> bool: + if arch == "armv7l": + return _is_linux_armhf() + if arch == "i686": + return _is_linux_i686() + return arch in {"x86_64", "aarch64", "ppc64", "ppc64le", "s390x"} + + +# If glibc ever changes its major version, we need to know what the last +# minor version was, so we can build the complete list of all versions. +# For now, guess what the highest minor version might be, assume it will +# be 50 for testing. Once this actually happens, update the dictionary +# with the actual value. +_LAST_GLIBC_MINOR: Dict[int, int] = collections.defaultdict(lambda: 50) + + +class _GLibCVersion(NamedTuple): + major: int + minor: int + + +def _glibc_version_string_confstr() -> Optional[str]: + """ + Primary implementation of glibc_version_string using os.confstr. + """ + # os.confstr is quite a bit faster than ctypes.DLL. It's also less likely + # to be broken or missing. This strategy is used in the standard library + # platform module. + # https://github.com/python/cpython/blob/fcf1d003bf4f0100c/Lib/platform.py#L175-L183 + try: + # os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17". + version_string = os.confstr("CS_GNU_LIBC_VERSION") + assert version_string is not None + _, version = version_string.split() + except (AssertionError, AttributeError, OSError, ValueError): + # os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)... + return None + return version + + +def _glibc_version_string_ctypes() -> Optional[str]: + """ + Fallback implementation of glibc_version_string using ctypes. + """ + try: + import ctypes + except ImportError: + return None + + # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen + # manpage says, "If filename is NULL, then the returned handle is for the + # main program". This way we can let the linker do the work to figure out + # which libc our process is actually using. + # + # We must also handle the special case where the executable is not a + # dynamically linked executable. This can occur when using musl libc, + # for example. In this situation, dlopen() will error, leading to an + # OSError. Interestingly, at least in the case of musl, there is no + # errno set on the OSError. The single string argument used to construct + # OSError comes from libc itself and is therefore not portable to + # hard code here. In any case, failure to call dlopen() means we + # can proceed, so we bail on our attempt. + try: + process_namespace = ctypes.CDLL(None) + except OSError: + return None + + try: + gnu_get_libc_version = process_namespace.gnu_get_libc_version + except AttributeError: + # Symbol doesn't exist -> therefore, we are not linked to + # glibc. + return None + + # Call gnu_get_libc_version, which returns a string like "2.5" + gnu_get_libc_version.restype = ctypes.c_char_p + version_str: str = gnu_get_libc_version() + # py2 / py3 compatibility: + if not isinstance(version_str, str): + version_str = version_str.decode("ascii") + + return version_str + + +def _glibc_version_string() -> Optional[str]: + """Returns glibc version string, or None if not using glibc.""" + return _glibc_version_string_confstr() or _glibc_version_string_ctypes() + + +def _parse_glibc_version(version_str: str) -> Tuple[int, int]: + """Parse glibc version. + + We use a regexp instead of str.split because we want to discard any + random junk that might come after the minor version -- this might happen + in patched/forked versions of glibc (e.g. Linaro's version of glibc + uses version strings like "2.20-2014.11"). See gh-3588. + """ + m = re.match(r"(?P[0-9]+)\.(?P[0-9]+)", version_str) + if not m: + warnings.warn( + "Expected glibc version with 2 components major.minor," + " got: %s" % version_str, + RuntimeWarning, + ) + return -1, -1 + return int(m.group("major")), int(m.group("minor")) + + +@functools.lru_cache() +def _get_glibc_version() -> Tuple[int, int]: + version_str = _glibc_version_string() + if version_str is None: + return (-1, -1) + return _parse_glibc_version(version_str) + + +# From PEP 513, PEP 600 +def _is_compatible(name: str, arch: str, version: _GLibCVersion) -> bool: + sys_glibc = _get_glibc_version() + if sys_glibc < version: + return False + # Check for presence of _manylinux module. + try: + import _manylinux # noqa + except ImportError: + return True + if hasattr(_manylinux, "manylinux_compatible"): + result = _manylinux.manylinux_compatible(version[0], version[1], arch) + if result is not None: + return bool(result) + return True + if version == _GLibCVersion(2, 5): + if hasattr(_manylinux, "manylinux1_compatible"): + return bool(_manylinux.manylinux1_compatible) + if version == _GLibCVersion(2, 12): + if hasattr(_manylinux, "manylinux2010_compatible"): + return bool(_manylinux.manylinux2010_compatible) + if version == _GLibCVersion(2, 17): + if hasattr(_manylinux, "manylinux2014_compatible"): + return bool(_manylinux.manylinux2014_compatible) + return True + + +_LEGACY_MANYLINUX_MAP = { + # CentOS 7 w/ glibc 2.17 (PEP 599) + (2, 17): "manylinux2014", + # CentOS 6 w/ glibc 2.12 (PEP 571) + (2, 12): "manylinux2010", + # CentOS 5 w/ glibc 2.5 (PEP 513) + (2, 5): "manylinux1", +} + + +def platform_tags(linux: str, arch: str) -> Iterator[str]: + if not _have_compatible_abi(arch): + return + # Oldest glibc to be supported regardless of architecture is (2, 17). + too_old_glibc2 = _GLibCVersion(2, 16) + if arch in {"x86_64", "i686"}: + # On x86/i686 also oldest glibc to be supported is (2, 5). + too_old_glibc2 = _GLibCVersion(2, 4) + current_glibc = _GLibCVersion(*_get_glibc_version()) + glibc_max_list = [current_glibc] + # We can assume compatibility across glibc major versions. + # https://sourceware.org/bugzilla/show_bug.cgi?id=24636 + # + # Build a list of maximum glibc versions so that we can + # output the canonical list of all glibc from current_glibc + # down to too_old_glibc2, including all intermediary versions. + for glibc_major in range(current_glibc.major - 1, 1, -1): + glibc_minor = _LAST_GLIBC_MINOR[glibc_major] + glibc_max_list.append(_GLibCVersion(glibc_major, glibc_minor)) + for glibc_max in glibc_max_list: + if glibc_max.major == too_old_glibc2.major: + min_minor = too_old_glibc2.minor + else: + # For other glibc major versions oldest supported is (x, 0). + min_minor = -1 + for glibc_minor in range(glibc_max.minor, min_minor, -1): + glibc_version = _GLibCVersion(glibc_max.major, glibc_minor) + tag = "manylinux_{}_{}".format(*glibc_version) + if _is_compatible(tag, arch, glibc_version): + yield linux.replace("linux", tag) + # Handle the legacy manylinux1, manylinux2010, manylinux2014 tags. + if glibc_version in _LEGACY_MANYLINUX_MAP: + legacy_tag = _LEGACY_MANYLINUX_MAP[glibc_version] + if _is_compatible(legacy_tag, arch, glibc_version): + yield linux.replace("linux", legacy_tag) diff --git a/venv/Lib/site-packages/setuptools/_vendor/packaging/_musllinux.py b/venv/Lib/site-packages/setuptools/_vendor/packaging/_musllinux.py new file mode 100644 index 0000000..8ac3059 --- /dev/null +++ b/venv/Lib/site-packages/setuptools/_vendor/packaging/_musllinux.py @@ -0,0 +1,136 @@ +"""PEP 656 support. + +This module implements logic to detect if the currently running Python is +linked against musl, and what musl version is used. +""" + +import contextlib +import functools +import operator +import os +import re +import struct +import subprocess +import sys +from typing import IO, Iterator, NamedTuple, Optional, Tuple + + +def _read_unpacked(f: IO[bytes], fmt: str) -> Tuple[int, ...]: + return struct.unpack(fmt, f.read(struct.calcsize(fmt))) + + +def _parse_ld_musl_from_elf(f: IO[bytes]) -> Optional[str]: + """Detect musl libc location by parsing the Python executable. + + Based on: https://gist.github.com/lyssdod/f51579ae8d93c8657a5564aefc2ffbca + ELF header: https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html + """ + f.seek(0) + try: + ident = _read_unpacked(f, "16B") + except struct.error: + return None + if ident[:4] != tuple(b"\x7fELF"): # Invalid magic, not ELF. + return None + f.seek(struct.calcsize("HHI"), 1) # Skip file type, machine, and version. + + try: + # e_fmt: Format for program header. + # p_fmt: Format for section header. + # p_idx: Indexes to find p_type, p_offset, and p_filesz. + e_fmt, p_fmt, p_idx = { + 1: ("IIIIHHH", "IIIIIIII", (0, 1, 4)), # 32-bit. + 2: ("QQQIHHH", "IIQQQQQQ", (0, 2, 5)), # 64-bit. + }[ident[4]] + except KeyError: + return None + else: + p_get = operator.itemgetter(*p_idx) + + # Find the interpreter section and return its content. + try: + _, e_phoff, _, _, _, e_phentsize, e_phnum = _read_unpacked(f, e_fmt) + except struct.error: + return None + for i in range(e_phnum + 1): + f.seek(e_phoff + e_phentsize * i) + try: + p_type, p_offset, p_filesz = p_get(_read_unpacked(f, p_fmt)) + except struct.error: + return None + if p_type != 3: # Not PT_INTERP. + continue + f.seek(p_offset) + interpreter = os.fsdecode(f.read(p_filesz)).strip("\0") + if "musl" not in interpreter: + return None + return interpreter + return None + + +class _MuslVersion(NamedTuple): + major: int + minor: int + + +def _parse_musl_version(output: str) -> Optional[_MuslVersion]: + lines = [n for n in (n.strip() for n in output.splitlines()) if n] + if len(lines) < 2 or lines[0][:4] != "musl": + return None + m = re.match(r"Version (\d+)\.(\d+)", lines[1]) + if not m: + return None + return _MuslVersion(major=int(m.group(1)), minor=int(m.group(2))) + + +@functools.lru_cache() +def _get_musl_version(executable: str) -> Optional[_MuslVersion]: + """Detect currently-running musl runtime version. + + This is done by checking the specified executable's dynamic linking + information, and invoking the loader to parse its output for a version + string. If the loader is musl, the output would be something like:: + + musl libc (x86_64) + Version 1.2.2 + Dynamic Program Loader + """ + with contextlib.ExitStack() as stack: + try: + f = stack.enter_context(open(executable, "rb")) + except OSError: + return None + ld = _parse_ld_musl_from_elf(f) + if not ld: + return None + proc = subprocess.run([ld], stderr=subprocess.PIPE, universal_newlines=True) + return _parse_musl_version(proc.stderr) + + +def platform_tags(arch: str) -> Iterator[str]: + """Generate musllinux tags compatible to the current platform. + + :param arch: Should be the part of platform tag after the ``linux_`` + prefix, e.g. ``x86_64``. The ``linux_`` prefix is assumed as a + prerequisite for the current platform to be musllinux-compatible. + + :returns: An iterator of compatible musllinux tags. + """ + sys_musl = _get_musl_version(sys.executable) + if sys_musl is None: # Python not dynamically linked against musl. + return + for minor in range(sys_musl.minor, -1, -1): + yield f"musllinux_{sys_musl.major}_{minor}_{arch}" + + +if __name__ == "__main__": # pragma: no cover + import sysconfig + + plat = sysconfig.get_platform() + assert plat.startswith("linux-"), "not linux" + + print("plat:", plat) + print("musl:", _get_musl_version(sys.executable)) + print("tags:", end=" ") + for t in platform_tags(re.sub(r"[.-]", "_", plat.split("-", 1)[-1])): + print(t, end="\n ") diff --git a/venv/Lib/site-packages/setuptools/_vendor/typing_extensions.py b/venv/Lib/site-packages/setuptools/_vendor/typing_extensions.py new file mode 100644 index 0000000..9f1c7aa --- /dev/null +++ b/venv/Lib/site-packages/setuptools/_vendor/typing_extensions.py @@ -0,0 +1,2296 @@ +import abc +import collections +import collections.abc +import operator +import sys +import typing + +# After PEP 560, internal typing API was substantially reworked. +# This is especially important for Protocol class which uses internal APIs +# quite extensively. +PEP_560 = sys.version_info[:3] >= (3, 7, 0) + +if PEP_560: + GenericMeta = type +else: + # 3.6 + from typing import GenericMeta, _type_vars # noqa + +# The two functions below are copies of typing internal helpers. +# They are needed by _ProtocolMeta + + +def _no_slots_copy(dct): + dict_copy = dict(dct) + if '__slots__' in dict_copy: + for slot in dict_copy['__slots__']: + dict_copy.pop(slot, None) + return dict_copy + + +def _check_generic(cls, parameters): + if not cls.__parameters__: + raise TypeError(f"{cls} is not a generic class") + alen = len(parameters) + elen = len(cls.__parameters__) + if alen != elen: + raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments for {cls};" + f" actual {alen}, expected {elen}") + + +# Please keep __all__ alphabetized within each category. +__all__ = [ + # Super-special typing primitives. + 'ClassVar', + 'Concatenate', + 'Final', + 'ParamSpec', + 'Self', + 'Type', + + # ABCs (from collections.abc). + 'Awaitable', + 'AsyncIterator', + 'AsyncIterable', + 'Coroutine', + 'AsyncGenerator', + 'AsyncContextManager', + 'ChainMap', + + # Concrete collection types. + 'ContextManager', + 'Counter', + 'Deque', + 'DefaultDict', + 'OrderedDict', + 'TypedDict', + + # Structural checks, a.k.a. protocols. + 'SupportsIndex', + + # One-off things. + 'Annotated', + 'final', + 'IntVar', + 'Literal', + 'NewType', + 'overload', + 'Protocol', + 'runtime', + 'runtime_checkable', + 'Text', + 'TypeAlias', + 'TypeGuard', + 'TYPE_CHECKING', +] + +if PEP_560: + __all__.extend(["get_args", "get_origin", "get_type_hints"]) + +# 3.6.2+ +if hasattr(typing, 'NoReturn'): + NoReturn = typing.NoReturn +# 3.6.0-3.6.1 +else: + class _NoReturn(typing._FinalTypingBase, _root=True): + """Special type indicating functions that never return. + Example:: + + from typing import NoReturn + + def stop() -> NoReturn: + raise Exception('no way') + + This type is invalid in other positions, e.g., ``List[NoReturn]`` + will fail in static type checkers. + """ + __slots__ = () + + def __instancecheck__(self, obj): + raise TypeError("NoReturn cannot be used with isinstance().") + + def __subclasscheck__(self, cls): + raise TypeError("NoReturn cannot be used with issubclass().") + + NoReturn = _NoReturn(_root=True) + +# Some unconstrained type variables. These are used by the container types. +# (These are not for export.) +T = typing.TypeVar('T') # Any type. +KT = typing.TypeVar('KT') # Key type. +VT = typing.TypeVar('VT') # Value type. +T_co = typing.TypeVar('T_co', covariant=True) # Any type covariant containers. +T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant. + +ClassVar = typing.ClassVar + +# On older versions of typing there is an internal class named "Final". +# 3.8+ +if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7): + Final = typing.Final +# 3.7 +elif sys.version_info[:2] >= (3, 7): + class _FinalForm(typing._SpecialForm, _root=True): + + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only single type') + return typing._GenericAlias(self, (item,)) + + Final = _FinalForm('Final', + doc="""A special typing construct to indicate that a name + cannot be re-assigned or overridden in a subclass. + For example: + + MAX_SIZE: Final = 9000 + MAX_SIZE += 1 # Error reported by type checker + + class Connection: + TIMEOUT: Final[int] = 10 + class FastConnector(Connection): + TIMEOUT = 1 # Error reported by type checker + + There is no runtime checking of these properties.""") +# 3.6 +else: + class _Final(typing._FinalTypingBase, _root=True): + """A special typing construct to indicate that a name + cannot be re-assigned or overridden in a subclass. + For example: + + MAX_SIZE: Final = 9000 + MAX_SIZE += 1 # Error reported by type checker + + class Connection: + TIMEOUT: Final[int] = 10 + class FastConnector(Connection): + TIMEOUT = 1 # Error reported by type checker + + There is no runtime checking of these properties. + """ + + __slots__ = ('__type__',) + + def __init__(self, tp=None, **kwds): + self.__type__ = tp + + def __getitem__(self, item): + cls = type(self) + if self.__type__ is None: + return cls(typing._type_check(item, + f'{cls.__name__[1:]} accepts only single type.'), + _root=True) + raise TypeError(f'{cls.__name__[1:]} cannot be further subscripted') + + def _eval_type(self, globalns, localns): + new_tp = typing._eval_type(self.__type__, globalns, localns) + if new_tp == self.__type__: + return self + return type(self)(new_tp, _root=True) + + def __repr__(self): + r = super().__repr__() + if self.__type__ is not None: + r += f'[{typing._type_repr(self.__type__)}]' + return r + + def __hash__(self): + return hash((type(self).__name__, self.__type__)) + + def __eq__(self, other): + if not isinstance(other, _Final): + return NotImplemented + if self.__type__ is not None: + return self.__type__ == other.__type__ + return self is other + + Final = _Final(_root=True) + + +# 3.8+ +if hasattr(typing, 'final'): + final = typing.final +# 3.6-3.7 +else: + def final(f): + """This decorator can be used to indicate to type checkers that + the decorated method cannot be overridden, and decorated class + cannot be subclassed. For example: + + class Base: + @final + def done(self) -> None: + ... + class Sub(Base): + def done(self) -> None: # Error reported by type checker + ... + @final + class Leaf: + ... + class Other(Leaf): # Error reported by type checker + ... + + There is no runtime checking of these properties. + """ + return f + + +def IntVar(name): + return typing.TypeVar(name) + + +# 3.8+: +if hasattr(typing, 'Literal'): + Literal = typing.Literal +# 3.7: +elif sys.version_info[:2] >= (3, 7): + class _LiteralForm(typing._SpecialForm, _root=True): + + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + return typing._GenericAlias(self, parameters) + + Literal = _LiteralForm('Literal', + doc="""A type that can be used to indicate to type checkers + that the corresponding value has a value literally equivalent + to the provided parameter. For example: + + var: Literal[4] = 4 + + The type checker understands that 'var' is literally equal to + the value 4 and no other value. + + Literal[...] cannot be subclassed. There is no runtime + checking verifying that the parameter is actually a value + instead of a type.""") +# 3.6: +else: + class _Literal(typing._FinalTypingBase, _root=True): + """A type that can be used to indicate to type checkers that the + corresponding value has a value literally equivalent to the + provided parameter. For example: + + var: Literal[4] = 4 + + The type checker understands that 'var' is literally equal to the + value 4 and no other value. + + Literal[...] cannot be subclassed. There is no runtime checking + verifying that the parameter is actually a value instead of a type. + """ + + __slots__ = ('__values__',) + + def __init__(self, values=None, **kwds): + self.__values__ = values + + def __getitem__(self, values): + cls = type(self) + if self.__values__ is None: + if not isinstance(values, tuple): + values = (values,) + return cls(values, _root=True) + raise TypeError(f'{cls.__name__[1:]} cannot be further subscripted') + + def _eval_type(self, globalns, localns): + return self + + def __repr__(self): + r = super().__repr__() + if self.__values__ is not None: + r += f'[{", ".join(map(typing._type_repr, self.__values__))}]' + return r + + def __hash__(self): + return hash((type(self).__name__, self.__values__)) + + def __eq__(self, other): + if not isinstance(other, _Literal): + return NotImplemented + if self.__values__ is not None: + return self.__values__ == other.__values__ + return self is other + + Literal = _Literal(_root=True) + + +_overload_dummy = typing._overload_dummy # noqa +overload = typing.overload + + +# This is not a real generic class. Don't use outside annotations. +Type = typing.Type + +# Various ABCs mimicking those in collections.abc. +# A few are simply re-exported for completeness. + + +class _ExtensionsGenericMeta(GenericMeta): + def __subclasscheck__(self, subclass): + """This mimics a more modern GenericMeta.__subclasscheck__() logic + (that does not have problems with recursion) to work around interactions + between collections, typing, and typing_extensions on older + versions of Python, see https://github.com/python/typing/issues/501. + """ + if self.__origin__ is not None: + if sys._getframe(1).f_globals['__name__'] not in ['abc', 'functools']: + raise TypeError("Parameterized generics cannot be used with class " + "or instance checks") + return False + if not self.__extra__: + return super().__subclasscheck__(subclass) + res = self.__extra__.__subclasshook__(subclass) + if res is not NotImplemented: + return res + if self.__extra__ in subclass.__mro__: + return True + for scls in self.__extra__.__subclasses__(): + if isinstance(scls, GenericMeta): + continue + if issubclass(subclass, scls): + return True + return False + + +Awaitable = typing.Awaitable +Coroutine = typing.Coroutine +AsyncIterable = typing.AsyncIterable +AsyncIterator = typing.AsyncIterator + +# 3.6.1+ +if hasattr(typing, 'Deque'): + Deque = typing.Deque +# 3.6.0 +else: + class Deque(collections.deque, typing.MutableSequence[T], + metaclass=_ExtensionsGenericMeta, + extra=collections.deque): + __slots__ = () + + def __new__(cls, *args, **kwds): + if cls._gorg is Deque: + return collections.deque(*args, **kwds) + return typing._generic_new(collections.deque, cls, *args, **kwds) + +ContextManager = typing.ContextManager +# 3.6.2+ +if hasattr(typing, 'AsyncContextManager'): + AsyncContextManager = typing.AsyncContextManager +# 3.6.0-3.6.1 +else: + from _collections_abc import _check_methods as _check_methods_in_mro # noqa + + class AsyncContextManager(typing.Generic[T_co]): + __slots__ = () + + async def __aenter__(self): + return self + + @abc.abstractmethod + async def __aexit__(self, exc_type, exc_value, traceback): + return None + + @classmethod + def __subclasshook__(cls, C): + if cls is AsyncContextManager: + return _check_methods_in_mro(C, "__aenter__", "__aexit__") + return NotImplemented + +DefaultDict = typing.DefaultDict + +# 3.7.2+ +if hasattr(typing, 'OrderedDict'): + OrderedDict = typing.OrderedDict +# 3.7.0-3.7.2 +elif (3, 7, 0) <= sys.version_info[:3] < (3, 7, 2): + OrderedDict = typing._alias(collections.OrderedDict, (KT, VT)) +# 3.6 +else: + class OrderedDict(collections.OrderedDict, typing.MutableMapping[KT, VT], + metaclass=_ExtensionsGenericMeta, + extra=collections.OrderedDict): + + __slots__ = () + + def __new__(cls, *args, **kwds): + if cls._gorg is OrderedDict: + return collections.OrderedDict(*args, **kwds) + return typing._generic_new(collections.OrderedDict, cls, *args, **kwds) + +# 3.6.2+ +if hasattr(typing, 'Counter'): + Counter = typing.Counter +# 3.6.0-3.6.1 +else: + class Counter(collections.Counter, + typing.Dict[T, int], + metaclass=_ExtensionsGenericMeta, extra=collections.Counter): + + __slots__ = () + + def __new__(cls, *args, **kwds): + if cls._gorg is Counter: + return collections.Counter(*args, **kwds) + return typing._generic_new(collections.Counter, cls, *args, **kwds) + +# 3.6.1+ +if hasattr(typing, 'ChainMap'): + ChainMap = typing.ChainMap +elif hasattr(collections, 'ChainMap'): + class ChainMap(collections.ChainMap, typing.MutableMapping[KT, VT], + metaclass=_ExtensionsGenericMeta, + extra=collections.ChainMap): + + __slots__ = () + + def __new__(cls, *args, **kwds): + if cls._gorg is ChainMap: + return collections.ChainMap(*args, **kwds) + return typing._generic_new(collections.ChainMap, cls, *args, **kwds) + +# 3.6.1+ +if hasattr(typing, 'AsyncGenerator'): + AsyncGenerator = typing.AsyncGenerator +# 3.6.0 +else: + class AsyncGenerator(AsyncIterator[T_co], typing.Generic[T_co, T_contra], + metaclass=_ExtensionsGenericMeta, + extra=collections.abc.AsyncGenerator): + __slots__ = () + +NewType = typing.NewType +Text = typing.Text +TYPE_CHECKING = typing.TYPE_CHECKING + + +def _gorg(cls): + """This function exists for compatibility with old typing versions.""" + assert isinstance(cls, GenericMeta) + if hasattr(cls, '_gorg'): + return cls._gorg + while cls.__origin__ is not None: + cls = cls.__origin__ + return cls + + +_PROTO_WHITELIST = ['Callable', 'Awaitable', + 'Iterable', 'Iterator', 'AsyncIterable', 'AsyncIterator', + 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', + 'ContextManager', 'AsyncContextManager'] + + +def _get_protocol_attrs(cls): + attrs = set() + for base in cls.__mro__[:-1]: # without object + if base.__name__ in ('Protocol', 'Generic'): + continue + annotations = getattr(base, '__annotations__', {}) + for attr in list(base.__dict__.keys()) + list(annotations.keys()): + if (not attr.startswith('_abc_') and attr not in ( + '__abstractmethods__', '__annotations__', '__weakref__', + '_is_protocol', '_is_runtime_protocol', '__dict__', + '__args__', '__slots__', + '__next_in_mro__', '__parameters__', '__origin__', + '__orig_bases__', '__extra__', '__tree_hash__', + '__doc__', '__subclasshook__', '__init__', '__new__', + '__module__', '_MutableMapping__marker', '_gorg')): + attrs.add(attr) + return attrs + + +def _is_callable_members_only(cls): + return all(callable(getattr(cls, attr, None)) for attr in _get_protocol_attrs(cls)) + + +# 3.8+ +if hasattr(typing, 'Protocol'): + Protocol = typing.Protocol +# 3.7 +elif PEP_560: + from typing import _collect_type_vars # noqa + + def _no_init(self, *args, **kwargs): + if type(self)._is_protocol: + raise TypeError('Protocols cannot be instantiated') + + class _ProtocolMeta(abc.ABCMeta): + # This metaclass is a bit unfortunate and exists only because of the lack + # of __instancehook__. + def __instancecheck__(cls, instance): + # We need this method for situations where attributes are + # assigned in __init__. + if ((not getattr(cls, '_is_protocol', False) or + _is_callable_members_only(cls)) and + issubclass(instance.__class__, cls)): + return True + if cls._is_protocol: + if all(hasattr(instance, attr) and + (not callable(getattr(cls, attr, None)) or + getattr(instance, attr) is not None) + for attr in _get_protocol_attrs(cls)): + return True + return super().__instancecheck__(instance) + + class Protocol(metaclass=_ProtocolMeta): + # There is quite a lot of overlapping code with typing.Generic. + # Unfortunately it is hard to avoid this while these live in two different + # modules. The duplicated code will be removed when Protocol is moved to typing. + """Base class for protocol classes. Protocol classes are defined as:: + + class Proto(Protocol): + def meth(self) -> int: + ... + + Such classes are primarily used with static type checkers that recognize + structural subtyping (static duck-typing), for example:: + + class C: + def meth(self) -> int: + return 0 + + def func(x: Proto) -> int: + return x.meth() + + func(C()) # Passes static type check + + See PEP 544 for details. Protocol classes decorated with + @typing_extensions.runtime act as simple-minded runtime protocol that checks + only the presence of given attributes, ignoring their type signatures. + + Protocol classes can be generic, they are defined as:: + + class GenProto(Protocol[T]): + def meth(self) -> T: + ... + """ + __slots__ = () + _is_protocol = True + + def __new__(cls, *args, **kwds): + if cls is Protocol: + raise TypeError("Type Protocol cannot be instantiated; " + "it can only be used as a base class") + return super().__new__(cls) + + @typing._tp_cache + def __class_getitem__(cls, params): + if not isinstance(params, tuple): + params = (params,) + if not params and cls is not typing.Tuple: + raise TypeError( + f"Parameter list to {cls.__qualname__}[...] cannot be empty") + msg = "Parameters to generic types must be types." + params = tuple(typing._type_check(p, msg) for p in params) # noqa + if cls is Protocol: + # Generic can only be subscripted with unique type variables. + if not all(isinstance(p, typing.TypeVar) for p in params): + i = 0 + while isinstance(params[i], typing.TypeVar): + i += 1 + raise TypeError( + "Parameters to Protocol[...] must all be type variables." + f" Parameter {i + 1} is {params[i]}") + if len(set(params)) != len(params): + raise TypeError( + "Parameters to Protocol[...] must all be unique") + else: + # Subscripting a regular Generic subclass. + _check_generic(cls, params) + return typing._GenericAlias(cls, params) + + def __init_subclass__(cls, *args, **kwargs): + tvars = [] + if '__orig_bases__' in cls.__dict__: + error = typing.Generic in cls.__orig_bases__ + else: + error = typing.Generic in cls.__bases__ + if error: + raise TypeError("Cannot inherit from plain Generic") + if '__orig_bases__' in cls.__dict__: + tvars = _collect_type_vars(cls.__orig_bases__) + # Look for Generic[T1, ..., Tn] or Protocol[T1, ..., Tn]. + # If found, tvars must be a subset of it. + # If not found, tvars is it. + # Also check for and reject plain Generic, + # and reject multiple Generic[...] and/or Protocol[...]. + gvars = None + for base in cls.__orig_bases__: + if (isinstance(base, typing._GenericAlias) and + base.__origin__ in (typing.Generic, Protocol)): + # for error messages + the_base = base.__origin__.__name__ + if gvars is not None: + raise TypeError( + "Cannot inherit from Generic[...]" + " and/or Protocol[...] multiple types.") + gvars = base.__parameters__ + if gvars is None: + gvars = tvars + else: + tvarset = set(tvars) + gvarset = set(gvars) + if not tvarset <= gvarset: + s_vars = ', '.join(str(t) for t in tvars if t not in gvarset) + s_args = ', '.join(str(g) for g in gvars) + raise TypeError(f"Some type variables ({s_vars}) are" + f" not listed in {the_base}[{s_args}]") + tvars = gvars + cls.__parameters__ = tuple(tvars) + + # Determine if this is a protocol or a concrete subclass. + if not cls.__dict__.get('_is_protocol', None): + cls._is_protocol = any(b is Protocol for b in cls.__bases__) + + # Set (or override) the protocol subclass hook. + def _proto_hook(other): + if not cls.__dict__.get('_is_protocol', None): + return NotImplemented + if not getattr(cls, '_is_runtime_protocol', False): + if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']: + return NotImplemented + raise TypeError("Instance and class checks can only be used with" + " @runtime protocols") + if not _is_callable_members_only(cls): + if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']: + return NotImplemented + raise TypeError("Protocols with non-method members" + " don't support issubclass()") + if not isinstance(other, type): + # Same error as for issubclass(1, int) + raise TypeError('issubclass() arg 1 must be a class') + for attr in _get_protocol_attrs(cls): + for base in other.__mro__: + if attr in base.__dict__: + if base.__dict__[attr] is None: + return NotImplemented + break + annotations = getattr(base, '__annotations__', {}) + if (isinstance(annotations, typing.Mapping) and + attr in annotations and + isinstance(other, _ProtocolMeta) and + other._is_protocol): + break + else: + return NotImplemented + return True + if '__subclasshook__' not in cls.__dict__: + cls.__subclasshook__ = _proto_hook + + # We have nothing more to do for non-protocols. + if not cls._is_protocol: + return + + # Check consistency of bases. + for base in cls.__bases__: + if not (base in (object, typing.Generic) or + base.__module__ == 'collections.abc' and + base.__name__ in _PROTO_WHITELIST or + isinstance(base, _ProtocolMeta) and base._is_protocol): + raise TypeError('Protocols can only inherit from other' + f' protocols, got {repr(base)}') + cls.__init__ = _no_init +# 3.6 +else: + from typing import _next_in_mro, _type_check # noqa + + def _no_init(self, *args, **kwargs): + if type(self)._is_protocol: + raise TypeError('Protocols cannot be instantiated') + + class _ProtocolMeta(GenericMeta): + """Internal metaclass for Protocol. + + This exists so Protocol classes can be generic without deriving + from Generic. + """ + def __new__(cls, name, bases, namespace, + tvars=None, args=None, origin=None, extra=None, orig_bases=None): + # This is just a version copied from GenericMeta.__new__ that + # includes "Protocol" special treatment. (Comments removed for brevity.) + assert extra is None # Protocols should not have extra + if tvars is not None: + assert origin is not None + assert all(isinstance(t, typing.TypeVar) for t in tvars), tvars + else: + tvars = _type_vars(bases) + gvars = None + for base in bases: + if base is typing.Generic: + raise TypeError("Cannot inherit from plain Generic") + if (isinstance(base, GenericMeta) and + base.__origin__ in (typing.Generic, Protocol)): + if gvars is not None: + raise TypeError( + "Cannot inherit from Generic[...] or" + " Protocol[...] multiple times.") + gvars = base.__parameters__ + if gvars is None: + gvars = tvars + else: + tvarset = set(tvars) + gvarset = set(gvars) + if not tvarset <= gvarset: + s_vars = ", ".join(str(t) for t in tvars if t not in gvarset) + s_args = ", ".join(str(g) for g in gvars) + cls_name = "Generic" if any(b.__origin__ is typing.Generic + for b in bases) else "Protocol" + raise TypeError(f"Some type variables ({s_vars}) are" + f" not listed in {cls_name}[{s_args}]") + tvars = gvars + + initial_bases = bases + if (extra is not None and type(extra) is abc.ABCMeta and + extra not in bases): + bases = (extra,) + bases + bases = tuple(_gorg(b) if isinstance(b, GenericMeta) else b + for b in bases) + if any(isinstance(b, GenericMeta) and b is not typing.Generic for b in bases): + bases = tuple(b for b in bases if b is not typing.Generic) + namespace.update({'__origin__': origin, '__extra__': extra}) + self = super(GenericMeta, cls).__new__(cls, name, bases, namespace, + _root=True) + super(GenericMeta, self).__setattr__('_gorg', + self if not origin else + _gorg(origin)) + self.__parameters__ = tvars + self.__args__ = tuple(... if a is typing._TypingEllipsis else + () if a is typing._TypingEmpty else + a for a in args) if args else None + self.__next_in_mro__ = _next_in_mro(self) + if orig_bases is None: + self.__orig_bases__ = initial_bases + elif origin is not None: + self._abc_registry = origin._abc_registry + self._abc_cache = origin._abc_cache + if hasattr(self, '_subs_tree'): + self.__tree_hash__ = (hash(self._subs_tree()) if origin else + super(GenericMeta, self).__hash__()) + return self + + def __init__(cls, *args, **kwargs): + super().__init__(*args, **kwargs) + if not cls.__dict__.get('_is_protocol', None): + cls._is_protocol = any(b is Protocol or + isinstance(b, _ProtocolMeta) and + b.__origin__ is Protocol + for b in cls.__bases__) + if cls._is_protocol: + for base in cls.__mro__[1:]: + if not (base in (object, typing.Generic) or + base.__module__ == 'collections.abc' and + base.__name__ in _PROTO_WHITELIST or + isinstance(base, typing.TypingMeta) and base._is_protocol or + isinstance(base, GenericMeta) and + base.__origin__ is typing.Generic): + raise TypeError(f'Protocols can only inherit from other' + f' protocols, got {repr(base)}') + + cls.__init__ = _no_init + + def _proto_hook(other): + if not cls.__dict__.get('_is_protocol', None): + return NotImplemented + if not isinstance(other, type): + # Same error as for issubclass(1, int) + raise TypeError('issubclass() arg 1 must be a class') + for attr in _get_protocol_attrs(cls): + for base in other.__mro__: + if attr in base.__dict__: + if base.__dict__[attr] is None: + return NotImplemented + break + annotations = getattr(base, '__annotations__', {}) + if (isinstance(annotations, typing.Mapping) and + attr in annotations and + isinstance(other, _ProtocolMeta) and + other._is_protocol): + break + else: + return NotImplemented + return True + if '__subclasshook__' not in cls.__dict__: + cls.__subclasshook__ = _proto_hook + + def __instancecheck__(self, instance): + # We need this method for situations where attributes are + # assigned in __init__. + if ((not getattr(self, '_is_protocol', False) or + _is_callable_members_only(self)) and + issubclass(instance.__class__, self)): + return True + if self._is_protocol: + if all(hasattr(instance, attr) and + (not callable(getattr(self, attr, None)) or + getattr(instance, attr) is not None) + for attr in _get_protocol_attrs(self)): + return True + return super(GenericMeta, self).__instancecheck__(instance) + + def __subclasscheck__(self, cls): + if self.__origin__ is not None: + if sys._getframe(1).f_globals['__name__'] not in ['abc', 'functools']: + raise TypeError("Parameterized generics cannot be used with class " + "or instance checks") + return False + if (self.__dict__.get('_is_protocol', None) and + not self.__dict__.get('_is_runtime_protocol', None)): + if sys._getframe(1).f_globals['__name__'] in ['abc', + 'functools', + 'typing']: + return False + raise TypeError("Instance and class checks can only be used with" + " @runtime protocols") + if (self.__dict__.get('_is_runtime_protocol', None) and + not _is_callable_members_only(self)): + if sys._getframe(1).f_globals['__name__'] in ['abc', + 'functools', + 'typing']: + return super(GenericMeta, self).__subclasscheck__(cls) + raise TypeError("Protocols with non-method members" + " don't support issubclass()") + return super(GenericMeta, self).__subclasscheck__(cls) + + @typing._tp_cache + def __getitem__(self, params): + # We also need to copy this from GenericMeta.__getitem__ to get + # special treatment of "Protocol". (Comments removed for brevity.) + if not isinstance(params, tuple): + params = (params,) + if not params and _gorg(self) is not typing.Tuple: + raise TypeError( + f"Parameter list to {self.__qualname__}[...] cannot be empty") + msg = "Parameters to generic types must be types." + params = tuple(_type_check(p, msg) for p in params) + if self in (typing.Generic, Protocol): + if not all(isinstance(p, typing.TypeVar) for p in params): + raise TypeError( + f"Parameters to {repr(self)}[...] must all be type variables") + if len(set(params)) != len(params): + raise TypeError( + f"Parameters to {repr(self)}[...] must all be unique") + tvars = params + args = params + elif self in (typing.Tuple, typing.Callable): + tvars = _type_vars(params) + args = params + elif self.__origin__ in (typing.Generic, Protocol): + raise TypeError(f"Cannot subscript already-subscripted {repr(self)}") + else: + _check_generic(self, params) + tvars = _type_vars(params) + args = params + + prepend = (self,) if self.__origin__ is None else () + return self.__class__(self.__name__, + prepend + self.__bases__, + _no_slots_copy(self.__dict__), + tvars=tvars, + args=args, + origin=self, + extra=self.__extra__, + orig_bases=self.__orig_bases__) + + class Protocol(metaclass=_ProtocolMeta): + """Base class for protocol classes. Protocol classes are defined as:: + + class Proto(Protocol): + def meth(self) -> int: + ... + + Such classes are primarily used with static type checkers that recognize + structural subtyping (static duck-typing), for example:: + + class C: + def meth(self) -> int: + return 0 + + def func(x: Proto) -> int: + return x.meth() + + func(C()) # Passes static type check + + See PEP 544 for details. Protocol classes decorated with + @typing_extensions.runtime act as simple-minded runtime protocol that checks + only the presence of given attributes, ignoring their type signatures. + + Protocol classes can be generic, they are defined as:: + + class GenProto(Protocol[T]): + def meth(self) -> T: + ... + """ + __slots__ = () + _is_protocol = True + + def __new__(cls, *args, **kwds): + if _gorg(cls) is Protocol: + raise TypeError("Type Protocol cannot be instantiated; " + "it can be used only as a base class") + return typing._generic_new(cls.__next_in_mro__, cls, *args, **kwds) + + +# 3.8+ +if hasattr(typing, 'runtime_checkable'): + runtime_checkable = typing.runtime_checkable +# 3.6-3.7 +else: + def runtime_checkable(cls): + """Mark a protocol class as a runtime protocol, so that it + can be used with isinstance() and issubclass(). Raise TypeError + if applied to a non-protocol class. + + This allows a simple-minded structural check very similar to the + one-offs in collections.abc such as Hashable. + """ + if not isinstance(cls, _ProtocolMeta) or not cls._is_protocol: + raise TypeError('@runtime_checkable can be only applied to protocol classes,' + f' got {cls!r}') + cls._is_runtime_protocol = True + return cls + + +# Exists for backwards compatibility. +runtime = runtime_checkable + + +# 3.8+ +if hasattr(typing, 'SupportsIndex'): + SupportsIndex = typing.SupportsIndex +# 3.6-3.7 +else: + @runtime_checkable + class SupportsIndex(Protocol): + __slots__ = () + + @abc.abstractmethod + def __index__(self) -> int: + pass + + +if sys.version_info >= (3, 9, 2): + # The standard library TypedDict in Python 3.8 does not store runtime information + # about which (if any) keys are optional. See https://bugs.python.org/issue38834 + # The standard library TypedDict in Python 3.9.0/1 does not honour the "total" + # keyword with old-style TypedDict(). See https://bugs.python.org/issue42059 + TypedDict = typing.TypedDict +else: + def _check_fails(cls, other): + try: + if sys._getframe(1).f_globals['__name__'] not in ['abc', + 'functools', + 'typing']: + # Typed dicts are only for static structural subtyping. + raise TypeError('TypedDict does not support instance and class checks') + except (AttributeError, ValueError): + pass + return False + + def _dict_new(*args, **kwargs): + if not args: + raise TypeError('TypedDict.__new__(): not enough arguments') + _, args = args[0], args[1:] # allow the "cls" keyword be passed + return dict(*args, **kwargs) + + _dict_new.__text_signature__ = '($cls, _typename, _fields=None, /, **kwargs)' + + def _typeddict_new(*args, total=True, **kwargs): + if not args: + raise TypeError('TypedDict.__new__(): not enough arguments') + _, args = args[0], args[1:] # allow the "cls" keyword be passed + if args: + typename, args = args[0], args[1:] # allow the "_typename" keyword be passed + elif '_typename' in kwargs: + typename = kwargs.pop('_typename') + import warnings + warnings.warn("Passing '_typename' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + raise TypeError("TypedDict.__new__() missing 1 required positional " + "argument: '_typename'") + if args: + try: + fields, = args # allow the "_fields" keyword be passed + except ValueError: + raise TypeError('TypedDict.__new__() takes from 2 to 3 ' + f'positional arguments but {len(args) + 2} ' + 'were given') + elif '_fields' in kwargs and len(kwargs) == 1: + fields = kwargs.pop('_fields') + import warnings + warnings.warn("Passing '_fields' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + fields = None + + if fields is None: + fields = kwargs + elif kwargs: + raise TypeError("TypedDict takes either a dict or keyword arguments," + " but not both") + + ns = {'__annotations__': dict(fields)} + try: + # Setting correct module is necessary to make typed dict classes pickleable. + ns['__module__'] = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + pass + + return _TypedDictMeta(typename, (), ns, total=total) + + _typeddict_new.__text_signature__ = ('($cls, _typename, _fields=None,' + ' /, *, total=True, **kwargs)') + + class _TypedDictMeta(type): + def __init__(cls, name, bases, ns, total=True): + super().__init__(name, bases, ns) + + def __new__(cls, name, bases, ns, total=True): + # Create new typed dict class object. + # This method is called directly when TypedDict is subclassed, + # or via _typeddict_new when TypedDict is instantiated. This way + # TypedDict supports all three syntaxes described in its docstring. + # Subclasses and instances of TypedDict return actual dictionaries + # via _dict_new. + ns['__new__'] = _typeddict_new if name == 'TypedDict' else _dict_new + tp_dict = super().__new__(cls, name, (dict,), ns) + + annotations = {} + own_annotations = ns.get('__annotations__', {}) + own_annotation_keys = set(own_annotations.keys()) + msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" + own_annotations = { + n: typing._type_check(tp, msg) for n, tp in own_annotations.items() + } + required_keys = set() + optional_keys = set() + + for base in bases: + annotations.update(base.__dict__.get('__annotations__', {})) + required_keys.update(base.__dict__.get('__required_keys__', ())) + optional_keys.update(base.__dict__.get('__optional_keys__', ())) + + annotations.update(own_annotations) + if total: + required_keys.update(own_annotation_keys) + else: + optional_keys.update(own_annotation_keys) + + tp_dict.__annotations__ = annotations + tp_dict.__required_keys__ = frozenset(required_keys) + tp_dict.__optional_keys__ = frozenset(optional_keys) + if not hasattr(tp_dict, '__total__'): + tp_dict.__total__ = total + return tp_dict + + __instancecheck__ = __subclasscheck__ = _check_fails + + TypedDict = _TypedDictMeta('TypedDict', (dict,), {}) + TypedDict.__module__ = __name__ + TypedDict.__doc__ = \ + """A simple typed name space. At runtime it is equivalent to a plain dict. + + TypedDict creates a dictionary type that expects all of its + instances to have a certain set of keys, with each key + associated with a value of a consistent type. This expectation + is not checked at runtime but is only enforced by type checkers. + Usage:: + + class Point2D(TypedDict): + x: int + y: int + label: str + + a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK + b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check + + assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first') + + The type info can be accessed via the Point2D.__annotations__ dict, and + the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets. + TypedDict supports two additional equivalent forms:: + + Point2D = TypedDict('Point2D', x=int, y=int, label=str) + Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str}) + + The class syntax is only supported in Python 3.6+, while two other + syntax forms work for Python 2.7 and 3.2+ + """ + + +# Python 3.9+ has PEP 593 (Annotated and modified get_type_hints) +if hasattr(typing, 'Annotated'): + Annotated = typing.Annotated + get_type_hints = typing.get_type_hints + # Not exported and not a public API, but needed for get_origin() and get_args() + # to work. + _AnnotatedAlias = typing._AnnotatedAlias +# 3.7-3.8 +elif PEP_560: + class _AnnotatedAlias(typing._GenericAlias, _root=True): + """Runtime representation of an annotated type. + + At its core 'Annotated[t, dec1, dec2, ...]' is an alias for the type 't' + with extra annotations. The alias behaves like a normal typing alias, + instantiating is the same as instantiating the underlying type, binding + it to types is also the same. + """ + def __init__(self, origin, metadata): + if isinstance(origin, _AnnotatedAlias): + metadata = origin.__metadata__ + metadata + origin = origin.__origin__ + super().__init__(origin, origin) + self.__metadata__ = metadata + + def copy_with(self, params): + assert len(params) == 1 + new_type = params[0] + return _AnnotatedAlias(new_type, self.__metadata__) + + def __repr__(self): + return (f"typing_extensions.Annotated[{typing._type_repr(self.__origin__)}, " + f"{', '.join(repr(a) for a in self.__metadata__)}]") + + def __reduce__(self): + return operator.getitem, ( + Annotated, (self.__origin__,) + self.__metadata__ + ) + + def __eq__(self, other): + if not isinstance(other, _AnnotatedAlias): + return NotImplemented + if self.__origin__ != other.__origin__: + return False + return self.__metadata__ == other.__metadata__ + + def __hash__(self): + return hash((self.__origin__, self.__metadata__)) + + class Annotated: + """Add context specific metadata to a type. + + Example: Annotated[int, runtime_check.Unsigned] indicates to the + hypothetical runtime_check module that this type is an unsigned int. + Every other consumer of this type can ignore this metadata and treat + this type as int. + + The first argument to Annotated must be a valid type (and will be in + the __origin__ field), the remaining arguments are kept as a tuple in + the __extra__ field. + + Details: + + - It's an error to call `Annotated` with less than two arguments. + - Nested Annotated are flattened:: + + Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] + + - Instantiating an annotated type is equivalent to instantiating the + underlying type:: + + Annotated[C, Ann1](5) == C(5) + + - Annotated can be used as a generic type alias:: + + Optimized = Annotated[T, runtime.Optimize()] + Optimized[int] == Annotated[int, runtime.Optimize()] + + OptimizedList = Annotated[List[T], runtime.Optimize()] + OptimizedList[int] == Annotated[List[int], runtime.Optimize()] + """ + + __slots__ = () + + def __new__(cls, *args, **kwargs): + raise TypeError("Type Annotated cannot be instantiated.") + + @typing._tp_cache + def __class_getitem__(cls, params): + if not isinstance(params, tuple) or len(params) < 2: + raise TypeError("Annotated[...] should be used " + "with at least two arguments (a type and an " + "annotation).") + msg = "Annotated[t, ...]: t must be a type." + origin = typing._type_check(params[0], msg) + metadata = tuple(params[1:]) + return _AnnotatedAlias(origin, metadata) + + def __init_subclass__(cls, *args, **kwargs): + raise TypeError( + f"Cannot subclass {cls.__module__}.Annotated" + ) + + def _strip_annotations(t): + """Strips the annotations from a given type. + """ + if isinstance(t, _AnnotatedAlias): + return _strip_annotations(t.__origin__) + if isinstance(t, typing._GenericAlias): + stripped_args = tuple(_strip_annotations(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + res = t.copy_with(stripped_args) + res._special = t._special + return res + return t + + def get_type_hints(obj, globalns=None, localns=None, include_extras=False): + """Return type hints for an object. + + This is often the same as obj.__annotations__, but it handles + forward references encoded as string literals, adds Optional[t] if a + default value equal to None is set and recursively replaces all + 'Annotated[T, ...]' with 'T' (unless 'include_extras=True'). + + The argument may be a module, class, method, or function. The annotations + are returned as a dictionary. For classes, annotations include also + inherited members. + + TypeError is raised if the argument is not of a type that can contain + annotations, and an empty dictionary is returned if no annotations are + present. + + BEWARE -- the behavior of globalns and localns is counterintuitive + (unless you are familiar with how eval() and exec() work). The + search order is locals first, then globals. + + - If no dict arguments are passed, an attempt is made to use the + globals from obj (or the respective module's globals for classes), + and these are also used as the locals. If the object does not appear + to have globals, an empty dictionary is used. + + - If one dict argument is passed, it is used for both globals and + locals. + + - If two dict arguments are passed, they specify globals and + locals, respectively. + """ + hint = typing.get_type_hints(obj, globalns=globalns, localns=localns) + if include_extras: + return hint + return {k: _strip_annotations(t) for k, t in hint.items()} +# 3.6 +else: + + def _is_dunder(name): + """Returns True if name is a __dunder_variable_name__.""" + return len(name) > 4 and name.startswith('__') and name.endswith('__') + + # Prior to Python 3.7 types did not have `copy_with`. A lot of the equality + # checks, argument expansion etc. are done on the _subs_tre. As a result we + # can't provide a get_type_hints function that strips out annotations. + + class AnnotatedMeta(typing.GenericMeta): + """Metaclass for Annotated""" + + def __new__(cls, name, bases, namespace, **kwargs): + if any(b is not object for b in bases): + raise TypeError("Cannot subclass " + str(Annotated)) + return super().__new__(cls, name, bases, namespace, **kwargs) + + @property + def __metadata__(self): + return self._subs_tree()[2] + + def _tree_repr(self, tree): + cls, origin, metadata = tree + if not isinstance(origin, tuple): + tp_repr = typing._type_repr(origin) + else: + tp_repr = origin[0]._tree_repr(origin) + metadata_reprs = ", ".join(repr(arg) for arg in metadata) + return f'{cls}[{tp_repr}, {metadata_reprs}]' + + def _subs_tree(self, tvars=None, args=None): # noqa + if self is Annotated: + return Annotated + res = super()._subs_tree(tvars=tvars, args=args) + # Flatten nested Annotated + if isinstance(res[1], tuple) and res[1][0] is Annotated: + sub_tp = res[1][1] + sub_annot = res[1][2] + return (Annotated, sub_tp, sub_annot + res[2]) + return res + + def _get_cons(self): + """Return the class used to create instance of this type.""" + if self.__origin__ is None: + raise TypeError("Cannot get the underlying type of a " + "non-specialized Annotated type.") + tree = self._subs_tree() + while isinstance(tree, tuple) and tree[0] is Annotated: + tree = tree[1] + if isinstance(tree, tuple): + return tree[0] + else: + return tree + + @typing._tp_cache + def __getitem__(self, params): + if not isinstance(params, tuple): + params = (params,) + if self.__origin__ is not None: # specializing an instantiated type + return super().__getitem__(params) + elif not isinstance(params, tuple) or len(params) < 2: + raise TypeError("Annotated[...] should be instantiated " + "with at least two arguments (a type and an " + "annotation).") + else: + msg = "Annotated[t, ...]: t must be a type." + tp = typing._type_check(params[0], msg) + metadata = tuple(params[1:]) + return self.__class__( + self.__name__, + self.__bases__, + _no_slots_copy(self.__dict__), + tvars=_type_vars((tp,)), + # Metadata is a tuple so it won't be touched by _replace_args et al. + args=(tp, metadata), + origin=self, + ) + + def __call__(self, *args, **kwargs): + cons = self._get_cons() + result = cons(*args, **kwargs) + try: + result.__orig_class__ = self + except AttributeError: + pass + return result + + def __getattr__(self, attr): + # For simplicity we just don't relay all dunder names + if self.__origin__ is not None and not _is_dunder(attr): + return getattr(self._get_cons(), attr) + raise AttributeError(attr) + + def __setattr__(self, attr, value): + if _is_dunder(attr) or attr.startswith('_abc_'): + super().__setattr__(attr, value) + elif self.__origin__ is None: + raise AttributeError(attr) + else: + setattr(self._get_cons(), attr, value) + + def __instancecheck__(self, obj): + raise TypeError("Annotated cannot be used with isinstance().") + + def __subclasscheck__(self, cls): + raise TypeError("Annotated cannot be used with issubclass().") + + class Annotated(metaclass=AnnotatedMeta): + """Add context specific metadata to a type. + + Example: Annotated[int, runtime_check.Unsigned] indicates to the + hypothetical runtime_check module that this type is an unsigned int. + Every other consumer of this type can ignore this metadata and treat + this type as int. + + The first argument to Annotated must be a valid type, the remaining + arguments are kept as a tuple in the __metadata__ field. + + Details: + + - It's an error to call `Annotated` with less than two arguments. + - Nested Annotated are flattened:: + + Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] + + - Instantiating an annotated type is equivalent to instantiating the + underlying type:: + + Annotated[C, Ann1](5) == C(5) + + - Annotated can be used as a generic type alias:: + + Optimized = Annotated[T, runtime.Optimize()] + Optimized[int] == Annotated[int, runtime.Optimize()] + + OptimizedList = Annotated[List[T], runtime.Optimize()] + OptimizedList[int] == Annotated[List[int], runtime.Optimize()] + """ + +# Python 3.8 has get_origin() and get_args() but those implementations aren't +# Annotated-aware, so we can't use those. Python 3.9's versions don't support +# ParamSpecArgs and ParamSpecKwargs, so only Python 3.10's versions will do. +if sys.version_info[:2] >= (3, 10): + get_origin = typing.get_origin + get_args = typing.get_args +# 3.7-3.9 +elif PEP_560: + try: + # 3.9+ + from typing import _BaseGenericAlias + except ImportError: + _BaseGenericAlias = typing._GenericAlias + try: + # 3.9+ + from typing import GenericAlias + except ImportError: + GenericAlias = typing._GenericAlias + + def get_origin(tp): + """Get the unsubscripted version of a type. + + This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar + and Annotated. Return None for unsupported types. Examples:: + + get_origin(Literal[42]) is Literal + get_origin(int) is None + get_origin(ClassVar[int]) is ClassVar + get_origin(Generic) is Generic + get_origin(Generic[T]) is Generic + get_origin(Union[T, int]) is Union + get_origin(List[Tuple[T, T]][int]) == list + get_origin(P.args) is P + """ + if isinstance(tp, _AnnotatedAlias): + return Annotated + if isinstance(tp, (typing._GenericAlias, GenericAlias, _BaseGenericAlias, + ParamSpecArgs, ParamSpecKwargs)): + return tp.__origin__ + if tp is typing.Generic: + return typing.Generic + return None + + def get_args(tp): + """Get type arguments with all substitutions performed. + + For unions, basic simplifications used by Union constructor are performed. + Examples:: + get_args(Dict[str, int]) == (str, int) + get_args(int) == () + get_args(Union[int, Union[T, int], str][int]) == (int, str) + get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) + get_args(Callable[[], T][int]) == ([], int) + """ + if isinstance(tp, _AnnotatedAlias): + return (tp.__origin__,) + tp.__metadata__ + if isinstance(tp, (typing._GenericAlias, GenericAlias)): + if getattr(tp, "_special", False): + return () + res = tp.__args__ + if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis: + res = (list(res[:-1]), res[-1]) + return res + return () + + +# 3.10+ +if hasattr(typing, 'TypeAlias'): + TypeAlias = typing.TypeAlias +# 3.9 +elif sys.version_info[:2] >= (3, 9): + class _TypeAliasForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + @_TypeAliasForm + def TypeAlias(self, parameters): + """Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example above. + """ + raise TypeError(f"{self} is not subscriptable") +# 3.7-3.8 +elif sys.version_info[:2] >= (3, 7): + class _TypeAliasForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + TypeAlias = _TypeAliasForm('TypeAlias', + doc="""Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example + above.""") +# 3.6 +else: + class _TypeAliasMeta(typing.TypingMeta): + """Metaclass for TypeAlias""" + + def __repr__(self): + return 'typing_extensions.TypeAlias' + + class _TypeAliasBase(typing._FinalTypingBase, metaclass=_TypeAliasMeta, _root=True): + """Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example above. + """ + __slots__ = () + + def __instancecheck__(self, obj): + raise TypeError("TypeAlias cannot be used with isinstance().") + + def __subclasscheck__(self, cls): + raise TypeError("TypeAlias cannot be used with issubclass().") + + def __repr__(self): + return 'typing_extensions.TypeAlias' + + TypeAlias = _TypeAliasBase(_root=True) + + +# Python 3.10+ has PEP 612 +if hasattr(typing, 'ParamSpecArgs'): + ParamSpecArgs = typing.ParamSpecArgs + ParamSpecKwargs = typing.ParamSpecKwargs +# 3.6-3.9 +else: + class _Immutable: + """Mixin to indicate that object should not be copied.""" + __slots__ = () + + def __copy__(self): + return self + + def __deepcopy__(self, memo): + return self + + class ParamSpecArgs(_Immutable): + """The args for a ParamSpec object. + + Given a ParamSpec object P, P.args is an instance of ParamSpecArgs. + + ParamSpecArgs objects have a reference back to their ParamSpec: + + P.args.__origin__ is P + + This type is meant for runtime introspection and has no special meaning to + static type checkers. + """ + def __init__(self, origin): + self.__origin__ = origin + + def __repr__(self): + return f"{self.__origin__.__name__}.args" + + class ParamSpecKwargs(_Immutable): + """The kwargs for a ParamSpec object. + + Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs. + + ParamSpecKwargs objects have a reference back to their ParamSpec: + + P.kwargs.__origin__ is P + + This type is meant for runtime introspection and has no special meaning to + static type checkers. + """ + def __init__(self, origin): + self.__origin__ = origin + + def __repr__(self): + return f"{self.__origin__.__name__}.kwargs" + +# 3.10+ +if hasattr(typing, 'ParamSpec'): + ParamSpec = typing.ParamSpec +# 3.6-3.9 +else: + + # Inherits from list as a workaround for Callable checks in Python < 3.9.2. + class ParamSpec(list): + """Parameter specification variable. + + Usage:: + + P = ParamSpec('P') + + Parameter specification variables exist primarily for the benefit of static + type checkers. They are used to forward the parameter types of one + callable to another callable, a pattern commonly found in higher order + functions and decorators. They are only valid when used in ``Concatenate``, + or s the first argument to ``Callable``. In Python 3.10 and higher, + they are also supported in user-defined Generics at runtime. + See class Generic for more information on generic types. An + example for annotating a decorator:: + + T = TypeVar('T') + P = ParamSpec('P') + + def add_logging(f: Callable[P, T]) -> Callable[P, T]: + '''A type-safe decorator to add logging to a function.''' + def inner(*args: P.args, **kwargs: P.kwargs) -> T: + logging.info(f'{f.__name__} was called') + return f(*args, **kwargs) + return inner + + @add_logging + def add_two(x: float, y: float) -> float: + '''Add two numbers together.''' + return x + y + + Parameter specification variables defined with covariant=True or + contravariant=True can be used to declare covariant or contravariant + generic types. These keyword arguments are valid, but their actual semantics + are yet to be decided. See PEP 612 for details. + + Parameter specification variables can be introspected. e.g.: + + P.__name__ == 'T' + P.__bound__ == None + P.__covariant__ == False + P.__contravariant__ == False + + Note that only parameter specification variables defined in global scope can + be pickled. + """ + + # Trick Generic __parameters__. + __class__ = typing.TypeVar + + @property + def args(self): + return ParamSpecArgs(self) + + @property + def kwargs(self): + return ParamSpecKwargs(self) + + def __init__(self, name, *, bound=None, covariant=False, contravariant=False): + super().__init__([self]) + self.__name__ = name + self.__covariant__ = bool(covariant) + self.__contravariant__ = bool(contravariant) + if bound: + self.__bound__ = typing._type_check(bound, 'Bound must be a type.') + else: + self.__bound__ = None + + # for pickling: + try: + def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + def_mod = None + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + def __repr__(self): + if self.__covariant__: + prefix = '+' + elif self.__contravariant__: + prefix = '-' + else: + prefix = '~' + return prefix + self.__name__ + + def __hash__(self): + return object.__hash__(self) + + def __eq__(self, other): + return self is other + + def __reduce__(self): + return self.__name__ + + # Hack to get typing._type_check to pass. + def __call__(self, *args, **kwargs): + pass + + if not PEP_560: + # Only needed in 3.6. + def _get_type_vars(self, tvars): + if self not in tvars: + tvars.append(self) + + +# 3.6-3.9 +if not hasattr(typing, 'Concatenate'): + # Inherits from list as a workaround for Callable checks in Python < 3.9.2. + class _ConcatenateGenericAlias(list): + + # Trick Generic into looking into this for __parameters__. + if PEP_560: + __class__ = typing._GenericAlias + else: + __class__ = typing._TypingBase + + # Flag in 3.8. + _special = False + # Attribute in 3.6 and earlier. + _gorg = typing.Generic + + def __init__(self, origin, args): + super().__init__(args) + self.__origin__ = origin + self.__args__ = args + + def __repr__(self): + _type_repr = typing._type_repr + return (f'{_type_repr(self.__origin__)}' + f'[{", ".join(_type_repr(arg) for arg in self.__args__)}]') + + def __hash__(self): + return hash((self.__origin__, self.__args__)) + + # Hack to get typing._type_check to pass in Generic. + def __call__(self, *args, **kwargs): + pass + + @property + def __parameters__(self): + return tuple( + tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec)) + ) + + if not PEP_560: + # Only required in 3.6. + def _get_type_vars(self, tvars): + if self.__origin__ and self.__parameters__: + typing._get_type_vars(self.__parameters__, tvars) + + +# 3.6-3.9 +@typing._tp_cache +def _concatenate_getitem(self, parameters): + if parameters == (): + raise TypeError("Cannot take a Concatenate of no types.") + if not isinstance(parameters, tuple): + parameters = (parameters,) + if not isinstance(parameters[-1], ParamSpec): + raise TypeError("The last parameter to Concatenate should be a " + "ParamSpec variable.") + msg = "Concatenate[arg, ...]: each arg must be a type." + parameters = tuple(typing._type_check(p, msg) for p in parameters) + return _ConcatenateGenericAlias(self, parameters) + + +# 3.10+ +if hasattr(typing, 'Concatenate'): + Concatenate = typing.Concatenate + _ConcatenateGenericAlias = typing._ConcatenateGenericAlias # noqa +# 3.9 +elif sys.version_info[:2] >= (3, 9): + @_TypeAliasForm + def Concatenate(self, parameters): + """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a + higher order function which adds, removes or transforms parameters of a + callable. + + For example:: + + Callable[Concatenate[int, P], int] + + See PEP 612 for detailed information. + """ + return _concatenate_getitem(self, parameters) +# 3.7-8 +elif sys.version_info[:2] >= (3, 7): + class _ConcatenateForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + return _concatenate_getitem(self, parameters) + + Concatenate = _ConcatenateForm( + 'Concatenate', + doc="""Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a + higher order function which adds, removes or transforms parameters of a + callable. + + For example:: + + Callable[Concatenate[int, P], int] + + See PEP 612 for detailed information. + """) +# 3.6 +else: + class _ConcatenateAliasMeta(typing.TypingMeta): + """Metaclass for Concatenate.""" + + def __repr__(self): + return 'typing_extensions.Concatenate' + + class _ConcatenateAliasBase(typing._FinalTypingBase, + metaclass=_ConcatenateAliasMeta, + _root=True): + """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a + higher order function which adds, removes or transforms parameters of a + callable. + + For example:: + + Callable[Concatenate[int, P], int] + + See PEP 612 for detailed information. + """ + __slots__ = () + + def __instancecheck__(self, obj): + raise TypeError("Concatenate cannot be used with isinstance().") + + def __subclasscheck__(self, cls): + raise TypeError("Concatenate cannot be used with issubclass().") + + def __repr__(self): + return 'typing_extensions.Concatenate' + + def __getitem__(self, parameters): + return _concatenate_getitem(self, parameters) + + Concatenate = _ConcatenateAliasBase(_root=True) + +# 3.10+ +if hasattr(typing, 'TypeGuard'): + TypeGuard = typing.TypeGuard +# 3.9 +elif sys.version_info[:2] >= (3, 9): + class _TypeGuardForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + @_TypeGuardForm + def TypeGuard(self, parameters): + """Special typing form used to annotate the return type of a user-defined + type guard function. ``TypeGuard`` only accepts a single type argument. + At runtime, functions marked this way should return a boolean. + + ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static + type checkers to determine a more precise type of an expression within a + program's code flow. Usually type narrowing is done by analyzing + conditional code flow and applying the narrowing to a block of code. The + conditional expression here is sometimes referred to as a "type guard". + + Sometimes it would be convenient to use a user-defined boolean function + as a type guard. Such a function should use ``TypeGuard[...]`` as its + return type to alert static type checkers to this intention. + + Using ``-> TypeGuard`` tells the static type checker that for a given + function: + + 1. The return value is a boolean. + 2. If the return value is ``True``, the type of its argument + is the type inside ``TypeGuard``. + + For example:: + + def is_str(val: Union[str, float]): + # "isinstance" type guard + if isinstance(val, str): + # Type of ``val`` is narrowed to ``str`` + ... + else: + # Else, type of ``val`` is narrowed to ``float``. + ... + + Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower + form of ``TypeA`` (it can even be a wider form) and this may lead to + type-unsafe results. The main reason is to allow for things like + narrowing ``List[object]`` to ``List[str]`` even though the latter is not + a subtype of the former, since ``List`` is invariant. The responsibility of + writing type-safe type guards is left to the user. + + ``TypeGuard`` also works with type variables. For more information, see + PEP 647 (User-Defined Type Guards). + """ + item = typing._type_check(parameters, f'{self} accepts only single type.') + return typing._GenericAlias(self, (item,)) +# 3.7-3.8 +elif sys.version_info[:2] >= (3, 7): + class _TypeGuardForm(typing._SpecialForm, _root=True): + + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type') + return typing._GenericAlias(self, (item,)) + + TypeGuard = _TypeGuardForm( + 'TypeGuard', + doc="""Special typing form used to annotate the return type of a user-defined + type guard function. ``TypeGuard`` only accepts a single type argument. + At runtime, functions marked this way should return a boolean. + + ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static + type checkers to determine a more precise type of an expression within a + program's code flow. Usually type narrowing is done by analyzing + conditional code flow and applying the narrowing to a block of code. The + conditional expression here is sometimes referred to as a "type guard". + + Sometimes it would be convenient to use a user-defined boolean function + as a type guard. Such a function should use ``TypeGuard[...]`` as its + return type to alert static type checkers to this intention. + + Using ``-> TypeGuard`` tells the static type checker that for a given + function: + + 1. The return value is a boolean. + 2. If the return value is ``True``, the type of its argument + is the type inside ``TypeGuard``. + + For example:: + + def is_str(val: Union[str, float]): + # "isinstance" type guard + if isinstance(val, str): + # Type of ``val`` is narrowed to ``str`` + ... + else: + # Else, type of ``val`` is narrowed to ``float``. + ... + + Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower + form of ``TypeA`` (it can even be a wider form) and this may lead to + type-unsafe results. The main reason is to allow for things like + narrowing ``List[object]`` to ``List[str]`` even though the latter is not + a subtype of the former, since ``List`` is invariant. The responsibility of + writing type-safe type guards is left to the user. + + ``TypeGuard`` also works with type variables. For more information, see + PEP 647 (User-Defined Type Guards). + """) +# 3.6 +else: + class _TypeGuard(typing._FinalTypingBase, _root=True): + """Special typing form used to annotate the return type of a user-defined + type guard function. ``TypeGuard`` only accepts a single type argument. + At runtime, functions marked this way should return a boolean. + + ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static + type checkers to determine a more precise type of an expression within a + program's code flow. Usually type narrowing is done by analyzing + conditional code flow and applying the narrowing to a block of code. The + conditional expression here is sometimes referred to as a "type guard". + + Sometimes it would be convenient to use a user-defined boolean function + as a type guard. Such a function should use ``TypeGuard[...]`` as its + return type to alert static type checkers to this intention. + + Using ``-> TypeGuard`` tells the static type checker that for a given + function: + + 1. The return value is a boolean. + 2. If the return value is ``True``, the type of its argument + is the type inside ``TypeGuard``. + + For example:: + + def is_str(val: Union[str, float]): + # "isinstance" type guard + if isinstance(val, str): + # Type of ``val`` is narrowed to ``str`` + ... + else: + # Else, type of ``val`` is narrowed to ``float``. + ... + + Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower + form of ``TypeA`` (it can even be a wider form) and this may lead to + type-unsafe results. The main reason is to allow for things like + narrowing ``List[object]`` to ``List[str]`` even though the latter is not + a subtype of the former, since ``List`` is invariant. The responsibility of + writing type-safe type guards is left to the user. + + ``TypeGuard`` also works with type variables. For more information, see + PEP 647 (User-Defined Type Guards). + """ + + __slots__ = ('__type__',) + + def __init__(self, tp=None, **kwds): + self.__type__ = tp + + def __getitem__(self, item): + cls = type(self) + if self.__type__ is None: + return cls(typing._type_check(item, + f'{cls.__name__[1:]} accepts only a single type.'), + _root=True) + raise TypeError(f'{cls.__name__[1:]} cannot be further subscripted') + + def _eval_type(self, globalns, localns): + new_tp = typing._eval_type(self.__type__, globalns, localns) + if new_tp == self.__type__: + return self + return type(self)(new_tp, _root=True) + + def __repr__(self): + r = super().__repr__() + if self.__type__ is not None: + r += f'[{typing._type_repr(self.__type__)}]' + return r + + def __hash__(self): + return hash((type(self).__name__, self.__type__)) + + def __eq__(self, other): + if not isinstance(other, _TypeGuard): + return NotImplemented + if self.__type__ is not None: + return self.__type__ == other.__type__ + return self is other + + TypeGuard = _TypeGuard(_root=True) + +if hasattr(typing, "Self"): + Self = typing.Self +elif sys.version_info[:2] >= (3, 7): + # Vendored from cpython typing._SpecialFrom + class _SpecialForm(typing._Final, _root=True): + __slots__ = ('_name', '__doc__', '_getitem') + + def __init__(self, getitem): + self._getitem = getitem + self._name = getitem.__name__ + self.__doc__ = getitem.__doc__ + + def __getattr__(self, item): + if item in {'__name__', '__qualname__'}: + return self._name + + raise AttributeError(item) + + def __mro_entries__(self, bases): + raise TypeError(f"Cannot subclass {self!r}") + + def __repr__(self): + return f'typing_extensions.{self._name}' + + def __reduce__(self): + return self._name + + def __call__(self, *args, **kwds): + raise TypeError(f"Cannot instantiate {self!r}") + + def __or__(self, other): + return typing.Union[self, other] + + def __ror__(self, other): + return typing.Union[other, self] + + def __instancecheck__(self, obj): + raise TypeError(f"{self} cannot be used with isinstance()") + + def __subclasscheck__(self, cls): + raise TypeError(f"{self} cannot be used with issubclass()") + + @typing._tp_cache + def __getitem__(self, parameters): + return self._getitem(self, parameters) + + @_SpecialForm + def Self(self, params): + """Used to spell the type of "self" in classes. + + Example:: + + from typing import Self + + class ReturnsSelf: + def parse(self, data: bytes) -> Self: + ... + return self + + """ + + raise TypeError(f"{self} is not subscriptable") +else: + class _Self(typing._FinalTypingBase, _root=True): + """Used to spell the type of "self" in classes. + + Example:: + + from typing import Self + + class ReturnsSelf: + def parse(self, data: bytes) -> Self: + ... + return self + + """ + + __slots__ = () + + def __instancecheck__(self, obj): + raise TypeError(f"{self} cannot be used with isinstance().") + + def __subclasscheck__(self, cls): + raise TypeError(f"{self} cannot be used with issubclass().") + + Self = _Self(_root=True) + + +if hasattr(typing, 'Required'): + Required = typing.Required + NotRequired = typing.NotRequired +elif sys.version_info[:2] >= (3, 9): + class _ExtensionsSpecialForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + @_ExtensionsSpecialForm + def Required(self, parameters): + """A special typing construct to mark a key of a total=False TypedDict + as required. For example: + + class Movie(TypedDict, total=False): + title: Required[str] + year: int + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + + There is no runtime checking that a required key is actually provided + when instantiating a related TypedDict. + """ + item = typing._type_check(parameters, f'{self._name} accepts only single type') + return typing._GenericAlias(self, (item,)) + + @_ExtensionsSpecialForm + def NotRequired(self, parameters): + """A special typing construct to mark a key of a TypedDict as + potentially missing. For example: + + class Movie(TypedDict): + title: str + year: NotRequired[int] + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + """ + item = typing._type_check(parameters, f'{self._name} accepts only single type') + return typing._GenericAlias(self, (item,)) + +elif sys.version_info[:2] >= (3, 7): + class _RequiredForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + item = typing._type_check(parameters, + '{} accepts only single type'.format(self._name)) + return typing._GenericAlias(self, (item,)) + + Required = _RequiredForm( + 'Required', + doc="""A special typing construct to mark a key of a total=False TypedDict + as required. For example: + + class Movie(TypedDict, total=False): + title: Required[str] + year: int + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + + There is no runtime checking that a required key is actually provided + when instantiating a related TypedDict. + """) + NotRequired = _RequiredForm( + 'NotRequired', + doc="""A special typing construct to mark a key of a TypedDict as + potentially missing. For example: + + class Movie(TypedDict): + title: str + year: NotRequired[int] + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + """) +else: + # NOTE: Modeled after _Final's implementation when _FinalTypingBase available + class _MaybeRequired(typing._FinalTypingBase, _root=True): + __slots__ = ('__type__',) + + def __init__(self, tp=None, **kwds): + self.__type__ = tp + + def __getitem__(self, item): + cls = type(self) + if self.__type__ is None: + return cls(typing._type_check(item, + '{} accepts only single type.'.format(cls.__name__[1:])), + _root=True) + raise TypeError('{} cannot be further subscripted' + .format(cls.__name__[1:])) + + def _eval_type(self, globalns, localns): + new_tp = typing._eval_type(self.__type__, globalns, localns) + if new_tp == self.__type__: + return self + return type(self)(new_tp, _root=True) + + def __repr__(self): + r = super().__repr__() + if self.__type__ is not None: + r += '[{}]'.format(typing._type_repr(self.__type__)) + return r + + def __hash__(self): + return hash((type(self).__name__, self.__type__)) + + def __eq__(self, other): + if not isinstance(other, type(self)): + return NotImplemented + if self.__type__ is not None: + return self.__type__ == other.__type__ + return self is other + + class _Required(_MaybeRequired, _root=True): + """A special typing construct to mark a key of a total=False TypedDict + as required. For example: + + class Movie(TypedDict, total=False): + title: Required[str] + year: int + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + + There is no runtime checking that a required key is actually provided + when instantiating a related TypedDict. + """ + + class _NotRequired(_MaybeRequired, _root=True): + """A special typing construct to mark a key of a TypedDict as + potentially missing. For example: + + class Movie(TypedDict): + title: str + year: NotRequired[int] + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + """ + + Required = _Required(_root=True) + NotRequired = _NotRequired(_root=True) diff --git a/venv/Lib/site-packages/setuptools/_vendor/zipp.py b/venv/Lib/site-packages/setuptools/_vendor/zipp.py new file mode 100644 index 0000000..26b723c --- /dev/null +++ b/venv/Lib/site-packages/setuptools/_vendor/zipp.py @@ -0,0 +1,329 @@ +import io +import posixpath +import zipfile +import itertools +import contextlib +import sys +import pathlib + +if sys.version_info < (3, 7): + from collections import OrderedDict +else: + OrderedDict = dict + + +__all__ = ['Path'] + + +def _parents(path): + """ + Given a path with elements separated by + posixpath.sep, generate all parents of that path. + + >>> list(_parents('b/d')) + ['b'] + >>> list(_parents('/b/d/')) + ['/b'] + >>> list(_parents('b/d/f/')) + ['b/d', 'b'] + >>> list(_parents('b')) + [] + >>> list(_parents('')) + [] + """ + return itertools.islice(_ancestry(path), 1, None) + + +def _ancestry(path): + """ + Given a path with elements separated by + posixpath.sep, generate all elements of that path + + >>> list(_ancestry('b/d')) + ['b/d', 'b'] + >>> list(_ancestry('/b/d/')) + ['/b/d', '/b'] + >>> list(_ancestry('b/d/f/')) + ['b/d/f', 'b/d', 'b'] + >>> list(_ancestry('b')) + ['b'] + >>> list(_ancestry('')) + [] + """ + path = path.rstrip(posixpath.sep) + while path and path != posixpath.sep: + yield path + path, tail = posixpath.split(path) + + +_dedupe = OrderedDict.fromkeys +"""Deduplicate an iterable in original order""" + + +def _difference(minuend, subtrahend): + """ + Return items in minuend not in subtrahend, retaining order + with O(1) lookup. + """ + return itertools.filterfalse(set(subtrahend).__contains__, minuend) + + +class CompleteDirs(zipfile.ZipFile): + """ + A ZipFile subclass that ensures that implied directories + are always included in the namelist. + """ + + @staticmethod + def _implied_dirs(names): + parents = itertools.chain.from_iterable(map(_parents, names)) + as_dirs = (p + posixpath.sep for p in parents) + return _dedupe(_difference(as_dirs, names)) + + def namelist(self): + names = super(CompleteDirs, self).namelist() + return names + list(self._implied_dirs(names)) + + def _name_set(self): + return set(self.namelist()) + + def resolve_dir(self, name): + """ + If the name represents a directory, return that name + as a directory (with the trailing slash). + """ + names = self._name_set() + dirname = name + '/' + dir_match = name not in names and dirname in names + return dirname if dir_match else name + + @classmethod + def make(cls, source): + """ + Given a source (filename or zipfile), return an + appropriate CompleteDirs subclass. + """ + if isinstance(source, CompleteDirs): + return source + + if not isinstance(source, zipfile.ZipFile): + return cls(_pathlib_compat(source)) + + # Only allow for FastLookup when supplied zipfile is read-only + if 'r' not in source.mode: + cls = CompleteDirs + + source.__class__ = cls + return source + + +class FastLookup(CompleteDirs): + """ + ZipFile subclass to ensure implicit + dirs exist and are resolved rapidly. + """ + + def namelist(self): + with contextlib.suppress(AttributeError): + return self.__names + self.__names = super(FastLookup, self).namelist() + return self.__names + + def _name_set(self): + with contextlib.suppress(AttributeError): + return self.__lookup + self.__lookup = super(FastLookup, self)._name_set() + return self.__lookup + + +def _pathlib_compat(path): + """ + For path-like objects, convert to a filename for compatibility + on Python 3.6.1 and earlier. + """ + try: + return path.__fspath__() + except AttributeError: + return str(path) + + +class Path: + """ + A pathlib-compatible interface for zip files. + + Consider a zip file with this structure:: + + . + ├── a.txt + └── b + ├── c.txt + └── d + └── e.txt + + >>> data = io.BytesIO() + >>> zf = zipfile.ZipFile(data, 'w') + >>> zf.writestr('a.txt', 'content of a') + >>> zf.writestr('b/c.txt', 'content of c') + >>> zf.writestr('b/d/e.txt', 'content of e') + >>> zf.filename = 'mem/abcde.zip' + + Path accepts the zipfile object itself or a filename + + >>> root = Path(zf) + + From there, several path operations are available. + + Directory iteration (including the zip file itself): + + >>> a, b = root.iterdir() + >>> a + Path('mem/abcde.zip', 'a.txt') + >>> b + Path('mem/abcde.zip', 'b/') + + name property: + + >>> b.name + 'b' + + join with divide operator: + + >>> c = b / 'c.txt' + >>> c + Path('mem/abcde.zip', 'b/c.txt') + >>> c.name + 'c.txt' + + Read text: + + >>> c.read_text() + 'content of c' + + existence: + + >>> c.exists() + True + >>> (b / 'missing.txt').exists() + False + + Coercion to string: + + >>> import os + >>> str(c).replace(os.sep, posixpath.sep) + 'mem/abcde.zip/b/c.txt' + + At the root, ``name``, ``filename``, and ``parent`` + resolve to the zipfile. Note these attributes are not + valid and will raise a ``ValueError`` if the zipfile + has no filename. + + >>> root.name + 'abcde.zip' + >>> str(root.filename).replace(os.sep, posixpath.sep) + 'mem/abcde.zip' + >>> str(root.parent) + 'mem' + """ + + __repr = "{self.__class__.__name__}({self.root.filename!r}, {self.at!r})" + + def __init__(self, root, at=""): + """ + Construct a Path from a ZipFile or filename. + + Note: When the source is an existing ZipFile object, + its type (__class__) will be mutated to a + specialized type. If the caller wishes to retain the + original type, the caller should either create a + separate ZipFile object or pass a filename. + """ + self.root = FastLookup.make(root) + self.at = at + + def open(self, mode='r', *args, pwd=None, **kwargs): + """ + Open this entry as text or binary following the semantics + of ``pathlib.Path.open()`` by passing arguments through + to io.TextIOWrapper(). + """ + if self.is_dir(): + raise IsADirectoryError(self) + zip_mode = mode[0] + if not self.exists() and zip_mode == 'r': + raise FileNotFoundError(self) + stream = self.root.open(self.at, zip_mode, pwd=pwd) + if 'b' in mode: + if args or kwargs: + raise ValueError("encoding args invalid for binary operation") + return stream + return io.TextIOWrapper(stream, *args, **kwargs) + + @property + def name(self): + return pathlib.Path(self.at).name or self.filename.name + + @property + def suffix(self): + return pathlib.Path(self.at).suffix or self.filename.suffix + + @property + def suffixes(self): + return pathlib.Path(self.at).suffixes or self.filename.suffixes + + @property + def stem(self): + return pathlib.Path(self.at).stem or self.filename.stem + + @property + def filename(self): + return pathlib.Path(self.root.filename).joinpath(self.at) + + def read_text(self, *args, **kwargs): + with self.open('r', *args, **kwargs) as strm: + return strm.read() + + def read_bytes(self): + with self.open('rb') as strm: + return strm.read() + + def _is_child(self, path): + return posixpath.dirname(path.at.rstrip("/")) == self.at.rstrip("/") + + def _next(self, at): + return self.__class__(self.root, at) + + def is_dir(self): + return not self.at or self.at.endswith("/") + + def is_file(self): + return self.exists() and not self.is_dir() + + def exists(self): + return self.at in self.root._name_set() + + def iterdir(self): + if not self.is_dir(): + raise ValueError("Can't listdir a file") + subs = map(self._next, self.root.namelist()) + return filter(self._is_child, subs) + + def __str__(self): + return posixpath.join(self.root.filename, self.at) + + def __repr__(self): + return self.__repr.format(self=self) + + def joinpath(self, *other): + next = posixpath.join(self.at, *map(_pathlib_compat, other)) + return self._next(self.root.resolve_dir(next)) + + __truediv__ = joinpath + + @property + def parent(self): + if not self.at: + return self.filename.parent + parent_at = posixpath.dirname(self.at.rstrip('/')) + if parent_at: + parent_at += '/' + return self._next(parent_at) diff --git a/venv/Lib/site-packages/setuptools/cli-arm64.exe b/venv/Lib/site-packages/setuptools/cli-arm64.exe new file mode 100644 index 0000000..7a87ce4 Binary files /dev/null and b/venv/Lib/site-packages/setuptools/cli-arm64.exe differ diff --git a/venv/Lib/site-packages/setuptools/command/build.py b/venv/Lib/site-packages/setuptools/command/build.py new file mode 100644 index 0000000..fa3c99e --- /dev/null +++ b/venv/Lib/site-packages/setuptools/command/build.py @@ -0,0 +1,146 @@ +import sys +import warnings +from typing import TYPE_CHECKING, List, Dict +from distutils.command.build import build as _build + +from setuptools import SetuptoolsDeprecationWarning + +if sys.version_info >= (3, 8): + from typing import Protocol +elif TYPE_CHECKING: + from typing_extensions import Protocol +else: + from abc import ABC as Protocol + + +_ORIGINAL_SUBCOMMANDS = {"build_py", "build_clib", "build_ext", "build_scripts"} + + +class build(_build): + # copy to avoid sharing the object with parent class + sub_commands = _build.sub_commands[:] + + def get_sub_commands(self): + subcommands = {cmd[0] for cmd in _build.sub_commands} + if subcommands - _ORIGINAL_SUBCOMMANDS: + msg = """ + It seems that you are using `distutils.command.build` to add + new subcommands. Using `distutils` directly is considered deprecated, + please use `setuptools.command.build`. + """ + warnings.warn(msg, SetuptoolsDeprecationWarning) + self.sub_commands = _build.sub_commands + return super().get_sub_commands() + + +class SubCommand(Protocol): + """In order to support editable installations (see :pep:`660`) all + build subcommands **SHOULD** implement this protocol. They also **MUST** inherit + from ``setuptools.Command``. + + When creating an :pep:`editable wheel <660>`, ``setuptools`` will try to evaluate + custom ``build`` subcommands using the following procedure: + + 1. ``setuptools`` will set the ``editable_mode`` attribute to ``True`` + 2. ``setuptools`` will execute the ``run()`` command. + + .. important:: + Subcommands **SHOULD** take advantage of ``editable_mode=True`` to adequate + its behaviour or perform optimisations. + + For example, if a subcommand doesn't need to generate an extra file and + all it does is to copy a source file into the build directory, + ``run()`` **SHOULD** simply "early return". + + Similarly, if the subcommand creates files that would be placed alongside + Python files in the final distribution, during an editable install + the command **SHOULD** generate these files "in place" (i.e. write them to + the original source directory, instead of using the build directory). + Note that ``get_output_mapping()`` should reflect that and include mappings + for "in place" builds accordingly. + + 3. ``setuptools`` use any knowledge it can derive from the return values of + ``get_outputs()`` and ``get_output_mapping()`` to create an editable wheel. + When relevant ``setuptools`` **MAY** attempt to use file links based on the value + of ``get_output_mapping()``. Alternatively, ``setuptools`` **MAY** attempt to use + :doc:`import hooks ` to redirect any attempt to import + to the directory with the original source code and other files built in place. + + Please note that custom sub-commands **SHOULD NOT** rely on ``run()`` being + executed (or not) to provide correct return values for ``get_outputs()``, + ``get_output_mapping()`` or ``get_source_files()``. The ``get_*`` methods should + work independently of ``run()``. + """ + + editable_mode: bool = False + """Boolean flag that will be set to ``True`` when setuptools is used for an + editable installation (see :pep:`660`). + Implementations **SHOULD** explicitly set the default value of this attribute to + ``False``. + When subcommands run, they can use this flag to perform optimizations or change + their behaviour accordingly. + """ + + build_lib: str + """String representing the directory where the build artifacts should be stored, + e.g. ``build/lib``. + For example, if a distribution wants to provide a Python module named ``pkg.mod``, + then a corresponding file should be written to ``{build_lib}/package/module.py``. + A way of thinking about this is that the files saved under ``build_lib`` + would be eventually copied to one of the directories in :obj:`site.PREFIXES` + upon installation. + + A command that produces platform-independent files (e.g. compiling text templates + into Python functions), **CAN** initialize ``build_lib`` by copying its value from + the ``build_py`` command. On the other hand, a command that produces + platform-specific files **CAN** initialize ``build_lib`` by copying its value from + the ``build_ext`` command. In general this is done inside the ``finalize_options`` + method with the help of the ``set_undefined_options`` command:: + + def finalize_options(self): + self.set_undefined_options("build_py", ("build_lib", "build_lib")) + ... + """ + + def initialize_options(self): + """(Required by the original :class:`setuptools.Command` interface)""" + + def finalize_options(self): + """(Required by the original :class:`setuptools.Command` interface)""" + + def run(self): + """(Required by the original :class:`setuptools.Command` interface)""" + + def get_source_files(self) -> List[str]: + """ + Return a list of all files that are used by the command to create the expected + outputs. + For example, if your build command transpiles Java files into Python, you should + list here all the Java files. + The primary purpose of this function is to help populating the ``sdist`` + with all the files necessary to build the distribution. + All files should be strings relative to the project root directory. + """ + + def get_outputs(self) -> List[str]: + """ + Return a list of files intended for distribution as they would have been + produced by the build. + These files should be strings in the form of + ``"{build_lib}/destination/file/path"``. + + .. note:: + The return value of ``get_output()`` should include all files used as keys + in ``get_output_mapping()`` plus files that are generated during the build + and don't correspond to any source file already present in the project. + """ + + def get_output_mapping(self) -> Dict[str, str]: + """ + Return a mapping between destination files as they would be produced by the + build (dict keys) into the respective existing (source) files (dict values). + Existing (source) files should be represented as strings relative to the project + root directory. + Destination files should be strings in the form of + ``"{build_lib}/destination/file/path"``. + """ diff --git a/venv/Lib/site-packages/setuptools/command/editable_wheel.py b/venv/Lib/site-packages/setuptools/command/editable_wheel.py new file mode 100644 index 0000000..d60cfbe --- /dev/null +++ b/venv/Lib/site-packages/setuptools/command/editable_wheel.py @@ -0,0 +1,844 @@ +""" +Create a wheel that, when installed, will make the source package 'editable' +(add it to the interpreter's path, including metadata) per PEP 660. Replaces +'setup.py develop'. + +.. note:: + One of the mechanisms briefly mentioned in PEP 660 to implement editable installs is + to create a separated directory inside ``build`` and use a .pth file to point to that + directory. In the context of this file such directory is referred as + *auxiliary build directory* or ``auxiliary_dir``. +""" + +import logging +import os +import re +import shutil +import sys +import traceback +import warnings +from contextlib import suppress +from enum import Enum +from inspect import cleandoc +from itertools import chain +from pathlib import Path +from tempfile import TemporaryDirectory +from typing import ( + TYPE_CHECKING, + Dict, + Iterable, + Iterator, + List, + Mapping, + Optional, + Tuple, + TypeVar, + Union, +) + +from setuptools import Command, SetuptoolsDeprecationWarning, errors, namespaces +from setuptools.command.build_py import build_py as build_py_cls +from setuptools.discovery import find_package_path +from setuptools.dist import Distribution + +if TYPE_CHECKING: + from wheel.wheelfile import WheelFile # noqa + +if sys.version_info >= (3, 8): + from typing import Protocol +elif TYPE_CHECKING: + from typing_extensions import Protocol +else: + from abc import ABC as Protocol + +_Path = Union[str, Path] +_P = TypeVar("_P", bound=_Path) +_logger = logging.getLogger(__name__) + + +class _EditableMode(Enum): + """ + Possible editable installation modes: + `lenient` (new files automatically added to the package - DEFAULT); + `strict` (requires a new installation when files are added/removed); or + `compat` (attempts to emulate `python setup.py develop` - DEPRECATED). + """ + + STRICT = "strict" + LENIENT = "lenient" + COMPAT = "compat" # TODO: Remove `compat` after Dec/2022. + + @classmethod + def convert(cls, mode: Optional[str]) -> "_EditableMode": + if not mode: + return _EditableMode.LENIENT # default + + _mode = mode.upper() + if _mode not in _EditableMode.__members__: + raise errors.OptionError(f"Invalid editable mode: {mode!r}. Try: 'strict'.") + + if _mode == "COMPAT": + msg = """ + The 'compat' editable mode is transitional and will be removed + in future versions of `setuptools`. + Please adapt your code accordingly to use either the 'strict' or the + 'lenient' modes. + + For more information, please check: + https://setuptools.pypa.io/en/latest/userguide/development_mode.html + """ + warnings.warn(msg, SetuptoolsDeprecationWarning) + + return _EditableMode[_mode] + + +_STRICT_WARNING = """ +New or renamed files may not be automatically picked up without a new installation. +""" + +_LENIENT_WARNING = """ +Options like `package-data`, `include/exclude-package-data` or +`packages.find.exclude/include` may have no effect. +""" + + +class editable_wheel(Command): + """Build 'editable' wheel for development. + (This command is reserved for internal use of setuptools). + """ + + description = "create a PEP 660 'editable' wheel" + + user_options = [ + ("dist-dir=", "d", "directory to put final built distributions in"), + ("dist-info-dir=", "I", "path to a pre-build .dist-info directory"), + ("mode=", None, cleandoc(_EditableMode.__doc__ or "")), + ] + + def initialize_options(self): + self.dist_dir = None + self.dist_info_dir = None + self.project_dir = None + self.mode = None + + def finalize_options(self): + dist = self.distribution + self.project_dir = dist.src_root or os.curdir + self.package_dir = dist.package_dir or {} + self.dist_dir = Path(self.dist_dir or os.path.join(self.project_dir, "dist")) + + def run(self): + try: + self.dist_dir.mkdir(exist_ok=True) + self._ensure_dist_info() + + # Add missing dist_info files + self.reinitialize_command("bdist_wheel") + bdist_wheel = self.get_finalized_command("bdist_wheel") + bdist_wheel.write_wheelfile(self.dist_info_dir) + + self._create_wheel_file(bdist_wheel) + except Exception as ex: + traceback.print_exc() + msg = """ + Support for editable installs via PEP 660 was recently introduced + in `setuptools`. If you are seeing this error, please report to: + + https://github.com/pypa/setuptools/issues + + Meanwhile you can try the legacy behavior by setting an + environment variable and trying to install again: + + SETUPTOOLS_ENABLE_FEATURES="legacy-editable" + """ + raise errors.InternalError(cleandoc(msg)) from ex + + def _ensure_dist_info(self): + if self.dist_info_dir is None: + dist_info = self.reinitialize_command("dist_info") + dist_info.output_dir = self.dist_dir + dist_info.ensure_finalized() + dist_info.run() + self.dist_info_dir = dist_info.dist_info_dir + else: + assert str(self.dist_info_dir).endswith(".dist-info") + assert Path(self.dist_info_dir, "METADATA").exists() + + def _install_namespaces(self, installation_dir, pth_prefix): + # XXX: Only required to support the deprecated namespace practice + dist = self.distribution + if not dist.namespace_packages: + return + + src_root = Path(self.project_dir, self.package_dir.get("", ".")).resolve() + installer = _NamespaceInstaller(dist, installation_dir, pth_prefix, src_root) + installer.install_namespaces() + + def _find_egg_info_dir(self) -> Optional[str]: + parent_dir = Path(self.dist_info_dir).parent if self.dist_info_dir else Path() + candidates = map(str, parent_dir.glob("*.egg-info")) + return next(candidates, None) + + def _configure_build( + self, name: str, unpacked_wheel: _Path, build_lib: _Path, tmp_dir: _Path + ): + """Configure commands to behave in the following ways: + + - Build commands can write to ``build_lib`` if they really want to... + (but this folder is expected to be ignored and modules are expected to live + in the project directory...) + - Binary extensions should be built in-place (editable_mode = True) + - Data/header/script files are not part of the "editable" specification + so they are written directly to the unpacked_wheel directory. + """ + # Non-editable files (data, headers, scripts) are written directly to the + # unpacked_wheel + + dist = self.distribution + wheel = str(unpacked_wheel) + build_lib = str(build_lib) + data = str(Path(unpacked_wheel, f"{name}.data", "data")) + headers = str(Path(unpacked_wheel, f"{name}.data", "headers")) + scripts = str(Path(unpacked_wheel, f"{name}.data", "scripts")) + + # egg-info may be generated again to create a manifest (used for package data) + egg_info = dist.reinitialize_command("egg_info", reinit_subcommands=True) + egg_info.egg_base = str(tmp_dir) + egg_info.ignore_egg_info_in_manifest = True + + build = dist.reinitialize_command("build", reinit_subcommands=True) + install = dist.reinitialize_command("install", reinit_subcommands=True) + + build.build_platlib = build.build_purelib = build.build_lib = build_lib + install.install_purelib = install.install_platlib = install.install_lib = wheel + install.install_scripts = build.build_scripts = scripts + install.install_headers = headers + install.install_data = data + + install_scripts = dist.get_command_obj("install_scripts") + install_scripts.no_ep = True + + build.build_temp = str(tmp_dir) + + build_py = dist.get_command_obj("build_py") + build_py.compile = False + build_py.existing_egg_info_dir = self._find_egg_info_dir() + + self._set_editable_mode() + + build.ensure_finalized() + install.ensure_finalized() + + def _set_editable_mode(self): + """Set the ``editable_mode`` flag in the build sub-commands""" + dist = self.distribution + build = dist.get_command_obj("build") + for cmd_name in build.get_sub_commands(): + cmd = dist.get_command_obj(cmd_name) + if hasattr(cmd, "editable_mode"): + cmd.editable_mode = True + elif hasattr(cmd, "inplace"): + cmd.inplace = True # backward compatibility with distutils + + def _collect_build_outputs(self) -> Tuple[List[str], Dict[str, str]]: + files: List[str] = [] + mapping: Dict[str, str] = {} + build = self.get_finalized_command("build") + + for cmd_name in build.get_sub_commands(): + cmd = self.get_finalized_command(cmd_name) + if hasattr(cmd, "get_outputs"): + files.extend(cmd.get_outputs() or []) + if hasattr(cmd, "get_output_mapping"): + mapping.update(cmd.get_output_mapping() or {}) + + return files, mapping + + def _run_build_commands( + self, dist_name: str, unpacked_wheel: _Path, build_lib: _Path, tmp_dir: _Path + ) -> Tuple[List[str], Dict[str, str]]: + self._configure_build(dist_name, unpacked_wheel, build_lib, tmp_dir) + self._run_build_subcommands() + files, mapping = self._collect_build_outputs() + self._run_install("headers") + self._run_install("scripts") + self._run_install("data") + return files, mapping + + def _run_build_subcommands(self): + """ + Issue #3501 indicates that some plugins/customizations might rely on: + + 1. ``build_py`` not running + 2. ``build_py`` always copying files to ``build_lib`` + + However both these assumptions may be false in editable_wheel. + This method implements a temporary workaround to support the ecosystem + while the implementations catch up. + """ + # TODO: Once plugins/customisations had the chance to catch up, replace + # `self._run_build_subcommands()` with `self.run_command("build")`. + # Also remove _safely_run, TestCustomBuildPy. Suggested date: Aug/2023. + build: Command = self.get_finalized_command("build") + for name in build.get_sub_commands(): + cmd = self.get_finalized_command(name) + if name == "build_py" and type(cmd) != build_py_cls: + self._safely_run(name) + else: + self.run_command(name) + + def _safely_run(self, cmd_name: str): + try: + return self.run_command(cmd_name) + except Exception: + msg = f"""{traceback.format_exc()}\n + If you are seeing this warning it is very likely that a setuptools + plugin or customization overrides the `{cmd_name}` command, without + taking into consideration how editable installs run build steps + starting from v64.0.0. + + Plugin authors and developers relying on custom build steps are encouraged + to update their `{cmd_name}` implementation considering the information in + https://setuptools.pypa.io/en/latest/userguide/extension.html + about editable installs. + + For the time being `setuptools` will silence this error and ignore + the faulty command, but this behaviour will change in future versions.\n + """ + warnings.warn(msg, SetuptoolsDeprecationWarning, stacklevel=2) + + def _create_wheel_file(self, bdist_wheel): + from wheel.wheelfile import WheelFile + + dist_info = self.get_finalized_command("dist_info") + dist_name = dist_info.name + tag = "-".join(bdist_wheel.get_tag()) + build_tag = "0.editable" # According to PEP 427 needs to start with digit + archive_name = f"{dist_name}-{build_tag}-{tag}.whl" + wheel_path = Path(self.dist_dir, archive_name) + if wheel_path.exists(): + wheel_path.unlink() + + unpacked_wheel = TemporaryDirectory(suffix=archive_name) + build_lib = TemporaryDirectory(suffix=".build-lib") + build_tmp = TemporaryDirectory(suffix=".build-temp") + + with unpacked_wheel as unpacked, build_lib as lib, build_tmp as tmp: + unpacked_dist_info = Path(unpacked, Path(self.dist_info_dir).name) + shutil.copytree(self.dist_info_dir, unpacked_dist_info) + self._install_namespaces(unpacked, dist_info.name) + files, mapping = self._run_build_commands(dist_name, unpacked, lib, tmp) + strategy = self._select_strategy(dist_name, tag, lib) + with strategy, WheelFile(wheel_path, "w") as wheel_obj: + strategy(wheel_obj, files, mapping) + wheel_obj.write_files(unpacked) + + return wheel_path + + def _run_install(self, category: str): + has_category = getattr(self.distribution, f"has_{category}", None) + if has_category and has_category(): + _logger.info(f"Installing {category} as non editable") + self.run_command(f"install_{category}") + + def _select_strategy( + self, + name: str, + tag: str, + build_lib: _Path, + ) -> "EditableStrategy": + """Decides which strategy to use to implement an editable installation.""" + build_name = f"__editable__.{name}-{tag}" + project_dir = Path(self.project_dir) + mode = _EditableMode.convert(self.mode) + + if mode is _EditableMode.STRICT: + auxiliary_dir = _empty_dir(Path(self.project_dir, "build", build_name)) + return _LinkTree(self.distribution, name, auxiliary_dir, build_lib) + + packages = _find_packages(self.distribution) + has_simple_layout = _simple_layout(packages, self.package_dir, project_dir) + is_compat_mode = mode is _EditableMode.COMPAT + if set(self.package_dir) == {""} and has_simple_layout or is_compat_mode: + # src-layout(ish) is relatively safe for a simple pth file + src_dir = self.package_dir.get("", ".") + return _StaticPth(self.distribution, name, [Path(project_dir, src_dir)]) + + # Use a MetaPathFinder to avoid adding accidental top-level packages/modules + return _TopLevelFinder(self.distribution, name) + + +class EditableStrategy(Protocol): + def __call__(self, wheel: "WheelFile", files: List[str], mapping: Dict[str, str]): + ... + + def __enter__(self): + ... + + def __exit__(self, _exc_type, _exc_value, _traceback): + ... + + +class _StaticPth: + def __init__(self, dist: Distribution, name: str, path_entries: List[Path]): + self.dist = dist + self.name = name + self.path_entries = path_entries + + def __call__(self, wheel: "WheelFile", files: List[str], mapping: Dict[str, str]): + entries = "\n".join((str(p.resolve()) for p in self.path_entries)) + contents = bytes(f"{entries}\n", "utf-8") + wheel.writestr(f"__editable__.{self.name}.pth", contents) + + def __enter__(self): + msg = f""" + Editable install will be performed using .pth file to extend `sys.path` with: + {list(map(os.fspath, self.path_entries))!r} + """ + _logger.warning(msg + _LENIENT_WARNING) + return self + + def __exit__(self, _exc_type, _exc_value, _traceback): + ... + + +class _LinkTree(_StaticPth): + """ + Creates a ``.pth`` file that points to a link tree in the ``auxiliary_dir``. + + This strategy will only link files (not dirs), so it can be implemented in + any OS, even if that means using hardlinks instead of symlinks. + + By collocating ``auxiliary_dir`` and the original source code, limitations + with hardlinks should be avoided. + """ + def __init__( + self, dist: Distribution, + name: str, + auxiliary_dir: _Path, + build_lib: _Path, + ): + self.auxiliary_dir = Path(auxiliary_dir) + self.build_lib = Path(build_lib).resolve() + self._file = dist.get_command_obj("build_py").copy_file + super().__init__(dist, name, [self.auxiliary_dir]) + + def __call__(self, wheel: "WheelFile", files: List[str], mapping: Dict[str, str]): + self._create_links(files, mapping) + super().__call__(wheel, files, mapping) + + def _normalize_output(self, file: str) -> Optional[str]: + # Files relative to build_lib will be normalized to None + with suppress(ValueError): + path = Path(file).resolve().relative_to(self.build_lib) + return str(path).replace(os.sep, '/') + return None + + def _create_file(self, relative_output: str, src_file: str, link=None): + dest = self.auxiliary_dir / relative_output + if not dest.parent.is_dir(): + dest.parent.mkdir(parents=True) + self._file(src_file, dest, link=link) + + def _create_links(self, outputs, output_mapping): + self.auxiliary_dir.mkdir(parents=True, exist_ok=True) + link_type = "sym" if _can_symlink_files(self.auxiliary_dir) else "hard" + mappings = { + self._normalize_output(k): v + for k, v in output_mapping.items() + } + mappings.pop(None, None) # remove files that are not relative to build_lib + + for output in outputs: + relative = self._normalize_output(output) + if relative and relative not in mappings: + self._create_file(relative, output) + + for relative, src in mappings.items(): + self._create_file(relative, src, link=link_type) + + def __enter__(self): + msg = "Strict editable install will be performed using a link tree.\n" + _logger.warning(msg + _STRICT_WARNING) + return self + + def __exit__(self, _exc_type, _exc_value, _traceback): + msg = f"""\n + Strict editable installation performed using the auxiliary directory: + {self.auxiliary_dir} + + Please be careful to not remove this directory, otherwise you might not be able + to import/use your package. + """ + warnings.warn(msg, InformationOnly) + + +class _TopLevelFinder: + def __init__(self, dist: Distribution, name: str): + self.dist = dist + self.name = name + + def __call__(self, wheel: "WheelFile", files: List[str], mapping: Dict[str, str]): + src_root = self.dist.src_root or os.curdir + top_level = chain(_find_packages(self.dist), _find_top_level_modules(self.dist)) + package_dir = self.dist.package_dir or {} + roots = _find_package_roots(top_level, package_dir, src_root) + + namespaces_: Dict[str, List[str]] = dict(chain( + _find_namespaces(self.dist.packages or [], roots), + ((ns, []) for ns in _find_virtual_namespaces(roots)), + )) + + name = f"__editable__.{self.name}.finder" + finder = _make_identifier(name) + content = bytes(_finder_template(name, roots, namespaces_), "utf-8") + wheel.writestr(f"{finder}.py", content) + + content = bytes(f"import {finder}; {finder}.install()", "utf-8") + wheel.writestr(f"__editable__.{self.name}.pth", content) + + def __enter__(self): + msg = "Editable install will be performed using a meta path finder.\n" + _logger.warning(msg + _LENIENT_WARNING) + return self + + def __exit__(self, _exc_type, _exc_value, _traceback): + msg = """\n + Please be careful with folders in your working directory with the same + name as your package as they may take precedence during imports. + """ + warnings.warn(msg, InformationOnly) + + +def _can_symlink_files(base_dir: Path) -> bool: + with TemporaryDirectory(dir=str(base_dir.resolve())) as tmp: + path1, path2 = Path(tmp, "file1.txt"), Path(tmp, "file2.txt") + path1.write_text("file1", encoding="utf-8") + with suppress(AttributeError, NotImplementedError, OSError): + os.symlink(path1, path2) + if path2.is_symlink() and path2.read_text(encoding="utf-8") == "file1": + return True + + try: + os.link(path1, path2) # Ensure hard links can be created + except Exception as ex: + msg = ( + "File system does not seem to support either symlinks or hard links. " + "Strict editable installs require one of them to be supported." + ) + raise LinksNotSupported(msg) from ex + return False + + +def _simple_layout( + packages: Iterable[str], package_dir: Dict[str, str], project_dir: Path +) -> bool: + """Return ``True`` if: + - all packages are contained by the same parent directory, **and** + - all packages become importable if the parent directory is added to ``sys.path``. + + >>> _simple_layout(['a'], {"": "src"}, "/tmp/myproj") + True + >>> _simple_layout(['a', 'a.b'], {"": "src"}, "/tmp/myproj") + True + >>> _simple_layout(['a', 'a.b'], {}, "/tmp/myproj") + True + >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"": "src"}, "/tmp/myproj") + True + >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a": "a", "b": "b"}, ".") + True + >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a": "_a", "b": "_b"}, ".") + False + >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a": "_a"}, "/tmp/myproj") + False + >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a.a1.a2": "_a2"}, ".") + False + >>> _simple_layout(['a', 'a.b'], {"": "src", "a.b": "_ab"}, "/tmp/myproj") + False + >>> # Special cases, no packages yet: + >>> _simple_layout([], {"": "src"}, "/tmp/myproj") + True + >>> _simple_layout([], {"a": "_a", "": "src"}, "/tmp/myproj") + False + """ + layout = { + pkg: find_package_path(pkg, package_dir, project_dir) + for pkg in packages + } + if not layout: + return set(package_dir) in ({}, {""}) + parent = os.path.commonpath([_parent_path(k, v) for k, v in layout.items()]) + return all( + _normalize_path(Path(parent, *key.split('.'))) == _normalize_path(value) + for key, value in layout.items() + ) + + +def _parent_path(pkg, pkg_path): + """Infer the parent path containing a package, that if added to ``sys.path`` would + allow importing that package. + When ``pkg`` is directly mapped into a directory with a different name, return its + own path. + >>> _parent_path("a", "src/a") + 'src' + >>> _parent_path("b", "src/c") + 'src/c' + """ + parent = pkg_path[:-len(pkg)] if pkg_path.endswith(pkg) else pkg_path + return parent.rstrip("/" + os.sep) + + +def _find_packages(dist: Distribution) -> Iterator[str]: + yield from iter(dist.packages or []) + + py_modules = dist.py_modules or [] + nested_modules = [mod for mod in py_modules if "." in mod] + if dist.ext_package: + yield dist.ext_package + else: + ext_modules = dist.ext_modules or [] + nested_modules += [x.name for x in ext_modules if "." in x.name] + + for module in nested_modules: + package, _, _ = module.rpartition(".") + yield package + + +def _find_top_level_modules(dist: Distribution) -> Iterator[str]: + py_modules = dist.py_modules or [] + yield from (mod for mod in py_modules if "." not in mod) + + if not dist.ext_package: + ext_modules = dist.ext_modules or [] + yield from (x.name for x in ext_modules if "." not in x.name) + + +def _find_package_roots( + packages: Iterable[str], + package_dir: Mapping[str, str], + src_root: _Path, +) -> Dict[str, str]: + pkg_roots: Dict[str, str] = { + pkg: _absolute_root(find_package_path(pkg, package_dir, src_root)) + for pkg in sorted(packages) + } + + return _remove_nested(pkg_roots) + + +def _absolute_root(path: _Path) -> str: + """Works for packages and top-level modules""" + path_ = Path(path) + parent = path_.parent + + if path_.exists(): + return str(path_.resolve()) + else: + return str(parent.resolve() / path_.name) + + +def _find_virtual_namespaces(pkg_roots: Dict[str, str]) -> Iterator[str]: + """By carefully designing ``package_dir``, it is possible to implement the logical + structure of PEP 420 in a package without the corresponding directories. + + Moreover a parent package can be purposefully/accidentally skipped in the discovery + phase (e.g. ``find_packages(include=["mypkg.*"])``, when ``mypkg.foo`` is included + by ``mypkg`` itself is not). + We consider this case to also be a virtual namespace (ignoring the original + directory) to emulate a non-editable installation. + + This function will try to find these kinds of namespaces. + """ + for pkg in pkg_roots: + if "." not in pkg: + continue + parts = pkg.split(".") + for i in range(len(parts) - 1, 0, -1): + partial_name = ".".join(parts[:i]) + path = Path(find_package_path(partial_name, pkg_roots, "")) + if not path.exists() or partial_name not in pkg_roots: + # partial_name not in pkg_roots ==> purposefully/accidentally skipped + yield partial_name + + +def _find_namespaces( + packages: List[str], pkg_roots: Dict[str, str] +) -> Iterator[Tuple[str, List[str]]]: + for pkg in packages: + path = find_package_path(pkg, pkg_roots, "") + if Path(path).exists() and not Path(path, "__init__.py").exists(): + yield (pkg, [path]) + + +def _remove_nested(pkg_roots: Dict[str, str]) -> Dict[str, str]: + output = dict(pkg_roots.copy()) + + for pkg, path in reversed(list(pkg_roots.items())): + if any( + pkg != other and _is_nested(pkg, path, other, other_path) + for other, other_path in pkg_roots.items() + ): + output.pop(pkg) + + return output + + +def _is_nested(pkg: str, pkg_path: str, parent: str, parent_path: str) -> bool: + """ + Return ``True`` if ``pkg`` is nested inside ``parent`` both logically and in the + file system. + >>> _is_nested("a.b", "path/a/b", "a", "path/a") + True + >>> _is_nested("a.b", "path/a/b", "a", "otherpath/a") + False + >>> _is_nested("a.b", "path/a/b", "c", "path/c") + False + >>> _is_nested("a.a", "path/a/a", "a", "path/a") + True + >>> _is_nested("b.a", "path/b/a", "a", "path/a") + False + """ + norm_pkg_path = _normalize_path(pkg_path) + rest = pkg.replace(parent, "", 1).strip(".").split(".") + return ( + pkg.startswith(parent) + and norm_pkg_path == _normalize_path(Path(parent_path, *rest)) + ) + + +def _normalize_path(filename: _Path) -> str: + """Normalize a file/dir name for comparison purposes""" + # See pkg_resources.normalize_path + file = os.path.abspath(filename) if sys.platform == 'cygwin' else filename + return os.path.normcase(os.path.realpath(os.path.normpath(file))) + + +def _empty_dir(dir_: _P) -> _P: + """Create a directory ensured to be empty. Existing files may be removed.""" + shutil.rmtree(dir_, ignore_errors=True) + os.makedirs(dir_) + return dir_ + + +def _make_identifier(name: str) -> str: + """Make a string safe to be used as Python identifier. + >>> _make_identifier("12abc") + '_12abc' + >>> _make_identifier("__editable__.myns.pkg-78.9.3_local") + '__editable___myns_pkg_78_9_3_local' + """ + safe = re.sub(r'\W|^(?=\d)', '_', name) + assert safe.isidentifier() + return safe + + +class _NamespaceInstaller(namespaces.Installer): + def __init__(self, distribution, installation_dir, editable_name, src_root): + self.distribution = distribution + self.src_root = src_root + self.installation_dir = installation_dir + self.editable_name = editable_name + self.outputs = [] + self.dry_run = False + + def _get_target(self): + """Installation target.""" + return os.path.join(self.installation_dir, self.editable_name) + + def _get_root(self): + """Where the modules/packages should be loaded from.""" + return repr(str(self.src_root)) + + +_FINDER_TEMPLATE = """\ +import sys +from importlib.machinery import ModuleSpec +from importlib.machinery import all_suffixes as module_suffixes +from importlib.util import spec_from_file_location +from itertools import chain +from pathlib import Path + +MAPPING = {mapping!r} +NAMESPACES = {namespaces!r} +PATH_PLACEHOLDER = {name!r} + ".__path_hook__" + + +class _EditableFinder: # MetaPathFinder + @classmethod + def find_spec(cls, fullname, path=None, target=None): + for pkg, pkg_path in reversed(list(MAPPING.items())): + if fullname == pkg or fullname.startswith(f"{{pkg}}."): + rest = fullname.replace(pkg, "", 1).strip(".").split(".") + return cls._find_spec(fullname, Path(pkg_path, *rest)) + + return None + + @classmethod + def _find_spec(cls, fullname, candidate_path): + init = candidate_path / "__init__.py" + candidates = (candidate_path.with_suffix(x) for x in module_suffixes()) + for candidate in chain([init], candidates): + if candidate.exists(): + return spec_from_file_location(fullname, candidate) + + +class _EditableNamespaceFinder: # PathEntryFinder + @classmethod + def _path_hook(cls, path): + if path == PATH_PLACEHOLDER: + return cls + raise ImportError + + @classmethod + def _paths(cls, fullname): + # Ensure __path__ is not empty for the spec to be considered a namespace. + return NAMESPACES[fullname] or MAPPING.get(fullname) or [PATH_PLACEHOLDER] + + @classmethod + def find_spec(cls, fullname, target=None): + if fullname in NAMESPACES: + spec = ModuleSpec(fullname, None, is_package=True) + spec.submodule_search_locations = cls._paths(fullname) + return spec + return None + + @classmethod + def find_module(cls, fullname): + return None + + +def install(): + if not any(finder == _EditableFinder for finder in sys.meta_path): + sys.meta_path.append(_EditableFinder) + + if not NAMESPACES: + return + + if not any(hook == _EditableNamespaceFinder._path_hook for hook in sys.path_hooks): + # PathEntryFinder is needed to create NamespaceSpec without private APIS + sys.path_hooks.append(_EditableNamespaceFinder._path_hook) + if PATH_PLACEHOLDER not in sys.path: + sys.path.append(PATH_PLACEHOLDER) # Used just to trigger the path hook +""" + + +def _finder_template( + name: str, mapping: Mapping[str, str], namespaces: Dict[str, List[str]] +) -> str: + """Create a string containing the code for the``MetaPathFinder`` and + ``PathEntryFinder``. + """ + mapping = dict(sorted(mapping.items(), key=lambda p: p[0])) + return _FINDER_TEMPLATE.format(name=name, mapping=mapping, namespaces=namespaces) + + +class InformationOnly(UserWarning): + """Currently there is no clear way of displaying messages to the users + that use the setuptools backend directly via ``pip``. + The only thing that might work is a warning, although it is not the + most appropriate tool for the job... + """ + + +class LinksNotSupported(errors.FileError): + """File system does not seem to support either symlinks or hard links.""" diff --git a/venv/Lib/site-packages/setuptools/discovery.py b/venv/Lib/site-packages/setuptools/discovery.py new file mode 100644 index 0000000..6244a18 --- /dev/null +++ b/venv/Lib/site-packages/setuptools/discovery.py @@ -0,0 +1,601 @@ +"""Automatic discovery of Python modules and packages (for inclusion in the +distribution) and other config values. + +For the purposes of this module, the following nomenclature is used: + +- "src-layout": a directory representing a Python project that contains a "src" + folder. Everything under the "src" folder is meant to be included in the + distribution when packaging the project. Example:: + + . + ├── tox.ini + ├── pyproject.toml + └── src/ + └── mypkg/ + ├── __init__.py + ├── mymodule.py + └── my_data_file.txt + +- "flat-layout": a Python project that does not use "src-layout" but instead + have a directory under the project root for each package:: + + . + ├── tox.ini + ├── pyproject.toml + └── mypkg/ + ├── __init__.py + ├── mymodule.py + └── my_data_file.txt + +- "single-module": a project that contains a single Python script direct under + the project root (no directory used):: + + . + ├── tox.ini + ├── pyproject.toml + └── mymodule.py + +""" + +import itertools +import os +from fnmatch import fnmatchcase +from glob import glob +from pathlib import Path +from typing import ( + TYPE_CHECKING, + Callable, + Dict, + Iterable, + Iterator, + List, + Mapping, + Optional, + Tuple, + Union +) + +import _distutils_hack.override # noqa: F401 + +from distutils import log +from distutils.util import convert_path + +_Path = Union[str, os.PathLike] +_Filter = Callable[[str], bool] +StrIter = Iterator[str] + +chain_iter = itertools.chain.from_iterable + +if TYPE_CHECKING: + from setuptools import Distribution # noqa + + +def _valid_name(path: _Path) -> bool: + # Ignore invalid names that cannot be imported directly + return os.path.basename(path).isidentifier() + + +class _Finder: + """Base class that exposes functionality for module/package finders""" + + ALWAYS_EXCLUDE: Tuple[str, ...] = () + DEFAULT_EXCLUDE: Tuple[str, ...] = () + + @classmethod + def find( + cls, + where: _Path = '.', + exclude: Iterable[str] = (), + include: Iterable[str] = ('*',) + ) -> List[str]: + """Return a list of all Python items (packages or modules, depending on + the finder implementation) found within directory 'where'. + + 'where' is the root directory which will be searched. + It should be supplied as a "cross-platform" (i.e. URL-style) path; + it will be converted to the appropriate local path syntax. + + 'exclude' is a sequence of names to exclude; '*' can be used + as a wildcard in the names. + When finding packages, 'foo.*' will exclude all subpackages of 'foo' + (but not 'foo' itself). + + 'include' is a sequence of names to include. + If it's specified, only the named items will be included. + If it's not specified, all found items will be included. + 'include' can contain shell style wildcard patterns just like + 'exclude'. + """ + + exclude = exclude or cls.DEFAULT_EXCLUDE + return list( + cls._find_iter( + convert_path(str(where)), + cls._build_filter(*cls.ALWAYS_EXCLUDE, *exclude), + cls._build_filter(*include), + ) + ) + + @classmethod + def _find_iter(cls, where: _Path, exclude: _Filter, include: _Filter) -> StrIter: + raise NotImplementedError + + @staticmethod + def _build_filter(*patterns: str) -> _Filter: + """ + Given a list of patterns, return a callable that will be true only if + the input matches at least one of the patterns. + """ + return lambda name: any(fnmatchcase(name, pat) for pat in patterns) + + +class PackageFinder(_Finder): + """ + Generate a list of all Python packages found within a directory + """ + + ALWAYS_EXCLUDE = ("ez_setup", "*__pycache__") + + @classmethod + def _find_iter(cls, where: _Path, exclude: _Filter, include: _Filter) -> StrIter: + """ + All the packages found in 'where' that pass the 'include' filter, but + not the 'exclude' filter. + """ + for root, dirs, files in os.walk(str(where), followlinks=True): + # Copy dirs to iterate over it, then empty dirs. + all_dirs = dirs[:] + dirs[:] = [] + + for dir in all_dirs: + full_path = os.path.join(root, dir) + rel_path = os.path.relpath(full_path, where) + package = rel_path.replace(os.path.sep, '.') + + # Skip directory trees that are not valid packages + if '.' in dir or not cls._looks_like_package(full_path, package): + continue + + # Should this package be included? + if include(package) and not exclude(package): + yield package + + # Keep searching subdirectories, as there may be more packages + # down there, even if the parent was excluded. + dirs.append(dir) + + @staticmethod + def _looks_like_package(path: _Path, _package_name: str) -> bool: + """Does a directory look like a package?""" + return os.path.isfile(os.path.join(path, '__init__.py')) + + +class PEP420PackageFinder(PackageFinder): + @staticmethod + def _looks_like_package(_path: _Path, _package_name: str) -> bool: + return True + + +class ModuleFinder(_Finder): + """Find isolated Python modules. + This function will **not** recurse subdirectories. + """ + + @classmethod + def _find_iter(cls, where: _Path, exclude: _Filter, include: _Filter) -> StrIter: + for file in glob(os.path.join(where, "*.py")): + module, _ext = os.path.splitext(os.path.basename(file)) + + if not cls._looks_like_module(module): + continue + + if include(module) and not exclude(module): + yield module + + _looks_like_module = staticmethod(_valid_name) + + +# We have to be extra careful in the case of flat layout to not include files +# and directories not meant for distribution (e.g. tool-related) + + +class FlatLayoutPackageFinder(PEP420PackageFinder): + _EXCLUDE = ( + "ci", + "bin", + "doc", + "docs", + "documentation", + "manpages", + "news", + "changelog", + "test", + "tests", + "unit_test", + "unit_tests", + "example", + "examples", + "scripts", + "tools", + "util", + "utils", + "python", + "build", + "dist", + "venv", + "env", + "requirements", + # ---- Task runners / Build tools ---- + "tasks", # invoke + "fabfile", # fabric + "site_scons", # SCons + # ---- Other tools ---- + "benchmark", + "benchmarks", + "exercise", + "exercises", + # ---- Hidden directories/Private packages ---- + "[._]*", + ) + + DEFAULT_EXCLUDE = tuple(chain_iter((p, f"{p}.*") for p in _EXCLUDE)) + """Reserved package names""" + + @staticmethod + def _looks_like_package(_path: _Path, package_name: str) -> bool: + names = package_name.split('.') + # Consider PEP 561 + root_pkg_is_valid = names[0].isidentifier() or names[0].endswith("-stubs") + return root_pkg_is_valid and all(name.isidentifier() for name in names[1:]) + + +class FlatLayoutModuleFinder(ModuleFinder): + DEFAULT_EXCLUDE = ( + "setup", + "conftest", + "test", + "tests", + "example", + "examples", + "build", + # ---- Task runners ---- + "toxfile", + "noxfile", + "pavement", + "dodo", + "tasks", + "fabfile", + # ---- Other tools ---- + "[Ss][Cc]onstruct", # SCons + "conanfile", # Connan: C/C++ build tool + "manage", # Django + "benchmark", + "benchmarks", + "exercise", + "exercises", + "htmlcov", + # ---- Hidden files/Private modules ---- + "[._]*", + ) + """Reserved top-level module names""" + + +def _find_packages_within(root_pkg: str, pkg_dir: _Path) -> List[str]: + nested = PEP420PackageFinder.find(pkg_dir) + return [root_pkg] + [".".join((root_pkg, n)) for n in nested] + + +class ConfigDiscovery: + """Fill-in metadata and options that can be automatically derived + (from other metadata/options, the file system or conventions) + """ + + def __init__(self, distribution: "Distribution"): + self.dist = distribution + self._called = False + self._disabled = False + self._skip_ext_modules = False + + def _disable(self): + """Internal API to disable automatic discovery""" + self._disabled = True + + def _ignore_ext_modules(self): + """Internal API to disregard ext_modules. + + Normally auto-discovery would not be triggered if ``ext_modules`` are set + (this is done for backward compatibility with existing packages relying on + ``setup.py`` or ``setup.cfg``). However, ``setuptools`` can call this function + to ignore given ``ext_modules`` and proceed with the auto-discovery if + ``packages`` and ``py_modules`` are not given (e.g. when using pyproject.toml + metadata). + """ + self._skip_ext_modules = True + + @property + def _root_dir(self) -> _Path: + # The best is to wait until `src_root` is set in dist, before using _root_dir. + return self.dist.src_root or os.curdir + + @property + def _package_dir(self) -> Dict[str, str]: + if self.dist.package_dir is None: + return {} + return self.dist.package_dir + + def __call__(self, force=False, name=True, ignore_ext_modules=False): + """Automatically discover missing configuration fields + and modifies the given ``distribution`` object in-place. + + Note that by default this will only have an effect the first time the + ``ConfigDiscovery`` object is called. + + To repeatedly invoke automatic discovery (e.g. when the project + directory changes), please use ``force=True`` (or create a new + ``ConfigDiscovery`` instance). + """ + if force is False and (self._called or self._disabled): + # Avoid overhead of multiple calls + return + + self._analyse_package_layout(ignore_ext_modules) + if name: + self.analyse_name() # depends on ``packages`` and ``py_modules`` + + self._called = True + + def _explicitly_specified(self, ignore_ext_modules: bool) -> bool: + """``True`` if the user has specified some form of package/module listing""" + ignore_ext_modules = ignore_ext_modules or self._skip_ext_modules + ext_modules = not (self.dist.ext_modules is None or ignore_ext_modules) + return ( + self.dist.packages is not None + or self.dist.py_modules is not None + or ext_modules + or hasattr(self.dist, "configuration") and self.dist.configuration + # ^ Some projects use numpy.distutils.misc_util.Configuration + ) + + def _analyse_package_layout(self, ignore_ext_modules: bool) -> bool: + if self._explicitly_specified(ignore_ext_modules): + # For backward compatibility, just try to find modules/packages + # when nothing is given + return True + + log.debug( + "No `packages` or `py_modules` configuration, performing " + "automatic discovery." + ) + + return ( + self._analyse_explicit_layout() + or self._analyse_src_layout() + # flat-layout is the trickiest for discovery so it should be last + or self._analyse_flat_layout() + ) + + def _analyse_explicit_layout(self) -> bool: + """The user can explicitly give a package layout via ``package_dir``""" + package_dir = self._package_dir.copy() # don't modify directly + package_dir.pop("", None) # This falls under the "src-layout" umbrella + root_dir = self._root_dir + + if not package_dir: + return False + + log.debug(f"`explicit-layout` detected -- analysing {package_dir}") + pkgs = chain_iter( + _find_packages_within(pkg, os.path.join(root_dir, parent_dir)) + for pkg, parent_dir in package_dir.items() + ) + self.dist.packages = list(pkgs) + log.debug(f"discovered packages -- {self.dist.packages}") + return True + + def _analyse_src_layout(self) -> bool: + """Try to find all packages or modules under the ``src`` directory + (or anything pointed by ``package_dir[""]``). + + The "src-layout" is relatively safe for automatic discovery. + We assume that everything within is meant to be included in the + distribution. + + If ``package_dir[""]`` is not given, but the ``src`` directory exists, + this function will set ``package_dir[""] = "src"``. + """ + package_dir = self._package_dir + src_dir = os.path.join(self._root_dir, package_dir.get("", "src")) + if not os.path.isdir(src_dir): + return False + + log.debug(f"`src-layout` detected -- analysing {src_dir}") + package_dir.setdefault("", os.path.basename(src_dir)) + self.dist.package_dir = package_dir # persist eventual modifications + self.dist.packages = PEP420PackageFinder.find(src_dir) + self.dist.py_modules = ModuleFinder.find(src_dir) + log.debug(f"discovered packages -- {self.dist.packages}") + log.debug(f"discovered py_modules -- {self.dist.py_modules}") + return True + + def _analyse_flat_layout(self) -> bool: + """Try to find all packages and modules under the project root. + + Since the ``flat-layout`` is more dangerous in terms of accidentally including + extra files/directories, this function is more conservative and will raise an + error if multiple packages or modules are found. + + This assumes that multi-package dists are uncommon and refuse to support that + use case in order to be able to prevent unintended errors. + """ + log.debug(f"`flat-layout` detected -- analysing {self._root_dir}") + return self._analyse_flat_packages() or self._analyse_flat_modules() + + def _analyse_flat_packages(self) -> bool: + self.dist.packages = FlatLayoutPackageFinder.find(self._root_dir) + top_level = remove_nested_packages(remove_stubs(self.dist.packages)) + log.debug(f"discovered packages -- {self.dist.packages}") + self._ensure_no_accidental_inclusion(top_level, "packages") + return bool(top_level) + + def _analyse_flat_modules(self) -> bool: + self.dist.py_modules = FlatLayoutModuleFinder.find(self._root_dir) + log.debug(f"discovered py_modules -- {self.dist.py_modules}") + self._ensure_no_accidental_inclusion(self.dist.py_modules, "modules") + return bool(self.dist.py_modules) + + def _ensure_no_accidental_inclusion(self, detected: List[str], kind: str): + if len(detected) > 1: + from inspect import cleandoc + + from setuptools.errors import PackageDiscoveryError + + msg = f"""Multiple top-level {kind} discovered in a flat-layout: {detected}. + + To avoid accidental inclusion of unwanted files or directories, + setuptools will not proceed with this build. + + If you are trying to create a single distribution with multiple {kind} + on purpose, you should not rely on automatic discovery. + Instead, consider the following options: + + 1. set up custom discovery (`find` directive with `include` or `exclude`) + 2. use a `src-layout` + 3. explicitly set `py_modules` or `packages` with a list of names + + To find more information, look for "package discovery" on setuptools docs. + """ + raise PackageDiscoveryError(cleandoc(msg)) + + def analyse_name(self): + """The packages/modules are the essential contribution of the author. + Therefore the name of the distribution can be derived from them. + """ + if self.dist.metadata.name or self.dist.name: + # get_name() is not reliable (can return "UNKNOWN") + return None + + log.debug("No `name` configuration, performing automatic discovery") + + name = ( + self._find_name_single_package_or_module() + or self._find_name_from_packages() + ) + if name: + self.dist.metadata.name = name + + def _find_name_single_package_or_module(self) -> Optional[str]: + """Exactly one module or package""" + for field in ('packages', 'py_modules'): + items = getattr(self.dist, field, None) or [] + if items and len(items) == 1: + log.debug(f"Single module/package detected, name: {items[0]}") + return items[0] + + return None + + def _find_name_from_packages(self) -> Optional[str]: + """Try to find the root package that is not a PEP 420 namespace""" + if not self.dist.packages: + return None + + packages = remove_stubs(sorted(self.dist.packages, key=len)) + package_dir = self.dist.package_dir or {} + + parent_pkg = find_parent_package(packages, package_dir, self._root_dir) + if parent_pkg: + log.debug(f"Common parent package detected, name: {parent_pkg}") + return parent_pkg + + log.warn("No parent package detected, impossible to derive `name`") + return None + + +def remove_nested_packages(packages: List[str]) -> List[str]: + """Remove nested packages from a list of packages. + + >>> remove_nested_packages(["a", "a.b1", "a.b2", "a.b1.c1"]) + ['a'] + >>> remove_nested_packages(["a", "b", "c.d", "c.d.e.f", "g.h", "a.a1"]) + ['a', 'b', 'c.d', 'g.h'] + """ + pkgs = sorted(packages, key=len) + top_level = pkgs[:] + size = len(pkgs) + for i, name in enumerate(reversed(pkgs)): + if any(name.startswith(f"{other}.") for other in top_level): + top_level.pop(size - i - 1) + + return top_level + + +def remove_stubs(packages: List[str]) -> List[str]: + """Remove type stubs (:pep:`561`) from a list of packages. + + >>> remove_stubs(["a", "a.b", "a-stubs", "a-stubs.b.c", "b", "c-stubs"]) + ['a', 'a.b', 'b'] + """ + return [pkg for pkg in packages if not pkg.split(".")[0].endswith("-stubs")] + + +def find_parent_package( + packages: List[str], package_dir: Mapping[str, str], root_dir: _Path +) -> Optional[str]: + """Find the parent package that is not a namespace.""" + packages = sorted(packages, key=len) + common_ancestors = [] + for i, name in enumerate(packages): + if not all(n.startswith(f"{name}.") for n in packages[i+1:]): + # Since packages are sorted by length, this condition is able + # to find a list of all common ancestors. + # When there is divergence (e.g. multiple root packages) + # the list will be empty + break + common_ancestors.append(name) + + for name in common_ancestors: + pkg_path = find_package_path(name, package_dir, root_dir) + init = os.path.join(pkg_path, "__init__.py") + if os.path.isfile(init): + return name + + return None + + +def find_package_path( + name: str, package_dir: Mapping[str, str], root_dir: _Path +) -> str: + """Given a package name, return the path where it should be found on + disk, considering the ``package_dir`` option. + + >>> path = find_package_path("my.pkg", {"": "root/is/nested"}, ".") + >>> path.replace(os.sep, "/") + './root/is/nested/my/pkg' + + >>> path = find_package_path("my.pkg", {"my": "root/is/nested"}, ".") + >>> path.replace(os.sep, "/") + './root/is/nested/pkg' + + >>> path = find_package_path("my.pkg", {"my.pkg": "root/is/nested"}, ".") + >>> path.replace(os.sep, "/") + './root/is/nested' + + >>> path = find_package_path("other.pkg", {"my.pkg": "root/is/nested"}, ".") + >>> path.replace(os.sep, "/") + './other/pkg' + """ + parts = name.split(".") + for i in range(len(parts), 0, -1): + # Look backwards, the most specific package_dir first + partial_name = ".".join(parts[:i]) + if partial_name in package_dir: + parent = package_dir[partial_name] + return os.path.join(root_dir, parent, *parts[i:]) + + parent = package_dir.get("") or "" + return os.path.join(root_dir, *parent.split("/"), *parts) + + +def construct_package_dir(packages: List[str], package_path: _Path) -> Dict[str, str]: + parent_pkgs = remove_nested_packages(packages) + prefix = Path(package_path).parts + return {pkg: "/".join([*prefix, *pkg.split(".")]) for pkg in parent_pkgs} diff --git a/venv/Lib/site-packages/setuptools/gui-arm64.exe b/venv/Lib/site-packages/setuptools/gui-arm64.exe new file mode 100644 index 0000000..5730f11 Binary files /dev/null and b/venv/Lib/site-packages/setuptools/gui-arm64.exe differ diff --git a/venv/Lib/site-packages/setuptools/logging.py b/venv/Lib/site-packages/setuptools/logging.py new file mode 100644 index 0000000..0653878 --- /dev/null +++ b/venv/Lib/site-packages/setuptools/logging.py @@ -0,0 +1,37 @@ +import sys +import inspect +import logging +import distutils.log +from . import monkey + + +def _not_warning(record): + return record.levelno < logging.WARNING + + +def configure(): + """ + Configure logging to emit warning and above to stderr + and everything else to stdout. This behavior is provided + for compatibility with distutils.log but may change in + the future. + """ + err_handler = logging.StreamHandler() + err_handler.setLevel(logging.WARNING) + out_handler = logging.StreamHandler(sys.stdout) + out_handler.addFilter(_not_warning) + handlers = err_handler, out_handler + logging.basicConfig( + format="{message}", style='{', handlers=handlers, level=logging.DEBUG) + if inspect.ismodule(distutils.dist.log): + monkey.patch_func(set_threshold, distutils.log, 'set_threshold') + # For some reason `distutils.log` module is getting cached in `distutils.dist` + # and then loaded again when patched, + # implying: id(distutils.log) != id(distutils.dist.log). + # Make sure the same module object is used everywhere: + distutils.dist.log = distutils.log + + +def set_threshold(level): + logging.root.setLevel(level*10) + return set_threshold.unpatched(level) diff --git a/venv/Lib/site-packages/toml-0.10.2.dist-info/INSTALLER b/venv/Lib/site-packages/toml-0.10.2.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/toml-0.10.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/toml-0.10.2.dist-info/LICENSE b/venv/Lib/site-packages/toml-0.10.2.dist-info/LICENSE new file mode 100644 index 0000000..5010e30 --- /dev/null +++ b/venv/Lib/site-packages/toml-0.10.2.dist-info/LICENSE @@ -0,0 +1,27 @@ +The MIT License + +Copyright 2013-2019 William Pearson +Copyright 2015-2016 Julien Enselme +Copyright 2016 Google Inc. +Copyright 2017 Samuel Vasko +Copyright 2017 Nate Prewitt +Copyright 2017 Jack Evans +Copyright 2019 Filippo Broggini + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/venv/Lib/site-packages/toml-0.10.2.dist-info/METADATA b/venv/Lib/site-packages/toml-0.10.2.dist-info/METADATA new file mode 100644 index 0000000..6f2635c --- /dev/null +++ b/venv/Lib/site-packages/toml-0.10.2.dist-info/METADATA @@ -0,0 +1,255 @@ +Metadata-Version: 2.1 +Name: toml +Version: 0.10.2 +Summary: Python Library for Tom's Obvious, Minimal Language +Home-page: https://github.com/uiri/toml +Author: William Pearson +Author-email: uiri@xqz.ca +License: MIT +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Requires-Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.* + +**** +TOML +**** + +.. image:: https://img.shields.io/pypi/v/toml + :target: https://pypi.org/project/toml/ + +.. image:: https://travis-ci.org/uiri/toml.svg?branch=master + :target: https://travis-ci.org/uiri/toml + +.. image:: https://img.shields.io/pypi/pyversions/toml.svg + :target: https://pypi.org/project/toml/ + + +A Python library for parsing and creating `TOML `_. + +The module passes `the TOML test suite `_. + +See also: + +* `The TOML Standard `_ +* `The currently supported TOML specification `_ + +Installation +============ + +To install the latest release on `PyPI `_, +simply run: + +:: + + pip install toml + +Or to install the latest development version, run: + +:: + + git clone https://github.com/uiri/toml.git + cd toml + python setup.py install + +Quick Tutorial +============== + +*toml.loads* takes in a string containing standard TOML-formatted data and +returns a dictionary containing the parsed data. + +.. code:: pycon + + >>> import toml + >>> toml_string = """ + ... # This is a TOML document. + ... + ... title = "TOML Example" + ... + ... [owner] + ... name = "Tom Preston-Werner" + ... dob = 1979-05-27T07:32:00-08:00 # First class dates + ... + ... [database] + ... server = "192.168.1.1" + ... ports = [ 8001, 8001, 8002 ] + ... connection_max = 5000 + ... enabled = true + ... + ... [servers] + ... + ... # Indentation (tabs and/or spaces) is allowed but not required + ... [servers.alpha] + ... ip = "10.0.0.1" + ... dc = "eqdc10" + ... + ... [servers.beta] + ... ip = "10.0.0.2" + ... dc = "eqdc10" + ... + ... [clients] + ... data = [ ["gamma", "delta"], [1, 2] ] + ... + ... # Line breaks are OK when inside arrays + ... hosts = [ + ... "alpha", + ... "omega" + ... ] + ... """ + >>> parsed_toml = toml.loads(toml_string) + + +*toml.dumps* takes a dictionary and returns a string containing the +corresponding TOML-formatted data. + +.. code:: pycon + + >>> new_toml_string = toml.dumps(parsed_toml) + >>> print(new_toml_string) + title = "TOML Example" + [owner] + name = "Tom Preston-Werner" + dob = 1979-05-27T07:32:00Z + [database] + server = "192.168.1.1" + ports = [ 8001, 8001, 8002,] + connection_max = 5000 + enabled = true + [clients] + data = [ [ "gamma", "delta",], [ 1, 2,],] + hosts = [ "alpha", "omega",] + [servers.alpha] + ip = "10.0.0.1" + dc = "eqdc10" + [servers.beta] + ip = "10.0.0.2" + dc = "eqdc10" + +*toml.dump* takes a dictionary and a file descriptor and returns a string containing the +corresponding TOML-formatted data. + +.. code:: pycon + + >>> with open('new_toml_file.toml', 'w') as f: + ... new_toml_string = toml.dump(parsed_toml, f) + >>> print(new_toml_string) + title = "TOML Example" + [owner] + name = "Tom Preston-Werner" + dob = 1979-05-27T07:32:00Z + [database] + server = "192.168.1.1" + ports = [ 8001, 8001, 8002,] + connection_max = 5000 + enabled = true + [clients] + data = [ [ "gamma", "delta",], [ 1, 2,],] + hosts = [ "alpha", "omega",] + [servers.alpha] + ip = "10.0.0.1" + dc = "eqdc10" + [servers.beta] + ip = "10.0.0.2" + dc = "eqdc10" + +For more functions, view the API Reference below. + +Note +---- + +For Numpy users, by default the data types ``np.floatX`` will not be translated to floats by toml, but will instead be encoded as strings. To get around this, specify the ``TomlNumpyEncoder`` when saving your data. + +.. code:: pycon + + >>> import toml + >>> import numpy as np + >>> a = np.arange(0, 10, dtype=np.double) + >>> output = {'a': a} + >>> toml.dumps(output) + 'a = [ "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "6.0", "7.0", "8.0", "9.0",]\n' + >>> toml.dumps(output, encoder=toml.TomlNumpyEncoder()) + 'a = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0,]\n' + +API Reference +============= + +``toml.load(f, _dict=dict)`` + Parse a file or a list of files as TOML and return a dictionary. + + :Args: + * ``f``: A path to a file, list of filepaths (to be read into single + object) or a file descriptor + * ``_dict``: The class of the dictionary object to be returned + + :Returns: + A dictionary (or object ``_dict``) containing parsed TOML data + + :Raises: + * ``TypeError``: When ``f`` is an invalid type or is a list containing + invalid types + * ``TomlDecodeError``: When an error occurs while decoding the file(s) + +``toml.loads(s, _dict=dict)`` + Parse a TOML-formatted string to a dictionary. + + :Args: + * ``s``: The TOML-formatted string to be parsed + * ``_dict``: Specifies the class of the returned toml dictionary + + :Returns: + A dictionary (or object ``_dict``) containing parsed TOML data + + :Raises: + * ``TypeError``: When a non-string object is passed + * ``TomlDecodeError``: When an error occurs while decoding the + TOML-formatted string + +``toml.dump(o, f, encoder=None)`` + Write a dictionary to a file containing TOML-formatted data + + :Args: + * ``o``: An object to be converted into TOML + * ``f``: A File descriptor where the TOML-formatted output should be stored + * ``encoder``: An instance of ``TomlEncoder`` (or subclass) for encoding the object. If ``None``, will default to ``TomlEncoder`` + + :Returns: + A string containing the TOML-formatted data corresponding to object ``o`` + + :Raises: + * ``TypeError``: When anything other than file descriptor is passed + +``toml.dumps(o, encoder=None)`` + Create a TOML-formatted string from an input object + + :Args: + * ``o``: An object to be converted into TOML + * ``encoder``: An instance of ``TomlEncoder`` (or subclass) for encoding the object. If ``None``, will default to ``TomlEncoder`` + + :Returns: + A string containing the TOML-formatted data corresponding to object ``o`` + + + +Licensing +========= + +This project is released under the terms of the MIT Open Source License. View +*LICENSE.txt* for more information. + + diff --git a/venv/Lib/site-packages/toml-0.10.2.dist-info/RECORD b/venv/Lib/site-packages/toml-0.10.2.dist-info/RECORD new file mode 100644 index 0000000..0c8a864 --- /dev/null +++ b/venv/Lib/site-packages/toml-0.10.2.dist-info/RECORD @@ -0,0 +1,16 @@ +toml-0.10.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +toml-0.10.2.dist-info/LICENSE,sha256=LZKUgj32yJNXyL5JJ_znk2HWVh5e51MtWSbmOTmqpTY,1252 +toml-0.10.2.dist-info/METADATA,sha256=n_YkspvEihd_QXLIZZ50WVSFz3rZ_k7jQP-OU1WUpWY,7142 +toml-0.10.2.dist-info/RECORD,, +toml-0.10.2.dist-info/WHEEL,sha256=ADKeyaGyKF5DwBNE0sRE5pvW-bSkFMJfBuhzZ3rceP4,110 +toml-0.10.2.dist-info/top_level.txt,sha256=2BO8ZRNnvJWgXyiQv66LBb_v87qBzcoUtEBefA75Ouk,5 +toml/__init__.py,sha256=Au3kqCwKD0cjbf4yJGOpUFwpsY0WHsC1ZRGvWgIKmpc,723 +toml/__pycache__/__init__.cpython-39.pyc,, +toml/__pycache__/decoder.cpython-39.pyc,, +toml/__pycache__/encoder.cpython-39.pyc,, +toml/__pycache__/ordered.cpython-39.pyc,, +toml/__pycache__/tz.cpython-39.pyc,, +toml/decoder.py,sha256=hSGTLf-2WBDZ_ddoCHWFy6N647XyMSh1o3rN2o4dEFg,38942 +toml/encoder.py,sha256=XjBc8ayvvlsLyd_qDA4tMWDNmMFRS4DpwtuDSWBq7zo,9940 +toml/ordered.py,sha256=mz03lZmV0bmc9lsYRIUOuj7Dsu5Ptwq-UtGVq5FdVZ4,354 +toml/tz.py,sha256=-5vg8wkg_atnVi2TnEveexIVE7T_FxBVr_-2WVfO1oA,701 diff --git a/venv/Lib/site-packages/toml-0.10.2.dist-info/WHEEL b/venv/Lib/site-packages/toml-0.10.2.dist-info/WHEEL new file mode 100644 index 0000000..6d38aa0 --- /dev/null +++ b/venv/Lib/site-packages/toml-0.10.2.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.35.1) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/toml-0.10.2.dist-info/top_level.txt b/venv/Lib/site-packages/toml-0.10.2.dist-info/top_level.txt new file mode 100644 index 0000000..bd79a65 --- /dev/null +++ b/venv/Lib/site-packages/toml-0.10.2.dist-info/top_level.txt @@ -0,0 +1 @@ +toml diff --git a/venv/Lib/site-packages/typed_ast-1.4.3.dist-info/INSTALLER b/venv/Lib/site-packages/typed_ast-1.4.3.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/typed_ast-1.4.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/typed_ast-1.4.3.dist-info/LICENSE b/venv/Lib/site-packages/typed_ast-1.4.3.dist-info/LICENSE new file mode 100644 index 0000000..2565558 --- /dev/null +++ b/venv/Lib/site-packages/typed_ast-1.4.3.dist-info/LICENSE @@ -0,0 +1,290 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: typed-ast +Source: https://pypi.python.org/pypi/typed-ast + +Files: * +Copyright: © 2016 David Fisher +License: Apache-2.0 + +Files: * +Copyright: © 2016 David Fisher + © 2008 Armin Ronacher +Comment: The original CPython source is licensed under the + Python Software Foundation License Version 2 +License: Python + +Files: ast27/Parser/spark.py +Copyright: © 1998-2002 John Aycock +License: Expat + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +License: Apache-2.0 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + . + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + . + 1. Definitions. + . + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + . + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + . + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + . + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + . + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + . + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + . + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + . + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + . + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + . + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + . + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + . + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + . + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + . + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + . + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + . + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + . + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + . + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + . + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + . + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + . + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + . + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + . + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + . + END OF TERMS AND CONDITIONS + . + APPENDIX: How to apply the Apache License to your work. + . + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + . + Copyright 2016 Dropbox, Inc. + . + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + . + http://www.apache.org/licenses/LICENSE-2.0 + . + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +License: Python + PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 + -------------------------------------------- + . + 1. This LICENSE AGREEMENT is between the Python Software Foundation + ("PSF"), and the Individual or Organization ("Licensee") accessing and + otherwise using this software ("Python") in source or binary form and + its associated documentation. + . + 2. Subject to the terms and conditions of this License Agreement, PSF hereby + grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, + analyze, test, perform and/or display publicly, prepare derivative works, + distribute, and otherwise use Python alone or in any derivative version, + provided, however, that PSF's License Agreement and PSF's notice of copyright, + i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, + 2011, 2012, 2013, 2014, 2015, 2016 Python Software Foundation; All Rights + Reserved" are retained in Python alone or in any derivative version prepared by + Licensee. + . + 3. In the event Licensee prepares a derivative work that is based on + or incorporates Python or any part thereof, and wants to make + the derivative work available to others as provided herein, then + Licensee hereby agrees to include in any such work a brief summary of + the changes made to Python. + . + 4. PSF is making Python available to Licensee on an "AS IS" + basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR + IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND + DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS + FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT + INFRINGE ANY THIRD PARTY RIGHTS. + . + 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON + FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS + A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, + OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + . + 6. This License Agreement will automatically terminate upon a material + breach of its terms and conditions. + . + 7. Nothing in this License Agreement shall be deemed to create any + relationship of agency, partnership, or joint venture between PSF and + Licensee. This License Agreement does not grant permission to use PSF + trademarks or trade name in a trademark sense to endorse or promote + products or services of Licensee, or any third party. + . + 8. By copying, installing or otherwise using Python, Licensee + agrees to be bound by the terms and conditions of this License + Agreement. diff --git a/venv/Lib/site-packages/typed_ast-1.4.3.dist-info/METADATA b/venv/Lib/site-packages/typed_ast-1.4.3.dist-info/METADATA new file mode 100644 index 0000000..7c7f56e --- /dev/null +++ b/venv/Lib/site-packages/typed_ast-1.4.3.dist-info/METADATA @@ -0,0 +1,30 @@ +Metadata-Version: 2.1 +Name: typed-ast +Version: 1.4.3 +Summary: a fork of Python 2 and 3 ast modules with type comment support +Home-page: https://github.com/python/typed_ast +Author: David Fisher +Author-email: UNKNOWN +License: Apache License 2.0 +Platform: POSIX +Platform: Windows +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: Operating System :: POSIX +Classifier: Operating System :: Microsoft +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Topic :: Software Development + +`typed_ast` is a Python 3 package that provides a Python 2.7 and Python 3 +parser similar to the standard `ast` library. Unlike `ast`, the parsers in +`typed_ast` include PEP 484 type comments and are independent of the version of +Python under which they are run. The `typed_ast` parsers produce the standard +Python AST (plus type comments), and are both fast and correct, as they are +based on the CPython 2.7 and 3.6 parsers. + diff --git a/venv/Lib/site-packages/typed_ast-1.4.3.dist-info/RECORD b/venv/Lib/site-packages/typed_ast-1.4.3.dist-info/RECORD new file mode 100644 index 0000000..d390912 --- /dev/null +++ b/venv/Lib/site-packages/typed_ast-1.4.3.dist-info/RECORD @@ -0,0 +1,18 @@ +typed_ast-1.4.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +typed_ast-1.4.3.dist-info/LICENSE,sha256=PwfDPiHJOi2_T6I50fxiYmilsIHot5rKO48KR7BQ8Uw,15191 +typed_ast-1.4.3.dist-info/METADATA,sha256=vYA3ENZwb2MWecgsHUU_t2Zd0RG6XC_B8V9JnzMA94o,1264 +typed_ast-1.4.3.dist-info/RECORD,, +typed_ast-1.4.3.dist-info/WHEEL,sha256=jr7ubY0Lkz_yXH9FfFe9PTtLhGOsf62dZkNvTYrJINE,100 +typed_ast-1.4.3.dist-info/top_level.txt,sha256=LCmBygYWBo6qqIoaZNicoxU-DO9gR2JvhQkVJwSyN1k,23 +typed_ast/__init__.py,sha256=rxvQUWSe6nvSADkIyuziyi8Irk70s2DZSxOB9c8cpAQ,22 +typed_ast/__pycache__/__init__.cpython-39.pyc,, +typed_ast/__pycache__/ast27.cpython-39.pyc,, +typed_ast/__pycache__/ast3.cpython-39.pyc,, +typed_ast/__pycache__/conversions.cpython-39.pyc,, +typed_ast/_ast27.cp39-win_amd64.pyd,sha256=DDhQW1UszBLDwIKseVcWJkvU2EZzMcJdvLSxitP22GM,166400 +typed_ast/_ast3.cp39-win_amd64.pyd,sha256=tsE_JjOZC398Z0baqk_XHkFF7stABiPmcXHtxbPM8Do,187392 +typed_ast/ast27.py,sha256=MouNmlSUIINEyl3LBa796DXBvZNOjo5-gCPzoYRDb1Q,12630 +typed_ast/ast3.py,sha256=2Fb_0TUknxmDPzBXPYe1XkGhJL1JxeR2zLivWII3TqI,13761 +typed_ast/conversions.py,sha256=J9wBDCg-it3cxfSnIAMWnBDiwLypfRBc7RTftRImwak,8632 +typed_ast/tests/__pycache__/test_basics.cpython-39.pyc,, +typed_ast/tests/test_basics.py,sha256=2aQmOXfqKyBNaVpB9FeYkMqSWy9Qz1aGwVCs70IrDKo,7516 diff --git a/venv/Lib/site-packages/typed_ast-1.4.3.dist-info/WHEEL b/venv/Lib/site-packages/typed_ast-1.4.3.dist-info/WHEEL new file mode 100644 index 0000000..d1267fc --- /dev/null +++ b/venv/Lib/site-packages/typed_ast-1.4.3.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.2) +Root-Is-Purelib: false +Tag: cp39-cp39-win_amd64 + diff --git a/venv/Lib/site-packages/typed_ast-1.4.3.dist-info/top_level.txt b/venv/Lib/site-packages/typed_ast-1.4.3.dist-info/top_level.txt new file mode 100644 index 0000000..8c96e51 --- /dev/null +++ b/venv/Lib/site-packages/typed_ast-1.4.3.dist-info/top_level.txt @@ -0,0 +1,3 @@ +_ast27 +_ast3 +typed_ast diff --git a/venv/Lib/site-packages/typing_extensions-4.4.0.dist-info/INSTALLER b/venv/Lib/site-packages/typing_extensions-4.4.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/typing_extensions-4.4.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/typing_extensions-4.4.0.dist-info/LICENSE b/venv/Lib/site-packages/typing_extensions-4.4.0.dist-info/LICENSE new file mode 100644 index 0000000..1df6b3b --- /dev/null +++ b/venv/Lib/site-packages/typing_extensions-4.4.0.dist-info/LICENSE @@ -0,0 +1,254 @@ +A. HISTORY OF THE SOFTWARE +========================== + +Python was created in the early 1990s by Guido van Rossum at Stichting +Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands +as a successor of a language called ABC. Guido remains Python's +principal author, although it includes many contributions from others. + +In 1995, Guido continued his work on Python at the Corporation for +National Research Initiatives (CNRI, see http://www.cnri.reston.va.us) +in Reston, Virginia where he released several versions of the +software. + +In May 2000, Guido and the Python core development team moved to +BeOpen.com to form the BeOpen PythonLabs team. In October of the same +year, the PythonLabs team moved to Digital Creations, which became +Zope Corporation. In 2001, the Python Software Foundation (PSF, see +https://www.python.org/psf/) was formed, a non-profit organization +created specifically to own Python-related Intellectual Property. +Zope Corporation was a sponsoring member of the PSF. + +All Python releases are Open Source (see http://www.opensource.org for +the Open Source Definition). Historically, most, but not all, Python +releases have also been GPL-compatible; the table below summarizes +the various releases. + + Release Derived Year Owner GPL- + from compatible? (1) + + 0.9.0 thru 1.2 1991-1995 CWI yes + 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes + 1.6 1.5.2 2000 CNRI no + 2.0 1.6 2000 BeOpen.com no + 1.6.1 1.6 2001 CNRI yes (2) + 2.1 2.0+1.6.1 2001 PSF no + 2.0.1 2.0+1.6.1 2001 PSF yes + 2.1.1 2.1+2.0.1 2001 PSF yes + 2.1.2 2.1.1 2002 PSF yes + 2.1.3 2.1.2 2002 PSF yes + 2.2 and above 2.1.1 2001-now PSF yes + +Footnotes: + +(1) GPL-compatible doesn't mean that we're distributing Python under + the GPL. All Python licenses, unlike the GPL, let you distribute + a modified version without making your changes open source. The + GPL-compatible licenses make it possible to combine Python with + other software that is released under the GPL; the others don't. + +(2) According to Richard Stallman, 1.6.1 is not GPL-compatible, + because its license has a choice of law clause. According to + CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 + is "not incompatible" with the GPL. + +Thanks to the many outside volunteers who have worked under Guido's +direction to make these releases possible. + + +B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON +=============================================================== + +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +analyze, test, perform and/or display publicly, prepare derivative works, +distribute, and otherwise use Python alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Python Software Foundation; +All Rights Reserved" are retained in Python alone or in any derivative version +prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 +------------------------------------------- + +BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 + +1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an +office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the +Individual or Organization ("Licensee") accessing and otherwise using +this software in source or binary form and its associated +documentation ("the Software"). + +2. Subject to the terms and conditions of this BeOpen Python License +Agreement, BeOpen hereby grants Licensee a non-exclusive, +royalty-free, world-wide license to reproduce, analyze, test, perform +and/or display publicly, prepare derivative works, distribute, and +otherwise use the Software alone or in any derivative version, +provided, however, that the BeOpen Python License is retained in the +Software, alone or in any derivative version prepared by Licensee. + +3. BeOpen is making the Software available to Licensee on an "AS IS" +basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE +SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS +AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY +DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +5. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +6. This License Agreement shall be governed by and interpreted in all +respects by the law of the State of California, excluding conflict of +law provisions. Nothing in this License Agreement shall be deemed to +create any relationship of agency, partnership, or joint venture +between BeOpen and Licensee. This License Agreement does not grant +permission to use BeOpen trademarks or trade names in a trademark +sense to endorse or promote products or services of Licensee, or any +third party. As an exception, the "BeOpen Python" logos available at +http://www.pythonlabs.com/logos.html may be used according to the +permissions granted on that web page. + +7. By copying, installing or otherwise using the software, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 +--------------------------------------- + +1. This LICENSE AGREEMENT is between the Corporation for National +Research Initiatives, having an office at 1895 Preston White Drive, +Reston, VA 20191 ("CNRI"), and the Individual or Organization +("Licensee") accessing and otherwise using Python 1.6.1 software in +source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, CNRI +hereby grants Licensee a nonexclusive, royalty-free, world-wide +license to reproduce, analyze, test, perform and/or display publicly, +prepare derivative works, distribute, and otherwise use Python 1.6.1 +alone or in any derivative version, provided, however, that CNRI's +License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) +1995-2001 Corporation for National Research Initiatives; All Rights +Reserved" are retained in Python 1.6.1 alone or in any derivative +version prepared by Licensee. Alternately, in lieu of CNRI's License +Agreement, Licensee may substitute the following text (omitting the +quotes): "Python 1.6.1 is made available subject to the terms and +conditions in CNRI's License Agreement. This Agreement together with +Python 1.6.1 may be located on the internet using the following +unique, persistent identifier (known as a handle): 1895.22/1013. This +Agreement may also be obtained from a proxy server on the internet +using the following URL: http://hdl.handle.net/1895.22/1013". + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python 1.6.1 or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python 1.6.1. + +4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" +basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. This License Agreement shall be governed by the federal +intellectual property law of the United States, including without +limitation the federal copyright law, and, to the extent such +U.S. federal law does not apply, by the law of the Commonwealth of +Virginia, excluding Virginia's conflict of law provisions. +Notwithstanding the foregoing, with regard to derivative works based +on Python 1.6.1 that incorporate non-separable material that was +previously distributed under the GNU General Public License (GPL), the +law of the Commonwealth of Virginia shall govern this License +Agreement only as to issues arising under or with respect to +Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this +License Agreement shall be deemed to create any relationship of +agency, partnership, or joint venture between CNRI and Licensee. This +License Agreement does not grant permission to use CNRI trademarks or +trade name in a trademark sense to endorse or promote products or +services of Licensee, or any third party. + +8. By clicking on the "ACCEPT" button where indicated, or by copying, +installing or otherwise using Python 1.6.1, Licensee agrees to be +bound by the terms and conditions of this License Agreement. + + ACCEPT + + +CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 +-------------------------------------------------- + +Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, +The Netherlands. All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/venv/Lib/site-packages/typing_extensions-4.4.0.dist-info/METADATA b/venv/Lib/site-packages/typing_extensions-4.4.0.dist-info/METADATA new file mode 100644 index 0000000..1ed963a --- /dev/null +++ b/venv/Lib/site-packages/typing_extensions-4.4.0.dist-info/METADATA @@ -0,0 +1,189 @@ +Metadata-Version: 2.1 +Name: typing_extensions +Version: 4.4.0 +Summary: Backported and Experimental Type Hints for Python 3.7+ +Keywords: annotations,backport,checker,checking,function,hinting,hints,type,typechecking,typehinting,typehints,typing +Author-email: "Guido van Rossum, Jukka Lehtosalo, Łukasz Langa, Michael Lee" +Requires-Python: >=3.7 +Description-Content-Type: text/markdown +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Python Software Foundation License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Topic :: Software Development +Project-URL: Bug Tracker, https://github.com/python/typing_extensions/issues +Project-URL: Changes, https://github.com/python/typing_extensions/blob/main/CHANGELOG.md +Project-URL: Documentation, https://typing.readthedocs.io/ +Project-URL: Home, https://github.com/python/typing_extensions +Project-URL: Q & A, https://github.com/python/typing/discussions +Project-URL: Repository, https://github.com/python/typing_extensions + +# Typing Extensions + +[![Chat at https://gitter.im/python/typing](https://badges.gitter.im/python/typing.svg)](https://gitter.im/python/typing) + +## Overview + +The `typing_extensions` module serves two related purposes: + +- Enable use of new type system features on older Python versions. For example, + `typing.TypeGuard` is new in Python 3.10, but `typing_extensions` allows + users on previous Python versions to use it too. +- Enable experimentation with new type system PEPs before they are accepted and + added to the `typing` module. + +New features may be added to `typing_extensions` as soon as they are specified +in a PEP that has been added to the [python/peps](https://github.com/python/peps) +repository. If the PEP is accepted, the feature will then be added to `typing` +for the next CPython release. No typing PEP has been rejected so far, so we +haven't yet figured out how to deal with that possibility. + +Starting with version 4.0.0, `typing_extensions` uses +[Semantic Versioning](https://semver.org/). The +major version is incremented for all backwards-incompatible changes. +Therefore, it's safe to depend +on `typing_extensions` like this: `typing_extensions >=x.y, <(x+1)`, +where `x.y` is the first version that includes all features you need. + +`typing_extensions` supports Python versions 3.7 and higher. In the future, +support for older Python versions will be dropped some time after that version +reaches end of life. + +## Included items + +This module currently contains the following: + +- Experimental features + + - `override` (see PEP 698) + - The `default=` argument to `TypeVar`, `ParamSpec`, and `TypeVarTuple` (see PEP 696) + - The `infer_variance=` argument to `TypeVar` (see PEP 695) + +- In `typing` since Python 3.11 + + - `assert_never` + - `assert_type` + - `clear_overloads` + - `@dataclass_transform()` (see PEP 681) + - `get_overloads` + - `LiteralString` (see PEP 675) + - `Never` + - `NotRequired` (see PEP 655) + - `reveal_type` + - `Required` (see PEP 655) + - `Self` (see PEP 673) + - `TypeVarTuple` (see PEP 646; the `typing_extensions` version supports the `default=` argument from PEP 696) + - `Unpack` (see PEP 646) + +- In `typing` since Python 3.10 + + - `Concatenate` (see PEP 612) + - `ParamSpec` (see PEP 612; the `typing_extensions` version supports the `default=` argument from PEP 696) + - `ParamSpecArgs` (see PEP 612) + - `ParamSpecKwargs` (see PEP 612) + - `TypeAlias` (see PEP 613) + - `TypeGuard` (see PEP 647) + - `is_typeddict` + +- In `typing` since Python 3.9 + + - `Annotated` (see PEP 593) + +- In `typing` since Python 3.8 + + - `final` (see PEP 591) + - `Final` (see PEP 591) + - `Literal` (see PEP 586) + - `Protocol` (see PEP 544) + - `runtime_checkable` (see PEP 544) + - `TypedDict` (see PEP 589) + - `get_origin` (`typing_extensions` provides this function only in Python 3.7+) + - `get_args` (`typing_extensions` provides this function only in Python 3.7+) + +- In `typing` since Python 3.7 + + - `OrderedDict` + +- In `typing` since Python 3.5 or 3.6 (see [the typing documentation](https://docs.python.org/3.10/library/typing.html) for details) + + - `AsyncContextManager` + - `AsyncGenerator` + - `AsyncIterable` + - `AsyncIterator` + - `Awaitable` + - `ChainMap` + - `ClassVar` (see PEP 526) + - `ContextManager` + - `Coroutine` + - `Counter` + - `DefaultDict` + - `Deque` + - `NewType` + - `NoReturn` + - `overload` + - `Text` + - `Type` + - `TYPE_CHECKING` + - `get_type_hints` + +- The following have always been present in `typing`, but the `typing_extensions` versions provide + additional features: + + - `Any` (supports inheritance since Python 3.11) + - `NamedTuple` (supports multiple inheritance with `Generic` since Python 3.11) + - `TypeVar` (see PEPs 695 and 696) + +# Other Notes and Limitations + +Certain objects were changed after they were added to `typing`, and +`typing_extensions` provides a backport even on newer Python versions: + +- `TypedDict` does not store runtime information + about which (if any) keys are non-required in Python 3.8, and does not + honor the `total` keyword with old-style `TypedDict()` in Python + 3.9.0 and 3.9.1. `TypedDict` also does not support multiple inheritance + with `typing.Generic` on Python <3.11. +- `get_origin` and `get_args` lack support for `Annotated` in + Python 3.8 and lack support for `ParamSpecArgs` and `ParamSpecKwargs` + in 3.9. +- `@final` was changed in Python 3.11 to set the `.__final__` attribute. +- `@overload` was changed in Python 3.11 to make function overloads + introspectable at runtime. In order to access overloads with + `typing_extensions.get_overloads()`, you must use + `@typing_extensions.overload`. +- `NamedTuple` was changed in Python 3.11 to allow for multiple inheritance + with `typing.Generic`. +- Since Python 3.11, it has been possible to inherit from `Any` at + runtime. `typing_extensions.Any` also provides this capability. +- `TypeVar` gains two additional parameters, `default=` and `infer_variance=`, + in the draft PEPs 695 and 696, which are being considered for inclusion + in Python 3.12. + +There are a few types whose interface was modified between different +versions of typing. For example, `typing.Sequence` was modified to +subclass `typing.Reversible` as of Python 3.5.3. + +These changes are _not_ backported to prevent subtle compatibility +issues when mixing the differing implementations of modified classes. + +Certain types have incorrect runtime behavior due to limitations of older +versions of the typing module: + +- `ParamSpec` and `Concatenate` will not work with `get_args` and + `get_origin`. Certain PEP 612 special cases in user-defined + `Generic`s are also not available. + +These types are only guaranteed to work for static type checking. + +## Running tests + +To run tests, navigate into the appropriate source directory and run +`test_typing_extensions.py`. + diff --git a/venv/Lib/site-packages/typing_extensions-4.4.0.dist-info/RECORD b/venv/Lib/site-packages/typing_extensions-4.4.0.dist-info/RECORD new file mode 100644 index 0000000..6fddc87 --- /dev/null +++ b/venv/Lib/site-packages/typing_extensions-4.4.0.dist-info/RECORD @@ -0,0 +1,7 @@ +__pycache__/typing_extensions.cpython-39.pyc,, +typing_extensions-4.4.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +typing_extensions-4.4.0.dist-info/LICENSE,sha256=x6-2XnVXB7n7kEhziaF20-09ADHVExr95FwjcV_16JE,12787 +typing_extensions-4.4.0.dist-info/METADATA,sha256=1zSh1eMLnLkLMMC6aZSGRKx3eRnivEGDFWGSVD1zqhA,7249 +typing_extensions-4.4.0.dist-info/RECORD,, +typing_extensions-4.4.0.dist-info/WHEEL,sha256=4TfKIB_xu-04bc2iKz6_zFt-gEFEEDU_31HGhqzOCE8,81 +typing_extensions.py,sha256=ipqWiq5AHzrwczt6c26AP05Llh6a5_GaXRpOBqbogHA,80078 diff --git a/venv/Lib/site-packages/typing_extensions-4.4.0.dist-info/WHEEL b/venv/Lib/site-packages/typing_extensions-4.4.0.dist-info/WHEEL new file mode 100644 index 0000000..668ba4d --- /dev/null +++ b/venv/Lib/site-packages/typing_extensions-4.4.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.7.1 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/venv/Lib/site-packages/typing_extensions.py b/venv/Lib/site-packages/typing_extensions.py new file mode 100644 index 0000000..ef42417 --- /dev/null +++ b/venv/Lib/site-packages/typing_extensions.py @@ -0,0 +1,2209 @@ +import abc +import collections +import collections.abc +import functools +import operator +import sys +import types as _types +import typing + + +__all__ = [ + # Super-special typing primitives. + 'Any', + 'ClassVar', + 'Concatenate', + 'Final', + 'LiteralString', + 'ParamSpec', + 'ParamSpecArgs', + 'ParamSpecKwargs', + 'Self', + 'Type', + 'TypeVar', + 'TypeVarTuple', + 'Unpack', + + # ABCs (from collections.abc). + 'Awaitable', + 'AsyncIterator', + 'AsyncIterable', + 'Coroutine', + 'AsyncGenerator', + 'AsyncContextManager', + 'ChainMap', + + # Concrete collection types. + 'ContextManager', + 'Counter', + 'Deque', + 'DefaultDict', + 'NamedTuple', + 'OrderedDict', + 'TypedDict', + + # Structural checks, a.k.a. protocols. + 'SupportsIndex', + + # One-off things. + 'Annotated', + 'assert_never', + 'assert_type', + 'clear_overloads', + 'dataclass_transform', + 'get_overloads', + 'final', + 'get_args', + 'get_origin', + 'get_type_hints', + 'IntVar', + 'is_typeddict', + 'Literal', + 'NewType', + 'overload', + 'override', + 'Protocol', + 'reveal_type', + 'runtime', + 'runtime_checkable', + 'Text', + 'TypeAlias', + 'TypeGuard', + 'TYPE_CHECKING', + 'Never', + 'NoReturn', + 'Required', + 'NotRequired', +] + +# for backward compatibility +PEP_560 = True +GenericMeta = type + +# The functions below are modified copies of typing internal helpers. +# They are needed by _ProtocolMeta and they provide support for PEP 646. + +_marker = object() + + +def _check_generic(cls, parameters, elen=_marker): + """Check correct count for parameters of a generic cls (internal helper). + This gives a nice error message in case of count mismatch. + """ + if not elen: + raise TypeError(f"{cls} is not a generic class") + if elen is _marker: + if not hasattr(cls, "__parameters__") or not cls.__parameters__: + raise TypeError(f"{cls} is not a generic class") + elen = len(cls.__parameters__) + alen = len(parameters) + if alen != elen: + if hasattr(cls, "__parameters__"): + parameters = [p for p in cls.__parameters__ if not _is_unpack(p)] + num_tv_tuples = sum(isinstance(p, TypeVarTuple) for p in parameters) + if (num_tv_tuples > 0) and (alen >= elen - num_tv_tuples): + return + raise TypeError(f"Too {'many' if alen > elen else 'few'} parameters for {cls};" + f" actual {alen}, expected {elen}") + + +if sys.version_info >= (3, 10): + def _should_collect_from_parameters(t): + return isinstance( + t, (typing._GenericAlias, _types.GenericAlias, _types.UnionType) + ) +elif sys.version_info >= (3, 9): + def _should_collect_from_parameters(t): + return isinstance(t, (typing._GenericAlias, _types.GenericAlias)) +else: + def _should_collect_from_parameters(t): + return isinstance(t, typing._GenericAlias) and not t._special + + +def _collect_type_vars(types, typevar_types=None): + """Collect all type variable contained in types in order of + first appearance (lexicographic order). For example:: + + _collect_type_vars((T, List[S, T])) == (T, S) + """ + if typevar_types is None: + typevar_types = typing.TypeVar + tvars = [] + for t in types: + if ( + isinstance(t, typevar_types) and + t not in tvars and + not _is_unpack(t) + ): + tvars.append(t) + if _should_collect_from_parameters(t): + tvars.extend([t for t in t.__parameters__ if t not in tvars]) + return tuple(tvars) + + +NoReturn = typing.NoReturn + +# Some unconstrained type variables. These are used by the container types. +# (These are not for export.) +T = typing.TypeVar('T') # Any type. +KT = typing.TypeVar('KT') # Key type. +VT = typing.TypeVar('VT') # Value type. +T_co = typing.TypeVar('T_co', covariant=True) # Any type covariant containers. +T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant. + + +if sys.version_info >= (3, 11): + from typing import Any +else: + + class _AnyMeta(type): + def __instancecheck__(self, obj): + if self is Any: + raise TypeError("typing_extensions.Any cannot be used with isinstance()") + return super().__instancecheck__(obj) + + def __repr__(self): + if self is Any: + return "typing_extensions.Any" + return super().__repr__() + + class Any(metaclass=_AnyMeta): + """Special type indicating an unconstrained type. + - Any is compatible with every type. + - Any assumed to have all methods. + - All values assumed to be instances of Any. + Note that all the above statements are true from the point of view of + static type checkers. At runtime, Any should not be used with instance + checks. + """ + def __new__(cls, *args, **kwargs): + if cls is Any: + raise TypeError("Any cannot be instantiated") + return super().__new__(cls, *args, **kwargs) + + +ClassVar = typing.ClassVar + +# On older versions of typing there is an internal class named "Final". +# 3.8+ +if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7): + Final = typing.Final +# 3.7 +else: + class _FinalForm(typing._SpecialForm, _root=True): + + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + Final = _FinalForm('Final', + doc="""A special typing construct to indicate that a name + cannot be re-assigned or overridden in a subclass. + For example: + + MAX_SIZE: Final = 9000 + MAX_SIZE += 1 # Error reported by type checker + + class Connection: + TIMEOUT: Final[int] = 10 + class FastConnector(Connection): + TIMEOUT = 1 # Error reported by type checker + + There is no runtime checking of these properties.""") + +if sys.version_info >= (3, 11): + final = typing.final +else: + # @final exists in 3.8+, but we backport it for all versions + # before 3.11 to keep support for the __final__ attribute. + # See https://bugs.python.org/issue46342 + def final(f): + """This decorator can be used to indicate to type checkers that + the decorated method cannot be overridden, and decorated class + cannot be subclassed. For example: + + class Base: + @final + def done(self) -> None: + ... + class Sub(Base): + def done(self) -> None: # Error reported by type checker + ... + @final + class Leaf: + ... + class Other(Leaf): # Error reported by type checker + ... + + There is no runtime checking of these properties. The decorator + sets the ``__final__`` attribute to ``True`` on the decorated object + to allow runtime introspection. + """ + try: + f.__final__ = True + except (AttributeError, TypeError): + # Skip the attribute silently if it is not writable. + # AttributeError happens if the object has __slots__ or a + # read-only property, TypeError if it's a builtin class. + pass + return f + + +def IntVar(name): + return typing.TypeVar(name) + + +# 3.8+: +if hasattr(typing, 'Literal'): + Literal = typing.Literal +# 3.7: +else: + class _LiteralForm(typing._SpecialForm, _root=True): + + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + return typing._GenericAlias(self, parameters) + + Literal = _LiteralForm('Literal', + doc="""A type that can be used to indicate to type checkers + that the corresponding value has a value literally equivalent + to the provided parameter. For example: + + var: Literal[4] = 4 + + The type checker understands that 'var' is literally equal to + the value 4 and no other value. + + Literal[...] cannot be subclassed. There is no runtime + checking verifying that the parameter is actually a value + instead of a type.""") + + +_overload_dummy = typing._overload_dummy # noqa + + +if hasattr(typing, "get_overloads"): # 3.11+ + overload = typing.overload + get_overloads = typing.get_overloads + clear_overloads = typing.clear_overloads +else: + # {module: {qualname: {firstlineno: func}}} + _overload_registry = collections.defaultdict( + functools.partial(collections.defaultdict, dict) + ) + + def overload(func): + """Decorator for overloaded functions/methods. + + In a stub file, place two or more stub definitions for the same + function in a row, each decorated with @overload. For example: + + @overload + def utf8(value: None) -> None: ... + @overload + def utf8(value: bytes) -> bytes: ... + @overload + def utf8(value: str) -> bytes: ... + + In a non-stub file (i.e. a regular .py file), do the same but + follow it with an implementation. The implementation should *not* + be decorated with @overload. For example: + + @overload + def utf8(value: None) -> None: ... + @overload + def utf8(value: bytes) -> bytes: ... + @overload + def utf8(value: str) -> bytes: ... + def utf8(value): + # implementation goes here + + The overloads for a function can be retrieved at runtime using the + get_overloads() function. + """ + # classmethod and staticmethod + f = getattr(func, "__func__", func) + try: + _overload_registry[f.__module__][f.__qualname__][ + f.__code__.co_firstlineno + ] = func + except AttributeError: + # Not a normal function; ignore. + pass + return _overload_dummy + + def get_overloads(func): + """Return all defined overloads for *func* as a sequence.""" + # classmethod and staticmethod + f = getattr(func, "__func__", func) + if f.__module__ not in _overload_registry: + return [] + mod_dict = _overload_registry[f.__module__] + if f.__qualname__ not in mod_dict: + return [] + return list(mod_dict[f.__qualname__].values()) + + def clear_overloads(): + """Clear all overloads in the registry.""" + _overload_registry.clear() + + +# This is not a real generic class. Don't use outside annotations. +Type = typing.Type + +# Various ABCs mimicking those in collections.abc. +# A few are simply re-exported for completeness. + + +Awaitable = typing.Awaitable +Coroutine = typing.Coroutine +AsyncIterable = typing.AsyncIterable +AsyncIterator = typing.AsyncIterator +Deque = typing.Deque +ContextManager = typing.ContextManager +AsyncContextManager = typing.AsyncContextManager +DefaultDict = typing.DefaultDict + +# 3.7.2+ +if hasattr(typing, 'OrderedDict'): + OrderedDict = typing.OrderedDict +# 3.7.0-3.7.2 +else: + OrderedDict = typing._alias(collections.OrderedDict, (KT, VT)) + +Counter = typing.Counter +ChainMap = typing.ChainMap +AsyncGenerator = typing.AsyncGenerator +NewType = typing.NewType +Text = typing.Text +TYPE_CHECKING = typing.TYPE_CHECKING + + +_PROTO_WHITELIST = ['Callable', 'Awaitable', + 'Iterable', 'Iterator', 'AsyncIterable', 'AsyncIterator', + 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', + 'ContextManager', 'AsyncContextManager'] + + +def _get_protocol_attrs(cls): + attrs = set() + for base in cls.__mro__[:-1]: # without object + if base.__name__ in ('Protocol', 'Generic'): + continue + annotations = getattr(base, '__annotations__', {}) + for attr in list(base.__dict__.keys()) + list(annotations.keys()): + if (not attr.startswith('_abc_') and attr not in ( + '__abstractmethods__', '__annotations__', '__weakref__', + '_is_protocol', '_is_runtime_protocol', '__dict__', + '__args__', '__slots__', + '__next_in_mro__', '__parameters__', '__origin__', + '__orig_bases__', '__extra__', '__tree_hash__', + '__doc__', '__subclasshook__', '__init__', '__new__', + '__module__', '_MutableMapping__marker', '_gorg')): + attrs.add(attr) + return attrs + + +def _is_callable_members_only(cls): + return all(callable(getattr(cls, attr, None)) for attr in _get_protocol_attrs(cls)) + + +def _maybe_adjust_parameters(cls): + """Helper function used in Protocol.__init_subclass__ and _TypedDictMeta.__new__. + + The contents of this function are very similar + to logic found in typing.Generic.__init_subclass__ + on the CPython main branch. + """ + tvars = [] + if '__orig_bases__' in cls.__dict__: + tvars = typing._collect_type_vars(cls.__orig_bases__) + # Look for Generic[T1, ..., Tn] or Protocol[T1, ..., Tn]. + # If found, tvars must be a subset of it. + # If not found, tvars is it. + # Also check for and reject plain Generic, + # and reject multiple Generic[...] and/or Protocol[...]. + gvars = None + for base in cls.__orig_bases__: + if (isinstance(base, typing._GenericAlias) and + base.__origin__ in (typing.Generic, Protocol)): + # for error messages + the_base = base.__origin__.__name__ + if gvars is not None: + raise TypeError( + "Cannot inherit from Generic[...]" + " and/or Protocol[...] multiple types.") + gvars = base.__parameters__ + if gvars is None: + gvars = tvars + else: + tvarset = set(tvars) + gvarset = set(gvars) + if not tvarset <= gvarset: + s_vars = ', '.join(str(t) for t in tvars if t not in gvarset) + s_args = ', '.join(str(g) for g in gvars) + raise TypeError(f"Some type variables ({s_vars}) are" + f" not listed in {the_base}[{s_args}]") + tvars = gvars + cls.__parameters__ = tuple(tvars) + + +# 3.8+ +if hasattr(typing, 'Protocol'): + Protocol = typing.Protocol +# 3.7 +else: + + def _no_init(self, *args, **kwargs): + if type(self)._is_protocol: + raise TypeError('Protocols cannot be instantiated') + + class _ProtocolMeta(abc.ABCMeta): # noqa: B024 + # This metaclass is a bit unfortunate and exists only because of the lack + # of __instancehook__. + def __instancecheck__(cls, instance): + # We need this method for situations where attributes are + # assigned in __init__. + if ((not getattr(cls, '_is_protocol', False) or + _is_callable_members_only(cls)) and + issubclass(instance.__class__, cls)): + return True + if cls._is_protocol: + if all(hasattr(instance, attr) and + (not callable(getattr(cls, attr, None)) or + getattr(instance, attr) is not None) + for attr in _get_protocol_attrs(cls)): + return True + return super().__instancecheck__(instance) + + class Protocol(metaclass=_ProtocolMeta): + # There is quite a lot of overlapping code with typing.Generic. + # Unfortunately it is hard to avoid this while these live in two different + # modules. The duplicated code will be removed when Protocol is moved to typing. + """Base class for protocol classes. Protocol classes are defined as:: + + class Proto(Protocol): + def meth(self) -> int: + ... + + Such classes are primarily used with static type checkers that recognize + structural subtyping (static duck-typing), for example:: + + class C: + def meth(self) -> int: + return 0 + + def func(x: Proto) -> int: + return x.meth() + + func(C()) # Passes static type check + + See PEP 544 for details. Protocol classes decorated with + @typing_extensions.runtime act as simple-minded runtime protocol that checks + only the presence of given attributes, ignoring their type signatures. + + Protocol classes can be generic, they are defined as:: + + class GenProto(Protocol[T]): + def meth(self) -> T: + ... + """ + __slots__ = () + _is_protocol = True + + def __new__(cls, *args, **kwds): + if cls is Protocol: + raise TypeError("Type Protocol cannot be instantiated; " + "it can only be used as a base class") + return super().__new__(cls) + + @typing._tp_cache + def __class_getitem__(cls, params): + if not isinstance(params, tuple): + params = (params,) + if not params and cls is not typing.Tuple: + raise TypeError( + f"Parameter list to {cls.__qualname__}[...] cannot be empty") + msg = "Parameters to generic types must be types." + params = tuple(typing._type_check(p, msg) for p in params) # noqa + if cls is Protocol: + # Generic can only be subscripted with unique type variables. + if not all(isinstance(p, typing.TypeVar) for p in params): + i = 0 + while isinstance(params[i], typing.TypeVar): + i += 1 + raise TypeError( + "Parameters to Protocol[...] must all be type variables." + f" Parameter {i + 1} is {params[i]}") + if len(set(params)) != len(params): + raise TypeError( + "Parameters to Protocol[...] must all be unique") + else: + # Subscripting a regular Generic subclass. + _check_generic(cls, params, len(cls.__parameters__)) + return typing._GenericAlias(cls, params) + + def __init_subclass__(cls, *args, **kwargs): + if '__orig_bases__' in cls.__dict__: + error = typing.Generic in cls.__orig_bases__ + else: + error = typing.Generic in cls.__bases__ + if error: + raise TypeError("Cannot inherit from plain Generic") + _maybe_adjust_parameters(cls) + + # Determine if this is a protocol or a concrete subclass. + if not cls.__dict__.get('_is_protocol', None): + cls._is_protocol = any(b is Protocol for b in cls.__bases__) + + # Set (or override) the protocol subclass hook. + def _proto_hook(other): + if not cls.__dict__.get('_is_protocol', None): + return NotImplemented + if not getattr(cls, '_is_runtime_protocol', False): + if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']: + return NotImplemented + raise TypeError("Instance and class checks can only be used with" + " @runtime protocols") + if not _is_callable_members_only(cls): + if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']: + return NotImplemented + raise TypeError("Protocols with non-method members" + " don't support issubclass()") + if not isinstance(other, type): + # Same error as for issubclass(1, int) + raise TypeError('issubclass() arg 1 must be a class') + for attr in _get_protocol_attrs(cls): + for base in other.__mro__: + if attr in base.__dict__: + if base.__dict__[attr] is None: + return NotImplemented + break + annotations = getattr(base, '__annotations__', {}) + if (isinstance(annotations, typing.Mapping) and + attr in annotations and + isinstance(other, _ProtocolMeta) and + other._is_protocol): + break + else: + return NotImplemented + return True + if '__subclasshook__' not in cls.__dict__: + cls.__subclasshook__ = _proto_hook + + # We have nothing more to do for non-protocols. + if not cls._is_protocol: + return + + # Check consistency of bases. + for base in cls.__bases__: + if not (base in (object, typing.Generic) or + base.__module__ == 'collections.abc' and + base.__name__ in _PROTO_WHITELIST or + isinstance(base, _ProtocolMeta) and base._is_protocol): + raise TypeError('Protocols can only inherit from other' + f' protocols, got {repr(base)}') + cls.__init__ = _no_init + + +# 3.8+ +if hasattr(typing, 'runtime_checkable'): + runtime_checkable = typing.runtime_checkable +# 3.7 +else: + def runtime_checkable(cls): + """Mark a protocol class as a runtime protocol, so that it + can be used with isinstance() and issubclass(). Raise TypeError + if applied to a non-protocol class. + + This allows a simple-minded structural check very similar to the + one-offs in collections.abc such as Hashable. + """ + if not isinstance(cls, _ProtocolMeta) or not cls._is_protocol: + raise TypeError('@runtime_checkable can be only applied to protocol classes,' + f' got {cls!r}') + cls._is_runtime_protocol = True + return cls + + +# Exists for backwards compatibility. +runtime = runtime_checkable + + +# 3.8+ +if hasattr(typing, 'SupportsIndex'): + SupportsIndex = typing.SupportsIndex +# 3.7 +else: + @runtime_checkable + class SupportsIndex(Protocol): + __slots__ = () + + @abc.abstractmethod + def __index__(self) -> int: + pass + + +if hasattr(typing, "Required"): + # The standard library TypedDict in Python 3.8 does not store runtime information + # about which (if any) keys are optional. See https://bugs.python.org/issue38834 + # The standard library TypedDict in Python 3.9.0/1 does not honour the "total" + # keyword with old-style TypedDict(). See https://bugs.python.org/issue42059 + # The standard library TypedDict below Python 3.11 does not store runtime + # information about optional and required keys when using Required or NotRequired. + # Generic TypedDicts are also impossible using typing.TypedDict on Python <3.11. + TypedDict = typing.TypedDict + _TypedDictMeta = typing._TypedDictMeta + is_typeddict = typing.is_typeddict +else: + def _check_fails(cls, other): + try: + if sys._getframe(1).f_globals['__name__'] not in ['abc', + 'functools', + 'typing']: + # Typed dicts are only for static structural subtyping. + raise TypeError('TypedDict does not support instance and class checks') + except (AttributeError, ValueError): + pass + return False + + def _dict_new(*args, **kwargs): + if not args: + raise TypeError('TypedDict.__new__(): not enough arguments') + _, args = args[0], args[1:] # allow the "cls" keyword be passed + return dict(*args, **kwargs) + + _dict_new.__text_signature__ = '($cls, _typename, _fields=None, /, **kwargs)' + + def _typeddict_new(*args, total=True, **kwargs): + if not args: + raise TypeError('TypedDict.__new__(): not enough arguments') + _, args = args[0], args[1:] # allow the "cls" keyword be passed + if args: + typename, args = args[0], args[1:] # allow the "_typename" keyword be passed + elif '_typename' in kwargs: + typename = kwargs.pop('_typename') + import warnings + warnings.warn("Passing '_typename' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + raise TypeError("TypedDict.__new__() missing 1 required positional " + "argument: '_typename'") + if args: + try: + fields, = args # allow the "_fields" keyword be passed + except ValueError: + raise TypeError('TypedDict.__new__() takes from 2 to 3 ' + f'positional arguments but {len(args) + 2} ' + 'were given') + elif '_fields' in kwargs and len(kwargs) == 1: + fields = kwargs.pop('_fields') + import warnings + warnings.warn("Passing '_fields' as keyword argument is deprecated", + DeprecationWarning, stacklevel=2) + else: + fields = None + + if fields is None: + fields = kwargs + elif kwargs: + raise TypeError("TypedDict takes either a dict or keyword arguments," + " but not both") + + ns = {'__annotations__': dict(fields)} + try: + # Setting correct module is necessary to make typed dict classes pickleable. + ns['__module__'] = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + pass + + return _TypedDictMeta(typename, (), ns, total=total) + + _typeddict_new.__text_signature__ = ('($cls, _typename, _fields=None,' + ' /, *, total=True, **kwargs)') + + class _TypedDictMeta(type): + def __init__(cls, name, bases, ns, total=True): + super().__init__(name, bases, ns) + + def __new__(cls, name, bases, ns, total=True): + # Create new typed dict class object. + # This method is called directly when TypedDict is subclassed, + # or via _typeddict_new when TypedDict is instantiated. This way + # TypedDict supports all three syntaxes described in its docstring. + # Subclasses and instances of TypedDict return actual dictionaries + # via _dict_new. + ns['__new__'] = _typeddict_new if name == 'TypedDict' else _dict_new + # Don't insert typing.Generic into __bases__ here, + # or Generic.__init_subclass__ will raise TypeError + # in the super().__new__() call. + # Instead, monkey-patch __bases__ onto the class after it's been created. + tp_dict = super().__new__(cls, name, (dict,), ns) + + if any(issubclass(base, typing.Generic) for base in bases): + tp_dict.__bases__ = (typing.Generic, dict) + _maybe_adjust_parameters(tp_dict) + + annotations = {} + own_annotations = ns.get('__annotations__', {}) + msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" + own_annotations = { + n: typing._type_check(tp, msg) for n, tp in own_annotations.items() + } + required_keys = set() + optional_keys = set() + + for base in bases: + annotations.update(base.__dict__.get('__annotations__', {})) + required_keys.update(base.__dict__.get('__required_keys__', ())) + optional_keys.update(base.__dict__.get('__optional_keys__', ())) + + annotations.update(own_annotations) + for annotation_key, annotation_type in own_annotations.items(): + annotation_origin = get_origin(annotation_type) + if annotation_origin is Annotated: + annotation_args = get_args(annotation_type) + if annotation_args: + annotation_type = annotation_args[0] + annotation_origin = get_origin(annotation_type) + + if annotation_origin is Required: + required_keys.add(annotation_key) + elif annotation_origin is NotRequired: + optional_keys.add(annotation_key) + elif total: + required_keys.add(annotation_key) + else: + optional_keys.add(annotation_key) + + tp_dict.__annotations__ = annotations + tp_dict.__required_keys__ = frozenset(required_keys) + tp_dict.__optional_keys__ = frozenset(optional_keys) + if not hasattr(tp_dict, '__total__'): + tp_dict.__total__ = total + return tp_dict + + __instancecheck__ = __subclasscheck__ = _check_fails + + TypedDict = _TypedDictMeta('TypedDict', (dict,), {}) + TypedDict.__module__ = __name__ + TypedDict.__doc__ = \ + """A simple typed name space. At runtime it is equivalent to a plain dict. + + TypedDict creates a dictionary type that expects all of its + instances to have a certain set of keys, with each key + associated with a value of a consistent type. This expectation + is not checked at runtime but is only enforced by type checkers. + Usage:: + + class Point2D(TypedDict): + x: int + y: int + label: str + + a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK + b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check + + assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first') + + The type info can be accessed via the Point2D.__annotations__ dict, and + the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets. + TypedDict supports two additional equivalent forms:: + + Point2D = TypedDict('Point2D', x=int, y=int, label=str) + Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str}) + + The class syntax is only supported in Python 3.6+, while two other + syntax forms work for Python 2.7 and 3.2+ + """ + + if hasattr(typing, "_TypedDictMeta"): + _TYPEDDICT_TYPES = (typing._TypedDictMeta, _TypedDictMeta) + else: + _TYPEDDICT_TYPES = (_TypedDictMeta,) + + def is_typeddict(tp): + """Check if an annotation is a TypedDict class + + For example:: + class Film(TypedDict): + title: str + year: int + + is_typeddict(Film) # => True + is_typeddict(Union[list, str]) # => False + """ + return isinstance(tp, tuple(_TYPEDDICT_TYPES)) + + +if hasattr(typing, "assert_type"): + assert_type = typing.assert_type + +else: + def assert_type(__val, __typ): + """Assert (to the type checker) that the value is of the given type. + + When the type checker encounters a call to assert_type(), it + emits an error if the value is not of the specified type:: + + def greet(name: str) -> None: + assert_type(name, str) # ok + assert_type(name, int) # type checker error + + At runtime this returns the first argument unchanged and otherwise + does nothing. + """ + return __val + + +if hasattr(typing, "Required"): + get_type_hints = typing.get_type_hints +else: + import functools + import types + + # replaces _strip_annotations() + def _strip_extras(t): + """Strips Annotated, Required and NotRequired from a given type.""" + if isinstance(t, _AnnotatedAlias): + return _strip_extras(t.__origin__) + if hasattr(t, "__origin__") and t.__origin__ in (Required, NotRequired): + return _strip_extras(t.__args__[0]) + if isinstance(t, typing._GenericAlias): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return t.copy_with(stripped_args) + if hasattr(types, "GenericAlias") and isinstance(t, types.GenericAlias): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return types.GenericAlias(t.__origin__, stripped_args) + if hasattr(types, "UnionType") and isinstance(t, types.UnionType): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return functools.reduce(operator.or_, stripped_args) + + return t + + def get_type_hints(obj, globalns=None, localns=None, include_extras=False): + """Return type hints for an object. + + This is often the same as obj.__annotations__, but it handles + forward references encoded as string literals, adds Optional[t] if a + default value equal to None is set and recursively replaces all + 'Annotated[T, ...]', 'Required[T]' or 'NotRequired[T]' with 'T' + (unless 'include_extras=True'). + + The argument may be a module, class, method, or function. The annotations + are returned as a dictionary. For classes, annotations include also + inherited members. + + TypeError is raised if the argument is not of a type that can contain + annotations, and an empty dictionary is returned if no annotations are + present. + + BEWARE -- the behavior of globalns and localns is counterintuitive + (unless you are familiar with how eval() and exec() work). The + search order is locals first, then globals. + + - If no dict arguments are passed, an attempt is made to use the + globals from obj (or the respective module's globals for classes), + and these are also used as the locals. If the object does not appear + to have globals, an empty dictionary is used. + + - If one dict argument is passed, it is used for both globals and + locals. + + - If two dict arguments are passed, they specify globals and + locals, respectively. + """ + if hasattr(typing, "Annotated"): + hint = typing.get_type_hints( + obj, globalns=globalns, localns=localns, include_extras=True + ) + else: + hint = typing.get_type_hints(obj, globalns=globalns, localns=localns) + if include_extras: + return hint + return {k: _strip_extras(t) for k, t in hint.items()} + + +# Python 3.9+ has PEP 593 (Annotated) +if hasattr(typing, 'Annotated'): + Annotated = typing.Annotated + # Not exported and not a public API, but needed for get_origin() and get_args() + # to work. + _AnnotatedAlias = typing._AnnotatedAlias +# 3.7-3.8 +else: + class _AnnotatedAlias(typing._GenericAlias, _root=True): + """Runtime representation of an annotated type. + + At its core 'Annotated[t, dec1, dec2, ...]' is an alias for the type 't' + with extra annotations. The alias behaves like a normal typing alias, + instantiating is the same as instantiating the underlying type, binding + it to types is also the same. + """ + def __init__(self, origin, metadata): + if isinstance(origin, _AnnotatedAlias): + metadata = origin.__metadata__ + metadata + origin = origin.__origin__ + super().__init__(origin, origin) + self.__metadata__ = metadata + + def copy_with(self, params): + assert len(params) == 1 + new_type = params[0] + return _AnnotatedAlias(new_type, self.__metadata__) + + def __repr__(self): + return (f"typing_extensions.Annotated[{typing._type_repr(self.__origin__)}, " + f"{', '.join(repr(a) for a in self.__metadata__)}]") + + def __reduce__(self): + return operator.getitem, ( + Annotated, (self.__origin__,) + self.__metadata__ + ) + + def __eq__(self, other): + if not isinstance(other, _AnnotatedAlias): + return NotImplemented + if self.__origin__ != other.__origin__: + return False + return self.__metadata__ == other.__metadata__ + + def __hash__(self): + return hash((self.__origin__, self.__metadata__)) + + class Annotated: + """Add context specific metadata to a type. + + Example: Annotated[int, runtime_check.Unsigned] indicates to the + hypothetical runtime_check module that this type is an unsigned int. + Every other consumer of this type can ignore this metadata and treat + this type as int. + + The first argument to Annotated must be a valid type (and will be in + the __origin__ field), the remaining arguments are kept as a tuple in + the __extra__ field. + + Details: + + - It's an error to call `Annotated` with less than two arguments. + - Nested Annotated are flattened:: + + Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] + + - Instantiating an annotated type is equivalent to instantiating the + underlying type:: + + Annotated[C, Ann1](5) == C(5) + + - Annotated can be used as a generic type alias:: + + Optimized = Annotated[T, runtime.Optimize()] + Optimized[int] == Annotated[int, runtime.Optimize()] + + OptimizedList = Annotated[List[T], runtime.Optimize()] + OptimizedList[int] == Annotated[List[int], runtime.Optimize()] + """ + + __slots__ = () + + def __new__(cls, *args, **kwargs): + raise TypeError("Type Annotated cannot be instantiated.") + + @typing._tp_cache + def __class_getitem__(cls, params): + if not isinstance(params, tuple) or len(params) < 2: + raise TypeError("Annotated[...] should be used " + "with at least two arguments (a type and an " + "annotation).") + allowed_special_forms = (ClassVar, Final) + if get_origin(params[0]) in allowed_special_forms: + origin = params[0] + else: + msg = "Annotated[t, ...]: t must be a type." + origin = typing._type_check(params[0], msg) + metadata = tuple(params[1:]) + return _AnnotatedAlias(origin, metadata) + + def __init_subclass__(cls, *args, **kwargs): + raise TypeError( + f"Cannot subclass {cls.__module__}.Annotated" + ) + +# Python 3.8 has get_origin() and get_args() but those implementations aren't +# Annotated-aware, so we can't use those. Python 3.9's versions don't support +# ParamSpecArgs and ParamSpecKwargs, so only Python 3.10's versions will do. +if sys.version_info[:2] >= (3, 10): + get_origin = typing.get_origin + get_args = typing.get_args +# 3.7-3.9 +else: + try: + # 3.9+ + from typing import _BaseGenericAlias + except ImportError: + _BaseGenericAlias = typing._GenericAlias + try: + # 3.9+ + from typing import GenericAlias as _typing_GenericAlias + except ImportError: + _typing_GenericAlias = typing._GenericAlias + + def get_origin(tp): + """Get the unsubscripted version of a type. + + This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar + and Annotated. Return None for unsupported types. Examples:: + + get_origin(Literal[42]) is Literal + get_origin(int) is None + get_origin(ClassVar[int]) is ClassVar + get_origin(Generic) is Generic + get_origin(Generic[T]) is Generic + get_origin(Union[T, int]) is Union + get_origin(List[Tuple[T, T]][int]) == list + get_origin(P.args) is P + """ + if isinstance(tp, _AnnotatedAlias): + return Annotated + if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias, _BaseGenericAlias, + ParamSpecArgs, ParamSpecKwargs)): + return tp.__origin__ + if tp is typing.Generic: + return typing.Generic + return None + + def get_args(tp): + """Get type arguments with all substitutions performed. + + For unions, basic simplifications used by Union constructor are performed. + Examples:: + get_args(Dict[str, int]) == (str, int) + get_args(int) == () + get_args(Union[int, Union[T, int], str][int]) == (int, str) + get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) + get_args(Callable[[], T][int]) == ([], int) + """ + if isinstance(tp, _AnnotatedAlias): + return (tp.__origin__,) + tp.__metadata__ + if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias)): + if getattr(tp, "_special", False): + return () + res = tp.__args__ + if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis: + res = (list(res[:-1]), res[-1]) + return res + return () + + +# 3.10+ +if hasattr(typing, 'TypeAlias'): + TypeAlias = typing.TypeAlias +# 3.9 +elif sys.version_info[:2] >= (3, 9): + class _TypeAliasForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + @_TypeAliasForm + def TypeAlias(self, parameters): + """Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example above. + """ + raise TypeError(f"{self} is not subscriptable") +# 3.7-3.8 +else: + class _TypeAliasForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + TypeAlias = _TypeAliasForm('TypeAlias', + doc="""Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example + above.""") + + +class _DefaultMixin: + """Mixin for TypeVarLike defaults.""" + + __slots__ = () + + def __init__(self, default): + if isinstance(default, (tuple, list)): + self.__default__ = tuple((typing._type_check(d, "Default must be a type") + for d in default)) + elif default: + self.__default__ = typing._type_check(default, "Default must be a type") + else: + self.__default__ = None + + +# Add default and infer_variance parameters from PEP 696 and 695 +class TypeVar(typing.TypeVar, _DefaultMixin, _root=True): + """Type variable.""" + + __module__ = 'typing' + + def __init__(self, name, *constraints, bound=None, + covariant=False, contravariant=False, + default=None, infer_variance=False): + super().__init__(name, *constraints, bound=bound, covariant=covariant, + contravariant=contravariant) + _DefaultMixin.__init__(self, default) + self.__infer_variance__ = infer_variance + + # for pickling: + try: + def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + def_mod = None + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + +# Python 3.10+ has PEP 612 +if hasattr(typing, 'ParamSpecArgs'): + ParamSpecArgs = typing.ParamSpecArgs + ParamSpecKwargs = typing.ParamSpecKwargs +# 3.7-3.9 +else: + class _Immutable: + """Mixin to indicate that object should not be copied.""" + __slots__ = () + + def __copy__(self): + return self + + def __deepcopy__(self, memo): + return self + + class ParamSpecArgs(_Immutable): + """The args for a ParamSpec object. + + Given a ParamSpec object P, P.args is an instance of ParamSpecArgs. + + ParamSpecArgs objects have a reference back to their ParamSpec: + + P.args.__origin__ is P + + This type is meant for runtime introspection and has no special meaning to + static type checkers. + """ + def __init__(self, origin): + self.__origin__ = origin + + def __repr__(self): + return f"{self.__origin__.__name__}.args" + + def __eq__(self, other): + if not isinstance(other, ParamSpecArgs): + return NotImplemented + return self.__origin__ == other.__origin__ + + class ParamSpecKwargs(_Immutable): + """The kwargs for a ParamSpec object. + + Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs. + + ParamSpecKwargs objects have a reference back to their ParamSpec: + + P.kwargs.__origin__ is P + + This type is meant for runtime introspection and has no special meaning to + static type checkers. + """ + def __init__(self, origin): + self.__origin__ = origin + + def __repr__(self): + return f"{self.__origin__.__name__}.kwargs" + + def __eq__(self, other): + if not isinstance(other, ParamSpecKwargs): + return NotImplemented + return self.__origin__ == other.__origin__ + +# 3.10+ +if hasattr(typing, 'ParamSpec'): + + # Add default Parameter - PEP 696 + class ParamSpec(typing.ParamSpec, _DefaultMixin, _root=True): + """Parameter specification variable.""" + + __module__ = 'typing' + + def __init__(self, name, *, bound=None, covariant=False, contravariant=False, + default=None): + super().__init__(name, bound=bound, covariant=covariant, + contravariant=contravariant) + _DefaultMixin.__init__(self, default) + + # for pickling: + try: + def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + def_mod = None + if def_mod != 'typing_extensions': + self.__module__ = def_mod + +# 3.7-3.9 +else: + + # Inherits from list as a workaround for Callable checks in Python < 3.9.2. + class ParamSpec(list, _DefaultMixin): + """Parameter specification variable. + + Usage:: + + P = ParamSpec('P') + + Parameter specification variables exist primarily for the benefit of static + type checkers. They are used to forward the parameter types of one + callable to another callable, a pattern commonly found in higher order + functions and decorators. They are only valid when used in ``Concatenate``, + or s the first argument to ``Callable``. In Python 3.10 and higher, + they are also supported in user-defined Generics at runtime. + See class Generic for more information on generic types. An + example for annotating a decorator:: + + T = TypeVar('T') + P = ParamSpec('P') + + def add_logging(f: Callable[P, T]) -> Callable[P, T]: + '''A type-safe decorator to add logging to a function.''' + def inner(*args: P.args, **kwargs: P.kwargs) -> T: + logging.info(f'{f.__name__} was called') + return f(*args, **kwargs) + return inner + + @add_logging + def add_two(x: float, y: float) -> float: + '''Add two numbers together.''' + return x + y + + Parameter specification variables defined with covariant=True or + contravariant=True can be used to declare covariant or contravariant + generic types. These keyword arguments are valid, but their actual semantics + are yet to be decided. See PEP 612 for details. + + Parameter specification variables can be introspected. e.g.: + + P.__name__ == 'T' + P.__bound__ == None + P.__covariant__ == False + P.__contravariant__ == False + + Note that only parameter specification variables defined in global scope can + be pickled. + """ + + # Trick Generic __parameters__. + __class__ = typing.TypeVar + + @property + def args(self): + return ParamSpecArgs(self) + + @property + def kwargs(self): + return ParamSpecKwargs(self) + + def __init__(self, name, *, bound=None, covariant=False, contravariant=False, + default=None): + super().__init__([self]) + self.__name__ = name + self.__covariant__ = bool(covariant) + self.__contravariant__ = bool(contravariant) + if bound: + self.__bound__ = typing._type_check(bound, 'Bound must be a type.') + else: + self.__bound__ = None + _DefaultMixin.__init__(self, default) + + # for pickling: + try: + def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + def_mod = None + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + def __repr__(self): + if self.__covariant__: + prefix = '+' + elif self.__contravariant__: + prefix = '-' + else: + prefix = '~' + return prefix + self.__name__ + + def __hash__(self): + return object.__hash__(self) + + def __eq__(self, other): + return self is other + + def __reduce__(self): + return self.__name__ + + # Hack to get typing._type_check to pass. + def __call__(self, *args, **kwargs): + pass + + +# 3.7-3.9 +if not hasattr(typing, 'Concatenate'): + # Inherits from list as a workaround for Callable checks in Python < 3.9.2. + class _ConcatenateGenericAlias(list): + + # Trick Generic into looking into this for __parameters__. + __class__ = typing._GenericAlias + + # Flag in 3.8. + _special = False + + def __init__(self, origin, args): + super().__init__(args) + self.__origin__ = origin + self.__args__ = args + + def __repr__(self): + _type_repr = typing._type_repr + return (f'{_type_repr(self.__origin__)}' + f'[{", ".join(_type_repr(arg) for arg in self.__args__)}]') + + def __hash__(self): + return hash((self.__origin__, self.__args__)) + + # Hack to get typing._type_check to pass in Generic. + def __call__(self, *args, **kwargs): + pass + + @property + def __parameters__(self): + return tuple( + tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec)) + ) + + +# 3.7-3.9 +@typing._tp_cache +def _concatenate_getitem(self, parameters): + if parameters == (): + raise TypeError("Cannot take a Concatenate of no types.") + if not isinstance(parameters, tuple): + parameters = (parameters,) + if not isinstance(parameters[-1], ParamSpec): + raise TypeError("The last parameter to Concatenate should be a " + "ParamSpec variable.") + msg = "Concatenate[arg, ...]: each arg must be a type." + parameters = tuple(typing._type_check(p, msg) for p in parameters) + return _ConcatenateGenericAlias(self, parameters) + + +# 3.10+ +if hasattr(typing, 'Concatenate'): + Concatenate = typing.Concatenate + _ConcatenateGenericAlias = typing._ConcatenateGenericAlias # noqa +# 3.9 +elif sys.version_info[:2] >= (3, 9): + @_TypeAliasForm + def Concatenate(self, parameters): + """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a + higher order function which adds, removes or transforms parameters of a + callable. + + For example:: + + Callable[Concatenate[int, P], int] + + See PEP 612 for detailed information. + """ + return _concatenate_getitem(self, parameters) +# 3.7-8 +else: + class _ConcatenateForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + return _concatenate_getitem(self, parameters) + + Concatenate = _ConcatenateForm( + 'Concatenate', + doc="""Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a + higher order function which adds, removes or transforms parameters of a + callable. + + For example:: + + Callable[Concatenate[int, P], int] + + See PEP 612 for detailed information. + """) + +# 3.10+ +if hasattr(typing, 'TypeGuard'): + TypeGuard = typing.TypeGuard +# 3.9 +elif sys.version_info[:2] >= (3, 9): + class _TypeGuardForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + @_TypeGuardForm + def TypeGuard(self, parameters): + """Special typing form used to annotate the return type of a user-defined + type guard function. ``TypeGuard`` only accepts a single type argument. + At runtime, functions marked this way should return a boolean. + + ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static + type checkers to determine a more precise type of an expression within a + program's code flow. Usually type narrowing is done by analyzing + conditional code flow and applying the narrowing to a block of code. The + conditional expression here is sometimes referred to as a "type guard". + + Sometimes it would be convenient to use a user-defined boolean function + as a type guard. Such a function should use ``TypeGuard[...]`` as its + return type to alert static type checkers to this intention. + + Using ``-> TypeGuard`` tells the static type checker that for a given + function: + + 1. The return value is a boolean. + 2. If the return value is ``True``, the type of its argument + is the type inside ``TypeGuard``. + + For example:: + + def is_str(val: Union[str, float]): + # "isinstance" type guard + if isinstance(val, str): + # Type of ``val`` is narrowed to ``str`` + ... + else: + # Else, type of ``val`` is narrowed to ``float``. + ... + + Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower + form of ``TypeA`` (it can even be a wider form) and this may lead to + type-unsafe results. The main reason is to allow for things like + narrowing ``List[object]`` to ``List[str]`` even though the latter is not + a subtype of the former, since ``List`` is invariant. The responsibility of + writing type-safe type guards is left to the user. + + ``TypeGuard`` also works with type variables. For more information, see + PEP 647 (User-Defined Type Guards). + """ + item = typing._type_check(parameters, f'{self} accepts only a single type.') + return typing._GenericAlias(self, (item,)) +# 3.7-3.8 +else: + class _TypeGuardForm(typing._SpecialForm, _root=True): + + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type') + return typing._GenericAlias(self, (item,)) + + TypeGuard = _TypeGuardForm( + 'TypeGuard', + doc="""Special typing form used to annotate the return type of a user-defined + type guard function. ``TypeGuard`` only accepts a single type argument. + At runtime, functions marked this way should return a boolean. + + ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static + type checkers to determine a more precise type of an expression within a + program's code flow. Usually type narrowing is done by analyzing + conditional code flow and applying the narrowing to a block of code. The + conditional expression here is sometimes referred to as a "type guard". + + Sometimes it would be convenient to use a user-defined boolean function + as a type guard. Such a function should use ``TypeGuard[...]`` as its + return type to alert static type checkers to this intention. + + Using ``-> TypeGuard`` tells the static type checker that for a given + function: + + 1. The return value is a boolean. + 2. If the return value is ``True``, the type of its argument + is the type inside ``TypeGuard``. + + For example:: + + def is_str(val: Union[str, float]): + # "isinstance" type guard + if isinstance(val, str): + # Type of ``val`` is narrowed to ``str`` + ... + else: + # Else, type of ``val`` is narrowed to ``float``. + ... + + Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower + form of ``TypeA`` (it can even be a wider form) and this may lead to + type-unsafe results. The main reason is to allow for things like + narrowing ``List[object]`` to ``List[str]`` even though the latter is not + a subtype of the former, since ``List`` is invariant. The responsibility of + writing type-safe type guards is left to the user. + + ``TypeGuard`` also works with type variables. For more information, see + PEP 647 (User-Defined Type Guards). + """) + + +# Vendored from cpython typing._SpecialFrom +class _SpecialForm(typing._Final, _root=True): + __slots__ = ('_name', '__doc__', '_getitem') + + def __init__(self, getitem): + self._getitem = getitem + self._name = getitem.__name__ + self.__doc__ = getitem.__doc__ + + def __getattr__(self, item): + if item in {'__name__', '__qualname__'}: + return self._name + + raise AttributeError(item) + + def __mro_entries__(self, bases): + raise TypeError(f"Cannot subclass {self!r}") + + def __repr__(self): + return f'typing_extensions.{self._name}' + + def __reduce__(self): + return self._name + + def __call__(self, *args, **kwds): + raise TypeError(f"Cannot instantiate {self!r}") + + def __or__(self, other): + return typing.Union[self, other] + + def __ror__(self, other): + return typing.Union[other, self] + + def __instancecheck__(self, obj): + raise TypeError(f"{self} cannot be used with isinstance()") + + def __subclasscheck__(self, cls): + raise TypeError(f"{self} cannot be used with issubclass()") + + @typing._tp_cache + def __getitem__(self, parameters): + return self._getitem(self, parameters) + + +if hasattr(typing, "LiteralString"): + LiteralString = typing.LiteralString +else: + @_SpecialForm + def LiteralString(self, params): + """Represents an arbitrary literal string. + + Example:: + + from typing_extensions import LiteralString + + def query(sql: LiteralString) -> ...: + ... + + query("SELECT * FROM table") # ok + query(f"SELECT * FROM {input()}") # not ok + + See PEP 675 for details. + + """ + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, "Self"): + Self = typing.Self +else: + @_SpecialForm + def Self(self, params): + """Used to spell the type of "self" in classes. + + Example:: + + from typing import Self + + class ReturnsSelf: + def parse(self, data: bytes) -> Self: + ... + return self + + """ + + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, "Never"): + Never = typing.Never +else: + @_SpecialForm + def Never(self, params): + """The bottom type, a type that has no members. + + This can be used to define a function that should never be + called, or a function that never returns:: + + from typing_extensions import Never + + def never_call_me(arg: Never) -> None: + pass + + def int_or_str(arg: int | str) -> None: + never_call_me(arg) # type checker error + match arg: + case int(): + print("It's an int") + case str(): + print("It's a str") + case _: + never_call_me(arg) # ok, arg is of type Never + + """ + + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, 'Required'): + Required = typing.Required + NotRequired = typing.NotRequired +elif sys.version_info[:2] >= (3, 9): + class _ExtensionsSpecialForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + @_ExtensionsSpecialForm + def Required(self, parameters): + """A special typing construct to mark a key of a total=False TypedDict + as required. For example: + + class Movie(TypedDict, total=False): + title: Required[str] + year: int + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + + There is no runtime checking that a required key is actually provided + when instantiating a related TypedDict. + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + @_ExtensionsSpecialForm + def NotRequired(self, parameters): + """A special typing construct to mark a key of a TypedDict as + potentially missing. For example: + + class Movie(TypedDict): + title: str + year: NotRequired[int] + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + +else: + class _RequiredForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + Required = _RequiredForm( + 'Required', + doc="""A special typing construct to mark a key of a total=False TypedDict + as required. For example: + + class Movie(TypedDict, total=False): + title: Required[str] + year: int + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + + There is no runtime checking that a required key is actually provided + when instantiating a related TypedDict. + """) + NotRequired = _RequiredForm( + 'NotRequired', + doc="""A special typing construct to mark a key of a TypedDict as + potentially missing. For example: + + class Movie(TypedDict): + title: str + year: NotRequired[int] + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + """) + + +if hasattr(typing, "Unpack"): # 3.11+ + Unpack = typing.Unpack +elif sys.version_info[:2] >= (3, 9): + class _UnpackSpecialForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + class _UnpackAlias(typing._GenericAlias, _root=True): + __class__ = typing.TypeVar + + @_UnpackSpecialForm + def Unpack(self, parameters): + """A special typing construct to unpack a variadic type. For example: + + Shape = TypeVarTuple('Shape') + Batch = NewType('Batch', int) + + def add_batch_axis( + x: Array[Unpack[Shape]] + ) -> Array[Batch, Unpack[Shape]]: ... + + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return _UnpackAlias(self, (item,)) + + def _is_unpack(obj): + return isinstance(obj, _UnpackAlias) + +else: + class _UnpackAlias(typing._GenericAlias, _root=True): + __class__ = typing.TypeVar + + class _UnpackForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type.') + return _UnpackAlias(self, (item,)) + + Unpack = _UnpackForm( + 'Unpack', + doc="""A special typing construct to unpack a variadic type. For example: + + Shape = TypeVarTuple('Shape') + Batch = NewType('Batch', int) + + def add_batch_axis( + x: Array[Unpack[Shape]] + ) -> Array[Batch, Unpack[Shape]]: ... + + """) + + def _is_unpack(obj): + return isinstance(obj, _UnpackAlias) + + +if hasattr(typing, "TypeVarTuple"): # 3.11+ + + # Add default Parameter - PEP 696 + class TypeVarTuple(typing.TypeVarTuple, _DefaultMixin, _root=True): + """Type variable tuple.""" + + def __init__(self, name, *, default=None): + super().__init__(name) + _DefaultMixin.__init__(self, default) + + # for pickling: + try: + def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + def_mod = None + if def_mod != 'typing_extensions': + self.__module__ = def_mod + +else: + class TypeVarTuple(_DefaultMixin): + """Type variable tuple. + + Usage:: + + Ts = TypeVarTuple('Ts') + + In the same way that a normal type variable is a stand-in for a single + type such as ``int``, a type variable *tuple* is a stand-in for a *tuple* + type such as ``Tuple[int, str]``. + + Type variable tuples can be used in ``Generic`` declarations. + Consider the following example:: + + class Array(Generic[*Ts]): ... + + The ``Ts`` type variable tuple here behaves like ``tuple[T1, T2]``, + where ``T1`` and ``T2`` are type variables. To use these type variables + as type parameters of ``Array``, we must *unpack* the type variable tuple using + the star operator: ``*Ts``. The signature of ``Array`` then behaves + as if we had simply written ``class Array(Generic[T1, T2]): ...``. + In contrast to ``Generic[T1, T2]``, however, ``Generic[*Shape]`` allows + us to parameterise the class with an *arbitrary* number of type parameters. + + Type variable tuples can be used anywhere a normal ``TypeVar`` can. + This includes class definitions, as shown above, as well as function + signatures and variable annotations:: + + class Array(Generic[*Ts]): + + def __init__(self, shape: Tuple[*Ts]): + self._shape: Tuple[*Ts] = shape + + def get_shape(self) -> Tuple[*Ts]: + return self._shape + + shape = (Height(480), Width(640)) + x: Array[Height, Width] = Array(shape) + y = abs(x) # Inferred type is Array[Height, Width] + z = x + x # ... is Array[Height, Width] + x.get_shape() # ... is tuple[Height, Width] + + """ + + # Trick Generic __parameters__. + __class__ = typing.TypeVar + + def __iter__(self): + yield self.__unpacked__ + + def __init__(self, name, *, default=None): + self.__name__ = name + _DefaultMixin.__init__(self, default) + + # for pickling: + try: + def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + def_mod = None + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + self.__unpacked__ = Unpack[self] + + def __repr__(self): + return self.__name__ + + def __hash__(self): + return object.__hash__(self) + + def __eq__(self, other): + return self is other + + def __reduce__(self): + return self.__name__ + + def __init_subclass__(self, *args, **kwds): + if '_root' not in kwds: + raise TypeError("Cannot subclass special typing classes") + + +if hasattr(typing, "reveal_type"): + reveal_type = typing.reveal_type +else: + def reveal_type(__obj: T) -> T: + """Reveal the inferred type of a variable. + + When a static type checker encounters a call to ``reveal_type()``, + it will emit the inferred type of the argument:: + + x: int = 1 + reveal_type(x) + + Running a static type checker (e.g., ``mypy``) on this example + will produce output similar to 'Revealed type is "builtins.int"'. + + At runtime, the function prints the runtime type of the + argument and returns it unchanged. + + """ + print(f"Runtime type is {type(__obj).__name__!r}", file=sys.stderr) + return __obj + + +if hasattr(typing, "assert_never"): + assert_never = typing.assert_never +else: + def assert_never(__arg: Never) -> Never: + """Assert to the type checker that a line of code is unreachable. + + Example:: + + def int_or_str(arg: int | str) -> None: + match arg: + case int(): + print("It's an int") + case str(): + print("It's a str") + case _: + assert_never(arg) + + If a type checker finds that a call to assert_never() is + reachable, it will emit an error. + + At runtime, this throws an exception when called. + + """ + raise AssertionError("Expected code to be unreachable") + + +if hasattr(typing, 'dataclass_transform'): + dataclass_transform = typing.dataclass_transform +else: + def dataclass_transform( + *, + eq_default: bool = True, + order_default: bool = False, + kw_only_default: bool = False, + field_specifiers: typing.Tuple[ + typing.Union[typing.Type[typing.Any], typing.Callable[..., typing.Any]], + ... + ] = (), + **kwargs: typing.Any, + ) -> typing.Callable[[T], T]: + """Decorator that marks a function, class, or metaclass as providing + dataclass-like behavior. + + Example: + + from typing_extensions import dataclass_transform + + _T = TypeVar("_T") + + # Used on a decorator function + @dataclass_transform() + def create_model(cls: type[_T]) -> type[_T]: + ... + return cls + + @create_model + class CustomerModel: + id: int + name: str + + # Used on a base class + @dataclass_transform() + class ModelBase: ... + + class CustomerModel(ModelBase): + id: int + name: str + + # Used on a metaclass + @dataclass_transform() + class ModelMeta(type): ... + + class ModelBase(metaclass=ModelMeta): ... + + class CustomerModel(ModelBase): + id: int + name: str + + Each of the ``CustomerModel`` classes defined in this example will now + behave similarly to a dataclass created with the ``@dataclasses.dataclass`` + decorator. For example, the type checker will synthesize an ``__init__`` + method. + + The arguments to this decorator can be used to customize this behavior: + - ``eq_default`` indicates whether the ``eq`` parameter is assumed to be + True or False if it is omitted by the caller. + - ``order_default`` indicates whether the ``order`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``kw_only_default`` indicates whether the ``kw_only`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``field_specifiers`` specifies a static list of supported classes + or functions that describe fields, similar to ``dataclasses.field()``. + + At runtime, this decorator records its arguments in the + ``__dataclass_transform__`` attribute on the decorated object. + + See PEP 681 for details. + + """ + def decorator(cls_or_fn): + cls_or_fn.__dataclass_transform__ = { + "eq_default": eq_default, + "order_default": order_default, + "kw_only_default": kw_only_default, + "field_specifiers": field_specifiers, + "kwargs": kwargs, + } + return cls_or_fn + return decorator + + +if hasattr(typing, "override"): + override = typing.override +else: + _F = typing.TypeVar("_F", bound=typing.Callable[..., typing.Any]) + + def override(__arg: _F) -> _F: + """Indicate that a method is intended to override a method in a base class. + + Usage: + + class Base: + def method(self) -> None: ... + pass + + class Child(Base): + @override + def method(self) -> None: + super().method() + + When this decorator is applied to a method, the type checker will + validate that it overrides a method with the same name on a base class. + This helps prevent bugs that may occur when a base class is changed + without an equivalent change to a child class. + + See PEP 698 for details. + + """ + return __arg + + +# We have to do some monkey patching to deal with the dual nature of +# Unpack/TypeVarTuple: +# - We want Unpack to be a kind of TypeVar so it gets accepted in +# Generic[Unpack[Ts]] +# - We want it to *not* be treated as a TypeVar for the purposes of +# counting generic parameters, so that when we subscript a generic, +# the runtime doesn't try to substitute the Unpack with the subscripted type. +if not hasattr(typing, "TypeVarTuple"): + typing._collect_type_vars = _collect_type_vars + typing._check_generic = _check_generic + + +# Backport typing.NamedTuple as it exists in Python 3.11. +# In 3.11, the ability to define generic `NamedTuple`s was supported. +# This was explicitly disallowed in 3.9-3.10, and only half-worked in <=3.8. +if sys.version_info >= (3, 11): + NamedTuple = typing.NamedTuple +else: + def _caller(): + try: + return sys._getframe(2).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): # For platforms without _getframe() + return None + + def _make_nmtuple(name, types, module, defaults=()): + fields = [n for n, t in types] + annotations = {n: typing._type_check(t, f"field {n} annotation must be a type") + for n, t in types} + nm_tpl = collections.namedtuple(name, fields, + defaults=defaults, module=module) + nm_tpl.__annotations__ = nm_tpl.__new__.__annotations__ = annotations + # The `_field_types` attribute was removed in 3.9; + # in earlier versions, it is the same as the `__annotations__` attribute + if sys.version_info < (3, 9): + nm_tpl._field_types = annotations + return nm_tpl + + _prohibited_namedtuple_fields = typing._prohibited + _special_namedtuple_fields = frozenset({'__module__', '__name__', '__annotations__'}) + + class _NamedTupleMeta(type): + def __new__(cls, typename, bases, ns): + assert _NamedTuple in bases + for base in bases: + if base is not _NamedTuple and base is not typing.Generic: + raise TypeError( + 'can only inherit from a NamedTuple type and Generic') + bases = tuple(tuple if base is _NamedTuple else base for base in bases) + types = ns.get('__annotations__', {}) + default_names = [] + for field_name in types: + if field_name in ns: + default_names.append(field_name) + elif default_names: + raise TypeError(f"Non-default namedtuple field {field_name} " + f"cannot follow default field" + f"{'s' if len(default_names) > 1 else ''} " + f"{', '.join(default_names)}") + nm_tpl = _make_nmtuple( + typename, types.items(), + defaults=[ns[n] for n in default_names], + module=ns['__module__'] + ) + nm_tpl.__bases__ = bases + if typing.Generic in bases: + class_getitem = typing.Generic.__class_getitem__.__func__ + nm_tpl.__class_getitem__ = classmethod(class_getitem) + # update from user namespace without overriding special namedtuple attributes + for key in ns: + if key in _prohibited_namedtuple_fields: + raise AttributeError("Cannot overwrite NamedTuple attribute " + key) + elif key not in _special_namedtuple_fields and key not in nm_tpl._fields: + setattr(nm_tpl, key, ns[key]) + if typing.Generic in bases: + nm_tpl.__init_subclass__() + return nm_tpl + + def NamedTuple(__typename, __fields=None, **kwargs): + if __fields is None: + __fields = kwargs.items() + elif kwargs: + raise TypeError("Either list of fields or keywords" + " can be provided to NamedTuple, not both") + return _make_nmtuple(__typename, __fields, module=_caller()) + + NamedTuple.__doc__ = typing.NamedTuple.__doc__ + _NamedTuple = type.__new__(_NamedTupleMeta, 'NamedTuple', (), {}) + + # On 3.8+, alter the signature so that it matches typing.NamedTuple. + # The signature of typing.NamedTuple on >=3.8 is invalid syntax in Python 3.7, + # so just leave the signature as it is on 3.7. + if sys.version_info >= (3, 8): + NamedTuple.__text_signature__ = '(typename, fields=None, /, **kwargs)' + + def _namedtuple_mro_entries(bases): + assert NamedTuple in bases + return (_NamedTuple,) + + NamedTuple.__mro_entries__ = _namedtuple_mro_entries diff --git a/venv/Lib/site-packages/wrapt-1.12.1-py3.9.egg-info/PKG-INFO b/venv/Lib/site-packages/wrapt-1.12.1-py3.9.egg-info/PKG-INFO new file mode 100644 index 0000000..dc8a594 --- /dev/null +++ b/venv/Lib/site-packages/wrapt-1.12.1-py3.9.egg-info/PKG-INFO @@ -0,0 +1,167 @@ +Metadata-Version: 2.1 +Name: wrapt +Version: 1.12.1 +Summary: Module for decorators, wrappers and monkey patching. +Home-page: https://github.com/GrahamDumpleton/wrapt +Author: Graham Dumpleton +Author-email: Graham.Dumpleton@gmail.com +License: BSD +Classifier: Development Status :: 5 - Production/Stable +Classifier: License :: OSI Approved :: BSD License +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +License-File: LICENSE + +wrapt +===== + +|Travis| |AppVeyor| |Coveralls| |PyPI| + +The aim of the **wrapt** module is to provide a transparent object proxy +for Python, which can be used as the basis for the construction of function +wrappers and decorator functions. + +The **wrapt** module focuses very much on correctness. It therefore goes +way beyond existing mechanisms such as ``functools.wraps()`` to ensure that +decorators preserve introspectability, signatures, type checking abilities +etc. The decorators that can be constructed using this module will work in +far more scenarios than typical decorators and provide more predictable and +consistent behaviour. + +To ensure that the overhead is as minimal as possible, a C extension module +is used for performance critical components. An automatic fallback to a +pure Python implementation is also provided where a target system does not +have a compiler to allow the C extension to be compiled. + +Documentation +------------- + +For further information on the **wrapt** module see: + +* http://wrapt.readthedocs.org/ + +Quick Start +----------- + +To implement your decorator you need to first define a wrapper function. +This will be called each time a decorated function is called. The wrapper +function needs to take four positional arguments: + +* ``wrapped`` - The wrapped function which in turns needs to be called by your wrapper function. +* ``instance`` - The object to which the wrapped function was bound when it was called. +* ``args`` - The list of positional arguments supplied when the decorated function was called. +* ``kwargs`` - The dictionary of keyword arguments supplied when the decorated function was called. + +The wrapper function would do whatever it needs to, but would usually in +turn call the wrapped function that is passed in via the ``wrapped`` +argument. + +The decorator ``@wrapt.decorator`` then needs to be applied to the wrapper +function to convert it into a decorator which can in turn be applied to +other functions. + +:: + + import wrapt + + @wrapt.decorator + def pass_through(wrapped, instance, args, kwargs): + return wrapped(*args, **kwargs) + + @pass_through + def function(): + pass + +If you wish to implement a decorator which accepts arguments, then wrap the +definition of the decorator in a function closure. Any arguments supplied +to the outer function when the decorator is applied, will be available to +the inner wrapper when the wrapped function is called. + +:: + + import wrapt + + def with_arguments(myarg1, myarg2): + @wrapt.decorator + def wrapper(wrapped, instance, args, kwargs): + return wrapped(*args, **kwargs) + return wrapper + + @with_arguments(1, 2) + def function(): + pass + +When applied to a normal function or static method, the wrapper function +when called will be passed ``None`` as the ``instance`` argument. + +When applied to an instance method, the wrapper function when called will +be passed the instance of the class the method is being called on as the +``instance`` argument. This will be the case even when the instance method +was called explicitly via the class and the instance passed as the first +argument. That is, the instance will never be passed as part of ``args``. + +When applied to a class method, the wrapper function when called will be +passed the class type as the ``instance`` argument. + +When applied to a class, the wrapper function when called will be passed +``None`` as the ``instance`` argument. The ``wrapped`` argument in this +case will be the class. + +The above rules can be summarised with the following example. + +:: + + import inspect + + @wrapt.decorator + def universal(wrapped, instance, args, kwargs): + if instance is None: + if inspect.isclass(wrapped): + # Decorator was applied to a class. + return wrapped(*args, **kwargs) + else: + # Decorator was applied to a function or staticmethod. + return wrapped(*args, **kwargs) + else: + if inspect.isclass(instance): + # Decorator was applied to a classmethod. + return wrapped(*args, **kwargs) + else: + # Decorator was applied to an instancemethod. + return wrapped(*args, **kwargs) + +Using these checks it is therefore possible to create a universal decorator +that can be applied in all situations. It is no longer necessary to create +different variants of decorators for normal functions and instance methods, +or use additional wrappers to convert a function decorator into one that +will work for instance methods. + +In all cases, the wrapped function passed to the wrapper function is called +in the same way, with ``args`` and ``kwargs`` being passed. The +``instance`` argument doesn't need to be used in calling the wrapped +function. + +Repository +---------- + +Full source code for the **wrapt** module, including documentation files +and unit tests, can be obtained from github. + +* https://github.com/GrahamDumpleton/wrapt + +.. |Travis| image:: https://travis-ci.org/GrahamDumpleton/wrapt.svg?branch=develop + :target: https://travis-ci.org/GrahamDumpleton/wrapt +.. |Appveyor| image:: https://ci.appveyor.com/api/projects/status/32r7s2skrgm9ubva?svg=true + :target: https://ci.appveyor.com/project/GrahamDumpleton/wrapt/branch/develop +.. |Coveralls| image:: https://img.shields.io/coveralls/GrahamDumpleton/wrapt/develop.svg + :target: https://coveralls.io/github/GrahamDumpleton/wrapt?branch=develop +.. |PyPI| image:: https://img.shields.io/pypi/v/wrapt.svg + :target: https://pypi.python.org/pypi/wrapt diff --git a/venv/Lib/site-packages/wrapt-1.12.1-py3.9.egg-info/SOURCES.txt b/venv/Lib/site-packages/wrapt-1.12.1-py3.9.egg-info/SOURCES.txt new file mode 100644 index 0000000..ceadf14 --- /dev/null +++ b/venv/Lib/site-packages/wrapt-1.12.1-py3.9.egg-info/SOURCES.txt @@ -0,0 +1,11 @@ +LICENSE +README.rst +setup.py +src/wrapt/__init__.py +src/wrapt/decorators.py +src/wrapt/importer.py +src/wrapt/wrappers.py +src/wrapt.egg-info/PKG-INFO +src/wrapt.egg-info/SOURCES.txt +src/wrapt.egg-info/dependency_links.txt +src/wrapt.egg-info/top_level.txt \ No newline at end of file diff --git a/venv/Lib/site-packages/wrapt-1.12.1-py3.9.egg-info/dependency_links.txt b/venv/Lib/site-packages/wrapt-1.12.1-py3.9.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/venv/Lib/site-packages/wrapt-1.12.1-py3.9.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/venv/Lib/site-packages/wrapt-1.12.1-py3.9.egg-info/installed-files.txt b/venv/Lib/site-packages/wrapt-1.12.1-py3.9.egg-info/installed-files.txt new file mode 100644 index 0000000..a6c4d96 --- /dev/null +++ b/venv/Lib/site-packages/wrapt-1.12.1-py3.9.egg-info/installed-files.txt @@ -0,0 +1,12 @@ +..\wrapt\__init__.py +..\wrapt\__pycache__\__init__.cpython-39.pyc +..\wrapt\__pycache__\decorators.cpython-39.pyc +..\wrapt\__pycache__\importer.cpython-39.pyc +..\wrapt\__pycache__\wrappers.cpython-39.pyc +..\wrapt\decorators.py +..\wrapt\importer.py +..\wrapt\wrappers.py +PKG-INFO +SOURCES.txt +dependency_links.txt +top_level.txt diff --git a/venv/Lib/site-packages/wrapt-1.12.1-py3.9.egg-info/top_level.txt b/venv/Lib/site-packages/wrapt-1.12.1-py3.9.egg-info/top_level.txt new file mode 100644 index 0000000..ba11553 --- /dev/null +++ b/venv/Lib/site-packages/wrapt-1.12.1-py3.9.egg-info/top_level.txt @@ -0,0 +1 @@ +wrapt diff --git a/venv/Lib/site-packages/wrapt/__init__.py b/venv/Lib/site-packages/wrapt/__init__.py new file mode 100644 index 0000000..7be739b --- /dev/null +++ b/venv/Lib/site-packages/wrapt/__init__.py @@ -0,0 +1,16 @@ +__version_info__ = ('1', '12', '1') +__version__ = '.'.join(__version_info__) + +from .wrappers import (ObjectProxy, CallableObjectProxy, FunctionWrapper, + BoundFunctionWrapper, WeakFunctionProxy, PartialCallableObjectProxy, + resolve_path, apply_patch, wrap_object, wrap_object_attribute, + function_wrapper, wrap_function_wrapper, patch_function_wrapper, + transient_function_wrapper) + +from .decorators import (adapter_factory, AdapterFactory, decorator, + synchronized) + +from .importer import (register_post_import_hook, when_imported, + notify_module_loaded, discover_post_import_hooks) + +from inspect import getcallargs diff --git a/venv/Lib/site-packages/wrapt/decorators.py b/venv/Lib/site-packages/wrapt/decorators.py new file mode 100644 index 0000000..506303d --- /dev/null +++ b/venv/Lib/site-packages/wrapt/decorators.py @@ -0,0 +1,516 @@ +"""This module implements decorators for implementing other decorators +as well as some commonly used decorators. + +""" + +import sys + +PY2 = sys.version_info[0] == 2 + +if PY2: + string_types = basestring, + + def exec_(_code_, _globs_=None, _locs_=None): + """Execute code in a namespace.""" + if _globs_ is None: + frame = sys._getframe(1) + _globs_ = frame.f_globals + if _locs_ is None: + _locs_ = frame.f_locals + del frame + elif _locs_ is None: + _locs_ = _globs_ + exec("""exec _code_ in _globs_, _locs_""") + +else: + string_types = str, + + import builtins + + exec_ = getattr(builtins, "exec") + del builtins + +from functools import partial +from inspect import ismethod, isclass, formatargspec +from collections import namedtuple +from threading import Lock, RLock + +try: + from inspect import signature +except ImportError: + pass + +from .wrappers import (FunctionWrapper, BoundFunctionWrapper, ObjectProxy, + CallableObjectProxy) + +# Adapter wrapper for the wrapped function which will overlay certain +# properties from the adapter function onto the wrapped function so that +# functions such as inspect.getargspec(), inspect.getfullargspec(), +# inspect.signature() and inspect.getsource() return the correct results +# one would expect. + +class _AdapterFunctionCode(CallableObjectProxy): + + def __init__(self, wrapped_code, adapter_code): + super(_AdapterFunctionCode, self).__init__(wrapped_code) + self._self_adapter_code = adapter_code + + @property + def co_argcount(self): + return self._self_adapter_code.co_argcount + + @property + def co_code(self): + return self._self_adapter_code.co_code + + @property + def co_flags(self): + return self._self_adapter_code.co_flags + + @property + def co_kwonlyargcount(self): + return self._self_adapter_code.co_kwonlyargcount + + @property + def co_varnames(self): + return self._self_adapter_code.co_varnames + +class _AdapterFunctionSurrogate(CallableObjectProxy): + + def __init__(self, wrapped, adapter): + super(_AdapterFunctionSurrogate, self).__init__(wrapped) + self._self_adapter = adapter + + @property + def __code__(self): + return _AdapterFunctionCode(self.__wrapped__.__code__, + self._self_adapter.__code__) + + @property + def __defaults__(self): + return self._self_adapter.__defaults__ + + @property + def __kwdefaults__(self): + return self._self_adapter.__kwdefaults__ + + @property + def __signature__(self): + if 'signature' not in globals(): + return self._self_adapter.__signature__ + else: + return signature(self._self_adapter) + + if PY2: + func_code = __code__ + func_defaults = __defaults__ + +class _BoundAdapterWrapper(BoundFunctionWrapper): + + @property + def __func__(self): + return _AdapterFunctionSurrogate(self.__wrapped__.__func__, + self._self_parent._self_adapter) + + @property + def __signature__(self): + if 'signature' not in globals(): + return self.__wrapped__.__signature__ + else: + return signature(self._self_parent._self_adapter) + + if PY2: + im_func = __func__ + +class AdapterWrapper(FunctionWrapper): + + __bound_function_wrapper__ = _BoundAdapterWrapper + + def __init__(self, *args, **kwargs): + adapter = kwargs.pop('adapter') + super(AdapterWrapper, self).__init__(*args, **kwargs) + self._self_surrogate = _AdapterFunctionSurrogate( + self.__wrapped__, adapter) + self._self_adapter = adapter + + @property + def __code__(self): + return self._self_surrogate.__code__ + + @property + def __defaults__(self): + return self._self_surrogate.__defaults__ + + @property + def __kwdefaults__(self): + return self._self_surrogate.__kwdefaults__ + + if PY2: + func_code = __code__ + func_defaults = __defaults__ + + @property + def __signature__(self): + return self._self_surrogate.__signature__ + +class AdapterFactory(object): + def __call__(self, wrapped): + raise NotImplementedError() + +class DelegatedAdapterFactory(AdapterFactory): + def __init__(self, factory): + super(DelegatedAdapterFactory, self).__init__() + self.factory = factory + def __call__(self, wrapped): + return self.factory(wrapped) + +adapter_factory = DelegatedAdapterFactory + +# Decorator for creating other decorators. This decorator and the +# wrappers which they use are designed to properly preserve any name +# attributes, function signatures etc, in addition to the wrappers +# themselves acting like a transparent proxy for the original wrapped +# function so the wrapper is effectively indistinguishable from the +# original wrapped function. + +def decorator(wrapper=None, enabled=None, adapter=None): + # The decorator should be supplied with a single positional argument + # which is the wrapper function to be used to implement the + # decorator. This may be preceded by a step whereby the keyword + # arguments are supplied to customise the behaviour of the + # decorator. The 'adapter' argument is used to optionally denote a + # separate function which is notionally used by an adapter + # decorator. In that case parts of the function '__code__' and + # '__defaults__' attributes are used from the adapter function + # rather than those of the wrapped function. This allows for the + # argument specification from inspect.getargspec() and similar + # functions to be overridden with a prototype for a different + # function than what was wrapped. The 'enabled' argument provides a + # way to enable/disable the use of the decorator. If the type of + # 'enabled' is a boolean, then it is evaluated immediately and the + # wrapper not even applied if it is False. If not a boolean, it will + # be evaluated when the wrapper is called for an unbound wrapper, + # and when binding occurs for a bound wrapper. When being evaluated, + # if 'enabled' is callable it will be called to obtain the value to + # be checked. If False, the wrapper will not be called and instead + # the original wrapped function will be called directly instead. + + if wrapper is not None: + # Helper function for creating wrapper of the appropriate + # time when we need it down below. + + def _build(wrapped, wrapper, enabled=None, adapter=None): + if adapter: + if isinstance(adapter, AdapterFactory): + adapter = adapter(wrapped) + + if not callable(adapter): + ns = {} + if not isinstance(adapter, string_types): + adapter = formatargspec(*adapter) + exec_('def adapter{}: pass'.format(adapter), ns, ns) + adapter = ns['adapter'] + + return AdapterWrapper(wrapped=wrapped, wrapper=wrapper, + enabled=enabled, adapter=adapter) + + return FunctionWrapper(wrapped=wrapped, wrapper=wrapper, + enabled=enabled) + + # The wrapper has been provided so return the final decorator. + # The decorator is itself one of our function wrappers so we + # can determine when it is applied to functions, instance methods + # or class methods. This allows us to bind the instance or class + # method so the appropriate self or cls attribute is supplied + # when it is finally called. + + def _wrapper(wrapped, instance, args, kwargs): + # We first check for the case where the decorator was applied + # to a class type. + # + # @decorator + # class mydecoratorclass(object): + # def __init__(self, arg=None): + # self.arg = arg + # def __call__(self, wrapped, instance, args, kwargs): + # return wrapped(*args, **kwargs) + # + # @mydecoratorclass(arg=1) + # def function(): + # pass + # + # In this case an instance of the class is to be used as the + # decorator wrapper function. If args was empty at this point, + # then it means that there were optional keyword arguments + # supplied to be used when creating an instance of the class + # to be used as the wrapper function. + + if instance is None and isclass(wrapped) and not args: + # We still need to be passed the target function to be + # wrapped as yet, so we need to return a further function + # to be able to capture it. + + def _capture(target_wrapped): + # Now have the target function to be wrapped and need + # to create an instance of the class which is to act + # as the decorator wrapper function. Before we do that, + # we need to first check that use of the decorator + # hadn't been disabled by a simple boolean. If it was, + # the target function to be wrapped is returned instead. + + _enabled = enabled + if type(_enabled) is bool: + if not _enabled: + return target_wrapped + _enabled = None + + # Now create an instance of the class which is to act + # as the decorator wrapper function. Any arguments had + # to be supplied as keyword only arguments so that is + # all we pass when creating it. + + target_wrapper = wrapped(**kwargs) + + # Finally build the wrapper itself and return it. + + return _build(target_wrapped, target_wrapper, + _enabled, adapter) + + return _capture + + # We should always have the target function to be wrapped at + # this point as the first (and only) value in args. + + target_wrapped = args[0] + + # Need to now check that use of the decorator hadn't been + # disabled by a simple boolean. If it was, then target + # function to be wrapped is returned instead. + + _enabled = enabled + if type(_enabled) is bool: + if not _enabled: + return target_wrapped + _enabled = None + + # We now need to build the wrapper, but there are a couple of + # different cases we need to consider. + + if instance is None: + if isclass(wrapped): + # In this case the decorator was applied to a class + # type but optional keyword arguments were not supplied + # for initialising an instance of the class to be used + # as the decorator wrapper function. + # + # @decorator + # class mydecoratorclass(object): + # def __init__(self, arg=None): + # self.arg = arg + # def __call__(self, wrapped, instance, + # args, kwargs): + # return wrapped(*args, **kwargs) + # + # @mydecoratorclass + # def function(): + # pass + # + # We still need to create an instance of the class to + # be used as the decorator wrapper function, but no + # arguments are pass. + + target_wrapper = wrapped() + + else: + # In this case the decorator was applied to a normal + # function, or possibly a static method of a class. + # + # @decorator + # def mydecoratorfuntion(wrapped, instance, + # args, kwargs): + # return wrapped(*args, **kwargs) + # + # @mydecoratorfunction + # def function(): + # pass + # + # That normal function becomes the decorator wrapper + # function. + + target_wrapper = wrapper + + else: + if isclass(instance): + # In this case the decorator was applied to a class + # method. + # + # class myclass(object): + # @decorator + # @classmethod + # def decoratorclassmethod(cls, wrapped, + # instance, args, kwargs): + # return wrapped(*args, **kwargs) + # + # instance = myclass() + # + # @instance.decoratorclassmethod + # def function(): + # pass + # + # This one is a bit strange because binding was actually + # performed on the wrapper created by our decorator + # factory. We need to apply that binding to the decorator + # wrapper function which which the decorator factory + # was applied to. + + target_wrapper = wrapper.__get__(None, instance) + + else: + # In this case the decorator was applied to an instance + # method. + # + # class myclass(object): + # @decorator + # def decoratorclassmethod(self, wrapped, + # instance, args, kwargs): + # return wrapped(*args, **kwargs) + # + # instance = myclass() + # + # @instance.decoratorclassmethod + # def function(): + # pass + # + # This one is a bit strange because binding was actually + # performed on the wrapper created by our decorator + # factory. We need to apply that binding to the decorator + # wrapper function which which the decorator factory + # was applied to. + + target_wrapper = wrapper.__get__(instance, type(instance)) + + # Finally build the wrapper itself and return it. + + return _build(target_wrapped, target_wrapper, _enabled, adapter) + + # We first return our magic function wrapper here so we can + # determine in what context the decorator factory was used. In + # other words, it is itself a universal decorator. The decorator + # function is used as the adapter so that linters see a signature + # corresponding to the decorator and not the wrapper it is being + # applied to. + + return _build(wrapper, _wrapper, adapter=decorator) + + else: + # The wrapper still has not been provided, so we are just + # collecting the optional keyword arguments. Return the + # decorator again wrapped in a partial using the collected + # arguments. + + return partial(decorator, enabled=enabled, adapter=adapter) + +# Decorator for implementing thread synchronization. It can be used as a +# decorator, in which case the synchronization context is determined by +# what type of function is wrapped, or it can also be used as a context +# manager, where the user needs to supply the correct synchronization +# context. It is also possible to supply an object which appears to be a +# synchronization primitive of some sort, by virtue of having release() +# and acquire() methods. In that case that will be used directly as the +# synchronization primitive without creating a separate lock against the +# derived or supplied context. + +def synchronized(wrapped): + # Determine if being passed an object which is a synchronization + # primitive. We can't check by type for Lock, RLock, Semaphore etc, + # as the means of creating them isn't the type. Therefore use the + # existence of acquire() and release() methods. This is more + # extensible anyway as it allows custom synchronization mechanisms. + + if hasattr(wrapped, 'acquire') and hasattr(wrapped, 'release'): + # We remember what the original lock is and then return a new + # decorator which accesses and locks it. When returning the new + # decorator we wrap it with an object proxy so we can override + # the context manager methods in case it is being used to wrap + # synchronized statements with a 'with' statement. + + lock = wrapped + + @decorator + def _synchronized(wrapped, instance, args, kwargs): + # Execute the wrapped function while the original supplied + # lock is held. + + with lock: + return wrapped(*args, **kwargs) + + class _PartialDecorator(CallableObjectProxy): + + def __enter__(self): + lock.acquire() + return lock + + def __exit__(self, *args): + lock.release() + + return _PartialDecorator(wrapped=_synchronized) + + # Following only apply when the lock is being created automatically + # based on the context of what was supplied. In this case we supply + # a final decorator, but need to use FunctionWrapper directly as we + # want to derive from it to add context manager methods in case it is + # being used to wrap synchronized statements with a 'with' statement. + + def _synchronized_lock(context): + # Attempt to retrieve the lock for the specific context. + + lock = vars(context).get('_synchronized_lock', None) + + if lock is None: + # There is no existing lock defined for the context we + # are dealing with so we need to create one. This needs + # to be done in a way to guarantee there is only one + # created, even if multiple threads try and create it at + # the same time. We can't always use the setdefault() + # method on the __dict__ for the context. This is the + # case where the context is a class, as __dict__ is + # actually a dictproxy. What we therefore do is use a + # meta lock on this wrapper itself, to control the + # creation and assignment of the lock attribute against + # the context. + + with synchronized._synchronized_meta_lock: + # We need to check again for whether the lock we want + # exists in case two threads were trying to create it + # at the same time and were competing to create the + # meta lock. + + lock = vars(context).get('_synchronized_lock', None) + + if lock is None: + lock = RLock() + setattr(context, '_synchronized_lock', lock) + + return lock + + def _synchronized_wrapper(wrapped, instance, args, kwargs): + # Execute the wrapped function while the lock for the + # desired context is held. If instance is None then the + # wrapped function is used as the context. + + with _synchronized_lock(instance if instance is not None else wrapped): + return wrapped(*args, **kwargs) + + class _FinalDecorator(FunctionWrapper): + + def __enter__(self): + self._self_lock = _synchronized_lock(self.__wrapped__) + self._self_lock.acquire() + return self._self_lock + + def __exit__(self, *args): + self._self_lock.release() + + return _FinalDecorator(wrapped=wrapped, wrapper=_synchronized_wrapper) + +synchronized._synchronized_meta_lock = Lock() diff --git a/venv/Lib/site-packages/wrapt/importer.py b/venv/Lib/site-packages/wrapt/importer.py new file mode 100644 index 0000000..4665f38 --- /dev/null +++ b/venv/Lib/site-packages/wrapt/importer.py @@ -0,0 +1,230 @@ +"""This module implements a post import hook mechanism styled after what is +described in PEP-369. Note that it doesn't cope with modules being reloaded. + +""" + +import sys +import threading + +PY2 = sys.version_info[0] == 2 + +if PY2: + string_types = basestring, +else: + import importlib + string_types = str, + +from .decorators import synchronized + +# The dictionary registering any post import hooks to be triggered once +# the target module has been imported. Once a module has been imported +# and the hooks fired, the list of hooks recorded against the target +# module will be truncacted but the list left in the dictionary. This +# acts as a flag to indicate that the module had already been imported. + +_post_import_hooks = {} +_post_import_hooks_init = False +_post_import_hooks_lock = threading.RLock() + +# Register a new post import hook for the target module name. This +# differs from the PEP-369 implementation in that it also allows the +# hook function to be specified as a string consisting of the name of +# the callback in the form 'module:function'. This will result in a +# proxy callback being registered which will defer loading of the +# specified module containing the callback function until required. + +def _create_import_hook_from_string(name): + def import_hook(module): + module_name, function = name.split(':') + attrs = function.split('.') + __import__(module_name) + callback = sys.modules[module_name] + for attr in attrs: + callback = getattr(callback, attr) + return callback(module) + return import_hook + +@synchronized(_post_import_hooks_lock) +def register_post_import_hook(hook, name): + # Create a deferred import hook if hook is a string name rather than + # a callable function. + + if isinstance(hook, string_types): + hook = _create_import_hook_from_string(hook) + + # Automatically install the import hook finder if it has not already + # been installed. + + global _post_import_hooks_init + + if not _post_import_hooks_init: + _post_import_hooks_init = True + sys.meta_path.insert(0, ImportHookFinder()) + + # Determine if any prior registration of a post import hook for + # the target modules has occurred and act appropriately. + + hooks = _post_import_hooks.get(name, None) + + if hooks is None: + # No prior registration of post import hooks for the target + # module. We need to check whether the module has already been + # imported. If it has we fire the hook immediately and add an + # empty list to the registry to indicate that the module has + # already been imported and hooks have fired. Otherwise add + # the post import hook to the registry. + + module = sys.modules.get(name, None) + + if module is not None: + _post_import_hooks[name] = [] + hook(module) + + else: + _post_import_hooks[name] = [hook] + + elif hooks == []: + # A prior registration of port import hooks for the target + # module was done and the hooks already fired. Fire the hook + # immediately. + + module = sys.modules[name] + hook(module) + + else: + # A prior registration of port import hooks for the target + # module was done but the module has not yet been imported. + + _post_import_hooks[name].append(hook) + +# Register post import hooks defined as package entry points. + +def _create_import_hook_from_entrypoint(entrypoint): + def import_hook(module): + __import__(entrypoint.module_name) + callback = sys.modules[entrypoint.module_name] + for attr in entrypoint.attrs: + callback = getattr(callback, attr) + return callback(module) + return import_hook + +def discover_post_import_hooks(group): + try: + import pkg_resources + except ImportError: + return + + for entrypoint in pkg_resources.iter_entry_points(group=group): + callback = _create_import_hook_from_entrypoint(entrypoint) + register_post_import_hook(callback, entrypoint.name) + +# Indicate that a module has been loaded. Any post import hooks which +# were registered against the target module will be invoked. If an +# exception is raised in any of the post import hooks, that will cause +# the import of the target module to fail. + +@synchronized(_post_import_hooks_lock) +def notify_module_loaded(module): + name = getattr(module, '__name__', None) + hooks = _post_import_hooks.get(name, None) + + if hooks: + _post_import_hooks[name] = [] + + for hook in hooks: + hook(module) + +# A custom module import finder. This intercepts attempts to import +# modules and watches out for attempts to import target modules of +# interest. When a module of interest is imported, then any post import +# hooks which are registered will be invoked. + +class _ImportHookLoader: + + def load_module(self, fullname): + module = sys.modules[fullname] + notify_module_loaded(module) + + return module + +class _ImportHookChainedLoader: + + def __init__(self, loader): + self.loader = loader + + def load_module(self, fullname): + module = self.loader.load_module(fullname) + notify_module_loaded(module) + + return module + +class ImportHookFinder: + + def __init__(self): + self.in_progress = {} + + @synchronized(_post_import_hooks_lock) + def find_module(self, fullname, path=None): + # If the module being imported is not one we have registered + # post import hooks for, we can return immediately. We will + # take no further part in the importing of this module. + + if not fullname in _post_import_hooks: + return None + + # When we are interested in a specific module, we will call back + # into the import system a second time to defer to the import + # finder that is supposed to handle the importing of the module. + # We set an in progress flag for the target module so that on + # the second time through we don't trigger another call back + # into the import system and cause a infinite loop. + + if fullname in self.in_progress: + return None + + self.in_progress[fullname] = True + + # Now call back into the import system again. + + try: + if PY2: + # For Python 2 we don't have much choice but to + # call back in to __import__(). This will + # actually cause the module to be imported. If no + # module could be found then ImportError will be + # raised. Otherwise we return a loader which + # returns the already loaded module and invokes + # the post import hooks. + + __import__(fullname) + + return _ImportHookLoader() + + else: + # For Python 3 we need to use find_spec().loader + # from the importlib.util module. It doesn't actually + # import the target module and only finds the + # loader. If a loader is found, we need to return + # our own loader which will then in turn call the + # real loader to import the module and invoke the + # post import hooks. + try: + import importlib.util + loader = importlib.util.find_spec(fullname).loader + except (ImportError, AttributeError): + loader = importlib.find_loader(fullname, path) + if loader: + return _ImportHookChainedLoader(loader) + + + finally: + del self.in_progress[fullname] + +# Decorator for marking that a function should be called as a post +# import hook when the target module is imported. + +def when_imported(name): + def register(hook): + register_post_import_hook(hook, name) + return hook + return register diff --git a/venv/Lib/site-packages/wrapt/wrappers.py b/venv/Lib/site-packages/wrapt/wrappers.py new file mode 100644 index 0000000..18cf5e0 --- /dev/null +++ b/venv/Lib/site-packages/wrapt/wrappers.py @@ -0,0 +1,947 @@ +import os +import sys +import functools +import operator +import weakref +import inspect + +PY2 = sys.version_info[0] == 2 + +if PY2: + string_types = basestring, +else: + string_types = str, + +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + return meta("NewBase", bases, {}) + +class _ObjectProxyMethods(object): + + # We use properties to override the values of __module__ and + # __doc__. If we add these in ObjectProxy, the derived class + # __dict__ will still be setup to have string variants of these + # attributes and the rules of descriptors means that they appear to + # take precedence over the properties in the base class. To avoid + # that, we copy the properties into the derived class type itself + # via a meta class. In that way the properties will always take + # precedence. + + @property + def __module__(self): + return self.__wrapped__.__module__ + + @__module__.setter + def __module__(self, value): + self.__wrapped__.__module__ = value + + @property + def __doc__(self): + return self.__wrapped__.__doc__ + + @__doc__.setter + def __doc__(self, value): + self.__wrapped__.__doc__ = value + + # We similar use a property for __dict__. We need __dict__ to be + # explicit to ensure that vars() works as expected. + + @property + def __dict__(self): + return self.__wrapped__.__dict__ + + # Need to also propagate the special __weakref__ attribute for case + # where decorating classes which will define this. If do not define + # it and use a function like inspect.getmembers() on a decorator + # class it will fail. This can't be in the derived classes. + + @property + def __weakref__(self): + return self.__wrapped__.__weakref__ + +class _ObjectProxyMetaType(type): + def __new__(cls, name, bases, dictionary): + # Copy our special properties into the class so that they + # always take precedence over attributes of the same name added + # during construction of a derived class. This is to save + # duplicating the implementation for them in all derived classes. + + dictionary.update(vars(_ObjectProxyMethods)) + + return type.__new__(cls, name, bases, dictionary) + +class ObjectProxy(with_metaclass(_ObjectProxyMetaType)): + + __slots__ = '__wrapped__' + + def __init__(self, wrapped): + object.__setattr__(self, '__wrapped__', wrapped) + + # Python 3.2+ has the __qualname__ attribute, but it does not + # allow it to be overridden using a property and it must instead + # be an actual string object instead. + + try: + object.__setattr__(self, '__qualname__', wrapped.__qualname__) + except AttributeError: + pass + + @property + def __name__(self): + return self.__wrapped__.__name__ + + @__name__.setter + def __name__(self, value): + self.__wrapped__.__name__ = value + + @property + def __class__(self): + return self.__wrapped__.__class__ + + @__class__.setter + def __class__(self, value): + self.__wrapped__.__class__ = value + + @property + def __annotations__(self): + return self.__wrapped__.__annotations__ + + @__annotations__.setter + def __annotations__(self, value): + self.__wrapped__.__annotations__ = value + + def __dir__(self): + return dir(self.__wrapped__) + + def __str__(self): + return str(self.__wrapped__) + + if not PY2: + def __bytes__(self): + return bytes(self.__wrapped__) + + def __repr__(self): + return '<{} at 0x{:x} for {} at 0x{:x}>'.format( + type(self).__name__, id(self), + type(self.__wrapped__).__name__, + id(self.__wrapped__)) + + def __reversed__(self): + return reversed(self.__wrapped__) + + if not PY2: + def __round__(self): + return round(self.__wrapped__) + + if sys.hexversion >= 0x03070000: + def __mro_entries__(self, bases): + return (self.__wrapped__,) + + def __lt__(self, other): + return self.__wrapped__ < other + + def __le__(self, other): + return self.__wrapped__ <= other + + def __eq__(self, other): + return self.__wrapped__ == other + + def __ne__(self, other): + return self.__wrapped__ != other + + def __gt__(self, other): + return self.__wrapped__ > other + + def __ge__(self, other): + return self.__wrapped__ >= other + + def __hash__(self): + return hash(self.__wrapped__) + + def __nonzero__(self): + return bool(self.__wrapped__) + + def __bool__(self): + return bool(self.__wrapped__) + + def __setattr__(self, name, value): + if name.startswith('_self_'): + object.__setattr__(self, name, value) + + elif name == '__wrapped__': + object.__setattr__(self, name, value) + try: + object.__delattr__(self, '__qualname__') + except AttributeError: + pass + try: + object.__setattr__(self, '__qualname__', value.__qualname__) + except AttributeError: + pass + + elif name == '__qualname__': + setattr(self.__wrapped__, name, value) + object.__setattr__(self, name, value) + + elif hasattr(type(self), name): + object.__setattr__(self, name, value) + + else: + setattr(self.__wrapped__, name, value) + + def __getattr__(self, name): + # If we are being to lookup '__wrapped__' then the + # '__init__()' method cannot have been called. + + if name == '__wrapped__': + raise ValueError('wrapper has not been initialised') + + return getattr(self.__wrapped__, name) + + def __delattr__(self, name): + if name.startswith('_self_'): + object.__delattr__(self, name) + + elif name == '__wrapped__': + raise TypeError('__wrapped__ must be an object') + + elif name == '__qualname__': + object.__delattr__(self, name) + delattr(self.__wrapped__, name) + + elif hasattr(type(self), name): + object.__delattr__(self, name) + + else: + delattr(self.__wrapped__, name) + + def __add__(self, other): + return self.__wrapped__ + other + + def __sub__(self, other): + return self.__wrapped__ - other + + def __mul__(self, other): + return self.__wrapped__ * other + + def __div__(self, other): + return operator.div(self.__wrapped__, other) + + def __truediv__(self, other): + return operator.truediv(self.__wrapped__, other) + + def __floordiv__(self, other): + return self.__wrapped__ // other + + def __mod__(self, other): + return self.__wrapped__ % other + + def __divmod__(self, other): + return divmod(self.__wrapped__, other) + + def __pow__(self, other, *args): + return pow(self.__wrapped__, other, *args) + + def __lshift__(self, other): + return self.__wrapped__ << other + + def __rshift__(self, other): + return self.__wrapped__ >> other + + def __and__(self, other): + return self.__wrapped__ & other + + def __xor__(self, other): + return self.__wrapped__ ^ other + + def __or__(self, other): + return self.__wrapped__ | other + + def __radd__(self, other): + return other + self.__wrapped__ + + def __rsub__(self, other): + return other - self.__wrapped__ + + def __rmul__(self, other): + return other * self.__wrapped__ + + def __rdiv__(self, other): + return operator.div(other, self.__wrapped__) + + def __rtruediv__(self, other): + return operator.truediv(other, self.__wrapped__) + + def __rfloordiv__(self, other): + return other // self.__wrapped__ + + def __rmod__(self, other): + return other % self.__wrapped__ + + def __rdivmod__(self, other): + return divmod(other, self.__wrapped__) + + def __rpow__(self, other, *args): + return pow(other, self.__wrapped__, *args) + + def __rlshift__(self, other): + return other << self.__wrapped__ + + def __rrshift__(self, other): + return other >> self.__wrapped__ + + def __rand__(self, other): + return other & self.__wrapped__ + + def __rxor__(self, other): + return other ^ self.__wrapped__ + + def __ror__(self, other): + return other | self.__wrapped__ + + def __iadd__(self, other): + self.__wrapped__ += other + return self + + def __isub__(self, other): + self.__wrapped__ -= other + return self + + def __imul__(self, other): + self.__wrapped__ *= other + return self + + def __idiv__(self, other): + self.__wrapped__ = operator.idiv(self.__wrapped__, other) + return self + + def __itruediv__(self, other): + self.__wrapped__ = operator.itruediv(self.__wrapped__, other) + return self + + def __ifloordiv__(self, other): + self.__wrapped__ //= other + return self + + def __imod__(self, other): + self.__wrapped__ %= other + return self + + def __ipow__(self, other): + self.__wrapped__ **= other + return self + + def __ilshift__(self, other): + self.__wrapped__ <<= other + return self + + def __irshift__(self, other): + self.__wrapped__ >>= other + return self + + def __iand__(self, other): + self.__wrapped__ &= other + return self + + def __ixor__(self, other): + self.__wrapped__ ^= other + return self + + def __ior__(self, other): + self.__wrapped__ |= other + return self + + def __neg__(self): + return -self.__wrapped__ + + def __pos__(self): + return +self.__wrapped__ + + def __abs__(self): + return abs(self.__wrapped__) + + def __invert__(self): + return ~self.__wrapped__ + + def __int__(self): + return int(self.__wrapped__) + + def __long__(self): + return long(self.__wrapped__) + + def __float__(self): + return float(self.__wrapped__) + + def __complex__(self): + return complex(self.__wrapped__) + + def __oct__(self): + return oct(self.__wrapped__) + + def __hex__(self): + return hex(self.__wrapped__) + + def __index__(self): + return operator.index(self.__wrapped__) + + def __len__(self): + return len(self.__wrapped__) + + def __contains__(self, value): + return value in self.__wrapped__ + + def __getitem__(self, key): + return self.__wrapped__[key] + + def __setitem__(self, key, value): + self.__wrapped__[key] = value + + def __delitem__(self, key): + del self.__wrapped__[key] + + def __getslice__(self, i, j): + return self.__wrapped__[i:j] + + def __setslice__(self, i, j, value): + self.__wrapped__[i:j] = value + + def __delslice__(self, i, j): + del self.__wrapped__[i:j] + + def __enter__(self): + return self.__wrapped__.__enter__() + + def __exit__(self, *args, **kwargs): + return self.__wrapped__.__exit__(*args, **kwargs) + + def __iter__(self): + return iter(self.__wrapped__) + + def __copy__(self): + raise NotImplementedError('object proxy must define __copy__()') + + def __deepcopy__(self, memo): + raise NotImplementedError('object proxy must define __deepcopy__()') + + def __reduce__(self): + raise NotImplementedError( + 'object proxy must define __reduce_ex__()') + + def __reduce_ex__(self, protocol): + raise NotImplementedError( + 'object proxy must define __reduce_ex__()') + +class CallableObjectProxy(ObjectProxy): + + def __call__(self, *args, **kwargs): + return self.__wrapped__(*args, **kwargs) + +class PartialCallableObjectProxy(ObjectProxy): + + def __init__(self, *args, **kwargs): + if len(args) < 1: + raise TypeError('partial type takes at least one argument') + + wrapped, args = args[0], args[1:] + + if not callable(wrapped): + raise TypeError('the first argument must be callable') + + super(PartialCallableObjectProxy, self).__init__(wrapped) + + self._self_args = args + self._self_kwargs = kwargs + + def __call__(self, *args, **kwargs): + _args = self._self_args + args + + _kwargs = dict(self._self_kwargs) + _kwargs.update(kwargs) + + return self.__wrapped__(*_args, **_kwargs) + +class _FunctionWrapperBase(ObjectProxy): + + __slots__ = ('_self_instance', '_self_wrapper', '_self_enabled', + '_self_binding', '_self_parent') + + def __init__(self, wrapped, instance, wrapper, enabled=None, + binding='function', parent=None): + + super(_FunctionWrapperBase, self).__init__(wrapped) + + object.__setattr__(self, '_self_instance', instance) + object.__setattr__(self, '_self_wrapper', wrapper) + object.__setattr__(self, '_self_enabled', enabled) + object.__setattr__(self, '_self_binding', binding) + object.__setattr__(self, '_self_parent', parent) + + def __get__(self, instance, owner): + # This method is actually doing double duty for both unbound and + # bound derived wrapper classes. It should possibly be broken up + # and the distinct functionality moved into the derived classes. + # Can't do that straight away due to some legacy code which is + # relying on it being here in this base class. + # + # The distinguishing attribute which determines whether we are + # being called in an unbound or bound wrapper is the parent + # attribute. If binding has never occurred, then the parent will + # be None. + # + # First therefore, is if we are called in an unbound wrapper. In + # this case we perform the binding. + # + # We have one special case to worry about here. This is where we + # are decorating a nested class. In this case the wrapped class + # would not have a __get__() method to call. In that case we + # simply return self. + # + # Note that we otherwise still do binding even if instance is + # None and accessing an unbound instance method from a class. + # This is because we need to be able to later detect that + # specific case as we will need to extract the instance from the + # first argument of those passed in. + + if self._self_parent is None: + if not inspect.isclass(self.__wrapped__): + descriptor = self.__wrapped__.__get__(instance, owner) + + return self.__bound_function_wrapper__(descriptor, instance, + self._self_wrapper, self._self_enabled, + self._self_binding, self) + + return self + + # Now we have the case of binding occurring a second time on what + # was already a bound function. In this case we would usually + # return ourselves again. This mirrors what Python does. + # + # The special case this time is where we were originally bound + # with an instance of None and we were likely an instance + # method. In that case we rebind against the original wrapped + # function from the parent again. + + if self._self_instance is None and self._self_binding == 'function': + descriptor = self._self_parent.__wrapped__.__get__( + instance, owner) + + return self._self_parent.__bound_function_wrapper__( + descriptor, instance, self._self_wrapper, + self._self_enabled, self._self_binding, + self._self_parent) + + return self + + def __call__(self, *args, **kwargs): + # If enabled has been specified, then evaluate it at this point + # and if the wrapper is not to be executed, then simply return + # the bound function rather than a bound wrapper for the bound + # function. When evaluating enabled, if it is callable we call + # it, otherwise we evaluate it as a boolean. + + if self._self_enabled is not None: + if callable(self._self_enabled): + if not self._self_enabled(): + return self.__wrapped__(*args, **kwargs) + elif not self._self_enabled: + return self.__wrapped__(*args, **kwargs) + + # This can occur where initial function wrapper was applied to + # a function that was already bound to an instance. In that case + # we want to extract the instance from the function and use it. + + if self._self_binding == 'function': + if self._self_instance is None: + instance = getattr(self.__wrapped__, '__self__', None) + if instance is not None: + return self._self_wrapper(self.__wrapped__, instance, + args, kwargs) + + # This is generally invoked when the wrapped function is being + # called as a normal function and is not bound to a class as an + # instance method. This is also invoked in the case where the + # wrapped function was a method, but this wrapper was in turn + # wrapped using the staticmethod decorator. + + return self._self_wrapper(self.__wrapped__, self._self_instance, + args, kwargs) + +class BoundFunctionWrapper(_FunctionWrapperBase): + + def __call__(self, *args, **kwargs): + # If enabled has been specified, then evaluate it at this point + # and if the wrapper is not to be executed, then simply return + # the bound function rather than a bound wrapper for the bound + # function. When evaluating enabled, if it is callable we call + # it, otherwise we evaluate it as a boolean. + + if self._self_enabled is not None: + if callable(self._self_enabled): + if not self._self_enabled(): + return self.__wrapped__(*args, **kwargs) + elif not self._self_enabled: + return self.__wrapped__(*args, **kwargs) + + # We need to do things different depending on whether we are + # likely wrapping an instance method vs a static method or class + # method. + + if self._self_binding == 'function': + if self._self_instance is None: + # This situation can occur where someone is calling the + # instancemethod via the class type and passing the instance + # as the first argument. We need to shift the args before + # making the call to the wrapper and effectively bind the + # instance to the wrapped function using a partial so the + # wrapper doesn't see anything as being different. + + if not args: + raise TypeError('missing 1 required positional argument') + + instance, args = args[0], args[1:] + wrapped = PartialCallableObjectProxy(self.__wrapped__, instance) + return self._self_wrapper(wrapped, instance, args, kwargs) + + return self._self_wrapper(self.__wrapped__, self._self_instance, + args, kwargs) + + else: + # As in this case we would be dealing with a classmethod or + # staticmethod, then _self_instance will only tell us whether + # when calling the classmethod or staticmethod they did it via an + # instance of the class it is bound to and not the case where + # done by the class type itself. We thus ignore _self_instance + # and use the __self__ attribute of the bound function instead. + # For a classmethod, this means instance will be the class type + # and for a staticmethod it will be None. This is probably the + # more useful thing we can pass through even though we loose + # knowledge of whether they were called on the instance vs the + # class type, as it reflects what they have available in the + # decoratored function. + + instance = getattr(self.__wrapped__, '__self__', None) + + return self._self_wrapper(self.__wrapped__, instance, args, + kwargs) + +class FunctionWrapper(_FunctionWrapperBase): + + __bound_function_wrapper__ = BoundFunctionWrapper + + def __init__(self, wrapped, wrapper, enabled=None): + # What it is we are wrapping here could be anything. We need to + # try and detect specific cases though. In particular, we need + # to detect when we are given something that is a method of a + # class. Further, we need to know when it is likely an instance + # method, as opposed to a class or static method. This can + # become problematic though as there isn't strictly a fool proof + # method of knowing. + # + # The situations we could encounter when wrapping a method are: + # + # 1. The wrapper is being applied as part of a decorator which + # is a part of the class definition. In this case what we are + # given is the raw unbound function, classmethod or staticmethod + # wrapper objects. + # + # The problem here is that we will not know we are being applied + # in the context of the class being set up. This becomes + # important later for the case of an instance method, because in + # that case we just see it as a raw function and can't + # distinguish it from wrapping a normal function outside of + # a class context. + # + # 2. The wrapper is being applied when performing monkey + # patching of the class type afterwards and the method to be + # wrapped was retrieved direct from the __dict__ of the class + # type. This is effectively the same as (1) above. + # + # 3. The wrapper is being applied when performing monkey + # patching of the class type afterwards and the method to be + # wrapped was retrieved from the class type. In this case + # binding will have been performed where the instance against + # which the method is bound will be None at that point. + # + # This case is a problem because we can no longer tell if the + # method was a static method, plus if using Python3, we cannot + # tell if it was an instance method as the concept of an + # unnbound method no longer exists. + # + # 4. The wrapper is being applied when performing monkey + # patching of an instance of a class. In this case binding will + # have been perfomed where the instance was not None. + # + # This case is a problem because we can no longer tell if the + # method was a static method. + # + # Overall, the best we can do is look at the original type of the + # object which was wrapped prior to any binding being done and + # see if it is an instance of classmethod or staticmethod. In + # the case where other decorators are between us and them, if + # they do not propagate the __class__ attribute so that the + # isinstance() checks works, then likely this will do the wrong + # thing where classmethod and staticmethod are used. + # + # Since it is likely to be very rare that anyone even puts + # decorators around classmethod and staticmethod, likelihood of + # that being an issue is very small, so we accept it and suggest + # that those other decorators be fixed. It is also only an issue + # if a decorator wants to actually do things with the arguments. + # + # As to not being able to identify static methods properly, we + # just hope that that isn't something people are going to want + # to wrap, or if they do suggest they do it the correct way by + # ensuring that it is decorated in the class definition itself, + # or patch it in the __dict__ of the class type. + # + # So to get the best outcome we can, whenever we aren't sure what + # it is, we label it as a 'function'. If it was already bound and + # that is rebound later, we assume that it will be an instance + # method and try an cope with the possibility that the 'self' + # argument it being passed as an explicit argument and shuffle + # the arguments around to extract 'self' for use as the instance. + + if isinstance(wrapped, classmethod): + binding = 'classmethod' + + elif isinstance(wrapped, staticmethod): + binding = 'staticmethod' + + elif hasattr(wrapped, '__self__'): + if inspect.isclass(wrapped.__self__): + binding = 'classmethod' + else: + binding = 'function' + + else: + binding = 'function' + + super(FunctionWrapper, self).__init__(wrapped, None, wrapper, + enabled, binding) + +try: + if not os.environ.get('WRAPT_DISABLE_EXTENSIONS'): + from ._wrappers import (ObjectProxy, CallableObjectProxy, + PartialCallableObjectProxy, FunctionWrapper, + BoundFunctionWrapper, _FunctionWrapperBase) +except ImportError: + pass + +# Helper functions for applying wrappers to existing functions. + +def resolve_path(module, name): + if isinstance(module, string_types): + __import__(module) + module = sys.modules[module] + + parent = module + + path = name.split('.') + attribute = path[0] + + # We can't just always use getattr() because in doing + # that on a class it will cause binding to occur which + # will complicate things later and cause some things not + # to work. For the case of a class we therefore access + # the __dict__ directly. To cope though with the wrong + # class being given to us, or a method being moved into + # a base class, we need to walk the class hierarchy to + # work out exactly which __dict__ the method was defined + # in, as accessing it from __dict__ will fail if it was + # not actually on the class given. Fallback to using + # getattr() if we can't find it. If it truly doesn't + # exist, then that will fail. + + def lookup_attribute(parent, attribute): + if inspect.isclass(parent): + for cls in inspect.getmro(parent): + if attribute in vars(cls): + return vars(cls)[attribute] + else: + return getattr(parent, attribute) + else: + return getattr(parent, attribute) + + original = lookup_attribute(parent, attribute) + + for attribute in path[1:]: + parent = original + original = lookup_attribute(parent, attribute) + + return (parent, attribute, original) + +def apply_patch(parent, attribute, replacement): + setattr(parent, attribute, replacement) + +def wrap_object(module, name, factory, args=(), kwargs={}): + (parent, attribute, original) = resolve_path(module, name) + wrapper = factory(original, *args, **kwargs) + apply_patch(parent, attribute, wrapper) + return wrapper + +# Function for applying a proxy object to an attribute of a class +# instance. The wrapper works by defining an attribute of the same name +# on the class which is a descriptor and which intercepts access to the +# instance attribute. Note that this cannot be used on attributes which +# are themselves defined by a property object. + +class AttributeWrapper(object): + + def __init__(self, attribute, factory, args, kwargs): + self.attribute = attribute + self.factory = factory + self.args = args + self.kwargs = kwargs + + def __get__(self, instance, owner): + value = instance.__dict__[self.attribute] + return self.factory(value, *self.args, **self.kwargs) + + def __set__(self, instance, value): + instance.__dict__[self.attribute] = value + + def __delete__(self, instance): + del instance.__dict__[self.attribute] + +def wrap_object_attribute(module, name, factory, args=(), kwargs={}): + path, attribute = name.rsplit('.', 1) + parent = resolve_path(module, path)[2] + wrapper = AttributeWrapper(attribute, factory, args, kwargs) + apply_patch(parent, attribute, wrapper) + return wrapper + +# Functions for creating a simple decorator using a FunctionWrapper, +# plus short cut functions for applying wrappers to functions. These are +# for use when doing monkey patching. For a more featured way of +# creating decorators see the decorator decorator instead. + +def function_wrapper(wrapper): + def _wrapper(wrapped, instance, args, kwargs): + target_wrapped = args[0] + if instance is None: + target_wrapper = wrapper + elif inspect.isclass(instance): + target_wrapper = wrapper.__get__(None, instance) + else: + target_wrapper = wrapper.__get__(instance, type(instance)) + return FunctionWrapper(target_wrapped, target_wrapper) + return FunctionWrapper(wrapper, _wrapper) + +def wrap_function_wrapper(module, name, wrapper): + return wrap_object(module, name, FunctionWrapper, (wrapper,)) + +def patch_function_wrapper(module, name): + def _wrapper(wrapper): + return wrap_object(module, name, FunctionWrapper, (wrapper,)) + return _wrapper + +def transient_function_wrapper(module, name): + def _decorator(wrapper): + def _wrapper(wrapped, instance, args, kwargs): + target_wrapped = args[0] + if instance is None: + target_wrapper = wrapper + elif inspect.isclass(instance): + target_wrapper = wrapper.__get__(None, instance) + else: + target_wrapper = wrapper.__get__(instance, type(instance)) + def _execute(wrapped, instance, args, kwargs): + (parent, attribute, original) = resolve_path(module, name) + replacement = FunctionWrapper(original, target_wrapper) + setattr(parent, attribute, replacement) + try: + return wrapped(*args, **kwargs) + finally: + setattr(parent, attribute, original) + return FunctionWrapper(target_wrapped, _execute) + return FunctionWrapper(wrapper, _wrapper) + return _decorator + +# A weak function proxy. This will work on instance methods, class +# methods, static methods and regular functions. Special treatment is +# needed for the method types because the bound method is effectively a +# transient object and applying a weak reference to one will immediately +# result in it being destroyed and the weakref callback called. The weak +# reference is therefore applied to the instance the method is bound to +# and the original function. The function is then rebound at the point +# of a call via the weak function proxy. + +def _weak_function_proxy_callback(ref, proxy, callback): + if proxy._self_expired: + return + + proxy._self_expired = True + + # This could raise an exception. We let it propagate back and let + # the weakref.proxy() deal with it, at which point it generally + # prints out a short error message direct to stderr and keeps going. + + if callback is not None: + callback(proxy) + +class WeakFunctionProxy(ObjectProxy): + + __slots__ = ('_self_expired', '_self_instance') + + def __init__(self, wrapped, callback=None): + # We need to determine if the wrapped function is actually a + # bound method. In the case of a bound method, we need to keep a + # reference to the original unbound function and the instance. + # This is necessary because if we hold a reference to the bound + # function, it will be the only reference and given it is a + # temporary object, it will almost immediately expire and + # the weakref callback triggered. So what is done is that we + # hold a reference to the instance and unbound function and + # when called bind the function to the instance once again and + # then call it. Note that we avoid using a nested function for + # the callback here so as not to cause any odd reference cycles. + + _callback = callback and functools.partial( + _weak_function_proxy_callback, proxy=self, + callback=callback) + + self._self_expired = False + + if isinstance(wrapped, _FunctionWrapperBase): + self._self_instance = weakref.ref(wrapped._self_instance, + _callback) + + if wrapped._self_parent is not None: + super(WeakFunctionProxy, self).__init__( + weakref.proxy(wrapped._self_parent, _callback)) + + else: + super(WeakFunctionProxy, self).__init__( + weakref.proxy(wrapped, _callback)) + + return + + try: + self._self_instance = weakref.ref(wrapped.__self__, _callback) + + super(WeakFunctionProxy, self).__init__( + weakref.proxy(wrapped.__func__, _callback)) + + except AttributeError: + self._self_instance = None + + super(WeakFunctionProxy, self).__init__( + weakref.proxy(wrapped, _callback)) + + def __call__(self, *args, **kwargs): + # We perform a boolean check here on the instance and wrapped + # function as that will trigger the reference error prior to + # calling if the reference had expired. + + instance = self._self_instance and self._self_instance() + function = self.__wrapped__ and self.__wrapped__ + + # If the wrapped function was originally a bound function, for + # which we retained a reference to the instance and the unbound + # function we need to rebind the function and then call it. If + # not just called the wrapped function. + + if instance is None: + return self.__wrapped__(*args, **kwargs) + + return function.__get__(instance, type(instance))(*args, **kwargs) diff --git a/venv/Scripts/black-primer.exe b/venv/Scripts/black-primer.exe new file mode 100644 index 0000000..c0f6e1f Binary files /dev/null and b/venv/Scripts/black-primer.exe differ diff --git a/venv/Scripts/black.exe b/venv/Scripts/black.exe new file mode 100644 index 0000000..695e2a6 Binary files /dev/null and b/venv/Scripts/black.exe differ diff --git a/venv/Scripts/blackd.exe b/venv/Scripts/blackd.exe new file mode 100644 index 0000000..e1f84ca Binary files /dev/null and b/venv/Scripts/blackd.exe differ diff --git a/venv/Scripts/dmypy.exe b/venv/Scripts/dmypy.exe new file mode 100644 index 0000000..61fd568 Binary files /dev/null and b/venv/Scripts/dmypy.exe differ diff --git a/venv/Scripts/epylint.exe b/venv/Scripts/epylint.exe new file mode 100644 index 0000000..f70f064 Binary files /dev/null and b/venv/Scripts/epylint.exe differ diff --git a/venv/Scripts/isort.exe b/venv/Scripts/isort.exe new file mode 100644 index 0000000..6c07a65 Binary files /dev/null and b/venv/Scripts/isort.exe differ diff --git a/venv/Scripts/mypy.exe b/venv/Scripts/mypy.exe new file mode 100644 index 0000000..1f6bdfd Binary files /dev/null and b/venv/Scripts/mypy.exe differ diff --git a/venv/Scripts/mypyc b/venv/Scripts/mypyc new file mode 100644 index 0000000..0354df8 --- /dev/null +++ b/venv/Scripts/mypyc @@ -0,0 +1,55 @@ +#!C:\Users\mihaz\Documents\GitHub\Waycooler1\venv\Scripts\python.exe +"""Mypyc command-line tool. + +Usage: + + $ mypyc foo.py [...] + $ python3 -c 'import foo' # Uses compiled 'foo' + + +This is just a thin wrapper that generates a setup.py file that uses +mypycify, suitable for prototyping and testing. +""" + +import os +import os.path +import subprocess +import sys +import tempfile +import time + +base_path = os.path.join(os.path.dirname(__file__), '..') + +setup_format = """\ +from distutils.core import setup +from mypyc.build import mypycify + +setup(name='mypyc_output', + ext_modules=mypycify({}, opt_level="{}"), +) +""" + +def main() -> None: + build_dir = 'build' # can this be overridden?? + try: + os.mkdir(build_dir) + except FileExistsError: + pass + + opt_level = os.getenv("MYPYC_OPT_LEVEL", '3') + + setup_file = os.path.join(build_dir, 'setup.py') + with open(setup_file, 'w') as f: + f.write(setup_format.format(sys.argv[1:], opt_level)) + + # We don't use run_setup (like we do in the test suite) because it throws + # away the error code from distutils, and we don't care about the slight + # performance loss here. + env = os.environ.copy() + base_path = os.path.join(os.path.dirname(__file__), '..') + env['PYTHONPATH'] = base_path + os.pathsep + env.get('PYTHONPATH', '') + cmd = subprocess.run([sys.executable, setup_file, 'build_ext', '--inplace'], env=env) + sys.exit(cmd.returncode) + +if __name__ == '__main__': + main() diff --git a/venv/Scripts/pip3.10.exe b/venv/Scripts/pip3.10.exe new file mode 100644 index 0000000..4794706 Binary files /dev/null and b/venv/Scripts/pip3.10.exe differ diff --git a/venv/Scripts/py.test.exe b/venv/Scripts/py.test.exe new file mode 100644 index 0000000..c50c88a Binary files /dev/null and b/venv/Scripts/py.test.exe differ diff --git a/venv/Scripts/pylint.exe b/venv/Scripts/pylint.exe new file mode 100644 index 0000000..3210b7b Binary files /dev/null and b/venv/Scripts/pylint.exe differ diff --git a/venv/Scripts/pyreverse.exe b/venv/Scripts/pyreverse.exe new file mode 100644 index 0000000..c823f04 Binary files /dev/null and b/venv/Scripts/pyreverse.exe differ diff --git a/venv/Scripts/pytest.exe b/venv/Scripts/pytest.exe new file mode 100644 index 0000000..c50c88a Binary files /dev/null and b/venv/Scripts/pytest.exe differ diff --git a/venv/Scripts/stubgen.exe b/venv/Scripts/stubgen.exe new file mode 100644 index 0000000..c720d3a Binary files /dev/null and b/venv/Scripts/stubgen.exe differ diff --git a/venv/Scripts/stubtest.exe b/venv/Scripts/stubtest.exe new file mode 100644 index 0000000..14ad110 Binary files /dev/null and b/venv/Scripts/stubtest.exe differ diff --git a/venv/Scripts/symilar.exe b/venv/Scripts/symilar.exe new file mode 100644 index 0000000..4cabb48 Binary files /dev/null and b/venv/Scripts/symilar.exe differ