Skip to content

Commit

Permalink
Merge branch '93-addtotalcheck' of github.com:AstuteSource/chasten in…
Browse files Browse the repository at this point in the history
…to 93-addtotalcheck
  • Loading branch information
CalebKendra committed Nov 5, 2023
2 parents 763aebb + 4a1f1e5 commit a9b205a
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 36 deletions.
22 changes: 11 additions & 11 deletions .chasten/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,32 @@ checks:
pattern: './/ClassDef'
count:
min: 1
max: 50
max: null
- name: "all-function-definition"
code: "AFD"
id: "F001"
pattern: './/FunctionDef'
count:
min: 1
max: 200
- name: "non-test-function-definition"
max: null
- name: "dummy-test-non-test-function-definition"
code: "NTF"
id: "F002"
pattern: './/FunctionDef[not(contains(@name, "test_"))]'
count:
min: 40
max: 70
- name: "single-nested-if"
min: null
max: null
- name: "dummy-test-single-nested-if"
code: "SNI"
id: "CL001"
pattern: './/FunctionDef/body//If'
count:
min: 1
max: 100
- name: "double-nested-if"
min: null
max: null
- name: "dummy-test-double-nested-if"
code: "DNI"
id: "CL002"
pattern: './/FunctionDef/body//If[ancestor::If and not(parent::orelse)]'
count:
min: 1
max: 15
min: null
max: null
39 changes: 30 additions & 9 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,18 @@ on:
branches: [ master ]

# Create one single job
# This job performs all necessary checks
# This job performs all of the necessary checks
jobs:
build:
# Use the latest version of Ubuntu on MacOS and Windows
# Use the latest version of Ubuntu, MacOS, and Windows
# Use the latest and most stable version of Python
# Important: test coverage monitoring and reporting
# through a badge and the GitHub Actions job summary
# only takes place with the Linux operating system.
# Important: the MacOS and Windows operating systems
# have test coverage calculation take place but they
# do not report the test coverage beyond its display
# inside of the GitHub Actions panel for that job.
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
Expand Down Expand Up @@ -53,7 +61,7 @@ jobs:
- name: Install Pip
if: always()
run: |
pip install -U pip
python -m pip install --upgrade pip
# Install poetry
- name: Install Poetry
if: always()
Expand All @@ -70,28 +78,41 @@ jobs:
if: always()
run: |
poetry run task lint
# Run the program
# Run the program
- name: Run program
if: always()
run: |
poetry run chasten analyze chasten --config $PWD/.chasten/ --debug-level ERROR --debug-dest CONSOLE --search-path .
# Run the tests
- name: Run Tests
if: always()
run: |
poetry run task test
# Run the test coverage monitoring
- name: Run Test Coverage
if: always()
# Run and collect the test coverage
# Important: only run and collect test coverage monitoring on Linux
- name: Run and Collect Test Coverage - Linux Only
if: always() && matrix.os == 'ubuntu-latest'
run: |
poetry run task test-coverage-silent > coverage.txt
# Display the Coverage Report
- name: Display Coverage
# Important: only report the monitored test coverage on Linux
- name: Display Collected Test Coverage - Linux Only
if: always() && matrix.os == 'ubuntu-latest'
run: |
export TOTAL=$(python -c "import json;print(json.load(open('coverage.json'))['totals']['percent_covered_display'])")
echo "total=$TOTAL" >> $GITHUB_ENV
echo "### Total coverage: ${TOTAL}%" >> $GITHUB_STEP_SUMMARY
CURRENT_GITHUB_STEP_SUMMARY="\`\`\`\n$(cat coverage.txt)\n\`\`\`"
echo "$CURRENT_GITHUB_STEP_SUMMARY" >> $GITHUB_STEP_SUMMARY
# Run and display the test coverage
# If the current operating system is MacOS, then only run test
# coverage monitoring and display it inside of the GitHub Actions
# panel. This allows for test coverage to be calculated for each
# operating system. However, coverage is only reported for Linux
# through the badge and through the GitHub job summary. Do not
# run any test coverage monitoring in Windows because it seems
# to be much slower and cause hypothesis-based tests to fail.
- name: Run and Report Test Coverage - MacOS Only
if: always() && matrix.os == 'macOS'
run: |
poetry run task test-coverage
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,45 @@ create the tool's command-line arguments and options through a terminal user
interface (TUI). To use TUI-based way to create a complete command-line for
`chasten` you can type the command `chasten interact`.

