adjust code style to follow PEP8

parser
Trolli Schmittlauch 2017-06-30 00:51:50 +02:00
parent 3edd920b0d
commit 40eaca47ae
3 changed files with 68 additions and 32 deletions

View File

@ -1,4 +1,4 @@
from typing import List, Tuple, Sequence, Optional, Union, Any
from typing import List, Tuple
import arpeggio
from itertools import chain
@ -7,7 +7,8 @@ __all__ = ["jobshop1_parser", "jobshop2_parser"]
grammar = """
# starting point for jobshop1 input file
job_shop1 = skip_preface
# eat away lines of preface, until first problem_instance is encountered; then the list of instances start
# eat away lines of preface, until first problem_instance is
# encountered; then the list of instances start
skip_preface = (!problem_instance r"[^\n]+" skip_preface) / (eol skip_preface) / instance_list
instance_list = problem_instance (sep_line trim_ws eol problem_instance eol?)* eof_sep
problem_instance = trim_ws "instance" ' ' instance_name trim_ws eol trim_ws eol sep_line description eol problem_data
@ -31,18 +32,23 @@ grammar = """
machine = nonneg_num
duration = nonneg_num
# task data for 1 job
job_data = ' '* machine ' '+ duration (' '+ machine ' '+ duration)* trim_ws eol
job_data = ' '* machine ' '+ duration (' '+ machine ' '+ duration)* trim_ws eol
"""
class ParseError(Exception):
"""To be thrown when parsing goes wrong"""
def __init__(self, message: str) -> None:
self.message = message
class JobShopProblem(list):
def __init__(self, jobs: int, machines: int, problem_data: List[List[Tuple[int, int]]], name: str = 'unnamed', description: str = '') -> None:
def __init__(
self, jobs: int, machines: int,
problem_data: List[List[Tuple[int, int]]],
name: str = 'unnamed', description: str = '') -> None:
# check plausibility of input
if len(problem_data) != jobs:
raise ParseError("Given number of jobs for problem \"{}\" differs from actual job data.".format(name))
@ -58,47 +64,52 @@ class JobShopProblem(list):
def __str__(self) -> str:
return "JobShopProblem " + str(self.name)
class JobShopVisitor(arpeggio.PTNodeVisitor):
"""contains visitor functions needed for both jobshop1 (list of instances)
and jobshop2 (single instance without name & description) input data"""
def visit_nonneg_num(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
def visit_nonneg_num(
self, node: arpeggio.ParseTreeNode,
children: arpeggio.SemanticActionResults) -> int:
if self.debug:
print("Converting non-negative integer", node.value)
return int(node.value)
def visit_machine(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
def visit_machine(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
return int(node.value)
def visit_duration(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
def visit_duration(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
return int(node.value)
def visit_num_machines(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
def visit_num_machines(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
return int(node.value)
def visit_num_jobs(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
def visit_num_jobs(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> int:
return int(node.value)
def visit_job_data(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> List[Tuple[int, int]]:
def visit_job_data(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> List[Tuple[int, int]]:
if self.debug:
print("Job data:\nnode:", type(node), "children:", children)
job_numbers = list(filter(lambda x: type(x) is int, children))
# job data needs to consist out of pairs of numbers
if len(job_numbers) % 2 ==1:
if len(job_numbers) % 2 == 1:
raise ParseError("Odd number of numbers in job data")
# returns list of (duration, machine) tuples
return list(zip(job_numbers[1::2], job_numbers[0::2])) # [::2] returns only every second element of the list
# [::2] returns only every second element of the list
return list(zip(job_numbers[1::2], job_numbers[0::2]))
def visit_problem_data(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> JobShopProblem:
def visit_problem_data(
self, node: arpeggio.ParseTreeNode,
children: arpeggio.SemanticActionResults) -> JobShopProblem:
if self.debug:
print("problem_data\nchildren:", children)
# filter out newlines or other strings
cleaned_data = list(filter(lambda x: type(x) is not str, children))
problem_data: List[List[Tuple[int, int]]] = [ cleaned_data[i] for i in range(2, len(cleaned_data))]
problem_data: List[List[Tuple[int, int]]] = [
cleaned_data[i] for i in range(2, len(cleaned_data))]
problem = JobShopProblem(children[0], children[1], problem_data)
if self.debug:
print("\nreturning a", type(problem), "\n")
print("problem_data:", problem_data)
return problem

View File

@ -1,13 +1,16 @@
from arpeggio.cleanpeg import ParserPEG
from typing import List, Tuple, Sequence, Optional, Union
from typing import List, Union
import arpeggio
from . import grammar, ParseError, JobShopProblem, JobShopVisitor
from . import grammar, JobShopProblem, JobShopVisitor
class JobShop1Visitor(JobShopVisitor):
"""instanciated for semantic analysis of parse_tree"""
def visit_problem_instance(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> JobShopProblem:
def visit_problem_instance(
self, node: arpeggio.ParseTreeNode,
children: arpeggio.SemanticActionResults) -> JobShopProblem:
if self.debug:
print("problem_instance\nchildren:", children)
problem: JobShopProblem = children[3]
@ -15,30 +18,40 @@ class JobShop1Visitor(JobShopVisitor):
problem.description = children[2]
return problem
def visit_instance_list(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> List[JobShopProblem]:
def visit_instance_list(
self, node: arpeggio.ParseTreeNode,
children: arpeggio.SemanticActionResults) -> List[JobShopProblem]:
if self.debug:
print("instance_list\nchildren:", children)
return list(filter(lambda x: isinstance(x, JobShopProblem), children))
def visit_skip_preface(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> List[JobShopProblem]:
def visit_skip_preface(
self, node: arpeggio.ParseTreeNode,
children: arpeggio.SemanticActionResults) -> List[JobShopProblem]:
if self.debug:
print("skip_preface\nchildren:", children)
return list(filter(lambda x: type(x) is list, children))[0]
# ignore eol nodes
def visit_eol(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> None:
def visit_eol(
self, node: arpeggio.ParseTreeNode,
children: arpeggio.SemanticActionResults) -> None:
return None
# ignore trim_ws nodes
def visit_trim_ws(self, node:arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> None:
def visit_trim_ws(
self, node: arpeggio.ParseTreeNode,
children: arpeggio.SemanticActionResults) -> None:
return None
def parse_string(inputdata: str) -> JobShopProblem:
"""parse string with jobshop1-formatted data (multiple problem instances)
and return list of JobShopProblem s"""
parse_tree = parser.parse(inputdata)
return arpeggio.visit_parse_tree(parse_tree, JobShop1Visitor())
def parse_file(filename: Union[str, bytes]) -> List[JobShopProblem]:
"""Open file with jobshop1-formatted data (multiple problem instances),
parse it and return list of JobShopProblem s"""
@ -46,11 +59,12 @@ def parse_file(filename: Union[str, bytes]) -> List[JobShopProblem]:
with open(filename) as datafile:
inputdata: str = datafile.read()
return parse_string(inputdata)
def main():
print(parse_file("../inputdata/jobshop1.txt"))
parser = ParserPEG(grammar, "job_shop1", skipws=False)
if __name__ == "__main__":

View File

@ -1,12 +1,15 @@
import arpeggio
from arpeggio.cleanpeg import ParserPEG
from typing import List, Tuple, Sequence, Optional, Union
from typing import Union
from . import grammar, JobShopVisitor, JobShopProblem, ParseError
class JobShop2Visitor(JobShopVisitor):
def visit_job_shop2(self, node: arpeggio.ParseTreeNode, children: arpeggio.SemanticActionResults) -> JobShopProblem:
def visit_job_shop2(
self, node: arpeggio.ParseTreeNode,
children: arpeggio.SemanticActionResults) -> JobShopProblem:
if self.debug:
print("job_shop2:\nchildren:", children)
problem = children[0]
@ -14,18 +17,24 @@ class JobShop2Visitor(JobShopVisitor):
print("returning a", type(problem))
return problem
def parse_string(inputdata: str) -> JobShopProblem:
"""parse string of jobshop2-formatted data (single problem instance, no name & description)
"""parse string of jobshop2-formatted data
(single problem instance, no name & description)
and return JobShopProblem
Raises a ParseError exception on errors"""
try:
parse_tree = parser.parse(inputdata)
except arpeggio.NoMatch as e:
raise ParseError("Error while parsing problem input data at line {}, col {}:\n Rules {} did not match.".format(e.line, e.col, e.rules))
raise ParseError(
"Error while parsing problem input data at line {}, col {}:\n"
"Rules {} did not match.".format(e.line, e.col, e.rules))
return arpeggio.visit_parse_tree(parse_tree, JobShop2Visitor())
def parse_file(filename: Union[str, bytes]) -> JobShopProblem:
"""Open file with jobshop2-formatted data (single problem instance, no name & description),
"""Open file with jobshop2-formatted data
(single problem instance, no name & description),
parse it and return JobShopProblem
Raises a ParseError exception on errors"""
@ -33,9 +42,11 @@ def parse_file(filename: Union[str, bytes]) -> JobShopProblem:
inputdata: str = datafile.read()
return parse_string(inputdata)
def main():
print(parse_file('../inputdata/jobshop2/ta13'))
parser = ParserPEG(grammar, "job_shop2", skipws=False)
if __name__ == "__main__":