def build_config(args: argparse.Namespace) -> m.Image: """Turn CLI arguments into a configuration argument.""" layers = [] for noise in args.noise: name, args_, loc, filters, blend = noise.split('_') layer = m.Layer( **{ 'source': _build_source(name, args_), 'blend': _build_blend(blend), 'blend_amount': _build_blend_amount(blend), 'location': _build_location(loc), 'filters': _build_filters(filters), 'mask': None, 'mask_filters': [], }) layers.append(layer) if len(layers) == 1: layers = layers[0] return m.Image( **{ 'source': layers, 'size': [int(n) for n in args.size[::-1]], 'filename': args.filename, 'format': get_format(args.filename), 'mode': args.mode, 'framerate': args.framerate, })
def load_conf(filename: str, args: Union[None, 'argparse.Namespace'] = None) -> m.Image: """Load a configuration file.""" # Get the configuration from the file. with open(filename, 'r') as fh: conf_json = fh.read() conf = json.loads(conf_json) # Deserialize configuration based on the given version. if (conf['Version'] == '0.2.0' or conf['Version'] == '0.3.0' or conf['Version'] == '0.3.1'): # Allow CLI arguments to change or override values in the # loaded config. if args and args.filename: conf['Image']['filename'] = args.filename conf['Image']['format'] = get_format(args.filename) if args and args.size: conf['Image']['size'] = args.size[::-1] if args and args.location: _update_location(conf['Image'], args.location[::-1]) # Deserialize and return the configuration object. return m.Image(**conf['Image']) # Otherwise, the version isn't recognized, so throw an error. else: raise ValueError(f'Version {conf["Version"]} not supported.')
def test_serialize_config_to_json_file(self): """Given a configuration object, serialize that object to file as JSON. """ # Set up for expected data. format = 'JPEG' filename = 'spam.json' framerate = None imagefile = 'spam.jpeg' location = [0, 0, 0] mode = 'RGB' size = [1, 1280, 720] conf = m.Image(**{ 'source': m.Layer(**{ 'source': s.Spot(**{ 'radius': 128, 'ease': 'l', }), 'location': location, 'filters': [], 'mask': None, 'mask_filters': [], 'blend': op.difference, 'blend_amount': 1.0, }), 'size': size, 'filename': imagefile, 'format': format, 'mode': mode, 'framerate': None }) serialized_conf = { 'Version': __version__, 'Image': conf.asdict() } # Expected values. exp_json = json.dumps(serialized_conf, indent=4) exp_args = (filename, 'w') # Set up test data and state. open_mock = mock_open() with patch('pjinoise.io.open', open_mock, create=True): # Run test. io.save_conf(conf) # Extract actual values. act_json = open_mock.return_value.write.call_args[0][0] # Determine if test passed. self.assertEqual(exp_json, act_json) open_mock.assert_called_with(*exp_args)
def test_load_config_from_json_file(self): """Given the path of a configuration serialized as JSON, deserialize and return that configuration. """ # Set up for expected data. format = 'JPEG' filename = 'spam.json' framerate = None imagefile = 'spam.jpeg' location = [0, 0, 0] mode = 'RGB' size = [1, 1280, 720] # Expected data. exp_conf = m.Image(**{ 'source': m.Layer(**{ 'source': s.Spot(**{ 'radius': 128, 'ease': 'l', }), 'location': location, 'filters': [], 'mask': None, 'mask_filters': [], 'blend': op.difference, 'blend_amount': 1.0, }), 'size': size, 'filename': imagefile, 'format': format, 'mode': mode, 'framerate': None }) exp_args = (filename, 'r') # Set up test data and state. conf = { 'Version': '0.2.0', 'Image': exp_conf.asdict(), } text = json.dumps(conf) open_mock = mock_open() with patch('pjinoise.io.open', open_mock, create=True): open_mock.return_value.read.return_value = text # Run test. act_conf = io.load_conf(filename) # Determine if test passed. self.assertEqual(exp_conf, act_conf) open_mock.assert_called_with(*exp_args)
def test_load_config_cli_override_filename(self): """If a filename was passed to the CLI, override the filename in the loaded config with that filename. """ # Expected value. exp = 'eggs.tiff' exp_format = 'TIFF' # Build test data and state. filename = 'spam.conf' args = _get_cli_args_mock() type(args).filename = PropertyMock(return_value=exp) type(args).load_config = PropertyMock(return_value=filename) image = m.Image(**{ 'source': m.Layer(**{ 'source': s.Spot(**{ 'radius': 128, 'ease': 'l', }), 'location': [0, 0, 0], 'filters': [], 'mask': None, 'mask_filters': [], 'blend': op.difference, 'blend_amount': 1.0, }), 'size': [1, 1280, 720], 'filename': 'spam.jpeg', 'format': 'JPEG', 'mode': 'RGB', 'framerate': None }) conf = json.dumps({ 'Version': __version__, 'Image': image.asdict() }) open_mock = mock_open() with patch('pjinoise.io.open', open_mock, create=True): open_mock.return_value.read.return_value = conf # Run test. result = io.load_conf(filename, args) # Extract actual values from result. act = result.filename act_format = result.format # Determine if test passed. self.assertEqual(exp, act) self.assertEqual(exp_format, act_format)
assert __version__ == '0.3.1' # Basic image file configuration and other commonly used values. filename = 'work.jpg' filetype = 'JPEG' colorspace = 'RGB' size = (1, 720, 1280) # Layers. layer = m.Layer( **{ 'source': None, 'blend': None, 'filters': [], 'mask': None, 'mask_filters': [], }) # Image. conf = m.Image( **{ 'source': layer, 'size': size, 'filename': filename, 'format': filetype, 'mode': colorspace, }) # Create image. pn.main(False, conf)
def test_load_config_cli_override_location(self): """If an image location was passed to the CLI, offset the locations in the loaded config with that location. """ # Expected value. exp = [10, 10, 10] # Build test data and state. filename = 'spam.conf' location = [4, 5, 6] offset = [6, 5, 4] args = _get_cli_args_mock() type(args).location = PropertyMock(return_value=offset[::-1]) type(args).load_config = PropertyMock(return_value=filename) image = m.Image(**{ 'source': m.Layer(**{ 'source': [ m.Layer(**{ 'source': s.Spot(**{ 'radius': 128, 'ease': 'l', }), 'location': location, 'filters': [], 'mask': None, 'mask_filters': [], 'blend': op.replace, 'blend_amount': 1.0, }), m.Layer(**{ 'source': s.Spot(**{ 'radius': 128, 'ease': 'l', }), 'location': location, 'filters': [], 'mask': None, 'mask_filters': [], 'blend': op.difference, 'blend_amount': 1.0, }), ], 'location': location, 'filters': [], 'mask': None, 'mask_filters': [], 'blend': op.replace, 'blend_amount': 1.0, }), 'size': [1, 1280, 720], 'filename': 'spam.jpeg', 'format': 'JPEG', 'mode': 'RGB', 'framerate': None }) conf = json.dumps({ 'Version': __version__, 'Image': image.asdict() }) open_mock = mock_open() with patch('pjinoise.io.open', open_mock, create=True): open_mock.return_value.read.return_value = conf # Run test. result = io.load_conf(filename, args) # Extract actual values from result. def find_location(item): result = [] if 'location' in vars(item): result.append(item.location) if '_source' in vars(item): if isinstance(item._source, Sequence): for obj in item._source: result.extend(find_location(obj)) else: result.extend(find_location(item._source)) return result acts = find_location(result) for act in acts: # Determine if test passed. self.assertListEqual(exp, act)
def main(seed=None, origin=(0, 0, 0), solve=False, save_dir='', unit=20): # Make sure the version of pjinoise supports mazer. assert __version__ == '0.3.1' # Set up the size and structure of the maze. size = (1, 720, 560) units = (1, unit, unit) exit_size = (1, int(unit * .8), unit) title = seed.replace('_', ' ').upper() # The maze interior. path = m.Layer( **{ 'filters': [], 'source': s.Path(width=.4, origin=origin, unit=units, seed=seed), 'blend': op.replace, }) # The solution. sol = m.Layer( **{ 'source': s.Solid(1), 'filters': [ f.Color('s'), ], 'mask': s.SolvedPath( width=.1, origin=origin, unit=units, seed=seed), 'blend': op.replace, }) # The maze entrance. entrance = m.Layer( **{ 'source': s.Box((0, int(unit * .6), 0), exit_size, 1.0), 'blend': op.lighter, }) # The maze exit. exit = m.Layer( **{ 'source': s.Box(*[(0, int(size[Y] - unit * 1.4), size[X] - unit), exit_size, 1.0]), 'blend': op.lighter, }) if unit >= 16: ft_origin = (int(unit * .6), 1) ft_size = int(unit * .5) title = m.Layer( **{ 'source': s.Text(title, size=ft_size, origin=ft_origin, font='Helvetica', face=1), 'blend': op.lighter, }) # Put it all together and you get the maze. layers = [ path, entrance, exit, ] if unit >= 16: layers.append(title) if solve: layers.append(sol) maze = m.Layer(**{ 'source': layers, 'blend': op.replace, }) # Image output configuration. mode = 'L' name = f'{save_dir}maze_{seed}_{origin}' if unit != 20: name = name + f'_{unit}' if solve: mode = 'RGB' name = name + '_solved' name = f'{name}.png' conf = m.Image( **{ 'source': maze, 'size': size, 'filename': name, 'format': 'PNG', 'mode': mode, }) # Create image. pn.main(False, conf)
def test_count_sources(self): """Given a configuration object, count the number of sources used in the configuration. This is used to display progress in the UI. """ # Expected values. exp = 3 # Set up test data and state. src = Source() conf = m.Image( **{ 'source': [ m.Layer( **{ 'source': Source(), 'blend': op.replace, 'blend_amount': 1, 'location': [0, 0, 0], 'filters': [], 'mask': None, 'mask_filters': [] }), m.Layer( **{ 'source': [ m.Layer( **{ 'source': Source(), 'blend': op.difference, 'blend_amount': 1, 'location': [0, 0, 0], 'filters': [], 'mask': None, 'mask_filters': [] }), m.Layer( **{ 'source': Source(), 'blend': op.difference, 'blend_amount': 1, 'location': [0, 0, 0], 'filters': [], 'mask': None, 'mask_filters': [] }), ], 'blend': op.difference, 'blend_amount': 1, 'location': [0, 0, 0], 'filters': [], 'mask': None, 'mask_filters': [] }), ], 'size': src.size, 'filename': 'spam.jpg', 'format': 'JPEG', 'mode': 'RGB', 'framerate': None, }) # Run test. act = conf.count_sources() # Determine if test passed. self.assertEqual(exp, act)
def test_create_single_layer_image(self): """Given the proper CLI options, cli.build_config should return the config as a model.Image object. """ # Back up initial state. argv_bkp = sys.argv try: # Set up data for expected values. format = 'JPEG' filename = 'spam.json' framerate = None imagefile = 'spam.jpeg' location = [5, 0, 0] mode = 'L' size = [1, 1280, 720] # Expected values. exp = m.Image( **{ 'source': m.Layer( **{ 'source': s.Spot(**{ 'radius': 128, 'ease': 'l', }), 'location': location, 'filters': [ f.BoxBlur(5), f.Skew(.1), ], 'mask': None, 'mask_filters': [], 'blend': op.difference, 'blend_amount': .5, }), 'size': size, 'filename': imagefile, 'format': format, 'mode': mode, 'framerate': None }) # Set up test data and state. sys.argv = [ 'python3.8 -m pjinoise.pjinoise', '-s', str(size[-1]), str(size[-2]), str(size[-3]), '-n', 'spot_128:l_0:0:5_boxblur:5+skew:.1_difference:.5', '-o', imagefile, '-m', mode, ] # Run tests. args = cli.parse_cli_args() act = cli.build_config(args) # Determine if test passed. try: self.assertEqual(exp, act) except AssertionError as e: exp = exp.asdict() act = act.asdict() result = map_compare(exp, act) if result is not True: msg = f'Path to bad key(s): {result}' raise ValueError(msg) else: raise e # Restore initial state. finally: sys.argv = argv_bkp