diff --git a/client/configuration/configuration.py b/client/configuration/configuration.py index cf14ca88f5f..a58ccd51e2c 100644 --- a/client/configuration/configuration.py +++ b/client/configuration/configuration.py @@ -824,7 +824,7 @@ def expand_and_get_existent_search_paths( self, ) -> List[search_path_module.Element]: site_roots = self.get_site_roots() - existent_paths = search_path_module.process_raw_elements( + existent_paths = search_path_module.process_required_raw_elements( self.search_path, site_roots ) + search_path_module.process_raw_elements( self.optional_search_path, site_roots diff --git a/client/configuration/search_path.py b/client/configuration/search_path.py index 61619eb92ef..236aec2c7d1 100644 --- a/client/configuration/search_path.py +++ b/client/configuration/search_path.py @@ -215,22 +215,24 @@ def assert_string_item(input: Dict[str, object], name: str) -> str: ) +def add_if_exists(elements: List[Element], element: Element) -> bool: + if os.path.exists(element.path()): + elements.append(element) + return True + return False + + def process_raw_elements( - raw_elements: Iterable[RawElement], site_roots: Sequence[str] + raw_elements: Iterable[RawElement], + site_roots: Sequence[str], ) -> List[Element]: elements: List[Element] = [] - def add_if_exists(element: Element) -> bool: - if os.path.exists(element.path()): - elements.append(element) - return True - return False - for raw_element in raw_elements: for expanded_raw_element in raw_element.expand_glob(): if isinstance(expanded_raw_element, SitePackageRawElement): added = any( - add_if_exists(expanded_raw_element.to_element(site_root)) + add_if_exists(elements, expanded_raw_element.to_element(site_root)) for site_root in site_roots ) if not added: @@ -242,7 +244,7 @@ def add_if_exists(element: Element) -> bool: expanded_raw_element, (SimpleRawElement, SubdirectoryRawElement) ): element = expanded_raw_element.to_element() - added = add_if_exists(element) + added = add_if_exists(elements, element) if not added: LOG.warning(f"Path does not exist for search path: {element}") else: @@ -251,3 +253,42 @@ def add_if_exists(element: Element) -> bool: ) return elements + + +def process_required_raw_elements( + raw_elements: Iterable[RawElement], + site_roots: Sequence[str], +) -> List[Element]: + elements: List[Element] = [] + + for raw_element in raw_elements: + expanded_raw_elements = raw_element.expand_glob() + if len(expanded_raw_elements) == 0: + raise exceptions.InvalidConfiguration( + f"Invalid path {raw_element}: does not exist." + ) + for expanded_raw_element in expanded_raw_elements: + if isinstance(expanded_raw_element, SitePackageRawElement): + added = any( + add_if_exists(elements, expanded_raw_element.to_element(site_root)) + for site_root in site_roots + ) + if not added: + raise exceptions.InvalidConfiguration( + f"Invalid path {expanded_raw_element.package_name}: does not exist." + ) + elif isinstance( + expanded_raw_element, (SimpleRawElement, SubdirectoryRawElement) + ): + element = expanded_raw_element.to_element() + added = add_if_exists(elements, element) + if not added: + raise exceptions.InvalidConfiguration( + f"Path does not exist for search path: {element}" + ) + else: + raise RuntimeError( + f"Unhandled raw search path element type: {expanded_raw_element}" + ) + + return elements diff --git a/client/configuration/tests/search_path_test.py b/client/configuration/tests/search_path_test.py index ef3ce182c73..053c3c2d405 100644 --- a/client/configuration/tests/search_path_test.py +++ b/client/configuration/tests/search_path_test.py @@ -13,6 +13,7 @@ from ..search_path import ( create_raw_element, process_raw_elements, + process_required_raw_elements, SimpleElement, SimpleRawElement, SitePackageElement, @@ -202,3 +203,64 @@ def test_process_raw_elements_site_root_priority(self) -> None: ), ], ) + + def test_process_required_raw_elements_existence(self) -> None: + with tempfile.TemporaryDirectory() as root: + root_path = Path(root).resolve() + ensure_directories_exists( + root_path, ["a", "b/c", "d/e/f", "venv/lib/pythonX/site-packages"] + ) + + self.assertListEqual( + process_required_raw_elements( + [ + SimpleRawElement(str(root_path / "a")), + SubdirectoryRawElement( + root=str(root_path / "b"), subdirectory="c" + ), + SitePackageRawElement(package_name="f"), + ], + site_roots=[str(root_path / "d/e"), str(root_path / "u/v")], + ), + [ + SimpleElement(str(root_path / "a")), + SubdirectoryElement(root=str(root_path / "b"), subdirectory="c"), + SitePackageElement( + site_root=str(root_path / "d/e"), package_name="f" + ), + ], + ) + + def test_process_required_raw_elements_nonexistence(self) -> None: + with self.assertRaises(InvalidConfiguration): + process_required_raw_elements( + [ + SimpleRawElement("/tmp/does-not-exist"), + ], + site_roots=[], + ) + + def test_process_required_raw_elements_glob_nonexistence(self) -> None: + with self.assertRaises(InvalidConfiguration): + process_required_raw_elements( + [ + SimpleRawElement("/tmp/does-not-exist/*"), + ], + site_roots=[], + ) + + def test_process_required_raw_elements_subdirectory_nonexistence(self) -> None: + with self.assertRaises(InvalidConfiguration): + process_required_raw_elements( + [ + SubdirectoryRawElement(root="/tmp", subdirectory="does-not-exist"), + ], + site_roots=[], + ) + + def test_process_required_raw_elements_site_package_nonexistence(self) -> None: + with self.assertRaises(InvalidConfiguration): + process_required_raw_elements( + [SitePackageRawElement(package_name="f")], + site_roots=[], + ) diff --git a/scripts/run_server_unsaved_changes_test.py b/scripts/run_server_unsaved_changes_test.py index 6ac4efbc499..0f4f730e1b1 100644 --- a/scripts/run_server_unsaved_changes_test.py +++ b/scripts/run_server_unsaved_changes_test.py @@ -141,7 +141,7 @@ def _initialize_pyre_directory( { "source_directories": ["."], "typeshed": str(typeshed_path.absolute()), - "search_path": ["stubs"], + "optional_search_path": ["stubs"], } ) )