def test_extendleft(self): d = deque("a") self.assertRaises(TypeError, d.extendleft, 1) d.extendleft("bcd") self.assertEqual(list(d), list(reversed("abcd"))) d.extendleft(d) self.assertEqual(list(d), list("abcddcba")) d = deque() d.extendleft(range(1000)) self.assertEqual(list(d), list(reversed(range(1000)))) self.assertRaises(SyntaxError, d.extendleft, fail())
def test_extendleft(self): d = deque('a') self.assertRaises(TypeError, d.extendleft, 1) d.extendleft('bcd') self.assertEqual(list(d), list(reversed('abcd'))) d.extendleft(d) self.assertEqual(list(d), list('abcddcba')) d = deque() d.extendleft(range(1000)) self.assertEqual(list(d), list(reversed(range(1000)))) self.assertRaises(SyntaxError, d.extendleft, fail())
def test_rotate(self): s = tuple("abcde") n = len(s) d = deque(s) d.rotate(1) # verify rot(1) self.assertEqual("".join(d), "eabcd") d = deque(s) d.rotate(-1) # verify rot(-1) self.assertEqual("".join(d), "bcdea") d.rotate() # check default to 1 self.assertEqual(tuple(d), s) for i in xrange(n * 3): d = deque(s) e = deque(d) d.rotate(i) # check vs. rot(1) n times for j in xrange(i): e.rotate(1) self.assertEqual(tuple(d), tuple(e)) d.rotate(-i) # check that it works in reverse self.assertEqual(tuple(d), s) e.rotate(n - i) # check that it wraps forward self.assertEqual(tuple(e), s) for i in xrange(n * 3): d = deque(s) e = deque(d) d.rotate(-i) for j in xrange(i): e.rotate(-1) # check vs. rot(-1) n times self.assertEqual(tuple(d), tuple(e)) d.rotate(i) # check that it works in reverse self.assertEqual(tuple(d), s) e.rotate(i - n) # check that it wraps backaround self.assertEqual(tuple(e), s) d = deque(s) e = deque(s) e.rotate(BIG + 17) # verify on long series of rotates dr = d.rotate for i in xrange(BIG + 17): dr() self.assertEqual(tuple(d), tuple(e)) self.assertRaises(TypeError, d.rotate, "x") # Wrong arg type self.assertRaises(TypeError, d.rotate, 1, 10) # Too many args d = deque() d.rotate() # rotate an empty deque self.assertEqual(d, deque())
def test_rotate(self): s = tuple('abcde') n = len(s) d = deque(s) d.rotate(1) # verify rot(1) self.assertEqual(''.join(d), 'eabcd') d = deque(s) d.rotate(-1) # verify rot(-1) self.assertEqual(''.join(d), 'bcdea') d.rotate() # check default to 1 self.assertEqual(tuple(d), s) for i in xrange(n * 3): d = deque(s) e = deque(d) d.rotate(i) # check vs. rot(1) n times for j in xrange(i): e.rotate(1) self.assertEqual(tuple(d), tuple(e)) d.rotate(-i) # check that it works in reverse self.assertEqual(tuple(d), s) e.rotate(n - i) # check that it wraps forward self.assertEqual(tuple(e), s) for i in xrange(n * 3): d = deque(s) e = deque(d) d.rotate(-i) for j in xrange(i): e.rotate(-1) # check vs. rot(-1) n times self.assertEqual(tuple(d), tuple(e)) d.rotate(i) # check that it works in reverse self.assertEqual(tuple(d), s) e.rotate(i - n) # check that it wraps backaround self.assertEqual(tuple(e), s) d = deque(s) e = deque(s) e.rotate(BIG + 17) # verify on long series of rotates dr = d.rotate for i in xrange(BIG + 17): dr() self.assertEqual(tuple(d), tuple(e)) self.assertRaises(TypeError, d.rotate, 'x') # Wrong arg type self.assertRaises(TypeError, d.rotate, 1, 10) # Too many args d = deque() d.rotate() # rotate an empty deque self.assertEqual(d, deque())
def test_maxlen_zero(self): it = iter(range(100)) deque(it, maxlen=0) self.assertEqual(list(it), []) it = iter(range(100)) d = deque(maxlen=0) d.extend(it) self.assertEqual(list(it), []) it = iter(range(100)) d = deque(maxlen=0) d.extendleft(it) self.assertEqual(list(it), [])
def test_pickle(self): d = deque(xrange(200)) for i in range(pickle.HIGHEST_PROTOCOL + 1): s = pickle.dumps(d, i) e = pickle.loads(s) self.assertNotEqual(id(d), id(e)) self.assertEqual(list(d), list(e))
def test_extend(self): d = deque('a') self.assertRaises(TypeError, d.extend, 1) d.extend('bcd') self.assertEqual(list(d), list('abcd')) d.extend(d) self.assertEqual(list(d), list('abcdabcd'))
def test_extend(self): d = deque("a") self.assertRaises(TypeError, d.extend, 1) d.extend("bcd") self.assertEqual(list(d), list("abcd")) d.extend(d) self.assertEqual(list(d), list("abcdabcd"))
def test_container_iterator(self): # Bug #3680: tp_traverse was not implemented for deque iterator objects class C(object): pass for i in range(2): obj = C() ref = weakref.ref(obj) if i == 0: container = deque([obj, 1]) else: container = reversed(deque([obj, 1])) obj.x = iter(container) del obj, container gc.collect() self.assertTrue(ref() is None, "Cycle was not collected")
def __init__(self): self.game = Game() self.found_game = False self.variation_stack = collections.deque([self.game]) self.starting_comment = "" self.in_variation = False
def test_copy(self): mut = [10] d = deque([mut]) e = copy.copy(d) self.assertEqual(list(d), list(e)) mut[0] = 11 self.assertNotEqual(id(d), id(e)) self.assertEqual(list(d), list(e))
def __init__(self): self._expectations = collections.deque() self._is_dead = threading.Event() self._std_streams_closed = False self._send_queue = queue.Queue() self._send_thread = threading.Thread(target=self._send_thread_target) self._send_thread.daemon = True
def test_comparisons(self): d = deque("xabc") d.popleft() for e in [d, deque("abc"), deque("ab"), deque(), list(d)]: self.assertEqual(d == e, type(d) == type(e) and list(d) == list(e)) self.assertEqual(d != e, not (type(d) == type(e) and list(d) == list(e))) args = map(deque, ("", "a", "b", "ab", "ba", "abc", "xba", "xabc", "cba")) for x in args: for y in args: self.assertEqual(x == y, list(x) == list(y), (x, y)) self.assertEqual(x != y, list(x) != list(y), (x, y)) self.assertEqual(x < y, list(x) < list(y), (x, y)) self.assertEqual(x <= y, list(x) <= list(y), (x, y)) self.assertEqual(x > y, list(x) > list(y), (x, y)) self.assertEqual(x >= y, list(x) >= list(y), (x, y)) self.assertEqual(cmp(x, y), cmp(list(x), list(y)), (x, y))
def test_clear(self): d = deque(xrange(100)) self.assertEqual(len(d), 100) d.clear() self.assertEqual(len(d), 0) self.assertEqual(list(d), []) d.clear() # clear an emtpy deque self.assertEqual(list(d), [])
def test_gc_doesnt_blowup(self): import gc # This used to assert-fail in deque_traverse() under a debug # build, or run wild with a NULL pointer in a release build. d = deque() for i in xrange(100): d.append(1) gc.collect()
def test_big_queue_popright(self): d = deque() append, pop = d.appendleft, d.pop for i in xrange(BIG): append(i) for i in xrange(BIG): x = pop() if x != i: self.assertEqual(x, i)
def test_long_steadystate_queue_popright(self): for size in (0, 1, 2, 100, 1000): d = deque(reversed(xrange(size))) append, pop = d.appendleft, d.pop for i in xrange(size, BIG): append(i) x = pop() if x != i - size: self.assertEqual(x, i - size) self.assertEqual(list(reversed(list(d))), range(BIG - size, BIG))
def test_comparisons(self): d = deque('xabc') d.popleft() for e in [d, deque('abc'), deque('ab'), deque(), list(d)]: self.assertEqual(d == e, type(d) == type(e) and list(d) == list(e)) self.assertEqual(d != e, not (type(d) == type(e) and list(d) == list(e))) args = map(deque, ('', 'a', 'b', 'ab', 'ba', 'abc', 'xba', 'xabc', 'cba')) for x in args: for y in args: self.assertEqual(x == y, list(x) == list(y), (x, y)) self.assertEqual(x != y, list(x) != list(y), (x, y)) self.assertEqual(x < y, list(x) < list(y), (x, y)) self.assertEqual(x <= y, list(x) <= list(y), (x, y)) self.assertEqual(x > y, list(x) > list(y), (x, y)) self.assertEqual(x >= y, list(x) >= list(y), (x, y)) self.assertEqual(cmp(x, y), cmp(list(x), list(y)), (x, y))
def test_getitem(self): n = 200 d = deque(xrange(n)) l = range(n) for i in xrange(n): d.popleft() l.pop(0) if random.random() < 0.5: d.append(i) l.append(i) for j in xrange(1 - len(l), len(l)): assert d[j] == l[j] d = deque('superman') self.assertEqual(d[0], 's') self.assertEqual(d[-1], 'n') d = deque() self.assertRaises(IndexError, d.__getitem__, 0) self.assertRaises(IndexError, d.__getitem__, -1)
def test_big_stack_left(self): d = deque() append, pop = d.appendleft, d.popleft for i in xrange(BIG): append(i) for i in reversed(xrange(BIG)): x = pop() if x != i: self.assertEqual(x, i) self.assertEqual(len(d), 0)
def test_constructor(self): for s in ("123", "", range(1000), ('do', 1.2), xrange(2000, 2200, 5)): for g in (seq_tests.Sequence, seq_tests.IterFunc, seq_tests.IterGen, seq_tests.IterFuncStop, seq_tests.itermulti, seq_tests.iterfunc): self.assertEqual(list(deque(g(s))), list(g(s))) self.assertRaises(TypeError, deque, seq_tests.IterNextOnly(s)) self.assertRaises(TypeError, deque, seq_tests.IterNoNext(s)) self.assertRaises(ZeroDivisionError, deque, seq_tests.IterGenExc(s))
def test_getitem(self): n = 200 d = deque(xrange(n)) l = range(n) for i in xrange(n): d.popleft() l.pop(0) if random.random() < 0.5: d.append(i) l.append(i) for j in xrange(1 - len(l), len(l)): assert d[j] == l[j] d = deque("superman") self.assertEqual(d[0], "s") self.assertEqual(d[-1], "n") d = deque() self.assertRaises(IndexError, d.__getitem__, 0) self.assertRaises(IndexError, d.__getitem__, -1)
def test_reverse(self): n = 500 # O(n**2) test, don't make this too big data = [random.random() for i in range(n)] for i in range(n): d = deque(data[:i]) r = d.reverse() self.assertEqual(list(d), list(reversed(data[:i]))) self.assertIs(r, None) d.reverse() self.assertEqual(list(d), data[:i]) self.assertRaises(TypeError, d.reverse, 1) # Arity is zero
def test_setitem(self): n = 200 d = deque(xrange(n)) for i in xrange(n): d[i] = 10 * i self.assertEqual(list(d), [10 * i for i in xrange(n)]) l = list(d) for i in xrange(1 - n, 0, -1): d[i] = 7 * i l[i] = 7 * i self.assertEqual(list(d), l)
def test_maxlen(self): self.assertRaises(ValueError, deque, 'abc', -1) self.assertRaises(ValueError, deque, 'abc', -2) it = iter(range(10)) d = deque(it, maxlen=3) self.assertEqual(list(it), []) self.assertEqual(repr(d), 'deque([7, 8, 9], maxlen=3)') self.assertEqual(list(d), range(7, 10)) self.assertEqual(d, deque(range(10), 3)) d.append(10) self.assertEqual(list(d), range(8, 11)) d.appendleft(7) self.assertEqual(list(d), range(7, 10)) d.extend([10, 11]) self.assertEqual(list(d), range(9, 12)) d.extendleft([8, 7]) self.assertEqual(list(d), range(7, 10)) d = deque(xrange(200), maxlen=10) d.append(d) test_support.unlink(test_support.TESTFN) fo = open(test_support.TESTFN, "wb") try: print >> fo, d, fo.close() fo = open(test_support.TESTFN, "rb") self.assertEqual(fo.read(), repr(d)) finally: fo.close() test_support.unlink(test_support.TESTFN) d = deque(range(10), maxlen=None) self.assertEqual(repr(d), 'deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])') fo = open(test_support.TESTFN, "wb") try: print >> fo, d, fo.close() fo = open(test_support.TESTFN, "rb") self.assertEqual(fo.read(), repr(d)) finally: fo.close() test_support.unlink(test_support.TESTFN)
def test_maxlen(self): self.assertRaises(ValueError, deque, "abc", -1) self.assertRaises(ValueError, deque, "abc", -2) it = iter(range(10)) d = deque(it, maxlen=3) self.assertEqual(list(it), []) self.assertEqual(repr(d), "deque([7, 8, 9], maxlen=3)") self.assertEqual(list(d), range(7, 10)) self.assertEqual(d, deque(range(10), 3)) d.append(10) self.assertEqual(list(d), range(8, 11)) d.appendleft(7) self.assertEqual(list(d), range(7, 10)) d.extend([10, 11]) self.assertEqual(list(d), range(9, 12)) d.extendleft([8, 7]) self.assertEqual(list(d), range(7, 10)) d = deque(xrange(200), maxlen=10) d.append(d) test_support.unlink(test_support.TESTFN) fo = open(test_support.TESTFN, "wb") try: print >> fo, d, fo.close() fo = open(test_support.TESTFN, "rb") self.assertEqual(fo.read(), repr(d)) finally: fo.close() test_support.unlink(test_support.TESTFN) d = deque(range(10), maxlen=None) self.assertEqual(repr(d), "deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])") fo = open(test_support.TESTFN, "wb") try: print >> fo, d, fo.close() fo = open(test_support.TESTFN, "rb") self.assertEqual(fo.read(), repr(d)) finally: fo.close() test_support.unlink(test_support.TESTFN)
def __init__(self, engine): self.engine = engine self._expectations = collections.deque() self._is_dead = threading.Event() self._std_streams_closed = False self.engine.on_process_spawned(self) self._send_queue = queue.Queue() self._send_thread = threading.Thread(target=self._send_thread_target) self._send_thread.daemon = True self._send_thread.start()
def test_print(self): d = deque(xrange(200)) d.append(d) test_support.unlink(test_support.TESTFN) fo = open(test_support.TESTFN, "wb") try: print >> fo, d, fo.close() fo = open(test_support.TESTFN, "rb") self.assertEqual(fo.read(), repr(d)) finally: fo.close() test_support.unlink(test_support.TESTFN)
def test_delitem(self): n = 500 # O(n**2) test, don't make this too big d = deque(xrange(n)) self.assertRaises(IndexError, d.__delitem__, -n - 1) self.assertRaises(IndexError, d.__delitem__, n) for i in xrange(n): self.assertEqual(len(d), n - i) j = random.randrange(-len(d), len(d)) val = d[j] self.assertIn(val, d) del d[j] self.assertNotIn(val, d) self.assertEqual(len(d), 0)
def test_constructor(self): for s in ("123", "", range(1000), ("do", 1.2), xrange(2000, 2200, 5)): for g in ( seq_tests.Sequence, seq_tests.IterFunc, seq_tests.IterGen, seq_tests.IterFuncStop, seq_tests.itermulti, seq_tests.iterfunc, ): self.assertEqual(list(deque(g(s))), list(g(s))) self.assertRaises(TypeError, deque, seq_tests.IterNextOnly(s)) self.assertRaises(TypeError, deque, seq_tests.IterNoNext(s)) self.assertRaises(ZeroDivisionError, deque, seq_tests.IterGenExc(s))
def test_count(self): for s in ('', 'abracadabra', 'simsalabim' * 500 + 'abc'): s = list(s) d = deque(s) for letter in 'abcdefghijklmnopqrstuvwxyz': self.assertEqual(s.count(letter), d.count(letter), (s, d, letter)) self.assertRaises(TypeError, d.count) # too few args self.assertRaises(TypeError, d.count, 1, 2) # too many args class BadCompare: def __eq__(self, other): raise ArithmeticError d = deque([1, 2, BadCompare(), 3]) self.assertRaises(ArithmeticError, d.count, 2) d = deque([1, 2, 3]) self.assertRaises(ArithmeticError, d.count, BadCompare()) class MutatingCompare: def __eq__(self, other): self.d.pop() return True m = MutatingCompare() d = deque([1, 2, 3, m, 4, 5]) m.d = d self.assertRaises(RuntimeError, d.count, 3) # test issue11004 # block advance failed after rotation aligned elements on right side of block d = deque([None] * 16) for i in range(len(d)): d.rotate(-1) d.rotate(1) self.assertEqual(d.count(1), 0) self.assertEqual(d.count(None), 16)
def test_maxlen_attribute(self): self.assertEqual(deque().maxlen, None) self.assertEqual(deque("abc").maxlen, None) self.assertEqual(deque("abc", maxlen=4).maxlen, 4) self.assertEqual(deque("abc", maxlen=2).maxlen, 2) self.assertEqual(deque("abc", maxlen=0).maxlen, 0) with self.assertRaises(AttributeError): d = deque("abc") d.maxlen = 10
def test_maxlen_attribute(self): self.assertEqual(deque().maxlen, None) self.assertEqual(deque('abc').maxlen, None) self.assertEqual(deque('abc', maxlen=4).maxlen, 4) self.assertEqual(deque('abc', maxlen=2).maxlen, 2) self.assertEqual(deque('abc', maxlen=0).maxlen, 0) with self.assertRaises(AttributeError): d = deque('abc') d.maxlen = 10
def test_len(self): d = deque('ab') self.assertEqual(len(d), 2) d.popleft() self.assertEqual(len(d), 1) d.pop() self.assertEqual(len(d), 0) self.assertRaises(IndexError, d.pop) self.assertEqual(len(d), 0) d.append('c') self.assertEqual(len(d), 1) d.appendleft('d') self.assertEqual(len(d), 2) d.clear() self.assertEqual(len(d), 0)
def test_count(self): for s in ("", "abracadabra", "simsalabim" * 500 + "abc"): s = list(s) d = deque(s) for letter in "abcdefghijklmnopqrstuvwxyz": self.assertEqual(s.count(letter), d.count(letter), (s, d, letter)) self.assertRaises(TypeError, d.count) # too few args self.assertRaises(TypeError, d.count, 1, 2) # too many args class BadCompare: def __eq__(self, other): raise ArithmeticError d = deque([1, 2, BadCompare(), 3]) self.assertRaises(ArithmeticError, d.count, 2) d = deque([1, 2, 3]) self.assertRaises(ArithmeticError, d.count, BadCompare()) class MutatingCompare: def __eq__(self, other): self.d.pop() return True m = MutatingCompare() d = deque([1, 2, 3, m, 4, 5]) m.d = d self.assertRaises(RuntimeError, d.count, 3) # test issue11004 # block advance failed after rotation aligned elements on right side of block d = deque([None] * 16) for i in range(len(d)): d.rotate(-1) d.rotate(1) self.assertEqual(d.count(1), 0) self.assertEqual(d.count(None), 16)
def test_len(self): d = deque("ab") self.assertEqual(len(d), 2) d.popleft() self.assertEqual(len(d), 1) d.pop() self.assertEqual(len(d), 0) self.assertRaises(IndexError, d.pop) self.assertEqual(len(d), 0) d.append("c") self.assertEqual(len(d), 1) d.appendleft("d") self.assertEqual(len(d), 2) d.clear() self.assertEqual(len(d), 0)
def test_basics(self): d = deque(xrange(-5125, -5000)) d.__init__(xrange(200)) for i in xrange(200, 400): d.append(i) for i in reversed(xrange(-200, 0)): d.appendleft(i) self.assertEqual(list(d), range(-200, 400)) self.assertEqual(len(d), 600) left = [d.popleft() for i in xrange(250)] self.assertEqual(left, range(-200, 50)) self.assertEqual(list(d), range(50, 400)) right = [d.pop() for i in xrange(250)] right.reverse() self.assertEqual(right, range(150, 400)) self.assertEqual(list(d), range(50, 150))
def from_board(cls, board): """Creates a game from the move stack of a :class:`~chess.Board()`.""" # Undo all moves. switchyard = collections.deque() while board.move_stack: switchyard.append(board.pop()) # Setup initial position. game = cls() game.setup(board) node = game # Replay all moves. while switchyard: move = switchyard.pop() node = node.add_variation(move) board.push(move) game.headers["Result"] = board.result() return game
def test_remove(self): d = deque('abcdefghcij') d.remove('c') self.assertEqual(d, deque('abdefghcij')) d.remove('c') self.assertEqual(d, deque('abdefghij')) self.assertRaises(ValueError, d.remove, 'c') self.assertEqual(d, deque('abdefghij')) # Handle comparison errors d = deque(['a', 'b', BadCmp(), 'c']) e = deque(d) self.assertRaises(RuntimeError, d.remove, 'c') for x, y in zip(d, e): # verify that original order and values are retained. self.assertTrue(x is y) # Handle evil mutator for match in (True, False): d = deque(['ab']) d.extend([MutateCmp(d, match), 'c']) self.assertRaises(IndexError, d.remove, 'c') self.assertEqual(d, deque())
def test_remove(self): d = deque("abcdefghcij") d.remove("c") self.assertEqual(d, deque("abdefghcij")) d.remove("c") self.assertEqual(d, deque("abdefghij")) self.assertRaises(ValueError, d.remove, "c") self.assertEqual(d, deque("abdefghij")) # Handle comparison errors d = deque(["a", "b", BadCmp(), "c"]) e = deque(d) self.assertRaises(RuntimeError, d.remove, "c") for x, y in zip(d, e): # verify that original order and values are retained. self.assertTrue(x is y) # Handle evil mutator for match in (True, False): d = deque(["ab"]) d.extend([MutateCmp(d, match), "c"]) self.assertRaises(IndexError, d.remove, "c") self.assertEqual(d, deque())
def read_game(handle, Visitor=GameModelCreator): """ Reads a game from a file opened in text mode. >>> pgn = open("data/pgn/kasparov-deep-blue-1997.pgn") >>> first_game = chess.pgn.read_game(pgn) >>> second_game = chess.pgn.read_game(pgn) >>> >>> first_game.headers["Event"] 'IBM Man-Machine, New York USA' By using text mode the parser does not need to handle encodings. It is the callers responsibility to open the file with the correct encoding. PGN files are ASCII or UTF-8 most of the time. So the following should cover most relevant cases (ASCII, UTF-8 without BOM, UTF-8 with BOM, UTF-8 with encoding errors). >>> pgn = open("data/pgn/kasparov-deep-blue-1997.pgn", encoding="utf-8-sig", errors="surrogateescape") Use `StringIO` to parse games from a string. >>> pgn_string = "1. e4 e5 2. Nf3 *" >>> >>> try: >>> from StringIO import StringIO # Python 2 >>> except ImportError: >>> from io import StringIO # Python 3 >>> >>> pgn = StringIO(pgn_string) >>> game = chess.pgn.read_game(pgn) The end of a game is determined by a completely blank line or the end of the file. (Of course blank lines in comments are possible.) According to the standard at least the usual 7 header tags are required for a valid game. This parser also handles games without any headers just fine. The parser is relatively forgiving when it comes to errors. It skips over tokens it can not parse. Any exceptions are logged. Returns the parsed game or ``None`` if the EOF is reached. """ visitor = Visitor() dummy_game = Game() found_game = False found_content = False line = handle.readline() # Parse game headers. while line: # Skip empty lines and comments. if not line.strip() or line.strip().startswith("%"): line = handle.readline() continue if not found_game: visitor.begin_game() visitor.begin_headers() found_game = True # Read header tags. tag_match = TAG_REGEX.match(line) if tag_match: dummy_game.headers[tag_match.group(1)] = tag_match.group(2) visitor.visit_header(tag_match.group(1), tag_match.group(2)) else: break line = handle.readline() if found_game: visitor.end_headers() # Get the next non-empty line. while not line.strip() and line: line = handle.readline() # Movetext parser state. try: board_stack = collections.deque([dummy_game.board()]) except ValueError as error: visitor.handle_error(error) board_stack = collections.deque([chess.Board()]) # Parse movetext. while line: read_next_line = True # An empty line is the end of a game. if not line.strip() and found_content: if found_game: visitor.end_game() return visitor.result() else: return for match in MOVETEXT_REGEX.finditer(line): token = match.group(0) if token.startswith("%"): # Ignore the rest of the line. line = handle.readline() continue if not found_game: found_game = True visitor.begin_game() if token.startswith("{"): # Consume until the end of the comment. line = token[1:] comment_lines = [] while line and "}" not in line: comment_lines.append(line.rstrip()) line = handle.readline() end_index = line.find("}") comment_lines.append(line[:end_index]) if "}" in line: line = line[end_index:] else: line = "" visitor.visit_comment("\n".join(comment_lines).strip()) # Continue with the current or the next line. if line: read_next_line = False break elif token.startswith("$"): # Found a NAG. try: nag = int(token[1:]) except ValueError as error: visitor.handle_error(error) else: visitor.visit_nag(nag) elif token == "?": visitor.visit_nag(NAG_MISTAKE) elif token == "??": visitor.visit_nag(NAG_BLUNDER) elif token == "!": visitor.visit_nag(NAG_GOOD_MOVE) elif token == "!!": visitor.visit_nag(NAG_BRILLIANT_MOVE) elif token == "!?": visitor.visit_nag(NAG_SPECULATIVE_MOVE) elif token == "?!": visitor.visit_nag(NAG_DUBIOUS_MOVE) elif token == "(": if board_stack[-1].move_stack: visitor.begin_variation() board = board_stack[-1].copy() board.pop() board_stack.append(board) elif token == ")": # Found a close variation token. Always leave at least the # root node on the stack. if len(board_stack) > 1: visitor.end_variation() board_stack.pop() elif token in ["1-0", "0-1", "1/2-1/2", "*"] and len(board_stack) == 1: # Found a result token. found_content = True visitor.visit_result(token) else: # Found a SAN token. found_content = True # Replace zeros castling notation. if token == "0-0": token = "O-O" elif token == "0-0-0": token = "O-O-O" # Parse the SAN. try: move = board_stack[-1].parse_san(token) except ValueError as error: visitor.handle_error(error) else: visitor.visit_move(board_stack[-1], move) board_stack[-1].push(move) if read_next_line: line = handle.readline() if found_game: visitor.end_game() return visitor.result()
def position(self, board, async_callback=None): """ Set up a given position. Instead of just the final FEN, the initial FEN and all moves leading up to the position will be sent, so that the engine can detect repetitions. If the position is from a new game it is recommended to use the *ucinewgame* command before the *position* command. :param board: A *chess.Board*. :return: Nothing :raises: :exc:`~chess.uci.EngineStateException` if the engine is still calculating. """ # Work on a local copy. board = board.copy() # Raise if this is called while the engine is still calculating. with self.state_changed: if not self.idle: raise EngineStateException("position command while engine is busy") builder = [] builder.append("position") # Take back moves to obtain the first FEN we know. Later giving the # moves explicitly allows for transposition detection. switchyard = collections.deque() while board.move_stack: switchyard.append(board.pop()) # Validate castling rights. if not self.uci_chess960 and board.chess960: if board.has_chess960_castling_rights(): LOGGER.error("not in UCI_Chess960 mode but position has non-standard castling rights") # Just send the final FEN without transpositions in hops # that this will work. while switchyard: board.push(switchyard.pop()) # Send startposition. if board.fen() == chess.STARTING_FEN: builder.append("startpos") else: builder.append("fen") if self.uci_chess960: builder.append(board.shredder_fen()) else: builder.append(board.fen()) # Send moves. if switchyard: builder.append("moves") while switchyard: move = switchyard.pop() builder.append(board.uci(move, chess960=self.uci_chess960)) board.push(move) self.board = board def command(): with self.semaphore: with self.readyok_received: self.send_line(" ".join(builder)) self.send_line("isready") self.readyok_received.wait() if self.terminated.is_set(): raise EngineTerminatedException() return self._queue_command(command, async_callback)
def read_game(handle, Visitor=GameModelCreator): """ Reads a game from a file opened in text mode. >>> pgn = open("data/pgn/kasparov-deep-blue-1997.pgn") >>> first_game = chess.pgn.read_game(pgn) >>> second_game = chess.pgn.read_game(pgn) >>> >>> first_game.headers["Event"] 'IBM Man-Machine, New York USA' By using text mode the parser does not need to handle encodings. It is the callers responsibility to open the file with the correct encoding. PGN files are ASCII or UTF-8 most of the time. So the following should cover most relevant cases (ASCII, UTF-8 without BOM, UTF-8 with BOM, UTF-8 with encoding errors). >>> pgn = open("data/pgn/kasparov-deep-blue-1997.pgn", encoding="utf-8-sig", errors="surrogateescape") Use `StringIO` to parse games from a string. >>> pgn_string = "1. e4 e5 2. Nf3 *" >>> >>> try: >>> from StringIO import StringIO # Python 2 >>> except ImportError: >>> from io import StringIO # Python 3 >>> >>> pgn = StringIO(pgn_string) >>> game = chess.pgn.read_game(pgn) The end of a game is determined by a completely blank line or the end of the file. (Of course blank lines in comments are possible.) According to the standard at least the usual 7 header tags are required for a valid game. This parser also handles games without any headers just fine. The parser is relatively forgiving when it comes to errors. It skips over tokens it can not parse. Any exceptions are logged. Returns the parsed game or ``None`` if the EOF is reached. """ visitor = Visitor() dummy_game = Game() found_game = False found_content = False line = handle.readline() # Parse game headers. while line: # Skip empty lines and comments. if not line.strip() or line.strip().startswith("%"): line = handle.readline() continue if not found_game: visitor.begin_game() visitor.begin_headers() found_game = True # Read header tags. tag_match = TAG_REGEX.match(line) if tag_match: dummy_game.headers[tag_match.group(1)] = tag_match.group(2) visitor.visit_header(tag_match.group(1), tag_match.group(2)) else: break line = handle.readline() if found_game: visitor.end_headers() # Get the next non-empty line. while not line.strip() and line: line = handle.readline() # Movetext parser state. try: board_stack = collections.deque([dummy_game.board()]) except ValueError as error: visitor.handle_error(error) board_stack = collections.deque([chess.Board()]) # Parse movetext. while line: read_next_line = True # An empty line is the end of a game. if not line.strip() and found_content: if found_game: visitor.end_game() return visitor.result() for match in MOVETEXT_REGEX.finditer(line): token = match.group(0) if token.startswith("%"): # Ignore the rest of the line. line = handle.readline() continue if not found_game: found_game = True visitor.begin_game() if token.startswith("{"): # Consume until the end of the comment. line = token[1:] comment_lines = [] while line and "}" not in line: comment_lines.append(line.rstrip()) line = handle.readline() end_index = line.find("}") comment_lines.append(line[:end_index]) if "}" in line: line = line[end_index:] else: line = "" visitor.visit_comment("\n".join(comment_lines).strip()) # Continue with the current or the next line. if line: read_next_line = False break elif token.startswith("$"): # Found a NAG. try: nag = int(token[1:]) except ValueError as error: visitor.handle_error(error) else: visitor.visit_nag(nag) elif token == "?": visitor.visit_nag(NAG_MISTAKE) elif token == "??": visitor.visit_nag(NAG_BLUNDER) elif token == "!": visitor.visit_nag(NAG_GOOD_MOVE) elif token == "!!": visitor.visit_nag(NAG_BRILLIANT_MOVE) elif token == "!?": visitor.visit_nag(NAG_SPECULATIVE_MOVE) elif token == "?!": visitor.visit_nag(NAG_DUBIOUS_MOVE) elif token == "(": if board_stack[-1].move_stack: visitor.begin_variation() board = board_stack[-1].copy() board.pop() board_stack.append(board) elif token == ")": # Found a close variation token. Always leave at least the # root node on the stack. if len(board_stack) > 1: visitor.end_variation() board_stack.pop() elif token in ["1-0", "0-1", "1/2-1/2", "*"] and len(board_stack) == 1: # Found a result token. found_content = True visitor.visit_result(token) else: # Found a SAN token. found_content = True # Replace zeros castling notation. if token == "0-0": token = "O-O" elif token == "0-0-0": token = "O-O-O" # Parse the SAN. try: move = board_stack[-1].parse_san(token) except ValueError as error: visitor.handle_error(error) else: visitor.visit_move(board_stack[-1], move) board_stack[-1].push(move) if read_next_line: line = handle.readline() if found_game: visitor.end_game() return visitor.result()