Skip to content

Commit

Permalink
.
Browse files Browse the repository at this point in the history
  • Loading branch information
kiyoon committed Jun 10, 2024
1 parent b720dc6 commit 485284d
Show file tree
Hide file tree
Showing 4 changed files with 260 additions and 2 deletions.
130 changes: 130 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
name: Tests

on:
- push
- pull_request

jobs:
pytest:
runs-on: ubuntu-latest
defaults:
run:
shell: bash -el {0} # setup-miniconda requires bash
steps:
- uses: actions/checkout@v4
- run: |
pip3 install toml
echo "python_version=$(python3 scripts/get_python_version.py)" >> "$GITHUB_OUTPUT"
pip3 install --user uv
id: get-python-version
- uses: conda-incubator/setup-miniconda@v3
with:
miniforge-version: latest
activate-environment: test
python-version: ${{ steps.get-python-version.outputs.python_version }}
- name: Cache Conda environment
id: cache-conda
uses: actions/cache@v4
env:
cache-name: cache-conda
with:
path: ~/miniconda3/envs/test
key: ${{ runner.os }}-conda-${{ env.cache-name }}-${{ hashFiles('deps/x86_64-unknown-linux-gnu/requirements_dev.txt') }}
# restore-keys: |
# ${{ runner.os }}-conda-${{ env.cache-name }}-
# ${{ runner.os }}-conda-
# ${{ runner.os }}-
- if: steps.cache-conda.outputs.cache-hit == 'true'
run: echo 'conda cache hit!'
- name: Install dependencies
if: steps.cache-conda.outputs.cache-hit != 'true'
run: |
# python -m pip install --upgrade pip
uv pip install -r deps/x86_64-unknown-linux-gnu/requirements_dev.txt
uv pip install -e .
bash scripts/install_binaries.sh
- name: Run pytest
run: |
set +e # Do not exit shell on pytest failure
out=$(pytest 2> stderr.txt)
exit_code=$?
err=$(<stderr.txt)
# Display the raw output in the step
echo "${out}"
echo "${err}"
# Display the Markdown output in the job summary
echo "\`\`\`python" >> $GITHUB_STEP_SUMMARY
echo "${out}" >> $GITHUB_STEP_SUMMARY
echo "${err}" >> $GITHUB_STEP_SUMMARY
if [[ $exit_code -eq 5 ]]
then
echo
echo 'WARNING: No tests were run and it is considered as success' >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
exit 0
else
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
# Exit with the exit-code returned by pytest
exit ${exit_code}
fi
doctest:
runs-on: ubuntu-latest
defaults:
run:
shell: bash -el {0} # setup-miniconda requires bash
steps:
- uses: actions/checkout@v4
- run: |
pip3 install toml
echo "python_version=$(python3 scripts/get_python_version.py)" >> "$GITHUB_OUTPUT"
pip3 install --user uv
id: get-python-version
- uses: conda-incubator/setup-miniconda@v3
with:
miniforge-version: latest
activate-environment: test
python-version: ${{ steps.get-python-version.outputs.python_version }}
- name: Cache Conda environment
id: cache-conda
uses: actions/cache@v4
env:
cache-name: cache-conda
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/miniconda3/envs/test
key: ${{ runner.os }}-conda-${{ env.cache-name }}-${{ hashFiles('deps/x86_64-unknown-linux-gnu/requirements_dev.txt') }}
# restore-keys: |
# ${{ runner.os }}-conda-${{ env.cache-name }}-
# ${{ runner.os }}-conda-
# ${{ runner.os }}-
- if: steps.cache-conda.outputs.cache-hit == 'true'
run: echo 'conda cache hit!'
- name: Install dependencies
if: steps.cache-conda.outputs.cache-hit != 'true'
run: |
# python -m pip install --upgrade pip
uv pip install -r deps/x86_64-unknown-linux-gnu/requirements_dev.txt
uv pip install -e .
bash scripts/install_binaries.sh
- name: Run doctest
run: |
set +e # Do not exit shell on pytest failure
out=$(python scripts/run_doctest.py 2> stderr.txt)
exit_code=$?
err=$(<stderr.txt)
# Display the raw output in the step
echo "${out}"
echo "${err}"
# Display the Markdown output in the job summary
echo "\`\`\`python" >> $GITHUB_STEP_SUMMARY
echo "${out}" >> $GITHUB_STEP_SUMMARY
echo "${err}" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
# Exit with the exit-code returned by pytest
exit ${exit_code}
45 changes: 45 additions & 0 deletions src/python_import/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import annotations

