html_url,issue_url,id,node_id,user,user_label,created_at,updated_at,author_association,body,reactions,issue,issue_label,performed_via_github_app https://github.com/simonw/datasette/issues/187#issuecomment-502401636,https://api.github.com/repos/simonw/datasette/issues/187,502401636,MDEyOklzc3VlQ29tbWVudDUwMjQwMTYzNg==,9599,simonw,2019-06-15T21:44:23Z,2019-06-15T21:44:23Z,OWNER,I'm closing his as a duplicate of the new #511 - I hope to have his working very shortly as a result of #272 ,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",309033998,Windows installation error, https://github.com/simonw/datasette/issues/272#issuecomment-502393107,https://api.github.com/repos/simonw/datasette/issues/272,502393107,MDEyOklzc3VlQ29tbWVudDUwMjM5MzEwNw==,9599,simonw,2019-06-15T19:25:54Z,2019-06-19T01:20:14Z,OWNER,"OK, time for a solid implementation plan. As soon as https://github.com/django/asgiref/pull/92 is merged (hopefully very soon) the ASGI spec will have support for an optional `raw_path` - which means we can continue to use `table%2Fnames` with embedded `/` without being unable to tell if a path has been decoded or not. Steps to implement: ## Refactor classes, then add .asgi() method to BaseView Add a `.asgi(self, scope, receive, send)` method to my base view class. This will expose an ASGI interface to the outside world: the method itself will construct a request object and call the existing `.get()` method. My only true shared base class is actually `RenderMixin` because the `IndexView` doesn't extend `BaseView`. I'm going to refactor the class hierarchy a bit here - `AsgiView` will be my top level class with the `.asgi()` method on it. `RenderMixin` will be renamed `BaseView(AsgiView)`, while existing `BaseView` will be renamed `DataView(BaseView)` since it mainly exists to introduce the handy `.data()` abstraction. So... * `AsgiView` - has `.asgi()` method, extends Sanic `HTTPMethodView` (for the moment) * `BaseView(AsgiView)` - defines utility methods currently on `RenderMixin` * `IndexView(BaseView)` - the current `IndexView` * `DataView(BaseView)` - defines the utilities currently on `BaseView`, including `data()` * Everything else subclasses `DataView` ## Extract routing logic out into a new `DatasetteView` I considered calling this `RouteView`, but one of the goals of this project is to allow other ASGI apps to import Datasette itself and reuse it as its own ASGI function. So `DatasetteView` will subclass `BaseView` and will do all of the routing logic. That logic currently lives here: https://github.com/simonw/datasette/blob/aa911122feab13f8e65875c98edb00fd3832b7b8/datasette/app.py#L594-L640 ## For tests: Implement a version of app_client.get() that calls ASGI instead Almost all of the unit tests currently use `app_client.get(""/path..."")`. I want to be able to run tests against both ASGI and existing-Sanic, so for the moment I'm going to teach `app_client.get()` to use ASGI instead but only in the presence of a new environment variable. I can then have Travis run the tests twice - once with that environement variable and once without. ## Make datasette serve --asgi run ASGI and uvicorn Uvicorn supports Python 3.5 again as of https://github.com/encode/uvicorn/issues/330 - so it's going to be the new dependency for Datasette. ## Do some comparative testing of ASGI and non-ASGI Just some sanity checking to make sure there aren't any weird issues. ## Final step: refactor out Sanic Hopefully this will just involve changes being made to the AsgiView base class, since that subclasses Sanic `HTTPMethodView`. Bonus: It looks like dropping Sanic as a dependency in favour of Uvicorn should give us Windows support! https://github.com/encode/uvicorn/issues/82 ","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",324188953,Port Datasette to ASGI, https://github.com/simonw/datasette/issues/272#issuecomment-502393267,https://api.github.com/repos/simonw/datasette/issues/272,502393267,MDEyOklzc3VlQ29tbWVudDUwMjM5MzI2Nw==,9599,simonw,2019-06-15T19:28:27Z,2019-06-15T19:28:27Z,OWNER,I'll probably revert 9fdb47ca952b93b7b60adddb965ea6642b1ff523 from https://github.com/simonw/datasette/issues/272#issuecomment-494192779 since I won't need it now that ASGI is getting `raw_path` support.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",324188953,Port Datasette to ASGI, https://github.com/simonw/datasette/issues/272#issuecomment-502394420,https://api.github.com/repos/simonw/datasette/issues/272,502394420,MDEyOklzc3VlQ29tbWVudDUwMjM5NDQyMA==,9599,simonw,2019-06-15T19:45:46Z,2019-06-15T19:45:46Z,OWNER,"For reference, here's some WIP code I wrote last year against the old ASGI 2 spec: https://github.com/simonw/datasette/commit/4fd36ba2f3f91da7258859808616078e3464fb97","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",324188953,Port Datasette to ASGI, https://github.com/simonw/datasette/issues/272#issuecomment-502395689,https://api.github.com/repos/simonw/datasette/issues/272,502395689,MDEyOklzc3VlQ29tbWVudDUwMjM5NTY4OQ==,9599,simonw,2019-06-15T20:05:26Z,2019-06-15T20:05:26Z,OWNER,"For the routing component: I'm going to base my implementation on the one from Django Channels. https://github.com/django/channels/blob/507cb54fcb36df63282dd19653ea743036e7d63c/channels/routing.py#L123-L149 Documented here: https://channels.readthedocs.io/en/latest/topics/routing.html#urlrouter Particularly relevant: my view classes need access to the components that were already parsed out of the URL by the router. I'm going to copy the Django Channels mechanism of stashing those in `scope[""url_route""][""kwargs""]`.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",324188953,Port Datasette to ASGI, https://github.com/simonw/datasette/issues/272#issuecomment-502401078,https://api.github.com/repos/simonw/datasette/issues/272,502401078,MDEyOklzc3VlQ29tbWVudDUwMjQwMTA3OA==,9599,simonw,2019-06-15T21:35:26Z,2019-06-15T21:35:26Z,OWNER,Started sketching out the router in the `asgi` branch: https://github.com/simonw/datasette/commit/7cdc55c6836fe246b1ca8a13a965a39991c9ffec,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",324188953,Port Datasette to ASGI, https://github.com/simonw/datasette/issues/507#issuecomment-502402586,https://api.github.com/repos/simonw/datasette/issues/507,502402586,MDEyOklzc3VlQ29tbWVudDUwMjQwMjU4Ng==,9599,simonw,2019-06-15T22:00:14Z,2019-06-15T22:00:14Z,OWNER,I need to find a good tool for taking screenshots on OSX that are reliably the same dimension across multiple sessions. Maybe in Firefox?,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",455852801,Every datasette plugin on the ecosystem page should have a screenshot, https://github.com/simonw/datasette/issues/509#issuecomment-502393573,https://api.github.com/repos/simonw/datasette/issues/509,502393573,MDEyOklzc3VlQ29tbWVudDUwMjM5MzU3Mw==,9599,simonw,2019-06-15T19:32:56Z,2019-06-15T19:32:56Z,OWNER,"Experimental exploratory patch: ```diff diff --git a/datasette/app.py b/datasette/app.py index 2ef7da4..ca51866 100644 --- a/datasette/app.py +++ b/datasette/app.py @@ -164,8 +164,10 @@ class Datasette: is_memory = True is_mutable = path not in self.immutables db = Database(self, path, is_mutable=is_mutable, is_memory=is_memory) + i = 1 if db.name in self.databases: - raise Exception(""Multiple files with same stem: {}"".format(db.name)) + db.stem = db.name + ""-"" + str(i) + i += 1 self.databases[db.name] = db self.cache_headers = cache_headers self.cors = cors diff --git a/datasette/database.py b/datasette/database.py index e491577..75c8681 100644 --- a/datasette/database.py +++ b/datasette/database.py @@ -14,6 +14,8 @@ from .inspect import inspect_hash class Database: + stem = None + def __init__(self, ds, path=None, is_mutable=False, is_memory=False): self.ds = ds self.path = path @@ -73,6 +75,8 @@ class Database: def name(self): if self.is_memory: return "":memory:"" + elif self.stem: + return self.stem else: return Path(self.path).stem ``` ","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",456568880,Support opening multiple databases with the same stem,