## 📊Log
`Chasten` has a built-in system log. While using chasten you can use the command
`chasten log` in your terminal. The system log feature allows the user to see
events and messages that are produced by `chasten`. In addition, the `chasten log`
feature will assist in finding bugs and the events that led to the bug happening.
For the `chasten` program to display to the system log you will have to open a
separate terminal and use the command `chasten log`. In addition for each command
that is run the `--debug-level <choice of level>` and `--debug-dest SYSLOG` will
need to be added.

For example, `chasten datasette-serve --debug-level DEBUG --debug-dest SYSLOG
< database path to file>` will produce the following output in the system log.

```
💫 chasten: Analyze the AST of Python Source Code
🔗 GitHub: https://github.com/gkapfham/chasten
✨ Syslog server for receiving debugging information

Display verbose output? False
Debug level? DEBUG
Debug destination? SYSLOG
```
In each command in `chasten`, there is an option to add a `--debug-level`. The debug level has 5 options debug, info, warning, error, and critical. Each level will show different issues in the system log where debug is the lowest level of issue from the input where critical is the highest level of error. To leverage more info on this you can reference `debug.py` file:
``` python
class DebugLevel(str, Enum):
"""The predefined levels for debugging."""
DEBUG = "DEBUG"
INFO = "INFO"
WARNING = "WARNING"
ERROR = "ERROR"
CRITICAL = "CRITICAL"
```




## 🤗 Learning

- **Curious about the nodes that are available in a Python program's AST?**
Expand Down
1 change: 1 addition & 0 deletions chasten-test
Submodule chasten-test added at 2d8478
32 changes: 27 additions & 5 deletions chasten/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""💫 Chasten checks the AST of a Python program."""

import sys
import time
from pathlib import Path
from typing import Any, Dict, List, Tuple, Union

Expand Down Expand Up @@ -382,8 +383,14 @@ def configure( # noqa: PLR0913


@cli.command()
def analyze( # noqa: PLR0913, PLR0915
def analyze( # noqa: PLR0912, PLR0913, PLR0915
project: str = typer.Argument(help="Name of the project."),
xpath: Path = typer.Option(
str,
"--xpath-version",
"-xp",
help="Accepts different xpath version, runs xpath version two by default.",
),
check_include: Tuple[enumerations.FilterableAttribute, str, int] = typer.Option(
(None, None, 0),
"--check-include",
Expand Down Expand Up @@ -441,6 +448,7 @@ def analyze( # noqa: PLR0913, PLR0915
save: bool = typer.Option(False, help="Enable saving of output file(s)."),
) -> None:
"""💫 Analyze the AST of Python source code."""
start_time = time.time()
# output the preamble, including extra parameters specific to this function
output_preamble(
verbose,
Expand Down Expand Up @@ -542,9 +550,18 @@ def analyze( # noqa: PLR0913, PLR0915
# search for the XML contents of an AST that match the provided
# XPATH query using the search_python_file in search module of pyastgrep;
# this looks for matches across all path(s) in the specified source path
match_generator = pyastgrepsearch.search_python_files(
paths=valid_directories, expression=current_xpath_pattern, xpath2=True
)
# match_generator = pyastgrepsearch.search_python_files(
# paths=valid_directories, expression=current_xpath_pattern, xpath2=True
# )
if xpath == "1.0":
match_generator = pyastgrepsearch.search_python_files(
paths=valid_directories, expression=current_xpath_pattern, xpath2=False
)
else:
match_generator = pyastgrepsearch.search_python_files(
paths=valid_directories, expression=current_xpath_pattern, xpath2=True
)

# materialize a list from the generator of (potential) matches;
# note that this list will also contain an object that will
# indicate that the analysis completed for each located file
Expand Down Expand Up @@ -676,10 +693,15 @@ def analyze( # noqa: PLR0913, PLR0915
# confirm whether or not all of the checks passed
# and then display the appropriate diagnostic message
all_checks_passed = all(check_status_list)
end_time = time.time()
elapsed_time = end_time - start_time

if not all_checks_passed:
output.console.print(":sweat: At least one check did not pass.")
sys.exit(constants.markers.Non_Zero_Exit)
output.console.print(":joy: All checks passed.")
output.console.print(
f"\n:joy: All checks passed. Elapsed Time: {elapsed_time} seconds"
)


@cli.command()
Expand Down
3 changes: 2 additions & 1 deletion tests/test_constants.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Pytest test suite for the constants module."""

from dataclasses import FrozenInstanceError
from pathlib import Path

