@@ -779,3 +779,143 @@ def get_value(self, key):
779779 assert project .default_source ["url" ] in [primary_index , extra_index ]
780780 finally :
781781 os .chdir (original_dir )
782+
783+
784+ class TestFormatRequirementForLockfile :
785+ """Tests for format_requirement_for_lockfile in locking.py.
786+
787+ These tests verify that various requirement types are correctly formatted
788+ for the lockfile, including direct URL dependencies (PEP 508 style).
789+ """
790+
791+ def test_direct_url_dependency_https (self ):
792+ """Test that HTTPS direct URL dependencies are stored in lockfile.
793+
794+ This is the fix for issue #5967 - when a package has an extra dependency
795+ with a direct URL like:
796+ my-private-dependency @ https://my-private-artifactory/.../package.whl
797+ The URL should be stored in the lockfile entry.
798+ """
799+ from pipenv .patched .pip ._internal .models .link import Link
800+ from pipenv .patched .pip ._internal .req .constructors import (
801+ install_req_from_line ,
802+ )
803+ from pipenv .utils .locking import format_requirement_for_lockfile
804+
805+ # Create an InstallRequirement with a direct HTTPS URL (PEP 508 style)
806+ req_str = "my-private-package @ https://my-artifactory.com/api/pypi/repo/my-private-package/1.0.0/my-private-package-1.0.0-py3-none-any.whl"
807+ req = install_req_from_line (req_str )
808+
809+ # Verify the link properties
810+ assert req .link is not None
811+ assert req .link .scheme == "https"
812+ assert req .link .is_file is False
813+ assert req .link .is_vcs is False
814+
815+ # Format for lockfile
816+ name , entry = format_requirement_for_lockfile (
817+ req ,
818+ markers_lookup = {},
819+ index_lookup = {},
820+ original_deps = {},
821+ pipfile_entries = {},
822+ hashes = None ,
823+ )
824+
825+ # Verify the URL is stored in the lockfile entry
826+ assert name == "my-private-package"
827+ assert "file" in entry , "Direct URL should be stored in 'file' key"
828+ assert entry ["file" ] == "https://my-artifactory.com/api/pypi/repo/my-private-package/1.0.0/my-private-package-1.0.0-py3-none-any.whl"
829+ assert "version" not in entry , "URL deps should not have version"
830+ assert "index" not in entry , "URL deps should not have index"
831+
832+ def test_direct_url_dependency_http (self ):
833+ """Test that HTTP direct URL dependencies are stored in lockfile."""
834+ from pipenv .patched .pip ._internal .req .constructors import (
835+ install_req_from_line ,
836+ )
837+ from pipenv .utils .locking import format_requirement_for_lockfile
838+
839+ # Create an InstallRequirement with a direct HTTP URL
840+ req_str = "example-package @ http://internal-server.local/packages/example-package-2.0.0.tar.gz"
841+ req = install_req_from_line (req_str )
842+
843+ # Verify the link properties
844+ assert req .link is not None
845+ assert req .link .scheme == "http"
846+
847+ # Format for lockfile
848+ name , entry = format_requirement_for_lockfile (
849+ req ,
850+ markers_lookup = {},
851+ index_lookup = {},
852+ original_deps = {},
853+ pipfile_entries = {},
854+ hashes = None ,
855+ )
856+
857+ # Verify the URL is stored
858+ assert name == "example-package"
859+ assert "file" in entry
860+ assert entry ["file" ] == "http://internal-server.local/packages/example-package-2.0.0.tar.gz"
861+
862+ def test_file_url_dependency (self ):
863+ """Test that local file:// URLs are still handled correctly."""
864+ from pipenv .patched .pip ._internal .req .constructors import (
865+ install_req_from_line ,
866+ )
867+ from pipenv .utils .locking import format_requirement_for_lockfile
868+
869+ # Create an InstallRequirement with a file:// URL
870+ req_str = "local-package @ file:///home/user/packages/local-package-1.0.0.whl"
871+ req = install_req_from_line (req_str )
872+
873+ # Verify the link properties
874+ assert req .link is not None
875+ assert req .link .scheme == "file"
876+ assert req .link .is_file is True
877+
878+ # Format for lockfile
879+ name , entry = format_requirement_for_lockfile (
880+ req ,
881+ markers_lookup = {},
882+ index_lookup = {},
883+ original_deps = {},
884+ pipfile_entries = {},
885+ hashes = None ,
886+ )
887+
888+ # Verify the URL is stored
889+ assert name == "local-package"
890+ assert "file" in entry
891+ assert entry ["file" ] == "file:///home/user/packages/local-package-1.0.0.whl"
892+
893+ def test_regular_pypi_dependency (self ):
894+ """Test that regular PyPI dependencies still work correctly."""
895+ from pipenv .patched .pip ._internal .req .constructors import (
896+ install_req_from_line ,
897+ )
898+ from pipenv .utils .locking import format_requirement_for_lockfile
899+
900+ # Create a regular PyPI requirement
901+ req_str = "requests==2.28.0"
902+ req = install_req_from_line (req_str )
903+
904+ # Regular requirements don't have a link
905+ assert req .link is None
906+
907+ # Format for lockfile
908+ name , entry = format_requirement_for_lockfile (
909+ req ,
910+ markers_lookup = {},
911+ index_lookup = {},
912+ original_deps = {},
913+ pipfile_entries = {},
914+ hashes = None ,
915+ )
916+
917+ # Verify version is stored, not URL
918+ assert name == "requests"
919+ assert "version" in entry
920+ assert entry ["version" ] == "==2.28.0"
921+ assert "file" not in entry
0 commit comments