def create_example(path: str, from_model='sioux_falls') -> Project: """Copies an example model to a new project project and returns the project handle Args: *path* (:obj:`str`): Path where to create a new model. must be a non-existing folder/directory. *from_model path* (:obj:`str`, `Optional`): Example to create from *sioux_falls* or *nauru*. Defaults to *sioux_falls* Returns: *project* (:obj:`Project`): Aequilibrae Project handle (open) """ if os.path.isdir(path): raise FileExistsError('Cannot overwrite an existing directory') if not os.path.isfile( join(dirname(__file__), f'../reference_files/{from_model}.zip')): raise FileExistsError('Example not found') os.mkdir(path) zipfile.ZipFile( join(dirname(__file__), f'../reference_files/{from_model}.zip')).extractall(path) proj = Project() proj.open(path) return proj
class TestModes(TestCase): def setUp(self) -> None: os.environ['PATH'] = os.path.join( tempfile.gettempdir(), 'temp_data') + ';' + os.environ['PATH'] self.temp_proj_folder = os.path.join(tempfile.gettempdir(), uuid.uuid4().hex) copytree(siouxfalls_project, self.temp_proj_folder) self.proj = Project() self.proj.open(self.temp_proj_folder) self.curr = self.proj.conn.cursor() def tearDown(self) -> None: self.proj.close() def test_add(self): new_mode = Mode('F') name = [ random.choice(string.ascii_letters + '_') for x in range(random.randint(1, 20)) ] name = ''.join(name) new_mode.mode_name = name self.proj.network.modes.add(new_mode) self.curr.execute('select mode_name from modes where mode_id="F"') self.assertEqual(self.curr.fetchone()[0], name, 'Could not save the mode properly to the database') def test_drop(self): self.proj.network.modes.delete('b') with self.assertRaises(IntegrityError): self.proj.network.modes.delete('c') def test_get(self): c = self.proj.network.modes.get('c') self.assertEqual('All motorized vehicles', c.description) del c with self.assertRaises(ValueError): _ = self.proj.network.modes.get('f') def test_new(self): modes = self.proj.network.modes self.assertIsInstance(modes.new('h'), Mode, 'Returned wrong type') m = list(modes.all_modes().keys())[0] with self.assertRaises(ValueError): modes.new(m) def test_fields(self): fields = self.proj.network.modes.fields() fields.all_fields() self.assertEqual(fields._table, 'modes', 'Returned wrong table handler')
class TestZone(TestCase): def setUp(self) -> None: self.temp_proj_folder = join(gettempdir(), uuid4().hex) copytree(siouxfalls_project, self.temp_proj_folder) self.proj = Project() self.proj.open(self.temp_proj_folder) def tearDown(self) -> None: self.proj.close() try: rmtree(self.temp_proj_folder) except Exception as e: warn(f'Error: {e.args}') def test_delete(self): zones = self.proj.zoning zone_downtown = zones.get(3) zone_downtown.delete() with self.assertRaises(ValueError): _ = zones.get(3) def test_save(self): zones = self.proj.zoning zn = zones.get(2) area = randint(0, 9999999999) zn.area = area zn.save() curr = self.proj.conn.cursor() curr.execute('Select area from Zones where zone_id=2') self.assertEqual(curr.fetchone()[0], area, "Zone didn't save area properly") geo = Point(0, 0).buffer(1) zn.geometry = geo zn.save() curr = self.proj.conn.cursor() curr.execute('Select asBinary(geometry) from Zones where zone_id=2') wkb = curr.fetchone()[0] self.assertEqual(shapely.wkb.loads(wkb), MultiPolygon([geo]), "Zone didn't save geometry properly") zn2 = zones.get(1) geo = MultiPolygon([Point(0, 0).buffer(1)]) zn2.geometry = geo zn2.save() curr = self.proj.conn.cursor() curr.execute('Select asBinary(geometry) from Zones where zone_id=1') wkb = curr.fetchone()[0] self.assertEqual(shapely.wkb.loads(wkb), geo, "Zone didn't save geometry properly") def __change_project(self): self.proj.close() self.proj = Project() self.proj = create_example(join(gettempdir(), uuid4().hex), 'nauru') zones = 5 network = self.proj.network nodes = network.nodes geo = network.convex_hull() zone_area = geo.area / zones zone_side = sqrt(2 * sqrt(3) * zone_area / 9) extent = network.extent() curr = self.proj.conn.cursor() b = extent.bounds curr.execute( 'select st_asbinary(HexagonalGrid(GeomFromWKB(?), ?, 0, GeomFromWKB(?)))', [extent.wkb, zone_side, Point(b[2], b[3]).wkb]) grid = curr.fetchone()[0] grid = shapely.wkb.loads(grid) grid = [p for p in grid if p.intersects(geo)] zoning = self.proj.zoning for i, zone_geo in enumerate(grid): zone = zoning.new(i + 1) zone.geometry = zone_geo zone.save() node = nodes.get(i + 1) node.renumber(i + 10001) def test_add_centroid(self): self.__change_project() zones = self.proj.zoning nodes = self.proj.network.nodes network = self.proj.network zone1 = zones.get(1) tot = network.count_centroids() zone1.add_centroid(None) self.assertEqual(tot + 1, network.count_centroids(), "Added less than it should've") tot = network.count_centroids() zone1.add_centroid(None) zone1.add_centroid(Point(0, 0)) self.assertEqual(tot, network.count_centroids(), "Added more than should've") node1 = nodes.get(1) self.assertEqual(node1.geometry, zone1.geometry.centroid) zone2 = zones.get(2) zone2.add_centroid(Point(0, 0)) node2 = nodes.get(2) self.assertEqual(node2.geometry, Point(0, 0)) def test_connect_mode(self): self.__change_project() curr = self.proj.conn.cursor() zones = self.proj.zoning zone1 = zones.get(1) zone1.add_centroid(None) zone1.connect_mode('c') curr.execute('Select count(*) from links where a_node=?', [1]) self.assertIsNot(0, curr.fetchone()[0], 'failed to add connectors') zone1.connect_mode('t') curr.execute( '''Select count(*) from links where a_node=? and instr(modes,'t')>0''', [1]) self.assertIsNot(0, curr.fetchone()[0], 'failed to add connectors for mode t') # Cannot connect a centroid that does not exist with self.assertRaises(ValueError): zone2 = zones.get(2) zone2.connect_mode('c') def test_disconnect_mode(self): self.__change_project() curr = self.proj.conn.cursor() zones = self.proj.zoning zone1 = zones.get(1) zone1.add_centroid(None) zone1.connect_mode('c') zone1.connect_mode('w') curr.execute('''select COUNT(*) from links where a_node=1''') tot = curr.fetchone()[0] curr.execute( '''Update links set modes = modes || 'w' where instr(modes,'w')=0''' ) self.proj.conn.commit() zone1.disconnect_mode('w') curr.execute('''select COUNT(*) from links where a_node=1''') self.assertIsNot(tot, curr.fetchone()[0], 'failed to delete links') curr.execute( '''Select count(*) from links where a_node=1 and instr(modes,'w')>0''' ) self.assertEqual(curr.fetchone()[0], 0, 'Failed to remove mode from all connectors')
class TestBlockingTrianglePathResults(TestCase): def setUp(self) -> None: os.environ['PATH'] = os.path.join( gettempdir(), 'temp_data') + ';' + os.environ['PATH'] self.proj_dir = os.path.join(gettempdir(), uuid.uuid4().hex) copytree(triangle_graph_blocking, self.proj_dir) self.project = Project() self.project.open(self.proj_dir) self.project.network.build_graphs(modes=["c"]) self.g = self.project.network.graphs["c"] # type: Graph self.g.set_graph("free_flow_time") self.g.set_blocked_centroid_flows(True) self.r = PathResults() self.r.prepare(self.g) def tearDown(self) -> None: self.project.close() del self.r def test_compute_paths(self): self.r.compute_path(1, 2) self.assertEqual(list(self.r.path_nodes), [1, 3, 2]) self.assertEqual(list(self.r.path), [1, 2]) self.r.compute_path(2, 1) self.assertEqual(list(self.r.path_nodes), [2, 1]) self.assertEqual(list(self.r.path), [3]) self.r.compute_path(3, 1) self.assertEqual(list(self.r.path_nodes), [3, 2, 1]) self.assertEqual(list(self.r.path), [2, 3]) self.r.compute_path(3, 2) self.assertEqual(list(self.r.path_nodes), [3, 2]) self.assertEqual(list(self.r.path), [2]) self.r.compute_path(1, 3) self.assertEqual(list(self.r.path_nodes), [1, 3]) self.assertEqual(list(self.r.path), [1]) self.r.compute_path(2, 3) self.assertEqual(list(self.r.path_nodes), [2, 1, 3]) self.assertEqual(list(self.r.path), [3, 1]) def test_compute_blocking_paths(self): self.r.compute_path(4, 5) self.assertEqual(list(self.r.path_nodes), [4, 1, 3, 2, 5]) self.assertEqual(list(self.r.path), [4, 1, 2, 5]) self.r.compute_path(5, 4) self.assertEqual(list(self.r.path_nodes), [5, 2, 1, 4]) self.assertEqual(list(self.r.path), [5, 3, 4]) self.r.compute_path(6, 4) self.assertEqual(list(self.r.path_nodes), [6, 3, 2, 1, 4]) self.assertEqual(list(self.r.path), [6, 2, 3, 4]) self.r.compute_path(6, 5) self.assertEqual(list(self.r.path_nodes), [6, 3, 2, 5]) self.assertEqual(list(self.r.path), [6, 2, 5]) self.r.compute_path(4, 6) self.assertEqual(list(self.r.path_nodes), [4, 1, 3, 6]) self.assertEqual(list(self.r.path), [4, 1, 6]) self.r.compute_path(5, 6) self.assertEqual(list(self.r.path_nodes), [5, 2, 1, 3, 6]) self.assertEqual(list(self.r.path), [5, 3, 1, 6]) def test_update_trace(self): self.r.compute_path(1, 2) self.assertEqual(list(self.r.path_nodes), [1, 3, 2]) self.assertEqual(list(self.r.path), [1, 2]) self.r.update_trace(3) self.assertEqual(list(self.r.path_nodes), [1, 3]) self.assertEqual(list(self.r.path), [1]) def test_update_blocking_trace(self): self.r.compute_path(4, 5) self.assertEqual(list(self.r.path_nodes), [4, 1, 3, 2, 5]) self.assertEqual(list(self.r.path), [4, 1, 2, 5]) self.r.update_trace(6) self.assertEqual(list(self.r.path_nodes), [4, 1, 3, 6]) self.assertEqual(list(self.r.path), [4, 1, 6])
class TestFieldEditor(TestCase): my_tables = ["link_types", "links", "modes", "nodes"] def setUp(self) -> None: os.environ["PATH"] = os.path.join( gettempdir(), "temp_data") + ";" + os.environ["PATH"] self.temp_proj_folder = join(gettempdir(), uuid4().hex) copytree(siouxfalls_project, self.temp_proj_folder) self.proj = Project() self.proj.open(self.temp_proj_folder) def tearDown(self) -> None: self.proj.close() def randomword(self, length): val = "".join(choice(ALLOWED_CHARACTERS) for i in range(length)) if val[0] == "_" or val[-1] == "_": return self.randomword(length) return val def test_building(self): for tab in ["modes", "links", "nodes", "link_types"]: table = FieldEditor(tab) qry = f'select count(*) from "attributes_documentation" where name_table="{tab}"' q = self.proj.conn.execute(qry).fetchone()[0] self.assertEqual( q, len(table._original_values), "Meta table populated with the wrong number of elements") def test_add(self): for tab in self.my_tables: table = FieldEditor(tab) qry = f'select count(*) from "attributes_documentation" where name_table="{tab}"' q = self.proj.conn.execute(qry).fetchone()[0] one = choice(list(table._original_values.keys())) self.proj.conn.commit() with self.assertRaises(ValueError) as em: table.add(one, self.randomword(30)) self.assertEqual("attribute_name already exists", str(em.exception), "failed in the wrong place") with self.assertRaises(ValueError) as em: table.add(f"{self.randomword(5)} {5}", self.randomword(30)) self.assertEqual( 'attribute_name can only contain letters, numbers and "_"', str(em.exception), "failed in the wrong place", ) with self.assertRaises(ValueError): table.add( choice("0123456789") + self.randomword(20), self.randomword(30)) new_one = self.randomword(20) while new_one[0] in "0123456789": new_one = self.randomword(20) table.add(new_one, self.randomword(30)) self.proj.conn.commit() curr = self.proj.conn.cursor() curr.execute( f'select count(*) from "attributes_documentation" where name_table="{tab}"' ) q2 = curr.fetchone()[0] self.assertEqual(q + 1, q2, "Adding element did not work") # If query fails, we failed to add new field to the database curr.execute( f'select "{new_one}" from "attributes_documentation" where name_table="{tab}"' ) if "alpha" in table._original_values.keys(): self.assertEqual(table.alpha, "Available for user convenience", "not being able to retrieve values") self.proj.conn.commit() del curr def test_check_completeness(self): for table in self.my_tables: curr = self.proj.conn.cursor() # We add a bogus record to the attribute list val = self.randomword(30).lower() qry = 'INSERT INTO "attributes_documentation" VALUES (?,?," ");' curr.execute(qry, (table, val)) self.proj.conn.commit() curr.execute( f'Select name_table from "attributes_documentation" where attribute="{val}"' ) self.assertEqual(curr.fetchone()[0], table, "Failed to insert bogus value") # Then we add a new field to the table val2 = self.randomword(10) curr.execute(f'Alter table "{table}" add column "{val2}" NUMERIC;') curr.execute(f"pragma table_info({table})") fields = [x[1] for x in curr.fetchall() if x[1] == val2] self.assertEqual([val2], fields, "failed to add a new field") table = FieldEditor(table) self.proj.conn.commit() curr = self.proj.conn.cursor() curr.execute( f'Select count(*) from "attributes_documentation" where attribute="{val}"' ) self.assertEqual(curr.fetchone()[0], 0, f"clean the table on loading failed {val}") curr.execute( f'Select count(*) from "attributes_documentation" where attribute="{val2}"' ) self.assertEqual(curr.fetchone()[0], 1, "clean the table on loading failed") print(table._original_values[val2]) self.proj.conn.commit() del curr def test_save(self): for tab in ["modes", "links", "nodes", "link_types"]: table = FieldEditor(tab) random_val = self.randomword(30) if "alpha" in table._original_values.keys(): table.alpha = random_val table.save() table2 = FieldEditor(tab) self.assertEqual(table2.alpha, random_val, "Did not save values properly") if "link_id" in table._original_values.keys(): table.link_id = random_val table.save() table2 = FieldEditor(tab) self.assertEqual(table2.link_id, random_val, "Did not save values properly") if "node_id" in table._original_values.keys(): table.node_id = random_val table.save() table2 = FieldEditor(tab) self.assertEqual(table2.node_id, random_val, "Did not save values properly") self.proj.conn.commit()
class TestAbout(TestCase): def setUp(self) -> None: os.environ['PATH'] = os.path.join(tempfile.gettempdir(), 'temp_data') + ';' + os.environ['PATH'] self.temp_proj_folder = os.path.join(tempfile.gettempdir(), uuid.uuid4().hex) copytree(siouxfalls_project, self.temp_proj_folder) self.proj = Project() self.proj.open(self.temp_proj_folder) self.curr = self.proj.conn.cursor() def tearDown(self) -> None: self.proj.close() def test_create_and_list(self): self.proj.about.create() with self.assertWarns(expected_warning=Warning): self.proj.about.create() list = self.proj.about.list_fields() expected = ['model_name', 'region', 'description', 'author', 'license', 'scenario_name', 'year', 'scenario_description', 'model_version', 'project_id', 'aequilibrae_version', 'projection'] failed = set(list).symmetric_difference(set(expected)) if failed: self.fail('About table does not have all expected fields') # idea from https://stackoverflow.com/a/2030081/1480643 def randomword(self, length): letters = string.ascii_lowercase + '_' return ''.join(random.choice(letters) for i in range(length)) def test_add_info_field(self): self.proj.about.create() all_added = set() for t in range(30): k = self.randomword(random.randint(1, 15)) if k not in all_added: all_added.add(k) self.proj.about.add_info_field(k) curr = self.proj.conn.cursor() curr.execute("select infoname from 'about'") charac = [x[0] for x in curr.fetchall()] for k in all_added: if k not in charac: self.fail(f'Failed to add {k}') # Should fail when trying to add a repeated guy with self.assertRaises(sqlite3.IntegrityError): self.proj.about.add_info_field('description') # Should fail when trying to add a repeated guy with self.assertRaises(ValueError): self.proj.about.add_info_field('descr1ption') def test_write_back(self): self.proj.about.create() self.proj.about.add_info_field('good_info_field_perhaps') val = self.randomword(random.randint(1, 15)) self.proj.about.good_info_field_perhaps = val val2 = self.randomword(random.randint(30, 250)) self.proj.about.description = val2 self.proj.about.write_back() self.proj.close() del self.proj self.proj = Project() self.proj.open(self.temp_proj_folder) self.assertEqual(val, self.proj.about.good_info_field_perhaps, 'failed to save data to about table') self.assertEqual(val2, self.proj.about.description, 'failed to save data to about table')
def test_fit(self): proj = Project() proj.open(self.proj_dir) mats = proj.matrices mats.update_database() seed = mats.get_matrix('SiouxFalls_omx') seed.computational_view('matrix') # row vector args = { "entries": seed.zones, "field_names": ["rows"], "data_types": [np.float64], "memory_mode": True } row_vector = AequilibraeData() row_vector.create_empty(**args) row_vector.rows[:] = np.random.rand(seed.zones)[:] * 1000 row_vector.index[:] = seed.index[:] # column vector args["field_names"] = ["columns"] column_vector = AequilibraeData() column_vector.create_empty(**args) column_vector.columns[:] = np.random.rand(seed.zones)[:] * 1000 column_vector.index[:] = seed.index[:] # balance vectors column_vector.columns[:] = column_vector.columns[:] * ( row_vector.rows.sum() / column_vector.columns.sum()) # The IPF per se args = { "matrix": seed, "rows": row_vector, "row_field": "rows", "columns": column_vector, "column_field": "columns", "nan_as_zero": False, } with self.assertRaises(TypeError): fratar = Ipf(data='test', test='data') fratar.fit() with self.assertRaises(ValueError): fratar = Ipf(**args) fratar.parameters = ['test'] fratar.fit() fratar = Ipf(**args) fratar.fit() result = fratar.output self.assertAlmostEqual(np.nansum(result.matrix_view), np.nansum(row_vector.data["rows"]), 4, "Ipf did not converge") self.assertGreater(fratar.parameters["convergence level"], fratar.gap, "Ipf did not converge") mr = fratar.save_to_project('my_matrix_ipf', 'my_matrix_ipf.aem') self.assertTrue( os.path.isfile(os.path.join(mats.fldr, 'my_matrix_ipf.aem')), 'Did not save file to the appropriate place') self.assertEqual(mr.procedure_id, fratar.procedure_id, 'procedure ID saved wrong') proj.close()