~piotr-machura/python-miniprojects

2db257da06566115a9c6115485d26df8124db650 — Piotr Machura 9 months ago 1263d53 master
Change formatting
M blackjack/__main__.py => blackjack/__main__.py +18 -17
@@ 1,10 1,11 @@
"""This is the `__main__` module."""
import os
import sys

from deck import Deck
from exception import (BustedException, ExitException, FoldException,
                       WinException)
from player import Dealer, Human
from exception import BustedException, WinException
from exception import ExitException, FoldException


def print_header():


@@ 13,20 14,20 @@ def print_header():
    """
    global PLAYER
    global DEALER
    os.system('cls' if os.name == 'nt' else 'clear')
    print('--------------- BLACKJACK ---------------', end='\n\n')
    print(DEALER, end='\n\n')
    print(PLAYER, end='\n\n')
    print('-----------------------------------------')
    os.system("cls" if os.name == "nt" else "clear")
    print("--------------- BLACKJACK ---------------", end="\n\n")
    print(DEALER, end="\n\n")
    print(PLAYER, end="\n\n")
    print("-----------------------------------------")


def bet_or_exit():
    """Asks the user whether they want to `bet` or exit."""
    choice = input('Input your bet (0 to fold, q to exit): ')
    if choice == '0':
    choice = input("Input your bet (0 to fold, q to exit): ")
    if choice == "0":
        raise FoldException()
    elif choice == 'q':
        print('Goodbye!')
    elif choice == "q":
        print("Goodbye!")
        sys.exit(0)
    else:
        PLAYER.bet(int(choice))


@@ 34,22 35,22 @@ def bet_or_exit():

def hit_or_stand():
    """Asks the user whether they want to `hit` or `stand`."""
    print('Choose your action:')
    print('[1] Hit [2] Stand [q] Quit ')
    print("Choose your action:")
    print("[1] Hit [2] Stand [q] Quit ")
    while True:
        try:
            choice = int(input('Choose an option: '))
            choice = int(input("Choose an option: "))
            break
        except ValueError:
            pass
    if choice == 0:
        print('Exiting...')
        print("Exiting...")
        sys.exit()
    elif choice == 1:
        PLAYER.hit(DECK, 1)


if __name__ == '__main__':
if __name__ == "__main__":
    DECK = Deck()
    DEALER = Dealer(DECK)
    PLAYER = Human(DECK, 1000)


@@ 68,5 69,5 @@ if __name__ == '__main__':
            try:
                hit_or_stand()
            except BustedException as ex:
                print('Busted!')
                print("Busted!")
                break

M blackjack/deck.py => blackjack/deck.py +19 -17
@@ 2,6 2,7 @@
"""
from random import randrange


class Card:
    """The Card class. Contains fields `symbol` (string) and a `value` (tuple).
    The static `TYPES` dictonary contains pairs of all of the valid symbols and


@@ 21,20 22,21 @@ class Card:
    def __eq__(self, o: object) -> bool:
        return isinstance(o, Card) and self.symbol == o.symbol

    TYPES = {'2': (2, 2),
             '3': (3, 3),
             '4': (4, 4),
             '5': (5, 5),
             '6': (6, 6),
             '7': (7, 7),
             '8': (8, 8),
             '9': (9, 9),
             '10': (10, 10),
             'Jack': (10, 10),
             'Queen': (10, 10),
             'King': (10, 10),
             'Ace': (1, 11)
             }
    TYPES = {
        "2": (2, 2),
        "3": (3, 3),
        "4": (4, 4),
        "5": (5, 5),
        "6": (6, 6),
        "7": (7, 7),
        "8": (8, 8),
        "9": (9, 9),
        "10": (10, 10),
        "Jack": (10, 10),
        "Queen": (10, 10),
        "King": (10, 10),
        "Ace": (1, 11),
    }


class Deck:


@@ 43,17 45,17 @@ class Deck:
    """

    def __init__(self):
        self.cards = 4*[Card(symbol) for symbol in Card.TYPES]
        self.cards = 4 * [Card(symbol) for symbol in Card.TYPES]

    def __len__(self) -> int:
        return len(self.cards)

    def __repr__(self) -> str:
        str_repr = 'Deck:\n'
        str_repr = "Deck:\n"
        for symbol in Card.TYPES:
            counter = self.cards.count(Card(symbol))
            if counter != 0:
                str_repr += f'[{symbol}]: {counter} '
                str_repr += f"[{symbol}]: {counter} "
        return str_repr

    def __str__(self) -> str:

M blackjack/exception.py => blackjack/exception.py +1 -0
@@ 1,5 1,6 @@
"""This module contains the exceptions used to manage game flow"""


class BlackJackException(Exception):
    """The base BlackJackException used to manage game flow."""


M blackjack/player.py => blackjack/player.py +16 -17
@@ 13,27 13,27 @@ class Player:
    def __init__(self):
        self.hand = []
        self.balance = None
        self.name = ''
        self.name = ""

    def __repr__(self) -> str:
        str_repr = f'-- {self.name} --\n'
        str_repr += 'Hand: '
        str_repr = f"-- {self.name} --\n"
        str_repr += "Hand: "
        for symbol in Card.TYPES.keys():
            counter = self.hand.count(Card(symbol))
            if counter != 0:
                str_repr += f'[{symbol}]: {counter} '
        str_repr += '\n'
                str_repr += f"[{symbol}]: {counter} "
        str_repr += "\n"

        points, points_alt = self.calculate_points()
        if points == points_alt:
            str_repr += f'Points: {points} '
            str_repr += f"Points: {points} "
        else:
            str_repr += f'Points (Ace=1): {points}, '
            str_repr += f'Points (Ace=11): {points_alt} '
            str_repr += f"Points (Ace=1): {points}, "
            str_repr += f"Points (Ace=11): {points_alt} "

        if self.balance is not None:
            str_repr += '\n'
            str_repr += f'Balance: {self.balance}'
            str_repr += "\n"
            str_repr += f"Balance: {self.balance}"

        return str_repr



