From 9022d3cb552fc03866bcf9ab18da1e3efb795d90 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Sat, 22 Oct 2022 17:58:58 +0200 Subject: [PATCH 1/3] solved issue with importing from files in same directory begin marked as missing dependencies --- Untitled.ipynb | 81 ++++++++++++++++ deptry/dependency_getter/setup_cfg.py | 127 ++++++++++++++++++++++++++ deptry/import_parser.py | 28 +++++- setup.cfg | 37 ++++++++ tests/test_import_parser.py | 11 +++ 5 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 Untitled.ipynb create mode 100644 deptry/dependency_getter/setup_cfg.py create mode 100644 setup.cfg diff --git a/Untitled.ipynb b/Untitled.ipynb new file mode 100644 index 00000000..acff13dd --- /dev/null +++ b/Untitled.ipynb @@ -0,0 +1,81 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "2f6134e7-c92e-487d-96ca-e64642d2a7e9", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/dk/4hmjslc11rggp3bqq8tnjv4w0000gn/T/ipykernel_2194/1410753484.py:2: SetuptoolsDeprecationWarning: As setuptools moves its configuration towards `pyproject.toml`,\n", + "`setuptools.config.read_configuration` became deprecated.\n", + "\n", + "For the time being, you can use the `setuptools.config.setupcfg` module\n", + "to access a backward compatible API, but this module is provisional\n", + "and might be removed in the future.\n", + "\n", + " setuptools.config.read_configuration(\"setup.cfg\")\n" + ] + }, + { + "ename": "ModuleNotFoundError", + "evalue": "my_package", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/var/folders/dk/4hmjslc11rggp3bqq8tnjv4w0000gn/T/ipykernel_2194/1410753484.py\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0msetuptools\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0msetuptools\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconfig\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread_configuration\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"setup.cfg\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/__init__.py\u001b[0m in \u001b[0;36m_wrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 27\u001b[0m \"\"\"\n\u001b[1;32m 28\u001b[0m \u001b[0mwarnings\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwarn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdedent\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmsg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mSetuptoolsDeprecationWarning\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstacklevel\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 29\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mfn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 30\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 31\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mcast\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mFn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_wrapper\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py\u001b[0m in \u001b[0;36mread_configuration\u001b[0;34m(filepath, find_others, ignore_option_errors)\u001b[0m\n\u001b[1;32m 62\u001b[0m \u001b[0mdist\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mDistribution\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 63\u001b[0m \u001b[0mfilenames\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdist\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfind_config_files\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mfind_others\u001b[0m \u001b[0;32melse\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 64\u001b[0;31m \u001b[0mhandlers\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_apply\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdist\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfilepath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfilenames\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mignore_option_errors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 65\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mconfiguration_to_dict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mhandlers\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 66\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py\u001b[0m in \u001b[0;36m_apply\u001b[0;34m(dist, filepath, other_files, ignore_option_errors)\u001b[0m\n\u001b[1;32m 94\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 95\u001b[0m \u001b[0m_Distribution\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mparse_config_files\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdist\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfilenames\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mfilenames\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 96\u001b[0;31m handlers = parse_configuration(\n\u001b[0m\u001b[1;32m 97\u001b[0m \u001b[0mdist\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdist\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcommand_options\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mignore_option_errors\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mignore_option_errors\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 98\u001b[0m )\n", + "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py\u001b[0m in \u001b[0;36mparse_configuration\u001b[0;34m(distribution, command_options, ignore_option_errors)\u001b[0m\n\u001b[1;32m 172\u001b[0m \u001b[0mdistribution\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msrc_root\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 173\u001b[0m )\n\u001b[0;32m--> 174\u001b[0;31m \u001b[0mmeta\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mparse\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 175\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 176\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mmeta\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moptions\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py\u001b[0m in \u001b[0;36mparse\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 494\u001b[0m )\n\u001b[1;32m 495\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 496\u001b[0;31m \u001b[0msection_parser_method\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msection_options\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 497\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 498\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_deprecated_config_handler\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmsg\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwarning_class\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py\u001b[0m in \u001b[0;36mparse_section\u001b[0;34m(self, section_options)\u001b[0m\n\u001b[1;32m 468\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mcontextlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msuppress\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mKeyError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 469\u001b[0m \u001b[0;31m# Keep silent for a new option may appear anytime.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 470\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 471\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 472\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mparse\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py\u001b[0m in \u001b[0;36m__setitem__\u001b[0;34m(self, option_name, value)\u001b[0m\n\u001b[1;32m 276\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mparser\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 277\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 278\u001b[0;31m \u001b[0mvalue\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mparser\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 279\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 280\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py\u001b[0m in \u001b[0;36m_parse_version\u001b[0;34m(self, value)\u001b[0m\n\u001b[1;32m 600\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mversion\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 601\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 602\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mexpand\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mversion\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_parse_attr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpackage_dir\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mroot_dir\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 603\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 604\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py\u001b[0m in \u001b[0;36m_parse_attr\u001b[0;34m(self, value, package_dir, root_dir)\u001b[0m\n\u001b[1;32m 410\u001b[0m \u001b[0;31m# Make sure package_dir is populated correctly, so `attr:` directives can work\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 411\u001b[0m \u001b[0mpackage_dir\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mensure_discovered\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpackage_dir\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 412\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mexpand\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread_attr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mattr_desc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpackage_dir\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mroot_dir\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 413\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 414\u001b[0m \u001b[0;34m@\u001b[0m\u001b[0mclassmethod\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/expand.py\u001b[0m in \u001b[0;36mread_attr\u001b[0;34m(attr_desc, package_dir, root_dir)\u001b[0m\n\u001b[1;32m 186\u001b[0m \u001b[0mmodule_name\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmodule_name\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0;34m'__init__'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 187\u001b[0m \u001b[0m_parent_path\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmodule_name\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_find_module\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmodule_name\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpackage_dir\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mroot_dir\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 188\u001b[0;31m \u001b[0mspec\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_find_spec\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmodule_name\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 189\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 190\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/expand.py\u001b[0m in \u001b[0;36m_find_spec\u001b[0;34m(module_name, module_path)\u001b[0m\n\u001b[1;32m 201\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 202\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mspec\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 203\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mModuleNotFoundError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmodule_name\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 204\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 205\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mspec\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mModuleNotFoundError\u001b[0m: my_package" + ] + } + ], + "source": [ + "import setuptools\n", + "setuptools.config.read_configuration(\"setup.cfg\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d390cf7-b154-4214-8e60-7be5a327a5ef", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/deptry/dependency_getter/setup_cfg.py b/deptry/dependency_getter/setup_cfg.py new file mode 100644 index 00000000..069f418c --- /dev/null +++ b/deptry/dependency_getter/setup_cfg.py @@ -0,0 +1,127 @@ +import itertools +import logging +import os +import re +from dataclasses import dataclass +from typing import List, Match, Optional, Tuple + +from deptry.dependency import Dependency +from deptry.dependency_getter.base import DependenciesExtract, DependencyGetter + + +@dataclass +class RequirementsTxtDependencyGetter(DependencyGetter): + """Extract dependencies from requirements.txt files.""" + + requirements_txt: Tuple[str, ...] = ("requirements.txt",) + requirements_txt_dev: Tuple[str, ...] = ("dev-requirements.txt", "requirements-dev.txt") + + def get(self) -> DependenciesExtract: + dependencies = list( + itertools.chain( + *(self._get_dependencies_from_requirements_file(file_name) for file_name in self.requirements_txt) + ) + ) + self._log_dependencies(dependencies=dependencies) + + dev_dependencies = list( + itertools.chain( + *( + self._get_dependencies_from_requirements_file(file_name) + for file_name in self._scan_for_dev_requirements_files() + ) + ) + ) + self._log_dependencies(dependencies=dev_dependencies, is_dev=True) + + return DependenciesExtract(dependencies, dev_dependencies) + + def _scan_for_dev_requirements_files(self) -> List[str]: + """ + Check if any of the files passed as requirements_txt_dev exist, and if so; return them. + """ + dev_requirements_files = [file_name for file_name in self.requirements_txt_dev if file_name in os.listdir()] + if dev_requirements_files: + logging.debug(f"Found files with development requirements! {dev_requirements_files}") + return dev_requirements_files + + def _get_dependencies_from_requirements_file(self, file_name: str, is_dev: bool = False) -> List[Dependency]: + logging.debug(f"Scanning {file_name} for {'dev ' if is_dev else ''}dependencies") + dependencies = [] + + with open(file_name) as f: + data = f.readlines() + + for line in data: + dependency = self._extract_dependency_from_line(line) + if dependency: + dependencies.append(dependency) + + return dependencies + + def _extract_dependency_from_line(self, line: str) -> Optional[Dependency]: + """ + Extract a dependency from a single line of a requirements.txt file. + """ + line = self._remove_comments_from(line) + line = self._remove_newlines_from(line) + name = self._find_dependency_name_in(line) + if name: + line = line.replace(name, "") + optional = self._check_if_dependency_is_optional(line) + conditional = self._check_if_dependency_is_conditional(line) + return Dependency(name=name, optional=optional, conditional=conditional) + else: + return None + + def _find_dependency_name_in(self, line: str) -> Optional[str]: + """ + Find the dependency name of a dependency specified according to the pip-standards for requirement.txt + """ + if self._line_is_url(line): + return self._extract_name_from_url(line) + else: + match = re.search("^[^-][a-zA-Z0-9-_]+", line) + if match: + return match.group(0) + return None + + @staticmethod + def _remove_comments_from(line: str) -> str: + return re.sub(r"\s+#.*", "", line).strip() + + @staticmethod + def _remove_newlines_from(line: str) -> str: + return line.replace("\n", "") + + @staticmethod + def _check_if_dependency_is_optional(line: str) -> bool: + return bool(re.findall(r"\[([a-zA-Z0-9-]+?)\]", line)) + + @staticmethod + def _check_if_dependency_is_conditional(line: str) -> bool: + return ";" in line + + @staticmethod + def _line_is_url(line: str) -> Optional[Match[str]]: + return re.search("^(http|https|git\+https)", line) + + @staticmethod + def _extract_name_from_url(line: str) -> Optional[str]: + # Try to find egg, for url like git+https://github.com/xxxxx/package@xxxxx#egg=package + match = re.search("egg=([a-zA-Z0-9-_]*)", line) + if match: + return match.group(1) + + # for url like git+https://github.com/name/python-module.git@0d6dc38d58 + match = re.search("\/((?:(?!\/).)*?)\.git", line) + if match: + return match.group(1) + + # for url like https://github.com/urllib3/urllib3/archive/refs/tags/1.26.8.zip + match = re.search("\/((?:(?!\/).)*?)\/archive\/", line) + if match: + return match.group(1) + + logging.warning(f"Could not parse dependency name from url {line}") + return None diff --git a/deptry/import_parser.py b/deptry/import_parser.py index 1d218294..3990c3df 100644 --- a/deptry/import_parser.py +++ b/deptry/import_parser.py @@ -13,7 +13,8 @@ class ImportParser: """ Class to scan Python files or Python code for import statements. Scanning is done by creating the abstract syntax tree - and extracting all nodes that contain import statements. + and extracting all nodes that contain import statements. For each file, imports from files in the same directory as the file that is being + scanned are excluded. """ def __init__(self) -> None: @@ -29,6 +30,7 @@ def get_imported_modules_for_list_of_files(self, list_of_files: List[Path]) -> L return unique_modules def get_imported_modules_from_file(self, path_to_file: Path) -> List[str]: + logging.debug(f"Scanning {path_to_file}...") try: if str(path_to_file).endswith(".ipynb"): modules = self._get_imported_modules_from_ipynb(path_to_file) @@ -39,6 +41,7 @@ def get_imported_modules_from_file(self, path_to_file: Path) -> List[str]: except AttributeError as e: logging.warning(f"Warning: Parsing imports for file {str(path_to_file)} failed.") raise (e) + modules = self._remove_local_file_imports(modules, path_to_file) return modules def get_imported_modules_from_str(self, file_str: str) -> List[str]: @@ -122,3 +125,26 @@ def _filter_exceptions(modules: List[str]) -> List[str]: def _get_file_encoding(file_name: Union[str, Path]) -> str: with open(file_name, "rb") as f: return chardet.detect(f.read())["encoding"] + + @staticmethod + def _remove_local_file_imports(modules: List[str], path_to_file: Path) -> List[str]: + """ + This omits imported modules from .py files in the same directory from the list of modules. consider the following directory: + + dir + - foo.py + - bar.py + + In this case, if foo.py any imports from bar.py such as 'from bar import x', we do not want 'bar' + to be included in the list of module that foo imports from. + """ + current_directory = path_to_file.parent + py_files_in_same_dir = [p.stem for p in current_directory.iterdir() if p.is_file() and p.suffix == ".py"] + local_files_imported = list(set(modules) & set(py_files_in_same_dir)) + if len(local_files_imported) > 0: + logging.debug( + f"Imports {local_files_imported} found to be imports from local .py files. Removing them from the list" + " of imported modules." + ) + return [module for module in modules if module not in py_files_in_same_dir] + return modules diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000..6365bddb --- /dev/null +++ b/setup.cfg @@ -0,0 +1,37 @@ +[metadata] +name = my_package +version = attr: my_package.VERSION +description = My package description +long_description = file: README.rst, CHANGELOG.rst, LICENSE.rst +keywords = one, two +license = BSD 3-Clause License +classifiers = + Framework :: Django + Programming Language :: Python :: 3 + +[options] +zip_safe = False +include_package_data = True +packages = find: +install_requires = + requests + importlib-metadata; python_version<"3.8" + +[options.package_data] +* = *.txt, *.rst +hello = *.msg + +[options.entry_points] +console_scripts = + executable-name = my_package.module:function + +[options.extras_require] +pdf = ReportLab>=1.2; RXP +rest = docutils>=0.3; pack ==1.1, ==1.3 + +[options.packages.find] +exclude = + examples* + tools* + docs* + my_package.tests* \ No newline at end of file diff --git a/tests/test_import_parser.py b/tests/test_import_parser.py index 62677fad..b31c5f10 100644 --- a/tests/test_import_parser.py +++ b/tests/test_import_parser.py @@ -129,6 +129,17 @@ def test_import_parser_file_encodings(tmp_path): assert set(imported_modules) == {"foo"} +def test_remove_local_file_imports(tmp_path): + with run_within_dir(tmp_path): + with open("foo.py", "w", encoding="utf-8") as f: + f.write("import hobbes\nimport bar\nfrom bar import x") + with open("bar.py", "w", encoding="utf-8") as f: + f.write("def x():\tprint('hello')") + + imported_modules = ImportParser().get_imported_modules_from_file(Path("foo.py")) + assert imported_modules == ["hobbes"] + + def test_import_parser_file_encodings_warning(tmp_path, caplog): with run_within_dir(tmp_path): with open("file1.py", "w", encoding="utf-8") as f: From 6e101bfa3f58c75cc2676ca289201d702c08270f Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Sat, 22 Oct 2022 18:02:05 +0200 Subject: [PATCH 2/3] deleted some files that were added by accident --- Untitled.ipynb | 81 ---------------- deptry/dependency_getter/setup_cfg.py | 127 -------------------------- 2 files changed, 208 deletions(-) delete mode 100644 Untitled.ipynb delete mode 100644 deptry/dependency_getter/setup_cfg.py diff --git a/Untitled.ipynb b/Untitled.ipynb deleted file mode 100644 index acff13dd..00000000 --- a/Untitled.ipynb +++ /dev/null @@ -1,81 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "2f6134e7-c92e-487d-96ca-e64642d2a7e9", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/var/folders/dk/4hmjslc11rggp3bqq8tnjv4w0000gn/T/ipykernel_2194/1410753484.py:2: SetuptoolsDeprecationWarning: As setuptools moves its configuration towards `pyproject.toml`,\n", - "`setuptools.config.read_configuration` became deprecated.\n", - "\n", - "For the time being, you can use the `setuptools.config.setupcfg` module\n", - "to access a backward compatible API, but this module is provisional\n", - "and might be removed in the future.\n", - "\n", - " setuptools.config.read_configuration(\"setup.cfg\")\n" - ] - }, - { - "ename": "ModuleNotFoundError", - "evalue": "my_package", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m/var/folders/dk/4hmjslc11rggp3bqq8tnjv4w0000gn/T/ipykernel_2194/1410753484.py\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0msetuptools\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0msetuptools\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconfig\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread_configuration\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"setup.cfg\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/__init__.py\u001b[0m in \u001b[0;36m_wrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 27\u001b[0m \"\"\"\n\u001b[1;32m 28\u001b[0m \u001b[0mwarnings\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwarn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdedent\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmsg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mSetuptoolsDeprecationWarning\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstacklevel\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 29\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mfn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 30\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 31\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mcast\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mFn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_wrapper\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py\u001b[0m in \u001b[0;36mread_configuration\u001b[0;34m(filepath, find_others, ignore_option_errors)\u001b[0m\n\u001b[1;32m 62\u001b[0m \u001b[0mdist\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mDistribution\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 63\u001b[0m \u001b[0mfilenames\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdist\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfind_config_files\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mfind_others\u001b[0m \u001b[0;32melse\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 64\u001b[0;31m \u001b[0mhandlers\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_apply\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdist\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfilepath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfilenames\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mignore_option_errors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 65\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mconfiguration_to_dict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mhandlers\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 66\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py\u001b[0m in \u001b[0;36m_apply\u001b[0;34m(dist, filepath, other_files, ignore_option_errors)\u001b[0m\n\u001b[1;32m 94\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 95\u001b[0m \u001b[0m_Distribution\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mparse_config_files\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdist\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfilenames\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mfilenames\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 96\u001b[0;31m handlers = parse_configuration(\n\u001b[0m\u001b[1;32m 97\u001b[0m \u001b[0mdist\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdist\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcommand_options\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mignore_option_errors\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mignore_option_errors\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 98\u001b[0m )\n", - "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py\u001b[0m in \u001b[0;36mparse_configuration\u001b[0;34m(distribution, command_options, ignore_option_errors)\u001b[0m\n\u001b[1;32m 172\u001b[0m \u001b[0mdistribution\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msrc_root\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 173\u001b[0m )\n\u001b[0;32m--> 174\u001b[0;31m \u001b[0mmeta\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mparse\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 175\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 176\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mmeta\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moptions\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py\u001b[0m in \u001b[0;36mparse\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 494\u001b[0m )\n\u001b[1;32m 495\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 496\u001b[0;31m \u001b[0msection_parser_method\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msection_options\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 497\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 498\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_deprecated_config_handler\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmsg\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mwarning_class\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py\u001b[0m in \u001b[0;36mparse_section\u001b[0;34m(self, section_options)\u001b[0m\n\u001b[1;32m 468\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mcontextlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msuppress\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mKeyError\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 469\u001b[0m \u001b[0;31m# Keep silent for a new option may appear anytime.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 470\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 471\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 472\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mparse\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py\u001b[0m in \u001b[0;36m__setitem__\u001b[0;34m(self, option_name, value)\u001b[0m\n\u001b[1;32m 276\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mparser\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 277\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 278\u001b[0;31m \u001b[0mvalue\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mparser\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 279\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 280\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py\u001b[0m in \u001b[0;36m_parse_version\u001b[0;34m(self, value)\u001b[0m\n\u001b[1;32m 600\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mversion\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 601\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 602\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mexpand\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mversion\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_parse_attr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpackage_dir\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mroot_dir\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 603\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 604\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py\u001b[0m in \u001b[0;36m_parse_attr\u001b[0;34m(self, value, package_dir, root_dir)\u001b[0m\n\u001b[1;32m 410\u001b[0m \u001b[0;31m# Make sure package_dir is populated correctly, so `attr:` directives can work\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 411\u001b[0m \u001b[0mpackage_dir\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mensure_discovered\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpackage_dir\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 412\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mexpand\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread_attr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mattr_desc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpackage_dir\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mroot_dir\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 413\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 414\u001b[0m \u001b[0;34m@\u001b[0m\u001b[0mclassmethod\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/expand.py\u001b[0m in \u001b[0;36mread_attr\u001b[0;34m(attr_desc, package_dir, root_dir)\u001b[0m\n\u001b[1;32m 186\u001b[0m \u001b[0mmodule_name\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmodule_name\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0;34m'__init__'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 187\u001b[0m \u001b[0m_parent_path\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpath\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmodule_name\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_find_module\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmodule_name\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpackage_dir\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mroot_dir\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 188\u001b[0;31m \u001b[0mspec\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_find_spec\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmodule_name\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpath\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 189\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 190\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/git/deptry/.venv/lib/python3.10/site-packages/setuptools/config/expand.py\u001b[0m in \u001b[0;36m_find_spec\u001b[0;34m(module_name, module_path)\u001b[0m\n\u001b[1;32m 201\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 202\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mspec\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 203\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mModuleNotFoundError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmodule_name\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 204\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 205\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mspec\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: my_package" - ] - } - ], - "source": [ - "import setuptools\n", - "setuptools.config.read_configuration(\"setup.cfg\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9d390cf7-b154-4214-8e60-7be5a327a5ef", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/deptry/dependency_getter/setup_cfg.py b/deptry/dependency_getter/setup_cfg.py deleted file mode 100644 index 069f418c..00000000 --- a/deptry/dependency_getter/setup_cfg.py +++ /dev/null @@ -1,127 +0,0 @@ -import itertools -import logging -import os -import re -from dataclasses import dataclass -from typing import List, Match, Optional, Tuple - -from deptry.dependency import Dependency -from deptry.dependency_getter.base import DependenciesExtract, DependencyGetter - - -@dataclass -class RequirementsTxtDependencyGetter(DependencyGetter): - """Extract dependencies from requirements.txt files.""" - - requirements_txt: Tuple[str, ...] = ("requirements.txt",) - requirements_txt_dev: Tuple[str, ...] = ("dev-requirements.txt", "requirements-dev.txt") - - def get(self) -> DependenciesExtract: - dependencies = list( - itertools.chain( - *(self._get_dependencies_from_requirements_file(file_name) for file_name in self.requirements_txt) - ) - ) - self._log_dependencies(dependencies=dependencies) - - dev_dependencies = list( - itertools.chain( - *( - self._get_dependencies_from_requirements_file(file_name) - for file_name in self._scan_for_dev_requirements_files() - ) - ) - ) - self._log_dependencies(dependencies=dev_dependencies, is_dev=True) - - return DependenciesExtract(dependencies, dev_dependencies) - - def _scan_for_dev_requirements_files(self) -> List[str]: - """ - Check if any of the files passed as requirements_txt_dev exist, and if so; return them. - """ - dev_requirements_files = [file_name for file_name in self.requirements_txt_dev if file_name in os.listdir()] - if dev_requirements_files: - logging.debug(f"Found files with development requirements! {dev_requirements_files}") - return dev_requirements_files - - def _get_dependencies_from_requirements_file(self, file_name: str, is_dev: bool = False) -> List[Dependency]: - logging.debug(f"Scanning {file_name} for {'dev ' if is_dev else ''}dependencies") - dependencies = [] - - with open(file_name) as f: - data = f.readlines() - - for line in data: - dependency = self._extract_dependency_from_line(line) - if dependency: - dependencies.append(dependency) - - return dependencies - - def _extract_dependency_from_line(self, line: str) -> Optional[Dependency]: - """ - Extract a dependency from a single line of a requirements.txt file. - """ - line = self._remove_comments_from(line) - line = self._remove_newlines_from(line) - name = self._find_dependency_name_in(line) - if name: - line = line.replace(name, "") - optional = self._check_if_dependency_is_optional(line) - conditional = self._check_if_dependency_is_conditional(line) - return Dependency(name=name, optional=optional, conditional=conditional) - else: - return None - - def _find_dependency_name_in(self, line: str) -> Optional[str]: - """ - Find the dependency name of a dependency specified according to the pip-standards for requirement.txt - """ - if self._line_is_url(line): - return self._extract_name_from_url(line) - else: - match = re.search("^[^-][a-zA-Z0-9-_]+", line) - if match: - return match.group(0) - return None - - @staticmethod - def _remove_comments_from(line: str) -> str: - return re.sub(r"\s+#.*", "", line).strip() - - @staticmethod - def _remove_newlines_from(line: str) -> str: - return line.replace("\n", "") - - @staticmethod - def _check_if_dependency_is_optional(line: str) -> bool: - return bool(re.findall(r"\[([a-zA-Z0-9-]+?)\]", line)) - - @staticmethod - def _check_if_dependency_is_conditional(line: str) -> bool: - return ";" in line - - @staticmethod - def _line_is_url(line: str) -> Optional[Match[str]]: - return re.search("^(http|https|git\+https)", line) - - @staticmethod - def _extract_name_from_url(line: str) -> Optional[str]: - # Try to find egg, for url like git+https://github.com/xxxxx/package@xxxxx#egg=package - match = re.search("egg=([a-zA-Z0-9-_]*)", line) - if match: - return match.group(1) - - # for url like git+https://github.com/name/python-module.git@0d6dc38d58 - match = re.search("\/((?:(?!\/).)*?)\.git", line) - if match: - return match.group(1) - - # for url like https://github.com/urllib3/urllib3/archive/refs/tags/1.26.8.zip - match = re.search("\/((?:(?!\/).)*?)\/archive\/", line) - if match: - return match.group(1) - - logging.warning(f"Could not parse dependency name from url {line}") - return None From 22f5bae7ca29c6cb199c0ae92fcc9f55a7c5f2b9 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Sat, 22 Oct 2022 18:02:56 +0200 Subject: [PATCH 3/3] deleted some files that were added by accident --- setup.cfg | 37 ------------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 setup.cfg diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 6365bddb..00000000 --- a/setup.cfg +++ /dev/null @@ -1,37 +0,0 @@ -[metadata] -name = my_package -version = attr: my_package.VERSION -description = My package description -long_description = file: README.rst, CHANGELOG.rst, LICENSE.rst -keywords = one, two -license = BSD 3-Clause License -classifiers = - Framework :: Django - Programming Language :: Python :: 3 - -[options] -zip_safe = False -include_package_data = True -packages = find: -install_requires = - requests - importlib-metadata; python_version<"3.8" - -[options.package_data] -* = *.txt, *.rst -hello = *.msg - -[options.entry_points] -console_scripts = - executable-name = my_package.module:function - -[options.extras_require] -pdf = ReportLab>=1.2; RXP -rest = docutils>=0.3; pack ==1.1, ==1.3 - -[options.packages.find] -exclude = - examples* - tools* - docs* - my_package.tests* \ No newline at end of file