def test_colour_at(): """ Get a colour at a point """ from painterm.image import Image image = Image.new_image(2, 1) # out-of-bounds colours for x, y in ((0, 1), (-1, 0), (2, 0), (0, -1)): with assert_raises(AssertionError): image.colour_at(x, y) assert_equals(image.colour_at(0, 0), BACKGROUND) assert_equals(image.colour_at(1, 0), BACKGROUND) colour = Colour(0, 1, 2, 0.5) image.draw(1, 0, colour) assert_equals(image.colour_at(0, 0), BACKGROUND) assert_equals(image.colour_at(1, 0), colour) colour2 = Colour(5, 4, 3, 0.2) image.draw(0, 0, colour2) image.draw(1, 0, colour2) assert_equals(image.colour_at(0, 0), colour2) assert_equals(image.colour_at(1, 0), colour2) redrawn = Image.new_image(1, 1) redrawn.draw(0, 0, BACKGROUND) redrawn.draw(0, 0, colour, continue_transaction=True) redrawn.draw(0, 0, colour2, continue_transaction=True) assert_equals(redrawn.colour_at(0, 0), colour2)
def test_load_image(): """ Load an existing image """ from painterm.image import Image # file-based: with TemporaryDirectory() as name: path = Path(name) / 'named' Image.new_image(9, 7, path) image = Image.load(path) assert_equals(image.width, 9) assert_equals(image.height, 7) assert_is_none(image.copyright) assert_is_none(image.description) cursor = image._cursor cursor.execute('SELECT major, minor, micro, width, height FROM meta;') assert_equals(cursor.fetchall(), [(0, 1, 0, 9, 7)]) cursor.execute('SELECT id, time FROM transactions;') assert_equals(cursor.fetchall(), [(0, 0)]) cursor.execute( 'SELECT transaction_id, x, y, red, green, blue, alpha FROM draws;' ) assert_equals( frozenset(cursor), {(0, x, y, *BACKGROUND) for x in range(9) for y in range(7)} )
def test_export_bitmap(): """ Export to a BMP """ from painterm.image import Image base = Path(__file__).absolute().parent expected = base / 'sample_image.bmp' points = { (1, 1), (1, 2), (2, 1), (2, 2), (5, 1), (5, 2), (6, 1), (6, 2), (6, 5), (6, 6), (5, 6), (4, 6), (3, 6) } yellow = Colour(234, 236, 35, 1.0) black = Colour(0, 0, 0, 1.0) image = Image.new_image(8, 8, background=yellow) for x, y in points: image.draw(x, y, black) with TemporaryDirectory() as name: actual = Path(name) / 'actual.bmp' image.export_bitmap(actual) assert_equals(actual.read_bytes(), expected.read_bytes()) # magnification for magnification in (3.3, -1, 0): with assert_raises(AssertionError): image.export_bitmap(actual, magnification=magnification) with TemporaryDirectory() as name: actual = Path(name) image = Image.new_image(2, 2, background=yellow) image.draw(0, 0, black) image.draw(1, 1, black) image.export_bitmap(actual / '4x.bmp', magnification=4) assert_equals( (actual / '4x.bmp').read_bytes(), (base / '4x.bmp').read_bytes()) image = Image.new_image(4, 4, background=yellow) image.draw(0, 0, black) image.draw(1, 1, black) image.export_bitmap(actual / '2x.bmp', magnification=2) assert_equals( (actual / '2x.bmp').read_bytes(), (base / '2x.bmp').read_bytes() )
def fillable(): """ Return the fillable image """ image = Image.new_image(4, 3,) image.draw(0, 1, colour) image.draw(1, 0, colour) image.draw(1, 2, colour) image.draw(3, 0, colour) image.draw(3, 2, colour) return image
def test_copyright(): """ Copyrights? """ from painterm.image import Image image = Image.new_image(1, 1) assert_is_none(image.copyright) image.set_copyright('©️2015 bcj') assert_equals(image.copyright, '©️2015 bcj')
def test_description(): """ described? """ from painterm.image import Image image = Image.new_image(1, 1) image.draw(0, 0, Colour(128, 197, 221, 1.0)) assert_is_none(image.description) image.set_description('A minimal Sagan') assert_equals(image.description, 'A minimal Sagan')
def test_resize(): """ Resize an image """ from painterm.image import Image image = Image.new_image(1, 1) colour1 = Colour(255, 0, 0, 1) colour2 = Colour(0, 255, 0, 1) image.draw(0, 0, colour1) image.resize(2, 2) assert_equals(image.width, 2) assert_equals(image.height, 2) assert_equals(image.colour_at(0, 0), colour1) assert_equals(image.colour_at(0, 1), BACKGROUND) assert_equals(image.colour_at(1, 0), BACKGROUND) assert_equals(image.colour_at(1, 1), BACKGROUND) image.fill(1, 1, colour2) image.draw(0, 1, colour1) image.draw(1, 0, colour1) image.resize(1, 2) assert_equals(image.width, 1) assert_equals(image.height, 2) assert_equals(image.colour_at(0, 0), colour1) assert_equals(image.colour_at(0, 1), colour1) # emptry transaction should be gone. next undo should remove # draw(0, 1) image.undo() assert_equals(image.width, 1) assert_equals(image.height, 2) assert_equals(image.colour_at(0, 0), colour1) assert_equals(image.colour_at(0, 1), colour2) image.resize(2, 1) assert_equals(image.width, 2) assert_equals(image.height, 1) assert_equals(image.colour_at(0, 0), colour1) assert_equals(image.colour_at(1, 0), BACKGROUND)
def test_export_pxon(): """ Export to PXON """ from painterm.image import Image, PXON_VERSION points = { (1, 1), (1, 2), (2, 1), (2, 2), (5, 1), (5, 2), (6, 1), (6, 2), (6, 5), (6, 6), (5, 6), (4, 6), (3, 6) } yellow = Colour(234, 236, 35, 1.0) black = Colour(0, 0, 0, 1.0) image = Image.new_image(8, 8) for x, y in points: image.draw(x, y, black) image.fill(0, 0, yellow) with TemporaryDirectory() as name: actual = Path(name) / 'actual.pxon' image.export_pxon(actual, size=1) with actual.open() as stream: pxon = json.load(stream) assert_equals(pxon.keys(), {'exif', 'pxif', 'version'}) assert_equals(tuple(pxon['version']), PXON_VERSION) exif = pxon['exif'] assert_equals( exif.keys(), {'software', 'dateTime', 'height', 'width'} ) assert_equals(exif['software'], 'painterm') assert_equals(exif['dateTime'], image.creation_date) assert_equals(exif['height'], image.height) assert_equals(exif['width'], image.width) pxif = pxon['pxif'] assert_equals(pxif.keys(), {'pixels'})
def test_authors(): """ who wrote this? """ from painterm.image import Image image = Image.new_image(1, 1) assert_equals(image.authors, frozenset()) image.add_authors() assert_equals(image.authors, frozenset()) image.add_authors('bcj') assert_equals(image.authors, {'bcj'}) image.add_authors('someone', 'else') assert_equals(image.authors, {'bcj', 'someone', 'else'})
def main(): """ Run painterm from the command line. """ parser = ArgumentParser(description="A curses-based pixel art tool") sub = parser.add_subparsers(help="functions") new = sub.add_parser('new', help="Create a new image") new.set_defaults(function='new') new.add_argument( 'path', type=lambda raw: Path(raw).expanduser().absolute(), help="The location to save to" ) new.add_argument( '--width', '-x', default=DEFAULT_WIDTH, type=int, help="The width of the new image." ) new.add_argument( '--height', '-y', default=DEFAULT_HEIGHT, type=int, help="The height of the new image." ) new.add_argument( '--platform', default=None, type=lambda name: Platform[name.lower()], help="The palette to use ({})".format( ', '.join(Platform.__members__.keys()) ) ) load = sub.add_parser('load', help="Load an existing image") load.set_defaults(function='load') load.add_argument( 'path', type=lambda raw: Path(raw).expanduser().absolute(), help="The location to load from to" ) load.add_argument( '--platform', default=None, type=lambda name: Platform[name.lower()], help="The palette to use ({})".format( ', '.join(Platform.__members__.keys()) ) ) bmp = sub.add_parser('bmp', help="Export image to a bitmap file") bmp.set_defaults(function='bmp') bmp.add_argument( 'input', type=lambda raw: Path(raw).expanduser().absolute(), help="The location of the image" ) bmp.add_argument( 'output', type=lambda raw: Path(raw).expanduser().absolute(), help="The location to save the bitmap" ) bmp.add_argument( '--magnification', '-m', default=1, type=int, help="How much to magnify the bitmap" ) pxon = sub.add_parser('pxon', help="Export image to a PXON file") pxon.set_defaults(function='pxon') pxon.add_argument( 'input', type=lambda raw: Path(raw).expanduser().absolute(), help="The location of the image" ) pxon.add_argument( 'output', type=lambda raw: Path(raw).expanduser().absolute(), help="The location to save the PXON file" ) pxon.add_argument( '--size', '-s', default=PXON_SIZE, type=int, help="How large each pixel should be" ) args = parser.parse_args() if not hasattr(args, 'function'): print('run painterm --help to see options') return if args.function == 'new': palette = get_palette(args.platform) image = Image.new_image( args.width, args.height, path=args.path, ) elif args.function == 'load': palette = get_palette(args.platform) image = Image.load(args.path) elif args.function == 'bmp': Image.load(args.input).export_bitmap( args.output, magnification=args.magnification ) return elif args.function == 'pxon': Image.load(args.input).export_pxon( args.output, size=args.size ) return curses.wrapper( painterm, image=image, palette=palette, )
def test_undo_redo(): """ Undo/Redo """ from painterm.image import Image image = Image.new_image(1, 1, background=Colour(0, 0, 0, 0)) def get_committed(): """ get committed transactions """ return { transaction_id for (transaction_id,) in image._cursor.execute( 'SELECT id FROM transactions WHERE time IS NOT NULL;' ) } def get_uncommitted(): """ get uncommitted transactions """ return { transaction_id for (transaction_id,) in image._cursor.execute( 'SELECT id FROM transactions WHERE time IS NULL;' ) } def get_draws(): """ get uncommitted transactions """ results = image._cursor.execute( 'SELECT transaction_id, red, green, blue, alpha FROM draws;' ).fetchall() return { transaction_id if all(transaction_id == channel for channel in channels[:3]) else (transaction_id, Colour(*channels)) for transaction_id, *channels in results } # undo/redo shouldn't effect a new image image.undo() assert_equals(get_committed(), {0}) assert_equals(get_uncommitted(), set()) assert_equals(get_draws(), {0}) assert_equals(image.colour_at(0, 0), Colour(0, 0, 0, 0)) image.redo() assert_equals(get_committed(), {0}) assert_equals(get_uncommitted(), set()) assert_equals(get_draws(), {0}) assert_equals(image.colour_at(0, 0), Colour(0, 0, 0, 0)) # redo should do nothing if at latest image.draw(0, 0, Colour(1, 1, 1, 1)) assert_equals(get_committed(), {0, 1}) assert_equals(get_uncommitted(), set()) assert_equals(get_draws(), {0, 1}) assert_equals(image.colour_at(0, 0), Colour(1, 1, 1, 1)) image.redo() assert_equals(get_committed(), {0, 1}) assert_equals(get_uncommitted(), set()) assert_equals(get_draws(), {0, 1}) assert_equals(image.colour_at(0, 0), Colour(1, 1, 1, 1)) # undo shouldn't happen more than once for _ in range(5): image.undo() assert_equals(get_committed(), {0}) assert_equals(get_uncommitted(), {1}) assert_equals(get_draws(), {0, 1}) assert_equals(image.colour_at(0, 0), Colour(0, 0, 0, 0)) image.redo() assert_equals(get_committed(), {0, 1}) assert_equals(get_uncommitted(), set()) assert_equals(get_draws(), {0, 1}) assert_equals(image.colour_at(0, 0), Colour(1, 1, 1, 1)) # multiple layars image.draw(0, 0, Colour(2, 2, 2, 0.2)) assert_equals(get_committed(), {0, 1, 2}) assert_equals(get_uncommitted(), set()) assert_equals(get_draws(), {0, 1, 2}) assert_equals(image.colour_at(0, 0), Colour(2, 2, 2, 0.2)) image.undo() image.undo() assert_equals(get_committed(), {0}) assert_equals(get_uncommitted(), {1, 2}) assert_equals(get_draws(), {0, 1, 2}) assert_equals(image.colour_at(0, 0), Colour(0, 0, 0, 0)) image.redo() assert_equals(get_committed(), {0, 1}) assert_equals(get_uncommitted(), {2}) assert_equals(get_draws(), {0, 1, 2}) assert_equals(image.colour_at(0, 0), Colour(1, 1, 1, 1)) # remove redo on overwrite image.undo() image.draw(0, 0, BACKGROUND) assert_equals(get_committed(), {0, 3}) assert_equals(get_uncommitted(), set()) assert_equals(get_draws(), {0, (3, Colour(255, 255, 255, 0))}) assert_equals(image.colour_at(0, 0), BACKGROUND) image.redo() assert_equals(get_committed(), {0, 3}) assert_equals(get_uncommitted(), set()) assert_equals(get_draws(), {0, (3, Colour(255, 255, 255, 0))}) assert_equals(image.colour_at(0, 0), BACKGROUND)
def test_fill(): """ Flood fill a pixel """ from painterm.image import Image image = Image.new_image(2, 1) cursor = image._cursor colour = Colour(0, 1, 2, 0.34) # out-of-bounds colours for x, y in ((0, 1), (-1, 0), (2, 0), (0, -1)): with assert_raises(AssertionError): image.fill(x, y, colour) for bad_colour in ((1, 2, 3), (2, 1, 0, -1)): with assert_raises(AssertionError): image.fill(0, 0, bad_colour) assert_equals( cursor.execute('SELECT COUNT(1) FROM transactions;').fetchone(), (1,) ) assert_equals(image.colour_at(0, 0), BACKGROUND) assert_equals(image.colour_at(1, 0), BACKGROUND) assert_equals(image.fill(1, 0, colour), {(0, 0), (1, 0)}) assert_equals( cursor.execute('SELECT COUNT(1) FROM transactions;').fetchone(), (2,) ) assert_equals( cursor.execute( 'SELECT id FROM transactions ORDER BY time DESC;' ).fetchall(), [(1,), (0,)] ) # Did it colour? results = cursor.execute( 'SELECT x, y, red, green, blue, alpha FROM draws ' 'WHERE transaction_id = ?;', (1,) ).fetchall() assert_equals(len(results), 2) for _, y, *actual_colour in results: assert_equals(y, 0) assert_equals(Colour(*actual_colour), colour) assert_equals(image.colour_at(0, 0), colour) assert_equals(image.colour_at(1, 0), colour) colour2 = Colour(5, 4, 3, 0.21) image.draw(0, 0, BACKGROUND) image.fill(1, 0, colour2, continue_transaction=True) assert_equals( cursor.execute('SELECT COUNT(1) FROM transactions;').fetchone(), (3,) ) assert_equals( cursor.execute( 'SELECT id FROM transactions ORDER BY time DESC;' ).fetchall(), [(2,), (1,), (0,)] ) # Did it colour? results = cursor.execute( 'SELECT x, y, red, green, blue, alpha FROM draws ' 'WHERE transaction_id = ?;', (2,) ).fetchall() assert_equals(len(results), 2) for x, y, *actual_colour in results: assert_equals(y, 0) if x == 0: assert_equals(Colour(*actual_colour), BACKGROUND) elif x == 1: assert_equals(Colour(*actual_colour), colour2) else: raise AssertionError assert_equals(image.colour_at(0, 0), BACKGROUND) assert_equals(image.colour_at(1, 0), colour2) # full fill test def fillable(): """ Return the fillable image """ image = Image.new_image(4, 3,) image.draw(0, 1, colour) image.draw(1, 0, colour) image.draw(1, 2, colour) image.draw(3, 0, colour) image.draw(3, 2, colour) return image # really test that filling works correctly image = fillable() assert_equals(image.fill(0, 0, colour2), {(0, 0)}) assert_equals(image.colour_at(0, 0), colour2) assert_equals(image.colour_at(0, 1), colour) assert_equals(image.colour_at(0, 2), BACKGROUND) assert_equals(image.colour_at(1, 0), colour) assert_equals(image.colour_at(1, 1), BACKGROUND) assert_equals(image.colour_at(1, 2), colour) assert_equals(image.colour_at(2, 0), BACKGROUND) assert_equals(image.colour_at(2, 1), BACKGROUND) assert_equals(image.colour_at(2, 2), BACKGROUND) assert_equals(image.colour_at(3, 0), colour) assert_equals(image.colour_at(3, 1), BACKGROUND) assert_equals(image.colour_at(3, 2), colour) image = fillable() assert_equals(image.fill(0, 1, colour2), {(0, 1)}) assert_equals(image.colour_at(0, 0), BACKGROUND) assert_equals(image.colour_at(0, 1), colour2) assert_equals(image.colour_at(0, 2), BACKGROUND) assert_equals(image.colour_at(1, 0), colour) assert_equals(image.colour_at(1, 1), BACKGROUND) assert_equals(image.colour_at(1, 2), colour) assert_equals(image.colour_at(2, 0), BACKGROUND) assert_equals(image.colour_at(2, 1), BACKGROUND) assert_equals(image.colour_at(2, 2), BACKGROUND) assert_equals(image.colour_at(3, 0), colour) assert_equals(image.colour_at(3, 1), BACKGROUND) assert_equals(image.colour_at(3, 2), colour) image = fillable() assert_equals(image.fill(0, 2, colour2), {(0, 2)}) assert_equals(image.colour_at(0, 0), BACKGROUND) assert_equals(image.colour_at(0, 1), colour) assert_equals(image.colour_at(0, 2), colour2) assert_equals(image.colour_at(1, 0), colour) assert_equals(image.colour_at(1, 1), BACKGROUND) assert_equals(image.colour_at(1, 2), colour) assert_equals(image.colour_at(2, 0), BACKGROUND) assert_equals(image.colour_at(2, 1), BACKGROUND) assert_equals(image.colour_at(2, 2), BACKGROUND) assert_equals(image.colour_at(3, 0), colour) assert_equals(image.colour_at(3, 1), BACKGROUND) assert_equals(image.colour_at(3, 2), colour) image = fillable() assert_equals(image.fill(1, 0, colour2), {(1, 0)}) assert_equals(image.colour_at(0, 0), BACKGROUND) assert_equals(image.colour_at(0, 1), colour) assert_equals(image.colour_at(0, 2), BACKGROUND) assert_equals(image.colour_at(1, 0), colour2) assert_equals(image.colour_at(1, 1), BACKGROUND) assert_equals(image.colour_at(1, 2), colour) assert_equals(image.colour_at(2, 0), BACKGROUND) assert_equals(image.colour_at(2, 1), BACKGROUND) assert_equals(image.colour_at(2, 2), BACKGROUND) assert_equals(image.colour_at(3, 0), colour) assert_equals(image.colour_at(3, 1), BACKGROUND) assert_equals(image.colour_at(3, 2), colour) image = fillable() assert_equals(image.fill(1, 2, colour2), {(1, 2)}) assert_equals(image.colour_at(0, 0), BACKGROUND) assert_equals(image.colour_at(0, 1), colour) assert_equals(image.colour_at(0, 2), BACKGROUND) assert_equals(image.colour_at(1, 0), colour) assert_equals(image.colour_at(1, 1), BACKGROUND) assert_equals(image.colour_at(1, 2), colour2) assert_equals(image.colour_at(2, 0), BACKGROUND) assert_equals(image.colour_at(2, 1), BACKGROUND) assert_equals(image.colour_at(2, 2), BACKGROUND) assert_equals(image.colour_at(3, 0), colour) assert_equals(image.colour_at(3, 1), BACKGROUND) assert_equals(image.colour_at(3, 2), colour) image = fillable() assert_equals(image.fill(3, 0, colour2), {(3, 0)}) assert_equals(image.colour_at(0, 0), BACKGROUND) assert_equals(image.colour_at(0, 1), colour) assert_equals(image.colour_at(0, 2), BACKGROUND) assert_equals(image.colour_at(1, 0), colour) assert_equals(image.colour_at(1, 1), BACKGROUND) assert_equals(image.colour_at(1, 2), colour) assert_equals(image.colour_at(2, 0), BACKGROUND) assert_equals(image.colour_at(2, 1), BACKGROUND) assert_equals(image.colour_at(2, 2), BACKGROUND) assert_equals(image.colour_at(3, 0), colour2) assert_equals(image.colour_at(3, 1), BACKGROUND) assert_equals(image.colour_at(3, 2), colour) image = fillable() assert_equals(image.fill(3, 2, colour2), {(3, 2)}) assert_equals(image.colour_at(0, 0), BACKGROUND) assert_equals(image.colour_at(0, 1), colour) assert_equals(image.colour_at(0, 2), BACKGROUND) assert_equals(image.colour_at(1, 0), colour) assert_equals(image.colour_at(1, 1), BACKGROUND) assert_equals(image.colour_at(1, 2), colour) assert_equals(image.colour_at(2, 0), BACKGROUND) assert_equals(image.colour_at(2, 1), BACKGROUND) assert_equals(image.colour_at(2, 2), BACKGROUND) assert_equals(image.colour_at(3, 0), colour) assert_equals(image.colour_at(3, 1), BACKGROUND) assert_equals(image.colour_at(3, 2), colour2) fill_group = {(1, 1), (2, 0), (2, 1), (2, 2), (3, 1)} for x, y in fill_group: image = fillable() assert_equals(image.fill(x, y, colour2), fill_group) assert_equals(image.colour_at(0, 0), BACKGROUND) assert_equals(image.colour_at(0, 1), colour) assert_equals(image.colour_at(0, 2), BACKGROUND) assert_equals(image.colour_at(1, 0), colour) assert_equals(image.colour_at(1, 1), colour2) assert_equals(image.colour_at(1, 2), colour) assert_equals(image.colour_at(2, 0), colour2) assert_equals(image.colour_at(2, 1), colour2) assert_equals(image.colour_at(2, 2), colour2) assert_equals(image.colour_at(3, 0), colour) assert_equals(image.colour_at(3, 1), colour2) assert_equals(image.colour_at(3, 2), colour)
def test_draw(): """ Draw a pixel """ from painterm.image import Image image = Image.new_image(2, 1) cursor = image._cursor colour = Colour(0, 1, 2, 1.0) # out-of-bounds colours for x, y in ((0, 1), (-1, 0), (2, 0), (0, -1)): with assert_raises(AssertionError): image.draw(x, y, colour) for bad_colour in ((1, 2, 3), (2, 1, 0, -1)): with assert_raises(AssertionError): image.draw(0, 0, bad_colour) assert_equals( cursor.execute('SELECT COUNT(1) FROM transactions;').fetchone(), (1,) ) assert_equals(image.colour_at(0, 0), BACKGROUND) assert_equals(image.colour_at(1, 0), BACKGROUND) image.draw(1, 0, colour) assert_equals( cursor.execute('SELECT COUNT(1) FROM transactions;').fetchone(), (2,) ) assert_equals( cursor.execute( 'SELECT id FROM transactions ORDER BY time DESC;' ).fetchall(), [(1,), (0,)] ) # Did it colour? results = cursor.execute( 'SELECT x, y, red, green, blue, alpha FROM draws ' 'WHERE transaction_id = ?;', (1,) ).fetchall() assert_equals(len(results), 1) x, y, *actual_colour = results[0] assert_equals(x, 1) assert_equals(y, 0) assert_equals(Colour(*actual_colour), colour) assert_equals(image.colour_at(0, 0), BACKGROUND) assert_equals(image.colour_at(1, 0), colour) colour2 = Colour(5, 4, 3, 0.21) image.draw(0, 0, colour2) image.draw(1, 0, colour2, continue_transaction=True) assert_equals( cursor.execute('SELECT COUNT(1) FROM transactions;').fetchone(), (3,) ) assert_equals( cursor.execute( 'SELECT id FROM transactions ORDER BY time DESC;' ).fetchall(), [(2,), (1,), (0,)] ) # Did it colour? results = cursor.execute( 'SELECT x, y, red, green, blue, alpha FROM draws ' 'WHERE transaction_id = ?;', (2,) ).fetchall() assert_equals(len(results), 2) for _, y, *actual_colour in results: assert_equals(y, 0) assert_equals(Colour(*actual_colour), colour2) assert_equals(image.colour_at(0, 0), colour2) assert_equals(image.colour_at(1, 0), colour2)
def test_new_image(): """ Create a new image """ from painterm.image import Image # bad width, height for width, height in ((5.5, 5), (-3, 5), (5, '5'), (5, 0)): with assert_raises(AssertionError): Image.new_image(width, height) # in memory image = Image.new_image(10, 5) cursor = image._cursor cursor.execute( 'SELECT major, minor, micro, width, height, ' 'copyright, description FROM meta;' ) assert_equals(cursor.fetchall(), [(0, 1, 0, 10, 5, None, None)]) cursor.execute('SELECT id, time FROM transactions;') assert_equals(cursor.fetchall(), [(0, 0)]) cursor.execute('SELECT name FROM authors;') assert_equals(cursor.fetchall(), []) cursor.execute( 'SELECT transaction_id, x, y, red, green, blue, alpha FROM draws;' ) assert_equals( frozenset(cursor), {(0, x, y, *BACKGROUND) for x in range(10) for y in range(5)} ) # with optional args background = Colour(1, 2, 3, 1.0) image = Image.new_image(3, 4, background=background) cursor = image._cursor cursor.execute('SELECT major, minor, micro, width, height FROM meta;') assert_equals(cursor.fetchall(), [(0, 1, 0, 3, 4)]) cursor.execute('SELECT id, time FROM transactions;') assert_equals(cursor.fetchall(), [(0, 0)]) cursor.execute( 'SELECT transaction_id, x, y, red, green, blue, alpha FROM draws;' ) assert_equals( frozenset(cursor), {(0, x, y, *background) for x in range(3) for y in range(4)} ) # file-based: with TemporaryDirectory() as name: path = Path(name) / 'named' image = Image.new_image(9, 7, path) cursor = sqlite3.connect(path.as_uri(), uri=True).cursor() cursor.execute('SELECT major, minor, micro, width, height FROM meta;') assert_equals(cursor.fetchall(), [(0, 1, 0, 9, 7)]) cursor.execute('SELECT id, time FROM transactions;') assert_equals(cursor.fetchall(), [(0, 0)]) cursor.execute( 'SELECT transaction_id, x, y, red, green, blue, alpha FROM draws;' ) assert_equals( frozenset(cursor), {(0, x, y, *BACKGROUND) for x in range(9) for y in range(7)} ) # don't overwrite an existing file with assert_raises(IOError): image = Image.new_image(12, 13, path, background) cursor.execute('SELECT major, minor, micro, width, height FROM meta;') assert_equals(cursor.fetchall(), [(0, 1, 0, 9, 7)]) cursor.execute('SELECT id, time FROM transactions;') assert_equals(cursor.fetchall(), [(0, 0)]) cursor.execute( 'SELECT transaction_id, x, y, red, green, blue, alpha FROM draws;' ) assert_equals( frozenset(cursor), {(0, x, y, *BACKGROUND) for x in range(9) for y in range(7)} )