import json
import subprocess
from collections import defaultdict
from os import PathLike
from pathlib import Path
Expand Down Expand Up @@ -248,3 +250,46 @@ def get_all_imports_in_file_as_absolute(
] += 1

return import_statement_to_count


def get_all_imports_in_file_as_absolute_with_word(
project_root: str | PathLike,
python_file_path: str | PathLike,
parser: Parser,
word: str,
) -> dict[str, int]:
"""
Just for testing purposes.
The locations will be determined using ripgrep.
"""
# NOTE: rg json outputs are (1, 0)-indexed
rg_outputs = subprocess.run(
[
"rg",
"--word-regexp",
"--fixed-strings",
"--json",
word,
str(python_file_path),
],
cwd=project_root,
capture_output=True,
)
# print(rg_outputs)

# 0-indexed row, col
rowcols: list[tuple[int, int]] = []
for line in rg_outputs.stdout.decode("utf-8").split("\n"):
if not line:
continue
rg_output = json.loads(line)
if rg_output["type"] == "match":
row = rg_output["data"]["line_number"] - 1
col = rg_output["data"]["submatches"][0]["start"]
# col_end = rg_output["data"]["submatches"][0]["end"]
rowcols.append((row, col))

return get_all_imports_in_file_as_absolute(
project_root, python_file_path, parser, rowcols
)
16 changes: 15 additions & 1 deletion tests/sample_projects/project1/src/myproject1/a/b/c/d.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
from __future__ import annotations

from foo import bar
from ....utils.a.b.c import relative1


def foo():
def lazy_import():
from ... import relative_three_dots


def foo1():
from python_import import foo

def foo2():
from python_import import foo

def foo3():
from python_import import foo

def invalid1():
from python_import import foo as bar
71 changes: 70 additions & 1 deletion tests/test_one_file.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,71 @@
from __future__ import annotations

def test_relative_import():
import logging
from pathlib import Path

import tree_sitter_python as tspython
from tree_sitter import Language, Parser

from python_import.utils import get_all_imports_in_file_as_absolute_with_word

logger = logging.getLogger(__name__)

SCRIPT_DIR = Path(__file__).parent
PY_LANGUAGE = Language(tspython.language())
parser = Parser(PY_LANGUAGE)


def test_multiple_counts():
imports = get_all_imports_in_file_as_absolute_with_word(
SCRIPT_DIR / "sample_projects/project1",
SCRIPT_DIR / "sample_projects/project1/src/myproject1/a/b/c/d.py",
parser,
"foo",
)

# not "from python_import import foo as bar"
# not from foo import bar
assert imports == {
"from python_import import foo": 3,
}


def test_multiple_statements():
imports = get_all_imports_in_file_as_absolute_with_word(
SCRIPT_DIR / "sample_projects/project1",
SCRIPT_DIR / "sample_projects/project1/src/myproject1/a/b/c/d.py",
parser,
"bar",
)

assert imports == {
"from foo import bar": 1,
"from python_import import foo as bar": 1,
}


def test_relative1():
imports = get_all_imports_in_file_as_absolute_with_word(
SCRIPT_DIR / "sample_projects/project1",
SCRIPT_DIR / "sample_projects/project1/src/myproject1/a/b/c/d.py",
parser,
"relative1",
)

assert imports == {
"from myproject1.utils.a.b.c import relative1": 1,
}


def test_relative_three_dots():
# from ... import relative_three_dots1
imports = get_all_imports_in_file_as_absolute_with_word(
SCRIPT_DIR / "sample_projects/project1",
SCRIPT_DIR / "sample_projects/project1/src/myproject1/a/b/c/d.py",
parser,
"relative_three_dots",
)

assert imports == {
"from myproject1.a import relative_three_dots": 1,
}

0 comments on commit 485284d

Please sign in to comment.