Skip to content
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
18 changes: 18 additions & 0 deletions .codacy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
engines:
bandit:
enabled: true
exclude_paths:
- 'test/**'
- 'tests/**'
prospector:
enabled: true
pylint:
enabled: true
pmd:
enabled: false
exclude_paths:
- '.venv/**'
- 'build/**'
- 'dist/**'
- 'docs/build/**'
4 changes: 2 additions & 2 deletions dev.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Rename to dev version
# This is dev version
[build-system]
requires = ["setuptools>=61.0"]
requires = ["setuptools>=82.0.1"]
build-backend = "setuptools.build_meta"

[project]
Expand Down Expand Up @@ -38,4 +38,4 @@ content-type = "text/markdown"
find = { namespaces = false }

[project.optional-dependencies]
gui = ["PySide6==6.10.0", "qt-material"]
gui = ["PySide6==6.11.0", "qt-material"]
1 change: 1 addition & 0 deletions dev_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
je_load_density_dev
defusedxml>=0.7.1
sphinx
twine
sphinx-rtd-theme
Expand Down
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

# -- Project information -----------------------------------------------------
project = 'LoadDensity'
copyright = '2022, JE-Chen'
project_copyright = '2022, JE-Chen'
author = 'JE-Chen'

# The full version, including alpha/beta/rc tags
Expand Down
4 changes: 2 additions & 2 deletions je_load_density/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# hook
from je_load_density.wrapper.event.request_hook import request_hook
# hook (side-effect import: registers Locust request hooks)
from je_load_density.wrapper.event.request_hook import request_hook # noqa: F401
# env
from je_load_density.utils.executor.action_executor import add_command_to_executor
# executor
Expand Down
1 change: 0 additions & 1 deletion je_load_density/gui/main_widget.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import logging
import queue
from typing import Optional

from PySide6.QtCore import QTimer
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import sys
from threading import Lock
from xml.dom.minidom import parseString
from defusedxml.minidom import parseString
from typing import Tuple

from je_load_density.utils.generate_report.generate_json_report import generate_json
Expand Down
21 changes: 13 additions & 8 deletions je_load_density/utils/package_manager/package_manager_class.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import re
from importlib import import_module
from importlib.util import find_spec
from inspect import getmembers, isfunction
from sys import stderr
from typing import Optional, Any

_VALID_PACKAGE_NAME = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$")

Check warning on line 8 in je_load_density/utils/package_manager/package_manager_class.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use concise character class syntax '\w' instead of '[A-Za-z0-9_]'.

See more on https://sonarcloud.io/project/issues?id=Integration-Automation_LoadDensity&issues=AZ3DPhxO-HHpeUn7jeb_&open=AZ3DPhxO-HHpeUn7jeb_&pullRequest=103

Check warning on line 8 in je_load_density/utils/package_manager/package_manager_class.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use concise character class syntax '\w' instead of '[A-Za-z0-9_]'.

See more on https://sonarcloud.io/project/issues?id=Integration-Automation_LoadDensity&issues=AZ3DPhxO-HHpeUn7jeb-&open=AZ3DPhxO-HHpeUn7jeb-&pullRequest=103


class PackageManager:
"""
Expand All @@ -28,15 +31,17 @@
:return: 套件模組或 None (Loaded module or None)
"""
if package not in self.installed_package_dict:
if not _VALID_PACKAGE_NAME.fullmatch(package):
print(f"Rejected invalid package name: {package!r}", file=stderr)
return None
found_spec = find_spec(package)
if found_spec is not None:
try:
installed_package = import_module(found_spec.name)
self.installed_package_dict[found_spec.name] = installed_package
except ModuleNotFoundError as error:
print(repr(error), file=stderr)
return None
else:
if found_spec is None or not _VALID_PACKAGE_NAME.fullmatch(found_spec.name):
return None
try:
installed_package = import_module(found_spec.name) # nosemgrep: python.lang.security.audit.non-literal-import.non-literal-import
self.installed_package_dict[found_spec.name] = installed_package
except ModuleNotFoundError as error:
print(repr(error), file=stderr)
return None
return self.installed_package_dict.get(package)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from collections import defaultdict
from xml.etree import ElementTree
from typing import Union, Dict, Any
from typing import Any, Dict
from xml.etree import ElementTree as _ElementTreeBuilder # nosec B405 - construction only, no parsing # nosemgrep: python.lang.security.use-defused-xml.use-defused-xml


def elements_tree_to_dict(elements_tree: ElementTree.Element) -> Dict[str, Any]:
def elements_tree_to_dict(elements_tree: _ElementTreeBuilder.Element) -> Dict[str, Any]:
"""
將 XML ElementTree 轉換為字典
Convert XML ElementTree to dictionary
Expand Down Expand Up @@ -52,7 +52,7 @@ def dict_to_elements_tree(json_dict: Dict[str, Any]) -> str:
:return: XML 字串 (XML string)
"""

def _to_elements_tree(json_dict: Any, root: ElementTree.Element) -> None:
def _to_elements_tree(json_dict: Any, root: _ElementTreeBuilder.Element) -> None:
if isinstance(json_dict, str):
root.text = json_dict
elif isinstance(json_dict, dict):
Expand All @@ -67,16 +67,16 @@ def _to_elements_tree(json_dict: Any, root: ElementTree.Element) -> None:
root.set(key[1:], value)
elif isinstance(value, list): # 處理子節點清單
for element in value:
_to_elements_tree(element, ElementTree.SubElement(root, key))
_to_elements_tree(element, _ElementTreeBuilder.SubElement(root, key))
else: # 處理單一子節點
_to_elements_tree(value, ElementTree.SubElement(root, key))
_to_elements_tree(value, _ElementTreeBuilder.SubElement(root, key))
else:
raise TypeError(f"Invalid type in dict_to_elements_tree: {type(json_dict)}")

