-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dash Pages bug fixes and enhancements for dash_pages param and layout module imports #2392
Conversation
4ca6e10
to
3766a18
Compare
hey @alexcjohnson, for some context, this started off from a discussion I had with @ann-marie-ward about supporting absolute paths for While working on this, I've also come up with what I think is a fairly clean solution to both #2263 and #2312, which doesn't involve the heavy-handed approach of clearing any global state, as I proposed in #2271 (but does assume the existence of the Would it make sense to bundle these improvements into this PR since they involve the same parts of the codebase, or should I hold of for a separate PR? (Assuming you're on board with this one here in the first place!) |
@ned2 this looks great! Really appreciate all the work you put into tests here as well.
Meaning you'd use the |
6c5072c
to
f4b5b9e
Compare
OK @alexcjohnson, have added in the fixes for Dash Pages imports as described in the updated PR description. Ready for review!
Oh no, yeah that would be weird. I'm only using Using the new fixture to clear state before and after the test is a little less heavy handed than actually clearing Dash state. (That said, I wonder if there is still a broader argument to clear Dash's global state to prevent these kinds if possible gotchas) btw, looks like something flaky is going on with the tests. Chrome is failing to start up intermittently on some tests in this and the previous run a push triggered. |
heya @alexcjohnson, just bumping this. would be great to get a review while it's still in my head, if you have capacity sometime soon :) |
dash/dash.py
Outdated
@@ -431,7 +433,7 @@ def __init__( # pylint: disable=too-many-statements | |||
_get_paths.CONFIG = self.config | |||
_pages.CONFIG = self.config | |||
|
|||
self.pages_folder = pages_folder | |||
self.pages_folder = str(pages_folder) | |||
self.use_pages = True if pages_folder != "pages" else use_pages |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not new in this PR but since you're fixing some related edge cases... currently if you call:
app = Dash(pages_folder="blah", use_pages=False)
the custom pages_folder
wins and enables pages even though you explicitly said use_pages=False
. I'm not sure why you'd do that (maybe to disable pages temporarily for debugging?), but it feels backward to me. Maybe we can switch use_pages
to have a default of None
, then this logic here can become something like:
self.use_pages = (pages_folder != "pages") if use_pages is None else use_pages
Or maybe even centralize all of this logic (after changing the default use_pages=None
) in _configs.py
, then these lines can just draw from config
:
self.pages_folder = config.pages_folder
self.use_pages = bool(config.pages_folder)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ahh yep, agreed, would be good to squeeze that in. I'll get onto it!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a heads up @alexcjohnson that this suggestion didn't end up making it in, perhaps could be worth creating an issue for it?
@@ -0,0 +1,2 @@ | |||
# this directory is used for testing custom values of `pages_folder` param that | |||
# need to exist as actual paths. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're adding a bunch of __init__.py
files to the tests in this PR - are these now required for pages to work or did you just add them for best practice?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, no, __init__.py
are not required for Dash pages to work. However Dash Pages now detects when discovered page modules happen to be inside of a package so this it can add the package name as a prefix to the module path. See _infer_module_name
. Note this relies on configuring Dash like so: Dash(name=__package__)
So in this particular case the __init__.py
needs to be added to make the test app a package for the tests to work. The other instances I just added them in for best-practice.
@ned2 thanks for the nudge. Just two small questions, then we should be good to go! The first about explicit |
…ven when pages_folder has custom value
f4b5b9e
to
11dbf86
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💃 Thanks @ned2 - this will go in v2.9 🎉
self.pages_folder = pages_folder | ||
self.use_pages = True if pages_folder != "pages" else use_pages | ||
self.pages_folder = str(pages_folder) | ||
self.use_pages = (pages_folder != "pages") if use_pages is None else use_pages |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this breaks backward compatibility (combined with the change in dash/_configs.py) because effectively use_pages=True behavior is inferred (by checking page_folder instead of use_pages), while the user relies on the previous use_pages=False behavior.
Dash Pages Improvements
Fixes and enhancements to
dash_pages
parampages_folder
param now accepts an absolute path (previously would throw an exception), bringing it in line with howassets_folder
behavespages_folder
param now accepts apathlib.Path
instance (previously would throw an exception), bringing it in line with howassets_folder
behavespages_folder
being set to to custom path (ie not the default value"path"
) did not forceuse_pages
to be set toTrue
(as indicated should occur in theDash
doc string)pages_folder
values containing_
,.
, or uppercase chars resulted in incorrectly derived defaultpath
values indash.page_registry
(egmy_pages/page.py
would result in a path of/my-pages/page
rather than/page
)app.config.pages_folder
to be read-only, since this param should only be set in theDash.__init__()
Exception
indash._validate
and one indash._pages
with appropriate exception subclassesclear_pages_state
to clear to reset all global Pages state before and after running of all tests that modify that state. this is needed to ensure that tests for Pages features are not broken by state set by other tests (and they don't break subsequent tests)Dash Community forum thread where the question was asked if there was any reason why
pages_folder
couldn't support absolute paths: https://community.plotly.com/t/set-pages-folder-to-an-absolute-path/71347Fixes to imports performed by Dash Pages
The Python modules found inside the
dash_pages
directory that are programatically imported for loading layouts had two problems that this PR also fixes:sys.modules
; fixes [BUG] page modules not imported correctly #2312name
param of theDash
instance is set to__package__
, the module name of auto imported Pages modules will now be prefixed with the package name. iemyproj/pages/page1.py
->myproj.pages.page1
(previously would have beenpages.page1
). Fixes [BUG] Dash Pages does not support relative package imports within page modules #2263