@@ 65,12 65,11 @@ class Dealer(Player):

    def __init__(self, deck: Deck):
        super().__init__()
        self.name = 'DEALER'
        self.name = "DEALER"
        self.hit(deck, 1)

    def hit_continuosly(self, deck: Deck, oponent: Player):
        """Hit until you have more points than `oponent` or exceed 21.
        """
        """Hit until you have more points than `oponent` or exceed 21."""
        while self.calculate_points() < 21:
            self.hit(deck, 1)
            points = self.calculate_points()


@@ 87,18 86,18 @@ class Human(Player):

    def __init__(self, deck: Deck, balance: int):
        super().__init__()
        self.name = 'PLAYER'
        self.name = "PLAYER"
        self.balance = balance
        self.hit(deck, 2)

    def bet(self, amount: int) -> int:
        """Bet `amount` on winning the current hand."""
        if self.balance - amount < 0:
            print(f'Not enough money to bet ${amount}.')
            print(f"Not enough money to bet ${amount}.")
        else:
            self.balance -= amount
            print(f'Bet of ${amount} placed.')
        print(f'Current balance: ${self.balance}')
            print(f"Bet of ${amount} placed.")
        print(f"Current balance: ${self.balance}")

    def stand(self):
        """Do nothing."""

M collatz/__main__.py => collatz/__main__.py +5 -4
@@ 1,12 1,13 @@
"""This is the `__main__` module."""
import sys
import os
from PyQt5 import QtWidgets, QtGui
import sys

from app import CollatzApp
from PyQt5 import QtGui, QtWidgets

if __name__ == '__main__':
if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    dir_name = os.path.dirname(os.path.realpath(__file__))
    app.setWindowIcon(QtGui.QIcon(dir_name + os.path.sep + 'icon.svg'))
    app.setWindowIcon(QtGui.QIcon(dir_name + os.path.sep + "icon.svg"))
    ex = CollatzApp()
    app.exec()

M collatz/app.py => collatz/app.py +16 -13
@@ 1,23 1,25 @@
"""This module contains the main app window"""
import os
import webbrowser

from dialog import BrowserDialog
from PyQt5 import QtCore, QtGui, QtWidgets
from validator import IntValidator
from dialog import BrowserDialog


class CollatzApp(QtWidgets.QMainWindow):
    """Main app window."""

    def __init__(self):
        super().__init__()
        self.setWindowTitle(' Collatz')
        self.setWindowTitle(" Collatz")
        self.setFixedSize(350, 550)
        dir_name = os.path.dirname(os.path.realpath(__file__))
        self.setWindowIcon(QtGui.QIcon(dir_name + os.path.sep + 'icon.svg'))
        self.setWindowIcon(QtGui.QIcon(dir_name + os.path.sep + "icon.svg"))
        self.counter = 0

        # Create start button
        self.start_button = QtWidgets.QPushButton('Start', self)
        self.start_button = QtWidgets.QPushButton("Start", self)
        self.start_button.clicked.connect(self._on_click_start)

        # Create textbox for number input


@@ 33,7 35,7 @@ class CollatzApp(QtWidgets.QMainWindow):

        # Create 'Steps' label
        self.steps_label = QtWidgets.QLabel(self)
        self.steps_label.setText('Steps')
        self.steps_label.setText("Steps")
        self.steps_label.setAlignment(QtCore.Qt.AlignCenter)
        font_ = self.steps_label.font()
        font_.setPointSize(10)


@@ 46,16 48,17 @@ class CollatzApp(QtWidgets.QMainWindow):
        self.steps_display.setFont(font_)
        # Set tab width to 4 spaces
        self.steps_display.setTabStopDistance(
            QtGui.QFontMetricsF(font_).horizontalAdvance(' ') * 8)
            QtGui.QFontMetricsF(font_).horizontalAdvance(" ") * 8
        )
        self.steps_display.setLineWrapMode(QtWidgets.QPlainTextEdit.NoWrap)
        self.steps_display.setReadOnly(True)

        # Create clear button
        self.clear_button = QtWidgets.QPushButton('Clear', self)
        self.clear_button = QtWidgets.QPushButton("Clear", self)
        self.clear_button.clicked.connect(self._on_click_clear)

        # Create info button
        self.info_button = QtWidgets.QPushButton('Info', self)
        self.info_button = QtWidgets.QPushButton("Info", self)
        self.info_button.clicked.connect(self._on_click_info)

        # Add widgets to window


@@ 87,14 90,13 @@ class CollatzApp(QtWidgets.QMainWindow):
        while number != 1:
            self.steps_display.insertPlainText(str(number))
            if number % 2 == 0:
                self.steps_display.insertPlainText('\t| /2\n')
                self.steps_display.insertPlainText("\t| /2\n")
                number = int(number / 2)
            else:
                self.steps_display.insertPlainText('\t| *3 + 1\n')
                self.steps_display.insertPlainText("\t| *3 + 1\n")
                number = 3 * number + 1
            self.counter += 1


    @QtCore.pyqtSlot()
    def _on_click_start(self):
        """Clear the `stepsDisplay` and start the Collatz sequence."""


