4747]
4848
4949import argparse
50- import logging
51- import sys
50+ import hashlib
5251import json
52+ import logging
5353import os
54- import hashlib
54+ import re
5555import subprocess
56+ import sys
5657import tempfile
5758from collections import deque
5859from itertools import chain
@@ -449,13 +450,26 @@ def _maybe_print_pip_freeze(pip_bin): # type: (str) -> None
449450 _LOGGER .warning ("Failed to perform pip freeze to check installed dependencies, the error is not fatal" )
450451
451452
452- def _poetry2pipfile_lock (): # type: () -> Dict[str, Any]
453+ def _translate_poetry_dependency (info ): # type: (str) -> str
454+ """Translate Poetry dependency specification as written in pyproject.toml into its Pipfile.lock equivalent."""
455+ if isinstance (info , str ) and re .match (r"^\d" , info ):
456+ return "=={}" .format (info )
457+
458+ # TODO: poetry uses version like ^0.10.4 that are not Pipfile.lock complaint.
459+ return info
460+
461+
462+ def _poetry2pipfile_lock (
463+ only_direct = False , no_default = False , no_dev = False
464+ ): # type: (bool, bool, bool) -> Dict[str, Any]
453465 """Convert Poetry files to Pipfile.lock as Pipenv would produce."""
454466 poetry_lock , pyproject_toml = _read_poetry ()
455467
468+ pyproject_poetry_section = pyproject_toml .get ("tool" , {}).get ("poetry" , {})
469+
456470 sources = []
457471 has_default = False # If default flag is set, it disallows PyPI.
458- for item in pyproject_toml . get ( "tool" , {}). get ( "poetry" , {}) .get ("source" , []):
472+ for item in pyproject_poetry_section .get ("source" , []):
459473 sources .append (
460474 {"name" : item ["name" ], "url" : item ["url" ], "verify_ssl" : True }
461475 )
@@ -473,6 +487,27 @@ def _poetry2pipfile_lock(): # type: () -> Dict[str, Any]
473487
474488 default = {}
475489 develop = {}
490+
491+ if only_direct :
492+ if not no_default :
493+ for dependency_name , info in pyproject_poetry_section .get ("dependencies" , {}).items ():
494+ default [dependency_name ] = _translate_poetry_dependency (info )
495+
496+ if not no_dev :
497+ for dependency_name , info in pyproject_poetry_section .get ("dev-dependencies" , {}).items ():
498+ develop [dependency_name ] = _translate_poetry_dependency (info )
499+
500+ return {
501+ "_meta" : {
502+ "hash" : {"sha256" : poetry_lock ["metadata" ]["content-hash" ]},
503+ "pipfile-spec" : 6 ,
504+ "sources" : sources ,
505+ "requires" : {"python_version" : "{}.{}" .format (sys .version_info .major , sys .version_info .minor )},
506+ },
507+ "default" : default ,
508+ "develop" : develop ,
509+ }
510+
476511 for entry in poetry_lock ["package" ]:
477512 hashes = []
478513 for file_entry in poetry_lock ["metadata" ]["files" ][entry ["name" ]]:
@@ -521,9 +556,11 @@ def _poetry2pipfile_lock(): # type: () -> Dict[str, Any]
521556 requirement ["extras" ] = sorted (requirement ["extras" ])
522557
523558 if entry ["category" ] == "main" :
524- default [entry ["name" ]] = requirement
559+ if not no_default :
560+ default [entry ["name" ]] = requirement
525561 elif entry ["category" ] == "dev" :
526- develop [entry ["name" ]] = requirement
562+ if not no_dev :
563+ develop [entry ["name" ]] = requirement
527564 else :
528565 raise PoetryError ("Unknown category for package {}: {}" .format (entry ["name" ], entry ["category" ]))
529566
@@ -641,12 +678,16 @@ def _parse_pipfile_dependency_info(pipfile_entry): # type: (Union[str, Dict[str
641678
642679def get_requirements_sections (
643680 * , pipfile = None , pipfile_lock = None , no_indexes = False , only_direct = False , no_default = False , no_dev = False
644- ): # type: (Optional[Dict[str, Any]], Optional[Dict[str, Any]], bool, bool, bool, bool) -> Dict[str, Dict[str, Any] ]
681+ ): # type: (Optional[Dict[str, Any]], Optional[Dict[str, Any]], bool, bool, bool, bool) -> Dict[str, Any]
645682 """Compute requirements of an application, the output generated is compatible with pip-tools."""
646683 if no_dev and no_default :
647684 raise ArgumentsError ("Cannot produce requirements as both, default and dev were asked to be discarded" )
648685
649- result = {}
686+ result = {
687+ "default" : {},
688+ "develop" : {},
689+ "sources" : [],
690+ } # type: Dict[str, Any]
650691
651692 if only_direct :
652693 pipfile = pipfile or _read_pipfile ()
@@ -777,7 +818,7 @@ def requirements(
777818 no_indexes = no_indexes , only_direct = only_direct , no_default = no_default , no_dev = no_dev
778819 )
779820 elif method == "poetry" :
780- sections = _poetry2pipfile_lock ()
821+ sections = _poetry2pipfile_lock (only_direct = only_direct , no_default = no_default , no_dev = no_dev )
781822 else :
782823 raise MicropipenvException ("Unhandled method for installing requirements: {}" .format (method ))
783824
@@ -826,7 +867,7 @@ def main(argv=None): # type: (Optional[List[str]]) -> int
826867 "--method" ,
827868 help = "Source of packages for the installation, perform detection if not provided." ,
828869 choices = ["pipenv" , "requirements" , "poetry" ],
829- default = os .getenv ("MICROPIPENV_METHOD" , "pipenv" )
870+ default = os .getenv ("MICROPIPENV_METHOD" )
830871 )
831872 parser_install .add_argument (
832873 "pip_args" ,
0 commit comments