diff --git a/CHANGELOG.md b/CHANGELOG.md index 52e3a52573..f567271575 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Fixed +- [#987](https://github.com/plotly/dash/pull/987) Fix cache string handling for component suites with nested folders in their packages. - [#986](https://github.com/plotly/dash/pull/986) Fix a bug with evaluation of `_force_eager_loading` when application is loaded with gunicorn ## [1.5.0] - 2019-10-29 diff --git a/dash/fingerprint.py b/dash/fingerprint.py index 01db7af5aa..b9c23d3034 100644 --- a/dash/fingerprint.py +++ b/dash/fingerprint.py @@ -1,31 +1,27 @@ import re -build_regex = re.compile(r'^(?P[\w@~-]+)(?P.*)$') - -check_regex = re.compile( - r'^(?P.*)[.]v[\w-]+m[0-9a-fA-F]+(?P(?:(?:(? 2 and cache_regex.match(name_parts[1]): + original_name = ".".join([name_parts[0]] + name_parts[2:]) + return "/".join(path_parts[:-1] + [original_name]), True + + return path, False diff --git a/tests/unit/test_fingerprint.py b/tests/unit/test_fingerprint.py index 913fb09d0f..36de80ddcc 100644 --- a/tests/unit/test_fingerprint.py +++ b/tests/unit/test_fingerprint.py @@ -1,56 +1,122 @@ - from dash.fingerprint import build_fingerprint, check_fingerprint version = 1 hash_value = 1 valid_resources = [ - {'path': 'react@16.8.6.min.js', 'fingerprint': 'react@16.v1m1.8.6.min.js'}, - {'path': 'react@16.8.6.min.js', 'fingerprint': 'react@16.v1_1_1m1234567890abcdef.8.6.min.js', 'version': '1.1.1', 'hash': '1234567890abcdef' }, - {'path': 'react@16.8.6.min.js', 'fingerprint': 'react@16.v1_1_1-alpha_1m1234567890abcdef.8.6.min.js', 'version': '1.1.1-alpha.1', 'hash': '1234567890abcdef' }, - {'path': 'dash.plotly.js', 'fingerprint': 'dash.v1m1.plotly.js'}, - {'path': 'dash.plotly.j_s', 'fingerprint': 'dash.v1m1.plotly.j_s'}, - {'path': 'dash.plotly.css', 'fingerprint': 'dash.v1m1.plotly.css'}, - {'path': 'dash.plotly.xxx.yyy.zzz', 'fingerprint': 'dash.v1m1.plotly.xxx.yyy.zzz'}, - {'path': 'dash~plotly.js', 'fingerprint': 'dash~plotly.v1m1.js'} + {"path": "react@16.8.6.min.js", "fingerprint": "react@16.v1m1.8.6.min.js"}, + { + "path": "react@16.8.6.min.js", + "fingerprint": "react@16.v1_1_1m1234567890abcdef.8.6.min.js", + "version": "1.1.1", + "hash": "1234567890abcdef", + }, + { + "path": "react@16.8.6.min.js", + "fingerprint": "react@16.v1_1_1-alpha_1m1234567890abcdef.8.6.min.js", + "version": "1.1.1-alpha.1", + "hash": "1234567890abcdef", + }, + {"path": "dash.plotly.js", "fingerprint": "dash.v1m1.plotly.js"}, + {"path": "dash.plotly.j_s", "fingerprint": "dash.v1m1.plotly.j_s"}, + {"path": "dash.plotly.css", "fingerprint": "dash.v1m1.plotly.css"}, + {"path": "dash.plotly.xxx.yyy.zzz", "fingerprint": "dash.v1m1.plotly.xxx.yyy.zzz"}, + {"path": "dash~plotly.js", "fingerprint": "dash~plotly.v1m1.js"}, + {"path": "nested/folder/file.js", "fingerprint": "nested/folder/file.v1m1.js"}, + { + # kind of pathological, but we have what looks like a version string + # in a different place - still works + "path": "nested.v2m2/folder/file.js", + "fingerprint": "nested.v2m2/folder/file.v1m1.js" + }, + { + # even works if it gets doubled up in the right place + "path": "nested/folder/file.v2m2.js", + "fingerprint": "nested/folder/file.v1m1.v2m2.js" + }, + { + "path": "nested.dotted/folder.structure/file.name.css", + "fingerprint": "nested.dotted/folder.structure/file.v1m1.name.css", + }, + { + "path": "dash..plotly.js", + "fingerprint": "dash.v1_1_1m1234567890..plotly.js", + "version": "1.1.1", + "hash": "1234567890", + }, + { + "path": "dash.", + "fingerprint": "dash.v1_1_1m1234567890.", + "version": "1.1.1", + "hash": "1234567890", + }, + { + "path": "dash..", + "fingerprint": "dash.v1_1_1m1234567890..", + "version": "1.1.1", + "hash": "1234567890", + }, + { + "path": "dash.js.", + "fingerprint": "dash.v1_1_1m1234567890.js.", + "version": "1.1.1", + "hash": "1234567890", + }, + { + "path": "dash.j-s", + "fingerprint": "dash.v1_1_1m1234567890.j-s", + "version": "1.1.1", + "hash": "1234567890", + }, ] valid_fingerprints = [ - 'react@16.v1_1_2m1571771240.8.6.min.js', - 'dash.plotly.v1_1_1m1234567890.js', - 'dash.plotly.v1_1_1m1234567890.j_s', - 'dash.plotly.v1_1_1m1234567890.css', - 'dash.plotly.v1_1_1m1234567890.xxx.yyy.zzz', - 'dash.plotly.v1_1_1-alpha1m1234567890.js', - 'dash.plotly.v1_1_1-alpha_3m1234567890.js', - 'dash.plotly.v1_1_1m1234567890123.js', - 'dash.plotly.v1_1_1m4bc3.js', - 'dash~plotly.v1m1.js' + "react@16.v1_1_2m1571771240.8.6.min.js", + "dash.v1_1_1m1234567890.plotly.js", + "dash.v1_1_1m1234567890.plotly.j_s", + "dash.v1_1_1m1234567890.plotly.css", + "dash.v1_1_1m1234567890.plotly.xxx.yyy.zzz", + "dash.v1_1_1-alpha1m1234567890.plotly.js", + "dash.v1_1_1-alpha_3m1234567890.plotly.js", + "dash.v1_1_1m1234567890123.plotly.js", + "dash.v1_1_1m4bc3.plotly.js", + "dash~plotly.v1m1.js", + "nested/folder/file.v1m1.js", + "nested.dotted/folder.structure/file.v1m1.name.css", + # this one has a pattern that looks like the version string in the wrong place + # AND one in the right place. + "nested.v2m2/folder/file.v1m1.js", + "nested.v2m2.dotted/folder.structure/file.v1m1.name.css", ] invalid_fingerprints = [ - 'dash.plotly.v1_1_1m1234567890..js', - 'dash.plotly.v1_1_1m1234567890.', - 'dash.plotly.v1_1_1m1234567890..', - 'dash.plotly.v1_1_1m1234567890.js.', - 'dash.plotly.v1_1_1m1234567890.j-s' + "dash.plotly.v1_1_1m1234567890.js", + "folder/dash.plotly.v1_1_1m1234567890.js", + "nested.v1m1/folder/file.js", + "nested.v1m1.dotted/folder.structure/file.name.css", ] + def test_fingerprint(): for resource in valid_resources: # The fingerprint matches expectations - fingerprint = build_fingerprint(resource.get('path'), resource.get('version', version), resource.get('hash', hash_value)) - assert fingerprint == resource.get('fingerprint') + fingerprint = build_fingerprint( + resource.get("path"), + resource.get("version", version), + resource.get("hash", hash_value), + ) + assert fingerprint == resource.get("fingerprint") (original_path, has_fingerprint) = check_fingerprint(fingerprint) - # The inverse operation returns that the fingerprint was valid and the original path + # The inverse operation returns that the fingerprint was valid + # and the original path assert has_fingerprint - assert original_path == resource.get('path') + assert original_path == resource.get("path") for resource in valid_fingerprints: (_, has_fingerprint) = check_fingerprint(resource) - assert has_fingerprint + assert has_fingerprint, resource for resource in invalid_fingerprints: (_, has_fingerprint) = check_fingerprint(resource) - assert not has_fingerprint + assert not has_fingerprint, resource