Skip to content

Commit

Permalink
Allow patterns for INCLUDE/EXCLUDE from py3.13 onwards (#73)
Browse files Browse the repository at this point in the history
* Refactor Filter to allow patterns for INCLUDE/EXCLUDE from py3.13 onwards

* Add pytest to CI
  • Loading branch information
kunaltyagi authored Oct 26, 2024
1 parent 559898c commit bb77fc4
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 31 deletions.
13 changes: 13 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,16 @@ jobs:
- name: Run NSIQCppStyle App tests
timeout-minutes: 5
run: python nsiqcppstyle_exe.py -f nsiqunittest/rules/comment_and_empty_lines.txt --ci nsiqunittest/src/simple_main.cpp

run-pytest:
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected]
- name: Set up Python
uses: actions/[email protected]
with:
python-version: 3.13 # any python is ok
- name: Install Hatch
run: pipx install hatch
- name: Run pytest
run: hatch run test:test
82 changes: 51 additions & 31 deletions nsiqcppstyle_exe.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@
import copy
import functools
import re
import sys
import tempfile
from dataclasses import dataclass
from enum import Flag, auto
from pathlib import Path
from typing import List
from typing import List, Set

import nsiqcppstyle_checker
import nsiqcppstyle_reporter
Expand Down Expand Up @@ -470,6 +473,33 @@ def GetFilterFile(self, filterfile):
##############################################################################


class FileFilter:
def __init__(self, filter_string: str, include: bool = True):
self.include = include
self.filter_string = filter_string

if sys.version_info >= (3, 13) and "*" in self.filter_string:
from glob import translate # type: ignore[attr-defined] # sys version already checked

regex = translate(self.filter_string, recursive=True, include_hidden=True)
else:
# prefix search capability only
regex = rf"^{re.escape(filter_string)}"
self.filter_regex: re.Pattern = re.compile(regex)

def __hash__(self):
return hash(self.filter_string)

def __eq__(self, other):
if not isinstance(other, FileFilter):
return False
return self.filter_string == other.filter_string

def __repr__(self):
status = "included" if self.include else "excluded"
return f"{self.filter_string} is {status}"


class Filter:
"""
Filter
Expand All @@ -481,7 +511,7 @@ def __init__(self, filterName, baseExtLangMap, baseVarMap):
self.extLangMap = baseExtLangMap
self.varMap = baseVarMap
self.filterName = filterName
self.filefilter = []
self.filefilter: List[FileFilter] = []
self.match = re.compile("^(\\\\|//)")
self.nsiqCppStyleRules = []

Expand All @@ -492,40 +522,32 @@ def to_string(self):
Current File extension and Language Settings
%s"""
s = ""
count = 1
for eachfilter in self.filefilter:
filterment = ""
filterment = "is included" if eachfilter[0] else "is excluded"
s = s + (f" {count}. {eachfilter[1]} {filterment}\n")
count = count + 1
for count, eachfilter in enumerate(self.filefilter):
s = s + (f" {count+1}. {eachfilter}\n")
return template % (self.filterName, s, self.GetLangString())

def NormalizePath(self, eachFilter):
replacedpath = eachFilter.replace("/", os.path.sep)
def NormalizePath(self, filter_string):
replacedpath = filter_string.replace("/", os.path.sep)
replacedpath = replacedpath.replace("\\\\", os.path.sep)
return replacedpath.replace("\\", os.path.sep)

def CheckExist(self, includeOrExclude, eachFilter, startwith):
return self.filefilter.count([includeOrExclude, eachFilter, startwith]) == 1
def AddInclude(self, filter_string):
self.AddFilter(True, filter_string)

def AddInclude(self, eachFilter):
self.AddFilter(True, eachFilter)

def AddExclude(self, eachFilter):
self.AddFilter(False, eachFilter)
def AddExclude(self, filter_string):
self.AddFilter(False, filter_string)

def AddCppChecker(self, eachChecker):
self.nsiqCppStyleRules.append(eachChecker)

def AddFilter(self, inclusion, eachFilter):
startwith = False
if eachFilter.startswith(("\\\\", "//")):
eachFilter = self.match.sub("", eachFilter)
def AddFilter(self, inclusion, filter_string):
if filter_string.startswith(("\\\\", "//")):
filter_string = self.match.sub("", filter_string)

filterString = self.NormalizePath(eachFilter)
if self.CheckExist(inclusion, filterString, startwith):
self.filefilter.remove([inclusion, filterString, startwith])
self.filefilter.append([inclusion, filterString, startwith])
filterString = self.NormalizePath(filter_string)
if filter_string in self.filefilter:
self.filefilter.remove(FileFilter(filter_string=filterString))
self.filefilter.append(FileFilter(filterString, inclusion))

def GetFileFilter(self):
return self.filefilter
Expand All @@ -545,14 +567,12 @@ def GetLangString(self):
return s

def CheckFileInclusion(self, fileStr):
eachfile = self.NormalizePath(fileStr)
filename = self.NormalizePath(fileStr)
inclusion = True
for eachfilter in self.filefilter:
if eachfilter[2] is True:
if eachfile.startswith(eachfilter[1]):
inclusion = eachfilter[0]
elif eachfile.find(eachfilter[1]) != -1:
inclusion = eachfilter[0]
if eachfilter.filter_regex.match(filename) is None:
continue
inclusion = eachfilter.include
return inclusion

def GetLangMap(self):
Expand Down
35 changes: 35 additions & 0 deletions tests/test_file_filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import sys

import pytest

from nsiqcppstyle_exe import Filter


@pytest.fixture
def simple_filter():
return Filter("simple_test", {}, {})


@pytest.mark.skipif(sys.version_info < (3, 13), reason="Needs new glob features from 3.13")
def test_non_recursive_exclude(simple_filter: Filter):
simple_filter.AddExclude("*.py")
assert not simple_filter.CheckFileInclusion("hello.py")
assert simple_filter.CheckFileInclusion("SomeDir/hello.py")


@pytest.mark.skipif(sys.version_info < (3, 13), reason="Needs new glob features from 3.13")
def test_recursive_exclude(simple_filter: Filter):
simple_filter.AddExclude("**/*.py")
assert not simple_filter.CheckFileInclusion("hello.py")
assert not simple_filter.CheckFileInclusion("SomeDir/hello.py")


def test_prefix_match(simple_filter: Filter):
simple_filter.AddExclude("test/")
assert simple_filter.CheckFileInclusion("test.py")
assert not simple_filter.CheckFileInclusion("test/test.py")
assert not simple_filter.CheckFileInclusion("test/hello.py")

simple_filter.AddInclude("test/test")
assert simple_filter.CheckFileInclusion("test/test.py")
assert not simple_filter.CheckFileInclusion("test/hello.py")

0 comments on commit bb77fc4

Please sign in to comment.