/ tests / utils / test_python_env.py
test_python_env.py
  1  from unittest import mock
  2  
  3  import pytest
  4  
  5  from mlflow.utils import PYTHON_VERSION
  6  from mlflow.utils.environment import _PythonEnv
  7  
  8  
  9  def test_constructor_argument_validation():
 10      with pytest.raises(TypeError, match="`python` must be a string"):
 11          _PythonEnv(python=1)
 12  
 13      with pytest.raises(TypeError, match="`build_dependencies` must be a list"):
 14          _PythonEnv(build_dependencies=0)
 15  
 16      with pytest.raises(TypeError, match="`dependencies` must be a list"):
 17          _PythonEnv(dependencies=0)
 18  
 19  
 20  def test_to_yaml(tmp_path):
 21      yaml_path = tmp_path / "python_env.yaml"
 22      _PythonEnv(PYTHON_VERSION, ["a"], ["b"]).to_yaml(yaml_path)
 23      expected_content = f"""
 24  python: {PYTHON_VERSION}
 25  build_dependencies:
 26  - a
 27  dependencies:
 28  - b
 29  """.lstrip()
 30      assert yaml_path.read_text() == expected_content
 31  
 32  
 33  def test_from_yaml(tmp_path):
 34      content = f"""
 35  python: {PYTHON_VERSION}
 36  build_dependencies:
 37  - a
 38  - b
 39  dependencies:
 40  - c
 41  - d
 42  """
 43      yaml_path = tmp_path / "test.yaml"
 44      yaml_path.write_text(content)
 45      python_env = _PythonEnv.from_yaml(yaml_path)
 46      assert python_env.python == PYTHON_VERSION
 47      assert python_env.build_dependencies == ["a", "b"]
 48      assert python_env.dependencies == ["c", "d"]
 49  
 50  
 51  def test_from_conda_yaml(tmp_path):
 52      content = f"""
 53  name: example
 54  channels:
 55    - conda-forge
 56  dependencies:
 57    - python={PYTHON_VERSION}
 58    - pip
 59    - pip:
 60      - a
 61      - b
 62  """
 63      yaml_path = tmp_path / "conda.yaml"
 64      yaml_path.write_text(content)
 65      python_env = _PythonEnv.from_conda_yaml(yaml_path)
 66      assert python_env.python == PYTHON_VERSION
 67      assert python_env.build_dependencies == ["pip"]
 68      assert python_env.dependencies == ["a", "b"]
 69  
 70  
 71  def test_from_conda_yaml_build_dependencies(tmp_path):
 72      content = f"""
 73  name: example
 74  channels:
 75    - conda-forge
 76  dependencies:
 77    - python={PYTHON_VERSION}
 78    - pip=1.2.3
 79    - wheel==4.5.6
 80    - setuptools<=7.8.9
 81    - pip:
 82      - a
 83      - b
 84  """
 85      yaml_path = tmp_path / "conda.yaml"
 86      yaml_path.write_text(content)
 87      python_env = _PythonEnv.from_conda_yaml(yaml_path)
 88      assert python_env.python == PYTHON_VERSION
 89      assert python_env.build_dependencies == ["pip==1.2.3", "wheel==4.5.6", "setuptools<=7.8.9"]
 90      assert python_env.dependencies == ["a", "b"]
 91  
 92  
 93  def test_from_conda_yaml_use_current_python_version_when_no_python_spec_in_conda_yaml(tmp_path):
 94      content = """
 95  name: example
 96  channels:
 97    - conda-forge
 98  dependencies:
 99    - pip
100    - pip:
101      - a
102      - b
103  """
104      yaml_path = tmp_path / "conda.yaml"
105      yaml_path.write_text(content)
106      assert _PythonEnv.from_conda_yaml(yaml_path).python == PYTHON_VERSION
107  
108  
109  def test_from_conda_yaml_invalid_python_comparator(tmp_path):
110      content = f"""
111  name: example
112  channels:
113    - conda-forge
114  dependencies:
115    - python<{PYTHON_VERSION}
116    - pip:
117      - a
118      - b
119  """
120      yaml_path = tmp_path / "conda.yaml"
121      yaml_path.write_text(content)
122      with pytest.raises(Exception, match="Invalid version comparator for python"):
123          _PythonEnv.from_conda_yaml(yaml_path)
124  
125  
126  def test_from_conda_yaml_conda_dependencies_warning(tmp_path):
127      content = f"""
128  name: example
129  channels:
130    - conda-forge
131  dependencies:
132    - python={PYTHON_VERSION}
133    - foo
134    - bar
135    - pip:
136      - a
137  """
138      yaml_path = tmp_path / "conda.yaml"
139      yaml_path.write_text(content)
140      with mock.patch("mlflow.utils.environment._logger.warning") as mock_warning:
141          _PythonEnv.from_conda_yaml(yaml_path)
142          mock_warning.assert_called_with(
143              "The following conda dependencies will not be installed "
144              "in the resulting environment: %s",
145              ["foo", "bar"],
146          )