PK!ã&poetrify/__init__.py__version__ = "0.3.0" PK!m  poetrify/api.pyimport shlex import licensename from .files import get_requires from .files import Pipfile from .files import RequirementsTxt def generate_init_cmd(src): """ Generate command string to pass to poetry :param str src: Source file name. :return: Generated command for 'poetry init' . :rtype: str """ if src == "Pipfile": src = Pipfile(src) else: src = RequirementsTxt(src) try: packages, dev_packages = get_requires(src) except FileNotFoundError: return cmd = ["poetry", "init"] for package in packages: cmd.append(f"--dependency={shlex.quote(package)}") for package in dev_packages: cmd.append(f"--dev-dependency={shlex.quote(package)}") try: license_name = licensename.from_file("LICENSE") except FileNotFoundError: license_name = "" else: if license_name is None: license_name = "" if license_name: cmd.append(f"--license={license_name}") return " ".join(cmd) PK!poetrify/cli.py#!/usr/bin/env python from cleo import Application from . import __version__ from .commands import GenerateCommand application = Application("poetrify", __version__, complete=True) application.add(GenerateCommand()) PK!_ܩpoetrify/commands.pyimport errno import os import subprocess import sys from pathlib import Path from cleo import Command from .api import generate_init_cmd class GenerateCommand(Command): """ Generate pyproject.toml from the source file generate {--w|workspace= : Working space} {--s|src=Pipfile : source file} {--d|dry-run : Only display the generated command.} """ def _determine_workspace(self, _workspace): if _workspace: workspace = Path(_workspace) else: workspace = Path(".") return workspace def _remove_source_files(self, workspace, src): # TODO: To clean up this dirty code source_file = workspace / src if src == "Pipfile": lock_file = workspace / "Pipfile.lock" if source_file.exists(): if self.confirm("Do you wanna delete Pipfile?", False): os.remove(source_file) self.info("Pipfile deleted!") if lock_file.exists(): if self.confirm("Do you wanna delete Pipfile.lock?", False): os.remove(lock_file) self.info("Pipfile.lock deleted!") else: if source_file.exists(): if self.confirm("Do you wanna delete requirements.txt?", False): os.remove(source_file) self.info("requirements.txt deleted!") def handle(self): workspace = self._determine_workspace(self.option("workspace")) os.chdir(workspace) src = self.option("src") cmd = generate_init_cmd(src) if not cmd: self.line_error("[ERROR] Source file not found.", style="error") sys.exit(errno.ENOENT) self.info("Generated init command:") self.line(f"\n{cmd}\n") self.line("") if self.option("dry-run"): sys.exit(os.EX_OK) self.info( "Execute the above command. Also, the following output is due to Poetry." ) r = subprocess.run(cmd, shell=True) if r.returncode != os.EX_OK: sys.exit(r.returncode) self._remove_source_files(workspace, src) PK!A$kpoetrify/files.pyfrom dataclasses import dataclass from dataclasses import field from functools import singledispatch import requests import tomlkit @dataclass class Pipfile: src: str body: dict = field(init=False) def __post_init__(self): with open(self.src) as f: self.body = tomlkit.parse(f.read()) @property def packages(self): if self.body: return list(self.body["packages"].keys()) @property def dev_packages(self): if self.body: return list(self.body["dev-packages"].keys()) def find_descendant_packages(package_names): requires = [] for name in package_names: r = requests.get(f"https://pypi.org/pypi/{name}/json") r.raise_for_status() j = r.json() requires_dist = j["info"].get("requires_dist") if requires_dist: for dist in requires_dist: if "extra ==" in dist: continue dist_name = dist.split(" ")[0] requires.append(dist_name) package_name_set = {p.lower() for p in package_names} requires_set = {r.lower() for r in requires} return sorted(package_name_set - requires_set) @dataclass class RequirementsTxt: src: str body: list = field(init=False) _decent_packages: list = None def __post_init__(self): with open(self.src) as f: self.body = [l.strip() for l in f.readlines()] @property def packages(self): packages = [] for line in self.body: if "egg=" in line: continue if "==" in line: package = line.split("==")[0] else: package = line packages.append(package) return packages def get_decent_packages(self): if not self._decent_packages: self._decent_packages = find_descendant_packages(self.packages) return self._decent_packages @singledispatch def get_requires(src): raise TypeError(f"Unsupported type: {src}") @get_requires.register(Pipfile) def get_requires_from_pipfile(src): return src.packages, src.dev_packages @get_requires.register(RequirementsTxt) def get_requires_from_requirements_txt(src): return src.get_decent_packages(), [] PK!H'=49)poetrify-0.3.0.dist-info/entry_points.txtN+I/N.,()*O-)L1s2 r2K2JPK!c+$$ poetrify-0.3.0.dist-info/LICENSEMIT License Copyright (c) 2019 kk6 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PK!HڽTUpoetrify-0.3.0.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!H /G!poetrify-0.3.0.dist-info/METADATAXnn"FMJlY,*ua;F( ##j$^!rً>KeRvj6t)'iw=v%29ΨiŖgMeT~J%wUao2rYʧk"د:A!09WA(7+'aCs"[ ^߲Qf 80̄JF ;S%!qbRi Px wTXJ߉Tq•>J=琕{\ ӹթ@9ϝcQ+G0ns?xsGl6xqArmtbD<"OJK⇇P{Fn(LqONuRvxvva?ll#r`_BۮUMxlBOs ʈՊ5Vxy8ܷ6OۋS<(RIv]z}9PE!$ gd y֍S=PO%G)u =QM`-,d|r km:zR^_U%+a'R(7~,mV=倱5X41Q54h1< "AiiM0F?nК@Y˚xwdS0 !`HkWH10l]0iim ;.fZ ??*tT0LfM.ulE?Je?M04U㻥6~ܖE En)WP[ȈkM3LDc>˩(SS+p,Ȃ'a\q7)wɏhʀb.lQp/蟩(8`s^xkHb8M9aӺ̈́bhmK= *Lt !KpBZ>s-#jdK<EtCZ8?T^m&z/aFLe-ͨ{qZ2c`4ĄHL+Sc +ͼۋ&w^ߟ;v/m&W2I)d;L(ȨFMz$7ASJ~2H꟣ e5ȭ%)}K:cx}af>p Dvj<JmӞUQK2V`oj?fz ʹbS;&^V ωyfJUV,21Qnؘg{ԍ6#7J / pb 4nekx;XK/OPg tE+!e1}R)$nRұu-MpPG&ؽ pNI =Zq>s'VSryD鑟Y8(YoKj-HK.K8DvR਍bmVVP_(g8LsbX{(>GY'Q%=ƛ0^ũn ]z@EO-vnXk^(.&a`$U>;s PK!ã&poetrify/__init__.pyPK!m  Hpoetrify/api.pyPK!poetrify/cli.pyPK!_ܩpoetrify/commands.pyPK!A$kbpoetrify/files.pyPK!H'=49)poetrify-0.3.0.dist-info/entry_points.txtPK!c+$$ poetrify-0.3.0.dist-info/LICENSEPK!HڽTUfpoetrify-0.3.0.dist-info/WHEELPK!H /G!poetrify-0.3.0.dist-info/METADATAPK!H䫜|%poetrify-0.3.0.dist-info/RECORDPK '