@@ 108,7 110,8 @@ class CollatzApp(QtWidgets.QMainWindow):
        self.counter = 0
        self._sequence(input_value)
        self.steps_display.insertPlainText(
            f'Terminated after {self.counter} iterations.')
            f"Terminated after {self.counter} iterations."
        )
        self.steps_display.moveCursor(QtGui.QTextCursor.End)

    @QtCore.pyqtSlot()


@@ 124,6 127,6 @@ class CollatzApp(QtWidgets.QMainWindow):
        """Open a dialog window to acces the relevant Wikipedia article."""

        if BrowserDialog(self).exec():
            webbrowser.open('https://en.wikipedia.org/wiki/Collatz_conjecture')
            webbrowser.open("https://en.wikipedia.org/wiki/Collatz_conjecture")
        else:
            self.input_box.setFocus()

M collatz/dialog.py => collatz/dialog.py +5 -6
@@ 1,10 1,11 @@
"""This module contains the custom dialog box."""
import os
from PyQt5 import QtGui, QtWidgets, QtCore

from PyQt5 import QtCore, QtGui, QtWidgets


class BrowserDialog(QtWidgets.QDialog):
    """ This is a custom dialog box for opening the Collatz
    """This is a custom dialog box for opening the Collatz
    conjecture Wikipedia page in a web browser.
    """



@@ 12,8 13,7 @@ class BrowserDialog(QtWidgets.QDialog):
        super(BrowserDialog, self).__init__(*args, **kwargs)

        self.setWindowTitle("Info")
        self.setWindowIcon(QtGui.QIcon(
            os.path.dirname(__file__) + '/icon.svg'))
        self.setWindowIcon(QtGui.QIcon(os.path.dirname(__file__) + "/icon.svg"))

        # Buttons
        q_btn = QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel


@@ 21,8 21,7 @@ class BrowserDialog(QtWidgets.QDialog):
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)

        self.message = QtWidgets.QLabel(
            'This will open your browser.\nContinue?', self)
        self.message = QtWidgets.QLabel("This will open your browser.\nContinue?", self)
        self.message.setAlignment(QtCore.Qt.AlignCenter)

        self.layout = QtWidgets.QVBoxLayout()

M collatz/validator.py => collatz/validator.py +2 -2
@@ 8,13 8,13 @@ class IntValidator(QtGui.QDoubleValidator):
    integers, which are possible in Python.
    """

    def __init__(self, bottom=float('-inf'), top=float('inf')):
    def __init__(self, bottom=float("-inf"), top=float("inf")):
        super(IntValidator, self).__init__(bottom, top, 0)
        self.setNotation(QtGui.QDoubleValidator.StandardNotation)

    def validate(self, text, pos):
        """Validate which disalows the '.' symbol."""
        # Disallow '.' symbol since only ints are allowed
        if text.endswith('.'):
        if text.endswith("."):
            return QtGui.QValidator.Invalid, text, pos
        return super(IntValidator, self).validate(text, pos)

M poetry.lock => poetry.lock +366 -1
@@ 1,4 1,150 @@
[[package]]
name = "astroid"
version = "2.9.3"
description = "An abstract syntax tree for Python with inference support."
category = "dev"
optional = false
python-versions = ">=3.6.2"

[package.dependencies]
lazy-object-proxy = ">=1.4.0"
typing-extensions = {version = ">=3.10", markers = "python_version < \"3.10\""}
wrapt = ">=1.11,<1.14"

[[package]]
name = "black"
version = "22.1.0"
description = "The uncompromising code formatter."
category = "dev"
optional = false
python-versions = ">=3.6.2"

[package.dependencies]
click = ">=8.0.0"
mypy-extensions = ">=0.4.3"
pathspec = ">=0.9.0"
platformdirs = ">=2"
tomli = ">=1.1.0"
typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}

[package.extras]
colorama = ["colorama (>=0.4.3)"]
d = ["aiohttp (>=3.7.4)"]
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
uvloop = ["uvloop (>=0.15.2)"]

[[package]]
name = "click"
version = "8.0.4"
description = "Composable command line interface toolkit"
category = "dev"
optional = false
python-versions = ">=3.6"

[package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""}

[[package]]
name = "colorama"
version = "0.4.4"
description = "Cross-platform colored terminal text."
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"

[[package]]
name = "isort"
version = "5.10.1"
description = "A Python utility / library to sort Python imports."
category = "dev"
optional = false
python-versions = ">=3.6.1,<4.0"

[package.extras]
pipfile_deprecated_finder = ["pipreqs", "requirementslib"]
requirements_deprecated_finder = ["pipreqs", "pip-api"]
colors = ["colorama (>=0.4.3,<0.5.0)"]
plugins = ["setuptools"]

[[package]]
name = "lazy-object-proxy"
version = "1.7.1"
description = "A fast and thorough lazy object proxy."
category = "dev"
optional = false
python-versions = ">=3.6"

[[package]]
name = "mccabe"
version = "0.6.1"
description = "McCabe checker, plugin for flake8"
category = "dev"
optional = false
python-versions = "*"

[[package]]
name = "mypy"
version = "0.931"
description = "Optional static typing for Python"
category = "dev"
optional = false
python-versions = ">=3.6"

[package.dependencies]
mypy-extensions = ">=0.4.3"
tomli = ">=1.1.0"
typing-extensions = ">=3.10"

[package.extras]
dmypy = ["psutil (>=4.0)"]
python2 = ["typed-ast (>=1.4.0,<2)"]

[[package]]
name = "mypy-extensions"
version = "0.4.3"
description = "Experimental type system extensions for programs checked with the mypy typechecker."
category = "dev"
optional = false
python-versions = "*"

