├── grapher ├── .gitignore ├── __init__.py ├── util.py ├── file_grapher_test.py ├── pydepwrap.py ├── builtin.py ├── django.py ├── graph.py ├── scan.py ├── structures.py └── file_grapher.py ├── testdata ├── .gitignore └── expected │ ├── python27-syntax │ ├── PipPackage.depresolve.json │ ├── PipPackage.unit.json │ └── PipPackage.graph.json │ ├── python-django-app │ └── myproject │ │ ├── DjangoApp.depresolve.json │ │ └── DjangoApp.unit.json │ ├── python-mock-stdlib │ ├── Python │ │ ├── PipPackage.depresolve.json │ │ ├── PipPackage.unit.json │ │ └── PipPackage.graph.json │ └── __builtin__ │ │ ├── PipPackage.depresolve.json │ │ ├── PipPackage.unit.json │ │ └── PipPackage.graph.json │ ├── python-no-url │ └── python-no-uri │ │ ├── PipPackage.depresolve.json │ │ ├── PipPackage.unit.json │ │ └── PipPackage.graph.json │ ├── python-sample-0 │ └── python-sample-0 │ │ ├── PipPackage.depresolve.json │ │ ├── PipPackage.unit.json │ │ └── PipPackage.graph.json │ ├── python-sample-1 │ └── python-sample-1 │ │ ├── PipPackage.depresolve.json │ │ ├── PipPackage.unit.json │ │ └── PipPackage.graph.json │ ├── python-sample-2 │ └── python-sample-2 │ │ ├── PipPackage.depresolve.json │ │ ├── PipPackage.unit.json │ │ └── PipPackage.graph.json │ ├── python-link-tests │ └── python-link-tests │ │ ├── PipPackage.depresolve.json │ │ ├── PythonTestPackage.depresolve.json │ │ ├── PipPackage.unit.json │ │ ├── PythonTestPackage.unit.json │ │ ├── PipPackage.graph.json │ │ └── PythonTestPackage.graph.json │ ├── python-stdlib-refs │ └── python-stdlib-refs │ │ ├── PipPackage.depresolve.json │ │ └── PipPackage.unit.json │ ├── python-reqstxt-setuppy │ └── python-reqstxt-setuppy │ │ ├── PipPackage.depresolve.json │ │ ├── PipPackage.unit.json │ │ └── PipPackage.graph.json │ ├── python-single-module-lib │ └── single-module-lib │ │ ├── PipPackage.depresolve.json │ │ ├── PipPackage.unit.json │ │ └── PipPackage.graph.json │ ├── python-unresolved-reqstxt │ └── python-unresolved-reqstxt │ │ ├── PipPackage.depresolve.json │ │ ├── PipPackage.unit.json │ │ └── PipPackage.graph.json │ └── python-single-module-dependent │ └── single-module-dependent │ ├── PipPackage.depresolve.json │ ├── PipPackage.unit.json │ └── PipPackage.graph.json ├── .dockerignore ├── .gitattributes ├── .bin ├── srclib-python.bat └── srclib-python ├── .gitignore ├── requirements.txt ├── NOTICE ├── setup.py ├── Srclibtoolchain ├── .travis.yml ├── srclib-python.py ├── Makefile ├── README.md └── .gitmodules /grapher/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc -------------------------------------------------------------------------------- /grapher/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /testdata/.gitignore: -------------------------------------------------------------------------------- 1 | actual/ -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .bin/ 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sh text eol=lf -------------------------------------------------------------------------------- /testdata/expected/python27-syntax/PipPackage.depresolve.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /testdata/expected/python-django-app/myproject/DjangoApp.depresolve.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /testdata/expected/python-mock-stdlib/Python/PipPackage.depresolve.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /testdata/expected/python-mock-stdlib/__builtin__/PipPackage.depresolve.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /testdata/expected/python-no-url/python-no-uri/PipPackage.depresolve.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /testdata/expected/python-sample-0/python-sample-0/PipPackage.depresolve.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /testdata/expected/python-sample-1/python-sample-1/PipPackage.depresolve.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /testdata/expected/python-sample-2/python-sample-2/PipPackage.depresolve.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /testdata/expected/python-link-tests/python-link-tests/PipPackage.depresolve.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /testdata/expected/python-stdlib-refs/python-stdlib-refs/PipPackage.depresolve.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /testdata/expected/python-link-tests/python-link-tests/PythonTestPackage.depresolve.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /testdata/expected/python-reqstxt-setuppy/python-reqstxt-setuppy/PipPackage.depresolve.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /testdata/expected/python-single-module-lib/single-module-lib/PipPackage.depresolve.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /testdata/expected/python-unresolved-reqstxt/python-unresolved-reqstxt/PipPackage.depresolve.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /.bin/srclib-python.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | "%~dp0/../.env/Scripts/python.exe" -m srclib-python %* 4 | -------------------------------------------------------------------------------- /testdata/expected/python-single-module-dependent/single-module-dependent/PipPackage.depresolve.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | build/ 3 | dist/ 4 | grapher.egg-info/ 5 | vendor/*/ 6 | __pycache__/ 7 | .srclib-cache/ -------------------------------------------------------------------------------- /grapher/util.py: -------------------------------------------------------------------------------- 1 | def normalize(p: str) -> str: 2 | """ Transform p to Unix-style by replacing backslashes """ 3 | return p.replace('\\', '/') 4 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/sourcegraph/pydep.git@6e725f473454c4de392a25dbbfcd10079c77b1fd 2 | virtualenv==13.1.0 3 | pip==7.1.2 4 | jedi==0.9.0 5 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | srclib Project 2 | Copyright 2014 Sourcegraph, Inc 3 | 4 | This product includes software developed at Sourcegraph, Inc. 5 | (https://sourcegraph.com/). 6 | -------------------------------------------------------------------------------- /testdata/expected/python-mock-stdlib/Python/PipPackage.unit.json: -------------------------------------------------------------------------------- 1 | {"Name":"Python","Type":"PipPackage","Repo":"github.com/python/cpython","Files":["Lib/os.py"],"Dir":"Lib"} 2 | -------------------------------------------------------------------------------- /testdata/expected/python-mock-stdlib/__builtin__/PipPackage.unit.json: -------------------------------------------------------------------------------- 1 | {"Name":"__builtin__","Type":"PipPackage","Repo":"github.com/python/cpython","Files":["Modules/itertoolsmodule.c"],"Dir":"Modules"} 2 | -------------------------------------------------------------------------------- /testdata/expected/python27-syntax/PipPackage.unit.json: -------------------------------------------------------------------------------- 1 | {"Name":".","Type":"PipPackage","Files":["py27lib.py","setup.py"],"Dir":".","Dependencies":[{"Repo":"github.com/pypa/setuptools","Type":"PipPackage","Name":"setuptools"}],"Data":{"ReqFiles":["./requirements.txt"],"Reqs":[]}} 2 | -------------------------------------------------------------------------------- /testdata/expected/python-no-url/python-no-uri/PipPackage.unit.json: -------------------------------------------------------------------------------- 1 | {"Name":"python-no-uri","Type":"PipPackage","Files":["mod0.py","setup.py"],"Dir":".","Dependencies":[{"Repo":"github.com/pypa/setuptools","Type":"PipPackage","Name":"setuptools"}],"Data":{"ReqFiles":["./requirements.txt"],"Reqs":[]}} 2 | -------------------------------------------------------------------------------- /testdata/expected/python-single-module-lib/single-module-lib/PipPackage.unit.json: -------------------------------------------------------------------------------- 1 | {"Name":"single-module-lib","Type":"PipPackage","Files":["mod.py","setup.py"],"Dir":".","Dependencies":[{"Repo":"github.com/pypa/setuptools","Type":"PipPackage","Name":"setuptools"}],"Data":{"ReqFiles":["./requirements.txt"],"Reqs":[]}} 2 | -------------------------------------------------------------------------------- /testdata/expected/python-stdlib-refs/python-stdlib-refs/PipPackage.unit.json: -------------------------------------------------------------------------------- 1 | {"Name":"python-stdlib-refs","Type":"PipPackage","Files":["pkg/__init__.py","setup.py"],"Dir":".","Dependencies":[{"Repo":"github.com/pypa/setuptools","Type":"PipPackage","Name":"setuptools"}],"Data":{"ReqFiles":["./requirements.txt"],"Reqs":[]}} 2 | -------------------------------------------------------------------------------- /testdata/expected/python-unresolved-reqstxt/python-unresolved-reqstxt/PipPackage.unit.json: -------------------------------------------------------------------------------- 1 | {"Name":"python-unresolved-reqstxt","Type":"PipPackage","Files":["mod123.py","setup.py"],"Dir":".","Dependencies":[{"Repo":"github.com/pypa/setuptools","Type":"PipPackage","Name":"setuptools"}],"Data":{"ReqFiles":["./requirements.txt"],"Reqs":[]}} 2 | -------------------------------------------------------------------------------- /testdata/expected/python-sample-0/python-sample-0/PipPackage.unit.json: -------------------------------------------------------------------------------- 1 | {"Name":"python-sample-0","Type":"PipPackage","Files":["pkg0/__init__.py","pkg0/m0.py","pkg0/m1.py","setup.py"],"Dir":".","Dependencies":[{"Repo":"github.com/pypa/setuptools","Type":"PipPackage","Name":"setuptools"}],"Data":{"ReqFiles":["./requirements.txt"],"Reqs":[]}} 2 | -------------------------------------------------------------------------------- /testdata/expected/python-link-tests/python-link-tests/PipPackage.unit.json: -------------------------------------------------------------------------------- 1 | {"Name":"python-link-tests","Type":"PipPackage","Files":["app/pkg0/__init__.py","app/pkg0/m0.py","app/setup.py"],"Dir":"app","Dependencies":[{"Repo":"github.com/pypa/setuptools","Type":"PipPackage","Name":"setuptools"}],"Data":{"ReqFiles":["app/requirements.txt"],"Reqs":[]}} 2 | -------------------------------------------------------------------------------- /.bin/srclib-python: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3.5 2 | 3 | import sys 4 | import os 5 | import os.path 6 | import subprocess 7 | 8 | rootdir = os.path.dirname(os.path.dirname(__file__)) 9 | python = os.path.join(rootdir, ".env", "bin", "python3.5") 10 | 11 | os.environ["SRCLIBPY_ROOTDIR"] = rootdir 12 | 13 | args = [python, "-m", "srclib-python"] 14 | args.extend(sys.argv[1:]) 15 | subprocess.run(args, check=True) 16 | -------------------------------------------------------------------------------- /testdata/expected/python-link-tests/python-link-tests/PythonTestPackage.unit.json: -------------------------------------------------------------------------------- 1 | {"Name":"python-link-tests","Type":"PythonTestPackage","Files":["app/tests/test_m0.py"],"Dir":"app/tests","Dependencies":[{"Type":"PipPackage","Name":"python-link-tests"},{"Repo":"github.com/pypa/setuptools","Type":"PipPackage","Name":"setuptools"}],"Data":{"ReqFiles":[],"Reqs":[{"modules":["pkg0.__init__","pkg0.m0","setup"],"packages":["pkg0"],"project_name":"python-link-tests","repo_url":""}]}} 2 | -------------------------------------------------------------------------------- /testdata/expected/python-sample-1/python-sample-1/PipPackage.unit.json: -------------------------------------------------------------------------------- 1 | {"Name":"python-sample-1","Type":"PipPackage","Files":["app/__init__.py","app/app.py","setup.py"],"Dir":".","Dependencies":[{"Repo":"?","Type":"PipPackage","Name":"python-sample-0"},{"Repo":"github.com/pypa/setuptools","Type":"PipPackage","Name":"setuptools"}],"Data":{"ReqFiles":["./requirements.txt"],"Reqs":[{"extras":null,"key":"https://github.com/sgtest/python-sample-0","modules":null,"packages":["pkg0"],"project_name":"python-sample-0","repo_url":"https://github.com/sgtest/python-sample-0","resolved":true,"specs":null,"type":"vcs","unsafe_name":null}]}} 2 | -------------------------------------------------------------------------------- /testdata/expected/python-single-module-dependent/single-module-dependent/PipPackage.unit.json: -------------------------------------------------------------------------------- 1 | {"Name":"single-module-dependent","Type":"PipPackage","Files":["app.py","setup.py"],"Dir":".","Dependencies":[{"Repo":"?","Type":"PipPackage","Name":"single-module-lib"},{"Repo":"github.com/pypa/setuptools","Type":"PipPackage","Name":"setuptools"}],"Data":{"ReqFiles":["./requirements.txt"],"Reqs":[{"extras":null,"key":"https://github.com/sgtest/python-single-module-lib","modules":["mod"],"packages":null,"project_name":"single-module-lib","repo_url":"https://github.com/sgtest/python-single-module-lib","resolved":true,"specs":null,"type":"vcs","unsafe_name":null}]}} 2 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | name='grapher', 5 | version='0.0', 6 | url='http://sourcegraph.com/sourcegraph/srclib-python', 7 | packages=['grapher'], 8 | py_modules=['srclib-python'], 9 | author='Beyang Liu', 10 | description='Generate the graph for a Python code rooted at a directory' 11 | 'Help: graph.py -h', 12 | zip_safe=False, 13 | # MaikuMori(23/03/2015) 14 | # Don't declare dependency here because pip will just pull jedi from pip repository instead of 15 | # git+https://github.com/beyang/jedi.git@c4a51cba12bc4849e19c4aa25aeb30d66e5fd238 16 | # install_requires=['jedi'], 17 | ) 18 | -------------------------------------------------------------------------------- /Srclibtoolchain: -------------------------------------------------------------------------------- 1 | { 2 | "Tools": [ 3 | { 4 | "Subcmd": "scan", 5 | "Op": "scan", 6 | "SourceUnitTypes": [ 7 | "PipPackage", 8 | "DjangoApp", 9 | "PythonTestPackage" 10 | ] 11 | }, 12 | { 13 | "Subcmd": "graph", 14 | "Op": "graph", 15 | "SourceUnitTypes": [ 16 | "PipPackage", 17 | "DjangoApp", 18 | "PythonTestPackage" 19 | ] 20 | }, 21 | { 22 | "Subcmd": "depresolve", 23 | "Op": "depresolve", 24 | "SourceUnitTypes": [ 25 | "PipPackage", 26 | "DjangoApp", 27 | "PythonTestPackage" 28 | ] 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /testdata/expected/python-sample-2/python-sample-2/PipPackage.unit.json: -------------------------------------------------------------------------------- 1 | {"Name":"python-sample-2","Type":"PipPackage","Files":["app/__init__.py","app/app.py","setup.py"],"Dir":".","Dependencies":[{"Repo":"?","Type":"PipPackage","Name":"requests"},{"Repo":"github.com/pypa/setuptools","Type":"PipPackage","Name":"setuptools"}],"Data":{"ReqFiles":["./requirements.txt"],"Reqs":[{"extras":{},"key":"requests","modules":null,"packages":["requests","requests.packages","requests.packages.chardet","requests.packages.urllib3","requests.packages.urllib3.packages","requests.packages.urllib3.contrib","requests.packages.urllib3.util","requests.packages.urllib3.packages.ssl_match_hostname"],"project_name":"requests","repo_url":null,"resolved":true,"specs":[],"type":"setuptools","unsafe_name":"requests"}]}} 2 | -------------------------------------------------------------------------------- /testdata/expected/python-reqstxt-setuppy/python-reqstxt-setuppy/PipPackage.unit.json: -------------------------------------------------------------------------------- 1 | {"Name":"python-reqstxt-setuppy","Type":"PipPackage","Files":["mod123.py","setup.py"],"Dir":".","Dependencies":[{"Repo":"?","Type":"PipPackage","Name":"click"},{"Repo":"?","Type":"PipPackage","Name":"Jinja2"},{"Repo":"github.com/pypa/setuptools","Type":"PipPackage","Name":"setuptools"}],"Data":{"ReqFiles":["./requirements.txt"],"Reqs":[{"extras":{},"key":"click","modules":null,"packages":["click"],"project_name":"click","repo_url":"http://github.com/mitsuhiko/click","resolved":true,"specs":[],"type":"setuptools","unsafe_name":"click"},{"extras":{},"key":"jinja2","modules":null,"packages":["jinja2"],"project_name":"Jinja2","repo_url":null,"resolved":true,"specs":[{}],"type":"setuptools","unsafe_name":"Jinja2"}]}} 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | python: "3.5" 4 | 5 | before_install: 6 | - pip install setuptools 7 | - mkdir -p $HOME/src/sourcegraph.com/sourcegraph 8 | - mv $TRAVIS_BUILD_DIR $HOME/src/sourcegraph.com/sourcegraph/srclib-python 9 | - export TRAVIS_BUILD_DIR=$HOME/src/sourcegraph.com/sourcegraph/srclib-python 10 | - mkdir -p $HOME/bin 11 | - export PATH=$PATH:$HOME/bin 12 | - mkdir -p $HOME/.srclib/sourcegraph.com/sourcegraph/ 13 | 14 | install: 15 | # installing srclib 16 | - export GOPATH=$HOME 17 | - go get -u -v sourcegraph.com/sourcegraph/srclib/cmd/srclib 18 | - export PATH=$PATH:$GOPATH/bin 19 | # installing toolchain 20 | - ln -s $TRAVIS_BUILD_DIR $HOME/.srclib/sourcegraph.com/sourcegraph/srclib-python 21 | - make install 22 | 23 | # TODO(sqs): add `go test` 24 | script: 25 | - make test 26 | -------------------------------------------------------------------------------- /grapher/file_grapher_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from grapher.file_grapher import FileGrapher 3 | 4 | class TestFileGrapher(unittest.TestCase): 5 | """ 6 | Tests for FileGrapher. 7 | """ 8 | def test_module_path_to_parent_module_name(self): 9 | """ Check if parent module name is correctly detected. """ 10 | cases = [ 11 | ('foo.py', ''), 12 | ('foo/bar.py', 'foo'), 13 | ('foo/__init__.py', ''), 14 | ('foo/bar/__init__.py', 'foo'), 15 | ('foo/bar/chocolate/__init__.py', 'foo.bar'), 16 | ('foo/bar/chocolate/crunchy.py', 'foo.bar.chocolate'), 17 | ('__init__.py', ''), 18 | ] 19 | for case in cases: 20 | filepath, exp_module_name = case[0], case[1] 21 | act_module_name = FileGrapher._get_module_parent_from_module_path(filepath) 22 | self.assertEqual( 23 | exp_module_name, 24 | act_module_name, 25 | msg=('{}: {} != {}'.format(filepath, exp_module_name, act_module_name)) 26 | ) 27 | -------------------------------------------------------------------------------- /srclib-python.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | import sys 4 | 5 | from grapher.scan import scan 6 | from grapher.graph import graph 7 | 8 | def main() -> None: 9 | parser = argparse.ArgumentParser(description="") 10 | subparsers = parser.add_subparsers(help="", dest="subcmd") 11 | 12 | scanparser = subparsers.add_parser("scan", help="") 13 | depresolveparser = subparsers.add_parser("depresolve", help="") 14 | graphparser = subparsers.add_parser("graph", help="") 15 | graphparser.add_argument('--verbose', help='verbose', action='store_true', default=True) 16 | graphparser.add_argument('--debug', help='debug', action='store_true', default=False) 17 | graphparser.add_argument('--quiet', help='quiet', action='store_true', default=False) 18 | graphparser.add_argument('--unit-file', help="debugging purposes", default=None) 19 | 20 | 21 | args = parser.parse_args() 22 | if args.subcmd == "scan": 23 | scan(os.getcwd()) 24 | elif args.subcmd == "depresolve": 25 | print('[]', end="") 26 | elif args.subcmd == "graph": 27 | if args.unit_file is not None: 28 | with open(args.unit_file) as f: 29 | graph(args, f) 30 | else: 31 | graph(args, sys.stdin) 32 | 33 | if __name__ == '__main__': 34 | main() 35 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(OS),Windows_NT) 2 | # You can't change pip.exe being in use on Windows, so we'll copy original one and use it 3 | PIPCMD = cmd /C .env\\Scripts\\pip-vendored.exe --isolated --disable-pip-version-check 4 | PIP2CMD = cmd /C .env\\Scripts\\pip-vendored.exe --isolated --disable-pip-version-check 5 | ENV = virtualenv 6 | ENV2 = virtualenv 7 | MYPY = .env/Scripts/mypy 8 | else 9 | PIPCMD = .env/bin/pip3.5 10 | PIP2CMD = .env/bin/pip2.7 11 | ENV = virtualenv -p python3.5 12 | ENV2 = virtualenv -p python2.7 13 | MYPY = .env/bin/mypy 14 | endif 15 | 16 | .PHONY: install test check 17 | 18 | default: .env install test 19 | 20 | .env: 21 | $(ENV2) .env 22 | $(ENV) .env 23 | ifeq ($(OS),Windows_NT) 24 | cp .env/Scripts/pip.exe .env/Scripts/pip-vendored.exe 25 | endif 26 | 27 | $(MYPY): 28 | $(PIPCMD) install mypy-lang 29 | 30 | install-force: .env 31 | $(PIPCMD) install . --upgrade 32 | $(PIPCMD) install -r requirements.txt --upgrade 33 | $(PIP2CMD) install . --upgrade 34 | $(PIP2CMD) install -r requirements.txt --upgrade 35 | 36 | install: .env 37 | $(PIPCMD) install . 38 | $(PIPCMD) install -r requirements.txt 39 | $(PIP2CMD) install . 40 | $(PIP2CMD) install -r requirements.txt 41 | 42 | test: .env check 43 | srclib test 44 | 45 | check: $(MYPY) 46 | $(MYPY) --silent-imports grapher 47 | -------------------------------------------------------------------------------- /testdata/expected/python-mock-stdlib/__builtin__/PipPackage.graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "Defs": [ 3 | { 4 | "Repo": "github.com/python/cpython", 5 | "UnitType": "PipPackage", 6 | "Unit": "__builtin__", 7 | "Path": "itertools", 8 | "Name": "itertools", 9 | "File": "Modules/itertoolsmodule.c", 10 | "DefStart": 98, 11 | "DefEnd": 107, 12 | "Exported": true, 13 | "Data": { 14 | "Keyword": "", 15 | "Kind": "", 16 | "Name": "itertools", 17 | "Separator": "", 18 | "Type": "" 19 | } 20 | }, 21 | { 22 | "Repo": "github.com/python/cpython", 23 | "UnitType": "PipPackage", 24 | "Unit": "__builtin__", 25 | "Path": "itertools.groupby", 26 | "Name": "itertools.groupby", 27 | "File": "Modules/itertoolsmodule.c", 28 | "DefStart": 308, 29 | "DefEnd": 325, 30 | "Exported": true, 31 | "Data": { 32 | "Keyword": "", 33 | "Kind": "", 34 | "Name": "itertools.groupby", 35 | "Separator": "", 36 | "Type": "" 37 | } 38 | } 39 | ], 40 | "Refs": [ 41 | { 42 | "DefRepo": "github.com/python/cpython", 43 | "DefUnitType": "PipPackage", 44 | "DefUnit": "__builtin__", 45 | "DefPath": "itertools.groupby", 46 | "UnitType": "PipPackage", 47 | "Unit": "__builtin__", 48 | "Def": true, 49 | "File": "Modules/itertoolsmodule.c", 50 | "Start": 308, 51 | "End": 325 52 | }, 53 | { 54 | "DefRepo": "github.com/python/cpython", 55 | "DefUnitType": "PipPackage", 56 | "DefUnit": "__builtin__", 57 | "DefPath": "itertools", 58 | "UnitType": "PipPackage", 59 | "Unit": "__builtin__", 60 | "Def": true, 61 | "File": "Modules/itertoolsmodule.c", 62 | "Start": 98, 63 | "End": 107 64 | } 65 | ] 66 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # srclib-python [![Build Status](https://travis-ci.org/sourcegraph/srclib-python.png?branch=master)](https://travis-ci.org/sourcegraph/srclib-python) 2 | 3 | ## Jedi 4 | 5 | **srclib-python** is a [srclib](https://sourcegraph.com/sourcegraph/srclib) 6 | toolchain that performs Python code analysis: type checking, documentation 7 | generation, jump-to-definition, dependency resolution, etc. 8 | 9 | It enables this functionality in any client application whose code analysis is 10 | powered by srclib, including [Sourcegraph.com](https://sourcegraph.com). 11 | 12 | ## Installation 13 | 14 | This toolchain is not a standalone program; it provides additional functionality 15 | to applications that use [srclib](https://srclib.org). 16 | 17 | First, 18 | [install the `srclib` program (see srclib installation instructions)](https://srclib.org/gettingstarted/). 19 | 20 | Installing `srclib` should automatically install `srclib-python`. 21 | 22 | To verify that installation succeeded, run: 23 | 24 | ``` 25 | srclib toolchain list 26 | ``` 27 | 28 | You should see this srclib-python toolchain in the list. 29 | 30 | Now that this toolchain is installed, any program that relies on srclib will support Python. 31 | 32 | 33 | ## Known issues 34 | 35 | srclib-python is alpha-quality software. It powers code analysis on 36 | [Sourcegraph.com](https://sourcegraph.com) but has not been widely tested or 37 | adapted for other use cases. 38 | 39 | It also expects projects to follow best practices such as including a `setup.py` file. It doesn't currently handle 40 | decorators or namespace packages correctly. 41 | 42 | There also seems to be a problem with some function parameter type detection. 43 | 44 | srclib-python runs on Python 2.7 (and some glue code in Go), but it can still process Python 3 libraries. 45 | 46 | 47 | ## Misc 48 | 49 | srclib-python's type analysis is based on 50 | [Jedi](https://github.com/davidhalter/jedi). 51 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "testdata/case/python-sample-0"] 2 | path = testdata/case/python-sample-0 3 | url = https://github.com/sgtest/python-sample-0.git 4 | [submodule "testdata/case/python-sample-1"] 5 | path = testdata/case/python-sample-1 6 | url = https://github.com/sgtest/python-sample-1.git 7 | [submodule "testdata/case/python-sample-2"] 8 | path = testdata/case/python-sample-2 9 | url = https://github.com/sgtest/python-sample-2.git 10 | [submodule "testdata/case/python-single-module-dependent"] 11 | path = testdata/case/python-single-module-dependent 12 | url = https://github.com/sgtest/python-single-module-dependent.git 13 | [submodule "testdata/case/python-single-module-lib"] 14 | path = testdata/case/python-single-module-lib 15 | url = https://github.com/sgtest/python-single-module-lib.git 16 | [submodule "testdata/case/python-no-url"] 17 | path = testdata/case/python-no-url 18 | url = https://github.com/sgtest/python-no-url.git 19 | [submodule "testdata/case/python-stdlib-refs"] 20 | path = testdata/case/python-stdlib-refs 21 | url = https://github.com/sgtest/python-stdlib-refs 22 | [submodule "testdata/case/python-django-app"] 23 | path = testdata/case/python-django-app 24 | url = https://github.com/sgtest/python-django-app 25 | [submodule "testdata/case/python-mock-stdlib"] 26 | path = testdata/case/python-mock-stdlib 27 | url = https://github.com/sgtest/python-mock-stdlib 28 | [submodule "testdata/case/python-reqstxt-setuppy"] 29 | path = testdata/case/python-reqstxt-setuppy 30 | url = https://github.com/sgtest/python-reqstxt-setuppy 31 | [submodule "testdata/case/python-unresolved-reqstxt"] 32 | path = testdata/case/python-unresolved-reqstxt 33 | url = https://github.com/sgtest/python-unresolved-reqstxt.git 34 | [submodule "testdata/case/python-link-tests"] 35 | path = testdata/case/python-link-tests 36 | url = https://github.com/sgtest/python-link-tests.git 37 | [submodule "testdata/case/python27-syntax"] 38 | path = testdata/case/python27-syntax 39 | url = https://github.com/sgtest/python27-syntax 40 | -------------------------------------------------------------------------------- /grapher/pydepwrap.py: -------------------------------------------------------------------------------- 1 | """Convenience wrappers around pydep methods 2 | 3 | """ 4 | 5 | import subprocess 6 | import sys 7 | import os 8 | import os.path 9 | import json 10 | 11 | import pydep.setup_py 12 | import pydep.req 13 | 14 | from typing import Any, List, Dict 15 | from operator import itemgetter 16 | 17 | def setup_dirs(rootdir: str) -> List[str]: 18 | return pydep.setup_py.setup_dirs(rootdir) 19 | 20 | # pydep_in_python2 uses Python2 to run pydep and returns parsed JSON object. 21 | def pydep_in_python2(cmd: str, dir: str) -> Any: 22 | rootdir = os.environ.get('SRCLIBPY_ROOTDIR') 23 | pydep = os.path.join(rootdir, ".env", "bin", "pydep-run.py") 24 | python = os.path.join(rootdir, ".env", "bin", "python2.7") 25 | process = subprocess.Popen([python, pydep, cmd, dir], stdout=subprocess.PIPE) 26 | out, err = process.communicate() 27 | if err is not None: 28 | raise Exception(err) 29 | data = json.loads(out.decode('utf-8')) 30 | return data 31 | 32 | def setup_info_dir(setup_dir: str) -> Any: 33 | try: 34 | info, err = pydep.setup_py.setup_info_dir(setup_dir) 35 | if err is not None: 36 | raise Exception(err) 37 | return info 38 | except SyntaxError as e: 39 | return pydep_in_python2("info", setup_dir) 40 | else: 41 | raise 42 | 43 | def requirements_from_requirements_txt(diry: str) -> List[Dict[str, Any]]: 44 | reqs, err = pydep.req.requirements_from_requirements_txt(diry) 45 | if err is not None: 46 | raise Exception(err) 47 | for r in reqs: 48 | if r.to_dict()['project_name'] == 'wsgiref': 49 | # Kludge: wsgiref's setup.py messes with sys.stdout, so should not be resolved 50 | continue 51 | try: 52 | r.resolve() 53 | except: 54 | sys.stderr.write('failed to resolve requirement {}\n'.format(r)) 55 | return sorted([r.to_dict() for r in reqs], key=itemgetter('key')) 56 | 57 | def requirements(pkgdir: str, resolve: bool) -> List[Dict[str, Any]]: 58 | try: 59 | pkgreqs, err = pydep.req.requirements(pkgdir, resolve) 60 | if err is not None: 61 | raise Exception(err) 62 | return sorted(pkgreqs, key=itemgetter('key')) 63 | except SyntaxError as e: 64 | pkgreqs = pydep_in_python2("dep", pkgdir) 65 | return sorted(pkgreqs, key=itemgetter('key')) 66 | else: 67 | raise 68 | -------------------------------------------------------------------------------- /grapher/builtin.py: -------------------------------------------------------------------------------- 1 | import glob # type: ignore (ignore strange redefinition of glob mypy error) 2 | import os 3 | import os.path 4 | import re 5 | import sys 6 | 7 | from .structures import * 8 | from .util import normalize 9 | 10 | module_def_pattern = re.compile(r'static struct PyModuleDef ([A-Za-z0-9_]+)module\s') 11 | 12 | class Builtin: 13 | def __init__( 14 | self, 15 | path: str, 16 | start: int, 17 | end: int, 18 | filename: str, 19 | ) -> None: 20 | self.path = path 21 | self.start = start 22 | self.end = end 23 | self.filename = normalize(filename) 24 | 25 | def __repr__(self) -> str: 26 | return 'Builtin{}'.format(self.__dict__) 27 | 28 | def to_def(self) -> Def: 29 | name = os.path.basename(self.path) 30 | return Def( 31 | Repo=BUILTIN_UNIT_KEY.Repo, 32 | Unit=BUILTIN_UNIT_KEY.Name, 33 | UnitType=BUILTIN_UNIT_KEY.Type, 34 | Path=self.path, 35 | Kind='', # TODO(beyang) 36 | Name=name, 37 | File=self.filename, 38 | DefStart=self.start, 39 | DefEnd=self.end, 40 | Exported=(not name.startswith('_')), 41 | Data=DefFormatData( 42 | Name=name, 43 | Keyword='', 44 | Type='', 45 | Kind='', 46 | Separator='', 47 | ), 48 | Builtin=True, 49 | ) 50 | 51 | def get_c_source_files(diry: str) -> List[str]: 52 | return glob.glob(os.path.join(diry, '**', '*.c'), recursive=True) # type: ignore (recursive=True) 53 | 54 | def find_modules(modules_dir) -> List[Builtin]: 55 | builtins = [] # type: List[Builtin] 56 | cfiles = get_c_source_files(modules_dir) 57 | 58 | for i, cfile in enumerate(cfiles): 59 | sys.stderr.write('processing file {}: {}/{}\n'.format(cfile, i, len(cfiles))) 60 | 61 | modules = [] 62 | with open(cfile) as f: 63 | text = f.read() 64 | matches = module_def_pattern.finditer(text) 65 | for match in matches: 66 | if match.group(1) == 'xx': # false positives 67 | continue 68 | modules.append(Builtin( 69 | path = match.group(1), 70 | start = match.start(1), 71 | end = match.end(1), 72 | filename = cfile, 73 | )) 74 | builtins.extend(modules) 75 | for module in modules: 76 | def_pattern = r'"({}(?:\.[A-Za-z0-9_]+)+)"'.format(module.path) 77 | for match in re.compile(def_pattern).finditer(text): 78 | path = match.group(1) 79 | if path.endswith('.c') or path.endswith('.h') or path == 'xx': # false positives 80 | continue 81 | builtins.append(Builtin( 82 | path = path, 83 | start = match.start(1), 84 | end = match.end(1), 85 | filename = cfile, 86 | )) 87 | return builtins 88 | -------------------------------------------------------------------------------- /testdata/expected/python-mock-stdlib/Python/PipPackage.graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "Defs": [ 3 | { 4 | "UnitType": "PipPackage", 5 | "Unit": "Python", 6 | "Path": "os.py/os._exists._exists", 7 | "Name": "_exists", 8 | "Kind": "function", 9 | "File": "Lib/os.py", 10 | "DefStart": 1134, 11 | "DefEnd": 1141, 12 | "Data": { 13 | "Keyword": "def", 14 | "Kind": "function", 15 | "Name": "_exists", 16 | "Separator": "", 17 | "Type": "(name)" 18 | } 19 | }, 20 | { 21 | "UnitType": "PipPackage", 22 | "Unit": "Python", 23 | "Path": "os.py/os._exists.name.name", 24 | "Name": "name", 25 | "Kind": "param", 26 | "File": "Lib/os.py", 27 | "DefStart": 1142, 28 | "DefEnd": 1146, 29 | "Exported": true, 30 | "Data": { 31 | "Keyword": "", 32 | "Kind": "param", 33 | "Name": "name", 34 | "Separator": "", 35 | "Type": "" 36 | } 37 | }, 38 | { 39 | "UnitType": "PipPackage", 40 | "Unit": "Python", 41 | "Path": "os.py/os.os", 42 | "Name": "os.py", 43 | "Kind": "module", 44 | "File": "Lib/os.py", 45 | "DefStart": 0, 46 | "DefEnd": 0, 47 | "Exported": true, 48 | "Data": { 49 | "Keyword": "module", 50 | "Kind": "module", 51 | "Name": "os", 52 | "Separator": "", 53 | "Type": "" 54 | } 55 | } 56 | ], 57 | "Refs": [ 58 | { 59 | "DefRepo": "github.com/python/cpython", 60 | "DefUnitType": "PipPackage", 61 | "DefUnit": "__builtin__", 62 | "DefPath": "globals", 63 | "UnitType": "PipPackage", 64 | "Unit": "Python", 65 | "File": "Lib/os.py", 66 | "Start": 1172, 67 | "End": 1179 68 | }, 69 | { 70 | "DefUnitType": "PipPackage", 71 | "DefUnit": "Python", 72 | "DefPath": "os.py/os._exists._exists", 73 | "UnitType": "PipPackage", 74 | "Unit": "Python", 75 | "Def": true, 76 | "File": "Lib/os.py", 77 | "Start": 1134, 78 | "End": 1141 79 | }, 80 | { 81 | "DefUnitType": "PipPackage", 82 | "DefUnit": "Python", 83 | "DefPath": "os.py/os._exists.name.name", 84 | "UnitType": "PipPackage", 85 | "Unit": "Python", 86 | "Def": true, 87 | "File": "Lib/os.py", 88 | "Start": 1142, 89 | "End": 1146 90 | }, 91 | { 92 | "DefUnitType": "PipPackage", 93 | "DefUnit": "Python", 94 | "DefPath": "os.py/os._exists.name.name", 95 | "UnitType": "PipPackage", 96 | "Unit": "Python", 97 | "File": "Lib/os.py", 98 | "Start": 1164, 99 | "End": 1168 100 | }, 101 | { 102 | "DefUnitType": "PipPackage", 103 | "DefUnit": "Python", 104 | "DefPath": "os.py/os.os", 105 | "UnitType": "PipPackage", 106 | "Unit": "Python", 107 | "Def": true, 108 | "File": "Lib/os.py", 109 | "Start": 0, 110 | "End": 0 111 | } 112 | ] 113 | } -------------------------------------------------------------------------------- /grapher/django.py: -------------------------------------------------------------------------------- 1 | from .structures import * 2 | from .util import normalize 3 | 4 | from . import pydepwrap 5 | 6 | import logging 7 | log = logging.getLogger('srclib-python.grapher.django') 8 | 9 | 10 | # find_units finds all Django application source units rooted at a directory. 11 | # 12 | # - diry is the root directoy at which to start the search. If this 13 | # directory also contains a requirements.txt file, its dependencies 14 | # will be included in all found source units. 15 | # - max_depth is the maximum recursion depth to search for units. 16 | def find_units(diry: str, max_depth: int = 5) -> List[Unit]: 17 | units = find_units_(diry, max_depth = max_depth) 18 | 19 | global_requirements = None # type: List[Dict] 20 | if os.path.isfile(os.path.join(diry, "requirements.txt")): 21 | global_requirements = pydepwrap.requirements_from_requirements_txt(diry) 22 | 23 | for unit in units: 24 | unit.Files = sorted(get_source_files(unit.Dir)) 25 | for i in range(len(unit.Files)): 26 | f = normalize(os.path.join(unit.Dir, unit.Files[i])) 27 | if f.startswith('./'): 28 | f = f[2:] 29 | unit.Files[i] = f 30 | 31 | reqs = [] # type: List[Dict] 32 | reqfiles = [] # type: List[str] 33 | if global_requirements is not None: 34 | reqs.extend(global_requirements) 35 | reqfiles.append(normalize(os.path.join(diry, "requirements.txt"))) 36 | try: 37 | reqs_ = pydepwrap.requirements_from_requirements_txt(unit.Dir) 38 | reqs.extend(reqs_) 39 | reqfiles.append(normalize(os.path.join(diry, "requirements.txt"))) 40 | except Exception as e: 41 | pass 42 | 43 | # Sort package and module lists for stable ordering 44 | for req in reqs: 45 | if 'packages' in req and isinstance(req['packages'], list): 46 | req['packages'] = sorted(req['packages']) 47 | if 'modules' in req and isinstance(req['modules'], list): 48 | req['modules'] = sorted(req['modules']) 49 | if 'py_modules' in req and isinstance(req['py_modules'], list): 50 | req['py_modules'] = sorted(req['py_modules']) 51 | 52 | deps = [] # type: List[UnitKey] 53 | for r in reqs: 54 | dep = pkgToUnitKey(r) 55 | if dep is not None: 56 | deps.append(dep) 57 | unit.Dependencies = deps 58 | unit.Data = Data(Reqs=[req for req in reqs if checkReq(req)], ReqFiles=reqfiles) 59 | 60 | return units 61 | 62 | # find_units_ is a recursive helper that generates the list of proto-units. 63 | def find_units_(diry: str, max_depth: int = 5) -> List[Unit]: 64 | if os.path.basename(diry) == "testdata": 65 | return [] # don't descend into testdata/ directory 66 | 67 | if max_depth < 0: return [] 68 | 69 | if os.path.isfile(os.path.join(diry, "manage.py")): 70 | return [Unit( 71 | Name = os.path.basename(os.path.abspath(diry)), 72 | Type = UNIT_DJANGO, 73 | Dir = normalize(diry), 74 | Files = None, 75 | Dependencies = None, 76 | Repo = None, 77 | CommitID = None, 78 | Version = None, 79 | Data = None, 80 | )] 81 | 82 | units = [] 83 | for entry in os.scandir(diry): # type: ignore (os.scandir exists) 84 | if entry.is_dir(): 85 | units.extend(find_units_(entry.path, max_depth = max_depth - 1)) 86 | return units 87 | -------------------------------------------------------------------------------- /grapher/graph.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | import logging 4 | import pip 5 | import os.path 6 | 7 | from subprocess import call 8 | 9 | from .structures import * 10 | from .file_grapher import FileGrapher, FileGrapherException 11 | from . import builtin 12 | 13 | def getModulePathPrefixToDep(u: Unit) -> Dict[str, UnitKey]: 14 | if not u.Data: 15 | return {} 16 | 17 | prefixToDep = {} 18 | for req in u.Data.Reqs: 19 | if req['repo_url']: 20 | repo, unit, unit_type = req['repo_url'], req['project_name'], UNIT_PIP 21 | else: 22 | repo, unit, unit_type = REPO_UNRESOLVED, req['project_name'], UNIT_PIP 23 | 24 | if req['packages'] is not None: 25 | for pkg in req['packages']: 26 | prefixToDep[pkg.replace('.', '/')] = UnitKey(Repo=repo, Name=unit, Type=unit_type, CommitID="", Version="") 27 | if req['modules'] is not None: 28 | for mod in req['modules']: 29 | prefixToDep[mod] = UnitKey(Repo=repo, Name=unit, Type=unit_type, CommitID="", Version="") 30 | 31 | # setuptools special case 32 | prefixToDep['setuptools'] = SETUPTOOLS_UNIT_KEY 33 | 34 | return prefixToDep 35 | 36 | def graph(args, fp) -> None: 37 | # Setup logging to stderr 38 | logger = logging.getLogger(__name__) 39 | handler = logging.StreamHandler() 40 | logger.addHandler(handler) 41 | logger.setLevel(logging.ERROR) 42 | if args.debug: 43 | logger.setLevel(logging.DEBUG) 44 | elif args.verbose: 45 | logger.setLevel(logging.INFO) 46 | elif args.quiet: 47 | logger.setLevel(logging.CRITICAL) 48 | 49 | u = fromJSONable(json.load(fp), Unit) # type: Unit 50 | graphunit(logger, args, u) 51 | 52 | def graphunit(logger, args, u: Unit) -> None: 53 | if u.key() == BUILTIN_UNIT_KEY: 54 | builtindefs = [b.to_def() for b in builtin.find_modules(u.Dir)] 55 | json.dump(toJSONable({ 56 | 'Defs': builtindefs, 57 | 'Refs': [d.defref() for d in builtindefs], 58 | 'Docs': [], 59 | }), sys.stdout, sort_keys=True) 60 | return 61 | 62 | if u.Dir is None or u.Dir == '': 63 | raise Exception('target directory must not be empty') 64 | 65 | if u.Type == UNIT_PIP: 66 | setupfile = os.path.join('.', u.Dir, 'setup.py') 67 | if os.path.lexists(setupfile): 68 | pip.main(['install', '-q', '--upgrade', os.path.join('.', u.Dir)]) 69 | 70 | if u.Data and u.Data.ReqFiles: 71 | for reqfile in u.Data.ReqFiles: 72 | if os.path.lexists(reqfile): 73 | pip.main(['install', '-q', '-r', reqfile]) 74 | 75 | prefixToDep = getModulePathPrefixToDep(u) 76 | 77 | defs = {} # type: Dict[str, Def] 78 | refs = {} # type: Dict[str, Ref] 79 | docs = {} # type: Dict[str, Doc] 80 | 81 | total = len(u.Files) 82 | for i, f in enumerate(u.Files, start=1): 83 | logger.info('processing file: {} ({}/{})'.format(f, i, total)) 84 | try: 85 | fg = FileGrapher(u.Dir, f, u.Name, u.Type, prefixToDep, sys.path, logger) 86 | defs_, refs_, docs_ = fg.graph() 87 | except FileGrapherException as e: 88 | logger.error('failed to graph {}: {}'.format(f, str(e))) 89 | continue 90 | except Exception as e: 91 | logger.error('failed to graph {} due to unanticipated error: {}'.format(f, str(e))) 92 | continue 93 | # Note: This uses last version of def/ref, but since file order is random anyway, 94 | # it should be OK. 95 | defs.update(defs_) 96 | refs.update(refs_) 97 | docs.update(docs_) 98 | 99 | json.dump(toJSONable({ 100 | 'Defs': [e for e in defs.values()], 101 | 'Refs': [e for e in refs.values()], 102 | 'Docs': [e for e in docs.values()], 103 | }), sys.stdout, sort_keys=True) 104 | -------------------------------------------------------------------------------- /testdata/expected/python-unresolved-reqstxt/python-unresolved-reqstxt/PipPackage.graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "Defs": [ 3 | { 4 | "UnitType": "PipPackage", 5 | "Unit": "python-unresolved-reqstxt", 6 | "Path": "mod123.py/mod123.mod123", 7 | "Name": "mod123.py", 8 | "Kind": "module", 9 | "File": "mod123.py", 10 | "DefStart": 0, 11 | "DefEnd": 0, 12 | "Exported": true, 13 | "Data": { 14 | "Keyword": "module", 15 | "Kind": "module", 16 | "Name": "mod123", 17 | "Separator": "", 18 | "Type": "" 19 | } 20 | }, 21 | { 22 | "UnitType": "PipPackage", 23 | "Unit": "python-unresolved-reqstxt", 24 | "Path": "setup.py/setup.setup", 25 | "Name": "setup.py", 26 | "Kind": "module", 27 | "File": "setup.py", 28 | "DefStart": 0, 29 | "DefEnd": 0, 30 | "Exported": true, 31 | "Data": { 32 | "Keyword": "module", 33 | "Kind": "module", 34 | "Name": "setup", 35 | "Separator": "", 36 | "Type": "" 37 | } 38 | } 39 | ], 40 | "Refs": [ 41 | { 42 | "DefUnitType": "PipPackage", 43 | "DefUnit": "python-unresolved-reqstxt", 44 | "DefPath": "mod123.py/mod123.mod123", 45 | "UnitType": "PipPackage", 46 | "Unit": "python-unresolved-reqstxt", 47 | "Def": true, 48 | "File": "mod123.py", 49 | "Start": 0, 50 | "End": 0 51 | }, 52 | { 53 | "DefUnitType": "PipPackage", 54 | "DefUnit": "python-unresolved-reqstxt", 55 | "DefPath": "setup.py/setup.name", 56 | "UnitType": "PipPackage", 57 | "Unit": "python-unresolved-reqstxt", 58 | "File": "setup.py", 59 | "Start": 41, 60 | "End": 45 61 | }, 62 | { 63 | "DefUnitType": "PipPackage", 64 | "DefUnit": "python-unresolved-reqstxt", 65 | "DefPath": "setup.py/setup.py_modules", 66 | "UnitType": "PipPackage", 67 | "Unit": "python-unresolved-reqstxt", 68 | "File": "setup.py", 69 | "Start": 157, 70 | "End": 167 71 | }, 72 | { 73 | "DefUnitType": "PipPackage", 74 | "DefUnit": "python-unresolved-reqstxt", 75 | "DefPath": "setup.py/setup.setup", 76 | "UnitType": "PipPackage", 77 | "Unit": "python-unresolved-reqstxt", 78 | "Def": true, 79 | "File": "setup.py", 80 | "Start": 0, 81 | "End": 0 82 | }, 83 | { 84 | "DefUnitType": "PipPackage", 85 | "DefUnit": "python-unresolved-reqstxt", 86 | "DefPath": "setup.py/setup.url", 87 | "UnitType": "PipPackage", 88 | "Unit": "python-unresolved-reqstxt", 89 | "File": "setup.py", 90 | "Start": 95, 91 | "End": 98 92 | }, 93 | { 94 | "DefUnitType": "PipPackage", 95 | "DefUnit": "python-unresolved-reqstxt", 96 | "DefPath": "setup.py/setup.version", 97 | "UnitType": "PipPackage", 98 | "Unit": "python-unresolved-reqstxt", 99 | "File": "setup.py", 100 | "Start": 79, 101 | "End": 86 102 | }, 103 | { 104 | "DefRepo": "github.com/pypa/setuptools", 105 | "DefUnitType": "PipPackage", 106 | "DefUnit": "setuptools", 107 | "DefPath": "setuptools/__init__.py/setuptools.setup", 108 | "UnitType": "PipPackage", 109 | "Unit": "python-unresolved-reqstxt", 110 | "File": "setup.py", 111 | "Start": 23, 112 | "End": 28 113 | }, 114 | { 115 | "DefRepo": "github.com/pypa/setuptools", 116 | "DefUnitType": "PipPackage", 117 | "DefUnit": "setuptools", 118 | "DefPath": "setuptools/__init__.py/setuptools.setup", 119 | "UnitType": "PipPackage", 120 | "Unit": "python-unresolved-reqstxt", 121 | "File": "setup.py", 122 | "Start": 30, 123 | "End": 35 124 | }, 125 | { 126 | "DefRepo": "github.com/pypa/setuptools", 127 | "DefUnitType": "PipPackage", 128 | "DefUnit": "setuptools", 129 | "DefPath": "setuptools/__init__.py/setuptools.setuptools", 130 | "UnitType": "PipPackage", 131 | "Unit": "python-unresolved-reqstxt", 132 | "File": "setup.py", 133 | "Start": 5, 134 | "End": 15 135 | } 136 | ] 137 | } -------------------------------------------------------------------------------- /testdata/expected/python-single-module-lib/single-module-lib/PipPackage.graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "Defs": [ 3 | { 4 | "UnitType": "PipPackage", 5 | "Unit": "single-module-lib", 6 | "Path": "mod.py/mod.mod", 7 | "Name": "mod.py", 8 | "Kind": "module", 9 | "File": "mod.py", 10 | "DefStart": 0, 11 | "DefEnd": 0, 12 | "Exported": true, 13 | "Data": { 14 | "Keyword": "module", 15 | "Kind": "module", 16 | "Name": "mod", 17 | "Separator": "", 18 | "Type": "" 19 | } 20 | }, 21 | { 22 | "UnitType": "PipPackage", 23 | "Unit": "single-module-lib", 24 | "Path": "setup.py/setup.setup", 25 | "Name": "setup.py", 26 | "Kind": "module", 27 | "File": "setup.py", 28 | "DefStart": 0, 29 | "DefEnd": 0, 30 | "Exported": true, 31 | "Data": { 32 | "Keyword": "module", 33 | "Kind": "module", 34 | "Name": "setup", 35 | "Separator": "", 36 | "Type": "" 37 | } 38 | } 39 | ], 40 | "Refs": [ 41 | { 42 | "DefUnitType": "PipPackage", 43 | "DefUnit": "single-module-lib", 44 | "DefPath": "mod.py/mod.mod", 45 | "UnitType": "PipPackage", 46 | "Unit": "single-module-lib", 47 | "Def": true, 48 | "File": "mod.py", 49 | "Start": 0, 50 | "End": 0 51 | }, 52 | { 53 | "DefUnitType": "PipPackage", 54 | "DefUnit": "single-module-lib", 55 | "DefPath": "setup.py/setup.install_requires", 56 | "UnitType": "PipPackage", 57 | "Unit": "single-module-lib", 58 | "File": "setup.py", 59 | "Start": 177, 60 | "End": 193 61 | }, 62 | { 63 | "DefUnitType": "PipPackage", 64 | "DefUnit": "single-module-lib", 65 | "DefPath": "setup.py/setup.name", 66 | "UnitType": "PipPackage", 67 | "Unit": "single-module-lib", 68 | "File": "setup.py", 69 | "Start": 41, 70 | "End": 45 71 | }, 72 | { 73 | "DefUnitType": "PipPackage", 74 | "DefUnit": "single-module-lib", 75 | "DefPath": "setup.py/setup.py_modules", 76 | "UnitType": "PipPackage", 77 | "Unit": "single-module-lib", 78 | "File": "setup.py", 79 | "Start": 153, 80 | "End": 163 81 | }, 82 | { 83 | "DefUnitType": "PipPackage", 84 | "DefUnit": "single-module-lib", 85 | "DefPath": "setup.py/setup.setup", 86 | "UnitType": "PipPackage", 87 | "Unit": "single-module-lib", 88 | "Def": true, 89 | "File": "setup.py", 90 | "Start": 0, 91 | "End": 0 92 | }, 93 | { 94 | "DefUnitType": "PipPackage", 95 | "DefUnit": "single-module-lib", 96 | "DefPath": "setup.py/setup.url", 97 | "UnitType": "PipPackage", 98 | "Unit": "single-module-lib", 99 | "File": "setup.py", 100 | "Start": 92, 101 | "End": 95 102 | }, 103 | { 104 | "DefUnitType": "PipPackage", 105 | "DefUnit": "single-module-lib", 106 | "DefPath": "setup.py/setup.version", 107 | "UnitType": "PipPackage", 108 | "Unit": "single-module-lib", 109 | "File": "setup.py", 110 | "Start": 71, 111 | "End": 78 112 | }, 113 | { 114 | "DefRepo": "github.com/pypa/setuptools", 115 | "DefUnitType": "PipPackage", 116 | "DefUnit": "setuptools", 117 | "DefPath": "setuptools/__init__.py/setuptools.setup", 118 | "UnitType": "PipPackage", 119 | "Unit": "single-module-lib", 120 | "File": "setup.py", 121 | "Start": 23, 122 | "End": 28 123 | }, 124 | { 125 | "DefRepo": "github.com/pypa/setuptools", 126 | "DefUnitType": "PipPackage", 127 | "DefUnit": "setuptools", 128 | "DefPath": "setuptools/__init__.py/setuptools.setup", 129 | "UnitType": "PipPackage", 130 | "Unit": "single-module-lib", 131 | "File": "setup.py", 132 | "Start": 30, 133 | "End": 35 134 | }, 135 | { 136 | "DefRepo": "github.com/pypa/setuptools", 137 | "DefUnitType": "PipPackage", 138 | "DefUnit": "setuptools", 139 | "DefPath": "setuptools/__init__.py/setuptools.setuptools", 140 | "UnitType": "PipPackage", 141 | "Unit": "single-module-lib", 142 | "File": "setup.py", 143 | "Start": 5, 144 | "End": 15 145 | } 146 | ] 147 | } -------------------------------------------------------------------------------- /testdata/expected/python-reqstxt-setuppy/python-reqstxt-setuppy/PipPackage.graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "Defs": [ 3 | { 4 | "UnitType": "PipPackage", 5 | "Unit": "python-reqstxt-setuppy", 6 | "Path": "mod123.py/mod123.mod123", 7 | "Name": "mod123.py", 8 | "Kind": "module", 9 | "File": "mod123.py", 10 | "DefStart": 0, 11 | "DefEnd": 0, 12 | "Exported": true, 13 | "Data": { 14 | "Keyword": "module", 15 | "Kind": "module", 16 | "Name": "mod123", 17 | "Separator": "", 18 | "Type": "" 19 | } 20 | }, 21 | { 22 | "UnitType": "PipPackage", 23 | "Unit": "python-reqstxt-setuppy", 24 | "Path": "setup.py/setup.setup", 25 | "Name": "setup.py", 26 | "Kind": "module", 27 | "File": "setup.py", 28 | "DefStart": 0, 29 | "DefEnd": 0, 30 | "Exported": true, 31 | "Data": { 32 | "Keyword": "module", 33 | "Kind": "module", 34 | "Name": "setup", 35 | "Separator": "", 36 | "Type": "" 37 | } 38 | } 39 | ], 40 | "Refs": [ 41 | { 42 | "DefUnitType": "PipPackage", 43 | "DefUnit": "python-reqstxt-setuppy", 44 | "DefPath": "mod123.py/mod123.mod123", 45 | "UnitType": "PipPackage", 46 | "Unit": "python-reqstxt-setuppy", 47 | "Def": true, 48 | "File": "mod123.py", 49 | "Start": 0, 50 | "End": 0 51 | }, 52 | { 53 | "DefUnitType": "PipPackage", 54 | "DefUnit": "python-reqstxt-setuppy", 55 | "DefPath": "setup.py/setup.install_requires", 56 | "UnitType": "PipPackage", 57 | "Unit": "python-reqstxt-setuppy", 58 | "File": "setup.py", 59 | "Start": 178, 60 | "End": 194 61 | }, 62 | { 63 | "DefUnitType": "PipPackage", 64 | "DefUnit": "python-reqstxt-setuppy", 65 | "DefPath": "setup.py/setup.name", 66 | "UnitType": "PipPackage", 67 | "Unit": "python-reqstxt-setuppy", 68 | "File": "setup.py", 69 | "Start": 41, 70 | "End": 45 71 | }, 72 | { 73 | "DefUnitType": "PipPackage", 74 | "DefUnit": "python-reqstxt-setuppy", 75 | "DefPath": "setup.py/setup.py_modules", 76 | "UnitType": "PipPackage", 77 | "Unit": "python-reqstxt-setuppy", 78 | "File": "setup.py", 79 | "Start": 151, 80 | "End": 161 81 | }, 82 | { 83 | "DefUnitType": "PipPackage", 84 | "DefUnit": "python-reqstxt-setuppy", 85 | "DefPath": "setup.py/setup.setup", 86 | "UnitType": "PipPackage", 87 | "Unit": "python-reqstxt-setuppy", 88 | "Def": true, 89 | "File": "setup.py", 90 | "Start": 0, 91 | "End": 0 92 | }, 93 | { 94 | "DefUnitType": "PipPackage", 95 | "DefUnit": "python-reqstxt-setuppy", 96 | "DefPath": "setup.py/setup.url", 97 | "UnitType": "PipPackage", 98 | "Unit": "python-reqstxt-setuppy", 99 | "File": "setup.py", 100 | "Start": 92, 101 | "End": 95 102 | }, 103 | { 104 | "DefUnitType": "PipPackage", 105 | "DefUnit": "python-reqstxt-setuppy", 106 | "DefPath": "setup.py/setup.version", 107 | "UnitType": "PipPackage", 108 | "Unit": "python-reqstxt-setuppy", 109 | "File": "setup.py", 110 | "Start": 76, 111 | "End": 83 112 | }, 113 | { 114 | "DefRepo": "github.com/pypa/setuptools", 115 | "DefUnitType": "PipPackage", 116 | "DefUnit": "setuptools", 117 | "DefPath": "setuptools/__init__.py/setuptools.setup", 118 | "UnitType": "PipPackage", 119 | "Unit": "python-reqstxt-setuppy", 120 | "File": "setup.py", 121 | "Start": 23, 122 | "End": 28 123 | }, 124 | { 125 | "DefRepo": "github.com/pypa/setuptools", 126 | "DefUnitType": "PipPackage", 127 | "DefUnit": "setuptools", 128 | "DefPath": "setuptools/__init__.py/setuptools.setup", 129 | "UnitType": "PipPackage", 130 | "Unit": "python-reqstxt-setuppy", 131 | "File": "setup.py", 132 | "Start": 30, 133 | "End": 35 134 | }, 135 | { 136 | "DefRepo": "github.com/pypa/setuptools", 137 | "DefUnitType": "PipPackage", 138 | "DefUnit": "setuptools", 139 | "DefPath": "setuptools/__init__.py/setuptools.setuptools", 140 | "UnitType": "PipPackage", 141 | "Unit": "python-reqstxt-setuppy", 142 | "File": "setup.py", 143 | "Start": 5, 144 | "End": 15 145 | } 146 | ] 147 | } -------------------------------------------------------------------------------- /testdata/expected/python-no-url/python-no-uri/PipPackage.graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "Defs": [ 3 | { 4 | "UnitType": "PipPackage", 5 | "Unit": "python-no-uri", 6 | "Path": "mod0.py/mod0.foo.foo", 7 | "Name": "foo", 8 | "Kind": "function", 9 | "File": "mod0.py", 10 | "DefStart": 4, 11 | "DefEnd": 7, 12 | "Exported": true, 13 | "Data": { 14 | "Keyword": "def", 15 | "Kind": "function", 16 | "Name": "foo", 17 | "Separator": "", 18 | "Type": "()" 19 | } 20 | }, 21 | { 22 | "UnitType": "PipPackage", 23 | "Unit": "python-no-uri", 24 | "Path": "mod0.py/mod0.mod0", 25 | "Name": "mod0.py", 26 | "Kind": "module", 27 | "File": "mod0.py", 28 | "DefStart": 0, 29 | "DefEnd": 0, 30 | "Exported": true, 31 | "Data": { 32 | "Keyword": "module", 33 | "Kind": "module", 34 | "Name": "mod0", 35 | "Separator": "", 36 | "Type": "" 37 | } 38 | }, 39 | { 40 | "UnitType": "PipPackage", 41 | "Unit": "python-no-uri", 42 | "Path": "setup.py/setup.setup", 43 | "Name": "setup.py", 44 | "Kind": "module", 45 | "File": "setup.py", 46 | "DefStart": 0, 47 | "DefEnd": 0, 48 | "Exported": true, 49 | "Data": { 50 | "Keyword": "module", 51 | "Kind": "module", 52 | "Name": "setup", 53 | "Separator": "", 54 | "Type": "" 55 | } 56 | } 57 | ], 58 | "Refs": [ 59 | { 60 | "DefUnitType": "PipPackage", 61 | "DefUnit": "python-no-uri", 62 | "DefPath": "mod0.py/mod0.foo.foo", 63 | "UnitType": "PipPackage", 64 | "Unit": "python-no-uri", 65 | "Def": true, 66 | "File": "mod0.py", 67 | "Start": 4, 68 | "End": 7 69 | }, 70 | { 71 | "DefUnitType": "PipPackage", 72 | "DefUnit": "python-no-uri", 73 | "DefPath": "mod0.py/mod0.mod0", 74 | "UnitType": "PipPackage", 75 | "Unit": "python-no-uri", 76 | "Def": true, 77 | "File": "mod0.py", 78 | "Start": 0, 79 | "End": 0 80 | }, 81 | { 82 | "DefUnitType": "PipPackage", 83 | "DefUnit": "python-no-uri", 84 | "DefPath": "setup.py/setup.install_requires", 85 | "UnitType": "PipPackage", 86 | "Unit": "python-no-uri", 87 | "File": "setup.py", 88 | "Start": 113, 89 | "End": 129 90 | }, 91 | { 92 | "DefUnitType": "PipPackage", 93 | "DefUnit": "python-no-uri", 94 | "DefPath": "setup.py/setup.name", 95 | "UnitType": "PipPackage", 96 | "Unit": "python-no-uri", 97 | "File": "setup.py", 98 | "Start": 41, 99 | "End": 45 100 | }, 101 | { 102 | "DefUnitType": "PipPackage", 103 | "DefUnit": "python-no-uri", 104 | "DefPath": "setup.py/setup.py_modules", 105 | "UnitType": "PipPackage", 106 | "Unit": "python-no-uri", 107 | "File": "setup.py", 108 | "Start": 88, 109 | "End": 98 110 | }, 111 | { 112 | "DefUnitType": "PipPackage", 113 | "DefUnit": "python-no-uri", 114 | "DefPath": "setup.py/setup.setup", 115 | "UnitType": "PipPackage", 116 | "Unit": "python-no-uri", 117 | "Def": true, 118 | "File": "setup.py", 119 | "Start": 0, 120 | "End": 0 121 | }, 122 | { 123 | "DefUnitType": "PipPackage", 124 | "DefUnit": "python-no-uri", 125 | "DefPath": "setup.py/setup.version", 126 | "UnitType": "PipPackage", 127 | "Unit": "python-no-uri", 128 | "File": "setup.py", 129 | "Start": 67, 130 | "End": 74 131 | }, 132 | { 133 | "DefRepo": "github.com/pypa/setuptools", 134 | "DefUnitType": "PipPackage", 135 | "DefUnit": "setuptools", 136 | "DefPath": "setuptools/__init__.py/setuptools.setup", 137 | "UnitType": "PipPackage", 138 | "Unit": "python-no-uri", 139 | "File": "setup.py", 140 | "Start": 23, 141 | "End": 28 142 | }, 143 | { 144 | "DefRepo": "github.com/pypa/setuptools", 145 | "DefUnitType": "PipPackage", 146 | "DefUnit": "setuptools", 147 | "DefPath": "setuptools/__init__.py/setuptools.setup", 148 | "UnitType": "PipPackage", 149 | "Unit": "python-no-uri", 150 | "File": "setup.py", 151 | "Start": 30, 152 | "End": 35 153 | }, 154 | { 155 | "DefRepo": "github.com/pypa/setuptools", 156 | "DefUnitType": "PipPackage", 157 | "DefUnit": "setuptools", 158 | "DefPath": "setuptools/__init__.py/setuptools.setuptools", 159 | "UnitType": "PipPackage", 160 | "Unit": "python-no-uri", 161 | "File": "setup.py", 162 | "Start": 5, 163 | "End": 15 164 | } 165 | ] 166 | } -------------------------------------------------------------------------------- /testdata/expected/python-single-module-dependent/single-module-dependent/PipPackage.graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "Defs": [ 3 | { 4 | "UnitType": "PipPackage", 5 | "Unit": "single-module-dependent", 6 | "Path": "app.py/app.app", 7 | "Name": "app.py", 8 | "Kind": "module", 9 | "File": "app.py", 10 | "DefStart": 0, 11 | "DefEnd": 0, 12 | "Exported": true, 13 | "Data": { 14 | "Keyword": "module", 15 | "Kind": "module", 16 | "Name": "app", 17 | "Separator": "", 18 | "Type": "" 19 | } 20 | }, 21 | { 22 | "UnitType": "PipPackage", 23 | "Unit": "single-module-dependent", 24 | "Path": "setup.py/setup.setup", 25 | "Name": "setup.py", 26 | "Kind": "module", 27 | "File": "setup.py", 28 | "DefStart": 0, 29 | "DefEnd": 0, 30 | "Exported": true, 31 | "Data": { 32 | "Keyword": "module", 33 | "Kind": "module", 34 | "Name": "setup", 35 | "Separator": "", 36 | "Type": "" 37 | } 38 | } 39 | ], 40 | "Refs": [ 41 | { 42 | "DefUnitType": "PipPackage", 43 | "DefUnit": "single-module-dependent", 44 | "DefPath": "app.py/app.app", 45 | "UnitType": "PipPackage", 46 | "Unit": "single-module-dependent", 47 | "Def": true, 48 | "File": "app.py", 49 | "Start": 0, 50 | "End": 0 51 | }, 52 | { 53 | "DefUnitType": "PipPackage", 54 | "DefUnit": "single-module-dependent", 55 | "DefPath": "app.py/app.mod", 56 | "UnitType": "PipPackage", 57 | "Unit": "single-module-dependent", 58 | "File": "app.py", 59 | "Start": 18, 60 | "End": 21 61 | }, 62 | { 63 | "DefRepo": "github.com/sgtest/python-single-module-lib", 64 | "DefUnitType": "PipPackage", 65 | "DefUnit": "single-module-lib", 66 | "DefPath": "mod.py/mod.mod", 67 | "UnitType": "PipPackage", 68 | "Unit": "single-module-dependent", 69 | "File": "app.py", 70 | "Start": 7, 71 | "End": 10 72 | }, 73 | { 74 | "DefRepo": "github.com/python/cpython", 75 | "DefUnitType": "PipPackage", 76 | "DefUnit": "__builtin__", 77 | "DefPath": "print", 78 | "UnitType": "PipPackage", 79 | "Unit": "single-module-dependent", 80 | "File": "app.py", 81 | "Start": 12, 82 | "End": 17 83 | }, 84 | { 85 | "DefUnitType": "PipPackage", 86 | "DefUnit": "single-module-dependent", 87 | "DefPath": "setup.py/setup.name", 88 | "UnitType": "PipPackage", 89 | "Unit": "single-module-dependent", 90 | "File": "setup.py", 91 | "Start": 41, 92 | "End": 45 93 | }, 94 | { 95 | "DefUnitType": "PipPackage", 96 | "DefUnit": "single-module-dependent", 97 | "DefPath": "setup.py/setup.py_modules", 98 | "UnitType": "PipPackage", 99 | "Unit": "single-module-dependent", 100 | "File": "setup.py", 101 | "Start": 98, 102 | "End": 108 103 | }, 104 | { 105 | "DefUnitType": "PipPackage", 106 | "DefUnit": "single-module-dependent", 107 | "DefPath": "setup.py/setup.setup", 108 | "UnitType": "PipPackage", 109 | "Unit": "single-module-dependent", 110 | "Def": true, 111 | "File": "setup.py", 112 | "Start": 0, 113 | "End": 0 114 | }, 115 | { 116 | "DefUnitType": "PipPackage", 117 | "DefUnit": "single-module-dependent", 118 | "DefPath": "setup.py/setup.url", 119 | "UnitType": "PipPackage", 120 | "Unit": "single-module-dependent", 121 | "File": "setup.py", 122 | "Start": 122, 123 | "End": 125 124 | }, 125 | { 126 | "DefUnitType": "PipPackage", 127 | "DefUnit": "single-module-dependent", 128 | "DefPath": "setup.py/setup.version", 129 | "UnitType": "PipPackage", 130 | "Unit": "single-module-dependent", 131 | "File": "setup.py", 132 | "Start": 77, 133 | "End": 84 134 | }, 135 | { 136 | "DefRepo": "github.com/pypa/setuptools", 137 | "DefUnitType": "PipPackage", 138 | "DefUnit": "setuptools", 139 | "DefPath": "setuptools/__init__.py/setuptools.setup", 140 | "UnitType": "PipPackage", 141 | "Unit": "single-module-dependent", 142 | "File": "setup.py", 143 | "Start": 23, 144 | "End": 28 145 | }, 146 | { 147 | "DefRepo": "github.com/pypa/setuptools", 148 | "DefUnitType": "PipPackage", 149 | "DefUnit": "setuptools", 150 | "DefPath": "setuptools/__init__.py/setuptools.setup", 151 | "UnitType": "PipPackage", 152 | "Unit": "single-module-dependent", 153 | "File": "setup.py", 154 | "Start": 30, 155 | "End": 35 156 | }, 157 | { 158 | "DefRepo": "github.com/pypa/setuptools", 159 | "DefUnitType": "PipPackage", 160 | "DefUnit": "setuptools", 161 | "DefPath": "setuptools/__init__.py/setuptools.setuptools", 162 | "UnitType": "PipPackage", 163 | "Unit": "single-module-dependent", 164 | "File": "setup.py", 165 | "Start": 5, 166 | "End": 15 167 | } 168 | ] 169 | } -------------------------------------------------------------------------------- /testdata/expected/python-sample-2/python-sample-2/PipPackage.graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "Defs": [ 3 | { 4 | "UnitType": "PipPackage", 5 | "Unit": "python-sample-2", 6 | "Path": "app/__init__.py/app.app", 7 | "Name": "app", 8 | "Kind": "module", 9 | "File": "app/__init__.py", 10 | "DefStart": 0, 11 | "DefEnd": 0, 12 | "Exported": true, 13 | "Data": { 14 | "Keyword": "package", 15 | "Kind": "package", 16 | "Name": "app", 17 | "Separator": "", 18 | "Type": "" 19 | } 20 | }, 21 | { 22 | "UnitType": "PipPackage", 23 | "Unit": "python-sample-2", 24 | "Path": "app/app.py/app.app.app", 25 | "Name": "app.py", 26 | "Kind": "module", 27 | "File": "app/app.py", 28 | "DefStart": 0, 29 | "DefEnd": 0, 30 | "Exported": true, 31 | "Data": { 32 | "Keyword": "module", 33 | "Kind": "module", 34 | "Name": "app.app", 35 | "Separator": "", 36 | "Type": "" 37 | } 38 | }, 39 | { 40 | "UnitType": "PipPackage", 41 | "Unit": "python-sample-2", 42 | "Path": "setup.py/setup.setup", 43 | "Name": "setup.py", 44 | "Kind": "module", 45 | "File": "setup.py", 46 | "DefStart": 0, 47 | "DefEnd": 0, 48 | "Exported": true, 49 | "Data": { 50 | "Keyword": "module", 51 | "Kind": "module", 52 | "Name": "setup", 53 | "Separator": "", 54 | "Type": "" 55 | } 56 | } 57 | ], 58 | "Refs": [ 59 | { 60 | "DefUnitType": "PipPackage", 61 | "DefUnit": "python-sample-2", 62 | "DefPath": "app/__init__.py/app.app", 63 | "UnitType": "PipPackage", 64 | "Unit": "python-sample-2", 65 | "Def": true, 66 | "File": "app/__init__.py", 67 | "Start": 0, 68 | "End": 0 69 | }, 70 | { 71 | "DefUnitType": "PipPackage", 72 | "DefUnit": "python-sample-2", 73 | "DefPath": "app/app.py/app.app.app", 74 | "UnitType": "PipPackage", 75 | "Unit": "python-sample-2", 76 | "Def": true, 77 | "File": "app/app.py", 78 | "Start": 0, 79 | "End": 0 80 | }, 81 | { 82 | "DefRepo": "?", 83 | "DefUnitType": "PipPackage", 84 | "DefUnit": "requests", 85 | "DefPath": "requests/__init__.py/requests.requests", 86 | "UnitType": "PipPackage", 87 | "Unit": "python-sample-2", 88 | "File": "app/app.py", 89 | "Start": 7, 90 | "End": 15 91 | }, 92 | { 93 | "DefUnitType": "PipPackage", 94 | "DefUnit": "python-sample-2", 95 | "DefPath": "setup.py/setup.name", 96 | "UnitType": "PipPackage", 97 | "Unit": "python-sample-2", 98 | "File": "setup.py", 99 | "Start": 41, 100 | "End": 45 101 | }, 102 | { 103 | "DefUnitType": "PipPackage", 104 | "DefUnit": "python-sample-2", 105 | "DefPath": "setup.py/setup.packages", 106 | "UnitType": "PipPackage", 107 | "Unit": "python-sample-2", 108 | "File": "setup.py", 109 | "Start": 143, 110 | "End": 151 111 | }, 112 | { 113 | "DefUnitType": "PipPackage", 114 | "DefUnit": "python-sample-2", 115 | "DefPath": "setup.py/setup.setup", 116 | "UnitType": "PipPackage", 117 | "Unit": "python-sample-2", 118 | "Def": true, 119 | "File": "setup.py", 120 | "Start": 0, 121 | "End": 0 122 | }, 123 | { 124 | "DefUnitType": "PipPackage", 125 | "DefUnit": "python-sample-2", 126 | "DefPath": "setup.py/setup.url", 127 | "UnitType": "PipPackage", 128 | "Unit": "python-sample-2", 129 | "File": "setup.py", 130 | "Start": 90, 131 | "End": 93 132 | }, 133 | { 134 | "DefUnitType": "PipPackage", 135 | "DefUnit": "python-sample-2", 136 | "DefPath": "setup.py/setup.version", 137 | "UnitType": "PipPackage", 138 | "Unit": "python-sample-2", 139 | "File": "setup.py", 140 | "Start": 69, 141 | "End": 76 142 | }, 143 | { 144 | "DefRepo": "github.com/pypa/setuptools", 145 | "DefUnitType": "PipPackage", 146 | "DefUnit": "setuptools", 147 | "DefPath": "setuptools/__init__.py/setuptools.setup", 148 | "UnitType": "PipPackage", 149 | "Unit": "python-sample-2", 150 | "File": "setup.py", 151 | "Start": 23, 152 | "End": 28 153 | }, 154 | { 155 | "DefRepo": "github.com/pypa/setuptools", 156 | "DefUnitType": "PipPackage", 157 | "DefUnit": "setuptools", 158 | "DefPath": "setuptools/__init__.py/setuptools.setup", 159 | "UnitType": "PipPackage", 160 | "Unit": "python-sample-2", 161 | "File": "setup.py", 162 | "Start": 30, 163 | "End": 35 164 | }, 165 | { 166 | "DefRepo": "github.com/pypa/setuptools", 167 | "DefUnitType": "PipPackage", 168 | "DefUnit": "setuptools", 169 | "DefPath": "setuptools/__init__.py/setuptools.setuptools", 170 | "UnitType": "PipPackage", 171 | "Unit": "python-sample-2", 172 | "File": "setup.py", 173 | "Start": 5, 174 | "End": 15 175 | } 176 | ] 177 | } -------------------------------------------------------------------------------- /testdata/expected/python-django-app/myproject/DjangoApp.unit.json: -------------------------------------------------------------------------------- 1 | {"Name":"myproject","Type":"DjangoApp","Files":["myproject/manage.py","myproject/myapp/__init__.py","myproject/myapp/admin.py","myproject/myapp/apps.py","myproject/myapp/migrations/__init__.py","myproject/myapp/models.py","myproject/myapp/tests.py","myproject/myapp/urls.py","myproject/myapp/views.py","myproject/myproject/__init__.py","myproject/myproject/settings.py","myproject/myproject/urls.py","myproject/myproject/wsgi.py"],"Dir":"./myproject","Dependencies":[{"Repo":"?","Type":"PipPackage","Name":"Django"},{"Repo":"github.com/pypa/setuptools","Type":"PipPackage","Name":"setuptools"}],"Data":{"ReqFiles":["./requirements.txt"],"Reqs":[{"extras":{},"key":"django","modules":null,"packages":["django","django.apps","django.conf","django.conf.locale","django.conf.locale.ar","django.conf.locale.az","django.conf.locale.bg","django.conf.locale.bn","django.conf.locale.bs","django.conf.locale.ca","django.conf.locale.cs","django.conf.locale.cy","django.conf.locale.da","django.conf.locale.de","django.conf.locale.de_CH","django.conf.locale.el","django.conf.locale.en","django.conf.locale.en_AU","django.conf.locale.en_GB","django.conf.locale.eo","django.conf.locale.es","django.conf.locale.es_AR","django.conf.locale.es_CO","django.conf.locale.es_MX","django.conf.locale.es_NI","django.conf.locale.es_PR","django.conf.locale.et","django.conf.locale.eu","django.conf.locale.fa","django.conf.locale.fi","django.conf.locale.fr","django.conf.locale.fy","django.conf.locale.ga","django.conf.locale.gd","django.conf.locale.gl","django.conf.locale.he","django.conf.locale.hi","django.conf.locale.hr","django.conf.locale.hu","django.conf.locale.id","django.conf.locale.is","django.conf.locale.it","django.conf.locale.ja","django.conf.locale.ka","django.conf.locale.km","django.conf.locale.kn","django.conf.locale.ko","django.conf.locale.lt","django.conf.locale.lv","django.conf.locale.mk","django.conf.locale.ml","django.conf.locale.mn","django.conf.locale.nb","django.conf.locale.nl","django.conf.locale.nn","django.conf.locale.pl","django.conf.locale.pt","django.conf.locale.pt_BR","django.conf.locale.ro","django.conf.locale.ru","django.conf.locale.sk","django.conf.locale.sl","django.conf.locale.sq","django.conf.locale.sr","django.conf.locale.sr_Latn","django.conf.locale.sv","django.conf.locale.ta","django.conf.locale.te","django.conf.locale.th","django.conf.locale.tr","django.conf.locale.uk","django.conf.locale.vi","django.conf.locale.zh_Hans","django.conf.locale.zh_Hant","django.conf.urls","django.contrib","django.contrib.admin","django.contrib.admin.migrations","django.contrib.admin.templatetags","django.contrib.admin.views","django.contrib.admindocs","django.contrib.admindocs.tests","django.contrib.auth","django.contrib.auth.handlers","django.contrib.auth.management","django.contrib.auth.management.commands","django.contrib.auth.migrations","django.contrib.auth.tests","django.contrib.contenttypes","django.contrib.contenttypes.migrations","django.contrib.flatpages","django.contrib.flatpages.migrations","django.contrib.flatpages.templatetags","django.contrib.gis","django.contrib.gis.admin","django.contrib.gis.db","django.contrib.gis.db.backends","django.contrib.gis.db.backends.base","django.contrib.gis.db.backends.mysql","django.contrib.gis.db.backends.oracle","django.contrib.gis.db.backends.postgis","django.contrib.gis.db.backends.spatialite","django.contrib.gis.db.models","django.contrib.gis.db.models.sql","django.contrib.gis.forms","django.contrib.gis.gdal","django.contrib.gis.gdal.prototypes","django.contrib.gis.gdal.raster","django.contrib.gis.geoip","django.contrib.gis.geoip2","django.contrib.gis.geometry","django.contrib.gis.geometry.backend","django.contrib.gis.geos","django.contrib.gis.geos.prototypes","django.contrib.gis.management","django.contrib.gis.management.commands","django.contrib.gis.maps","django.contrib.gis.maps.google","django.contrib.gis.maps.openlayers","django.contrib.gis.serializers","django.contrib.gis.sitemaps","django.contrib.gis.utils","django.contrib.humanize","django.contrib.humanize.templatetags","django.contrib.messages","django.contrib.messages.storage","django.contrib.postgres","django.contrib.postgres.aggregates","django.contrib.postgres.fields","django.contrib.postgres.forms","django.contrib.redirects","django.contrib.redirects.migrations","django.contrib.sessions","django.contrib.sessions.backends","django.contrib.sessions.management","django.contrib.sessions.management.commands","django.contrib.sessions.migrations","django.contrib.sitemaps","django.contrib.sitemaps.management","django.contrib.sitemaps.management.commands","django.contrib.sites","django.contrib.sites.migrations","django.contrib.staticfiles","django.contrib.staticfiles.management","django.contrib.staticfiles.management.commands","django.contrib.staticfiles.templatetags","django.contrib.syndication","django.contrib.webdesign","django.contrib.webdesign.templatetags","django.core","django.core.cache","django.core.cache.backends","django.core.checks","django.core.checks.compatibility","django.core.checks.security","django.core.files","django.core.handlers","django.core.mail","django.core.mail.backends","django.core.management","django.core.management.commands","django.core.serializers","django.core.servers","django.db","django.db.backends","django.db.backends.base","django.db.backends.dummy","django.db.backends.mysql","django.db.backends.oracle","django.db.backends.postgresql","django.db.backends.postgresql_psycopg2","django.db.backends.sqlite3","django.db.migrations","django.db.migrations.operations","django.db.models","django.db.models.fields","django.db.models.sql","django.dispatch","django.forms","django.forms.extras","django.http","django.middleware","django.template","django.template.backends","django.template.loaders","django.templatetags","django.test","django.utils","django.utils.translation","django.views","django.views.decorators","django.views.generic"],"project_name":"Django","repo_url":null,"resolved":true,"specs":[{}],"type":"setuptools","unsafe_name":"Django"}]}} 2 | -------------------------------------------------------------------------------- /testdata/expected/python-link-tests/python-link-tests/PipPackage.graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "Defs": [ 3 | { 4 | "UnitType": "PipPackage", 5 | "Unit": "python-link-tests", 6 | "Path": "pkg0/__init__.py/pkg0.pkg0", 7 | "Name": "pkg0", 8 | "Kind": "module", 9 | "File": "app/pkg0/__init__.py", 10 | "DefStart": 0, 11 | "DefEnd": 0, 12 | "Exported": true, 13 | "Data": { 14 | "Keyword": "package", 15 | "Kind": "package", 16 | "Name": "pkg0", 17 | "Separator": "", 18 | "Type": "" 19 | } 20 | }, 21 | { 22 | "UnitType": "PipPackage", 23 | "Unit": "python-link-tests", 24 | "Path": "pkg0/m0.py/m0.foo.foo", 25 | "Name": "foo", 26 | "Kind": "function", 27 | "File": "app/pkg0/m0.py", 28 | "DefStart": 4, 29 | "DefEnd": 7, 30 | "Exported": true, 31 | "Data": { 32 | "Keyword": "def", 33 | "Kind": "function", 34 | "Name": "foo", 35 | "Separator": "", 36 | "Type": "()" 37 | } 38 | }, 39 | { 40 | "UnitType": "PipPackage", 41 | "Unit": "python-link-tests", 42 | "Path": "pkg0/m0.py/pkg0.m0.m0", 43 | "Name": "m0.py", 44 | "Kind": "module", 45 | "File": "app/pkg0/m0.py", 46 | "DefStart": 0, 47 | "DefEnd": 0, 48 | "Exported": true, 49 | "Data": { 50 | "Keyword": "module", 51 | "Kind": "module", 52 | "Name": "pkg0.m0", 53 | "Separator": "", 54 | "Type": "" 55 | } 56 | }, 57 | { 58 | "UnitType": "PipPackage", 59 | "Unit": "python-link-tests", 60 | "Path": "setup.py/setup.setup", 61 | "Name": "setup.py", 62 | "Kind": "module", 63 | "File": "app/setup.py", 64 | "DefStart": 0, 65 | "DefEnd": 0, 66 | "Exported": true, 67 | "Data": { 68 | "Keyword": "module", 69 | "Kind": "module", 70 | "Name": "setup", 71 | "Separator": "", 72 | "Type": "" 73 | } 74 | } 75 | ], 76 | "Refs": [ 77 | { 78 | "DefUnitType": "PipPackage", 79 | "DefUnit": "python-link-tests", 80 | "DefPath": "pkg0/__init__.py/pkg0.pkg0", 81 | "UnitType": "PipPackage", 82 | "Unit": "python-link-tests", 83 | "Def": true, 84 | "File": "app/pkg0/__init__.py", 85 | "Start": 0, 86 | "End": 0 87 | }, 88 | { 89 | "DefUnitType": "PipPackage", 90 | "DefUnit": "python-link-tests", 91 | "DefPath": "pkg0/m0.py/m0.foo.foo", 92 | "UnitType": "PipPackage", 93 | "Unit": "python-link-tests", 94 | "Def": true, 95 | "File": "app/pkg0/m0.py", 96 | "Start": 4, 97 | "End": 7 98 | }, 99 | { 100 | "DefUnitType": "PipPackage", 101 | "DefUnit": "python-link-tests", 102 | "DefPath": "pkg0/m0.py/pkg0.m0.m0", 103 | "UnitType": "PipPackage", 104 | "Unit": "python-link-tests", 105 | "Def": true, 106 | "File": "app/pkg0/m0.py", 107 | "Start": 0, 108 | "End": 0 109 | }, 110 | { 111 | "DefUnitType": "PipPackage", 112 | "DefUnit": "python-link-tests", 113 | "DefPath": "setup.py/setup.install_requires", 114 | "UnitType": "PipPackage", 115 | "Unit": "python-link-tests", 116 | "File": "app/setup.py", 117 | "Start": 169, 118 | "End": 185 119 | }, 120 | { 121 | "DefUnitType": "PipPackage", 122 | "DefUnit": "python-link-tests", 123 | "DefPath": "setup.py/setup.name", 124 | "UnitType": "PipPackage", 125 | "Unit": "python-link-tests", 126 | "File": "app/setup.py", 127 | "Start": 41, 128 | "End": 45 129 | }, 130 | { 131 | "DefUnitType": "PipPackage", 132 | "DefUnit": "python-link-tests", 133 | "DefPath": "setup.py/setup.packages", 134 | "UnitType": "PipPackage", 135 | "Unit": "python-link-tests", 136 | "File": "app/setup.py", 137 | "Start": 146, 138 | "End": 154 139 | }, 140 | { 141 | "DefUnitType": "PipPackage", 142 | "DefUnit": "python-link-tests", 143 | "DefPath": "setup.py/setup.setup", 144 | "UnitType": "PipPackage", 145 | "Unit": "python-link-tests", 146 | "Def": true, 147 | "File": "app/setup.py", 148 | "Start": 0, 149 | "End": 0 150 | }, 151 | { 152 | "DefUnitType": "PipPackage", 153 | "DefUnit": "python-link-tests", 154 | "DefPath": "setup.py/setup.url", 155 | "UnitType": "PipPackage", 156 | "Unit": "python-link-tests", 157 | "File": "app/setup.py", 158 | "Start": 92, 159 | "End": 95 160 | }, 161 | { 162 | "DefUnitType": "PipPackage", 163 | "DefUnit": "python-link-tests", 164 | "DefPath": "setup.py/setup.version", 165 | "UnitType": "PipPackage", 166 | "Unit": "python-link-tests", 167 | "File": "app/setup.py", 168 | "Start": 71, 169 | "End": 78 170 | }, 171 | { 172 | "DefRepo": "github.com/pypa/setuptools", 173 | "DefUnitType": "PipPackage", 174 | "DefUnit": "setuptools", 175 | "DefPath": "setuptools/__init__.py/setuptools.setup", 176 | "UnitType": "PipPackage", 177 | "Unit": "python-link-tests", 178 | "File": "app/setup.py", 179 | "Start": 23, 180 | "End": 28 181 | }, 182 | { 183 | "DefRepo": "github.com/pypa/setuptools", 184 | "DefUnitType": "PipPackage", 185 | "DefUnit": "setuptools", 186 | "DefPath": "setuptools/__init__.py/setuptools.setup", 187 | "UnitType": "PipPackage", 188 | "Unit": "python-link-tests", 189 | "File": "app/setup.py", 190 | "Start": 30, 191 | "End": 35 192 | }, 193 | { 194 | "DefRepo": "github.com/pypa/setuptools", 195 | "DefUnitType": "PipPackage", 196 | "DefUnit": "setuptools", 197 | "DefPath": "setuptools/__init__.py/setuptools.setuptools", 198 | "UnitType": "PipPackage", 199 | "Unit": "python-link-tests", 200 | "File": "app/setup.py", 201 | "Start": 5, 202 | "End": 15 203 | } 204 | ] 205 | } -------------------------------------------------------------------------------- /testdata/expected/python27-syntax/PipPackage.graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "Defs": [ 3 | { 4 | "UnitType": "PipPackage", 5 | "Unit": ".", 6 | "Path": "py27lib.py/py27lib.hello.hello", 7 | "Name": "hello", 8 | "Kind": "function", 9 | "File": "py27lib.py", 10 | "DefStart": 4, 11 | "DefEnd": 9, 12 | "Exported": true, 13 | "Data": { 14 | "Keyword": "def", 15 | "Kind": "function", 16 | "Name": "hello", 17 | "Separator": "", 18 | "Type": "()" 19 | } 20 | }, 21 | { 22 | "UnitType": "PipPackage", 23 | "Unit": ".", 24 | "Path": "py27lib.py/py27lib.hello.s", 25 | "Name": "s", 26 | "Kind": "statement", 27 | "File": "py27lib.py", 28 | "DefStart": 17, 29 | "DefEnd": 18, 30 | "Exported": true, 31 | "Data": { 32 | "Keyword": "", 33 | "Kind": "statement", 34 | "Name": "s", 35 | "Separator": " ", 36 | "Type": "= \"hello world\"" 37 | } 38 | }, 39 | { 40 | "UnitType": "PipPackage", 41 | "Unit": ".", 42 | "Path": "py27lib.py/py27lib.py27lib", 43 | "Name": "py27lib.py", 44 | "Kind": "module", 45 | "File": "py27lib.py", 46 | "DefStart": 0, 47 | "DefEnd": 0, 48 | "Exported": true, 49 | "Data": { 50 | "Keyword": "module", 51 | "Kind": "module", 52 | "Name": "py27lib", 53 | "Separator": "", 54 | "Type": "" 55 | } 56 | }, 57 | { 58 | "UnitType": "PipPackage", 59 | "Unit": ".", 60 | "Path": "setup.py/setup.setup", 61 | "Name": "setup.py", 62 | "Kind": "module", 63 | "File": "setup.py", 64 | "DefStart": 0, 65 | "DefEnd": 0, 66 | "Exported": true, 67 | "Data": { 68 | "Keyword": "module", 69 | "Kind": "module", 70 | "Name": "setup", 71 | "Separator": "", 72 | "Type": "" 73 | } 74 | } 75 | ], 76 | "Refs": [ 77 | { 78 | "DefRepo": "github.com/python/cpython", 79 | "DefUnitType": "PipPackage", 80 | "DefUnit": "__builtin__", 81 | "DefPath": "print", 82 | "UnitType": "PipPackage", 83 | "Unit": ".", 84 | "File": "py27lib.py", 85 | "Start": 51, 86 | "End": 56 87 | }, 88 | { 89 | "DefUnitType": "PipPackage", 90 | "DefUnit": ".", 91 | "DefPath": "py27lib.py/py27lib.hello.hello", 92 | "UnitType": "PipPackage", 93 | "Unit": ".", 94 | "Def": true, 95 | "File": "py27lib.py", 96 | "Start": 4, 97 | "End": 9 98 | }, 99 | { 100 | "DefUnitType": "PipPackage", 101 | "DefUnit": ".", 102 | "DefPath": "py27lib.py/py27lib.hello.s", 103 | "UnitType": "PipPackage", 104 | "Unit": ".", 105 | "Def": true, 106 | "File": "py27lib.py", 107 | "Start": 17, 108 | "End": 18 109 | }, 110 | { 111 | "DefUnitType": "PipPackage", 112 | "DefUnit": ".", 113 | "DefPath": "py27lib.py/py27lib.hello.s", 114 | "UnitType": "PipPackage", 115 | "Unit": ".", 116 | "File": "py27lib.py", 117 | "Start": 57, 118 | "End": 58 119 | }, 120 | { 121 | "DefUnitType": "PipPackage", 122 | "DefUnit": ".", 123 | "DefPath": "py27lib.py/py27lib.py27lib", 124 | "UnitType": "PipPackage", 125 | "Unit": ".", 126 | "Def": true, 127 | "File": "py27lib.py", 128 | "Start": 0, 129 | "End": 0 130 | }, 131 | { 132 | "DefUnitType": "PipPackage", 133 | "DefUnit": ".", 134 | "DefPath": "setup.py/setup.install_requires", 135 | "UnitType": "PipPackage", 136 | "Unit": ".", 137 | "File": "setup.py", 138 | "Start": 222, 139 | "End": 238 140 | }, 141 | { 142 | "DefUnitType": "PipPackage", 143 | "DefUnit": ".", 144 | "DefPath": "setup.py/setup.name", 145 | "UnitType": "PipPackage", 146 | "Unit": ".", 147 | "File": "setup.py", 148 | "Start": 93, 149 | "End": 97 150 | }, 151 | { 152 | "DefUnitType": "PipPackage", 153 | "DefUnit": ".", 154 | "DefPath": "setup.py/setup.py_modules", 155 | "UnitType": "PipPackage", 156 | "Unit": ".", 157 | "File": "setup.py", 158 | "Start": 194, 159 | "End": 204 160 | }, 161 | { 162 | "DefUnitType": "PipPackage", 163 | "DefUnit": ".", 164 | "DefPath": "setup.py/setup.setup", 165 | "UnitType": "PipPackage", 166 | "Unit": ".", 167 | "Def": true, 168 | "File": "setup.py", 169 | "Start": 0, 170 | "End": 0 171 | }, 172 | { 173 | "DefUnitType": "PipPackage", 174 | "DefUnit": ".", 175 | "DefPath": "setup.py/setup.url", 176 | "UnitType": "PipPackage", 177 | "Unit": ".", 178 | "File": "setup.py", 179 | "Start": 142, 180 | "End": 145 181 | }, 182 | { 183 | "DefUnitType": "PipPackage", 184 | "DefUnit": ".", 185 | "DefPath": "setup.py/setup.version", 186 | "UnitType": "PipPackage", 187 | "Unit": ".", 188 | "File": "setup.py", 189 | "Start": 121, 190 | "End": 128 191 | }, 192 | { 193 | "DefRepo": "github.com/pypa/setuptools", 194 | "DefUnitType": "PipPackage", 195 | "DefUnit": "setuptools", 196 | "DefPath": "setuptools/__init__.py/setuptools.setup", 197 | "UnitType": "PipPackage", 198 | "Unit": ".", 199 | "File": "setup.py", 200 | "Start": 23, 201 | "End": 28 202 | }, 203 | { 204 | "DefRepo": "github.com/pypa/setuptools", 205 | "DefUnitType": "PipPackage", 206 | "DefUnit": "setuptools", 207 | "DefPath": "setuptools/__init__.py/setuptools.setup", 208 | "UnitType": "PipPackage", 209 | "Unit": ".", 210 | "File": "setup.py", 211 | "Start": 82, 212 | "End": 87 213 | }, 214 | { 215 | "DefRepo": "github.com/pypa/setuptools", 216 | "DefUnitType": "PipPackage", 217 | "DefUnit": "setuptools", 218 | "DefPath": "setuptools/__init__.py/setuptools.setuptools", 219 | "UnitType": "PipPackage", 220 | "Unit": ".", 221 | "File": "setup.py", 222 | "Start": 5, 223 | "End": 15 224 | } 225 | ] 226 | } -------------------------------------------------------------------------------- /testdata/expected/python-link-tests/python-link-tests/PythonTestPackage.graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "Defs": [ 3 | { 4 | "UnitType": "PythonTestPackage", 5 | "Unit": "python-link-tests", 6 | "Path": "test_m0.py/test_m0.TESTS_ROOT", 7 | "Name": "TESTS_ROOT", 8 | "Kind": "statement", 9 | "File": "app/tests/test_m0.py", 10 | "DefStart": 35, 11 | "DefEnd": 45, 12 | "Exported": true, 13 | "Data": { 14 | "Keyword": "", 15 | "Kind": "statement", 16 | "Name": "TESTS_ROOT", 17 | "Separator": " ", 18 | "Type": "= os.path.abspath(os.path.dirname(__file__))" 19 | } 20 | }, 21 | { 22 | "UnitType": "PythonTestPackage", 23 | "Unit": "python-link-tests", 24 | "Path": "test_m0.py/test_m0.bar.bar", 25 | "Name": "bar", 26 | "Kind": "function", 27 | "File": "app/tests/test_m0.py", 28 | "DefStart": 96, 29 | "DefEnd": 99, 30 | "Exported": true, 31 | "Data": { 32 | "Keyword": "def", 33 | "Kind": "function", 34 | "Name": "bar", 35 | "Separator": "", 36 | "Type": "()" 37 | } 38 | }, 39 | { 40 | "UnitType": "PythonTestPackage", 41 | "Unit": "python-link-tests", 42 | "Path": "test_m0.py/test_m0.test_m0", 43 | "Name": "test_m0.py", 44 | "Kind": "module", 45 | "File": "app/tests/test_m0.py", 46 | "DefStart": 0, 47 | "DefEnd": 0, 48 | "Exported": true, 49 | "Data": { 50 | "Keyword": "module", 51 | "Kind": "module", 52 | "Name": "test_m0", 53 | "Separator": "", 54 | "Type": "" 55 | } 56 | } 57 | ], 58 | "Refs": [ 59 | { 60 | "DefRepo": "github.com/python/cpython", 61 | "DefUnitType": "PipPackage", 62 | "DefUnit": "Python", 63 | "DefPath": "ntpath.py/os.path.abspath.abspath", 64 | "UnitType": "PythonTestPackage", 65 | "Unit": "python-link-tests", 66 | "File": "app/tests/test_m0.py", 67 | "Start": 56, 68 | "End": 63 69 | }, 70 | { 71 | "DefRepo": "github.com/python/cpython", 72 | "DefUnitType": "PipPackage", 73 | "DefUnit": "Python", 74 | "DefPath": "ntpath.py/os.path.dirname.dirname", 75 | "UnitType": "PythonTestPackage", 76 | "Unit": "python-link-tests", 77 | "File": "app/tests/test_m0.py", 78 | "Start": 72, 79 | "End": 79 80 | }, 81 | { 82 | "DefRepo": "github.com/python/cpython", 83 | "DefUnitType": "PipPackage", 84 | "DefUnit": "Python", 85 | "DefPath": "ntpath.py/os.path.ntpath", 86 | "UnitType": "PythonTestPackage", 87 | "Unit": "python-link-tests", 88 | "File": "app/tests/test_m0.py", 89 | "Start": 51, 90 | "End": 55 91 | }, 92 | { 93 | "DefRepo": "github.com/python/cpython", 94 | "DefUnitType": "PipPackage", 95 | "DefUnit": "Python", 96 | "DefPath": "ntpath.py/os.path.ntpath", 97 | "UnitType": "PythonTestPackage", 98 | "Unit": "python-link-tests", 99 | "File": "app/tests/test_m0.py", 100 | "Start": 67, 101 | "End": 71 102 | }, 103 | { 104 | "DefRepo": "github.com/python/cpython", 105 | "DefUnitType": "PipPackage", 106 | "DefUnit": "Python", 107 | "DefPath": "os.py/os.os", 108 | "UnitType": "PythonTestPackage", 109 | "Unit": "python-link-tests", 110 | "File": "app/tests/test_m0.py", 111 | "Start": 48, 112 | "End": 50 113 | }, 114 | { 115 | "DefRepo": "github.com/python/cpython", 116 | "DefUnitType": "PipPackage", 117 | "DefUnit": "Python", 118 | "DefPath": "os.py/os.os", 119 | "UnitType": "PythonTestPackage", 120 | "Unit": "python-link-tests", 121 | "File": "app/tests/test_m0.py", 122 | "Start": 64, 123 | "End": 66 124 | }, 125 | { 126 | "DefRepo": "github.com/python/cpython", 127 | "DefUnitType": "PipPackage", 128 | "DefUnit": "Python", 129 | "DefPath": "os.py/os.os", 130 | "UnitType": "PythonTestPackage", 131 | "Unit": "python-link-tests", 132 | "File": "app/tests/test_m0.py", 133 | "Start": 7, 134 | "End": 9 135 | }, 136 | { 137 | "DefRepo": "?", 138 | "DefUnitType": "PipPackage", 139 | "DefUnit": "python-link-tests", 140 | "DefPath": "pkg0/__init__.py/pkg0.pkg0", 141 | "UnitType": "PythonTestPackage", 142 | "Unit": "python-link-tests", 143 | "File": "app/tests/test_m0.py", 144 | "Start": 15, 145 | "End": 19 146 | }, 147 | { 148 | "DefRepo": "?", 149 | "DefUnitType": "PipPackage", 150 | "DefUnit": "python-link-tests", 151 | "DefPath": "pkg0/m0.py/m0.foo.foo", 152 | "UnitType": "PythonTestPackage", 153 | "Unit": "python-link-tests", 154 | "File": "app/tests/test_m0.py", 155 | "Start": 104, 156 | "End": 107 157 | }, 158 | { 159 | "DefRepo": "?", 160 | "DefUnitType": "PipPackage", 161 | "DefUnit": "python-link-tests", 162 | "DefPath": "pkg0/m0.py/m0.foo.foo", 163 | "UnitType": "PythonTestPackage", 164 | "Unit": "python-link-tests", 165 | "File": "app/tests/test_m0.py", 166 | "Start": 30, 167 | "End": 33 168 | }, 169 | { 170 | "DefRepo": "?", 171 | "DefUnitType": "PipPackage", 172 | "DefUnit": "python-link-tests", 173 | "DefPath": "pkg0/m0.py/pkg0.m0.m0", 174 | "UnitType": "PythonTestPackage", 175 | "Unit": "python-link-tests", 176 | "File": "app/tests/test_m0.py", 177 | "Start": 20, 178 | "End": 22 179 | }, 180 | { 181 | "DefUnitType": "PythonTestPackage", 182 | "DefUnit": "python-link-tests", 183 | "DefPath": "test_m0.py/test_m0.TESTS_ROOT", 184 | "UnitType": "PythonTestPackage", 185 | "Unit": "python-link-tests", 186 | "Def": true, 187 | "File": "app/tests/test_m0.py", 188 | "Start": 35, 189 | "End": 45 190 | }, 191 | { 192 | "DefUnitType": "PythonTestPackage", 193 | "DefUnit": "python-link-tests", 194 | "DefPath": "test_m0.py/test_m0.__file__", 195 | "UnitType": "PythonTestPackage", 196 | "Unit": "python-link-tests", 197 | "File": "app/tests/test_m0.py", 198 | "Start": 80, 199 | "End": 88 200 | }, 201 | { 202 | "DefUnitType": "PythonTestPackage", 203 | "DefUnit": "python-link-tests", 204 | "DefPath": "test_m0.py/test_m0.bar.bar", 205 | "UnitType": "PythonTestPackage", 206 | "Unit": "python-link-tests", 207 | "Def": true, 208 | "File": "app/tests/test_m0.py", 209 | "Start": 96, 210 | "End": 99 211 | }, 212 | { 213 | "DefUnitType": "PythonTestPackage", 214 | "DefUnit": "python-link-tests", 215 | "DefPath": "test_m0.py/test_m0.test_m0", 216 | "UnitType": "PythonTestPackage", 217 | "Unit": "python-link-tests", 218 | "Def": true, 219 | "File": "app/tests/test_m0.py", 220 | "Start": 0, 221 | "End": 0 222 | } 223 | ] 224 | } -------------------------------------------------------------------------------- /testdata/expected/python-sample-1/python-sample-1/PipPackage.graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "Defs": [ 3 | { 4 | "UnitType": "PipPackage", 5 | "Unit": "python-sample-1", 6 | "Path": "app/__init__.py/app.app", 7 | "Name": "app", 8 | "Kind": "module", 9 | "File": "app/__init__.py", 10 | "DefStart": 0, 11 | "DefEnd": 0, 12 | "Exported": true, 13 | "Data": { 14 | "Keyword": "package", 15 | "Kind": "package", 16 | "Name": "app", 17 | "Separator": "", 18 | "Type": "" 19 | } 20 | }, 21 | { 22 | "UnitType": "PipPackage", 23 | "Unit": "python-sample-1", 24 | "Path": "app/app.py/app.app.app", 25 | "Name": "app.py", 26 | "Kind": "module", 27 | "File": "app/app.py", 28 | "DefStart": 0, 29 | "DefEnd": 0, 30 | "Exported": true, 31 | "Data": { 32 | "Keyword": "module", 33 | "Kind": "module", 34 | "Name": "app.app", 35 | "Separator": "", 36 | "Type": "" 37 | } 38 | }, 39 | { 40 | "UnitType": "PipPackage", 41 | "Unit": "python-sample-1", 42 | "Path": "app/app.py/app.x", 43 | "Name": "x", 44 | "Kind": "statement", 45 | "File": "app/app.py", 46 | "DefStart": 16, 47 | "DefEnd": 17, 48 | "Exported": true, 49 | "Data": { 50 | "Keyword": "", 51 | "Kind": "statement", 52 | "Name": "x", 53 | "Separator": " ", 54 | "Type": "= pkg0.m0.Class0()" 55 | } 56 | }, 57 | { 58 | "UnitType": "PipPackage", 59 | "Unit": "python-sample-1", 60 | "Path": "setup.py/setup.setup", 61 | "Name": "setup.py", 62 | "Kind": "module", 63 | "File": "setup.py", 64 | "DefStart": 0, 65 | "DefEnd": 0, 66 | "Exported": true, 67 | "Data": { 68 | "Keyword": "module", 69 | "Kind": "module", 70 | "Name": "setup", 71 | "Separator": "", 72 | "Type": "" 73 | } 74 | } 75 | ], 76 | "Refs": [ 77 | { 78 | "DefUnitType": "PipPackage", 79 | "DefUnit": "python-sample-1", 80 | "DefPath": "app/__init__.py/app.app", 81 | "UnitType": "PipPackage", 82 | "Unit": "python-sample-1", 83 | "Def": true, 84 | "File": "app/__init__.py", 85 | "Start": 0, 86 | "End": 0 87 | }, 88 | { 89 | "DefUnitType": "PipPackage", 90 | "DefUnit": "python-sample-1", 91 | "DefPath": "app/app.py/app.app.app", 92 | "UnitType": "PipPackage", 93 | "Unit": "python-sample-1", 94 | "Def": true, 95 | "File": "app/app.py", 96 | "Start": 0, 97 | "End": 0 98 | }, 99 | { 100 | "DefUnitType": "PipPackage", 101 | "DefUnit": "python-sample-1", 102 | "DefPath": "app/app.py/app.x", 103 | "UnitType": "PipPackage", 104 | "Unit": "python-sample-1", 105 | "Def": true, 106 | "File": "app/app.py", 107 | "Start": 16, 108 | "End": 17 109 | }, 110 | { 111 | "DefUnitType": "PipPackage", 112 | "DefUnit": "python-sample-1", 113 | "DefPath": "app/app.py/app.x", 114 | "UnitType": "PipPackage", 115 | "Unit": "python-sample-1", 116 | "File": "app/app.py", 117 | "Start": 37, 118 | "End": 38 119 | }, 120 | { 121 | "DefRepo": "github.com/sgtest/python-sample-0", 122 | "DefUnitType": "PipPackage", 123 | "DefUnit": "python-sample-0", 124 | "DefPath": "pkg0/__init__.py/pkg0.pkg0", 125 | "UnitType": "PipPackage", 126 | "Unit": "python-sample-1", 127 | "File": "app/app.py", 128 | "Start": 20, 129 | "End": 24 130 | }, 131 | { 132 | "DefRepo": "github.com/sgtest/python-sample-0", 133 | "DefUnitType": "PipPackage", 134 | "DefUnit": "python-sample-0", 135 | "DefPath": "pkg0/__init__.py/pkg0.pkg0", 136 | "UnitType": "PipPackage", 137 | "Unit": "python-sample-1", 138 | "File": "app/app.py", 139 | "Start": 7, 140 | "End": 11 141 | }, 142 | { 143 | "DefRepo": "github.com/sgtest/python-sample-0", 144 | "DefUnitType": "PipPackage", 145 | "DefUnit": "python-sample-0", 146 | "DefPath": "pkg0/m0.py/m0.Class0.Class0", 147 | "UnitType": "PipPackage", 148 | "Unit": "python-sample-1", 149 | "File": "app/app.py", 150 | "Start": 28, 151 | "End": 34 152 | }, 153 | { 154 | "DefRepo": "github.com/sgtest/python-sample-0", 155 | "DefUnitType": "PipPackage", 156 | "DefUnit": "python-sample-0", 157 | "DefPath": "pkg0/m0.py/m0.Class0.meth0.meth0", 158 | "UnitType": "PipPackage", 159 | "Unit": "python-sample-1", 160 | "File": "app/app.py", 161 | "Start": 39, 162 | "End": 44 163 | }, 164 | { 165 | "DefRepo": "github.com/sgtest/python-sample-0", 166 | "DefUnitType": "PipPackage", 167 | "DefUnit": "python-sample-0", 168 | "DefPath": "pkg0/m0.py/pkg0.m0.m0", 169 | "UnitType": "PipPackage", 170 | "Unit": "python-sample-1", 171 | "File": "app/app.py", 172 | "Start": 12, 173 | "End": 14 174 | }, 175 | { 176 | "DefRepo": "github.com/sgtest/python-sample-0", 177 | "DefUnitType": "PipPackage", 178 | "DefUnit": "python-sample-0", 179 | "DefPath": "pkg0/m0.py/pkg0.m0.m0", 180 | "UnitType": "PipPackage", 181 | "Unit": "python-sample-1", 182 | "File": "app/app.py", 183 | "Start": 25, 184 | "End": 27 185 | }, 186 | { 187 | "DefUnitType": "PipPackage", 188 | "DefUnit": "python-sample-1", 189 | "DefPath": "setup.py/setup.name", 190 | "UnitType": "PipPackage", 191 | "Unit": "python-sample-1", 192 | "File": "setup.py", 193 | "Start": 41, 194 | "End": 45 195 | }, 196 | { 197 | "DefUnitType": "PipPackage", 198 | "DefUnit": "python-sample-1", 199 | "DefPath": "setup.py/setup.packages", 200 | "UnitType": "PipPackage", 201 | "Unit": "python-sample-1", 202 | "File": "setup.py", 203 | "Start": 143, 204 | "End": 151 205 | }, 206 | { 207 | "DefUnitType": "PipPackage", 208 | "DefUnit": "python-sample-1", 209 | "DefPath": "setup.py/setup.setup", 210 | "UnitType": "PipPackage", 211 | "Unit": "python-sample-1", 212 | "Def": true, 213 | "File": "setup.py", 214 | "Start": 0, 215 | "End": 0 216 | }, 217 | { 218 | "DefUnitType": "PipPackage", 219 | "DefUnit": "python-sample-1", 220 | "DefPath": "setup.py/setup.url", 221 | "UnitType": "PipPackage", 222 | "Unit": "python-sample-1", 223 | "File": "setup.py", 224 | "Start": 90, 225 | "End": 93 226 | }, 227 | { 228 | "DefUnitType": "PipPackage", 229 | "DefUnit": "python-sample-1", 230 | "DefPath": "setup.py/setup.version", 231 | "UnitType": "PipPackage", 232 | "Unit": "python-sample-1", 233 | "File": "setup.py", 234 | "Start": 69, 235 | "End": 76 236 | }, 237 | { 238 | "DefRepo": "github.com/pypa/setuptools", 239 | "DefUnitType": "PipPackage", 240 | "DefUnit": "setuptools", 241 | "DefPath": "setuptools/__init__.py/setuptools.setup", 242 | "UnitType": "PipPackage", 243 | "Unit": "python-sample-1", 244 | "File": "setup.py", 245 | "Start": 23, 246 | "End": 28 247 | }, 248 | { 249 | "DefRepo": "github.com/pypa/setuptools", 250 | "DefUnitType": "PipPackage", 251 | "DefUnit": "setuptools", 252 | "DefPath": "setuptools/__init__.py/setuptools.setup", 253 | "UnitType": "PipPackage", 254 | "Unit": "python-sample-1", 255 | "File": "setup.py", 256 | "Start": 30, 257 | "End": 35 258 | }, 259 | { 260 | "DefRepo": "github.com/pypa/setuptools", 261 | "DefUnitType": "PipPackage", 262 | "DefUnit": "setuptools", 263 | "DefPath": "setuptools/__init__.py/setuptools.setuptools", 264 | "UnitType": "PipPackage", 265 | "Unit": "python-sample-1", 266 | "File": "setup.py", 267 | "Start": 5, 268 | "End": 15 269 | } 270 | ] 271 | } -------------------------------------------------------------------------------- /grapher/scan.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import os.path 4 | import json 5 | 6 | from . import pydepwrap 7 | from . import django 8 | from . import builtin 9 | from .structures import * 10 | from .util import normalize 11 | 12 | 13 | def stdlibUnits(diry: str) -> Tuple[List[Unit], bool]: 14 | if not os.path.lexists(os.path.join(diry, "Lib")): 15 | return None, False 16 | if not os.path.lexists(os.path.join(diry, "Include")): 17 | return None, False 18 | if not os.path.lexists(os.path.join(diry, "Modules")): 19 | return None, False 20 | 21 | # HACK(performance): filter out test files in standard lib 22 | files = [f for f in get_source_files(diry) if ( 23 | (f.startswith('Lib/')) and ('/test/' not in f) and ('_test' not in f) and ('test_' not in f) 24 | )] 25 | 26 | return [Unit( 27 | Name = STDLIB_UNIT_KEY.Name, 28 | Type = STDLIB_UNIT_KEY.Type, 29 | Repo = STDLIB_UNIT_KEY.Repo, 30 | CommitID = STDLIB_UNIT_KEY.CommitID, 31 | Version = STDLIB_UNIT_KEY.Version, 32 | Files = sorted(files), 33 | Dir = 'Lib', 34 | Dependencies = [], 35 | ), Unit( 36 | Name = BUILTIN_UNIT_KEY.Name, 37 | Type = BUILTIN_UNIT_KEY.Type, 38 | Repo = BUILTIN_UNIT_KEY.Repo, 39 | CommitID = BUILTIN_UNIT_KEY.CommitID, 40 | Version = BUILTIN_UNIT_KEY.Version, 41 | Files = builtin.get_c_source_files('Modules'), 42 | Dir = 'Modules', 43 | Dependencies = [], 44 | )], True 45 | 46 | def find_pip_pkgs(rootdir: str) -> List: 47 | setup_dirs = pydepwrap.setup_dirs(rootdir) 48 | setup_infos = [] 49 | for setup_dir in setup_dirs: 50 | setup_dict = pydepwrap.setup_info_dir(setup_dir) 51 | setup_infos.append( 52 | setup_dict_to_json_serializable_dict(setup_dict, rootdir=os.path.relpath(setup_dir, rootdir))) 53 | return setup_infos 54 | 55 | # Directory name for test files in common practice. 56 | TEST_DIR = "tests" 57 | 58 | def source_files_for_pip_unit(metadata: Dict) -> Tuple[List[str], List[str]]: 59 | packages, modules = [], [] # type: List[str], List[str] 60 | if 'packages' in metadata and metadata['packages'] is not None: 61 | packages.extend(metadata['packages']) 62 | if 'modules' in metadata and metadata['modules'] is not None: 63 | modules.extend(metadata['modules']) 64 | if 'py_modules' in metadata and metadata['py_modules'] is not None: 65 | modules.extend(metadata['py_modules']) 66 | 67 | # Indicate whether this unit is in root direcotry of repository. 68 | unit_dir = metadata['rootdir'] 69 | is_root_dir = unit_dir == "." 70 | included_tests = False 71 | files = [] 72 | for module in modules: 73 | if not is_root_dir: 74 | module = os.path.join(unit_dir, module) 75 | files.append('{}.py'.format(normalize(module))) 76 | for pkg in packages: 77 | pkg_path = pkg.replace('.', '/') 78 | 79 | if not included_tests: 80 | included_tests = pkg_path.split('/')[0] == TEST_DIR 81 | 82 | if not is_root_dir: 83 | pkg_path = os.path.join(unit_dir, pkg_path) 84 | pkg_files = get_source_files(pkg_path) 85 | for pkg_file in pkg_files: 86 | files.append(normalize(os.path.join(pkg_path, pkg_file))) 87 | 88 | # Make good guess for test files when they are not linked. 89 | test_files = [] 90 | if not included_tests: 91 | test_dir = TEST_DIR 92 | if not is_root_dir: 93 | test_dir = os.path.join(unit_dir, TEST_DIR) 94 | 95 | pkg_files = get_source_files(test_dir) 96 | for pkg_file in pkg_files: 97 | test_files.append(normalize(os.path.join(test_dir, pkg_file))) 98 | 99 | if is_root_dir: 100 | files.append('setup.py') 101 | else: 102 | files.append(os.path.join(unit_dir, 'setup.py')) 103 | files = list(set(files)) 104 | test_files = list(set(test_files)) 105 | return files, test_files 106 | 107 | # filesToModules transforms from source files to list of modules. 108 | # Because setup.py file only defines modules and packages the library wants to expose, 109 | # but test files are using ones that are not defined in the setup.py as well. 110 | def filesToModules(rootdir: str, files: List[str]) -> List[str]: 111 | modules = [] 112 | for file in files: 113 | # Convert file path to Python module name format . 114 | file = os.path.splitext(file)[0].replace('/', '.') 115 | # Remove directory prefix if setup.py is not in root directory. 116 | if rootdir != ".": 117 | file = file[len(rootdir)+1:] 118 | modules.append(file) 119 | modules = sorted(modules) 120 | return modules 121 | 122 | # pkgToUnits transforms a Pip package struct into a list of source units, 123 | # including main unit and possible test unit. 124 | def pkgToUnits(pkg: Dict) -> List[Unit]: 125 | pkgdir = pkg['rootdir'] 126 | files, test_files = source_files_for_pip_unit(pkg) 127 | pkgreqs = pydepwrap.requirements(pkgdir, True) 128 | deps = [] 129 | for pkgreq in pkgreqs: 130 | dep = pkgToUnitKey(pkgreq) 131 | if dep is not None: 132 | deps.append(dep) 133 | 134 | unit = Unit( 135 | Name = pkg['project_name'] if pkg['project_name'] is not None else pkgdir, 136 | Type = UNIT_PIP, 137 | Repo = "", # empty Repo signals it is from this repository 138 | CommitID = "", 139 | Files = sorted(files), 140 | Dir = normalize(pkgdir), 141 | Dependencies = deps, # unresolved dependencies 142 | Data = Data( 143 | Reqs = [req for req in pkgreqs if checkReq(req)], 144 | ReqFiles = [normalize(os.path.join(pkgdir, "requirements.txt"))], 145 | ) 146 | ) 147 | if len(test_files) == 0: 148 | return [unit] 149 | 150 | test_dir = TEST_DIR 151 | if pkgdir != ".": 152 | test_dir = os.path.join(pkgdir, TEST_DIR) 153 | return [unit, Unit( 154 | Name = unit.Name, 155 | Type = TEST_UNIT_KEY.Type, 156 | Repo = "", 157 | CommitID = "", 158 | Files = sorted(test_files), 159 | Dir = test_dir, 160 | Dependencies = [UnitKey( 161 | Name = unit.Name, 162 | Type = unit.Type, 163 | Repo = unit.Repo, 164 | CommitID = unit.CommitID, 165 | Version = unit.Version, 166 | )], 167 | Data = Data( 168 | Reqs = [{ 169 | "project_name": unit.Name, 170 | "repo_url": "", 171 | "packages": pkg['packages'] if pkg['packages'] is not None else None, 172 | "modules": filesToModules(pkgdir, files), 173 | }] 174 | ) 175 | )] 176 | 177 | def scan(diry: str) -> None: 178 | # special case for standard library 179 | stdunits, isStdlib = stdlibUnits(diry) 180 | if isStdlib: 181 | json.dump(toJSONable(stdunits), sys.stdout, sort_keys=True) 182 | return 183 | 184 | units = [] # type: List[Unit] 185 | for pkg in find_pip_pkgs(diry): 186 | units.extend(pkgToUnits(pkg)) 187 | for proj in django.find_units("."): 188 | units.append(proj) 189 | 190 | # add setuptools as a dependency for all non-stdlib units 191 | for u in units: 192 | u.Dependencies.append(SETUPTOOLS_UNIT_KEY) 193 | 194 | json.dump(toJSONable(units), sys.stdout, sort_keys=True) 195 | 196 | 197 | # 198 | # Helpers 199 | # 200 | 201 | # setup_dict_to_json_serializable_dict is copy-pasted from pydep-run.py 202 | def setup_dict_to_json_serializable_dict(d, **kw): 203 | modules = [] 204 | if 'py_modules' in d and d['py_modules'] is not None: 205 | modules.extend(d['py_modules']) 206 | if 'modules' in d and d['modules'] is not None: 207 | modules.extend(d['modules']) 208 | if len(modules) == 0: 209 | modules = None 210 | return { 211 | 'rootdir': kw['rootdir'] if 'rootdir' in kw else None, 212 | 'project_name': d['name'] if 'name' in d else None, 213 | 'version': d['version'] if 'version' in d else None, 214 | 'repo_url': d['url'] if 'url' in d else None, 215 | 'packages': d['packages'] if 'packages' in d else None, 216 | 'modules': modules, 217 | 'scripts': d['scripts'] if 'scripts' in d else None, 218 | 'author': d['author'] if 'author' in d else None, 219 | 'description': d['description'] if 'description' in d else None, 220 | } 221 | -------------------------------------------------------------------------------- /grapher/structures.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | 4 | from copy import copy 5 | from typing import List, Dict, Tuple, NamedTuple, Union, Any 6 | 7 | from .util import normalize 8 | 9 | # TODO(beyang): START HERE: fix JSON marshaling / unmarshaling issue 10 | 11 | class Data: 12 | def __init__(self, 13 | Reqs: List[Dict[str, Any]] = [], 14 | ReqFiles: List[str] = [], 15 | ) -> None: 16 | self.Reqs = Reqs # type: List[Dict] 17 | self.ReqFiles = ReqFiles # type: List[str] 18 | 19 | class UnitKey: 20 | def __init__(self, 21 | Name: str, 22 | Type: str, 23 | Repo: str = "", 24 | CommitID: str = "", 25 | Version: str = "", 26 | ) -> None: 27 | self.Name = Name 28 | self.Type = Type 29 | self.Repo = Repo 30 | self.CommitID = CommitID 31 | self.Version = Version 32 | 33 | def __eq__(self, other) -> bool: 34 | return self.__dict__ == other.__dict__ 35 | 36 | class Unit: 37 | def __init__( 38 | self, 39 | Name: str, 40 | Type: str, 41 | Files: List[str], 42 | Dir: str, 43 | Dependencies: List[UnitKey] = None, 44 | Repo: str = "", 45 | CommitID: str = "", 46 | Version: str = "", 47 | Data: Data = None, # List of raw requirements 48 | ) -> None: 49 | self.Name = Name 50 | self.Type = Type 51 | self.Repo = Repo 52 | self.CommitID = CommitID 53 | self.Version = Version 54 | self.Files = Files 55 | self.Dir = Dir 56 | self.Dependencies = Dependencies if Dependencies is not None else [] 57 | self.Data = Data 58 | 59 | def key(self) -> UnitKey: 60 | return UnitKey( 61 | Name=self.Name, 62 | Type=self.Type, 63 | Repo=self.Repo, 64 | CommitID=self.CommitID, 65 | Version=self.Version, 66 | ) 67 | 68 | class DefFormatData: 69 | def __init__( 70 | self, 71 | Name: str, 72 | Keyword: str, 73 | Type: str, 74 | Kind: str, 75 | Separator: str, 76 | ) -> None: 77 | self.Name = Name 78 | self.Keyword = Keyword 79 | self.Type = Type 80 | self.Kind = Kind 81 | self.Separator = Separator 82 | 83 | DefKey = NamedTuple('DefKey', [ 84 | ('Repo', str), 85 | ('Unit', str), 86 | ('UnitType', str), 87 | ('Path', str), 88 | ]) 89 | 90 | class Ref: 91 | def __init__( 92 | self, 93 | DefRepo: str, 94 | DefUnit: str, 95 | DefUnitType: str, 96 | DefPath: str, 97 | Def: bool, 98 | Unit: str, 99 | UnitType: str, 100 | File: str, 101 | Start: int, 102 | End: int, 103 | ToBuiltin: bool, 104 | ) -> None: 105 | self.DefRepo = DefRepo 106 | self.DefUnit = DefUnit 107 | self.DefUnitType = DefUnitType 108 | self.DefPath = DefPath 109 | self.Def = Def 110 | self.Unit = Unit 111 | self.UnitType = UnitType 112 | self.File = File 113 | self.Start = Start 114 | self.End = End 115 | self.ToBuiltin = ToBuiltin 116 | 117 | class Def: 118 | def __init__( 119 | self, 120 | Repo: str, 121 | Unit: str, 122 | UnitType: str, 123 | Path: str, 124 | Kind: str, 125 | Name: str, 126 | File: str, 127 | DefStart: int, 128 | DefEnd: int, 129 | Exported: bool, 130 | Data: DefFormatData, 131 | Builtin: bool = False, 132 | ) -> None: 133 | self.Repo = Repo 134 | self.Unit = Unit 135 | self.UnitType = UnitType 136 | self.Path = Path 137 | self.Kind = Kind 138 | self.Name = Name 139 | self.File = File 140 | self.DefStart = DefStart 141 | self.DefEnd = DefEnd 142 | self.Exported = Exported 143 | self.Data = Data 144 | self.Builtin = Builtin 145 | 146 | def defref(self) -> Ref: 147 | return Ref( 148 | DefRepo=self.Repo, 149 | DefUnit=self.Unit, 150 | DefUnitType=self.UnitType, 151 | DefPath=self.Path, 152 | Def=True, 153 | Unit=self.Unit, 154 | UnitType=self.UnitType, 155 | File=self.File, 156 | Start=self.DefStart, 157 | End=self.DefEnd, 158 | ToBuiltin=self.Builtin, 159 | ) 160 | 161 | Doc = NamedTuple('Doc', [ 162 | ('Unit', str), 163 | ('UnitType', str), 164 | ('Path', str), 165 | ('Format', str), 166 | ('Data', str), 167 | ('File', str), 168 | ]) 169 | 170 | UNIT_PIP = "PipPackage" 171 | UNIT_DJANGO = "DjangoApp" 172 | UNIT_TEST = "PythonTestPackage" 173 | REPO_UNRESOLVED = "?" 174 | STDLIB_UNIT_KEY = UnitKey( 175 | Name = 'Python', 176 | Type = UNIT_PIP, 177 | Repo = 'github.com/python/cpython', 178 | CommitID = '', 179 | Version='', 180 | ) 181 | BUILTIN_UNIT_KEY = UnitKey( 182 | Name = '__builtin__', 183 | Type = UNIT_PIP, 184 | Repo = 'github.com/python/cpython', 185 | CommitID = '', 186 | Version = '', 187 | ) 188 | TEST_UNIT_KEY = UnitKey( 189 | Name = '__test__', 190 | Type = UNIT_TEST, 191 | Repo = '', 192 | CommitID = '', 193 | Version = '', 194 | ) 195 | 196 | # SETUPTOOLS_UNIT_KEY is the unit key for the setuptools source unit. This 197 | # package is treated specially as it is always available (like the standard lib) 198 | # even when it is not explicitly specified as a requirement. Unlike the standard 199 | # lib, the setuptools repository builds successfully. However, it needs to be 200 | # included as a requirement for all third-party Python libraries. 201 | SETUPTOOLS_UNIT_KEY = UnitKey( 202 | Name = 'setuptools', 203 | Type = UNIT_PIP, 204 | Repo = 'github.com/pypa/setuptools', 205 | CommitID = '', 206 | Version='' 207 | ) 208 | 209 | 210 | """ 211 | Helper functions 212 | """ 213 | 214 | def get_source_files(diry: str) -> List[str]: 215 | """ Get list of all Python source files in a directory. """ 216 | files = [] # type: List[str] 217 | for path, _, filenames in os.walk(diry): 218 | rel_dir = os.path.relpath(path, diry) 219 | files.extend([normalize(os.path.normpath(os.path.join(rel_dir, f))) for f in filenames if os.path.splitext(f)[1] == '.py']) 220 | if diry != "" and diry != ".": 221 | for i in range(len(files)): 222 | if files[i].startswith('./'): 223 | files[i] = files[i][2:] 224 | return files 225 | 226 | def pkgToUnitKey(pkg: Dict) -> UnitKey: 227 | if not checkReq(pkg): 228 | return None 229 | return UnitKey( 230 | Name = pkg['project_name'], 231 | Type = UNIT_PIP, 232 | Repo = REPO_UNRESOLVED, 233 | Version = "", 234 | CommitID = "", 235 | ) 236 | 237 | def fromJSONable(j: Any, dst_t: Union[type, List, Dict]) -> Any: 238 | if j is None: 239 | return None 240 | elif str(dst_t) == 'typing.Any': 241 | return copy(j) 242 | elif str(dst_t).startswith('typing.List['): 243 | if type(j) is not list: 244 | raise Exception('attempting to unmarshal non-list {} into list'.format(j)) 245 | return [fromJSONable(e, dst_t.__parameters__[0]) for e in j] # type: ignore (List.__parameters_ exists) 246 | elif dst_t is list: 247 | if type(j) is not list: 248 | raise Exception('attempting to unmarshal non-list into list') 249 | return copy(j) 250 | elif str(dst_t).startswith('typing.Dict['): 251 | if type(j) is not dict: 252 | raise Exception('attempting to unmarshal non-dict into dict') 253 | if dst_t.__parameters__[0] is not str: # type: ignore (Dict.__parameters_ exists) 254 | raise Exception('attempting to unmarshal into a dict with non-str keys') 255 | value_t = dst_t.__parameters__[1] # type: ignore (Dict.__parameters_ exists) 256 | return {k: fromJSONable(v, value_t) for k, v in j.items()} 257 | elif dst_t is dict: 258 | if type(j) is not dict: 259 | raise Exception('attempting to unmarshal non-dict into dict') 260 | return copy(j) 261 | elif dst_t is str: 262 | if type(j) is not str: 263 | raise Exception('attempting to umarshal non-str into str') 264 | return j 265 | elif dst_t is int or dst_t is float: 266 | if type(j) is not int and type(j) is not float: 267 | raise Exception('attempting to unmarshal non-number into number') 268 | return j 269 | else: # dst_t is a Class 270 | if not isinstance(dst_t, type): 271 | raise Exception("couldn't find a constructor for type {}".format(dst_t)) 272 | if not isinstance(j, dict): 273 | raise Exception("couldn't recognize JSON j (type {}) as serializable into type {}".format(type(j), dst_t)) 274 | params = copy(dst_t.__init__.__annotations__) # type: ignore (SomeClass.__init__ exists) 275 | if 'return' in params: 276 | del params['return'] 277 | jk = set([e for e in j.keys()]) 278 | pk = set([e for e in params.keys()]) 279 | if not jk.issubset(pk): 280 | raise Exception('attempting to unmarshal from JSON object into class {}: {} is not a subset of {}'.format(dst_t, jk, pk)) 281 | d = {k: fromJSONable(v, params[k]) for k, v in j.items()} 282 | return dst_t(**d) 283 | 284 | def toJSONable(c: Any) -> Union[Dict, List, str, int]: 285 | if isinstance(c, int): 286 | return c 287 | elif isinstance(c, str): 288 | return c 289 | elif isinstance(c, list): 290 | return [toJSONable(e) for e in c] 291 | elif c is None: 292 | return c 293 | elif isinstance(c, dict): 294 | for k in c: 295 | if not isinstance(k, str): 296 | raise Exception("cannot serialize dictionary with key {} (type wasn't str)".format(k)) 297 | return {k: toJSONable(v) for k, v in c.items()} 298 | else: 299 | fields = [f for f in dir(c) if not f.startswith('_')] 300 | if len(fields) == 0: 301 | return None 302 | return {f: toJSONable(c.__getattribute__(f)) for f in fields if not ismethod(c.__getattribute__(f))} 303 | 304 | def ismethod(m: Any) -> bool: 305 | return hasattr(m, '__call__') and hasattr(m, '__self__') 306 | 307 | def checkReq(req: Dict) -> bool: 308 | return req['project_name'] is not None 309 | -------------------------------------------------------------------------------- /grapher/file_grapher.py: -------------------------------------------------------------------------------- 1 | from collections import namedtuple 2 | import os 3 | import re 4 | 5 | import jedi 6 | 7 | from .structures import * 8 | from .util import normalize 9 | 10 | def _debug_print_tree(node, indent=0, func=repr): 11 | """ Print visual representation of Jedi AST. """ 12 | ret = "\t" * indent + func(node) + "\n" 13 | 14 | children = getattr(node, "children", None) 15 | if children: 16 | for child in children: 17 | ret += _debug_print_tree(child, indent=indent+1, func=func) 18 | return ret 19 | 20 | 21 | class FileGrapherException(Exception): 22 | """ Something went wrong while graphing the file. """ 23 | 24 | class FileGrapher(object): 25 | """ 26 | FileGrapher is used to extract definitions and references from single Python source file. 27 | """ 28 | _exported_regex = re.compile('\_[a-zA-Z0-9]') 29 | 30 | def __init__(self, base_dir, source_file, unit, unit_type, modulePathPrefixToDep, syspath, log): 31 | """ 32 | Create a new grapher. 33 | """ 34 | self._base_dir = base_dir 35 | self._abs_base_dir = os.path.abspath(base_dir) 36 | self._file = source_file 37 | self._unit = unit 38 | self._unit_type = unit_type 39 | self._modulePathPrefixToDep = modulePathPrefixToDep 40 | self._syspath = list(reversed(sorted(syspath))) 41 | self._virtual_env = os.getenv('VIRTUAL_ENV') 42 | self._log = log 43 | self._source = None 44 | self._defs = {} 45 | self._refs = {} 46 | self._docs = {} 47 | self._load() 48 | 49 | self._stdlibpaths = [] 50 | for p in syspath: 51 | if not p.endswith('site-packages'): 52 | self._stdlibpaths.append(p) 53 | 54 | def graph(self): 55 | # Add module/package defs. 56 | basic_module_path = normalize(os.path.relpath(self._file, self._base_dir)) 57 | name = os.path.basename(basic_module_path) 58 | module_keyword = 'module' 59 | if basic_module_path.startswith('./'): 60 | basic_module_path = basic_module_path[2:] 61 | if os.path.basename(self._file) == '__init__.py': 62 | dot_path = normalize(os.path.dirname(basic_module_path)).replace('/', '.') 63 | module_keyword= 'package' 64 | name = dot_path.split('.')[-1] 65 | else: 66 | dot_path = normalize(os.path.splitext(basic_module_path)[0]).replace('/', '.') 67 | module_path = '{}/{}.{}'.format(basic_module_path, dot_path, dot_path.split('.')[-1]) 68 | self._add_def(Def( 69 | Repo="", 70 | Unit=self._unit, 71 | UnitType=self._unit_type, 72 | Path=module_path, 73 | Kind='module', 74 | Name=name, 75 | File=normalize(self._file), 76 | DefStart=0, 77 | DefEnd=0, 78 | Exported=True, 79 | Data=DefFormatData( 80 | Name=dot_path, 81 | Keyword=module_keyword, 82 | Type='', 83 | Kind=module_keyword, 84 | Separator='', 85 | ), 86 | )) 87 | # TODO(beyang): extract module/package-level doc. 88 | 89 | # Get occurrences of names via Jedi. 90 | try: 91 | jedi_names = jedi.names(source=self._source, path=self._file, all_scopes=True, references=True) 92 | except Exception as e: 93 | raise FileGrapherException('failed to parse {}: {}'.format(self._file, str(e))) 94 | 95 | jedi_defs, jedi_refs = [], [] 96 | for jedi_name in jedi_names: 97 | # Imports should be refs. 98 | if jedi_name.is_definition() and jedi_name.type != 'import': 99 | jedi_defs.append(jedi_name) 100 | else: 101 | jedi_refs.append(jedi_name) 102 | 103 | # Defs and docs. 104 | for jedi_def in jedi_defs: 105 | self._log.debug( 106 | 'processing def: %s | %s | %s', 107 | jedi_def.desc_with_module, 108 | jedi_def.name, 109 | jedi_def.type, 110 | ) 111 | try: 112 | def_, doc = self._jedi_def_to_def(jedi_def) 113 | self._add_def(def_) 114 | if doc is not None and doc.Data is not None and len(doc.Data) > 0: 115 | self._add_doc(doc) 116 | except Exception as e: 117 | self._log.error( 118 | u'failed to process def `%s`: %s', 119 | jedi_def.name, 120 | e, 121 | ) 122 | continue 123 | 124 | # Refs. 125 | for jedi_ref in jedi_refs: 126 | self._log.debug( 127 | 'processing ref: %s | %s | %s', 128 | jedi_ref.desc_with_module, 129 | jedi_ref.name, 130 | jedi_ref.type, 131 | ) 132 | 133 | ref_def = self._find_def_for_ref(jedi_ref) 134 | # We found nothing. 135 | if ref_def is None: 136 | continue 137 | 138 | try: 139 | sg_def = self._jedi_def_to_def_key(ref_def) 140 | except Exception as e: 141 | self._log.error( 142 | u'failed to process def to def-key `%s`: %s', 143 | ref_def.name, 144 | e, 145 | ) 146 | continue 147 | 148 | ref_start = self._to_offset(jedi_ref.line, jedi_ref.column) 149 | ref_end = ref_start + len(jedi_ref.name) 150 | 151 | self._add_ref(Ref( 152 | DefRepo=sg_def.Repo, 153 | DefUnit=sg_def.Unit, 154 | DefUnitType=sg_def.UnitType, 155 | DefPath=sg_def.Path, 156 | Unit=self._unit, 157 | UnitType=self._unit_type, 158 | Def=False, 159 | File=normalize(self._file), 160 | Start=ref_start, 161 | End=ref_end, 162 | ToBuiltin=ref_def.in_builtin_module(), 163 | )) 164 | 165 | return self._defs, self._refs, self._docs 166 | 167 | def _find_def_for_ref(self, jedi_ref, max_depth=100): 168 | """ Attempt to lookup definition for the reference. If lookup fails return None. """ 169 | ref_def = jedi_ref 170 | # If def is import, then follow it. 171 | depth = 0 172 | while (not ref_def.is_definition() or ref_def.type == "import") and depth < max_depth: 173 | depth += 1 174 | # noinspection PyBroadException 175 | try: 176 | ref_defs = ref_def.goto_assignments() 177 | except: 178 | self._log.error(u'jedi error getting definitions for reference {}'.format(jedi_ref)) 179 | break 180 | 181 | if len(ref_defs) == 0: 182 | break 183 | 184 | ref_def = ref_defs[0] 185 | else: 186 | self._log.debug( 187 | 'ref def search (precondition failed) | %s | %s | %s', 188 | ref_def.is_definition(), 189 | ref_def.type, 190 | ref_def.name 191 | ) 192 | 193 | if ref_def.type == "import": 194 | # We didn't find anything. 195 | self._log.debug('ref def not found') 196 | return None 197 | 198 | return ref_def 199 | 200 | def _load(self): 201 | """ Load file in memory. """ 202 | with open(self._file) as f: 203 | self._source = f.read() 204 | 205 | source_lines = self._source.splitlines(True) 206 | self._cumulative_off = [0] 207 | for line in source_lines: 208 | self._cumulative_off.append(self._cumulative_off[-1] + len(line)) 209 | 210 | def _jedi_def_is_ivar(self, df) -> bool: 211 | try: 212 | return (df.parent().type == 'function' and 213 | df.parent().parent().type in ['class', 'instance'] and 214 | df.description.startswith('self.')) 215 | except: 216 | return False 217 | 218 | def _jedi_def_ivar_classname(self, df) -> str: 219 | return '.'.join(df.full_name.split('.')[:-1]) 220 | 221 | # _jedi_def_to_name_and_type returns the display name and type of 222 | # a Jedi definition. For statements, it displays the set of 223 | # inferred possible values as the type. 224 | def _jedi_def_to_name_and_type(self, df) -> Tuple[str, str]: 225 | if df.type == 'function': 226 | typ_str = '('+', '.join([self._jedi_def_to_name_and_type(p)[0] for p in df.params])+')' 227 | if df.parent().type == 'class': 228 | return df.parent().name+'.'+df.name, typ_str 229 | else: 230 | return df.name, typ_str 231 | elif df.type == 'class': # class ${classname}(${superclass}[, ${superclass}]...) 232 | # best-effort extract name of superclass(es) 233 | try: 234 | return "{}({})".format(df.name, df._definition.base.get_super_arglist().get_code()), '' 235 | except Exception: 236 | return df.name, '' 237 | elif df.type == 'statement': 238 | parent = '' 239 | if df.parent().type == 'class': 240 | parent = df.parent().name+'.' 241 | elif self._jedi_def_is_ivar(df): 242 | parent = "("+df.parent().parent().name+') self.' 243 | 244 | def_types = set([]) 245 | for df_ in df.goto_assignments(): 246 | idx = df_.description.index('=') 247 | if idx != -1: 248 | def_types.add(df_.description[idx+1:].strip()) 249 | else: 250 | def_types.add('?') 251 | 252 | if len(def_types) == 0: 253 | return parent + df.name, '' 254 | elif len(def_types) == 1: 255 | return parent + df.name, '= '+list(def_types)[0] 256 | else: 257 | return parent + df.name, '= {'+', '.join(sorted(def_types))+'}' 258 | elif df.type == 'param': 259 | return df.name, '' 260 | else: 261 | self._log.debug('could not format unrecognized Jedi definition type {}'.format(df.type)) 262 | return df.name, '' 263 | 264 | def _jedi_def_to_format_data(self, df) -> DefFormatData: 265 | name, typ = self._jedi_def_to_name_and_type(df) 266 | keyword, sep = '', '' 267 | if df.type == 'function': 268 | keyword = 'def' 269 | elif df.type == 'class': 270 | keyword = 'class' 271 | sep = ' ' 272 | elif df.type == 'statement': 273 | keyword = '' 274 | sep = ' ' 275 | elif df.type == 'param': 276 | pass 277 | else: 278 | self._log.debug('could not format unrecognized Jedi definition type {}'.format(df.type)) 279 | 280 | return DefFormatData( 281 | Name = name, 282 | Type = typ, 283 | Keyword = keyword, 284 | Kind = df.type, 285 | Separator = sep, 286 | ) 287 | 288 | def _jedi_def_to_def(self, d): 289 | dk = self._jedi_def_to_def_key(d) 290 | start = self._to_offset(d.line, d.column) 291 | end = start + len(d.name) 292 | def_ = Def( 293 | Repo=dk.Repo, 294 | Unit=dk.Unit, 295 | UnitType=dk.UnitType, 296 | Path=dk.Path, 297 | Kind=d.type, 298 | Name=d.name, 299 | File=normalize(self._file), 300 | DefStart=start, 301 | DefEnd=end, 302 | Exported=self._is_exported(d.name), 303 | Data=self._jedi_def_to_format_data(d), 304 | ) 305 | 306 | doc = None 307 | docstring = d.docstring(raw=True) 308 | if docstring is not None: 309 | doc = Doc( 310 | Unit=def_.Unit, 311 | UnitType=def_.UnitType, 312 | Path=def_.Path, 313 | Format='plaintext', 314 | Data=docstring, 315 | File=def_.File, 316 | ) 317 | 318 | return def_, doc 319 | 320 | def _jedi_def_to_def_key(self, d): 321 | path, dep = self._full_name_and_dep(d) 322 | if dep is not None: 323 | repo, unit, unit_type = dep.Repo, dep.Name, dep.Type 324 | else: 325 | repo, unit, unit_type = "", self._unit, self._unit_type 326 | return DefKey( 327 | Repo=repo, 328 | Unit=unit, 329 | UnitType=unit_type, 330 | Path=path, 331 | ) 332 | 333 | # _rel_module_path returns (relative_module_path, is_internal) 334 | # TODO(beyang): replace startswith with os.path.commonpath (Python 3 function) 335 | def _rel_module_path(self, module_path): 336 | if module_path.startswith(self._abs_base_dir): 337 | return normalize(os.path.relpath(module_path, self._abs_base_dir)), True # internal 338 | 339 | for p in self._syspath: 340 | if p == '': 341 | continue 342 | if module_path.startswith(p): 343 | return normalize(os.path.relpath(module_path, p)), False # external 344 | 345 | if self._virtual_env is not None and module_path.startswith(self._virtual_env): 346 | module_path = normalize(os.path.relpath(module_path, self._virtual_env)) 347 | return module_path.split('/site-packages/', 1)[1], False 348 | 349 | return None, False 350 | 351 | def _module_to_dep(self, m): 352 | # Check explicit pip dependencies 353 | for pkg, dep in self._modulePathPrefixToDep.items(): 354 | if m.startswith(pkg): 355 | return dep, None 356 | for stdlibpath in self._stdlibpaths: 357 | if os.path.lexists(os.path.join(stdlibpath, m)): 358 | # Standard lib module 359 | return UnitKey(Repo=STDLIB_UNIT_KEY.Repo, 360 | Type=STDLIB_UNIT_KEY.Type, 361 | Name=STDLIB_UNIT_KEY.Name, 362 | CommitID=STDLIB_UNIT_KEY.CommitID, 363 | Version=STDLIB_UNIT_KEY.Version), None 364 | return None, ('could not find dep module for module %s, candidates were %s' % (m, repr(self._modulePathPrefixToDep.keys()))) 365 | 366 | def _full_name_and_dep(self, d): 367 | if d.in_builtin_module(): 368 | return d.full_name, UnitKey(Repo=STDLIB_UNIT_KEY.Repo, Type=UNIT_PIP, Name="__builtin__", CommitID="", Version="") 369 | 370 | if d.module_path is None: 371 | raise Exception('no module path for definition %s' % repr(d)) 372 | 373 | # This detects `self` and `cls` parameters makes them to point to the class: 374 | # To trigger this parameters must be for a method (a class function). 375 | if d.type == 'param' and (d.name == 'self' or d.name == 'cls') and d.parent().parent().type == 'class': 376 | d = d.parent().parent() 377 | 378 | module_path, is_internal = self._rel_module_path(d.module_path) 379 | if module_path is None: 380 | raise Exception('could not find name for module path %s' % d.module_path) 381 | 382 | if self._jedi_def_is_ivar(d): 383 | classname = self._jedi_def_ivar_classname(d) 384 | path = '{}/{}.{}'.format(module_path, classname, d.name) 385 | else: 386 | path = '{}/{}.{}'.format(module_path, d.full_name, d.name) 387 | 388 | dep = None 389 | if not is_internal: 390 | dep, err = self._module_to_dep(module_path) 391 | if err is not None: 392 | raise Exception(err) 393 | 394 | return path, dep 395 | 396 | @staticmethod 397 | def _get_module_parent_from_module_path(module_path): 398 | if os.path.basename(module_path) == '__init__.py': 399 | parent_module = os.path.dirname(os.path.dirname(module_path)) 400 | else: 401 | parent_module = os.path.dirname(module_path) 402 | return parent_module.replace(os.sep, '.') 403 | 404 | def _abs_module_path_to_relative_module_path(self, module_path): 405 | rel_path = module_path 406 | try: 407 | rel_path = os.path.relpath(module_path, self._base_dir) 408 | if not rel_path.startswith('..'): 409 | return rel_path 410 | except ValueError: 411 | # (alexsaveliev) virtualenv may use python from the different location. 412 | # This situation may cause "path is on drive C:, start on drive D:" 413 | pass 414 | 415 | components = module_path.split(os.sep) 416 | pi1 = pi2 = -1 417 | prev_component = None 418 | prev_index = -1 419 | for i, component in enumerate(components): 420 | if component in ['site-packages', 'dist-packages']: 421 | pi1 = i 422 | break 423 | # Fallback. 424 | # Windows case .env/lib/file.py, Unix case .env/lib/python.../file.py 425 | if pi2 == -1 and component == 'lib' and prev_component == '.env': 426 | pi2 = i 427 | elif pi2 == prev_index and component.startswith('python'): 428 | pi2 = i 429 | elif pi2 == -1 and prev_component is not None and prev_component.lower().startswith('python') and component.lower() == 'lib': 430 | pi2 = i 431 | prev_component = component 432 | prev_index = i 433 | 434 | pi = pi1 if pi1 != -1 else pi2 435 | if pi != -1: 436 | return os.path.join(*components[pi + 1:]) 437 | 438 | raise FileGrapherException('could not convert absolute module path {} ' 439 | 'to relative module path'.format(module_path)) 440 | 441 | def _is_exported(self, name): 442 | """ Checks if keyword is public or non-public. 443 | 444 | There are no private methods/variables in Python, however: 445 | 446 | There is a convention to prefix private methods/variables with 447 | underscore. And that's what we're going to use. 448 | 449 | https://www.python.org/dev/peps/pep-0008/#id40 450 | """ 451 | return self._exported_regex.match(name) is None 452 | 453 | def _add_def(self, d): 454 | """ Add a definition, also adds a self-reference. """ 455 | self._log.debug('adding def: %s | %s | %s', d.Name, d.Path, d.Kind) 456 | if d.Path not in self._defs: 457 | self._defs[d.Path] = d 458 | # Add self-reference. 459 | self._add_ref(Ref( 460 | DefRepo=d.Repo, 461 | DefUnit=d.Unit, 462 | DefUnitType=d.UnitType, 463 | DefPath=d.Path, 464 | Unit=self._unit, 465 | UnitType=self._unit_type, 466 | Def=True, 467 | File=d.File, 468 | Start=d.DefStart, 469 | End=d.DefEnd, 470 | ToBuiltin=False, 471 | )) 472 | 473 | def _add_ref(self, r): 474 | """ Add a reference. """ 475 | self._log.debug('adding ref: %s', r.DefPath) 476 | key = (r.DefPath, r.File, r.Start, r.End) 477 | if key not in self._refs: 478 | self._refs[key] = r 479 | 480 | def _add_doc(self, d): 481 | """ Add a docstring. """ 482 | key = DefKey(Repo="", Unit=d.Unit, UnitType=d.UnitType, Path=d.Path) 483 | if key in self._docs: 484 | raise Exception("Attempt to add duplicate doc for {}", key) 485 | self._docs[key] = d 486 | 487 | def _to_offset(self, line, column): 488 | """ 489 | Converts from (line, col) position to byte offset. 490 | Line is 1-indexed, column is 0-indexed. 491 | """ 492 | line -= 1 493 | if line >= len(self._cumulative_off): 494 | raise FileGrapherException('requested line out of bounds {} > {}'.format( 495 | line + 1, 496 | len(self._cumulative_off) - 1) 497 | ) 498 | return self._cumulative_off[line] + column 499 | -------------------------------------------------------------------------------- /testdata/expected/python-sample-0/python-sample-0/PipPackage.graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "Defs": [ 3 | { 4 | "UnitType": "PipPackage", 5 | "Unit": "python-sample-0", 6 | "Path": "pkg0/__init__.py/pkg0.pkg0", 7 | "Name": "pkg0", 8 | "Kind": "module", 9 | "File": "pkg0/__init__.py", 10 | "DefStart": 0, 11 | "DefEnd": 0, 12 | "Exported": true, 13 | "Data": { 14 | "Keyword": "package", 15 | "Kind": "package", 16 | "Name": "pkg0", 17 | "Separator": "", 18 | "Type": "" 19 | } 20 | }, 21 | { 22 | "UnitType": "PipPackage", 23 | "Unit": "python-sample-0", 24 | "Path": "pkg0/m0.py/m0.Class0.Class0", 25 | "Name": "Class0", 26 | "Kind": "class", 27 | "File": "pkg0/m0.py", 28 | "DefStart": 60, 29 | "DefEnd": 66, 30 | "Exported": true, 31 | "Data": { 32 | "Keyword": "class", 33 | "Kind": "class", 34 | "Name": "Class0(object)", 35 | "Separator": " ", 36 | "Type": "" 37 | } 38 | }, 39 | { 40 | "UnitType": "PipPackage", 41 | "Unit": "python-sample-0", 42 | "Path": "pkg0/m0.py/m0.Class0.meth0.meth0", 43 | "Name": "meth0", 44 | "Kind": "function", 45 | "File": "pkg0/m0.py", 46 | "DefStart": 124, 47 | "DefEnd": 129, 48 | "Exported": true, 49 | "Data": { 50 | "Keyword": "def", 51 | "Kind": "function", 52 | "Name": "Class0.meth0", 53 | "Separator": "", 54 | "Type": "(self)" 55 | } 56 | }, 57 | { 58 | "UnitType": "PipPackage", 59 | "Unit": "python-sample-0", 60 | "Path": "pkg0/m0.py/m0.Class0.var0", 61 | "Name": "var0", 62 | "Kind": "statement", 63 | "File": "pkg0/m0.py", 64 | "DefStart": 107, 65 | "DefEnd": 111, 66 | "Exported": true, 67 | "Data": { 68 | "Keyword": "", 69 | "Kind": "statement", 70 | "Name": "Class0.var0", 71 | "Separator": " ", 72 | "Type": "= 0" 73 | } 74 | }, 75 | { 76 | "UnitType": "PipPackage", 77 | "Unit": "python-sample-0", 78 | "Path": "pkg0/m0.py/m0.Class0_0.Class0_0", 79 | "Name": "Class0_0", 80 | "Kind": "class", 81 | "File": "pkg0/m0.py", 82 | "DefStart": 380, 83 | "DefEnd": 388, 84 | "Exported": true, 85 | "Data": { 86 | "Keyword": "class", 87 | "Kind": "class", 88 | "Name": "Class0_0(Class0)", 89 | "Separator": " ", 90 | "Type": "" 91 | } 92 | }, 93 | { 94 | "UnitType": "PipPackage", 95 | "Unit": "python-sample-0", 96 | "Path": "pkg0/m0.py/m0.Class0_0.__init__.__init__", 97 | "Name": "__init__", 98 | "Kind": "function", 99 | "File": "pkg0/m0.py", 100 | "DefStart": 406, 101 | "DefEnd": 414, 102 | "Exported": true, 103 | "Data": { 104 | "Keyword": "def", 105 | "Kind": "function", 106 | "Name": "Class0_0.__init__", 107 | "Separator": "", 108 | "Type": "(self, arg0, arg1, args, kwargs)" 109 | } 110 | }, 111 | { 112 | "UnitType": "PipPackage", 113 | "Unit": "python-sample-0", 114 | "Path": "pkg0/m0.py/m0.Class0_0.__init__.arg0.arg0", 115 | "Name": "arg0", 116 | "Kind": "param", 117 | "File": "pkg0/m0.py", 118 | "DefStart": 421, 119 | "DefEnd": 425, 120 | "Exported": true, 121 | "Data": { 122 | "Keyword": "", 123 | "Kind": "param", 124 | "Name": "arg0", 125 | "Separator": "", 126 | "Type": "" 127 | } 128 | }, 129 | { 130 | "UnitType": "PipPackage", 131 | "Unit": "python-sample-0", 132 | "Path": "pkg0/m0.py/m0.Class0_0.__init__.arg1.arg1", 133 | "Name": "arg1", 134 | "Kind": "param", 135 | "File": "pkg0/m0.py", 136 | "DefStart": 427, 137 | "DefEnd": 431, 138 | "Exported": true, 139 | "Data": { 140 | "Keyword": "", 141 | "Kind": "param", 142 | "Name": "arg1", 143 | "Separator": "", 144 | "Type": "" 145 | } 146 | }, 147 | { 148 | "UnitType": "PipPackage", 149 | "Unit": "python-sample-0", 150 | "Path": "pkg0/m0.py/m0.Class0_0.__init__.args.args", 151 | "Name": "args", 152 | "Kind": "param", 153 | "File": "pkg0/m0.py", 154 | "DefStart": 434, 155 | "DefEnd": 438, 156 | "Exported": true, 157 | "Data": { 158 | "Keyword": "", 159 | "Kind": "param", 160 | "Name": "args", 161 | "Separator": "", 162 | "Type": "" 163 | } 164 | }, 165 | { 166 | "UnitType": "PipPackage", 167 | "Unit": "python-sample-0", 168 | "Path": "pkg0/m0.py/m0.Class0_0.__init__.kwargs.kwargs", 169 | "Name": "kwargs", 170 | "Kind": "param", 171 | "File": "pkg0/m0.py", 172 | "DefStart": 442, 173 | "DefEnd": 448, 174 | "Exported": true, 175 | "Data": { 176 | "Keyword": "", 177 | "Kind": "param", 178 | "Name": "kwargs", 179 | "Separator": "", 180 | "Type": "" 181 | } 182 | }, 183 | { 184 | "UnitType": "PipPackage", 185 | "Unit": "python-sample-0", 186 | "Path": "pkg0/m0.py/m0.Class1.Class1", 187 | "Name": "Class1", 188 | "Kind": "class", 189 | "File": "pkg0/m0.py", 190 | "DefStart": 149, 191 | "DefEnd": 155, 192 | "Exported": true, 193 | "Data": { 194 | "Keyword": "class", 195 | "Kind": "class", 196 | "Name": "Class1(object)", 197 | "Separator": " ", 198 | "Type": "" 199 | } 200 | }, 201 | { 202 | "UnitType": "PipPackage", 203 | "Unit": "python-sample-0", 204 | "Path": "pkg0/m0.py/m0.Class1.__init__.__init__", 205 | "Name": "__init__", 206 | "Kind": "function", 207 | "File": "pkg0/m0.py", 208 | "DefStart": 173, 209 | "DefEnd": 181, 210 | "Exported": true, 211 | "Data": { 212 | "Keyword": "def", 213 | "Kind": "function", 214 | "Name": "Class1.__init__", 215 | "Separator": "", 216 | "Type": "(self)" 217 | } 218 | }, 219 | { 220 | "UnitType": "PipPackage", 221 | "Unit": "python-sample-0", 222 | "Path": "pkg0/m0.py/m0.Class1.meth0.meth0", 223 | "Name": "meth0", 224 | "Kind": "function", 225 | "File": "pkg0/m0.py", 226 | "DefStart": 268, 227 | "DefEnd": 273, 228 | "Exported": true, 229 | "Data": { 230 | "Keyword": "def", 231 | "Kind": "function", 232 | "Name": "Class1.meth0", 233 | "Separator": "", 234 | "Type": "(self)" 235 | } 236 | }, 237 | { 238 | "UnitType": "PipPackage", 239 | "Unit": "python-sample-0", 240 | "Path": "pkg0/m0.py/m0.Class1.meth0.var0", 241 | "Name": "var0", 242 | "Kind": "statement", 243 | "File": "pkg0/m0.py", 244 | "DefStart": 289, 245 | "DefEnd": 293, 246 | "Exported": true, 247 | "Data": { 248 | "Keyword": "", 249 | "Kind": "statement", 250 | "Name": "var0", 251 | "Separator": " ", 252 | "Type": "= Class0()" 253 | } 254 | }, 255 | { 256 | "UnitType": "PipPackage", 257 | "Unit": "python-sample-0", 258 | "Path": "pkg0/m0.py/m0.Class1.meth0.x", 259 | "Name": "x", 260 | "Kind": "statement", 261 | "File": "pkg0/m0.py", 262 | "DefStart": 359, 263 | "DefEnd": 360, 264 | "Exported": true, 265 | "Data": { 266 | "Keyword": "", 267 | "Kind": "statement", 268 | "Name": "x", 269 | "Separator": " ", 270 | "Type": "= self.var1" 271 | } 272 | }, 273 | { 274 | "UnitType": "PipPackage", 275 | "Unit": "python-sample-0", 276 | "Path": "pkg0/m0.py/m0.Class1.var0", 277 | "Name": "var0", 278 | "Kind": "statement", 279 | "File": "pkg0/m0.py", 280 | "DefStart": 202, 281 | "DefEnd": 206, 282 | "Exported": true, 283 | "Data": { 284 | "Keyword": "", 285 | "Kind": "statement", 286 | "Name": "(Class1) self.var0", 287 | "Separator": " ", 288 | "Type": "= {0, []}" 289 | } 290 | }, 291 | { 292 | "UnitType": "PipPackage", 293 | "Unit": "python-sample-0", 294 | "Path": "pkg0/m0.py/m0.Class1.var1", 295 | "Name": "var1", 296 | "Kind": "statement", 297 | "File": "pkg0/m0.py", 298 | "DefStart": 247, 299 | "DefEnd": 251, 300 | "Exported": true, 301 | "Data": { 302 | "Keyword": "", 303 | "Kind": "statement", 304 | "Name": "(Class1) self.var1", 305 | "Separator": " ", 306 | "Type": "= {None, var0}" 307 | } 308 | }, 309 | { 310 | "UnitType": "PipPackage", 311 | "Unit": "python-sample-0", 312 | "Path": "pkg0/m0.py/m0.f0.f0", 313 | "Name": "f0", 314 | "Kind": "function", 315 | "File": "pkg0/m0.py", 316 | "DefStart": 494, 317 | "DefEnd": 496, 318 | "Exported": true, 319 | "Data": { 320 | "Keyword": "def", 321 | "Kind": "function", 322 | "Name": "f0", 323 | "Separator": "", 324 | "Type": "()" 325 | } 326 | }, 327 | { 328 | "UnitType": "PipPackage", 329 | "Unit": "python-sample-0", 330 | "Path": "pkg0/m0.py/m0.f0.var0", 331 | "Name": "var0", 332 | "Kind": "statement", 333 | "File": "pkg0/m0.py", 334 | "DefStart": 504, 335 | "DefEnd": 508, 336 | "Exported": true, 337 | "Data": { 338 | "Keyword": "", 339 | "Kind": "statement", 340 | "Name": "var0", 341 | "Separator": " ", 342 | "Type": "= Class0()" 343 | } 344 | }, 345 | { 346 | "UnitType": "PipPackage", 347 | "Unit": "python-sample-0", 348 | "Path": "pkg0/m0.py/m0.f0.var1", 349 | "Name": "var1", 350 | "Kind": "statement", 351 | "File": "pkg0/m0.py", 352 | "DefStart": 524, 353 | "DefEnd": 528, 354 | "Exported": true, 355 | "Data": { 356 | "Keyword": "", 357 | "Kind": "statement", 358 | "Name": "var1", 359 | "Separator": " ", 360 | "Type": "= Class1()" 361 | } 362 | }, 363 | { 364 | "UnitType": "PipPackage", 365 | "Unit": "python-sample-0", 366 | "Path": "pkg0/m0.py/m0.f0.var2", 367 | "Name": "var2", 368 | "Kind": "statement", 369 | "File": "pkg0/m0.py", 370 | "DefStart": 544, 371 | "DefEnd": 548, 372 | "Exported": true, 373 | "Data": { 374 | "Keyword": "", 375 | "Kind": "statement", 376 | "Name": "var2", 377 | "Separator": " ", 378 | "Type": "= Class0_0(1, 2)" 379 | } 380 | }, 381 | { 382 | "UnitType": "PipPackage", 383 | "Unit": "python-sample-0", 384 | "Path": "pkg0/m0.py/m0.x", 385 | "Name": "x", 386 | "Kind": "statement", 387 | "File": "pkg0/m0.py", 388 | "DefStart": 630, 389 | "DefEnd": 631, 390 | "Exported": true, 391 | "Data": { 392 | "Keyword": "", 393 | "Kind": "statement", 394 | "Name": "x", 395 | "Separator": " ", 396 | "Type": "= 1" 397 | } 398 | }, 399 | { 400 | "UnitType": "PipPackage", 401 | "Unit": "python-sample-0", 402 | "Path": "pkg0/m0.py/pkg0.m0.m0", 403 | "Name": "m0.py", 404 | "Kind": "module", 405 | "File": "pkg0/m0.py", 406 | "DefStart": 0, 407 | "DefEnd": 0, 408 | "Exported": true, 409 | "Data": { 410 | "Keyword": "module", 411 | "Kind": "module", 412 | "Name": "pkg0.m0", 413 | "Separator": "", 414 | "Type": "" 415 | } 416 | }, 417 | { 418 | "UnitType": "PipPackage", 419 | "Unit": "python-sample-0", 420 | "Path": "pkg0/m1.py/m1.Class0_0.Class0_0", 421 | "Name": "Class0_0", 422 | "Kind": "class", 423 | "File": "pkg0/m1.py", 424 | "DefStart": 90, 425 | "DefEnd": 98, 426 | "Exported": true, 427 | "Data": { 428 | "Keyword": "class", 429 | "Kind": "class", 430 | "Name": "Class0_0(Class0)", 431 | "Separator": " ", 432 | "Type": "" 433 | } 434 | }, 435 | { 436 | "UnitType": "PipPackage", 437 | "Unit": "python-sample-0", 438 | "Path": "pkg0/m1.py/m1.Class0_0.__init__.__init__", 439 | "Name": "__init__", 440 | "Kind": "function", 441 | "File": "pkg0/m1.py", 442 | "DefStart": 116, 443 | "DefEnd": 124, 444 | "Exported": true, 445 | "Data": { 446 | "Keyword": "def", 447 | "Kind": "function", 448 | "Name": "Class0_0.__init__", 449 | "Separator": "", 450 | "Type": "(self)" 451 | } 452 | }, 453 | { 454 | "UnitType": "PipPackage", 455 | "Unit": "python-sample-0", 456 | "Path": "pkg0/m1.py/m1.m2_fn1.m2_fn1", 457 | "Name": "m2_fn1", 458 | "Kind": "function", 459 | "File": "pkg0/m1.py", 460 | "DefStart": 178, 461 | "DefEnd": 184, 462 | "Exported": true, 463 | "Data": { 464 | "Keyword": "def", 465 | "Kind": "function", 466 | "Name": "m2_fn1", 467 | "Separator": "", 468 | "Type": "()" 469 | } 470 | }, 471 | { 472 | "UnitType": "PipPackage", 473 | "Unit": "python-sample-0", 474 | "Path": "pkg0/m1.py/m1.m2_fn1.var0", 475 | "Name": "var0", 476 | "Kind": "statement", 477 | "File": "pkg0/m1.py", 478 | "DefStart": 192, 479 | "DefEnd": 196, 480 | "Exported": true, 481 | "Data": { 482 | "Keyword": "", 483 | "Kind": "statement", 484 | "Name": "var0", 485 | "Separator": " ", 486 | "Type": "= Class0()" 487 | } 488 | }, 489 | { 490 | "UnitType": "PipPackage", 491 | "Unit": "python-sample-0", 492 | "Path": "pkg0/m1.py/m1.m2_fn1.var1", 493 | "Name": "var1", 494 | "Kind": "statement", 495 | "File": "pkg0/m1.py", 496 | "DefStart": 212, 497 | "DefEnd": 216, 498 | "Exported": true, 499 | "Data": { 500 | "Keyword": "", 501 | "Kind": "statement", 502 | "Name": "var1", 503 | "Separator": " ", 504 | "Type": "= Class0_0()" 505 | } 506 | }, 507 | { 508 | "UnitType": "PipPackage", 509 | "Unit": "python-sample-0", 510 | "Path": "pkg0/m1.py/m1.m2_fn1.var2", 511 | "Name": "var2", 512 | "Kind": "statement", 513 | "File": "pkg0/m1.py", 514 | "DefStart": 234, 515 | "DefEnd": 238, 516 | "Exported": true, 517 | "Data": { 518 | "Keyword": "", 519 | "Kind": "statement", 520 | "Name": "var2", 521 | "Separator": " ", 522 | "Type": "= var0.meth0()" 523 | } 524 | }, 525 | { 526 | "UnitType": "PipPackage", 527 | "Unit": "python-sample-0", 528 | "Path": "pkg0/m1.py/pkg0.m1.m1", 529 | "Name": "m1.py", 530 | "Kind": "module", 531 | "File": "pkg0/m1.py", 532 | "DefStart": 0, 533 | "DefEnd": 0, 534 | "Exported": true, 535 | "Data": { 536 | "Keyword": "module", 537 | "Kind": "module", 538 | "Name": "pkg0.m1", 539 | "Separator": "", 540 | "Type": "" 541 | } 542 | }, 543 | { 544 | "UnitType": "PipPackage", 545 | "Unit": "python-sample-0", 546 | "Path": "setup.py/setup.setup", 547 | "Name": "setup.py", 548 | "Kind": "module", 549 | "File": "setup.py", 550 | "DefStart": 0, 551 | "DefEnd": 0, 552 | "Exported": true, 553 | "Data": { 554 | "Keyword": "module", 555 | "Kind": "module", 556 | "Name": "setup", 557 | "Separator": "", 558 | "Type": "" 559 | } 560 | } 561 | ], 562 | "Refs": [ 563 | { 564 | "DefRepo": "github.com/python/cpython", 565 | "DefUnitType": "PipPackage", 566 | "DefUnit": "__builtin__", 567 | "DefPath": "object.__init__", 568 | "UnitType": "PipPackage", 569 | "Unit": "python-sample-0", 570 | "File": "pkg0/m1.py", 571 | "Start": 162, 572 | "End": 170 573 | }, 574 | { 575 | "DefRepo": "github.com/python/cpython", 576 | "DefUnitType": "PipPackage", 577 | "DefUnit": "__builtin__", 578 | "DefPath": "object", 579 | "UnitType": "PipPackage", 580 | "Unit": "python-sample-0", 581 | "File": "pkg0/m0.py", 582 | "Start": 156, 583 | "End": 162 584 | }, 585 | { 586 | "DefRepo": "github.com/python/cpython", 587 | "DefUnitType": "PipPackage", 588 | "DefUnit": "__builtin__", 589 | "DefPath": "object", 590 | "UnitType": "PipPackage", 591 | "Unit": "python-sample-0", 592 | "File": "pkg0/m0.py", 593 | "Start": 67, 594 | "End": 73 595 | }, 596 | { 597 | "DefRepo": "github.com/python/cpython", 598 | "DefUnitType": "PipPackage", 599 | "DefUnit": "Python", 600 | "DefPath": "os.py/os.os", 601 | "UnitType": "PipPackage", 602 | "Unit": "python-sample-0", 603 | "File": "pkg0/m0.py", 604 | "Start": 50, 605 | "End": 52 606 | }, 607 | { 608 | "DefUnitType": "PipPackage", 609 | "DefUnit": "python-sample-0", 610 | "DefPath": "pkg0/__init__.py/pkg0.pkg0", 611 | "UnitType": "PipPackage", 612 | "Unit": "python-sample-0", 613 | "Def": true, 614 | "File": "pkg0/__init__.py", 615 | "Start": 0, 616 | "End": 0 617 | }, 618 | { 619 | "DefUnitType": "PipPackage", 620 | "DefUnit": "python-sample-0", 621 | "DefPath": "pkg0/__init__.py/pkg0.pkg0", 622 | "UnitType": "PipPackage", 623 | "Unit": "python-sample-0", 624 | "File": "pkg0/m1.py", 625 | "Start": 265, 626 | "End": 269 627 | }, 628 | { 629 | "DefUnitType": "PipPackage", 630 | "DefUnit": "python-sample-0", 631 | "DefPath": "pkg0/__init__.py/pkg0.pkg0", 632 | "UnitType": "PipPackage", 633 | "Unit": "python-sample-0", 634 | "File": "pkg0/m1.py", 635 | "Start": 51, 636 | "End": 55 637 | }, 638 | { 639 | "DefUnitType": "PipPackage", 640 | "DefUnit": "python-sample-0", 641 | "DefPath": "pkg0/__init__.py/pkg0.pkg0", 642 | "UnitType": "PipPackage", 643 | "Unit": "python-sample-0", 644 | "File": "pkg0/m1.py", 645 | "Start": 61, 646 | "End": 65 647 | }, 648 | { 649 | "DefUnitType": "PipPackage", 650 | "DefUnit": "python-sample-0", 651 | "DefPath": "pkg0/m0.py/m0.Class0.Class0", 652 | "UnitType": "PipPackage", 653 | "Unit": "python-sample-0", 654 | "Def": true, 655 | "File": "pkg0/m0.py", 656 | "Start": 130, 657 | "End": 134 658 | }, 659 | { 660 | "DefUnitType": "PipPackage", 661 | "DefUnit": "python-sample-0", 662 | "DefPath": "pkg0/m0.py/m0.Class0.Class0", 663 | "UnitType": "PipPackage", 664 | "Unit": "python-sample-0", 665 | "File": "pkg0/m0.py", 666 | "Start": 296, 667 | "End": 302 668 | }, 669 | { 670 | "DefUnitType": "PipPackage", 671 | "DefUnit": "python-sample-0", 672 | "DefPath": "pkg0/m0.py/m0.Class0.Class0", 673 | "UnitType": "PipPackage", 674 | "Unit": "python-sample-0", 675 | "File": "pkg0/m0.py", 676 | "Start": 389, 677 | "End": 395 678 | }, 679 | { 680 | "DefUnitType": "PipPackage", 681 | "DefUnit": "python-sample-0", 682 | "DefPath": "pkg0/m0.py/m0.Class0.Class0", 683 | "UnitType": "PipPackage", 684 | "Unit": "python-sample-0", 685 | "File": "pkg0/m0.py", 686 | "Start": 511, 687 | "End": 517 688 | }, 689 | { 690 | "DefUnitType": "PipPackage", 691 | "DefUnit": "python-sample-0", 692 | "DefPath": "pkg0/m0.py/m0.Class0.Class0", 693 | "UnitType": "PipPackage", 694 | "Unit": "python-sample-0", 695 | "Def": true, 696 | "File": "pkg0/m0.py", 697 | "Start": 60, 698 | "End": 66 699 | }, 700 | { 701 | "DefUnitType": "PipPackage", 702 | "DefUnit": "python-sample-0", 703 | "DefPath": "pkg0/m0.py/m0.Class0.Class0", 704 | "UnitType": "PipPackage", 705 | "Unit": "python-sample-0", 706 | "File": "pkg0/m1.py", 707 | "Start": 199, 708 | "End": 205 709 | }, 710 | { 711 | "DefUnitType": "PipPackage", 712 | "DefUnit": "python-sample-0", 713 | "DefPath": "pkg0/m0.py/m0.Class0.Class0", 714 | "UnitType": "PipPackage", 715 | "Unit": "python-sample-0", 716 | "File": "pkg0/m1.py", 717 | "Start": 76, 718 | "End": 82 719 | }, 720 | { 721 | "DefUnitType": "PipPackage", 722 | "DefUnit": "python-sample-0", 723 | "DefPath": "pkg0/m0.py/m0.Class0.Class0", 724 | "UnitType": "PipPackage", 725 | "Unit": "python-sample-0", 726 | "File": "pkg0/m1.py", 727 | "Start": 99, 728 | "End": 105 729 | }, 730 | { 731 | "DefUnitType": "PipPackage", 732 | "DefUnit": "python-sample-0", 733 | "DefPath": "pkg0/m0.py/m0.Class0.meth0.meth0", 734 | "UnitType": "PipPackage", 735 | "Unit": "python-sample-0", 736 | "Def": true, 737 | "File": "pkg0/m0.py", 738 | "Start": 124, 739 | "End": 129 740 | }, 741 | { 742 | "DefUnitType": "PipPackage", 743 | "DefUnit": "python-sample-0", 744 | "DefPath": "pkg0/m0.py/m0.Class0.meth0.meth0", 745 | "UnitType": "PipPackage", 746 | "Unit": "python-sample-0", 747 | "File": "pkg0/m0.py", 748 | "Start": 318, 749 | "End": 323 750 | }, 751 | { 752 | "DefUnitType": "PipPackage", 753 | "DefUnit": "python-sample-0", 754 | "DefPath": "pkg0/m0.py/m0.Class0.meth0.meth0", 755 | "UnitType": "PipPackage", 756 | "Unit": "python-sample-0", 757 | "File": "pkg0/m0.py", 758 | "Start": 481, 759 | "End": 486 760 | }, 761 | { 762 | "DefUnitType": "PipPackage", 763 | "DefUnit": "python-sample-0", 764 | "DefPath": "pkg0/m0.py/m0.Class0.meth0.meth0", 765 | "UnitType": "PipPackage", 766 | "Unit": "python-sample-0", 767 | "File": "pkg0/m1.py", 768 | "Start": 246, 769 | "End": 251 770 | }, 771 | { 772 | "DefUnitType": "PipPackage", 773 | "DefUnit": "python-sample-0", 774 | "DefPath": "pkg0/m0.py/m0.Class0.var0", 775 | "UnitType": "PipPackage", 776 | "Unit": "python-sample-0", 777 | "Def": true, 778 | "File": "pkg0/m0.py", 779 | "Start": 107, 780 | "End": 111 781 | }, 782 | { 783 | "DefUnitType": "PipPackage", 784 | "DefUnit": "python-sample-0", 785 | "DefPath": "pkg0/m0.py/m0.Class0_0.Class0_0", 786 | "UnitType": "PipPackage", 787 | "Unit": "python-sample-0", 788 | "Def": true, 789 | "File": "pkg0/m0.py", 790 | "Start": 380, 791 | "End": 388 792 | }, 793 | { 794 | "DefUnitType": "PipPackage", 795 | "DefUnit": "python-sample-0", 796 | "DefPath": "pkg0/m0.py/m0.Class0_0.Class0_0", 797 | "UnitType": "PipPackage", 798 | "Unit": "python-sample-0", 799 | "Def": true, 800 | "File": "pkg0/m0.py", 801 | "Start": 415, 802 | "End": 419 803 | }, 804 | { 805 | "DefUnitType": "PipPackage", 806 | "DefUnit": "python-sample-0", 807 | "DefPath": "pkg0/m0.py/m0.Class0_0.Class0_0", 808 | "UnitType": "PipPackage", 809 | "Unit": "python-sample-0", 810 | "File": "pkg0/m0.py", 811 | "Start": 465, 812 | "End": 473 813 | }, 814 | { 815 | "DefUnitType": "PipPackage", 816 | "DefUnit": "python-sample-0", 817 | "DefPath": "pkg0/m0.py/m0.Class0_0.Class0_0", 818 | "UnitType": "PipPackage", 819 | "Unit": "python-sample-0", 820 | "File": "pkg0/m0.py", 821 | "Start": 475, 822 | "End": 479 823 | }, 824 | { 825 | "DefUnitType": "PipPackage", 826 | "DefUnit": "python-sample-0", 827 | "DefPath": "pkg0/m0.py/m0.Class0_0.Class0_0", 828 | "UnitType": "PipPackage", 829 | "Unit": "python-sample-0", 830 | "File": "pkg0/m0.py", 831 | "Start": 551, 832 | "End": 559 833 | }, 834 | { 835 | "DefUnitType": "PipPackage", 836 | "DefUnit": "python-sample-0", 837 | "DefPath": "pkg0/m0.py/m0.Class0_0.Class0_0", 838 | "UnitType": "PipPackage", 839 | "Unit": "python-sample-0", 840 | "File": "pkg0/m1.py", 841 | "Start": 273, 842 | "End": 281 843 | }, 844 | { 845 | "DefUnitType": "PipPackage", 846 | "DefUnit": "python-sample-0", 847 | "DefPath": "pkg0/m0.py/m0.Class0_0.__init__.__init__", 848 | "UnitType": "PipPackage", 849 | "Unit": "python-sample-0", 850 | "Def": true, 851 | "File": "pkg0/m0.py", 852 | "Start": 406, 853 | "End": 414 854 | }, 855 | { 856 | "DefUnitType": "PipPackage", 857 | "DefUnit": "python-sample-0", 858 | "DefPath": "pkg0/m0.py/m0.Class0_0.__init__.arg0.arg0", 859 | "UnitType": "PipPackage", 860 | "Unit": "python-sample-0", 861 | "Def": true, 862 | "File": "pkg0/m0.py", 863 | "Start": 421, 864 | "End": 425 865 | }, 866 | { 867 | "DefUnitType": "PipPackage", 868 | "DefUnit": "python-sample-0", 869 | "DefPath": "pkg0/m0.py/m0.Class0_0.__init__.arg1.arg1", 870 | "UnitType": "PipPackage", 871 | "Unit": "python-sample-0", 872 | "Def": true, 873 | "File": "pkg0/m0.py", 874 | "Start": 427, 875 | "End": 431 876 | }, 877 | { 878 | "DefUnitType": "PipPackage", 879 | "DefUnit": "python-sample-0", 880 | "DefPath": "pkg0/m0.py/m0.Class0_0.__init__.args.args", 881 | "UnitType": "PipPackage", 882 | "Unit": "python-sample-0", 883 | "Def": true, 884 | "File": "pkg0/m0.py", 885 | "Start": 434, 886 | "End": 438 887 | }, 888 | { 889 | "DefUnitType": "PipPackage", 890 | "DefUnit": "python-sample-0", 891 | "DefPath": "pkg0/m0.py/m0.Class0_0.__init__.kwargs.kwargs", 892 | "UnitType": "PipPackage", 893 | "Unit": "python-sample-0", 894 | "Def": true, 895 | "File": "pkg0/m0.py", 896 | "Start": 442, 897 | "End": 448 898 | }, 899 | { 900 | "DefUnitType": "PipPackage", 901 | "DefUnit": "python-sample-0", 902 | "DefPath": "pkg0/m0.py/m0.Class1.Class1", 903 | "UnitType": "PipPackage", 904 | "Unit": "python-sample-0", 905 | "Def": true, 906 | "File": "pkg0/m0.py", 907 | "Start": 149, 908 | "End": 155 909 | }, 910 | { 911 | "DefUnitType": "PipPackage", 912 | "DefUnit": "python-sample-0", 913 | "DefPath": "pkg0/m0.py/m0.Class1.Class1", 914 | "UnitType": "PipPackage", 915 | "Unit": "python-sample-0", 916 | "Def": true, 917 | "File": "pkg0/m0.py", 918 | "Start": 182, 919 | "End": 186 920 | }, 921 | { 922 | "DefUnitType": "PipPackage", 923 | "DefUnit": "python-sample-0", 924 | "DefPath": "pkg0/m0.py/m0.Class1.Class1", 925 | "UnitType": "PipPackage", 926 | "Unit": "python-sample-0", 927 | "File": "pkg0/m0.py", 928 | "Start": 197, 929 | "End": 201 930 | }, 931 | { 932 | "DefUnitType": "PipPackage", 933 | "DefUnit": "python-sample-0", 934 | "DefPath": "pkg0/m0.py/m0.Class1.Class1", 935 | "UnitType": "PipPackage", 936 | "Unit": "python-sample-0", 937 | "File": "pkg0/m0.py", 938 | "Start": 219, 939 | "End": 223 940 | }, 941 | { 942 | "DefUnitType": "PipPackage", 943 | "DefUnit": "python-sample-0", 944 | "DefPath": "pkg0/m0.py/m0.Class1.Class1", 945 | "UnitType": "PipPackage", 946 | "Unit": "python-sample-0", 947 | "File": "pkg0/m0.py", 948 | "Start": 242, 949 | "End": 246 950 | }, 951 | { 952 | "DefUnitType": "PipPackage", 953 | "DefUnit": "python-sample-0", 954 | "DefPath": "pkg0/m0.py/m0.Class1.Class1", 955 | "UnitType": "PipPackage", 956 | "Unit": "python-sample-0", 957 | "Def": true, 958 | "File": "pkg0/m0.py", 959 | "Start": 274, 960 | "End": 278 961 | }, 962 | { 963 | "DefUnitType": "PipPackage", 964 | "DefUnit": "python-sample-0", 965 | "DefPath": "pkg0/m0.py/m0.Class1.Class1", 966 | "UnitType": "PipPackage", 967 | "Unit": "python-sample-0", 968 | "File": "pkg0/m0.py", 969 | "Start": 334, 970 | "End": 338 971 | }, 972 | { 973 | "DefUnitType": "PipPackage", 974 | "DefUnit": "python-sample-0", 975 | "DefPath": "pkg0/m0.py/m0.Class1.Class1", 976 | "UnitType": "PipPackage", 977 | "Unit": "python-sample-0", 978 | "File": "pkg0/m0.py", 979 | "Start": 363, 980 | "End": 367 981 | }, 982 | { 983 | "DefUnitType": "PipPackage", 984 | "DefUnit": "python-sample-0", 985 | "DefPath": "pkg0/m0.py/m0.Class1.Class1", 986 | "UnitType": "PipPackage", 987 | "Unit": "python-sample-0", 988 | "File": "pkg0/m0.py", 989 | "Start": 531, 990 | "End": 537 991 | }, 992 | { 993 | "DefUnitType": "PipPackage", 994 | "DefUnit": "python-sample-0", 995 | "DefPath": "pkg0/m0.py/m0.Class1.__init__.__init__", 996 | "UnitType": "PipPackage", 997 | "Unit": "python-sample-0", 998 | "Def": true, 999 | "File": "pkg0/m0.py", 1000 | "Start": 173, 1001 | "End": 181 1002 | }, 1003 | { 1004 | "DefUnitType": "PipPackage", 1005 | "DefUnit": "python-sample-0", 1006 | "DefPath": "pkg0/m0.py/m0.Class1.meth0.meth0", 1007 | "UnitType": "PipPackage", 1008 | "Unit": "python-sample-0", 1009 | "Def": true, 1010 | "File": "pkg0/m0.py", 1011 | "Start": 268, 1012 | "End": 273 1013 | }, 1014 | { 1015 | "DefUnitType": "PipPackage", 1016 | "DefUnit": "python-sample-0", 1017 | "DefPath": "pkg0/m0.py/m0.Class1.meth0.var0", 1018 | "UnitType": "PipPackage", 1019 | "Unit": "python-sample-0", 1020 | "Def": true, 1021 | "File": "pkg0/m0.py", 1022 | "Start": 289, 1023 | "End": 293 1024 | }, 1025 | { 1026 | "DefUnitType": "PipPackage", 1027 | "DefUnit": "python-sample-0", 1028 | "DefPath": "pkg0/m0.py/m0.Class1.meth0.var0", 1029 | "UnitType": "PipPackage", 1030 | "Unit": "python-sample-0", 1031 | "File": "pkg0/m0.py", 1032 | "Start": 313, 1033 | "End": 317 1034 | }, 1035 | { 1036 | "DefUnitType": "PipPackage", 1037 | "DefUnit": "python-sample-0", 1038 | "DefPath": "pkg0/m0.py/m0.Class1.meth0.var0", 1039 | "UnitType": "PipPackage", 1040 | "Unit": "python-sample-0", 1041 | "File": "pkg0/m0.py", 1042 | "Start": 346, 1043 | "End": 350 1044 | }, 1045 | { 1046 | "DefUnitType": "PipPackage", 1047 | "DefUnit": "python-sample-0", 1048 | "DefPath": "pkg0/m0.py/m0.Class1.meth0.x", 1049 | "UnitType": "PipPackage", 1050 | "Unit": "python-sample-0", 1051 | "Def": true, 1052 | "File": "pkg0/m0.py", 1053 | "Start": 359, 1054 | "End": 360 1055 | }, 1056 | { 1057 | "DefUnitType": "PipPackage", 1058 | "DefUnit": "python-sample-0", 1059 | "DefPath": "pkg0/m0.py/m0.Class1.var0", 1060 | "UnitType": "PipPackage", 1061 | "Unit": "python-sample-0", 1062 | "Def": true, 1063 | "File": "pkg0/m0.py", 1064 | "Start": 202, 1065 | "End": 206 1066 | }, 1067 | { 1068 | "DefUnitType": "PipPackage", 1069 | "DefUnit": "python-sample-0", 1070 | "DefPath": "pkg0/m0.py/m0.Class1.var0", 1071 | "UnitType": "PipPackage", 1072 | "Unit": "python-sample-0", 1073 | "Def": true, 1074 | "File": "pkg0/m0.py", 1075 | "Start": 224, 1076 | "End": 228 1077 | }, 1078 | { 1079 | "DefUnitType": "PipPackage", 1080 | "DefUnit": "python-sample-0", 1081 | "DefPath": "pkg0/m0.py/m0.Class1.var1", 1082 | "UnitType": "PipPackage", 1083 | "Unit": "python-sample-0", 1084 | "Def": true, 1085 | "File": "pkg0/m0.py", 1086 | "Start": 247, 1087 | "End": 251 1088 | }, 1089 | { 1090 | "DefUnitType": "PipPackage", 1091 | "DefUnit": "python-sample-0", 1092 | "DefPath": "pkg0/m0.py/m0.Class1.var1", 1093 | "UnitType": "PipPackage", 1094 | "Unit": "python-sample-0", 1095 | "Def": true, 1096 | "File": "pkg0/m0.py", 1097 | "Start": 339, 1098 | "End": 343 1099 | }, 1100 | { 1101 | "DefUnitType": "PipPackage", 1102 | "DefUnit": "python-sample-0", 1103 | "DefPath": "pkg0/m0.py/m0.Class1.var1", 1104 | "UnitType": "PipPackage", 1105 | "Unit": "python-sample-0", 1106 | "File": "pkg0/m0.py", 1107 | "Start": 368, 1108 | "End": 372 1109 | }, 1110 | { 1111 | "DefUnitType": "PipPackage", 1112 | "DefUnit": "python-sample-0", 1113 | "DefPath": "pkg0/m0.py/m0.f0.f0", 1114 | "UnitType": "PipPackage", 1115 | "Unit": "python-sample-0", 1116 | "Def": true, 1117 | "File": "pkg0/m0.py", 1118 | "Start": 494, 1119 | "End": 496 1120 | }, 1121 | { 1122 | "DefUnitType": "PipPackage", 1123 | "DefUnit": "python-sample-0", 1124 | "DefPath": "pkg0/m0.py/m0.f0.var0", 1125 | "UnitType": "PipPackage", 1126 | "Unit": "python-sample-0", 1127 | "Def": true, 1128 | "File": "pkg0/m0.py", 1129 | "Start": 504, 1130 | "End": 508 1131 | }, 1132 | { 1133 | "DefUnitType": "PipPackage", 1134 | "DefUnit": "python-sample-0", 1135 | "DefPath": "pkg0/m0.py/m0.f0.var0", 1136 | "UnitType": "PipPackage", 1137 | "Unit": "python-sample-0", 1138 | "File": "pkg0/m0.py", 1139 | "Start": 578, 1140 | "End": 582 1141 | }, 1142 | { 1143 | "DefUnitType": "PipPackage", 1144 | "DefUnit": "python-sample-0", 1145 | "DefPath": "pkg0/m0.py/m0.f0.var1", 1146 | "UnitType": "PipPackage", 1147 | "Unit": "python-sample-0", 1148 | "Def": true, 1149 | "File": "pkg0/m0.py", 1150 | "Start": 524, 1151 | "End": 528 1152 | }, 1153 | { 1154 | "DefUnitType": "PipPackage", 1155 | "DefUnit": "python-sample-0", 1156 | "DefPath": "pkg0/m0.py/m0.f0.var1", 1157 | "UnitType": "PipPackage", 1158 | "Unit": "python-sample-0", 1159 | "File": "pkg0/m0.py", 1160 | "Start": 584, 1161 | "End": 588 1162 | }, 1163 | { 1164 | "DefUnitType": "PipPackage", 1165 | "DefUnit": "python-sample-0", 1166 | "DefPath": "pkg0/m0.py/m0.f0.var2", 1167 | "UnitType": "PipPackage", 1168 | "Unit": "python-sample-0", 1169 | "Def": true, 1170 | "File": "pkg0/m0.py", 1171 | "Start": 544, 1172 | "End": 548 1173 | }, 1174 | { 1175 | "DefUnitType": "PipPackage", 1176 | "DefUnit": "python-sample-0", 1177 | "DefPath": "pkg0/m0.py/m0.f0.var2", 1178 | "UnitType": "PipPackage", 1179 | "Unit": "python-sample-0", 1180 | "File": "pkg0/m0.py", 1181 | "Start": 590, 1182 | "End": 594 1183 | }, 1184 | { 1185 | "DefUnitType": "PipPackage", 1186 | "DefUnit": "python-sample-0", 1187 | "DefPath": "pkg0/m0.py/m0.x", 1188 | "UnitType": "PipPackage", 1189 | "Unit": "python-sample-0", 1190 | "Def": true, 1191 | "File": "pkg0/m0.py", 1192 | "Start": 630, 1193 | "End": 631 1194 | }, 1195 | { 1196 | "DefUnitType": "PipPackage", 1197 | "DefUnit": "python-sample-0", 1198 | "DefPath": "pkg0/m0.py/m0.x", 1199 | "UnitType": "PipPackage", 1200 | "Unit": "python-sample-0", 1201 | "Def": true, 1202 | "File": "pkg0/m0.py", 1203 | "Start": 649, 1204 | "End": 650 1205 | }, 1206 | { 1207 | "DefUnitType": "PipPackage", 1208 | "DefUnit": "python-sample-0", 1209 | "DefPath": "pkg0/m0.py/pkg0.m0.m0", 1210 | "UnitType": "PipPackage", 1211 | "Unit": "python-sample-0", 1212 | "Def": true, 1213 | "File": "pkg0/m0.py", 1214 | "Start": 0, 1215 | "End": 0 1216 | }, 1217 | { 1218 | "DefUnitType": "PipPackage", 1219 | "DefUnit": "python-sample-0", 1220 | "DefPath": "pkg0/m0.py/pkg0.m0.m0", 1221 | "UnitType": "PipPackage", 1222 | "Unit": "python-sample-0", 1223 | "File": "pkg0/m1.py", 1224 | "Start": 270, 1225 | "End": 272 1226 | }, 1227 | { 1228 | "DefUnitType": "PipPackage", 1229 | "DefUnit": "python-sample-0", 1230 | "DefPath": "pkg0/m0.py/pkg0.m0.m0", 1231 | "UnitType": "PipPackage", 1232 | "Unit": "python-sample-0", 1233 | "File": "pkg0/m1.py", 1234 | "Start": 66, 1235 | "End": 68 1236 | }, 1237 | { 1238 | "DefUnitType": "PipPackage", 1239 | "DefUnit": "python-sample-0", 1240 | "DefPath": "pkg0/m1.py/m1.Class0_0.Class0_0", 1241 | "UnitType": "PipPackage", 1242 | "Unit": "python-sample-0", 1243 | "Def": true, 1244 | "File": "pkg0/m1.py", 1245 | "Start": 125, 1246 | "End": 129 1247 | }, 1248 | { 1249 | "DefUnitType": "PipPackage", 1250 | "DefUnit": "python-sample-0", 1251 | "DefPath": "pkg0/m1.py/m1.Class0_0.Class0_0", 1252 | "UnitType": "PipPackage", 1253 | "Unit": "python-sample-0", 1254 | "File": "pkg0/m1.py", 1255 | "Start": 146, 1256 | "End": 154 1257 | }, 1258 | { 1259 | "DefUnitType": "PipPackage", 1260 | "DefUnit": "python-sample-0", 1261 | "DefPath": "pkg0/m1.py/m1.Class0_0.Class0_0", 1262 | "UnitType": "PipPackage", 1263 | "Unit": "python-sample-0", 1264 | "File": "pkg0/m1.py", 1265 | "Start": 156, 1266 | "End": 160 1267 | }, 1268 | { 1269 | "DefUnitType": "PipPackage", 1270 | "DefUnit": "python-sample-0", 1271 | "DefPath": "pkg0/m1.py/m1.Class0_0.Class0_0", 1272 | "UnitType": "PipPackage", 1273 | "Unit": "python-sample-0", 1274 | "File": "pkg0/m1.py", 1275 | "Start": 219, 1276 | "End": 227 1277 | }, 1278 | { 1279 | "DefUnitType": "PipPackage", 1280 | "DefUnit": "python-sample-0", 1281 | "DefPath": "pkg0/m1.py/m1.Class0_0.Class0_0", 1282 | "UnitType": "PipPackage", 1283 | "Unit": "python-sample-0", 1284 | "Def": true, 1285 | "File": "pkg0/m1.py", 1286 | "Start": 90, 1287 | "End": 98 1288 | }, 1289 | { 1290 | "DefUnitType": "PipPackage", 1291 | "DefUnit": "python-sample-0", 1292 | "DefPath": "pkg0/m1.py/m1.Class0_0.__init__.__init__", 1293 | "UnitType": "PipPackage", 1294 | "Unit": "python-sample-0", 1295 | "Def": true, 1296 | "File": "pkg0/m1.py", 1297 | "Start": 116, 1298 | "End": 124 1299 | }, 1300 | { 1301 | "DefUnitType": "PipPackage", 1302 | "DefUnit": "python-sample-0", 1303 | "DefPath": "pkg0/m1.py/m1.m2_fn1.m2_fn1", 1304 | "UnitType": "PipPackage", 1305 | "Unit": "python-sample-0", 1306 | "Def": true, 1307 | "File": "pkg0/m1.py", 1308 | "Start": 178, 1309 | "End": 184 1310 | }, 1311 | { 1312 | "DefUnitType": "PipPackage", 1313 | "DefUnit": "python-sample-0", 1314 | "DefPath": "pkg0/m1.py/m1.m2_fn1.var0", 1315 | "UnitType": "PipPackage", 1316 | "Unit": "python-sample-0", 1317 | "Def": true, 1318 | "File": "pkg0/m1.py", 1319 | "Start": 192, 1320 | "End": 196 1321 | }, 1322 | { 1323 | "DefUnitType": "PipPackage", 1324 | "DefUnit": "python-sample-0", 1325 | "DefPath": "pkg0/m1.py/m1.m2_fn1.var0", 1326 | "UnitType": "PipPackage", 1327 | "Unit": "python-sample-0", 1328 | "File": "pkg0/m1.py", 1329 | "Start": 241, 1330 | "End": 245 1331 | }, 1332 | { 1333 | "DefUnitType": "PipPackage", 1334 | "DefUnit": "python-sample-0", 1335 | "DefPath": "pkg0/m1.py/m1.m2_fn1.var1", 1336 | "UnitType": "PipPackage", 1337 | "Unit": "python-sample-0", 1338 | "Def": true, 1339 | "File": "pkg0/m1.py", 1340 | "Start": 212, 1341 | "End": 216 1342 | }, 1343 | { 1344 | "DefUnitType": "PipPackage", 1345 | "DefUnit": "python-sample-0", 1346 | "DefPath": "pkg0/m1.py/m1.m2_fn1.var2", 1347 | "UnitType": "PipPackage", 1348 | "Unit": "python-sample-0", 1349 | "Def": true, 1350 | "File": "pkg0/m1.py", 1351 | "Start": 234, 1352 | "End": 238 1353 | }, 1354 | { 1355 | "DefUnitType": "PipPackage", 1356 | "DefUnit": "python-sample-0", 1357 | "DefPath": "pkg0/m1.py/pkg0.m1.m1", 1358 | "UnitType": "PipPackage", 1359 | "Unit": "python-sample-0", 1360 | "Def": true, 1361 | "File": "pkg0/m1.py", 1362 | "Start": 0, 1363 | "End": 0 1364 | }, 1365 | { 1366 | "DefUnitType": "PipPackage", 1367 | "DefUnit": "python-sample-0", 1368 | "DefPath": "setup.py/setup.install_requires", 1369 | "UnitType": "PipPackage", 1370 | "Unit": "python-sample-0", 1371 | "File": "setup.py", 1372 | "Start": 166, 1373 | "End": 182 1374 | }, 1375 | { 1376 | "DefUnitType": "PipPackage", 1377 | "DefUnit": "python-sample-0", 1378 | "DefPath": "setup.py/setup.name", 1379 | "UnitType": "PipPackage", 1380 | "Unit": "python-sample-0", 1381 | "File": "setup.py", 1382 | "Start": 41, 1383 | "End": 45 1384 | }, 1385 | { 1386 | "DefUnitType": "PipPackage", 1387 | "DefUnit": "python-sample-0", 1388 | "DefPath": "setup.py/setup.packages", 1389 | "UnitType": "PipPackage", 1390 | "Unit": "python-sample-0", 1391 | "File": "setup.py", 1392 | "Start": 143, 1393 | "End": 151 1394 | }, 1395 | { 1396 | "DefUnitType": "PipPackage", 1397 | "DefUnit": "python-sample-0", 1398 | "DefPath": "setup.py/setup.setup", 1399 | "UnitType": "PipPackage", 1400 | "Unit": "python-sample-0", 1401 | "Def": true, 1402 | "File": "setup.py", 1403 | "Start": 0, 1404 | "End": 0 1405 | }, 1406 | { 1407 | "DefUnitType": "PipPackage", 1408 | "DefUnit": "python-sample-0", 1409 | "DefPath": "setup.py/setup.url", 1410 | "UnitType": "PipPackage", 1411 | "Unit": "python-sample-0", 1412 | "File": "setup.py", 1413 | "Start": 90, 1414 | "End": 93 1415 | }, 1416 | { 1417 | "DefUnitType": "PipPackage", 1418 | "DefUnit": "python-sample-0", 1419 | "DefPath": "setup.py/setup.version", 1420 | "UnitType": "PipPackage", 1421 | "Unit": "python-sample-0", 1422 | "File": "setup.py", 1423 | "Start": 69, 1424 | "End": 76 1425 | }, 1426 | { 1427 | "DefRepo": "github.com/pypa/setuptools", 1428 | "DefUnitType": "PipPackage", 1429 | "DefUnit": "setuptools", 1430 | "DefPath": "setuptools/__init__.py/setuptools.setup", 1431 | "UnitType": "PipPackage", 1432 | "Unit": "python-sample-0", 1433 | "File": "setup.py", 1434 | "Start": 23, 1435 | "End": 28 1436 | }, 1437 | { 1438 | "DefRepo": "github.com/pypa/setuptools", 1439 | "DefUnitType": "PipPackage", 1440 | "DefUnit": "setuptools", 1441 | "DefPath": "setuptools/__init__.py/setuptools.setup", 1442 | "UnitType": "PipPackage", 1443 | "Unit": "python-sample-0", 1444 | "File": "setup.py", 1445 | "Start": 30, 1446 | "End": 35 1447 | }, 1448 | { 1449 | "DefRepo": "github.com/pypa/setuptools", 1450 | "DefUnitType": "PipPackage", 1451 | "DefUnit": "setuptools", 1452 | "DefPath": "setuptools/__init__.py/setuptools.setuptools", 1453 | "UnitType": "PipPackage", 1454 | "Unit": "python-sample-0", 1455 | "File": "setup.py", 1456 | "Start": 5, 1457 | "End": 15 1458 | }, 1459 | { 1460 | "DefRepo": "github.com/python/cpython", 1461 | "DefUnitType": "PipPackage", 1462 | "DefUnit": "__builtin__", 1463 | "DefPath": "super", 1464 | "UnitType": "PipPackage", 1465 | "Unit": "python-sample-0", 1466 | "File": "pkg0/m0.py", 1467 | "Start": 459, 1468 | "End": 464 1469 | }, 1470 | { 1471 | "DefRepo": "github.com/python/cpython", 1472 | "DefUnitType": "PipPackage", 1473 | "DefUnit": "__builtin__", 1474 | "DefPath": "super", 1475 | "UnitType": "PipPackage", 1476 | "Unit": "python-sample-0", 1477 | "File": "pkg0/m1.py", 1478 | "Start": 140, 1479 | "End": 145 1480 | } 1481 | ], 1482 | "Docs": [ 1483 | { 1484 | "UnitType": "PipPackage", 1485 | "Unit": "python-sample-0", 1486 | "Path": "pkg0/m0.py/m0.Class0.Class0", 1487 | "Format": "plaintext", 1488 | "Data": "Class0 docstring", 1489 | "File": "pkg0/m0.py" 1490 | }, 1491 | { 1492 | "UnitType": "PipPackage", 1493 | "Unit": "python-sample-0", 1494 | "Path": "pkg0/m0.py/m0.Class0.var0", 1495 | "Format": "plaintext", 1496 | "Data": "Class0 docstring", 1497 | "File": "pkg0/m0.py" 1498 | } 1499 | ] 1500 | } --------------------------------------------------------------------------------