kopia lustrzana https://github.com/simonw/datasette
				
				
				
			New run_sanity_checks mechanism, for SpatiLite
Moved VirtualSpatialIndex check into a new mechanism that should allow us to add further sanity checks in the future. To test this I've had to commit a binary sample SpatiaLite database to the repository. I included a build script for creating that database. Closes #466pull/479/head
							rodzic
							
								
									c692cd2911
								
							
						
					
					
						commit
						da0b3ce2b7
					
				|  | @ -9,9 +9,8 @@ scratchpad | |||
| Pipfile | ||||
| Pipfile.lock | ||||
| 
 | ||||
| # SQLite databases | ||||
| *.db | ||||
| *.sqlite | ||||
| fixtures.db | ||||
| *test.db | ||||
| 
 | ||||
| # Byte-compiled / optimized / DLL files | ||||
| __pycache__/ | ||||
|  |  | |||
|  | @ -344,6 +344,28 @@ class Datasette: | |||
|                 except ValueError: | ||||
|                     # Plugin already registered | ||||
|                     pass | ||||
|         # Run the sanity checks | ||||
|         asyncio.get_event_loop().run_until_complete(self.run_sanity_checks()) | ||||
| 
 | ||||
|     async def run_sanity_checks(self): | ||||
|         # Only one check right now, for Spatialite | ||||
|         for database_name, database in self.databases.items(): | ||||
|             # Run pragma_info on every table | ||||
|             for table in await database.table_names(): | ||||
|                 try: | ||||
|                     await self.execute( | ||||
|                         database_name, | ||||
|                         "PRAGMA table_info({});".format(escape_sqlite(table)), | ||||
|                     ) | ||||
|                 except sqlite3.OperationalError as e: | ||||
|                     if e.args[0] == "no such module: VirtualSpatialIndex": | ||||
|                         raise click.UsageError( | ||||
|                             "It looks like you're trying to load a SpatiaLite" | ||||
|                             " database without first loading the SpatiaLite module." | ||||
|                             "\n\nRead more: https://datasette.readthedocs.io/en/latest/spatialite.html" | ||||
|                         ) | ||||
|                     else: | ||||
|                         raise | ||||
| 
 | ||||
|     def config(self, key): | ||||
|         return self._config.get(key, None) | ||||
|  | @ -530,29 +552,17 @@ class Datasette: | |||
|                 name = path.stem | ||||
|                 if name in self._inspect: | ||||
|                     raise Exception("Multiple files with same stem %s" % name) | ||||
|                 try: | ||||
|                     with sqlite3.connect( | ||||
|                         "file:{}?mode=ro".format(path), uri=True | ||||
|                     ) as conn: | ||||
|                         self.prepare_connection(conn) | ||||
|                         self._inspect[name] = { | ||||
|                             "hash": inspect_hash(path), | ||||
|                             "file": str(path), | ||||
|                             "size": path.stat().st_size, | ||||
|                             "views": inspect_views(conn), | ||||
|                             "tables": inspect_tables( | ||||
|                                 conn, (self.metadata("databases") or {}).get(name, {}) | ||||
|                             ), | ||||
|                         } | ||||
|                 except sqlite3.OperationalError as e: | ||||
|                     if e.args[0] == "no such module: VirtualSpatialIndex": | ||||
|                         raise click.UsageError( | ||||
|                             "It looks like you're trying to load a SpatiaLite" | ||||
|                             " database without first loading the SpatiaLite module." | ||||
|                             "\n\nRead more: https://datasette.readthedocs.io/en/latest/spatialite.html" | ||||
|                         ) | ||||
|                     else: | ||||
|                         raise | ||||
|                 with sqlite3.connect("file:{}?mode=ro".format(path), uri=True) as conn: | ||||
|                     self.prepare_connection(conn) | ||||
|                     self._inspect[name] = { | ||||
|                         "hash": inspect_hash(path), | ||||
|                         "file": str(path), | ||||
|                         "size": path.stat().st_size, | ||||
|                         "views": inspect_views(conn), | ||||
|                         "tables": inspect_tables( | ||||
|                             conn, (self.metadata("databases") or {}).get(name, {}) | ||||
|                         ), | ||||
|                     } | ||||
|         return self._inspect | ||||
| 
 | ||||
|     def register_custom_units(self): | ||||
|  |  | |||
|  | @ -0,0 +1,23 @@ | |||
| import sqlite3 | ||||
| 
 | ||||
| # This script generates the spatialite.db file in our tests directory. | ||||
| 
 | ||||
| 
 | ||||
| def generate_it(filename): | ||||
|     conn = sqlite3.connect(filename) | ||||
|     # Lead the spatialite extension: | ||||
|     conn.enable_load_extension(True) | ||||
|     conn.load_extension("/usr/local/lib/mod_spatialite.dylib") | ||||
|     conn.execute("select InitSpatialMetadata(1)") | ||||
|     conn.executescript("create table museums (name text)") | ||||
|     conn.execute("SELECT AddGeometryColumn('museums', 'point_geom', 4326, 'POINT', 2);") | ||||
|     # At this point it is around 5MB - we can shrink it dramatically by doing thisO | ||||
|     conn.execute("delete from spatial_ref_sys") | ||||
|     conn.execute("delete from spatial_ref_sys_aux") | ||||
|     conn.commit() | ||||
|     conn.execute("vacuum") | ||||
|     conn.close() | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     generate_it("spatialite.db") | ||||
										
											Plik binarny nie jest wyświetlany.
										
									
								
							|  | @ -1,6 +1,7 @@ | |||
| from .fixtures import app_client | ||||
| from datasette.cli import cli | ||||
| from click.testing import CliRunner | ||||
| import pathlib | ||||
| import json | ||||
| 
 | ||||
| 
 | ||||
|  | @ -28,3 +29,12 @@ def test_inspect_cli_writes_to_file(app_client): | |||
|     assert 0 == result.exit_code, result.output | ||||
|     data = json.load(open("foo.json")) | ||||
|     assert ["fixtures"] == list(data.keys()) | ||||
| 
 | ||||
| 
 | ||||
| def test_spatialite_error_if_attempt_to_open_spatialite(): | ||||
|     runner = CliRunner() | ||||
|     result = runner.invoke( | ||||
|         cli, ["serve", str(pathlib.Path(__file__).parent / "spatialite.db")] | ||||
|     ) | ||||
|     assert result.exit_code != 0 | ||||
|     assert "trying to load a SpatiaLite database" in result.output | ||||
		Ładowanie…
	
		Reference in New Issue
	
	 Simon Willison
						Simon Willison