[[package]]
name = "pathspec"
version = "0.9.0"
description = "Utility library for gitignore style pattern matching of file paths."
category = "dev"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"

[[package]]
name = "platformdirs"
version = "2.5.1"
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
category = "dev"
optional = false
python-versions = ">=3.7"

[package.extras]
docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"]
test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"]

[[package]]
name = "pylint"
version = "2.12.2"
description = "python code static checker"
category = "dev"
optional = false
python-versions = ">=3.6.2"

[package.dependencies]
astroid = ">=2.9.0,<2.10"
colorama = {version = "*", markers = "sys_platform == \"win32\""}
isort = ">=4.2.5,<6"
mccabe = ">=0.6,<0.7"
platformdirs = ">=2.2.0"
toml = ">=0.9.2"
typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""}

[[package]]
name = "pyqt5"
version = "5.15.0"
description = "Python bindings for the Qt cross platform application toolkit"


@@ 17,12 163,166 @@ category = "main"
optional = false
python-versions = ">=3.5"

[[package]]
name = "toml"
version = "0.10.2"
description = "Python Library for Tom's Obvious, Minimal Language"
category = "dev"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"

[[package]]
name = "tomli"
version = "2.0.1"
description = "A lil' TOML parser"
category = "dev"
optional = false
python-versions = ">=3.7"

[[package]]
name = "typing-extensions"
version = "4.1.1"
description = "Backported and Experimental Type Hints for Python 3.6+"
category = "dev"
optional = false
python-versions = ">=3.6"

[[package]]
name = "wrapt"
version = "1.13.3"
description = "Module for decorators, wrappers and monkey patching."
category = "dev"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"

[metadata]
lock-version = "1.1"
python-versions = "^3.9"
content-hash = "d06223251f14b9f8135949d336b4eb3b33e35c51ec7ce1d26ce3d71000a9d9e4"
content-hash = "e12a4ba428f67a983fe0088b87fde14ade252818df294a007fe1a7c88d72873a"

