diff --git a/.github/labels/issue_labeler.yml b/.github/labels/issue_labeler.yml
new file mode 100644
index 0000000..fe55a58
--- /dev/null
+++ b/.github/labels/issue_labeler.yml
@@ -0,0 +1,11 @@
+# Add/remove 'critical' label if issue contains the words 'urgent' or 'critical'
+critical:
+ - '(critical|urgent)'
+
+# Add/remove 'bug' label if issue contains the words 'bug'
+bug:
+ - '(bug)'
+
+# Add/remove 'feature' label if issue contains the words 'feature'
+feature:
+ - '(feature)'
\ No newline at end of file
diff --git a/.github/labels/labeler.yml b/.github/labels/labeler.yml
new file mode 100644
index 0000000..2806311
--- /dev/null
+++ b/.github/labels/labeler.yml
@@ -0,0 +1,30 @@
+---
+# configuration spec at https://github.com/actions/labeler/blob/master/README.md
+sh/docs:
+ - CHANGELOG.md
+ - CONTRIBUTING.md
+ - LICENSE
+ - README.md
+sh/tests:
+ - tests/*
+ - tox.ini
+sh/code:
+ - data/*
+ - asserts/*
+ - shconfparser
+sh/ci:
+ - .github/workflows/*
+ - .github/labels/*
+ - .travis.yml
+ - .coveralls.yml
+sh/settings:
+ - setup.py
+ - tox.ini
+ - .gitignore
+ - .python-version
+sh/pip:
+ - requirements.txt
+ - requirements_dev.txt
+ - requirements_dev27.txt
+ - Pipfile
+ - Pipfile.lock
\ No newline at end of file
diff --git a/.github/labels/labels.yml b/.github/labels/labels.yml
new file mode 100644
index 0000000..11e1a92
--- /dev/null
+++ b/.github/labels/labels.yml
@@ -0,0 +1,49 @@
+---
+# Default GitHub labels
+- color: d73a4a
+ name: bug
+ description: Something isn't working
+- color: cfd3d7
+ name: duplicate
+ description: This issue or pull request already exists
+- color: a2eeef
+ name: enhancement
+ description: New feature or request
+- color: 7057ff
+ name: good first issue
+ description: Good for newcomers
+- color: 008672
+ name: help wanted
+ description: Extra attention is needed
+- color: e4e669
+ name: invalid
+ description: This doesn't seem right
+- color: d876e3
+ name: question
+ description: Further information is requested
+- color: ffffff
+ name: wontfix
+ description: This will not be worked on
+
+# Labels specific to shconfparser
+- color: 0366d6
+ name: sh/wip
+ description: Work in progress
+- color: 0366d6
+ name: sh/docs
+ description: Improvements or additions to documentation
+- color: 0366d6
+ name: sh/tests
+ description: Everything related to molecule tests and linters
+- color: 0366d6
+ name: sh/code
+ description: Bots, bots everywhere
+- color: 0366d6
+ name: sh/ci
+ description: Ansible variables used in role
+- color: 0366d6
+ name: sh/settings
+ description: Logic behind ansible role
+- color: 0366d6
+ name: sh/pip
+ description: Templates
\ No newline at end of file
diff --git a/.github/workflows/issue_labeler.yml b/.github/workflows/issue_labeler.yml
new file mode 100644
index 0000000..09fa52a
--- /dev/null
+++ b/.github/workflows/issue_labeler.yml
@@ -0,0 +1,15 @@
+name: "Issue Labeler"
+on:
+ issues:
+ types: [opened, edited]
+
+jobs:
+ triage:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: github/issue-labeler@v2.0
+ with:
+ repo-token: "${{ secrets.GITHUB_TOKEN }}"
+ configuration-path: .github/labels/issue_labeler.yml
+ # not-before: 2020-01-15T02:54:32Z
+ enable-versioned-regex: 0
\ No newline at end of file
diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml
new file mode 100644
index 0000000..17ac2cf
--- /dev/null
+++ b/.github/workflows/labeler.yml
@@ -0,0 +1,13 @@
+---
+name: Pull request labeler
+on:
+ schedule:
+ - cron: '*/15 * * * *'
+jobs:
+ labeler:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: paulfantom/periodic-labeler@master
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
\ No newline at end of file
diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml
new file mode 100644
index 0000000..3425cf5
--- /dev/null
+++ b/.github/workflows/labels.yml
@@ -0,0 +1,17 @@
+---
+name: Sync labels in the declarative way
+on:
+ push:
+ branches:
+ - master
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@1.0.0
+ - uses: micnncim/action-label-syncer@v0.3.1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
+ with:
+ manifest: .github/labels/labels.yml
\ No newline at end of file
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 0000000..6b1df62
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,31 @@
+name: Upload Python Package
+
+on:
+ release:
+ types: [created]
+
+jobs:
+ deploy:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up Python
+ uses: actions/setup-python@v2
+ with:
+ python-version: '3.x'
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install setuptools wheel twine
+ - name: Build python package
+ run: |
+ python setup.py sdist bdist_wheel
+ - name: Publish package
+ uses: pypa/gh-action-pypi-publish@v1.4.2
+ with:
+ user: __token__
+ password: ${{ secrets.PYPI_API_TOKEN }}
+ skip_existing: true
+ verbose: true
\ No newline at end of file
diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml
new file mode 100644
index 0000000..216dfbc
--- /dev/null
+++ b/.github/workflows/pytest.yml
@@ -0,0 +1,43 @@
+name: "pytest"
+
+on:
+ push:
+ branches:
+ - '**'
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ build:
+
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ python-version: [3.7, 3.9]
+ os: [ubuntu-latest]
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ python -m pip install -r requirements_dev.txt
+ - name: Lint with flake8
+ run: |
+ # stop the build if there are Python syntax errors or undefined names
+ flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
+ # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
+ flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
+ - name: Test with pytest
+ run: |
+ pytest -v --cov=shconfparser
+ - name: Upload coverage
+ uses: codecov/codecov-action@v1
+ with:
+ name: ${{ matrix.os }} Python ${{ matrix.python-version }}
+ token: ${{ secrets.CODECOV_TOKEN }}
+ verbose: true
\ No newline at end of file
diff --git a/.github/workflows/pytest_27.yml b/.github/workflows/pytest_27.yml
new file mode 100644
index 0000000..ba84e79
--- /dev/null
+++ b/.github/workflows/pytest_27.yml
@@ -0,0 +1,31 @@
+name: "pytest 2.7.x"
+
+on:
+ push:
+ branches:
+ - '**'
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ build:
+
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ python-version: [2.7]
+ os: [ubuntu-latest]
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ python -m pip install -r requirements_dev27.txt
+ - name: Test with pytest
+ run: |
+ pytest -v --cov=shconfparser
diff --git a/.github/workflows/remove_labeler.yml b/.github/workflows/remove_labeler.yml
new file mode 100644
index 0000000..295f7fb
--- /dev/null
+++ b/.github/workflows/remove_labeler.yml
@@ -0,0 +1,14 @@
+name: Remove All Labels
+
+on:
+ pull_request:
+ types: [closed]
+
+jobs:
+ remove_labels:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: rogerluan/label-remover@v1.0.1
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 22ec05a..8454c6d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,9 @@
+# Editor specific
+
+.idea
+.idea/
+.vscode/
+
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
deleted file mode 100644
index a55e7a1..0000000
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 94a25f7..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..e69de29
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..e69de29
diff --git a/requirements_dev.txt b/requirements_dev.txt
index 31f30fa..3f93aa1 100644
--- a/requirements_dev.txt
+++ b/requirements_dev.txt
@@ -2,4 +2,6 @@ pytest-cov==2.8.1
pytest==5.3.0
coveralls==1.5.1
tox==3.7.0
+wheel
+flake8
diff --git a/shconfparser/search.py b/shconfparser/search.py
index 14cc61c..5509336 100644
--- a/shconfparser/search.py
+++ b/shconfparser/search.py
@@ -16,36 +16,37 @@ def validate(self, data, dtype=OrderedDict):
"""
if data == None:
return None
-
if type(data) != dtype:
return None
-
return True
def get_pattern(self, pattern, strip=True):
"""
This method converts the given string to regex pattern
"""
- if type(pattern) == re.Pattern:
- return pattern
+ try:
+ if type(pattern) == re.Pattern:
+ return pattern
+ except AttributeError:
+ if type(pattern) != str:
+ return pattern
if strip and type(pattern) == str:
pattern = pattern.strip()
return re.compile(pattern)
-
def search_in_tree(self, pattern, data=None):
if not self.validate(data):
return None
p = self.get_pattern(pattern)
for key in data.keys():
- if p.match(key):
- return key
+ res = p.match(key)
+ if res:
+ return res
return None
-
def search_all_in_tree(self, pattern, data=None):
if not self.validate(data):
return None
@@ -53,9 +54,9 @@ def search_all_in_tree(self, pattern, data=None):
p = self.get_pattern(pattern)
match = OrderedDict()
for key in data.keys():
- if p.match(key):
- match[key] = key
-
+ res = p.match(key)
+ if res:
+ match[res] = key
return match if len(match) else None
def search_in_tree_level(self, pattern, data=None, level=0):
@@ -75,7 +76,7 @@ def search_in_tree_level(self, pattern, data=None, level=0):
return None
def search_in_table(self, pattern, data=None, header_column=None):
- if not self.validate(data):
+ if not self.validate(data, dtype=list):
return None
p = self.get_pattern(pattern)
@@ -84,13 +85,13 @@ def search_in_table(self, pattern, data=None, header_column=None):
return each_row
def search_all_in_table(self, pattern, data=None, header_column=None):
- if not self.validate(data):
+ if not self.validate(data, dtype=list):
return None
p = self.get_pattern(pattern)
match = []
+ match = []
for each_row in data:
if p.match(each_row[header_column]):
match.append(each_row)
-
return match if len(match) else None
diff --git a/tests/test_search.py b/tests/test_search.py
index 66f859d..07fdf5a 100644
--- a/tests/test_search.py
+++ b/tests/test_search.py
@@ -23,21 +23,27 @@ def setup(self):
p.s.shcmd_dict['ip_interface_brief'] = p.parse_table(p.s.shcmd_dict['ip_interface_brief'], header)
yield p
+ def test_search_in_tree_level(self, setup):
+ data = setup.s.shcmd_dict
+ pattern = r' privilege level 15'
+ m = setup.search.search_in_tree_level(pattern, data['running'], level=10)
+ assert pattern.strip() in m
+
def test_search_all_in_tree(self, setup):
data = setup.s.shcmd_dict
- pattern = 'interface\s+FastEthernet.*'
+ pattern = r'interface\s+FastEthernet.*'
m = setup.search.search_all_in_tree(pattern, data['running'])
assert 'interface FastEthernet0/0' in m.values()
def test_search_in_tree(self, setup):
data = setup.s.shcmd_dict
- pattern = 'Cisco\s+IOS\s+Software.*'
+ pattern = r'Cisco\s+IOS\s+Software.*'
m = setup.search.search_in_tree(pattern, data['version'])
assert 'Version 12.4(25d)' in m.group(0)
def test_search_in_table(self, setup):
data = setup.s.shcmd_dict
- pattern = 'R\d+'
+ pattern = r'R\d+'
header = 'Device ID'
m = setup.search.search_in_table(pattern, data['cdp_neighbors'], header)
assert 'Device ID' in m
@@ -45,7 +51,7 @@ def test_search_in_table(self, setup):
def test_search_all_in_table(self, setup):
data = setup.s.shcmd_dict
- pattern = 'FastEthernet.*'
+ pattern = r'FastEthernet.*'
header = 'Interface'
m = setup.search.search_all_in_table(pattern, data['ip_interface_brief'], header)
assert type(m) is list