def _plays_to_games(self, data): def after_players_hook(_, status): return status["name"] if "name" in status else "Unknown" plays_processor = xml.dictionary("plays", [ xml.array( xml.dictionary('play', [ xml.integer(".", attribute="id", alias="playid"), xml.dictionary('item', [ xml.string(".", attribute="name", alias="gamename"), xml.integer(".", attribute="objectid", alias="gameid") ], alias='game'), xml.array( xml.dictionary( 'players/player', [ xml.string(".", attribute="name", required=False, default="Unknown") ], required=False, alias='players', hooks=xml.Hooks(after_parse=after_players_hook))) ], required=False, alias="plays")) ]) plays = xml.parse_from_string(plays_processor, data) plays = plays["plays"] return plays
def test_processor_locations_parsing(): """Get processor location in hooks callback.""" expected_locations = [ xml.ProcessorLocation(element_path='data', array_index=None), xml.ProcessorLocation(element_path='value', array_index=None) ] def trace(state, _): assert isinstance(state, xml.ProcessorStateView) assert expected_locations == list(state.locations) hooks = xml.Hooks( after_parse=trace, before_serialize=trace, ) processor = xml.dictionary('data', [ xml.integer('value', hooks=hooks), ]) xml_string = strip_xml(""" <data> <value>1</value> </data> """) value = {'value': 1} xml.parse_from_string(processor, xml_string) xml.serialize_to_string(processor, value)
def test_primitive_transform_array_element(): """Transform a primitive value that is an array element""" xml_string = strip_xml(""" <data> <value>3</value> <value>7</value> <value>16</value> </data> """) value = [ 6, 14, 32, ] def _after_parse(_, x): return int(x * 2) def _before_serialize(_, x): return int(x / 2) hooks = xml.Hooks(after_parse=_after_parse, before_serialize=_before_serialize) processor = xml.array(xml.integer('value', hooks=hooks), nested='data') _transform_test_case_run(processor, value, xml_string)
def test_primitive_transform_attribute(): """Transform a primitive value that is an attribute""" xml_string = strip_xml(""" <data> <element value="3" /> </data> """) value = { 'value': 6, } def _after_parse(_, x): return int(x * 2) def _before_serialize(_, x): return int(x / 2) hooks = xml.Hooks(after_parse=_after_parse, before_serialize=_before_serialize) processor = xml.dictionary( 'data', [xml.integer('element', attribute='value', hooks=hooks)]) _transform_test_case_run(processor, value, xml_string)
def test_named_tuple_transform(): """Transform a named tuple value""" Person = namedtuple('Person', ['name', 'age']) xml_string = strip_xml(""" <person> <name>John</name> <age>24</age> </person> """) value = { 'name': 'John', 'age': 24, } def _after_parse(_, tuple_value): return { 'name': tuple_value.name, 'age': tuple_value.age, } def _before_serialize(_, dict_value): return Person(name=dict_value['name'], age=dict_value['age']) processor = xml.named_tuple('person', Person, [ xml.string('name'), xml.integer('age'), ], hooks=xml.Hooks( after_parse=_after_parse, before_serialize=_before_serialize)) _transform_test_case_run(processor, value, xml_string)
def test_boolean_transform(): """Transform boolean values""" xml_string = strip_xml(""" <data> <value>True</value> </data> """) value = {'value': 'It is true'} def _after_parse(_, x): if x: return 'It is true' else: return 'It is false' def _before_serialize(_, x): if x == 'It is true': return True else: return False hooks = xml.Hooks(after_parse=_after_parse, before_serialize=_before_serialize) processor = xml.dictionary('data', [xml.boolean('value', hooks=hooks)]) _transform_test_case_run(processor, value, xml_string)
def _collection_to_games(self, data): def after_status_hook(_, status): return [tag for tag, value in status.items() if value == "1"] game_in_collection_processor = xml.dictionary( "items", [ xml.array( xml.dictionary('item', [ xml.integer(".", attribute="objectid", alias="id"), xml.string("name"), xml.string("thumbnail", required=False, alias="image"), xml.string("version/item/thumbnail", required=False, alias="image_version"), xml.dictionary( "status", [ xml.string(".", attribute="fortrade"), xml.string(".", attribute="own"), xml.string(".", attribute="preordered"), xml.string(".", attribute="prevowned"), xml.string(".", attribute="want"), xml.string(".", attribute="wanttobuy"), xml.string(".", attribute="wanttoplay"), xml.string(".", attribute="wishlist"), ], alias='tags', hooks=xml.Hooks(after_parse=after_status_hook)), xml.integer("numplays"), ], required=False, alias="items"), ) ]) collection = xml.parse_from_string(game_in_collection_processor, data) collection = collection["items"] return collection
def _hooks(self): def validate(state, _): state.raise_error(_ValidationError, 'Invalid value') return xml.Hooks( after_parse=validate, before_serialize=validate, )
def _dict_processor(self): hooks = xml.Hooks(after_parse=self._after_parse, before_serialize=self._before_serialize) return xml.dictionary('data', [ xml.integer('a'), xml.integer('b'), xml.integer('c'), ], hooks=hooks)
def _user_object_processor(self): hooks = xml.Hooks( after_parse=self._after_parse, before_serialize=self._before_serialize, ) return xml.user_object('person', self._Person, [ xml.string('name'), xml.integer('age'), ], hooks=hooks)
def _processor(self): def validate(state, value): if value < 0: state.raise_error(_ValidationError) return value hooks = xml.Hooks(after_parse=validate, before_serialize=validate) processor = xml.dictionary('data', [xml.integer('value', hooks=hooks)]) return processor
def _processor(self): def validate(state, value): if len(value) != len(set(value)): state.raise_error(_ValidationError) return value hooks = xml.Hooks( after_parse=validate, before_serialize=validate, ) processor = xml.array(xml.integer('value'), hooks=hooks, nested='data') return processor
def test_primitive_missing_hooks(): """Process primitive value with missing hooks.""" hooks = xml.Hooks(after_parse=None, before_serialize=None) processor = xml.dictionary('data', [xml.integer('value', hooks=hooks)]) xml_string = strip_xml(""" <data> <value>1</value> </data> """) value = {'value': 1} _assert_valid(processor, value, xml_string)
def _processor(self): def validate(state, value): if value.name == 'Bob' and value.age == 24: state.raise_error(_ValidationError) return value hooks = xml.Hooks( after_parse=validate, before_serialize=validate, ) processor = xml.user_object( 'user', _UserClass, [xml.string('name'), xml.integer('age')], hooks=hooks) return processor
def _processor(self): def validate(state, value): if value['a'] == 5 and value['b'] == 6: state.raise_error(_ValidationError) return value hooks = xml.Hooks( after_parse=validate, before_serialize=validate, ) processor = xml.dictionary('data', [ xml.integer('a'), xml.integer('b'), ], hooks=hooks) return processor
def test_aggregate_missing_hooks(): """Process with missing aggregate hooks.""" hooks = xml.Hooks(after_parse=None, before_serialize=None) processor = xml.dictionary( 'data', [xml.integer('a'), xml.integer('b')], hooks=hooks) xml_string = strip_xml(""" <data> <a>1</a> <b>2</b> </data> """) value = { 'a': 1, 'b': 2, } _assert_valid(processor, value, xml_string)
def test_integer_transform(): """Transform integer values""" xml_string = strip_xml(""" <data> <value>3</value> </data> """) value = {'value': 6} def _after_parse(_, x): return int(x * 2) def _before_serialize(_, x): return int(x / 2) hooks = xml.Hooks(after_parse=_after_parse, before_serialize=_before_serialize) processor = xml.dictionary('data', [xml.integer('value', hooks=hooks)]) _transform_test_case_run(processor, value, xml_string)
def test_string_transform(): """Transform string values""" xml_string = strip_xml(""" <data> <value>hello</value> </data> """) value = {'value': 'HELLO'} def _after_parse(_, x): return x.upper() def _before_serialize(_, x): return x.lower() hooks = xml.Hooks(after_parse=_after_parse, before_serialize=_before_serialize) processor = xml.dictionary('data', [xml.string('value', hooks=hooks)]) _transform_test_case_run(processor, value, xml_string)
def test_floating_point_transform(): """Transform floating point values""" xml_string = strip_xml(""" <data> <value>13.1</value> </data> """) value = {'value': 26.2} def _after_parse(_, x): return x * 2.0 def _before_serialize(_, x): return x / 2.0 hooks = xml.Hooks(after_parse=_after_parse, before_serialize=_before_serialize) processor = xml.dictionary('data', [xml.floating_point('value', hooks=hooks)]) _transform_test_case_run(processor, value, xml_string)
def _hooks(self): return xml.Hooks(after_parse=self._after_parse, before_serialize=self._before_serialize)
def _games_list_to_games(self, data): def numplayers_to_result(_, results): result = { result["value"].lower().replace(" ", "_"): int(result["numvotes"]) for result in results } if not result: result = {'best': 0, 'recommended': 0, 'not_recommended': 0} is_recommended = result['best'] + result['recommended'] > result[ 'not_recommended'] if not is_recommended: return "not_recommended" is_best = result['best'] > 10 and result['best'] > result[ 'recommended'] if is_best: return "best" return "recommended" def suggested_numplayers(_, numplayers): # Remove not_recommended player counts numplayers = [ players for players in numplayers if players["result"] != "not_recommended" ] # If there's only one player count, that's the best one if len(numplayers) == 1: numplayers[0]["result"] = "best" # Just return the numbers return [(players["numplayers"], players["result"]) for players in numplayers] def log_item(_, item): logger.debug("Successfully parsed: {} (id: {}).".format( item["name"], item["id"])) return item game_processor = xml.dictionary("items", [ xml.array( xml.dictionary( "item", [ xml.integer(".", attribute="id"), xml.string(".", attribute="type"), xml.string("name[@type='primary']", attribute="value", alias="name"), xml.string("description"), xml.array( xml.string("link[@type='boardgamecategory']", attribute="value", required=False), alias="categories", ), xml.array( xml.string("link[@type='boardgamemechanic']", attribute="value", required=False), alias="mechanics", ), xml.array( xml.dictionary( "link[@type='boardgameexpansion']", [ xml.integer(".", attribute="id"), xml.boolean(".", attribute="inbound", required=False), ], required=False), alias="expansions", ), xml.array( xml.dictionary( "poll[@name='suggested_numplayers']/results", [ xml.string(".", attribute="numplayers"), xml.array(xml.dictionary("result", [ xml.string(".", attribute="value"), xml.integer(".", attribute="numvotes"), ], required=False), hooks=xml.Hooks( after_parse= numplayers_to_result)) ]), alias="suggested_numplayers", hooks=xml.Hooks(after_parse=suggested_numplayers), ), xml.string("statistics/ratings/averageweight", attribute="value", alias="weight"), xml.string( "statistics/ratings/ranks/rank[@friendlyname='Board Game Rank']", attribute="value", required=False, alias="rank"), xml.string("statistics/ratings/usersrated", attribute="value", alias="usersrated"), xml.string("statistics/ratings/owned", attribute="value", alias="numowned"), xml.string("statistics/ratings/bayesaverage", attribute="value", alias="rating"), xml.string("playingtime", attribute="value", alias="playing_time"), ], required=False, alias="items", hooks=xml.Hooks(after_parse=log_item), )) ]) games = xml.parse_from_string(game_processor, data) games = games["items"] return games
def __init__(self, group_name="Imported", group_desc=""): self.group_name = group_name self.group_desc = group_desc self.scenario_group = None def dict_to_scenario(state, value): session = Session() value['id'] = Scenario.scenario_hash(value['acq_time'], value['scen_materials'], value['scen_bckg_materials'], value['influences']) q = session.query(Scenario).filter_by(id=value['id']).first() if q: if self.scenario_group: self.scenario_group.scenarios.append(q) return q else: scenario = Scenario(value['acq_time'], value['replication'], value['scen_materials'], value['scen_bckg_materials'], value['influences'], [self.scenario_group]) return scenario def scenario_to_dict(state, value): return value.__dict__ def material_validate(state, value): session = Session() q = session.query(Material).filter_by(name=value.name).first() if q: return q else: session.add(value) return value def trace(state, value): print('Got {} at {}'.format(value, state)) print(value.__dict__) return value def influence_validate(state, value): session = Session() q = session.query(Influence).filter_by(name=value.name).first() if q: return q else: session.add(value) return value self.scenario_hooks = xml.Hooks( after_parse=dict_to_scenario, before_serialize=scenario_to_dict, ) self.material_hooks = xml.Hooks( after_parse=material_validate, before_serialize=lambda _, x: x, ) self.influence_hooks = xml.Hooks( after_parse=influence_validate, before_serialize=lambda _, x: x, ) self.material_processor = xml.user_object( 'Material', Material, [xml.string('BaseMaterialName', alias='name')], alias='material', hooks=self.material_hooks) self.sourcematerials_processor = xml.user_object( 'ScenarioMaterial', ScenarioMaterial, [ self.material_processor, xml.string('fd_mode'), xml.floating_point('dose'), ], alias='scen_materials') self.bkgmaterial_processor = xml.user_object( 'ScenarioBackgroundMaterial', ScenarioBackgroundMaterial, [ self.material_processor, xml.string('fd_mode'), xml.floating_point('dose'), ], alias='scen_bckg_materials', required=False) self.influence_processor = xml.user_object( 'Influence', Influence, [xml.string('InfluenceName', alias='name')], alias='influences', hooks=self.influence_hooks, required=False) self.scenario_processor = xml.dictionary('Scenario', [ xml.string("id", required=False), xml.floating_point("acq_time"), xml.integer("replication"), xml.array(self.sourcematerials_processor), xml.array(self.bkgmaterial_processor), xml.array(self.influence_processor) ], hooks=self.scenario_hooks) self.scenarios_processor = xml.dictionary( 'Scenarios', [xml.array(self.scenario_processor)])