Repository: readthedocs/readthedocs.org

Issue:
Better error when using conda without an environment file
In this build https://readthedocs.org/projects/test-builds/builds/16326429/ I'm using coda, but I didn't define the environment file in the config file, so it gave me a generic error

The error came from https://github.com/readthedocs/readthedocs.org/blob/6752de13bd7f8ebcf393e66c4fdb738e17171046/readthedocs/doc_builder/python_environments.py#L550-L557

We should probably require using conda.environment when using build.tools.python = conda


Discussion:
> We should probably require using conda.environment when using build.tools.python = conda

This sounds like the right approach to me as well! 💯 
The other way should also be considered probably: defining `conda.environment` but using `build.tools.python: "3.8"`. See https://github.com/readthedocs/readthedocs.org/issues/10047#issuecomment-1438326133
When working on this issue, we should also take a look at https://github.com/readthedocs/readthedocs.org/issues/10502 which is strongly related.
Something similar happens when the Git submodule does not exist: https://github.com/readthedocs/readthedocs.org/pull/10594/files#r1282428289 -- The user gets a weird error.

I noting this here so we don't forget to improve this error when working on this.
This is another issue related to better error messaging on the config file https://github.com/readthedocs/readthedocs.org/issues/8595

Resolving patch:
diff --git a/readthedocs/config/config.py b/readthedocs/config/config.py
--- a/readthedocs/config/config.py
+++ b/readthedocs/config/config.py
@@ -226,9 +226,11 @@ def settings(self):
     def validate(self):
         """Validates and process ``raw_config``."""
         self._config['formats'] = self.validate_formats()
+
+        # This should be called before ``validate_python`` and ``validate_conda``
+        self._config["build"] = self.validate_build()
+
         self._config['conda'] = self.validate_conda()
-        # This should be called before validate_python
-        self._config['build'] = self.validate_build()
         self._config['python'] = self.validate_python()
         # Call this before validate sphinx and mkdocs
         self.validate_doc_types()
@@ -258,6 +260,11 @@ def validate_conda(self):
         """Validates the conda key."""
         raw_conda = self._raw_config.get('conda')
         if raw_conda is None:
+            if self.is_using_conda:
+                raise ConfigError(
+                    message_id=ConfigError.CONDA_KEY_REQUIRED,
+                    format_values={"key": "conda"},
+                )
             return None
 
         with self.catch_validation_error('conda'):
diff --git a/readthedocs/config/exceptions.py b/readthedocs/config/exceptions.py
--- a/readthedocs/config/exceptions.py
+++ b/readthedocs/config/exceptions.py
@@ -22,6 +22,7 @@ class ConfigError(BuildUserError):
     SUBMODULES_INCLUDE_EXCLUDE_TOGETHER = "config:submodules:include-exclude-together"
     INVALID_KEY_NAME = "config:base:invalid-key-name"
     SYNTAX_INVALID = "config:base:invalid-syntax"
+    CONDA_KEY_REQUIRED = "config:conda:required"
 
 
 # TODO: improve these error messages shown to the user
diff --git a/readthedocs/config/notifications.py b/readthedocs/config/notifications.py
--- a/readthedocs/config/notifications.py
+++ b/readthedocs/config/notifications.py
@@ -237,6 +237,18 @@
         ),
         type=ERROR,
     ),
+    Message(
+        id=ConfigError.CONDA_KEY_REQUIRED,
+        header=_("Missing required key"),
+        body=_(
+            textwrap.dedent(
+                """
+            The key <code>conda.environment</code> is required when using Conda or Mamba.
+            """
+            ).strip(),
+        ),
+        type=ERROR,
+    ),
 ]
 registry.add(messages)
 


Test patch:
diff --git a/readthedocs/config/tests/test_config.py b/readthedocs/config/tests/test_config.py
--- a/readthedocs/config/tests/test_config.py
+++ b/readthedocs/config/tests/test_config.py
@@ -282,6 +282,23 @@ def test_conda_check_valid(self, tmpdir):
         build.validate()
         assert build.conda.environment == "environment.yml"
 
+    def test_conda_key_required_for_conda_mamba(self):
+        build = get_build_config(
+            {
+                "build": {
+                    "os": "ubuntu-22.04",
+                    "tools": {
+                        "python": "miniconda3-4.7",
+                    },
+                },
+            }
+        )
+        print(build)
+        with raises(ConfigError) as excinfo:
+            build.validate()
+        assert excinfo.value.message_id == ConfigError.CONDA_KEY_REQUIRED
+        assert excinfo.value.format_values.get("key") == "conda"
+
     @pytest.mark.parametrize("value", [3, [], "invalid"])
     def test_conda_check_invalid_value(self, value):
         build = get_build_config({"conda": value})