[metadata.files]
astroid = [
    {file = "astroid-2.9.3-py3-none-any.whl", hash = "sha256:506daabe5edffb7e696ad82483ad0228245a9742ed7d2d8c9cdb31537decf9f6"},
    {file = "astroid-2.9.3.tar.gz", hash = "sha256:1efdf4e867d4d8ba4a9f6cf9ce07cd182c4c41de77f23814feb27ca93ca9d877"},
]
black = [
    {file = "black-22.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1297c63b9e1b96a3d0da2d85d11cd9bf8664251fd69ddac068b98dc4f34f73b6"},
    {file = "black-22.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ff96450d3ad9ea499fc4c60e425a1439c2120cbbc1ab959ff20f7c76ec7e866"},
    {file = "black-22.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e21e1f1efa65a50e3960edd068b6ae6d64ad6235bd8bfea116a03b21836af71"},
    {file = "black-22.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f69158a7d120fd641d1fa9a921d898e20d52e44a74a6fbbcc570a62a6bc8ab"},
    {file = "black-22.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:228b5ae2c8e3d6227e4bde5920d2fc66cc3400fde7bcc74f480cb07ef0b570d5"},
    {file = "black-22.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b1a5ed73ab4c482208d20434f700d514f66ffe2840f63a6252ecc43a9bc77e8a"},
    {file = "black-22.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35944b7100af4a985abfcaa860b06af15590deb1f392f06c8683b4381e8eeaf0"},
    {file = "black-22.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7835fee5238fc0a0baf6c9268fb816b5f5cd9b8793423a75e8cd663c48d073ba"},
    {file = "black-22.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dae63f2dbf82882fa3b2a3c49c32bffe144970a573cd68d247af6560fc493ae1"},
    {file = "black-22.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa1db02410b1924b6749c245ab38d30621564e658297484952f3d8a39fce7e8"},
    {file = "black-22.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c8226f50b8c34a14608b848dc23a46e5d08397d009446353dad45e04af0c8e28"},
    {file = "black-22.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2d6f331c02f0f40aa51a22e479c8209d37fcd520c77721c034517d44eecf5912"},
    {file = "black-22.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:742ce9af3086e5bd07e58c8feb09dbb2b047b7f566eb5f5bc63fd455814979f3"},
    {file = "black-22.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fdb8754b453fb15fad3f72cd9cad3e16776f0964d67cf30ebcbf10327a3777a3"},
    {file = "black-22.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5660feab44c2e3cb24b2419b998846cbb01c23c7fe645fee45087efa3da2d61"},
    {file = "black-22.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:6f2f01381f91c1efb1451998bd65a129b3ed6f64f79663a55fe0e9b74a5f81fd"},
    {file = "black-22.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:efbadd9b52c060a8fc3b9658744091cb33c31f830b3f074422ed27bad2b18e8f"},
    {file = "black-22.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8871fcb4b447206904932b54b567923e5be802b9b19b744fdff092bd2f3118d0"},
    {file = "black-22.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccad888050f5393f0d6029deea2a33e5ae371fd182a697313bdbd835d3edaf9c"},
    {file = "black-22.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07e5c049442d7ca1a2fc273c79d1aecbbf1bc858f62e8184abe1ad175c4f7cc2"},
    {file = "black-22.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:373922fc66676133ddc3e754e4509196a8c392fec3f5ca4486673e685a421321"},
    {file = "black-22.1.0-py3-none-any.whl", hash = "sha256:3524739d76b6b3ed1132422bf9d82123cd1705086723bc3e235ca39fd21c667d"},
    {file = "black-22.1.0.tar.gz", hash = "sha256:a7c0192d35635f6fc1174be575cb7915e92e5dd629ee79fdaf0dcfa41a80afb5"},
]
click = [
    {file = "click-8.0.4-py3-none-any.whl", hash = "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1"},
    {file = "click-8.0.4.tar.gz", hash = "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"},
]
colorama = [
    {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
    {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
]
isort = [
    {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"},
    {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"},
]
lazy-object-proxy = [
    {file = "lazy-object-proxy-1.7.1.tar.gz", hash = "sha256:d609c75b986def706743cdebe5e47553f4a5a1da9c5ff66d76013ef396b5a8a4"},
    {file = "lazy_object_proxy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb8c5fd1684d60a9902c60ebe276da1f2281a318ca16c1d0a96db28f62e9166b"},
    {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a57d51ed2997e97f3b8e3500c984db50a554bb5db56c50b5dab1b41339b37e36"},
    {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd45683c3caddf83abbb1249b653a266e7069a09f486daa8863fb0e7496a9fdb"},
    {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8561da8b3dd22d696244d6d0d5330618c993a215070f473b699e00cf1f3f6443"},
    {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fccdf7c2c5821a8cbd0a9440a456f5050492f2270bd54e94360cac663398739b"},
    {file = "lazy_object_proxy-1.7.1-cp310-cp310-win32.whl", hash = "sha256:898322f8d078f2654d275124a8dd19b079080ae977033b713f677afcfc88e2b9"},
    {file = "lazy_object_proxy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:85b232e791f2229a4f55840ed54706110c80c0a210d076eee093f2b2e33e1bfd"},
    {file = "lazy_object_proxy-1.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:46ff647e76f106bb444b4533bb4153c7370cdf52efc62ccfc1a28bdb3cc95442"},
    {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12f3bb77efe1367b2515f8cb4790a11cffae889148ad33adad07b9b55e0ab22c"},
    {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c19814163728941bb871240d45c4c30d33b8a2e85972c44d4e63dd7107faba44"},
    {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e40f2013d96d30217a51eeb1db28c9ac41e9d0ee915ef9d00da639c5b63f01a1"},
    {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2052837718516a94940867e16b1bb10edb069ab475c3ad84fd1e1a6dd2c0fcfc"},
    {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win32.whl", hash = "sha256:6a24357267aa976abab660b1d47a34aaf07259a0c3859a34e536f1ee6e76b5bb"},
    {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6aff3fe5de0831867092e017cf67e2750c6a1c7d88d84d2481bd84a2e019ec35"},
    {file = "lazy_object_proxy-1.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6a6e94c7b02641d1311228a102607ecd576f70734dc3d5e22610111aeacba8a0"},
    {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ce15276a1a14549d7e81c243b887293904ad2d94ad767f42df91e75fd7b5b6"},
    {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e368b7f7eac182a59ff1f81d5f3802161932a41dc1b1cc45c1f757dc876b5d2c"},
    {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6ecbb350991d6434e1388bee761ece3260e5228952b1f0c46ffc800eb313ff42"},
    {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:553b0f0d8dbf21890dd66edd771f9b1b5f51bd912fa5f26de4449bfc5af5e029"},
    {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win32.whl", hash = "sha256:c7a683c37a8a24f6428c28c561c80d5f4fd316ddcf0c7cab999b15ab3f5c5c69"},
    {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:df2631f9d67259dc9620d831384ed7732a198eb434eadf69aea95ad18c587a28"},
    {file = "lazy_object_proxy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07fa44286cda977bd4803b656ffc1c9b7e3bc7dff7d34263446aec8f8c96f88a"},
    {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dca6244e4121c74cc20542c2ca39e5c4a5027c81d112bfb893cf0790f96f57e"},
    {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91ba172fc5b03978764d1df5144b4ba4ab13290d7bab7a50f12d8117f8630c38"},
    {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:043651b6cb706eee4f91854da4a089816a6606c1428fd391573ef8cb642ae4f7"},
    {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b9e89b87c707dd769c4ea91f7a31538888aad05c116a59820f28d59b3ebfe25a"},
    {file = "lazy_object_proxy-1.7.1-cp38-cp38-win32.whl", hash = "sha256:9d166602b525bf54ac994cf833c385bfcc341b364e3ee71e3bf5a1336e677b55"},
    {file = "lazy_object_proxy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:8f3953eb575b45480db6568306893f0bd9d8dfeeebd46812aa09ca9579595148"},
    {file = "lazy_object_proxy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dd7ed7429dbb6c494aa9bc4e09d94b778a3579be699f9d67da7e6804c422d3de"},
    {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70ed0c2b380eb6248abdef3cd425fc52f0abd92d2b07ce26359fcbc399f636ad"},
    {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7096a5e0c1115ec82641afbdd70451a144558ea5cf564a896294e346eb611be1"},
    {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f769457a639403073968d118bc70110e7dce294688009f5c24ab78800ae56dc8"},
    {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:39b0e26725c5023757fc1ab2a89ef9d7ab23b84f9251e28f9cc114d5b59c1b09"},
    {file = "lazy_object_proxy-1.7.1-cp39-cp39-win32.whl", hash = "sha256:2130db8ed69a48a3440103d4a520b89d8a9405f1b06e2cc81640509e8bf6548f"},
    {file = "lazy_object_proxy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61"},
    {file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"},
]
mccabe = [
    {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
    {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
]
mypy = [
    {file = "mypy-0.931-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3c5b42d0815e15518b1f0990cff7a705805961613e701db60387e6fb663fe78a"},
    {file = "mypy-0.931-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c89702cac5b302f0c5d33b172d2b55b5df2bede3344a2fbed99ff96bddb2cf00"},
    {file = "mypy-0.931-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:300717a07ad09525401a508ef5d105e6b56646f7942eb92715a1c8d610149714"},
    {file = "mypy-0.931-cp310-cp310-win_amd64.whl", hash = "sha256:7b3f6f557ba4afc7f2ce6d3215d5db279bcf120b3cfd0add20a5d4f4abdae5bc"},
    {file = "mypy-0.931-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:1bf752559797c897cdd2c65f7b60c2b6969ffe458417b8d947b8340cc9cec08d"},
    {file = "mypy-0.931-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4365c60266b95a3f216a3047f1d8e3f895da6c7402e9e1ddfab96393122cc58d"},
    {file = "mypy-0.931-cp36-cp36m-win_amd64.whl", hash = "sha256:1b65714dc296a7991000b6ee59a35b3f550e0073411ac9d3202f6516621ba66c"},
    {file = "mypy-0.931-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e839191b8da5b4e5d805f940537efcaa13ea5dd98418f06dc585d2891d228cf0"},
    {file = "mypy-0.931-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:50c7346a46dc76a4ed88f3277d4959de8a2bd0a0fa47fa87a4cde36fe247ac05"},
    {file = "mypy-0.931-cp37-cp37m-win_amd64.whl", hash = "sha256:d8f1ff62f7a879c9fe5917b3f9eb93a79b78aad47b533911b853a757223f72e7"},
    {file = "mypy-0.931-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f9fe20d0872b26c4bba1c1be02c5340de1019530302cf2dcc85c7f9fc3252ae0"},
    {file = "mypy-0.931-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1b06268df7eb53a8feea99cbfff77a6e2b205e70bf31743e786678ef87ee8069"},
    {file = "mypy-0.931-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8c11003aaeaf7cc2d0f1bc101c1cc9454ec4cc9cb825aef3cafff8a5fdf4c799"},
    {file = "mypy-0.931-cp38-cp38-win_amd64.whl", hash = "sha256:d9d2b84b2007cea426e327d2483238f040c49405a6bf4074f605f0156c91a47a"},
    {file = "mypy-0.931-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ff3bf387c14c805ab1388185dd22d6b210824e164d4bb324b195ff34e322d166"},
    {file = "mypy-0.931-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5b56154f8c09427bae082b32275a21f500b24d93c88d69a5e82f3978018a0266"},
    {file = "mypy-0.931-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8ca7f8c4b1584d63c9a0f827c37ba7a47226c19a23a753d52e5b5eddb201afcd"},
    {file = "mypy-0.931-cp39-cp39-win_amd64.whl", hash = "sha256:74f7eccbfd436abe9c352ad9fb65872cc0f1f0a868e9d9c44db0893440f0c697"},
    {file = "mypy-0.931-py3-none-any.whl", hash = "sha256:1171f2e0859cfff2d366da2c7092b06130f232c636a3f7301e3feb8b41f6377d"},
    {file = "mypy-0.931.tar.gz", hash = "sha256:0038b21890867793581e4cb0d810829f5fd4441aa75796b53033af3aa30430ce"},
]
mypy-extensions = [
    {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
    {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
]
pathspec = [
    {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"},
    {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
]
platformdirs = [
    {file = "platformdirs-2.5.1-py3-none-any.whl", hash = "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227"},
    {file = "platformdirs-2.5.1.tar.gz", hash = "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d"},
]
pylint = [
    {file = "pylint-2.12.2-py3-none-any.whl", hash = "sha256:daabda3f7ed9d1c60f52d563b1b854632fd90035bcf01443e234d3dc794e3b74"},
    {file = "pylint-2.12.2.tar.gz", hash = "sha256:9d945a73640e1fec07ee34b42f5669b770c759acd536ec7b16d7e4b87a9c9ff9"},
]
pyqt5 = [
    {file = "PyQt5-5.15.0-5.15.0-cp35.cp36.cp37.cp38-abi3-macosx_10_6_intel.whl", hash = "sha256:14be35c0c1bcc804791a096d2ef9950f12c6fd34dd11dbe61b8c769fefcdf98c"},
    {file = "PyQt5-5.15.0-5.15.0-cp35.cp36.cp37.cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:3605d34ba6291b9194c46035e228d6d01f39d120cf5ecc70301c11e7900fed21"},


@@ 53,3 353,68 @@ pyqt5-sip = [
    {file = "PyQt5_sip-12.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:b09f4cd36a4831229fb77c424d89635fa937d97765ec90685e2f257e56a2685a"},
    {file = "PyQt5_sip-12.9.0.tar.gz", hash = "sha256:d3e4489d7c2b0ece9d203ae66e573939f7f60d4d29e089c9f11daa17cfeaae32"},
]
toml = [
    {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
    {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
]
tomli = [
    {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
    {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]
typing-extensions = [
    {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"},
    {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"},
]
wrapt = [
    {file = "wrapt-1.13.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:e05e60ff3b2b0342153be4d1b597bbcfd8330890056b9619f4ad6b8d5c96a81a"},
    {file = "wrapt-1.13.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:85148f4225287b6a0665eef08a178c15097366d46b210574a658c1ff5b377489"},
    {file = "wrapt-1.13.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:2dded5496e8f1592ec27079b28b6ad2a1ef0b9296d270f77b8e4a3a796cf6909"},
    {file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e94b7d9deaa4cc7bac9198a58a7240aaf87fe56c6277ee25fa5b3aa1edebd229"},
    {file = "wrapt-1.13.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:498e6217523111d07cd67e87a791f5e9ee769f9241fcf8a379696e25806965af"},
    {file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ec7e20258ecc5174029a0f391e1b948bf2906cd64c198a9b8b281b811cbc04de"},
    {file = "wrapt-1.13.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:87883690cae293541e08ba2da22cacaae0a092e0ed56bbba8d018cc486fbafbb"},
    {file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:f99c0489258086308aad4ae57da9e8ecf9e1f3f30fa35d5e170b4d4896554d80"},
    {file = "wrapt-1.13.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6a03d9917aee887690aa3f1747ce634e610f6db6f6b332b35c2dd89412912bca"},
    {file = "wrapt-1.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:936503cb0a6ed28dbfa87e8fcd0a56458822144e9d11a49ccee6d9a8adb2ac44"},
    {file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f9c51d9af9abb899bd34ace878fbec8bf357b3194a10c4e8e0a25512826ef056"},
    {file = "wrapt-1.13.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:220a869982ea9023e163ba915077816ca439489de6d2c09089b219f4e11b6785"},
    {file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0877fe981fd76b183711d767500e6b3111378ed2043c145e21816ee589d91096"},
    {file = "wrapt-1.13.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:43e69ffe47e3609a6aec0fe723001c60c65305784d964f5007d5b4fb1bc6bf33"},
    {file = "wrapt-1.13.3-cp310-cp310-win32.whl", hash = "sha256:78dea98c81915bbf510eb6a3c9c24915e4660302937b9ae05a0947164248020f"},
    {file = "wrapt-1.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:ea3e746e29d4000cd98d572f3ee2a6050a4f784bb536f4ac1f035987fc1ed83e"},
    {file = "wrapt-1.13.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8c73c1a2ec7c98d7eaded149f6d225a692caa1bd7b2401a14125446e9e90410d"},
    {file = "wrapt-1.13.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:086218a72ec7d986a3eddb7707c8c4526d677c7b35e355875a0fe2918b059179"},
    {file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:e92d0d4fa68ea0c02d39f1e2f9cb5bc4b4a71e8c442207433d8db47ee79d7aa3"},
    {file = "wrapt-1.13.3-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:d4a5f6146cfa5c7ba0134249665acd322a70d1ea61732723c7d3e8cc0fa80755"},
    {file = "wrapt-1.13.3-cp35-cp35m-win32.whl", hash = "sha256:8aab36778fa9bba1a8f06a4919556f9f8c7b33102bd71b3ab307bb3fecb21851"},
    {file = "wrapt-1.13.3-cp35-cp35m-win_amd64.whl", hash = "sha256:944b180f61f5e36c0634d3202ba8509b986b5fbaf57db3e94df11abee244ba13"},
    {file = "wrapt-1.13.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2ebdde19cd3c8cdf8df3fc165bc7827334bc4e353465048b36f7deeae8ee0918"},
    {file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:610f5f83dd1e0ad40254c306f4764fcdc846641f120c3cf424ff57a19d5f7ade"},
    {file = "wrapt-1.13.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5601f44a0f38fed36cc07db004f0eedeaadbdcec90e4e90509480e7e6060a5bc"},
    {file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:e6906d6f48437dfd80464f7d7af1740eadc572b9f7a4301e7dd3d65db285cacf"},
    {file = "wrapt-1.13.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:766b32c762e07e26f50d8a3468e3b4228b3736c805018e4b0ec8cc01ecd88125"},
    {file = "wrapt-1.13.3-cp36-cp36m-win32.whl", hash = "sha256:5f223101f21cfd41deec8ce3889dc59f88a59b409db028c469c9b20cfeefbe36"},
    {file = "wrapt-1.13.3-cp36-cp36m-win_amd64.whl", hash = "sha256:f122ccd12fdc69628786d0c947bdd9cb2733be8f800d88b5a37c57f1f1d73c10"},
    {file = "wrapt-1.13.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:46f7f3af321a573fc0c3586612db4decb7eb37172af1bc6173d81f5b66c2e068"},
    {file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:778fd096ee96890c10ce96187c76b3e99b2da44e08c9e24d5652f356873f6709"},
    {file = "wrapt-1.13.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0cb23d36ed03bf46b894cfec777eec754146d68429c30431c99ef28482b5c1df"},
    {file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:96b81ae75591a795d8c90edc0bfaab44d3d41ffc1aae4d994c5aa21d9b8e19a2"},
    {file = "wrapt-1.13.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7dd215e4e8514004c8d810a73e342c536547038fb130205ec4bba9f5de35d45b"},
    {file = "wrapt-1.13.3-cp37-cp37m-win32.whl", hash = "sha256:47f0a183743e7f71f29e4e21574ad3fa95676136f45b91afcf83f6a050914829"},
    {file = "wrapt-1.13.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fd76c47f20984b43d93de9a82011bb6e5f8325df6c9ed4d8310029a55fa361ea"},
    {file = "wrapt-1.13.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b73d4b78807bd299b38e4598b8e7bd34ed55d480160d2e7fdaabd9931afa65f9"},
    {file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ec9465dd69d5657b5d2fa6133b3e1e989ae27d29471a672416fd729b429eb554"},
    {file = "wrapt-1.13.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dd91006848eb55af2159375134d724032a2d1d13bcc6f81cd8d3ed9f2b8e846c"},
    {file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ae9de71eb60940e58207f8e71fe113c639da42adb02fb2bcbcaccc1ccecd092b"},
    {file = "wrapt-1.13.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:51799ca950cfee9396a87f4a1240622ac38973b6df5ef7a41e7f0b98797099ce"},
    {file = "wrapt-1.13.3-cp38-cp38-win32.whl", hash = "sha256:4b9c458732450ec42578b5642ac53e312092acf8c0bfce140ada5ca1ac556f79"},
    {file = "wrapt-1.13.3-cp38-cp38-win_amd64.whl", hash = "sha256:7dde79d007cd6dfa65afe404766057c2409316135cb892be4b1c768e3f3a11cb"},
    {file = "wrapt-1.13.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:981da26722bebb9247a0601e2922cedf8bb7a600e89c852d063313102de6f2cb"},
    {file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:705e2af1f7be4707e49ced9153f8d72131090e52be9278b5dbb1498c749a1e32"},
    {file = "wrapt-1.13.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:25b1b1d5df495d82be1c9d2fad408f7ce5ca8a38085e2da41bb63c914baadff7"},
    {file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:77416e6b17926d953b5c666a3cb718d5945df63ecf922af0ee576206d7033b5e"},
    {file = "wrapt-1.13.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:865c0b50003616f05858b22174c40ffc27a38e67359fa1495605f96125f76640"},
    {file = "wrapt-1.13.3-cp39-cp39-win32.whl", hash = "sha256:0a017a667d1f7411816e4bf214646d0ad5b1da2c1ea13dec6c162736ff25a374"},
    {file = "wrapt-1.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:81bd7c90d28a4b2e1df135bfbd7c23aee3050078ca6441bead44c42483f9ebfb"},
    {file = "wrapt-1.13.3.tar.gz", hash = "sha256:1fea9cd438686e6682271d36f3481a9f3636195578bab9ca3382e2f5f01fc185"},
]

M pyproject.toml => pyproject.toml +4 -0
@@ 15,6 15,10 @@ python = "^3.9"
pyqt5 = "5.15.0"

[tool.poetry.dev-dependencies]
pylint = "^2.12.2"
black = "^22.1.0"
mypy = "^0.931"
isort = "^5.10.1"

[build-system]
requires = ["poetry-core>=1.0.0"]

M tictactoe/__main__.py => tictactoe/__main__.py +6 -5
@@ 1,14 1,15 @@
"""This is the `__main__` module."""
import random
from game import print_board, input_position, check_win

from game import check_win, input_position, print_board

if __name__ == "__main__":
    CURRENT_PLAYER = random.choice(['o', 'x'])
    CURRENT_PLAYER = random.choice(["o", "x"])
    while True:
        print_board()
        check_win()
        input_position(CURRENT_PLAYER)
        if CURRENT_PLAYER == 'x':
            CURRENT_PLAYER = 'o'
        if CURRENT_PLAYER == "x":
            CURRENT_PLAYER = "o"
        else:
            CURRENT_PLAYER = 'x'
            CURRENT_PLAYER = "x"

M tictactoe/game.py => tictactoe/game.py +15 -14
@@ 5,18 5,19 @@ import sys
# Global variable board is a 0-9 list, which eventually get replaced with x/o
BOARD = list(range(9))


def print_board():
    """Clear the terminal screen and print the board."""

    global BOARD
    # Clear the screen with cls (Windows) or clear (other systems)
    os.system('cls' if os.name == 'nt' else 'clear')
    os.system("cls" if os.name == "nt" else "clear")
    # Print the board
    print(f'{BOARD[0]} | {BOARD[1]} | {BOARD[2]}')
    print('----------')
    print(f'{BOARD[3]} | {BOARD[4]} | {BOARD[5]}')
    print('----------')
    print(f'{BOARD[6]} | {BOARD[7]} | {BOARD[8]}', end='\n\n')
    print(f"{BOARD[0]} | {BOARD[1]} | {BOARD[2]}")
    print("----------")
    print(f"{BOARD[3]} | {BOARD[4]} | {BOARD[5]}")
    print("----------")
    print(f"{BOARD[6]} | {BOARD[7]} | {BOARD[8]}", end="\n\n")


def input_position(player):


@@ 24,8 25,8 @@ def input_position(player):

    while True:
        try:
            pos_string = input(f'{player}\'s turn: ')
            if pos_string == 'q':
            pos_string = input(f"{player}'s turn: ")
            if pos_string == "q":
                sys.exit()
            position = int(pos_string)
            if position in BOARD:


@@ 47,26 48,26 @@ def check_win():
    # Check horizontal lines with h_index and vertical lines with v_index
    for _ in range(0, 3):
        if BOARD[h_index] == BOARD[h_index + 1] == BOARD[h_index + 2]:
            print(f'{BOARD[h_index]} won!')
            print(f"{BOARD[h_index]} won!")
            sys.exit()
        if BOARD[v_index] == BOARD[v_index + 3] == BOARD[v_index + 6]:
            print(f'{BOARD[v_index]} won!')
            print(f"{BOARD[v_index]} won!")
            sys.exit()
        h_index += 3
        v_index += 1

    # Check diagonals
    if BOARD[0] == BOARD[4] == BOARD[8]:
        print(f'{BOARD[0]} won!')
        print(f"{BOARD[0]} won!")
        sys.exit()
    if BOARD[2] == BOARD[4] == BOARD[6]:
        print(f'{BOARD[2]} won!')
        print(f"{BOARD[2]} won!")
        sys.exit()
    # Check if the board is NOT full
    for cell in BOARD:
        if str(cell) in '012345678':
        if str(cell) in "012345678":
            break
    # If full draw the game
    else:
        print('Draw!')
        print("Draw!")
        sys.exit()