def prune_select_col_types(self, db, schema, agg_col, tsq, pos): if tsq.types: tsq_type = tsq.types[pos] col_type = schema.get_col(agg_col.col_id).type if self.no_fk_select and schema.get_col(agg_col.col_id).fk_ref: if self.debug: print('Prune: foreign keys are not to be projected.') return Tribool(False) if agg_col.has_agg == TRUE: if tsq_type != 'number': if self.debug: print('Prune: all aggs must produce numeric output.') return Tribool(False) elif agg_col.has_agg == UNKNOWN: if col_type == 'number' and tsq_type == 'text': if self.debug: print('Prune: cannot output text from numeric column.') return Tribool(False) else: if col_type != tsq_type: if self.debug: print('Prune: column type does not match TSQ type.') return Tribool(False)
def test_or(): for value in (True, False, None): for other in (True, False, None): result = Tribool._or[value, other] assert (Tribool(value) | Tribool(other))._value == result assert (value | Tribool(other))._value == result assert (Tribool(value) | other)._value == result
def test_xor(): for value in (True, False, None): for other in (True, False, None): result = Tribool._xor[value, other] assert (Tribool(value) ^ Tribool(other)).value == result assert (value ^ Tribool(other)).value == result assert (Tribool(value) ^ other).value == result
def test_and(): for value in (True, False, None): for other in (True, False, None): result = Tribool._and[value, other] assert (Tribool(value) & Tribool(other)).value == result assert (value & Tribool(other)).value == result assert (Tribool(value) & other).value == result
def to_tribool_proto(proto_tribool): if proto_tribool == UNKNOWN: return Tribool(None) elif proto_tribool == TRUE: return Tribool(True) else: return Tribool(False)
def experiment_thread(self, db, schema, tsq, literals, ready, tsq_level, gold): address = ('', self.port) listener = Listener(address, authkey=self.authkey) ready.set() print(f'DuoquestServer listening on port {self.port}...') conn = listener.accept() print('DuoquestServer connection accepted from:', listener.last_accepted) self.verifier.init_stats() while True: msg = conn.recv_bytes() try: if msg.decode('utf-8') == 'close': conn.close() break except Exception: pass protolist = ProtoQueryList() protolist.ParseFromString(msg) response = ProtoResult() for query in protolist.queries: if query.done_query: if tsq_level == 'nlq_only': result = Tribool(True) else: result = self.verifier.verify(db, schema, query, tsq, literals) else: if tsq_level == 'nlq_only' or tsq_level == 'chain': result = Tribool(None) else: result = self.verifier.verify(db, schema, query, tsq, literals) if result.value is None: response.results.append(UNKNOWN) elif result.value: response.results.append(TRUE) if matches_gold(gold, query): response.answer_found = True else: response.results.append(FALSE) conn.send_bytes(response.SerializeToString()) pprint(self.verifier.stats) listener.close()
def prune_by_num_cols(self, query, tsq): if query.done_select and tsq.num_cols != len(query.select): if self.debug: print('Prune: number of columns does not match TSQ.') return Tribool(False) if tsq.num_cols < max(len(query.select), query.min_select_cols): if self.debug: print('Prune: number of columns exceeds TSQ.') return Tribool(False) else: return None
def prune_by_subquery(self, schema, pred, literals): if pred.op == BETWEEN: if self.debug: print('Prune: cannot have BETWEEN with subquery.') return Tribool(False) if max(pred.subquery.min_select_cols, len(pred.subquery.select)) > 1: if self.debug: print('Prune: subquery cannot have more than 1 SELECT column.') return Tribool(False) if pred.subquery.select: subq_col_id = pred.subquery.select[0].col_id if subq_col_id != pred.col_id and \ schema.get_col(subq_col_id).fk_ref != pred.col_id: if self.debug: print('Prune: failed condition I8.') return Tribool(False) if pred.subquery.select[0].has_agg == TRUE and \ pred.subquery.select[0].agg == COUNT: if self.debug: print('Prune: Subquery cannot project COUNT().') return Tribool(False) if max(pred.subquery.min_where_preds, len(pred.subquery.where.predicates)) > 1: if self.debug: print('Prune: failed condition I9.') return Tribool(False) if max(pred.subquery.min_group_by_cols, len( pred.subquery.group_by)) > 1: if self.debug: print( 'Prune: subquery cannot have more than 1 GROUP BY column.') return Tribool(False) if max(pred.subquery.min_having_preds, len(pred.subquery.having.predicates)) > 1: if self.debug: print( 'Prune: subquery cannot have more than 1 HAVING predicate.' ) return Tribool(False) if max(pred.subquery.min_order_by_cols, len( pred.subquery.order_by)) > 1: if self.debug: print( 'Prune: subquery cannot have more than 1 ORDER BY column.') return Tribool(False) if pred.subquery.has_order_by == TRUE and \ pred.subquery.has_limit == FALSE: if self.debug: print('Prune: subquery cannot have ORDER BY without LIMIT.') return Tribool(False) subq = self.prune_by_semantics(schema, pred.subquery, literals) if subq is not None: return subq return None
def prune_by_num_literals(self, query, literals): for literal in literals.num_lits: if not self.find_literal_usage(query, literal): if self.debug: print(f'Prune: No literal {literal}') return Tribool(False) return None
def test_cmp(): for value in (True, False, None): for other in (True, False, None): tri_value = Tribool(value) tri_other = Tribool(other) _eq = Tribool._eq[value, other] assert (tri_value == tri_other).value == _eq _lt = Tribool._lt[value, other] assert (tri_value < tri_other).value == _lt tri_value != tri_other tri_value <= tri_other tri_value > tri_other tri_value >= tri_other
def prune_by_text_literals(self, query, literals): for literal in literals.text_lits: if not self.find_literal_usage(query, literal): if self.debug: print( f'Prune: No literal {literal.col_id}:{literal.value}') return Tribool(False) return None
def handle(points): results = [] for point in points: xy = point.split(',') x = xy[0] y = xy[1] x_squared = float(x) * float(x) y_squared = float(y) * float(y) xy_squared = (x_squared + y_squared) if xy_squared <= 1: result = Tribool(True) else: result = Tribool(False) results.append(str(result)) return results
def verifyData(data: str): msg = "" valid = Tribool(True) # Extract Version version = "" if versionFinder := re.search(r'version\s+=\s+"(.+)"', data, re.IGNORECASE): version = versionFinder.group(1)
def prune_by_order(self, db, schema, query, tsq): conn = db.get_conn(db_name=schema.db_id) conn.text_factory = bytes cur = conn.cursor() # TODO: to speed up instead of generate_sql_str, we could do a variation # of verify_sql_str where we put (col = val1 or col = val2) as part of # the sql_str for each value order_sql = generate_sql_str(query, schema) if self.debug: print(f'ORDER SQL: {order_sql}') cur.execute(order_sql) values_copy = list(tsq.values) prune = False while values_copy: db_row = cur.fetchone() if db_row is None: break index = self.first_matching_row(db_row, values_copy) if index is None: continue elif index == 0: values_copy = values_copy[1:] else: prune = True break if prune: if self.debug: print('Prune: ordering is incorrect.') return Tribool(False) elif values_copy: if self.debug: for val in values_copy: print(f'Prune: could not find match for: {val}.') return Tribool(False) else: return None
def bool_input(string): preConversionInput = input(string) if (preConversionInput == "") or (preConversionInput == "?"): preConversionInput = None try: convertedAnswer = Tribool(bool(int(preConversionInput))) except TypeError: convertedAnswer = Tribool(preConversionInput) except ValueError: try: convertedAnswer = Tribool(preConversionInput) except: print( "Warning: Response was unclear. Answer has been marked as 'Unknown'." ) convertedAnswer = Tribool() finally: convertedAnswerVal = convertedAnswer.value if config.unitTesting: print("\t" * 10 + str(convertedAnswer)) return convertedAnswerVal
def parseSiteData(data: str): msg = "" valid, emsg = verifyData(data) if (valid == Tribool(None)).value: msg += emsg if (valid == Tribool(False)).value: return emsg blocks = re.findall( r"(\"[0-9-\s:]+\",[\s0-9]+,[\s0-9]+,[\s0-9]+,[(\s0-9)|None]+,[\s0-9]+,[\s0-9]+,[\s0-9]+)", data, re.MULTILINE) dBlocks = re.findall(r'("[0-9-\s:]+",[\s0-9.-]+,[\s0-9.-]+,[\s0-9.-]+\))', data, re.MULTILINE) blockData = [] dBlockData = [] for block in blocks: blockData.append(parseBlockData(block)) for dBlock in dBlocks: dBlockData.append(parseDarknessBlocks(dBlock)) relevantData = [ d for d in mergeListMaps(blockData, dBlockData) if today < d["date"] < tomorrow ] goodTimes = [d["date"] for d in filterTonight(relevantData)] #print(goodTimes) ranges = checkRanges(goodTimes) #print(ranges) for r in ranges: if r: (start, end) = r msg += " ({} to {})".format(start.strftime("%H:%M"), end.strftime("%H:%M")) if msg != "": msg = "Observing is a GO! Found the following acceptable time range(s) (24Hr time):\n" \ + msg.replace(") (", "), (") else: msg = "Observing is a NO GO! No 3 hour time window could be composed!" return msg
def test_names(): Yes, No, Maybe = map(Tribool, (True, False, None)) assert Yes is Tribool('True') assert No is Tribool('False') assert Maybe is Tribool('None') assert Maybe is Tribool('Indeterminate') assert Maybe is Tribool('Maybe') assert Maybe is Tribool('Unknown')
def prune_select_col_values(self, db, schema, agg_col, tsq, pos): if agg_col.has_agg == UNKNOWN: return None col_id = agg_col.col_id col_name = schema.get_col(col_id).sem_name for row in tsq.values: if row[pos] is None: # empty cell continue elif isinstance(row[pos], list): # range constraint if agg_col.has_agg == FALSE or \ (agg_col.has_agg == TRUE and \ agg_col.agg in (MIN, MAX, AVG)): if not db.intersects_range(schema, col_id, row[pos]): if self.debug: print(f'Prune: <{row[pos]}> doesn\'t ' + \ f'intersect range of <{col_name}>.') return Tribool(False) else: # exact constraint if (tsq.types and tsq.types[pos] == 'text') or \ agg_col.has_agg == FALSE or \ (agg_col.has_agg == TRUE and agg_col.agg in (MIN, MAX)): if not db.has_exact(schema, col_id, row[pos]): if self.debug: print(f'Prune: <{row[pos]}> not ' + f'in <{col_name}>.') return Tribool(False) elif agg_col.has_agg == TRUE and agg_col.agg == AVG: if not db.intersects_range(schema, col_id, [row[pos], row[pos]]): if self.debug: print(f'Prune: <{row[pos]}> doesn\'t ' + \ f'intersect range of <{col_name}>.') return Tribool(False) return None
def send(self, msg, address, sender, receiver): # Send the message via our own SMTP server, but don't include the # envelope header. try: s = smtplib.SMTP(address) s.sendmail(sender, receiver, msg.as_string()) s.quit() return Tribool(None) except smtplib.SMTPRecipientsRefused: return False pass except smtplib.SMTPServerDisconnected: return False pass except socket.error: return False pass
def prune_by_row(self, db, schema, query, tsq): conn = db.get_conn(db_name=schema.db_id) for row in tsq.values: cur = conn.cursor() verify_q = verify_sql_str(query, schema, row) if self.debug: print(f'VERIFY: {verify_q}') cur.execute(verify_q) if not cur.fetchone(): if self.debug: print('Prune: Verify failed.') return Tribool(False) cur.close() conn.close() return None
def prune_by_clauses(self, query, tsq, set_op, literals): if set_op != NO_SET_OP: if query.has_order_by == TRUE: if self.debug: print( 'Prune: child of set operation cannot have ORDER BY.') return Tribool(False) if query.has_limit == TRUE: if self.debug: print('Prune: child of set operation cannot have LIMIT.') return Tribool(False) else: if not self.disable_literals and query.has_where == FALSE \ and literals.text_lits: if self.debug: print('Prune: text literal requires WHERE clause.') return Tribool(False) if query.has_order_by == TRUE and not tsq.order: if self.debug: print('Prune: query has ORDER BY when TSQ has none.') return Tribool(False) if query.has_order_by == FALSE and tsq.order: if self.debug: print('Prune: query has no ORDER BY when TSQ does.') return Tribool(False) if query.has_limit == TRUE and not tsq.limit: if self.debug: print('Prune: query has LIMIT when TSQ has none.') return Tribool(False) if query.has_limit == FALSE and tsq.limit: if self.debug: print('Prune: query has no LIMIT when TSQ does.') return Tribool(False) return None
def test_repr(): assert repr(Tribool(True)) == 'Tribool(True)' assert repr(Tribool(False)) == 'Tribool(False)' assert repr(Tribool(None)) == 'Tribool(None)'
def test_bool(): bool(Tribool())
def test_not(): for value in (True, False, None): assert (~Tribool(value)).value == Tribool._not[value]
def test_init_raises(): """Test intializer raises on bad input.""" Tribool(0)
def test_check(): for value in (True, False, None): Tribool(value)._check()
def test_str(): assert str(Tribool(True)) == 'True' assert str(Tribool(False)) == 'False' assert str(Tribool(None)) == 'Indeterminate'
def test_init(): """Test initializer values for Tribool.""" for value in (True, False, None): assert Tribool(value).value == value assert Tribool(Tribool(value)).value == value
def test_contains(): values = (Yes, No, Maybe) = list(map(Tribool, (True, False, None))) assert any(value is Tribool(True) for value in values) assert any(value is Tribool(False) for value in values) assert any(value is Tribool(None) for value in values)
def test_int(): int(Tribool())