Repository: encode/starlette

Issue:
Mounts without a name strips the path arg from calls to child routes in url_path_for
I'm using an unnamed Mount which contains a mount to a StaticFiles instance and when using "url_for" it is unable to find the matching file. After a bit of digging it seems to be directly related to url_for_path in Mount clearing the path arg whenever the mount does not have a name set. 

https://github.com/encode/starlette/blob/master/starlette/routing.py#L337

Calling url_path_for in the child router works as expected. I'm unclear as to why you'd want to strip this arg just because the mount is not named.

```
app.mount('/stuff', app=Router(routes=[
    Mount('/static', app=StaticFiles(directory='static'), name='static'),
]))
```

```
In [6]: app.url_path_for('static', path='css/bootstap.min.css')
---------------------------------------------------------------------------
NoMatchFound
...
In [7]: app.routes[0].routes[0].url_path_for('static', path='css/bootstap.min.css')
Out[7]: '/static/css/bootstap.min.css'
```


Discussion:
+1 For the issue
Can not getting work `url_for` for Route()
```
app = Router([
    Route('/', endpoint=Homepage, methods=['GET'])
    ])
```
```
  File "templates/base.html", line 13, in top-level template code
    <link href="{{ url_for('static', path='/css/bootstrap.min.css') }}" rel="stylesheet">
...
  File "/home/stan/devel/starlette-example/venv/lib/python3.6/site-packages/starlette/routing.py", line 576, in url_path_for
    raise NoMatchFound()
starlette.routing.NoMatchFound
```
```
>>> print(starlette.__version__)
0.12.10
```

-1
solved by add static mount for Router()
```
app = Router([
    Mount('/static', app=StaticFiles(directory='statics'), name="static"),
    Route('/', endpoint=Homepage, methods=['GET'])
    ])
```
I have the exact same issue with the same example.. https://github.com/encode/starlette-example
@tomchristie would it be reasonable to consider making it a bit stricter, like
```
(
    (
        '/stuff', (
            '/static', ..., name='static',
            '/thing', ..., name='thing'
        ),
        name = None
    ),
    (
        '/staff', (
            '/{id}', (
                '/details', ..., 'details',
            ), name='person',
        ),
        name = 'staff'
    ),
    (
        '/products', (
            '/{id}', (
                '/details', ..., 'details',
            ), name='item',
        ),
        name = 'products'
    )
)
```
so, it'll be a tree (shown as a dict for simplicity)
```
{
    'staff': {
        'person': {
            'details': None
        },
    }
    'products': {
        'item': {
            'details': None
        }
    }
}
```
and look up for
- `staff:person:details` returns `/staff/{id}/details`
- `products:brand:details` returns exception like _No registered name "brand" for "product"_

And for the initial issue statements: `static` -> _No registered name "static"_
+1, spent 2h debugging before I thought to check repo:issues. Documentation is also lacking on how `name`s compose in nested routing for `url_for`. This thread has more detail than the docs.

Resolving patch:
diff --git a/starlette/routing.py b/starlette/routing.py
--- a/starlette/routing.py
+++ b/starlette/routing.py
@@ -336,15 +336,18 @@ def url_path_for(self, name: str, **path_params: str) -> URLPath:
             else:
                 # 'name' matches "<mount_name>:<child_name>".
                 remaining_name = name[len(self.name) + 1 :]
+            path_kwarg = path_params.get("path")
             path_params["path"] = ""
-            path, remaining_params = replace_params(
+            path_prefix, remaining_params = replace_params(
                 self.path_format, self.param_convertors, path_params
             )
+            if path_kwarg is not None:
+                remaining_params["path"] = path_kwarg
             for route in self.routes or []:
                 try:
                     url = route.url_path_for(remaining_name, **remaining_params)
                     return URLPath(
-                        path=path.rstrip("/") + str(url), protocol=url.protocol
+                        path=path_prefix.rstrip("/") + str(url), protocol=url.protocol
                     )
                 except NoMatchFound:
                     pass


Test patch:
diff --git a/tests/test_routing.py b/tests/test_routing.py
--- a/tests/test_routing.py
+++ b/tests/test_routing.py
@@ -400,3 +400,14 @@ def test_url_for_with_root_path():
         "index": "https://www.example.org/sub_path/",
         "submount": "https://www.example.org/sub_path/submount/",
     }
+
+
+double_mount_routes = [
+    Mount("/mount", name="mount", routes=[Mount("/static", ..., name="static")],),
+]
+
+
+def test_url_for_with_double_mount():
+    app = Starlette(routes=double_mount_routes)
+    url = app.url_path_for("mount:static", path="123")
+    assert url == "/mount/static/123"