@@ -730,6 +730,14 @@ def set_up(self):
730730 pass
731731
732732
733+ def _create_fake_object_with_module (module_name ):
734+ class FakeObject :
735+ pass
736+
737+ FakeObject .__module__ = module_name
738+ return FakeObject ()
739+
740+
733741@pytest .mark .usefixtures ("google_auth_mock" )
734742class TestAgentEngineHelpers :
735743 def setup_method (self ):
@@ -919,6 +927,102 @@ def test_register_api_methods(self):
919927 "description"
920928 )
921929
930+ @pytest .mark .usefixtures ("caplog" )
931+ def test_invalid_requirement_warning (self , caplog ):
932+ _agent_engines_utils ._parse_constraints (["invalid requirement line" ])
933+ assert "Failed to parse constraint" in caplog .text
934+
935+ def test_requirements_with_whl_files (self ):
936+ whl_files = [
937+ "wxPython-4.2.4-cp39-cp39-macosx_12_0_x86_64.whl" ,
938+ "/content/wxPython-4.2.3-cp39-cp39-macosx_12_0_x86_64.whl" ,
939+ "https://wxpython.org/Phoenix/snapshot-builds/wxPython-4.2.2-cp38-cp38-macosx_12_0_x86_64.whl" ,
940+ ]
941+ result = _agent_engines_utils ._parse_constraints (whl_files )
942+ assert result == {
943+ "wxPython-4.2.2-cp38-cp38-macosx_12_0_x86_64.whl" : None ,
944+ "wxPython-4.2.3-cp39-cp39-macosx_12_0_x86_64.whl" : None ,
945+ "wxPython-4.2.4-cp39-cp39-macosx_12_0_x86_64.whl" : None ,
946+ }
947+
948+ def test_compare_requirements_with_required_packages (self ):
949+ requirements = {"requests" : "2.0.0" }
950+ constraints = ["requests==1.0.0" ]
951+ result = _agent_engines_utils ._compare_requirements (requirements , constraints )
952+ assert result == {
953+ "actions" : {"append" : set ()},
954+ "warnings" : {
955+ "incompatible" : {"requests==2.0.0 (required: ==1.0.0)" },
956+ "missing" : set (),
957+ },
958+ }
959+
960+ @pytest .mark .usefixtures ("importlib_metadata_version_mock" )
961+ def test_scan_simple_object (self ):
962+ """Test scanning an object importing a known third-party package."""
963+ fake_obj = _create_fake_object_with_module ("requests" )
964+ requirements = _agent_engines_utils ._scan_requirements (
965+ fake_obj ,
966+ package_distributions = _TEST_PACKAGE_DISTRIBUTIONS ,
967+ )
968+ assert requirements == {
969+ "cloudpickle" : "3.0.0" ,
970+ "pydantic" : "1.11.1" ,
971+ "requests" : "2.0.0" ,
972+ }
973+
974+ @pytest .mark .usefixtures ("importlib_metadata_version_mock" )
975+ def test_scan_object_with_stdlib_module (self ):
976+ """Test that stdlib modules are ignored by default."""
977+ fake_obj_stdlib = _create_fake_object_with_module ("json" )
978+ requirements = _agent_engines_utils ._scan_requirements (
979+ fake_obj_stdlib ,
980+ package_distributions = _TEST_PACKAGE_DISTRIBUTIONS ,
981+ )
982+ # Requirements should not contain 'json',
983+ # because 'json' is a stdlib module.
984+ assert requirements == {
985+ "cloudpickle" : "3.0.0" ,
986+ "pydantic" : "1.11.1" ,
987+ }
988+
989+ @pytest .mark .usefixtures ("importlib_metadata_version_mock" )
990+ def test_scan_with_default_ignore_modules (self , monkeypatch ):
991+ """Test implicitly ignoring a module."""
992+ fake_obj = _create_fake_object_with_module ("requests" )
993+ original_base = _agent_engines_utils ._BASE_MODULES
994+ monkeypatch .setattr (
995+ _agent_engines_utils ,
996+ "_BASE_MODULES" ,
997+ set (original_base ) | {"requests" },
998+ )
999+ requirements = _agent_engines_utils ._scan_requirements (
1000+ fake_obj ,
1001+ package_distributions = _TEST_PACKAGE_DISTRIBUTIONS ,
1002+ )
1003+ # Requirements should not contain 'requests',
1004+ # because 'requests' is implicitly ignored in `_BASE_MODULES`.
1005+ assert requirements == {
1006+ "cloudpickle" : "3.0.0" ,
1007+ "pydantic" : "1.11.1" ,
1008+ }
1009+
1010+ @pytest .mark .usefixtures ("importlib_metadata_version_mock" )
1011+ def test_scan_with_explicit_ignore_modules (self ):
1012+ """Test explicitly ignoring a module."""
1013+ fake_obj = _create_fake_object_with_module ("requests" )
1014+ requirements = _agent_engines_utils ._scan_requirements (
1015+ fake_obj ,
1016+ ignore_modules = ["requests" ],
1017+ package_distributions = _TEST_PACKAGE_DISTRIBUTIONS ,
1018+ )
1019+ # Requirements should not contain 'requests',
1020+ # because 'requests' is explicitly ignored in `ignore_modules`.
1021+ assert requirements == {
1022+ "cloudpickle" : "3.0.0" ,
1023+ "pydantic" : "1.11.1" ,
1024+ }
1025+
9221026
9231027@pytest .mark .usefixtures ("google_auth_mock" )
9241028class TestAgentEngine :
0 commit comments