diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml new file mode 100644 index 0000000..cd97d32 --- /dev/null +++ b/.github/workflows/main.yaml @@ -0,0 +1,33 @@ +name: Dashmips + +on: + push: + branches: + - master + - "feature/**" + pull_request: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install Poetry + run: | + curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python + source $HOME/.poetry/env + - name: Install Dependencies + run: | + source $HOME/.poetry/env + poetry install + - name: Test with pytest + run: | + source $HOME/.poetry/env + poetry run pytest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..49c2dcf --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,62 @@ +on: + push: + # Sequence of patterns matched against refs/tags + tags: + - "*" # Push events to matching v*, i.e. v1.0, v20.15.10 + +name: Upload Release Asset + +jobs: + build: + name: Upload Release Asset + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install Poetry + run: | + curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python + source $HOME/.poetry/env + + # makes ./dist/dashmips-{version}-py3-none-any.whl + # file name is: {distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}.whl + - name: Build project + run: | + source $HOME/.poetry/env + poetry build -f wheel + + - name: Get the version + id: get_version + run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//} + shell: bash + + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + draft: false + prerelease: false + + - name: Upload Release Asset + id: upload-release-asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./dist/dashmips-${{ steps.get_version.outputs.VERSION }}-py3-none-any.whl + asset_name: dashmips-${{ steps.get_version.outputs.VERSION }}-py3-none-any.whl + asset_content_type: application/x-wheel+zip + + - name: Publish a Python distribution to PyPI + uses: pypa/gh-action-pypi-publish@v1.3.1 + with: + user: __token__ + password: ${{ secrets.pypi_password }} diff --git a/.gitignore b/.gitignore index bc26811..504dbb7 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ dist/ dashmips_env/ testout/ .pytest_cache/ +.venv diff --git a/dashmips/__init__.py b/dashmips/__init__.py index 594e2e1..ad3ffb4 100644 --- a/dashmips/__init__.py +++ b/dashmips/__init__.py @@ -6,7 +6,7 @@ _DASH_HOME = _os.path.dirname(_os.path.abspath(__file__)) # Import all instructions -_instr_filter = (lambda fn: fn.endswith("_instructions.py")) +_instr_filter = lambda fn: fn.endswith("_instructions.py") _instr_files = _os.listdir(_os.path.join(_DASH_HOME, "instructions")) _instr_files = filter(_instr_filter, _instr_files) # type: ignore _instr_modules = [f"dashmips.instructions.{mn[:-3]}" for mn in _instr_files] @@ -15,7 +15,7 @@ _import_module(_im) # Import all syscalls -_syscall_filter = (lambda fn: fn.endswith("_syscalls.py")) +_syscall_filter = lambda fn: fn.endswith("_syscalls.py") _syscall_files = _os.listdir(_os.path.join(_DASH_HOME, "syscalls")) _syscall_files = filter(_syscall_filter, _syscall_files) # type: ignore _syscall_modules = [f"dashmips.syscalls.{mn[:-3]}" for mn in _syscall_files] @@ -23,7 +23,4 @@ for _sm in _syscall_modules: _import_module(_sm) -__all__ = [ - "syscalls", "instructions", "plugins", "directives", "hardware", "mips", - "models", "preprocessor", "run", "debugger", "debuggerserver" -] +__all__ = ["syscalls", "instructions", "plugins", "directives", "hardware", "mips", "models", "preprocessor", "run", "debugger", "debuggerserver"] diff --git a/dashmips/__main__.py b/dashmips/__main__.py index 1fe617e..a92cb9c 100644 --- a/dashmips/__main__.py +++ b/dashmips/__main__.py @@ -5,10 +5,10 @@ from threading import Thread from typing import Any, List, NoReturn -from .utils import MipsException from .extension import generate_snippets, instruction_name_regex from .plugins.vt100 import VT100 from .preprocessor import preprocess +from .utils import MipsException def main_compile(args: argparse.Namespace) -> int: @@ -28,7 +28,7 @@ def main_run(args: argparse.Namespace) -> int: program = preprocess(args.FILE, args=args.mips_args) plugins: List[Any] = [] if args.vt100: - vt = VT100() # type: ignore + vt = VT100() # program.memory.on_change(vt.push) t = Thread(target=run, args=(program,)) t.start() @@ -42,10 +42,11 @@ def main_run(args: argparse.Namespace) -> int: def main_debug(args: argparse.Namespace) -> int: """Start debug server for mips.""" from .debuggerserver import debug_mips, connectPreprocessFailure + try: program = preprocess(args.FILE, args=args.mips_args) except MipsException as err: - connectPreprocessFailure(host = args.host, port = args.port) + connectPreprocessFailure(host=args.host, port=args.port) raise MipsException(err.message) debug_mips(program, args.host, args.port, should_log=args.log) return 0 diff --git a/dashmips/debugger.py b/dashmips/debugger.py index 074fc57..1375cd8 100644 --- a/dashmips/debugger.py +++ b/dashmips/debugger.py @@ -82,6 +82,7 @@ def debug_verify_breakpoints(program: MipsProgram, params) -> Tuple[List[int], L local_breakpoints = [] remote_breakpoints = [] for breakpoint in breakpoints: + def checkfile(f: str) -> bool: return os.path.samefile(f, breakpoint["path"]) diff --git a/dashmips/debuggerserver.py b/dashmips/debuggerserver.py index cd704a8..04d041d 100644 --- a/dashmips/debuggerserver.py +++ b/dashmips/debuggerserver.py @@ -49,8 +49,7 @@ def debug_mips(program: MipsProgram, host="localhost", port=2390, should_log=Fal :param should_log: (Default value = False) """ log.basicConfig( - format="%(asctime)-15s %(levelname)-7s %(message)s", - level=log.INFO if should_log else log.CRITICAL, + format="%(asctime)-15s %(levelname)-7s %(message)s", level=log.INFO if should_log else log.CRITICAL, ) logger = log.getLogger("sockets.server") logger.addHandler(log.StreamHandler()) @@ -71,7 +70,7 @@ def handle(self): header = b"" while True: header += self.request.recv(1) - if header and chr(header[-1]) == '}': + if header and chr(header[-1]) == "}": break if len(header) >= 1000: log.error("Communication error between client and server") @@ -88,7 +87,7 @@ def handle(self): log.info("Program exited normally") break - self.request.sendall(bytes(json.dumps({"size": len(response)}), 'ascii') + bytes(response, 'ascii')) + self.request.sendall(bytes(json.dumps({"size": len(response)}), "ascii") + bytes(response, "ascii")) # Allows server to reuse address to prevent crash socketserver.TCPServer.allow_reuse_address = True @@ -101,8 +100,8 @@ def handle(self): def connectPreprocessFailure(host: str = "localhost", port: int = 2390): """Connect to extension and fail due to preprocessing failure.""" - class TCPHandler(socketserver.BaseRequestHandler): + class TCPHandler(socketserver.BaseRequestHandler): def handle(self): sleep(0.1) return diff --git a/dashmips/hardware.py b/dashmips/hardware.py index 731d1bd..369e452 100644 --- a/dashmips/hardware.py +++ b/dashmips/hardware.py @@ -1,8 +1,10 @@ """Mips Hardware.""" -from typing import Dict, Union, Tuple, Any, NoReturn, TypedDict, Literal, cast - import sys -from .utils import as_twos_comp, intify, MipsException +from typing import Any, Dict, NoReturn, Tuple, Union, cast + +from typing_extensions import Literal, TypedDict + +from .utils import MipsException, as_twos_comp, intify register_names = ( # fmt: off @@ -47,9 +49,9 @@ def __setitem__(self, key: str, value: int): if key in Registers.SPECIAL: return super().__setitem__(key, value) if key not in Registers.resolve: - raise MipsException(f'Unknown register Reg[{key}]={hex(value)}') + raise MipsException(f"Unknown register Reg[{key}]={hex(value)}") if value > 0xFFFF_FFFF: - print(f'Warning: Overflowed 32-bit Reg[{key}]={hex(value)}', file=sys.stderr) + print(f"Warning: Overflowed 32-bit Reg[{key}]={hex(value)}", file=sys.stderr) super().__setitem__(Registers.resolve[key], value & 0xFFFF_FFFF) def __getitem__(self, key: str) -> int: @@ -59,7 +61,7 @@ def __getitem__(self, key: str) -> int: return as_twos_comp(super().__getitem__(Registers.resolve[key])) -SectionNames = Union[Literal['stack'], Literal['heap'], Literal['data']] +SectionNames = Union[Literal["stack"], Literal["heap"], Literal["data"]] class RAMPART(TypedDict): @@ -81,8 +83,8 @@ class RAM(TypedDict): class Memory: """Memory simulated.""" - PAGE_SIZE = 2**12 - TASK_LIMIT = 0xc0000000 + PAGE_SIZE = 2 ** 12 + TASK_LIMIT = 0xC0000000 START_DATA = 0x00804900 STACK_STOP = 0x05F5E100 HEAP_START = 0x00600000 @@ -90,25 +92,14 @@ class Memory: def __init__(self): """Create Mips Memory.""" self.ram: RAM = { - "stack": { - "m": bytearray(), - "start": Memory.STACK_STOP, - "stops": Memory.STACK_STOP - }, - "heap": { - "m": bytearray(), - "start": Memory.HEAP_START, - "stops": Memory.HEAP_START - }, - "data": { - "m": bytearray(), - "start": Memory.START_DATA, - "stops": Memory.START_DATA - }, + "stack": {"m": bytearray(), "start": Memory.STACK_STOP, "stops": Memory.STACK_STOP}, + "heap": {"m": bytearray(), "start": Memory.HEAP_START, "stops": Memory.HEAP_START}, + "data": {"m": bytearray(), "start": Memory.START_DATA, "stops": Memory.START_DATA}, } def _tlb(self, virtual_address: int, sizeof=1) -> Tuple[SectionNames, slice]: - def v2p(pa: int): return slice(pa, pa + sizeof, 1) + def v2p(pa: int): + return slice(pa, pa + sizeof, 1) for section_name in self.ram: section_name = cast(SectionNames, section_name) @@ -249,5 +240,5 @@ def write_str(self, virtual_address: int, data: bytes): def alignment_zeros(data_len) -> bytearray: """Return array of 0s to align to 4.""" - alignment = ((4 - data_len % 4) % 4) + alignment = (4 - data_len % 4) % 4 return bytearray(alignment) diff --git a/dashmips/instructions/Instruction.py b/dashmips/instructions/Instruction.py index cde385e..136c893 100644 --- a/dashmips/instructions/Instruction.py +++ b/dashmips/instructions/Instruction.py @@ -36,7 +36,7 @@ def __call__(self, program: MipsProgram, args: Iterable[Any] = tuple()): try: self.function(program, *args) except KeyError as err: - raise MipsException(f'Symbol {err} not found in symbol table') + raise MipsException(f"Symbol {err} not found in symbol table") program.registers["pc"] += 1 def __repr__(self) -> str: diff --git a/dashmips/instructions/__init__.py b/dashmips/instructions/__init__.py index 6a46b65..696f8c6 100644 --- a/dashmips/instructions/__init__.py +++ b/dashmips/instructions/__init__.py @@ -11,6 +11,7 @@ def mips_instruction(pattern: str, parser, label: bool = False): """Make an Instruction object from decorated function.""" + def decorator(function) -> Instruction: """Instruction Decorator wrapper.""" instr = Instruction(function, pattern, parser, label=label) diff --git a/dashmips/instructions/pseudo_instructions.py b/dashmips/instructions/pseudo_instructions.py index 7080b8a..af3e462 100644 --- a/dashmips/instructions/pseudo_instructions.py +++ b/dashmips/instructions/pseudo_instructions.py @@ -43,8 +43,7 @@ def b(program: MipsProgram, label: str): @mips_instruction( - r"{instr_gap}({register}){args_gap}({register}|{number}){args_gap}({label})", - lambda args: (args[2], args[3], args[4]), + r"{instr_gap}({register}){args_gap}({register}|{number}){args_gap}({label})", lambda args: (args[2], args[3], args[4]), ) def bgt(program: MipsProgram, rd: str, rs: str, label: str): """Branch to label if Reg[rd]>Reg[rs].""" @@ -57,10 +56,7 @@ def bgt(program: MipsProgram, rd: str, rs: str, label: str): program.registers["pc"] = program.labels[label].value - 1 -@mips_instruction( - r"{instr_gap}({register}){args_gap}({register}|{number}){args_gap}({label})", - lambda args: (args[2], args[3], args[4]) -) +@mips_instruction(r"{instr_gap}({register}){args_gap}({register}|{number}){args_gap}({label})", lambda args: (args[2], args[3], args[4])) def blt(program: MipsProgram, rd: str, rs: str, label: str): """Branch to label if Reg[rd]Reg[rs].""" @@ -89,8 +84,7 @@ def bge(program: MipsProgram, rd: str, rs: str, label: str): @mips_instruction( - r"{instr_gap}({register}){args_gap}({register}){args_gap}({label})", - lambda args: (args[2], args[3], args[4]), + r"{instr_gap}({register}){args_gap}({register}){args_gap}({label})", lambda args: (args[2], args[3], args[4]), ) def ble(program: MipsProgram, rd: str, rs: str, label: str): """Branch to label if Reg[rd] str: def close(self, *a: Any): """Close the VT100 Window.""" - self.root.quit() # type: ignore + self.root.quit() def request_close(self): """Request to close the VT100 Window.""" @@ -111,7 +104,7 @@ def request_close(self): def pull(self, *changes: Any): """Pull Updated Screen.""" - vga_memory: bytes = self.content.get() # type: ignore + vga_memory: bytes = self.content.get() if not len(vga_memory) % 2 == 0 or not len(vga_memory) <= VT100.SIZE: # Sequence incomplete @@ -123,13 +116,13 @@ def pull(self, *changes: Any): for i, (color, char) in enumerate(vga): tag = VT100.get_tagname(color) pos = VT100.get_index(i) - self.vt.insert(pos, char, (tag)) # type: ignore + self.vt.insert(pos, char, (tag)) self.vt["state"] = "disabled" def push(self, memory: bytearray): """Push a new memory text layout.""" - mmio = bytes(memory[VT100.BASE_ADDR: VT100.BASE_ADDR + VT100.SIZE]) + mmio = bytes(memory[VT100.BASE_ADDR : VT100.BASE_ADDR + VT100.SIZE]) if mmio == self.screen: return - self.content.set(mmio) # type: ignore + self.content.set(mmio) diff --git a/dashmips/preprocessor.py b/dashmips/preprocessor.py index b3738c0..3589861 100644 --- a/dashmips/preprocessor.py +++ b/dashmips/preprocessor.py @@ -4,7 +4,8 @@ from typing import Any, Dict, Iterable, List, Optional, TextIO, Tuple from .hardware import Memory, Registers -from .mips import RE as mipsRE, Directives +from .mips import RE as mipsRE +from .mips import Directives from .models import Label, MipsProgram, SourceLine from .utils import MipsException, bytesify, hexdump @@ -15,7 +16,7 @@ def preprocess(file: TextIO, args: Optional[List[str]] = None) -> MipsProgram: Breaks the code into directive and text sections. """ filename = os.path.abspath(file.name) - memory = Memory() # type: ignore + memory = Memory() argv = [filename] if args: @@ -40,23 +41,15 @@ def preprocess(file: TextIO, args: Optional[List[str]] = None) -> MipsProgram: if not ("main" in labels and labels["main"].location == mipsRE.TEXT_SEC): raise MipsException(f"Cannot locate main label in {filename}") - registers = Registers() # type: ignore + registers = Registers() load_args(registers, memory, argv) registers["pc"] = labels["main"].value registers["$sp"] = registers["$fp"] = registers["$gp"] = memory.ram["stack"]["stops"] - memory.extend_stack(bytes([ord('@')] * Memory.PAGE_SIZE)) + memory.extend_stack(bytes([ord("@")] * Memory.PAGE_SIZE)) - return MipsProgram( - name=filename, - filenames=[filename, *includes], - labels=labels, - memory=memory, - source=processed_code, - registers=registers, - eqvs=eqvs, - ) + return MipsProgram(name=filename, filenames=[filename, *includes], labels=labels, memory=memory, source=processed_code, registers=registers, eqvs=eqvs,) def split_to_sections(code: List[SourceLine]) -> Tuple[List[str], List[SourceLine]]: @@ -124,11 +117,11 @@ def data_labels(labels: Dict[str, Label], data_sec: List[str], memory: Memory): if pair[1] in labels: raw_data = match[3].replace(pair[1], str(labels[pair[1]].value)) else: - label_position = [i for i in range(0, len(second_pass)) if second_pass[i][0][0:len(pair[1])] == pair[1]] + label_position = [i for i in range(0, len(second_pass)) if second_pass[i][0][0 : len(pair[1])] == pair[1]] if len(label_position) == 0: - raise MipsException(f'Symbol {pair[1]} not found in symbol table') + raise MipsException(f"Symbol {pair[1]} not found in symbol table") elif len(label_position) > 1000: - raise MipsException(f'Cannot make labels refer to each other') + raise MipsException(f"Cannot make labels refer to each other") else: second_pass.insert(label_position[-1] + 1, pair) continue @@ -148,7 +141,7 @@ def data_labels(labels: Dict[str, Label], data_sec: List[str], memory: Memory): else: raise MipsException(f"Unknown directive {pair[0]}") - address = Directives["space"]('4', memory) # Pad the end of data section + address = Directives["space"]("4", memory) # Pad the end of data section def code_labels(labels: Dict[str, Label], text_sec: List[SourceLine]) -> List[SourceLine]: @@ -170,7 +163,7 @@ def code_labels(labels: Dict[str, Label], text_sec: List[SourceLine]) -> List[So # If the line is longer than what was matched, lets assume # the rest is an instruction (comments and whitespace should # already have been stripped) we cut out the label - srcline.line = srcline.line[len(match[0]):].strip() + srcline.line = srcline.line[len(match[0]) :].strip() text.append(srcline) else: # To offset the previously removed label lines @@ -291,9 +284,7 @@ def resolve_macros(lines: List[SourceLine]) -> List[SourceLine]: if match: found_macro = match[1] macros[match[1]] = { - "args": [a.strip() for a in match[2].split(", ")] - if match[2] - else None, + "args": [a.strip() for a in match[2].split(", ")] if match[2] else None, "lines": [], } lines_to_remove.append(idx) @@ -330,11 +321,7 @@ def macro_with_args(idx: int, lines: List[SourceLine], macro: str, macroinfo: Di modified_line = s.line for a, v in argsmap.items(): modified_line = modified_line.replace(a, v) - expanded_macro.append( - SourceLine( - line=modified_line, - lineno=s.lineno, - filename=s.filename)) + expanded_macro.append(SourceLine(line=modified_line, lineno=s.lineno, filename=s.filename)) lines[idx] = expanded_macro # type: ignore diff --git a/dashmips/syscalls/__init__.py b/dashmips/syscalls/__init__.py index 4e7979b..ee4bbce 100644 --- a/dashmips/syscalls/__init__.py +++ b/dashmips/syscalls/__init__.py @@ -13,6 +13,7 @@ def mips_syscall(number: int): """Make a Syscall object from decorated function.""" + def decorator(function: Callable[[MipsProgram], None]) -> Syscall: """Syscall Decorator wrapper.""" syscall = Syscall(function, number) diff --git a/dashmips/syscalls/process_syscalls.py b/dashmips/syscalls/process_syscalls.py index 48b5a75..dc03c17 100644 --- a/dashmips/syscalls/process_syscalls.py +++ b/dashmips/syscalls/process_syscalls.py @@ -10,5 +10,5 @@ def sbrk(program: MipsProgram): """Allocate heap space.""" num_bytes = program.registers["$a0"] num_pages = (num_bytes // Memory.PAGE_SIZE) + (0 if num_bytes % Memory.PAGE_SIZE == 0 else 1) - address = program.memory.extend_heap(bytes([ord('@')] * (num_pages * Memory.PAGE_SIZE))) + address = program.memory.extend_heap(bytes([ord("@")] * (num_pages * Memory.PAGE_SIZE))) program.registers["$v0"] = address diff --git a/dashmips/syscalls/read_syscalls.py b/dashmips/syscalls/read_syscalls.py index 691cf26..07a3408 100644 --- a/dashmips/syscalls/read_syscalls.py +++ b/dashmips/syscalls/read_syscalls.py @@ -1,8 +1,9 @@ """Syscalls for reading from stdin.""" import os -from . import mips_syscall + from ..models import MipsProgram from ..utils import bytesify, intify +from . import mips_syscall @mips_syscall(5) @@ -19,10 +20,10 @@ def read_int(program: MipsProgram): def read_str(program: MipsProgram): """Read Str from stdin. $a0 = address of input buffer $a1 = maximum number of characters to read.""" user_input = input("") - truncated_user_input = user_input[:program.registers["$a1"]] + truncated_user_input = user_input[: program.registers["$a1"]] address = program.registers["$a0"] for offset, byte in enumerate(bytesify(truncated_user_input)): - program.memory.write08(address + offset, intify(byte)) + program.memory.write08(address + offset, bytes(byte)) @mips_syscall(12) diff --git a/dashmips/utils.py b/dashmips/utils.py index a8795e0..9d00131 100644 --- a/dashmips/utils.py +++ b/dashmips/utils.py @@ -16,8 +16,8 @@ def __init__(self, message: str): def parse_int(int_str: str) -> int: """Take a python number literal and returns an int.""" - if '\"' in int_str: - raise MipsException('"%s" is not a valid integer constant or label.' % int_str[int_str.index('\"'): int_str.replace('\"', 'x', 1).find('\"') + 1]) + if '"' in int_str: + raise MipsException('"%s" is not a valid integer constant or label.' % int_str[int_str.index('"') : int_str.replace('"', "x", 1).find('"') + 1]) # WARNING: SECURITY FLAW arg: Union[int, str] = eval(int_str) @@ -58,17 +58,14 @@ def hexdump(data: bytes, *, offset=0, reverse_idx=False) -> str: if reverse_idx: calc_idx = ((len(rows) - 1) * ROW_MUL) - (idx * ROW_MUL) else: - calc_idx = (idx * ROW_MUL) + calc_idx = idx * ROW_MUL calc_idx += offset hex_string += f"{calc_idx:08x} " hex_string += " ".join([f"{byte:02x}" for byte in byte_row[:ROW_MUL]]) - hex_string += " " if len(byte_row) > ROW_HAF else ' ' + hex_string += " " if len(byte_row) > ROW_HAF else " " hex_string += " ".join([f"{byte:02x}" for byte in byte_row[ROW_MUL:]]) - spaces = '' if idx != len(rows) - 1 else ' ' * (ROW_MUL - len(byte_row)) * 3 - ascii_str = "".join([ - chr(byte) if ord(' ') <= byte <= ord('~') else '.' - for byte in byte_row - ]) + spaces = "" if idx != len(rows) - 1 else " " * (ROW_MUL - len(byte_row)) * 3 + ascii_str = "".join([chr(byte) if ord(" ") <= byte <= ord("~") else "." for byte in byte_row]) hex_string += f"{spaces} |{ascii_str}|" hex_string += "\n" diff --git a/mypy.ini b/mypy.ini index c814793..bbbc153 100644 --- a/mypy.ini +++ b/mypy.ini @@ -1,11 +1,11 @@ [mypy] -python_version = 3.7 +python_version = 3.9 ignore_missing_imports = True follow_imports = silent show_column_numbers = True warn_unused_configs = True disallow_subclassing_any = True -disallow_untyped_calls = True +disallow_untyped_calls = False disallow_untyped_defs = False disallow_incomplete_defs = False check_untyped_defs = True diff --git a/poetry.lock b/poetry.lock index 69e1159..bb91253 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,3 +1,11 @@ +[[package]] +category = "dev" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +name = "appdirs" +optional = false +python-versions = "*" +version = "1.4.4" + [[package]] category = "dev" description = "Atomic file writes." @@ -23,15 +31,31 @@ tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.i [[package]] category = "dev" -description = "A tool that automatically formats Python code to conform to the PEP 8 style guide" -name = "autopep8" +description = "The uncompromising code formatter." +name = "black" optional = false -python-versions = "*" -version = "1.5.3" +python-versions = ">=3.6" +version = "19.10b0" [package.dependencies] -pycodestyle = ">=2.6.0" -toml = "*" +appdirs = "*" +attrs = ">=18.1.0" +click = ">=6.5" +pathspec = ">=0.6,<1" +regex = "*" +toml = ">=0.9.4" +typed-ast = ">=1.4.0" + +[package.extras] +d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] + +[[package]] +category = "dev" +description = "Composable command line interface toolkit" +name = "click" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "7.1.2" [[package]] category = "dev" @@ -42,24 +66,32 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" version = "0.4.3" +[[package]] +category = "dev" +description = "A platform independent file lock." +name = "filelock" +optional = false +python-versions = "*" +version = "3.0.12" + [[package]] category = "dev" description = "More routines for operating on iterables, beyond itertools" name = "more-itertools" optional = false python-versions = ">=3.5" -version = "8.3.0" +version = "8.4.0" [[package]] category = "dev" description = "Optional static typing for Python" name = "mypy" optional = false -python-versions = "*" -version = "0.720" +python-versions = ">=3.5" +version = "0.782" [package.dependencies] -mypy-extensions = ">=0.4.0,<0.5.0" +mypy-extensions = ">=0.4.3,<0.5.0" typed-ast = ">=1.4.0,<1.5.0" typing-extensions = ">=3.7.4" @@ -86,6 +118,14 @@ version = "20.4" pyparsing = ">=2.0.2" six = "*" +[[package]] +category = "dev" +description = "Utility library for gitignore style pattern matching of file paths." +name = "pathspec" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.8.0" + [[package]] category = "dev" description = "plugin and hook calling mechanisms for python" @@ -103,7 +143,7 @@ description = "library with cross-python path, ini-parsing, io, code, log facili name = "py" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.8.1" +version = "1.9.0" [[package]] category = "dev" @@ -118,11 +158,10 @@ category = "dev" description = "Python docstring style checker" name = "pydocstyle" optional = false -python-versions = "*" -version = "3.0.0" +python-versions = ">=3.5" +version = "5.0.2" [package.dependencies] -six = "*" snowballstemmer = "*" [[package]] @@ -155,34 +194,52 @@ wcwidth = "*" checkqa-mypy = ["mypy (v0.761)"] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] +[[package]] +category = "dev" +description = "A pytest plugin to enable format checking with black" +name = "pytest-black" +optional = false +python-versions = ">=2.7" +version = "0.3.10" + +[package.dependencies] +pytest = ">=3.5.0" +toml = "*" + +[package.dependencies.black] +python = ">=3.6" +version = "*" + [[package]] category = "dev" description = "Mypy static type checker plugin for Pytest" name = "pytest-mypy" optional = false python-versions = "~=3.4" -version = "0.3.3" +version = "0.6.2" [package.dependencies] +filelock = ">=3.0" + [package.dependencies.mypy] -python = ">=3.5" -version = ">=0.570" +python = ">=3.8" +version = ">=0.700" [package.dependencies.pytest] python = ">=3.5" -version = ">=2.8" +version = ">=3.5" [[package]] category = "dev" description = "pytest plugin to run pycodestyle" name = "pytest-pycodestyle" optional = false -python-versions = "~=3.5" -version = "1.4.1" +python-versions = "~=3.6" +version = "2.1.3" [package.dependencies] pycodestyle = "*" -pytest = "*" +pytest = ">=5.4,<6.0" [package.extras] tests = ["pytest-isort"] @@ -192,28 +249,23 @@ category = "dev" description = "pytest plugin to run pydocstyle" name = "pytest-pydocstyle" optional = false -python-versions = "~=3.5" -version = "1.5.2" +python-versions = "~=3.6" +version = "2.1.3" [package.dependencies] pydocstyle = "*" -pytest = "*" +pytest = ">=5.4,<6.0" [package.extras] -tests = ["pytest-codestyle (>=1.4,<2.0)", "pytest-isort"] +tests = ["pytest-pycodestyle (>=2.1,<3.0)", "pytest-isort"] [[package]] category = "dev" -description = "Test Anything Protocol (TAP) reporting plugin for pytest" -name = "pytest-tap" +description = "Alternative regular expression module, to replace re." +name = "regex" optional = false python-versions = "*" -version = "2.5" - -[package.dependencies] -pytest = "*" -six = "*" -"tap.py" = ">=2.5,<3.0" +version = "2020.6.8" [[package]] category = "dev" @@ -231,17 +283,6 @@ optional = false python-versions = "*" version = "2.0.0" -[[package]] -category = "dev" -description = "Test Anything Protocol (TAP) tools" -name = "tap.py" -optional = false -python-versions = "*" -version = "2.6.2" - -[package.extras] -yaml = ["more-itertools", "pyyaml"] - [[package]] category = "dev" description = "Python Library for Tom's Obvious, Minimal Language" @@ -259,7 +300,7 @@ python-versions = "*" version = "1.4.1" [[package]] -category = "dev" +category = "main" description = "Backported and Experimental Type Hints for Python 3.5+" name = "typing-extensions" optional = false @@ -272,13 +313,28 @@ description = "Measures the displayed width of unicode strings in a terminal" name = "wcwidth" optional = false python-versions = "*" -version = "0.2.4" +version = "0.2.5" + +[[package]] +category = "dev" +description = "A built-package format for Python" +name = "wheel" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.34.2" + +[package.extras] +test = ["pytest (>=3.0.0)", "pytest-cov"] [metadata] -content-hash = "192b99ef3be98188dd14dd1cfd89a4f2815909d41daa3d5a20fc710486150450" +content-hash = "bba2d28b86400b6c05037f830f3884bdc65520da5a43df21b6667ccc71a867d2" python-versions = "^3.8" [metadata.files] +appdirs = [ + {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, + {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, +] atomicwrites = [ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, @@ -287,29 +343,41 @@ attrs = [ {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, ] -autopep8 = [ - {file = "autopep8-1.5.3.tar.gz", hash = "sha256:60fd8c4341bab59963dafd5d2a566e94f547e660b9b396f772afe67d8481dbf0"}, +black = [ + {file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"}, + {file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"}, +] +click = [ + {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, + {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, ] colorama = [ {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, {file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"}, ] +filelock = [ + {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, + {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, +] more-itertools = [ - {file = "more-itertools-8.3.0.tar.gz", hash = "sha256:558bb897a2232f5e4f8e2399089e35aecb746e1f9191b6584a151647e89267be"}, - {file = "more_itertools-8.3.0-py3-none-any.whl", hash = "sha256:7818f596b1e87be009031c7653d01acc46ed422e6656b394b0f765ce66ed4982"}, + {file = "more-itertools-8.4.0.tar.gz", hash = "sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5"}, + {file = "more_itertools-8.4.0-py3-none-any.whl", hash = "sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2"}, ] mypy = [ - {file = "mypy-0.720-cp35-cp35m-macosx_10_6_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:437020a39417e85e22ea8edcb709612903a9924209e10b3ec6d8c9f05b79f498"}, - {file = "mypy-0.720-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:10af62f87b6921eac50271e667cc234162a194e742d8e02fc4ddc121e129a5b0"}, - {file = "mypy-0.720-cp35-cp35m-win_amd64.whl", hash = "sha256:0107bff4f46a289f0e4081d59b77cef1c48ea43da5a0dbf0005d54748b26df2a"}, - {file = "mypy-0.720-cp36-cp36m-macosx_10_6_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:352c24ba054a89bb9a35dd064ee95ab9b12903b56c72a8d3863d882e2632dc76"}, - {file = "mypy-0.720-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:7a17613f7ea374ab64f39f03257f22b5755335b73251d0d253687a69029701ba"}, - {file = "mypy-0.720-cp36-cp36m-win_amd64.whl", hash = "sha256:07957f5471b3bb768c61f08690c96d8a09be0912185a27a68700f3ede99184e4"}, - {file = "mypy-0.720-cp37-cp37m-macosx_10_6_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:6724fcd5777aa6cebfa7e644c526888c9d639bd22edd26b2a8038c674a7c34bd"}, - {file = "mypy-0.720-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:15e43d3b1546813669bd1a6ec7e6a11d2888db938e0607f7b5eef6b976671339"}, - {file = "mypy-0.720-cp37-cp37m-win_amd64.whl", hash = "sha256:cdc1151ced496ca1496272da7fc356580e95f2682be1d32377c22ddebdf73c91"}, - {file = "mypy-0.720-py3-none-any.whl", hash = "sha256:11fd60d2f69f0cefbe53ce551acf5b1cec1a89e7ce2d47b4e95a84eefb2899ae"}, - {file = "mypy-0.720.tar.gz", hash = "sha256:49925f9da7cee47eebf3420d7c0e00ec662ec6abb2780eb0a16260a7ba25f9c4"}, + {file = "mypy-0.782-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:2c6cde8aa3426c1682d35190b59b71f661237d74b053822ea3d748e2c9578a7c"}, + {file = "mypy-0.782-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9c7a9a7ceb2871ba4bac1cf7217a7dd9ccd44c27c2950edbc6dc08530f32ad4e"}, + {file = "mypy-0.782-cp35-cp35m-win_amd64.whl", hash = "sha256:c05b9e4fb1d8a41d41dec8786c94f3b95d3c5f528298d769eb8e73d293abc48d"}, + {file = "mypy-0.782-cp36-cp36m-macosx_10_6_x86_64.whl", hash = "sha256:6731603dfe0ce4352c555c6284c6db0dc935b685e9ce2e4cf220abe1e14386fd"}, + {file = "mypy-0.782-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:f05644db6779387ccdb468cc47a44b4356fc2ffa9287135d05b70a98dc83b89a"}, + {file = "mypy-0.782-cp36-cp36m-win_amd64.whl", hash = "sha256:b7fbfabdbcc78c4f6fc4712544b9b0d6bf171069c6e0e3cb82440dd10ced3406"}, + {file = "mypy-0.782-cp37-cp37m-macosx_10_6_x86_64.whl", hash = "sha256:3fdda71c067d3ddfb21da4b80e2686b71e9e5c72cca65fa216d207a358827f86"}, + {file = "mypy-0.782-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d7df6eddb6054d21ca4d3c6249cae5578cb4602951fd2b6ee2f5510ffb098707"}, + {file = "mypy-0.782-cp37-cp37m-win_amd64.whl", hash = "sha256:a4a2cbcfc4cbf45cd126f531dedda8485671545b43107ded25ce952aac6fb308"}, + {file = "mypy-0.782-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6bb93479caa6619d21d6e7160c552c1193f6952f0668cdda2f851156e85186fc"}, + {file = "mypy-0.782-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:81c7908b94239c4010e16642c9102bfc958ab14e36048fa77d0be3289dda76ea"}, + {file = "mypy-0.782-cp38-cp38-win_amd64.whl", hash = "sha256:5dd13ff1f2a97f94540fd37a49e5d255950ebcdf446fb597463a40d0df3fac8b"}, + {file = "mypy-0.782-py3-none-any.whl", hash = "sha256:e0b61738ab504e656d1fe4ff0c0601387a5489ca122d55390ade31f9ca0e252d"}, + {file = "mypy-0.782.tar.gz", hash = "sha256:eff7d4a85e9eea55afa34888dfeaccde99e7520b51f867ac28a48492c0b1130c"}, ] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, @@ -319,22 +387,25 @@ packaging = [ {file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"}, {file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"}, ] +pathspec = [ + {file = "pathspec-0.8.0-py2.py3-none-any.whl", hash = "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0"}, + {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"}, +] pluggy = [ {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, ] py = [ - {file = "py-1.8.1-py2.py3-none-any.whl", hash = "sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0"}, - {file = "py-1.8.1.tar.gz", hash = "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa"}, + {file = "py-1.9.0-py2.py3-none-any.whl", hash = "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2"}, + {file = "py-1.9.0.tar.gz", hash = "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342"}, ] pycodestyle = [ {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, ] pydocstyle = [ - {file = "pydocstyle-3.0.0-py2-none-any.whl", hash = "sha256:2258f9b0df68b97bf3a6c29003edc5238ff8879f1efb6f1999988d934e432bd8"}, - {file = "pydocstyle-3.0.0-py3-none-any.whl", hash = "sha256:ed79d4ec5e92655eccc21eb0c6cf512e69512b4a97d215ace46d17e4990f2039"}, - {file = "pydocstyle-3.0.0.tar.gz", hash = "sha256:5741c85e408f9e0ddf873611085e819b809fca90b619f5fd7f34bd4959da3dd4"}, + {file = "pydocstyle-5.0.2-py3-none-any.whl", hash = "sha256:da7831660b7355307b32778c4a0dbfb137d89254ef31a2b2978f50fc0b4d7586"}, + {file = "pydocstyle-5.0.2.tar.gz", hash = "sha256:f4f5d210610c2d153fae39093d44224c17429e2ad7da12a8b419aba5c2f614b5"}, ] pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, @@ -344,19 +415,41 @@ pytest = [ {file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"}, {file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"}, ] +pytest-black = [ + {file = "pytest-black-0.3.10.tar.gz", hash = "sha256:5f3c0cfee9b41e6281a9e52e2987f4c90ec4a13a92bbf2f249d26d7b58747437"}, +] pytest-mypy = [ - {file = "pytest-mypy-0.3.3.tar.gz", hash = "sha256:917438af835beb87f14c9f6261137f8e992b3bf87ebf73f836ac7ede03424a0f"}, - {file = "pytest_mypy-0.3.3-py3-none-any.whl", hash = "sha256:419d1d4877d41a6a80f0eb31faa7c50bb9445557f7ff1b02a1a26d10d7dc7691"}, + {file = "pytest-mypy-0.6.2.tar.gz", hash = "sha256:2560a9b27d59bb17810d12ec3402dfc7c8e100e40539a70d2814bcbb27240f27"}, + {file = "pytest_mypy-0.6.2-py3-none-any.whl", hash = "sha256:76e705cfd3800bf2b534738e792245ac5bb8d780698d0f8cd6c79032cc5e9923"}, ] pytest-pycodestyle = [ - {file = "pytest-pycodestyle-1.4.1.tar.gz", hash = "sha256:b3d257f6b40308cff63a1f71e60604b38efbc952ab716f6e3f25363f02d97855"}, + {file = "pytest-pycodestyle-2.1.3.tar.gz", hash = "sha256:a5c21f4829e61f945be0d367347d8f9e397d2e4b7165f950d03b2a18a489feed"}, ] pytest-pydocstyle = [ - {file = "pytest-pydocstyle-1.5.2.tar.gz", hash = "sha256:18756c6a98ca747780924d67565280d7e53c6489356a07ed1549585e0883b272"}, + {file = "pytest-pydocstyle-2.1.3.tar.gz", hash = "sha256:fa3332df8387f6d7756649cd4c5c873ccde14bbd2832b84d3ff19a4bd6c908c7"}, ] -pytest-tap = [ - {file = "pytest-tap-2.5.tar.gz", hash = "sha256:9bd16c07ba2991aa14f1085ba74b94a0340e98f23442b12c46c1046b8c8db0b8"}, - {file = "pytest_tap-2.5-py2.py3-none-any.whl", hash = "sha256:0c0db713f0a8c113ca59b92f492d1f1eb451ca9b40b63b0ae7f2dab210a6c86c"}, +regex = [ + {file = "regex-2020.6.8-cp27-cp27m-win32.whl", hash = "sha256:fbff901c54c22425a5b809b914a3bfaf4b9570eee0e5ce8186ac71eb2025191c"}, + {file = "regex-2020.6.8-cp27-cp27m-win_amd64.whl", hash = "sha256:112e34adf95e45158c597feea65d06a8124898bdeac975c9087fe71b572bd938"}, + {file = "regex-2020.6.8-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:92d8a043a4241a710c1cf7593f5577fbb832cf6c3a00ff3fc1ff2052aff5dd89"}, + {file = "regex-2020.6.8-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bae83f2a56ab30d5353b47f9b2a33e4aac4de9401fb582b55c42b132a8ac3868"}, + {file = "regex-2020.6.8-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:b2ba0f78b3ef375114856cbdaa30559914d081c416b431f2437f83ce4f8b7f2f"}, + {file = "regex-2020.6.8-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:95fa7726d073c87141f7bbfb04c284901f8328e2d430eeb71b8ffdd5742a5ded"}, + {file = "regex-2020.6.8-cp36-cp36m-win32.whl", hash = "sha256:e3cdc9423808f7e1bb9c2e0bdb1c9dc37b0607b30d646ff6faf0d4e41ee8fee3"}, + {file = "regex-2020.6.8-cp36-cp36m-win_amd64.whl", hash = "sha256:c78e66a922de1c95a208e4ec02e2e5cf0bb83a36ceececc10a72841e53fbf2bd"}, + {file = "regex-2020.6.8-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:08997a37b221a3e27d68ffb601e45abfb0093d39ee770e4257bd2f5115e8cb0a"}, + {file = "regex-2020.6.8-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2f6f211633ee8d3f7706953e9d3edc7ce63a1d6aad0be5dcee1ece127eea13ae"}, + {file = "regex-2020.6.8-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:55b4c25cbb3b29f8d5e63aeed27b49fa0f8476b0d4e1b3171d85db891938cc3a"}, + {file = "regex-2020.6.8-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:89cda1a5d3e33ec9e231ece7307afc101b5217523d55ef4dc7fb2abd6de71ba3"}, + {file = "regex-2020.6.8-cp37-cp37m-win32.whl", hash = "sha256:690f858d9a94d903cf5cada62ce069b5d93b313d7d05456dbcd99420856562d9"}, + {file = "regex-2020.6.8-cp37-cp37m-win_amd64.whl", hash = "sha256:1700419d8a18c26ff396b3b06ace315b5f2a6e780dad387e4c48717a12a22c29"}, + {file = "regex-2020.6.8-cp38-cp38-manylinux1_i686.whl", hash = "sha256:654cb773b2792e50151f0e22be0f2b6e1c3a04c5328ff1d9d59c0398d37ef610"}, + {file = "regex-2020.6.8-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:52e1b4bef02f4040b2fd547357a170fc1146e60ab310cdbdd098db86e929b387"}, + {file = "regex-2020.6.8-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:cf59bbf282b627130f5ba68b7fa3abdb96372b24b66bdf72a4920e8153fc7910"}, + {file = "regex-2020.6.8-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:5aaa5928b039ae440d775acea11d01e42ff26e1561c0ffcd3d805750973c6baf"}, + {file = "regex-2020.6.8-cp38-cp38-win32.whl", hash = "sha256:97712e0d0af05febd8ab63d2ef0ab2d0cd9deddf4476f7aa153f76feef4b2754"}, + {file = "regex-2020.6.8-cp38-cp38-win_amd64.whl", hash = "sha256:6ad8663c17db4c5ef438141f99e291c4d4edfeaacc0ce28b5bba2b0bf273d9b5"}, + {file = "regex-2020.6.8.tar.gz", hash = "sha256:e9b64e609d37438f7d6e68c2546d2cb8062f3adb27e6336bc129b51be20773ac"}, ] six = [ {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, @@ -366,10 +459,6 @@ snowballstemmer = [ {file = "snowballstemmer-2.0.0-py2.py3-none-any.whl", hash = "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0"}, {file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"}, ] -"tap.py" = [ - {file = "tap.py-2.6.2-py2.py3-none-any.whl", hash = "sha256:7b9ad4d17fa3615bbe2262ab16204d20662b4bff61ec5ecdba60398801e8c096"}, - {file = "tap.py-2.6.2.tar.gz", hash = "sha256:5f219d92dbad5e378f8f7549cdfe655b0d5fd2a778f9c83bee51b61c6ca40efb"}, -] toml = [ {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, {file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"}, @@ -403,6 +492,10 @@ typing-extensions = [ {file = "typing_extensions-3.7.4.2.tar.gz", hash = "sha256:79ee589a3caca649a9bfd2a8de4709837400dfa00b6cc81962a1e6a1815969ae"}, ] wcwidth = [ - {file = "wcwidth-0.2.4-py2.py3-none-any.whl", hash = "sha256:79375666b9954d4a1a10739315816324c3e73110af9d0e102d906fdb0aec009f"}, - {file = "wcwidth-0.2.4.tar.gz", hash = "sha256:8c6b5b6ee1360b842645f336d9e5d68c55817c26d3050f46b235ef2bc650e48f"}, + {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, + {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, +] +wheel = [ + {file = "wheel-0.34.2-py2.py3-none-any.whl", hash = "sha256:df277cb51e61359aba502208d680f90c0493adec6f0e848af94948778aed386e"}, + {file = "wheel-0.34.2.tar.gz", hash = "sha256:8788e9155fe14f54164c1b9eb0a319d98ef02c160725587ad60f14ddc57b6f96"}, ] diff --git a/poetry.toml b/poetry.toml new file mode 100644 index 0000000..99efa6f --- /dev/null +++ b/poetry.toml @@ -0,0 +1,3 @@ +[virtualenvs] +create = true +in-project = true diff --git a/pyproject.toml b/pyproject.toml index 1d5b686..b8d9459 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,12 +1,12 @@ [tool.poetry] name = "dashmips" -version = "0.1.4" +version = "0.1.5" description = "Mips Interpreter" authors = ["Neal Beeken "] license = "MIT" readme = "README.md" repository = "https://github.com/nbbeeken/dashmips" -classifiers=[ +classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Education", "Topic :: Software Development :: Assemblers", @@ -20,19 +20,28 @@ dashmips = "dashmips.__main__:main" [tool.poetry.dependencies] "python" = "^3.8" "dataclasses" = { version = "^0.6", python = "3.6" } +"typing-extensions" = "3.7.4.2" [tool.poetry.dev-dependencies] -"mypy" = "^0.720" +"pip" = "^20.1.1" +"wheel" = "^0.34.2" +"mypy" = "^0.782" "mypy-extensions" = "^0.4.1" "pycodestyle" = "^2.5.0" -"autopep8" = "^1.4.4" -"pydocstyle" = "^3.0.0" +"pydocstyle" = "^5.0.2" +"black" = "^19.10b0" "pytest" = "^5.0.1" -"pytest-pycodestyle" = "^1.4.0" -"pytest-pydocstyle" = "^1.5.0" -"pytest-tap" = "^2.3" -"pytest-mypy" = "^0.3.2" +"pytest-pycodestyle" = "^2.0.1" +"pytest-pydocstyle" = "^2.0.1" +"pytest-mypy" = "^0.6.2" +"pytest-black" = "^0.3.9" + +[tool.black] +"line-length" = 160 + +[metadata] +license_files = "LICENSE" [build-system] -requires = ["poetry>=1.0.0"] +requires = ["poetry>=0.12"] build-backend = "poetry.masonry.api" diff --git a/scripts.py b/scripts.py deleted file mode 100755 index 023ae19..0000000 --- a/scripts.py +++ /dev/null @@ -1,69 +0,0 @@ -#! /usr/bin/env python -"""Run Publish Commands.""" -import argparse -import shutil -import sys -import os -from shlex import split -from subprocess import run -from typing import * - - -def find_all(name: str) -> Iterator[str]: - """Find all matching files or dirs.""" - for root, dirs, files in os.walk('.'): - if '.\\.git' in root: - continue - if name in files or name in dirs: - yield os.path.join(root, name) - - -def main_clean() -> int: - """Clean project working directory.""" - def rm(file: str): shutil.rmtree(file, ignore_errors=True) - def rm_all(file: str): [rm(f) for f in find_all(file)] - - rm("dist") - rm("build") - rm("testout") - rm_all("dashmips.egg-info") - rm_all(".pytest_cache") - rm_all(".mypy_cache") - rm_all("__pycache__") - return 0 - - -def main_publish() -> int: - """Publish module to pypi.""" - main_clean() - run(split("poetry build"), shell=True) - run(split("twine upload dist/*"), shell=True) - return 0 - - -def main_hooks() -> int: - """Install git hooks.""" - return 0 - - -if __name__ == "__main__": - parser = argparse.ArgumentParser('Helpful scripts') - - subparser = parser.add_subparsers(title="commands", dest="command") - cleancommand = subparser.add_parser("clean", help="clean up working dir") - publishcommand = subparser.add_parser("publish", help="publish to pypi") - hookscommand = subparser.add_parser("hooks", help="install git hooks") - - cleancommand.set_defaults(func=main_clean) - publishcommand.set_defaults(func=main_publish) - - prog_args = parser.parse_args() - try: - ret_val = prog_args.func() - exit(ret_val) - except AttributeError: - # This is for python 3.6 compatibility - # you cannot enforce subparser to require in less than 3.6 - print('Must provide a command') - parser.print_help() - sys.exit(1) diff --git a/setup.cfg b/setup.cfg index ad10299..83effd4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,8 +1,13 @@ +[tool:pytest] +addopts = --pycodestyle --pydocstyle --mypy --black +codestyle_max_line_length = 160 +codestyle_ignore = E251,E701,E203,E731 +docstyle_ignore = D202,D213 + [pycodestyle] max-line-length = 160 -ignore = E251,E701 +ignore = E251,E701,E203,E731 statistics = True -[tool:pytest] -codestyle_max_line_length = 160 -codestyle_ignore = E251 E701 +[pydocstyle] +add-ignore = D202,D213 diff --git a/setup.py b/setup.py deleted file mode 100644 index a302178..0000000 --- a/setup.py +++ /dev/null @@ -1,9 +0,0 @@ -import setuptools - -# NOT MEANT FOR GENERAL CONSUMPTION -# THIS IS ONLY FOR LOCAL DEVELOPMENT - -setuptools.setup( - name='dashmips', - version="INVALID" -) diff --git a/tests/test_debugger/debugserver_tests.py b/tests/test_debugger/debugserver_tests.py index ec16159..7ee196c 100644 --- a/tests/test_debugger/debugserver_tests.py +++ b/tests/test_debugger/debugserver_tests.py @@ -15,18 +15,17 @@ def compile_file(filename: str) -> Dict[str, Any]: """Run compiler on filename.""" - proc = run(split(f"python -m dashmips c {filename} -j"), - capture_output=True, encoding='utf8') + proc = run(split(f"python -m dashmips c {filename} -j"), capture_output=True, encoding="utf8") return cast(Dict[str, Any], json.loads(proc.stdout.strip())) def communicate(msg: Dict[str, Any]) -> Any: """Send json encoded message.""" s = socket() - s.connect(('localhost', 9999)) - wfile = s.makefile('w', encoding='utf8', buffering=1) - rfile = s.makefile('r', encoding='utf8', buffering=1) - wfile.write(json.dumps(msg) + '\r\n') + s.connect(("localhost", 9999)) + wfile = s.makefile("w", encoding="utf8", buffering=1) + rfile = s.makefile("r", encoding="utf8", buffering=1) + wfile.write(json.dumps(msg) + "\r\n") wfile.flush() received = rfile.readline().strip() resp = json.loads(received) @@ -37,8 +36,8 @@ def communicate(msg: Dict[str, Any]) -> Any: def recv() -> Dict[str, Any]: """Recv json encoded message.""" s = socket() - s.connect(('localhost', 9999)) - rfile = s.makefile('r', encoding='utf8', buffering=1) + s.connect(("localhost", 9999)) + rfile = s.makefile("r", encoding="utf8", buffering=1) received = rfile.readline().strip() resp = json.loads(received) s.close() @@ -50,17 +49,17 @@ class TestMipsDebugServer(unittest.TestCase): def test_start(self): """Test start command.""" - program = compile_file('test.mips') + program = compile_file("test.mips") - resp = communicate({'command': 'start', 'program': program}) + resp = communicate({"command": "start", "program": program}) - program = resp['program'] + program = resp["program"] - self.assertIn('command', resp, pformat(resp)) - self.assertIn('program', resp, pformat(resp)) - self.assertEqual(resp['command'], 'start', pformat(resp)) - self.assertEqual(program['labels']['main']['value'], program['registers']['pc'], pformat(resp)) - self.assertLessEqual(program['registers']['pc'], len(program['source']), pformat(resp)) + self.assertIn("command", resp, pformat(resp)) + self.assertIn("program", resp, pformat(resp)) + self.assertEqual(resp["command"], "start", pformat(resp)) + self.assertEqual(program["labels"]["main"]["value"], program["registers"]["pc"], pformat(resp)) + self.assertLessEqual(program["registers"]["pc"], len(program["source"]), pformat(resp)) self.stop_debugging() def stop_debugging(self): @@ -68,7 +67,7 @@ def stop_debugging(self): SERVER.kill() -if __name__ == '__main__': +if __name__ == "__main__": try: unittest.main() finally: