def test_assign_to_state_territory_color_were_preserved(): state1 = State.from_dict({ 'validity_start': '1918-01-01T00:00:00Z', 'validity_end': '1919-01-01T00:00:00Z', 'representations': [ { 'name': 'test ' + datetime.now().isoformat() + str(randint(1, 1e6)), 'validity_start': '1918-01-01T00:00:00Z', 'validity_end': '1919-01-01T00:00:00Z', 'color' : '#FF0000' # red } ] }) state2 = State.from_dict({ 'validity_start': '1918-02-01T00:00:00Z', 'validity_end': '1918-12-01T00:00:00Z', 'representations': [ { 'name': 'test ' + datetime.now().isoformat() + str(randint(1, 1e6)), 'validity_start': '1918-02-01T00:00:00Z', 'validity_end': '1918-12-01T00:00:00Z', 'color' : '#0000FF' #blue } ] }) # territory exists in jan and dec 1918 and state2 does not territory = get_example_territory() territory.color = None # will be red at first with get_api_with_state_and_territory((state1, territory), (state2, None)) as [(_, territory_with_id), (state2_w_id, _)]: with get_cursor() as cursor : created_ids = TerritoryTag._assign_to_state(cursor, territory_with_id, state2_w_id.state_id) # The reassigned territory was set to red (so the assign did not change the color) assert TerritoryTag.get(territory_with_id.territory_id).color=='#FF0000' assert all(TerritoryTag.get(created_id).color == None for created_id in created_ids)
def test_assign_to_state_with_unmatching_period(): state1 = State.from_dict({ 'validity_start': '1918-01-01T00:00:00Z', 'validity_end': '1919-01-01T00:00:00Z', 'representations': [ { 'name': 'test ' + datetime.now().isoformat() + str(randint(1, 1e6)), 'validity_start': '1918-01-01T00:00:00Z', 'validity_end': '1919-01-01T00:00:00Z', 'color' : '#000000' } ] }) state2 = State.from_dict({ 'validity_start': '1919-01-01T00:00:00Z', 'validity_end': '1920-01-01T00:00:00Z', 'representations': [ { 'name': 'test ' + datetime.now().isoformat() + str(randint(1, 1e6)), 'validity_start': '1919-01-01T00:00:00Z', 'validity_end': '1920-01-01T00:00:00Z', 'color' : '#000000' } ] }) territory = get_example_territory() # state2 and territory have no period in common with get_api_with_state_and_territory((state1, territory), (state2, None)) as [(_, territory_with_id), (state2_w_id, _)]: with pytest.raises(BadRequest): with get_cursor() as cursor : TerritoryTag._assign_to_state(cursor, territory_with_id, state2_w_id.state_id)
def test_assign_to_state_territory_starts_before_new_state(): state1 = State.from_dict({ 'validity_start': '1918-01-01T00:00:00Z', 'validity_end': '1919-01-01T00:00:00Z', 'representations': [ { 'name': 'test ' + datetime.now().isoformat() + str(randint(1, 1e6)), 'validity_start': '1918-01-01T00:00:00Z', 'validity_end': '1919-01-01T00:00:00Z', 'color' : '#000000' } ] }) state2 = State.from_dict({ 'validity_start': '1918-02-01T00:00:00Z', 'validity_end': '1919-01-01T00:00:00Z', 'representations': [ { 'name': 'test ' + datetime.now().isoformat() + str(randint(1, 1e6)), 'validity_start': '1918-02-01T00:00:00Z', 'validity_end': '1919-01-01T00:00:00Z', 'color' : '#000000' } ] }) # territory exists in jan 1918 and state2 does not territory = get_example_territory() with get_api_with_state_and_territory((state1, territory), (state2, None)) as [(state1_with_id, territory_with_id), (state2_w_id, _)]: territory_count = TerritoryTag.count() with get_cursor() as cursor : created_ids = TerritoryTag._assign_to_state(cursor, territory_with_id, state2_w_id.state_id) # a territory was created for jan 1918 and it still belongs to state1 assert TerritoryTag.count() == territory_count + 1 assert len(created_ids) == 1 assert TerritoryTag.get(created_ids[0]).state_id == state1_with_id.state_id
def post(state): assert isinstance(state, State) with get_cursor() as cursor: conflicts = StateTag.__get_name_conflicts(state, cursor) if len(conflicts): report = ', by '.join([ f'{c.state_id} from {c.validity_start.year} to {c.validity_end.year}' for c in conflicts ]) raise Conflict(f'names are already taken by {report} ') return StateCRUD.add(cursor, state)
def get(bbox, date, precision_level): assert isinstance(bbox, BoundingBox) assert isinstance(date, datetime) assert date.tzinfo is None with get_cursor() as cursor: territories = TerritoryCRUD.get_within_bbox_at_time(cursor, bbox, date, precision_level) state_ids = frozenset(t.state_id for t in territories) states = StateCRUD.get_many(cursor, state_ids) return { 'states' : states, 'territories' : territories }
def put(territory): assert isinstance(territory, Territory) with get_cursor() as cursor: original_territory = TerritoryCRUD.get(cursor, territory.territory_id) if original_territory.state_id != territory.state_id: TerritoryTag._assign_to_state(cursor, original_territory, territory.state_id) TerritoryCRUD.edit( cursor, territory, change_color=original_territory.color != territory.color, change_name=original_territory.name != territory.name) return territory.territory_id
def delete(territory_id): with get_cursor() as cursor: territory = TerritoryCRUD.get(cursor, territory_id) state = StateCRUD.get(cursor, territory.state_id) if len(state.representations ) == 1 and not state.representations[0].name: its_territories = TerritoryCRUD.get_by_state( cursor, territory.state_id) if len(its_territories) == 1: StateCRUD.delete(cursor, state.state_id) return { "deleted_state": state.state_id, "deleted_territory": territory_id } TerritoryCRUD.delete(cursor, territory_id) return {"deleted_state": None, "deleted_territory": territory_id}
def get_by_state(state_id, date, pixel_width): assert isinstance(state_id, int) assert isinstance(date, datetime) assert isinstance(pixel_width, float) with get_cursor() as cursor: bbox = StateCRUD.get_bbox(cursor, state_id, date).enlarge_to_aspect_ratio(16/9) precision = precision_from_bbox_and_px_width(bbox, pixel_width) territories = TerritoryCRUD.get_within_bbox_at_time(cursor, bbox, date, precision) state_ids = frozenset(t.state_id for t in territories) states = StateCRUD.get_many(cursor, state_ids) return { 'states' : states, 'territories' : territories, 'bounding_box' : bbox, 'date' : date }
def put(state, absorb_conflicts): assert isinstance(state, State) with get_cursor() as cursor: conflicts = StateTag.__get_name_conflicts(state, cursor) if len(conflicts): if absorb_conflicts: start_conflicts = min(s.validity_start for s in conflicts) end_conflicts = max(s.validity_end for s in conflicts) StateCRUD.edit(cursor, state, change_validity_start=True, change_validity_end=True) if start_conflicts < state.validity_start or end_conflicts > state.validity_end: raise Conflict( f'Cannot absorb conflicts : they go from {start_conflicts.isoformat()} to {end_conflicts.isoformat()}' ) for c in conflicts: StateTag.__merge_with_cursor(cursor, c.state_id, state.state_id) else: report = ', by '.join([ f'{c.state_id} from {c.validity_start.year} to {c.validity_end.year}' for c in conflicts ]) raise Conflict(f'names are already taken by {report} ') its_territories = TerritoryCRUD.get_by_state( cursor, state.state_id) conflicting_territories = [ t for t in its_territories if t.validity_start < state.validity_start or t.validity_end > state.validity_end ] if len(conflicting_territories): raise Conflict( f'Cannot update : territories {[t.territory_id for t in conflicting_territories]} have range from {min(t.validity_start for t in conflicting_territories)} to {max(t.validity_end for t in conflicting_territories)}' ) StateCRUD.edit(cursor, state, change_representations=True, change_validity_start=True, change_validity_end=True) return state.state_id
def post(territory): assert isinstance(territory, Territory) with get_cursor() as cursor: state = StateCRUD.get(cursor, territory.state_id) if territory.validity_start < state.validity_start or territory.validity_end > state.validity_end: raise Conflict( f"Cannot add territory ({territory.validity_start} , {territory.validity_end}) to state ({state.validity_start}, {state.validity_end}) : period overflows" ) potentially_intersecting = TerritoryCRUD.get_within_bbox_in_period( cursor, territory.bounding_box, territory.validity_start, territory.validity_end, 0) t_conflict_ids = [ other.territory_id for other in potentially_intersecting if territories_conflict(territory, other) ] if len(t_conflict_ids): raise Conflict( f"Cannot add the territory : it conflicts with territories {t_conflict_ids}" ) compressed_territory = compress_territory(territory) return TerritoryCRUD.add(cursor, compressed_territory)
def get_evolution_by_state(state_id, pixel_width): assert isinstance(state_id, int) assert isinstance(pixel_width, float) with get_cursor() as cursor: res = [] for date in _determine_dates_to_show(cursor, state_id): try : bbox = StateCRUD.get_bbox(cursor, state_id, date).enlarge_to_aspect_ratio(16/9) logging.error('setting last bbox') last_bbox = bbox except NotFound: bbox = last_bbox precision = precision_from_bbox_and_px_width(bbox, pixel_width) territories = TerritoryCRUD.get_within_bbox_at_time(cursor, bbox, date, precision) state_ids = frozenset(t.state_id for t in territories) states = StateCRUD.get_many(cursor, state_ids) res.append({ 'states' : states, 'territories' : territories, 'bounding_box' : bbox, 'date' : date, 'lands': LandCRUD.get_lands(cursor, bbox, precision) }) return res
def count(): with get_cursor() as cursor: return TerritoryCRUD.count(cursor)
def get(territory_id): with get_cursor() as cursor: territory = TerritoryCRUD.get(cursor, territory_id) assert territory.representations[0].precision_in_km == 0 return territory
def merge(to_merge_id, sovereign_state_id): with get_cursor() as cursor: StateTag.__merge_with_cursor(cursor, to_merge_id, sovereign_state_id) return sovereign_state_id
def search(pattern): assert isinstance(pattern, str) with get_cursor() as cursor: return StateCRUD.search(cursor, pattern)
def delete(state_id): assert isinstance(state_id, int) with get_cursor() as cursor: return StateCRUD.delete(cursor, state_id)