Skip to content

Fixed broken build, made file paths OS-agnostic #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ jobs:
flake8_py3:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.8
uses: actions/setup-python@v2
- uses: actions/checkout@v4
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: 3.8
python-version: 3.12
- name: Install dependencies
run: |
python -m pip install --upgrade pip
Expand All @@ -32,11 +32,11 @@ jobs:
needs: [flake8_py3]
strategy:
matrix:
python: [3.8, 3.9, '3.10']
python: [3.12]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- name: Install dependencies
Expand Down
2 changes: 1 addition & 1 deletion .isort.cfg
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[settings]
known_third_party = clifier,matplotlib,networkx,pytest
known_third_party = click,matplotlib,networkx,pytest
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ repos:
hooks:
- id: seed-isort-config
- repo: https://github.com/pycqa/isort
rev: 5.4.2
rev: 5.13.2
hooks:
- id: isort
- repo: https://github.com/ambv/black
rev: stable
rev: 24.10.0
hooks:
- id: black
language_version: python3.8
language_version: python3.12
- repo: https://github.com/PyCQA/flake8
rev: 3.8.3
rev: 7.1.1
hooks:
- id: flake8
17 changes: 0 additions & 17 deletions codegraph/conf/cli.yml

This file was deleted.

40 changes: 38 additions & 2 deletions codegraph/core.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
from argparse import Namespace
from collections import defaultdict
from typing import Dict, List, Text, Tuple
from collections import defaultdict, deque
from typing import Dict, List, Set, Text, Tuple

from codegraph.parser import Import, create_objects_array
from codegraph.utils import get_python_paths_list
Expand Down Expand Up @@ -87,6 +87,42 @@ def usage_graph(self) -> Dict:
dependencies = populate_free_nodes(self.modules_data, dependencies)
return dependencies

def get_dependencies(self, file_path: str, distance: int) -> Dict[str, Set[str]]:
"""
Get dependencies that are 'distance' nodes away from the given file.

:param file_path: Path of the file to start from
:param distance: Number of edges to traverse
:return: Dictionary with distances as keys and sets of dependent files as values
"""
dependencies = {i: set() for i in range(1, distance + 1)}
graph = self.usage_graph()

if file_path not in graph:
return dependencies

queue = deque([(file_path, 0)])
visited = set()

while queue:
current_file, current_distance = queue.popleft()

if current_distance >= distance:
continue

if current_file not in visited:
visited.add(current_file)

for entity, used_entities in graph[current_file].items():
for used_entity in used_entities:
if "." in used_entity:
dependent_file = used_entity.split(".")[0] + ".py"
if dependent_file != current_file:
dependencies[current_distance + 1].add(dependent_file)
queue.append((dependent_file, current_distance + 1))

return dependencies


def get_module_name(code_path: Text) -> Text:
module_name = os.path.basename(code_path).replace(".py", "")
Expand Down
68 changes: 53 additions & 15 deletions codegraph/main.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,65 @@
""" main module of testsdiffer for console (cli) usage"""
import os
""" main module of testsdiffer for console (cli) usage"""

import pprint
import sys

import clifier
import click

from codegraph import __version__, core

CLI_CFG_NAME = "conf/cli.yml"
CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])


@click.command(context_settings=CONTEXT_SETTINGS)
@click.version_option(version=__version__, message="CodeGraph version %(version)s")
@click.argument("paths", nargs=-1, type=click.Path(exists=True))
@click.option(
"-o",
"--object-only",
is_flag=True,
help="Don't visualize code dependencies as graph",
)
@click.option("--file-path", help="File path to start dependency search from")
@click.option("--distance", type=int, help="Distance to search for dependencies")
def cli(paths, object_only, file_path, distance):
"""
Tool that creates a graph of code to show dependencies between code entities (methods, classes, etc.).
CodeGraph does not execute code, it is based only on lex and syntax parsing.

PATHS: Provide path(s) to code base
"""
if not paths:
click.echo(
"Error: No paths provided. Please specify at least one path to the code base.",
err=True,
)
sys.exit(1)

def cli():
config_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), CLI_CFG_NAME)
_cli = clifier.Clifier(config_path, prog_version=__version__)
parser = _cli.create_parser()
args = parser.parse_args()
args = {
"paths": paths,
"object_only": object_only,
"file_path": file_path,
"distance": distance,
}
main(args)


def main(args):
usage_graph = core.CodeGraph(args).usage_graph()
pprint.pprint(usage_graph)
if not args.object_only:
# to make more quick work if not needed to visualize
import codegraph.vizualyzer as vz
code_graph = core.CodeGraph(args)
usage_graph = code_graph.usage_graph()

if args.get("file_path") and args.get("distance"):
dependencies = code_graph.get_dependencies(args["file_path"], args["distance"])
print(f"Dependencies for {args['file_path']}:")
for distance, files in dependencies.items():
print(f" Distance {distance}: {', '.join(files)}")
else:
pprint.pprint(usage_graph)
if not args["object_only"]:
import codegraph.vizualyzer as vz

vz.draw_graph(usage_graph)


vz.draw_graph(usage_graph)
if __name__ == "__main__":
cli()
11 changes: 5 additions & 6 deletions codegraph/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from typing import List, Union


def get_python_paths_list(paths: Union[str, List]) -> List:
def get_python_paths_list(paths: Union[str, List]) -> List[str]:
"""
return list of paths to python files, that found in provided path
:param paths: paths to folder or python file that need to tests
Expand All @@ -22,11 +22,10 @@ def get_python_paths_list(paths: Union[str, List]) -> List:
for path in paths:
path = Path(path).absolute()
if not path.exists():
raise ValueError(f"Path {path.as_posix()} does not exists")
path = path.as_posix()
raise ValueError(f"Path {path.as_posix()} does not exist")
paths_list += [
path
for path in glob.glob(path + "/*", recursive=True)
if path.endswith(".py") and not path.endswith("__init__.py")
Path(p).as_posix()
for p in glob.glob(str(path / "**" / "*.py"), recursive=True)
if not p.endswith("__init__.py")
]
return paths_list
11 changes: 8 additions & 3 deletions codegraph/vizualyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,17 @@ def draw_graph(modules_entities: Dict) -> None:
font_family="Arial",
font_size=10,
)

arrow_size = 15

nx.draw_networkx_edges(
G,
pos,
edgelist=module_edges_all,
edge_color="#009c2c",
width=2,
arrows=False,
arrows=True,
arrowsize=arrow_size,
style="dashed",
node_size=50,
)
Expand All @@ -91,9 +95,10 @@ def draw_graph(modules_entities: Dict) -> None:
edgelist=sub_edges_all,
edge_color="r",
width=2,
arrows=False,
arrows=True,
arrowsize=arrow_size,
style="dashed",
)
for p in pos: # raise text positions
for p in pos:
pos[p][1] += 0.07
plt.show()
Loading
Loading