if not isinstance(json_dict, dict) or len(json_dict) != 1:
raise ValueError("Input must be a dictionary with a single root element")

tag, body = next(iter(json_dict.items()))
node = ElementTree.Element(tag)
node = _ElementTreeBuilder.Element(tag)
_to_elements_tree(body, node)
return ElementTree.tostring(node, encoding="utf-8").decode("utf-8")
return _ElementTreeBuilder.tostring(node, encoding="utf-8").decode("utf-8")
20 changes: 11 additions & 9 deletions je_load_density/utils/xml/xml_file/xml_file.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import xml.dom.minidom
from xml.etree import ElementTree
from xml.etree.ElementTree import ParseError
from typing import Optional
from xml.etree import ElementTree as _SafeElementTree # nosec B405 - used only for typing/wrapping; parsing routes through defusedxml # nosemgrep: python.lang.security.use-defused-xml.use-defused-xml
from xml.etree.ElementTree import ParseError # nosec B405 # nosemgrep: python.lang.security.use-defused-xml.use-defused-xml

import defusedxml.ElementTree as ElementTree
from defusedxml.minidom import parseString as _parse_xml_string

from je_load_density.utils.exception.exception_tags import cant_read_xml_error, xml_type_error
from je_load_density.utils.exception.exceptions import XMLException, XMLTypeException
Expand All @@ -15,7 +17,7 @@ def reformat_xml_file(xml_string: str) -> str:
:param xml_string: 原始 XML 字串 (Raw XML string)
:return: 格式化後的 XML 字串 (Pretty-printed XML string)
"""
dom = xml.dom.minidom.parseString(xml_string)
dom = _parse_xml_string(xml_string)
return dom.toprettyxml(indent=" ")


Expand All @@ -36,8 +38,8 @@ def __init__(self, xml_string: str, xml_type: str = "string") -> None:
:param xml_string: XML 字串或檔案路徑 (XML string or file path)
:param xml_type: "string" 或 "file" (Parse from string or file)
"""
self.tree: Optional[ElementTree.ElementTree] = None
self.xml_root: Optional[ElementTree.Element] = None
self.tree: Optional[_SafeElementTree.ElementTree] = None
self.xml_root: Optional[_SafeElementTree.Element] = None
self.xml_from_type: str = "string"
self.xml_string: str = xml_string.strip()

Expand All @@ -50,7 +52,7 @@ def __init__(self, xml_string: str, xml_type: str = "string") -> None:
else:
self.xml_parser_from_file()

def xml_parser_from_string(self, **kwargs) -> ElementTree.Element:
def xml_parser_from_string(self, **kwargs) -> _SafeElementTree.Element:
"""
從字串解析 XML
Parse XML from string
Expand All @@ -64,7 +66,7 @@ def xml_parser_from_string(self, **kwargs) -> ElementTree.Element:
raise XMLException(f"{cant_read_xml_error}: {error}")
return self.xml_root

def xml_parser_from_file(self, **kwargs) -> ElementTree.Element:
def xml_parser_from_file(self, **kwargs) -> _SafeElementTree.Element:
"""
從檔案解析 XML
Parse XML from file
Expand All @@ -90,7 +92,7 @@ def write_xml(self, write_xml_filename: str, write_content: str) -> None:
"""
try:
content = ElementTree.fromstring(write_content.strip())
tree = ElementTree.ElementTree(content)
tree = _SafeElementTree.ElementTree(content)
tree.write(write_xml_filename, encoding="utf-8", xml_declaration=True)
except ParseError as error:
raise XMLException(f"{cant_read_xml_error}: {error}")
11 changes: 9 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Rename to stable version
# This is stable version
[build-system]
requires = ["setuptools>=61.0"]
requires = ["setuptools>=82.0.1"]
build-backend = "setuptools.build_meta"

[project]
Expand All @@ -15,6 +15,7 @@ requires-python = ">=3.10"
license-files = ["LICENSE"]
dependencies = [
"locust",
"defusedxml>=0.7.1",
]
classifiers = [
"Programming Language :: Python :: 3.10",
Expand All @@ -38,4 +39,10 @@ content-type = "text/markdown"
find = { namespaces = false }

[project.optional-dependencies]
gui = ["PySide6==6.10.0", "qt-material"]
gui = ["PySide6==6.11.0", "qt-material"]

[tool.bandit]
exclude_dirs = ["test", "tests", ".venv", "build", "dist"]

[tool.bandit.assert_used]
skips = ["**/test_*.py", "**/*_test.py", "**/conftest.py"]
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
je_load_density
defusedxml>=0.7.1
pytest
1 change: 0 additions & 1 deletion test/test_executor.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import json
import os

import pytest

Expand Down
3 changes: 0 additions & 3 deletions test/test_file_process.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import json
import os

from je_load_density.utils.file_process.get_dir_file_list import get_dir_files_as_list


Expand Down
2 changes: 1 addition & 1 deletion test/test_report_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import pytest

from je_load_density.utils.test_record.test_record_class import TestRecord, test_record_instance
from je_load_density.utils.test_record.test_record_class import test_record_instance
from je_load_density.utils.generate_report.generate_html_report import generate_html, generate_html_report
from je_load_density.utils.generate_report.generate_json_report import generate_json, generate_json_report
from je_load_density.utils.generate_report.generate_xml_report import generate_xml, generate_xml_report
Expand Down
Loading