class Reader: """Read records from tables""" MATCH_MEMORY = re.compile(r'^<memory at .*>') def __init__(self, table, inline=False): self._table = table self._inline = inline self._message = "" self._request = None self._sql = SQLShowRequest() self._db = Database() self.create_request(table) def create_request(self, table): """show from SQL SELECT statement for table""" self._request = self._sql.table(table) def conditions(self, condition): """Add conditions to SQL request""" self._request += f"WHERE {condition}" @property def message(self): """Property message reader""" formatter = TabularOutputFormatter(format_name="simple") self._message = f"=== Liste des enregistrements de la " \ f"table '{self._table}' ===\n\n" headers, *records = self._db.request(self._request, ask=True, with_headers=True) if self._inline: for n, record in enumerate(records): line = f"== resultat => enregistrement {n + 1}: =>\n" for i, field in enumerate(record): if Reader.MATCH_MEMORY.match(str(field)): field = "-byte data-" line += "\t%-12s: %s \n" % (headers[i],str(field)) self._message += line + "\n" else: for x in formatter.format_output(records, headers): self._message += x + "\n" return self._message
class Field: """Act from field type (defined inside the XML file)""" IS_YES_OR_NO = re.compile(r'oui|non|o|n', re.IGNORECASE) IS_YES = re.compile(r'o|oui', re.IGNORECASE) IS_DATE = re.compile(r'^(0[1-9]|[1-2]\d|3[0-1])/(0[1-9]|1[0-2])/' r'(20[1-3][0-9])$') IS_DATE_TIME = re.compile(r'^([0-1]\d|2[0-3]):([0-5][0-9]) (0[1-9]|' r'[1-2]\d|3[0-1])/(0[1-9]|1[0-2])/' r'(20[1-3][0-9])$') def __init__(self): self._convert = Convert() self._db = Database() def int_(self, field): """React for int field type""" value = input(field["question"]) return int(value) def numeric_(self, field): """Numeric type field reaction""" value = input(field["question"]) return float(value) def varchar_(self, field: dict) -> str: """React for varchar field type""" value = input(field["question"]) return value def file_(self, field): """varchar type field with test = file""" value = None is_file = False while not is_file: value = input(field["question"]) is_file = Path(value).is_file() if not is_file: print("Ce fichier n'existe pas... entrez un " "fichier qui existe svp") return value def image_(self, field): """varchar type field with test = image""" value = None is_image = False while not is_image: value = input(field["question"]) try: img = Image.open(value) img.close() except IOError: print("ce fichier n'est pas une image que " "je peux pas gérer (ou n'est pas une image)") is_image = False else: is_image = True return value def enum_(self, field: dict) -> str: """React for enum field type""" correct_answer = None value = None request = SQLShowRequest().type() enums = self._db.request(request, (field["type_name"], ), ask=True) valid = re.compile(r"%s" % enums[0][2]) while not correct_answer: question = "{}({}) : ".format(field["question"], enums[0][2]) value = input(question) correct_answer = valid.match(value) return value def bytea_(self, field: dict, values) -> bytes: """React for bytea field type""" value = input(field["question"]) if field["question"] else None if field["control"]: if field["control"] == "password": return self._convert.password(value) elif field["control"] == "thumb": return self._convert.thumb(values[-1])[1] elif field["control"] == "salt": return self._convert.salt def bool_(self, field: dict) -> bool: """React for bool field type""" value = None correct = None while not correct: value = input(field["question"]) correct = self.IS_YES_OR_NO.match(value) return bool(self.IS_YES.match(value)) def date_(self, field: dict) -> date: """React for date field type""" correct = False answer = None while not correct: question = field["question"] + " [DD/MM/YYY] " answer = input(question) correct = self.IS_DATE.match(answer) return datetime.strptime(answer, "%d/%m/%Y").date() def date_time_(self, field) -> datetime: """React for date_time field's type""" correct = False answer = None while not correct: question = field["question"] + "[HH:MM DD/MM/YYY] " answer = input(question) correct = self.IS_DATE_TIME.match(answer) return datetime.strptime(answer, "%H:%M %d/%m/%Y")
class Creator: """Create records""" YES = re.compile(r'o|y|oui|yes', re.IGNORECASE) ADD_A = re.compile(r'^(.*ajouter un[e]? )(.*)$', re.IGNORECASE) CHOOSE = re.compile(r'.*\[(.*)\].*', re.IGNORECASE) def __init__(self, target=None, observer=None): self._sql = SQLInsertRequest() self._db = Database() self._convert = Convert() if target: self._entry = TableEntry(target) if observer: self._observer = observer self._field = Field() @property def entry(self): """Property entry""" return self._entry def _create_simple(self, arg): """ask for fields entry and record, then return id""" id = [] entry = arg if isinstance(arg, TableEntry) else arg["entry"] while not id: values = self._get_fields_values_for(entry.fields) request = entry.request if self._observer: self._observer.add_debug_message( f"request: {request}\n ==> values: {values}") id = self._db.request(request, tuple(values), ask=True) return int(id[0][0]) def _create_maybe(self, relation, **kwargs): """ask from a list of records to choose one (exist=yes) or (exist=maybe) possibly create a new one or STOP link recording""" id = 0 while id == 0: if relation["exist"]: choices = self._show_existing_records(relation["table"], relation["show"], relation["exist"], **kwargs) answer = input("Faites un choix: ") if relation["exist"] == "maybe" and answer == choices[-1]: Record(relation["table"]) elif 1 <= int(answer) < len(choices): id = choices[int(answer)] elif int(answer) >= len(choices): print("re-essayez: vous avez fait un choix qui n'existe " "pas.") else: # Choice is 0 ==> STOP id = None return id def _record_through(self, through, values): """Record relational table""" request = self._sql.table(through, "script") if self._observer: self._observer.add_debug_message( f"request: {request}\n ==> values: {values}") success = self._db.request(request, tuple(values)) return success def _get_fields_values_for(self, fields, exception=[]) -> list: """Return field parser factories result list values""" values = list() for field in fields: if field["name"] not in exception: value = None if field["type"] == "varchar": if field["test"] == "file": value = self._field.file_(field) elif field["test"] == "image": value = self._field.image_(field) else: value = self._field.varchar_(field) if field["type"] == "int": value = self._field.int_(field) if field["type"] == "enum": value = self._field.enum_(field) if field["type"] == "bytea": value = self._field.bytea_(field, values) if field["type"] == "bool": value = self._field.bool_(field) if field["type"] == "date": value = self._field.date_(field) if field["type"] == "date_time": value = self._field.date_time_(field) if field["type"] == "numeric": value = self._field.numeric_(field) values.append(value) return values @staticmethod def _get_an_other(string) -> str: """Add 'autre ' inside string at precise point""" match = Creator.ADD_A.match(string) question = match.group(1) + "autre " + match.group(2) return question def _show_existing_records(self, table, fields, exist, **kwargs): """Print enumerated list of fields 'field' existing 'table' records and return a list of id and 'n': [id,.....,'n']""" choices = ["STOP"] print(" 0) -- RIEN --") sql = SQLShowRequest() sub_request = sql.table(table) request = re.sub(r'\*', f"id, {fields}", sub_request) \ if "request" not in kwargs or kwargs["request"] is None\ else kwargs["request"] records = self._db.request(request, ask=True)\ if "values" not in kwargs \ else self._db.request(request, kwargs["values"], ask=True) if self._observer: self._observer.add_debug_message( f"request: {request}\n ==> answer: {records}") for n, record in enumerate(records): choices.append(int(record[0])) string = "%3s) " % str(n + 1) for i_field in range(1, len(record)): string += f" %s - " % record[i_field] print(string) if exist == "maybe": choices.append("n") print(" n) -- Nouveau --") return choices def ask_for_choice(self, question): """Ask a question and return the answer depend of the validation of choices""" correct = False answer = "" choices = self.CHOOSE.match(question).group(1).split(", ") while not correct: answer = input(question) correct = bool((answer in choices) or "fin") return answer
class Inspector(): def __init__(self): self._sql = SQLShowRequest() self._db = Database() def tables(self) -> str: """Show tables of database 'oc-pizza'""" request = self._sql.list() string = "========================================================\n" string += "============= Tables list of 'oc-pizza': =============\n" string += "========================================================\n" string += "request: %s \n" % request records = self._db.request(request, ask=True) for record in records: string += record[0] + "\n" return string def table(self, name): """Show name and type of fields for table 'name'""" string = "========================================================\n" string += "========= Table %-24s : ==========\n" % name string += "========================================================\n" formatter = TabularOutputFormatter(format_name="simple") request = self._sql.columns() records = self._db.request(request, (name, ), ask=True) headers = ["Name", "Default", "Nullable", "Type"] for x in formatter.format_output(records, headers): string += x + "\n" return string def types(self): """Show types list and values""" string = "========================================================\n" string += "====================== Types =======================\n" string += "========================================================\n" formatter = TabularOutputFormatter(format_name="simple") request = self._sql.types() records = self._db.request(request, ask=True) data = list() for record in records: data.append(record[1:3]) headers = ["Name", "Enums values"] for x in formatter.format_output(data, headers): string += x + "\n" return string def type(self, target, return_values=False): """Show Type for target or return values only (if return_values=True)""" string = "========================================================\n" string += "================ Type %-12s =================\n" % target string += "========================================================\n" formatter = TabularOutputFormatter(format_name="simple") request = self._sql.type(target) records = self._db.request(request, ask=True) data = list() for record in records: data.append(record[1:3])