import pytest
from hypothesis import given, strategies
Expand Down Expand Up @@ -44,7 +45,7 @@ def test_fuzz_init(directory, configfile, checksfile, extra, yes, no): # noqa:
def test_fuzz_immutable(fs, hr):
"""Use Hypothesis to confirm that attribute's value cannot be re-assigned."""
with pytest.raises(FrozenInstanceError):
fs.Current_Directory = "/new/path"
fs.Current_Directory = str(Path("/new") / Path("path"))
with pytest.raises(FrozenInstanceError):
hr.Yes = "YES"
with pytest.raises(FrozenInstanceError):
Expand Down
9 changes: 5 additions & 4 deletions tests/test_filesystem.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Pytest test suite for the filesystem module."""

import pathlib
from pathlib import Path
from unittest.mock import patch

import pytest
Expand All @@ -12,31 +13,31 @@

def test_valid_directory() -> None:
"""Confirm that a valid directory is found."""
directory_str = "./tests/"
directory_str = str(Path("./tests/"))
directory = pathlib.Path(directory_str)
confirmation = filesystem.confirm_valid_directory(directory)
assert confirmation is True


def test_invalid_directory() -> None:
"""Confirm that a valid directory is found."""
directory_str = "./testsNOT/"
directory_str = str(Path("./testsNOT/"))
directory = pathlib.Path(directory_str)
confirmation = filesystem.confirm_valid_directory(directory)
assert confirmation is False


def test_valid_file() -> None:
"""Confirm that a valid directory is found."""
file_str = "./tests/test_filesystem.py"
file_str = str(Path("./tests") / Path("test_filesystem.py"))
this_file = pathlib.Path(file_str)
confirmation = filesystem.confirm_valid_file(this_file)
assert confirmation is True


def test_invalid_file() -> None:
"""Confirm that a valid directory is found."""
file_str = "./tests/test_filesystemNOT.py"
file_str = str(Path("./tests") / Path("test_filesystemNOT.py.py"))
this_file_not = pathlib.Path(file_str)
confirmation = filesystem.confirm_valid_file(this_file_not)
assert confirmation is False
Expand Down
10 changes: 5 additions & 5 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
pattern: './/ClassDef'
count:
min: 1
max: 10
max: null
- name: "all-function-definition"
code: "AFD"
id: "F001"
Expand Down Expand Up @@ -91,7 +91,7 @@ def test_cli_analyze_correct_arguments_nothing_to_analyze_not_looking(tmpdir):
project_name = "testing"
# create a reference to the internal
# .chasten directory that supports testing
configuration_directory = test_one + "/.chasten"
configuration_directory = test_one / Path(".chasten")
configuration_directory_path = Path(configuration_directory)
configuration_directory_path.mkdir()
configuration_file = configuration_directory_path / "config.yml"
Expand Down Expand Up @@ -122,7 +122,7 @@ def test_cli_analyze_correct_arguments_analyze_chasten_codebase(cwd):
project_name = "testing"
# create a reference to the internal
# .chasten directory that supports testing
configuration_directory = str(cwd) + "/.chasten"
configuration_directory = cwd / Path(".chasten")
result = runner.invoke(
main.cli,
[
Expand All @@ -144,7 +144,7 @@ def test_cli_analyze_incorrect_arguments_no_project(cwd, tmpdir):
test_one = tmpdir.mkdir("test_one")
# create a reference to the internal
# .chasten directory that supports testing
configuration_directory = str(cwd) + "/.chasten"
configuration_directory = cwd / Path(".chasten")
# call the analyze command
result = runner.invoke(
main.cli,
Expand Down Expand Up @@ -297,7 +297,7 @@ def test_fuzz_cli_analyze_single_directory(cwd, directory):
project_name = "testing"
# create a reference to the internal
# .chasten directory that supports testing
configuration_directory = str(cwd) + "/.chasten"
configuration_directory = cwd / Path(".chasten")
result = runner.invoke(
main.cli,
[
Expand Down
3 changes: 2 additions & 1 deletion tests/test_validate.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Pytest test suite for the validate module."""

import pytest
from hypothesis import given, strategies
from hypothesis import HealthCheck, given, settings, strategies
from hypothesis_jsonschema import from_schema

from chasten.validate import JSON_SCHEMA_CONFIG, validate_configuration
Expand Down Expand Up @@ -44,6 +44,7 @@ def test_validate_empty_config(config):


@given(from_schema(JSON_SCHEMA_CONFIG))
@settings(suppress_health_check=[HealthCheck.too_slow])
@pytest.mark.fuzz
def test_integers(config):
"""Use Hypothesis and the JSON schema plugin to confirm validation works for all possible valid instances."""
Expand Down

0 comments on commit a9b205a

Please sign in to comment.