@@ -1647,11 +1647,22 @@ def _normalize_dir(self, value):
1647
1647
value = os .path .abspath (value )
1648
1648
return value
1649
1649
1650
+ # Because the validation of preferred_dir depends on root_dir and validation
1651
+ # occurs when the trait is loaded, there are times when we should defer the
1652
+ # validation of preferred_dir (e.g., when preferred_dir is defined via CLI
1653
+ # and root_dir is defined via a config file).
1654
+ _defer_preferred_dir_validation = False
1655
+
1650
1656
@validate ("root_dir" )
1651
1657
def _root_dir_validate (self , proposal ):
1652
1658
value = self ._normalize_dir (proposal ["value" ])
1653
1659
if not os .path .isdir (value ):
1654
1660
raise TraitError (trans .gettext ("No such directory: '%r'" ) % value )
1661
+
1662
+ if self ._defer_preferred_dir_validation :
1663
+ # If we're here, then preferred_dir is configured on the CLI and
1664
+ # root_dir is configured in a file
1665
+ self ._preferred_dir_validation (self .preferred_dir , value )
1655
1666
return value
1656
1667
1657
1668
preferred_dir = Unicode (
@@ -1668,8 +1679,39 @@ def _preferred_dir_validate(self, proposal):
1668
1679
value = self ._normalize_dir (proposal ["value" ])
1669
1680
if not os .path .isdir (value ):
1670
1681
raise TraitError (trans .gettext ("No such preferred dir: '%r'" ) % value )
1682
+
1683
+ # Before we validate against root_dir, check if this trait is defined on the CLI
1684
+ # and root_dir is not. If that's the case, we'll defer it's further validation
1685
+ # until root_dir is validated or the server is starting (the latter occurs when
1686
+ # the default root_dir (cwd) is used).
1687
+ cli_config = self .cli_config .get ("ServerApp" , {})
1688
+ if "preferred_dir" in cli_config and "root_dir" not in cli_config :
1689
+ self ._defer_preferred_dir_validation = True
1690
+
1691
+ if not self ._defer_preferred_dir_validation : # Validate now
1692
+ self ._preferred_dir_validation (value , self .root_dir )
1671
1693
return value
1672
1694
1695
+ def _preferred_dir_validation (self , preferred_dir : str , root_dir : str ) -> None :
1696
+ """Validate preferred dir relative to root_dir - preferred_dir must be equal or a subdir of root_dir"""
1697
+ if not preferred_dir .startswith (root_dir ):
1698
+ raise TraitError (
1699
+ trans .gettext (
1700
+ "preferred_dir must be equal or a subdir of root_dir. preferred_dir: '%r' root_dir: '%r'"
1701
+ )
1702
+ % (preferred_dir , root_dir )
1703
+ )
1704
+ self ._defer_preferred_dir_validation = False
1705
+
1706
+ @observe ("root_dir" )
1707
+ def _root_dir_changed (self , change ):
1708
+ self ._root_dir_set = True
1709
+ if not self .preferred_dir .startswith (change ["new" ]):
1710
+ self .log .warning (
1711
+ trans .gettext ("Value of preferred_dir updated to use value of root_dir" )
1712
+ )
1713
+ self .preferred_dir = change ["new" ]
1714
+
1673
1715
@observe ("server_extensions" )
1674
1716
def _update_server_extensions (self , change ):
1675
1717
self .log .warning (_i18n ("server_extensions is deprecated, use jpserver_extensions" ))
@@ -1851,9 +1893,6 @@ def init_configurables(self):
1851
1893
parent = self ,
1852
1894
log = self .log ,
1853
1895
)
1854
- # Trigger a default/validation here explicitly while we still support the
1855
- # deprecated trait on ServerApp (FIXME remove when deprecation finalized)
1856
- self .contents_manager .preferred_dir
1857
1896
self .session_manager = self .session_manager_class (
1858
1897
parent = self ,
1859
1898
log = self .log ,
@@ -2478,6 +2517,10 @@ def initialize(
2478
2517
# Parse command line, load ServerApp config files,
2479
2518
# and update ServerApp config.
2480
2519
super ().initialize (argv = argv )
2520
+ if self ._defer_preferred_dir_validation :
2521
+ # If we're here, then preferred_dir is configured on the CLI and
2522
+ # root_dir has the default value (cwd)
2523
+ self ._preferred_dir_validation (self .preferred_dir , self .root_dir )
2481
2524
if self ._dispatching :
2482
2525
return
2483
2526
# initialize io loop as early as possible,
0 commit comments