diff --git a/.gitignore b/.gitignore
index 221ee37..e395bb1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,4 +42,5 @@ helpers-results
.coverage
/.mypy_cache/
.coverage
-.mypy_cache
\ No newline at end of file
+.mypy_cache
+test/tmp
\ No newline at end of file
diff --git a/Jenkinsfile b/Jenkinsfile
index 13ee83d..12ce00e 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -27,7 +27,7 @@ def _bDraft = false
// release content / changelog management
def _bAutoChangelog = true //Not supported yet
def _ReleaseContent_Title = "# _CI/CD Automatic Release_"
-def bPushMasterOnPypi = false
+def bPushMasterOnPypi = true
// full rebuild toogle
def _bFullRebuilt = true
def _MkDocsWebURL = "dabauto--mkdocs-web.dmz.chacha.home/mkdocs-web/"
@@ -183,8 +183,12 @@ pipeline {
sh("virtualenv --pip=embed --setuptools=embed --wheel=embed --no-periodic-update --activators bash,python TEST_ENV")
sh("virtualenv --pip=embed --setuptools=embed --wheel=embed --no-periodic-update --activators bash,python TOOLS_ENV")
- sh(". ~/BUILD_ENV/bin/activate && pip install --upgrade setuptools build pip copier jinja2-slug toml")
+ sh(". ~/BUILD_ENV/bin/activate && pip install --upgrade setuptools build pip")
+ sh(". ~/BUILD_ENV/bin/activate && pip install --upgrade 'copier==8.*' jinja2-slug toml")
+
+ sh(". ~/TEST_ENV/bin/activate && pip install --upgrade pip")
+ sh(". ~/TOOLS_ENV/bin/activate && pip install --upgrade pip")
sh(". ~/TOOLS_ENV/bin/activate && pip install simple_rest_client requests twine packaging")
script {
@@ -341,7 +345,7 @@ pipeline {
|'''.strip()
|
|import copier
- |copier.run_copy("./", "../_gitrepo",vcs_ref="HEAD",use_prereleases=True,defaults=True,cleanup_on_error=False)
+ |copier.run_copy("./", "../_gitrepo",vcs_ref="HEAD",use_prereleases=True,defaults=True,cleanup_on_error=False,unsafe=True)
|
|__EOWRAPPER__
""".stripMargin())
@@ -409,31 +413,31 @@ pipeline {
stage("CheckCode") {
steps {
dir("gitrepo") {
- sh(". ~/TEST_ENV/bin/activate && python -m helpers --type-check --quality-check")
+ sh(". ~/TEST_ENV/bin/activate && python -m chacha_cicd_helper --typecheck --qualitycheck")
script {
- def jsonObj = readJSON file: "helpers-results/quality_check/metrics.json"
+ def jsonObj = readJSON file: "helpers-results/cl_quality_check/metrics.json"
quality_score = new BigDecimal(jsonObj["GlobalScore"])
sz_quality_score = quality_score.setScale(2, RoundingMode.HALF_EVEN).toString()
badge_quality.setStatus(sz_quality_score)
badge_quality.setColor(getColorScale(quality_score))
}
- sh(". ~/TEST_ENV/bin/activate && python -m helpers --complexity-check")
+ sh(". ~/TEST_ENV/bin/activate && python -m chacha_cicd_helper --complexitycheck")
}
}
post {
always {
dir("gitrepo") {
- publishCoverage adapters: [cobertura(mergeToOneReport: true, path: "helpers-results/types_check/cobertura.xml")]
- junit 'helpers-results/types_check/junit.xml'
+ publishCoverage adapters: [cobertura(mergeToOneReport: true, path: "helpers-results/cl_types_check/cobertura.xml")]
+ junit 'helpers-results/cl_types_check/junit.xml'
publishHTML([
- reportDir: "helpers-results/quality_check",
+ reportDir: "helpers-results/cl_quality_check",
reportFiles: "report.html",
reportName: "quality-report",
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true])
publishHTML([
- reportDir: "helpers-results/types_check",
+ reportDir: "helpers-results/cl_types_check",
reportFiles: "index.html",
reportName: "types_check",
allowMissing: false,
@@ -447,7 +451,7 @@ pipeline {
steps {
plot([ csvFileName: 'plot-df7f03dc-8146-11ed-a1eb-0242ac120002.csv',
- csvSeries: [[ file: 'gitrepo/helpers-results/quality_check/metrics_GlobalScore.csv', inclusionFlag: 'OFF', url: '']],
+ csvSeries: [[ file: 'gitrepo/helpers-results/cl_quality_check/metrics_GlobalScore.csv', inclusionFlag: 'OFF', url: '']],
group: 'metrics',
title: 'code quality score',
style: 'line',
@@ -457,7 +461,7 @@ pipeline {
yaxisMinimum: '0'])
plot([ csvFileName: 'plot-c731cc84-8145-11ed-a1eb-0242ac120002.csv',
- csvSeries: [[ file: 'gitrepo/helpers-results/quality_check/metrics_rawpercent.csv', inclusionFlag: 'OFF', url: '']],
+ csvSeries: [[ file: 'gitrepo/helpers-results/cl_quality_check/metrics_rawpercent.csv', inclusionFlag: 'OFF', url: '']],
group: 'metrics',
title: 'code composition (%)',
style: 'stackedArea',
@@ -467,7 +471,7 @@ pipeline {
yaxisMinimum: '0'])
plot([ csvFileName: 'plot-cac33982-8145-11ed-a1eb-0242ac120002.csv',
- csvSeries: [[ file: 'gitrepo/helpers-results/quality_check/metrics_Statistics.csv', inclusionFlag: 'OFF', url: '']],
+ csvSeries: [[ file: 'gitrepo/helpers-results/cl_quality_check/metrics_Statistics.csv', inclusionFlag: 'OFF', url: '']],
group: 'metrics',
title: 'general statistics',
style: 'line',
@@ -475,7 +479,7 @@ pipeline {
numBuilds: ''])
plot([ csvFileName: 'plot-cddaced2-8145-11ed-a1eb-0242ac120002.csv',
- csvSeries: [[ file: 'gitrepo/helpers-results/quality_check/metrics_MessagesCat.csv', inclusionFlag: 'OFF', url: '']],
+ csvSeries: [[ file: 'gitrepo/helpers-results/cl_quality_check/metrics_MessagesCat.csv', inclusionFlag: 'OFF', url: '']],
group: 'metrics',
title: 'quality warnings',
style: 'stackedArea',
@@ -483,7 +487,7 @@ pipeline {
numBuilds: ''])
plot([ csvFileName: 'plot-4ceb9ee2-ca78-11ed-afa1-0242ac120002.csv',
- csvSeries: [[ file: 'gitrepo/helpers-results/complexity_check/MI.csv', inclusionFlag: 'INCLUDE_BY_STRING',exclusionValues: 'MeanMaintainability', url: '']],
+ csvSeries: [[ file: 'gitrepo/helpers-results/cl_complexity_check/MI.csv', inclusionFlag: 'INCLUDE_BY_STRING',exclusionValues: 'MeanMaintainability', url: '']],
group: 'metrics',
title: 'maintainability',
style: 'stackedArea',
@@ -495,14 +499,14 @@ pipeline {
stage("RunUnitTests") {
steps {
dir("gitrepo") {
- sh(". ~/TEST_ENV/bin/activate && python -m helpers --unit-test --coverage-check")
+ sh(". ~/TEST_ENV/bin/activate && python -m chacha_cicd_helper --unittest --coveragecheck")
script {
- unit_test_full_name__html=findFiles(glob: "helpers-results/unit_test_full/*.html")[0].getName()
+ unit_test_full_name__html=findFiles(glob: "helpers-results/cl_unit_test_full/*.html")[0].getName()
println unit_test_full_name__html
- unit_test_full_name__xml=findFiles(glob: "helpers-results/unit_test_full/*.xml")[0].getName()
+ unit_test_full_name__xml=findFiles(glob: "helpers-results/cl_unit_test_full/*.xml")[0].getName()
println unit_test_full_name__xml
- coverage_report_path = "helpers-results/unit_test_coverage/test_coverage.xml"
+ coverage_report_path = "helpers-results/cl_unit_test_coverage/test_coverage.xml"
println GetCoverageValue_lines_valid(coverage_report_path)
println GetCoverageValue_lines_covered(coverage_report_path)
println GetCoverageValue_line_rate(coverage_report_path)
@@ -517,7 +521,7 @@ pipeline {
badge_coverage.setColor(getColorScale(full_rate))
//badge_maintainability
- records = readCSV file: 'helpers-results/complexity_check/MI.csv'
+ records = readCSV file: 'helpers-results/cl_complexity_check/MI.csv'
maintainability = records[1][1]
badge_maintainability.setStatus(maintainability)
@@ -532,11 +536,11 @@ pipeline {
post {
always {
dir("gitrepo") {
- junit 'helpers-results/unit_test/*.xml'
+ junit 'helpers-results/cl_unit_test/*.xml'
// using cobertura format (= coverage xml format)
- publishCoverage adapters: [cobertura(mergeToOneReport: true, path: "helpers-results/unit_test_coverage/test_coverage.xml")]
+ publishCoverage adapters: [cobertura(mergeToOneReport: true, path: "helpers-results/cl_unit_test_coverage/test_coverage.xml")]
publishHTML([
- reportDir: "helpers-results/unit_test_coverage",
+ reportDir: "helpers-results/cl_unit_test_coverage",
reportFiles: "index.html",
reportName: "coverage-report-html",
allowMissing: false,
@@ -544,7 +548,7 @@ pipeline {
keepAll: true])
publishHTML([
- reportDir: "helpers-results/unit_test_full",
+ reportDir: "helpers-results/cl_unit_test_full",
reportFiles: unit_test_full_name__html,
reportName: "test-reports-full",
allowMissing: false,
@@ -558,15 +562,14 @@ pipeline {
stage("GenDOC") {
steps {
dir("gitrepo") {
- //--doc-gen-pdf
- sh(". ~/TEST_ENV/bin/activate && python -m helpers --doc-gen --doc-gen-pdf")
+ sh(". ~/TEST_ENV/bin/activate && python -m chacha_cicd_helper --docgen --docgenpdf")
}
}
post {
always {
dir("gitrepo") {
publishHTML([
- reportDir: "helpers-results/doc_gen/site",
+ reportDir: "helpers-results/cl_doc_gen/site",
reportFiles: "index.html",
reportName: "doc-html",
allowMissing: false,
@@ -671,11 +674,11 @@ pipeline {
|
|data = {
| "name": "Documentation (pdf)",
- | 'attachment': ("${PY_PROJECT_NAME}_${PY_PROJECT_VERSION}_UserManual.pdf", open("helpers-results/doc_gen/site/pdf/manual.pdf", 'rb')),
+ | 'attachment': ("${PY_PROJECT_NAME}_${PY_PROJECT_VERSION}_UserManual.pdf", open("helpers-results/cl_doc_gen/site/pdf/manual.pdf", 'rb')),
|}
|GiteaApi.assets.post("${_PROJECT_USER_NAME}","${PY_PROJECT_NAME}",new_release_id,files=data)
|
- |shutil.make_archive("doc", 'zip', "helpers-results/doc_gen/site")
+ |shutil.make_archive("doc", 'zip', "helpers-results/cl_doc_gen/site")
|reqData={
| "SECRET": "${MKDOCSTOKEN}",
| "USER": "${_PROJECT_USER_NAME}",
diff --git a/RUN_changelog.launch b/RUN_changelog.launch
deleted file mode 100644
index 4dde656..0000000
--- a/RUN_changelog.launch
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/RUN_complexity.launch b/RUN_complexity.launch
index 8e17941..364dd2f 100644
--- a/RUN_complexity.launch
+++ b/RUN_complexity.launch
@@ -2,14 +2,15 @@
-
+
-
+
+
-
+
diff --git a/RUN_mkdocs.launch b/RUN_mkdocs.launch
index b7c5f92..c7a94eb 100644
--- a/RUN_mkdocs.launch
+++ b/RUN_mkdocs.launch
@@ -2,17 +2,15 @@
-
+
-
-
-
-
+
+
-
+
diff --git a/RUN_quality.launch b/RUN_quality.launch
index 66bfecc..9fa6906 100644
--- a/RUN_quality.launch
+++ b/RUN_quality.launch
@@ -2,14 +2,15 @@
-
+
-
+
+
-
+
diff --git a/RUN_unittest.launch b/RUN_unittest.launch
index 8ea9138..2d2cdff 100644
--- a/RUN_unittest.launch
+++ b/RUN_unittest.launch
@@ -2,14 +2,15 @@
-
+
-
+
+
-
+
diff --git a/helpers/.gitignore b/helpers/.gitignore
deleted file mode 100644
index 9bfc441..0000000
--- a/helpers/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/.mypy_cache/
diff --git a/helpers/__init__.py b/helpers/__init__.py
deleted file mode 100644
index 725cc2e..0000000
--- a/helpers/__init__.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# pyChaChaDummyProject (c) by chacha
-#
-# pyChaChaDummyProject is licensed under a
-# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
-#
-# You should have received a copy of the license along with this
-# work. If not, see .
\ No newline at end of file
diff --git a/helpers/__main__.py b/helpers/__main__.py
deleted file mode 100644
index c5fb64a..0000000
--- a/helpers/__main__.py
+++ /dev/null
@@ -1,108 +0,0 @@
-# pyChaChaDummyProject (c) by chacha
-#
-# pyChaChaDummyProject is licensed under a
-# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
-#
-# You should have received a copy of the license along with this
-# work. If not, see .
-
-from __future__ import annotations
-from typing import TYPE_CHECKING
-
-from pathlib import Path
-import tomli
-import argparse
-import os
-import logging
-import sys
-
-if __package__ == "helpers":
- # when calling the module from: > python -m helpers
- from .types_check import types_check
- from .quality_check import quality_check
- from .unit_test import unit_test
- from .doc_gen import doc_gen
- from .complexity_check import complexity_check
-else:
- # when calling the __main__.py file (from IDE)
- from helpers.types_check import types_check
- from helpers.quality_check import quality_check
- from helpers.unit_test import unit_test
- from helpers.doc_gen import doc_gen
- from helpers.complexity_check import complexity_check
-
-logging.getLogger().setLevel(logging.INFO)
-
-if __name__ == "__main__":
- project_rootdir_path = Path(__file__).parent.parent.absolute()
-
- with open(project_rootdir_path / "pyproject.toml", mode="rb") as fp:
- pyproject = tomli.load(fp)
-
- parser = argparse.ArgumentParser(
- prog="continuous-integration-helper", description="A tiny set of scripts to help continous integration on python"
- )
-
- parser.add_argument("-tc", "--type-check", dest="typecheck", action="store_true", help="enable static typing check")
-
- parser.add_argument("-ut", "--unit-test", dest="unittest", action="store_true", help="enable unit-test")
- parser.add_argument(
- "-cc", "--coverage-check", dest="coveragecheck", action="store_true", help="enable unit-test coverage check (requires unit-test)"
- )
-
- parser.add_argument("-qc", "--quality-check", dest="qualitycheck", action="store_true", help="enable code quality check")
-
- parser.add_argument("-dg", "--doc-gen", dest="docgen", action="store_true", help="enable documentation generation using MkDoc")
- parser.add_argument(
- "-pdf", "--doc-gen-pdf", dest="docgenpdf", action="store_true", help="enable pdf documentation export (requires doc-gen)"
- )
-
- parser.add_argument("-cpc", "--complexity-check", dest="complexitycheck", action="store_true", help="enable complexity check")
-
- args = parser.parse_args()
-
- ##################################
- # Dev / Debug forced toogles
- #
- # --------------------------------
- #
- # args.typecheck = True
- # args.qualitycheck = True
- # args.unittest = True
- # args.coveragecheck = True
- # args.docgen = True
- # args.docgenpdf = True
- # args.complexitycheck = True
-
- helpers = []
- if args.typecheck == True:
- helpers.append(types_check)
-
- if args.unittest == True:
- helpers.append(unit_test)
-
- if args.coveragecheck == True:
- if args.unittest == True:
- unit_test.enable_coverage_check = True
- else:
- raise RuntimeError("unit-test is required to enable coverage-check")
-
- if args.qualitycheck == True:
- helpers.append(quality_check)
-
- if args.docgen == True:
- helpers.append(doc_gen)
-
- if args.docgenpdf == True:
- if args.docgen == True:
- doc_gen.enable_gen_pdf = True
- else:
- raise RuntimeError("doc-gen is required to enable doc-gen-pdf")
-
- if args.complexitycheck == True:
- helpers.append(complexity_check)
-
- for helper in helpers:
- helper.set_context(project_rootdir_path, pyproject)
- helper.reset_result_dir()
- helper.do_job()
diff --git a/helpers/complexity_check.py b/helpers/complexity_check.py
deleted file mode 100644
index 529e872..0000000
--- a/helpers/complexity_check.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# pyChaChaDummyProject (c) by chacha
-#
-# pyChaChaDummyProject is licensed under a
-# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
-#
-# You should have received a copy of the license along with this
-# work. If not, see .
-
-from __future__ import annotations
-from typing import TYPE_CHECKING
-
-# from pathlib import Path
-# import os
-import statistics
-import csv
-from json import loads as JSON_LOADS
-from radon.complexity import cc_rank, SCORE
-from radon.cli import Config
-from radon.cli.harvest import CCHarvester, HCHarvester, MIHarvester
-
-from .helper_base import helper_withresults_base
-from pprint import pprint
-
-
-class complexity_check(helper_withresults_base):
- @classmethod
- def do_job(cls):
- config = Config(
- exclude="__init__\.py",
- ignore=None,
- order=SCORE,
- show_closures=False,
- no_assert=True,
- min="A",
- max="F",
- multi=False,
- )
-
- h = MIHarvester([str(_) for _ in sorted((cls.project_rootdir_path / "src").rglob("*.py"))], config).as_json()
- res = JSON_LOADS(h)
-
- with open(cls.get_result_dir() / "MI.json", "w", newline="") as oFile:
- oFile.write(h)
-
- mean = statistics.mean(_["mi"] for _ in res.values())
-
- if mean >= 65:
- rank = "A+"
- elif mean >= 20:
- rank = "A"
- elif mean >= 10:
- rank = "B"
- else:
- rank = "C"
-
- RES_MI = {"MeanMaintainability": mean, "MaintainabilityIndex": rank}
- with open(cls.get_result_dir() / "MI.csv", "w", newline="") as oFile:
- writer = csv.DictWriter(oFile, fieldnames=RES_MI.keys())
- writer.writeheader()
- writer.writerow(RES_MI)
-
- config = Config(exclude=None, ignore=None, order=SCORE, show_closures=False, no_assert=True, min="A", max="F", multi=False)
- h = CCHarvester([str(_) for _ in sorted((cls.project_rootdir_path / "src").rglob("*.py"))], config).as_json()
- with open(cls.get_result_dir() / "CC.json", "w", newline="") as oFile:
- oFile.write(h)
-
- config = Config(exclude=None, ignore=None, order=SCORE, show_closures=False, no_assert=True, min="A", max="F", by_function=None)
- h = HCHarvester([str(_) for _ in sorted((cls.project_rootdir_path / "src").rglob("*.py"))], config).as_json()
- with open(cls.get_result_dir() / "HC.json", "w", newline="") as oFile:
- oFile.write(h)
diff --git a/helpers/doc_gen.py b/helpers/doc_gen.py
deleted file mode 100644
index 7c86dd9..0000000
--- a/helpers/doc_gen.py
+++ /dev/null
@@ -1,98 +0,0 @@
-# pyChaChaDummyProject (c) by chacha
-#
-# pyChaChaDummyProject is licensed under a
-# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
-#
-# You should have received a copy of the license along with this
-# work. If not, see .
-
-from __future__ import annotations
-from typing import TYPE_CHECKING
-
-import shutil
-import os
-import sys
-import subprocess
-from pathlib import Path
-from distutils.dir_util import copy_tree
-
-import yaml
-
-try:
- from yaml import CLoader as Loader, CDumper as Dumper
-except ImportError:
- from yaml import Loader, Dumper
-
-from .helper_base import helper_withresults_base
-
-
-class doc_gen(helper_withresults_base):
- enable_gen_pdf: bool = False
-
- @classmethod
- def do_job(cls):
-
- # create doc root dir
- doc_path = cls.project_rootdir_path / "docs"
- cls._reset_dir(doc_path)
-
- site_path = cls.get_result_dir() / "site"
- cls._reset_dir(site_path)
-
- # copy files from main project dir
- shutil.copyfile(str(cls.project_rootdir_path / "README.md"), str(doc_path / "README.md"))
- shutil.copyfile(str(cls.project_rootdir_path / "LICENSE.md"), str(doc_path / "LICENSE.md"))
-
- # copy files from static-doc dir
- copy_tree(str(cls.project_rootdir_path / "docs-static"), str(doc_path))
-
- # generating API doc + nav from python docstrings
- reference_path = doc_path / "reference"
- cls._reset_dir(reference_path)
-
- # create one .md per python module
- for path in sorted((cls.project_rootdir_path / "src").rglob("*.py")):
- module_path = path.relative_to(cls.project_rootdir_path / "src").with_suffix("")
- doc_path = path.relative_to(cls.project_rootdir_path / "src").with_suffix(".md")
- full_doc_path = Path(reference_path, doc_path)
-
- parts = list(module_path.parts)
-
- if parts[-1] in ("__init__", "__main__"):
- continue
-
- cls._create_dir(full_doc_path.parent.resolve())
- with open(full_doc_path, "w+") as fd:
- identifier = ".".join(parts)
- print("::: " + identifier, file=fd)
-
- cmdopts = [f"{sys.executable}", "-m", "mkdocs", "-v", "build", "--site-dir", str(site_path), "--clean"]
-
- # little hack here, to enable / disable pdf generation using own class config
- # => reason is mkdocs seems to try loading the plugin even if we disable it, so we need to
- # manually process the configuration file.
- with open(cls.project_rootdir_path / "mkdocs.yml", "r") as mkdocsCfgFile:
- mkdocsCfg = yaml.load(mkdocsCfgFile, Loader=yaml.Loader)
-
- if "plugins" in mkdocsCfg:
- mkdocsCfg["plugins"] = [_ for _ in mkdocsCfg["plugins"] if (not isinstance(_, dict) or "with-pdf" not in _.keys())]
-
- if cls.enable_gen_pdf == True:
- mkdocsCfg["plugins"].append(
- {
- "with-pdf": {
- "cover_subtitle": "User Manual",
- "cover_logo": str(cls.project_rootdir_path / "docs-static" / "Library.jpg"),
- "verbose": False,
- "exclude_pages": ["LICENSE"],
- "output_path": str(site_path / "pdf" / "manual.pdf"),
- }
- }
- )
- with open(cls.project_rootdir_path / "mkdocs.yml", "w") as mkdocsCfgFile:
- mkdocsCfgFile.write(yaml.dump(mkdocsCfg, Dumper=Dumper, default_flow_style=False, sort_keys=False))
-
- print(" !! start doc generation")
- res = cls.run_cmd(cmdopts)
- print(res.decode())
- print(" !! done")
diff --git a/helpers/helper_base.py b/helpers/helper_base.py
deleted file mode 100644
index e1bf5db..0000000
--- a/helpers/helper_base.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# pyChaChaDummyProject (c) by chacha
-#
-# pyChaChaDummyProject is licensed under a
-# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
-#
-# You should have received a copy of the license along with this
-# work. If not, see .
-
-from __future__ import annotations
-from typing import TYPE_CHECKING
-
-from abc import ABC, abstractmethod
-import os
-import shutil
-from pathlib import Path
-import subprocess
-
-if TYPE_CHECKING: # Only imports the below statements during type checking
- from typing import Union
-
-
-class helper_base(ABC):
- project_rootdir_path: Union[Path, None] = None
- pyproject: Union[dict, None] = None
- current_dir: Union[Path, None] = None
-
- @classmethod
- def set_context(cls, project_rootdir_path: Path, pyproject: dict):
- cls.project_rootdir_path = project_rootdir_path
- cls.pyproject = pyproject
- cls.current_dir = Path(__file__).parent.absolute()
-
- @classmethod
- def get_result_dir(cls):
- return None
-
- @staticmethod
- def _create_dir(dirpath: Path):
- dirpath = Path(dirpath)
- if not os.path.exists(dirpath):
- os.makedirs(dirpath)
-
- @staticmethod
- def _reset_dir(dirpath: Path):
- dirpath = Path(dirpath)
- if os.path.exists(dirpath):
- shutil.rmtree(dirpath)
- os.makedirs(dirpath)
-
- @classmethod
- def reset_result_dir(cls):
- result_dir = cls.get_result_dir()
- if result_dir != None:
- cls._reset_dir(result_dir)
-
- @classmethod
- @abstractmethod
- def do_job(cls):
- raise NotImplementedError()
-
- @classmethod
- def run_cmd_(cls, cmdarray):
- process = subprocess.run(cmdarray, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, check=True)
- return process.stdout
-
- @classmethod
- def run_cmd(cls, cmdarray, silent: bool = False):
- p = subprocess.run(cmdarray, capture_output=True)
- if not silent:
- print(p.stdout.decode())
- print(p.stderr.decode())
- return p.stdout
-
-
-class helper_withresults_base(helper_base):
- helper_results_dir: Union[Path, None] = None
-
- @classmethod
- def get_result_dir(cls):
- if cls.helper_results_dir == None:
- cls.helper_results_dir = cls.__name__
- return Path(__file__).parent.parent.absolute() / "helpers-results" / cls.helper_results_dir
diff --git a/helpers/quality_check.py b/helpers/quality_check.py
deleted file mode 100644
index c63207b..0000000
--- a/helpers/quality_check.py
+++ /dev/null
@@ -1,247 +0,0 @@
-# pyChaChaDummyProject (c) by chacha
-#
-# pyChaChaDummyProject is licensed under a
-# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
-#
-# You should have received a copy of the license along with this
-# work. If not, see .
-
-from __future__ import annotations
-from typing import TYPE_CHECKING
-
-from contextlib import redirect_stdout
-from io import StringIO
-import re
-import json
-from enum import Enum
-from contextlib import suppress
-import sys
-import pandas
-import csv
-import copy
-
-from pylint.lint import Run as pylint_Run
-import pylint_json2html
-
-from .helper_base import helper_withresults_base
-
-
-class PyLintMetricNotFound(Warning):
- pass
-
-
-class quality_check(helper_withresults_base):
- PylintMessageList = dict()
-
- @classmethod
- def GetPylintMessageList(cls):
- Messagelist = dict()
- regex = r"^:([a-zA-Z-]+) \(([^\)]+)\)"
- for line in cls.run_cmd([sys.executable, "-m", "pylint", "--list-msgs"], True).splitlines():
- if res := re.search(regex, line.decode()):
- Messagelist[res.group(1)] = res.group(2)
- cls.PylintMessageList = Messagelist
-
- @staticmethod
- def TryExtractPYReportMetric(line: str, tag: str):
- regex = f"^(?:\|{tag}\s*\|)(\d+)(?=\s*|)"
- if res := re.search(regex, line):
- return float(res.group(1))
- raise PyLintMetricNotFound()
-
- @classmethod
- def do_job(cls):
- print("checking code quality ...")
-
- cls.GetPylintMessageList()
-
- RES_all = dict()
- with StringIO() as StdOutput:
- JsonContent = ""
- with redirect_stdout(StdOutput):
- pylint_Run(
- [
- "--load-plugins=pylint.extensions.mccabe",
- "--output-format=json,parseable",
- "--disable=invalid-name,too-few-public-methods,too-many-arguments", # ignore
- "--ignore=_version.py",
- "--reports=y",
- "--score=yes",
- "--max-line-length=140",
- "src." + cls.pyproject["project"]["name"],
- ],
- exit=False,
- )
-
- with open(cls.get_result_dir() / "report.json", "w+", encoding="utf-8") as Outfile:
- # hacky way of exctracting json + having overall score...
- class TScanState(Enum):
- TEXT_REPORT = 1
- JSON_REPORT = 2
- OTHER_REPORT_START = 3
- OTHER_REPORT_STATISTICS = 4
- OTHER_REPORT_METRICS = 5
- OTHER_REPORT_DUPLICATION = 6
- OTHER_REPORT_MESSAGES_CAT = 7
- OTHER_REPORT_MESSAGES = 8
- OTHER_REPORT_END = 99
-
- RES_all["Statistics"] = dict()
- RES_all["RawMetrics"] = dict()
- RES_all["RawMetricsPercent"] = dict()
- RES_all["Duplication"] = dict()
- RES_all["MessagesCat"] = dict()
- RES_all["Messages"] = dict()
- RES_all["GlobalScore"] = -999
- RES_all["NbAnalysedStatments"] = -999
- RES_all["NbAnalysedLines"] = -999
-
- ScanState = TScanState.TEXT_REPORT
- for line in StdOutput.getvalue().split("\n"):
- print(line)
- if ScanState == TScanState.TEXT_REPORT:
- # ignoring this part, we need json
- if line == "[":
- JsonContent += line
- ScanState = TScanState.JSON_REPORT
- elif line == "[]":
- JsonContent += line
- ScanState = TScanState.OTHER_REPORT_START
-
- elif ScanState == TScanState.JSON_REPORT:
- JsonContent += line
- if line == "]":
- ScanState = TScanState.OTHER_REPORT_START
-
- elif ScanState == TScanState.OTHER_REPORT_START:
- if res := re.search(r"^(\d+)(?= statements analysed.)", line):
- RES_all["NbAnalysedStatments"] = float(res.group(1))
- if line == "Statistics by type":
- ScanState = TScanState.OTHER_REPORT_STATISTICS
-
- elif ScanState == TScanState.OTHER_REPORT_STATISTICS:
- if res := re.search(r"^(\d+)(?= lines have been analyzed)", line):
- RES_all["NbAnalysedLines"] = float(res.group(1))
- elif line == "Raw metrics":
- ScanState = TScanState.OTHER_REPORT_METRICS
- else:
- with suppress(PyLintMetricNotFound):
- RES_all["Statistics"]["module"] = cls.TryExtractPYReportMetric(line, "module")
- with suppress(PyLintMetricNotFound):
- RES_all["Statistics"]["class"] = cls.TryExtractPYReportMetric(line, "class")
- with suppress(PyLintMetricNotFound):
- RES_all["Statistics"]["method"] = cls.TryExtractPYReportMetric(line, "method")
- with suppress(PyLintMetricNotFound):
- RES_all["Statistics"]["function"] = cls.TryExtractPYReportMetric(line, "function")
-
- elif ScanState == TScanState.OTHER_REPORT_METRICS:
- if line == "Duplication":
- RES_all["RawMetricsPercent"]["code"] = RES_all["RawMetrics"]["code"] / RES_all["NbAnalysedLines"]
- RES_all["RawMetricsPercent"]["docstring"] = RES_all["RawMetrics"]["docstring"] / RES_all["NbAnalysedLines"]
- RES_all["RawMetricsPercent"]["comment"] = RES_all["RawMetrics"]["comment"] / RES_all["NbAnalysedLines"]
- RES_all["RawMetricsPercent"]["empty"] = RES_all["RawMetrics"]["empty"] / RES_all["NbAnalysedLines"]
- ScanState = TScanState.OTHER_REPORT_DUPLICATION
- else:
- with suppress(PyLintMetricNotFound):
- RES_all["RawMetrics"]["code"] = cls.TryExtractPYReportMetric(line, "code")
- with suppress(PyLintMetricNotFound):
- RES_all["RawMetrics"]["docstring"] = cls.TryExtractPYReportMetric(line, "docstring")
- with suppress(PyLintMetricNotFound):
- RES_all["RawMetrics"]["comment"] = cls.TryExtractPYReportMetric(line, "comment")
- with suppress(PyLintMetricNotFound):
- RES_all["RawMetrics"]["empty"] = cls.TryExtractPYReportMetric(line, "empty")
-
- elif ScanState == TScanState.OTHER_REPORT_DUPLICATION:
- if line == "Messages by category":
- ScanState = TScanState.OTHER_REPORT_MESSAGES_CAT
- else:
- with suppress(PyLintMetricNotFound):
- RES_all["Duplication"]["NbDupLines"] = cls.TryExtractPYReportMetric(line, "nb duplicated lines")
- with suppress(PyLintMetricNotFound):
- RES_all["Duplication"]["PersentDuplicatedLines"] = cls.TryExtractPYReportMetric(
- line, "percent duplicated lines"
- )
-
- elif ScanState == TScanState.OTHER_REPORT_MESSAGES_CAT:
- if line == "Messages":
- ScanState = TScanState.OTHER_REPORT_MESSAGES
- else:
- with suppress(PyLintMetricNotFound):
- RES_all["MessagesCat"]["Convention"] = cls.TryExtractPYReportMetric(line, "convention")
- with suppress(PyLintMetricNotFound):
- RES_all["MessagesCat"]["Refactor"] = cls.TryExtractPYReportMetric(line, "refactor")
- with suppress(PyLintMetricNotFound):
- RES_all["MessagesCat"]["Warning"] = cls.TryExtractPYReportMetric(line, "warning")
- with suppress(PyLintMetricNotFound):
- RES_all["MessagesCat"]["Error"] = cls.TryExtractPYReportMetric(line, "error")
-
- elif ScanState == TScanState.OTHER_REPORT_MESSAGES:
- # approx match because the number of '-' depend on screen width..
- if line.startswith("--------"):
- ScanState = TScanState.OTHER_REPORT_END
- else:
- for PylintMessage in cls.PylintMessageList.keys():
- with suppress(PyLintMetricNotFound):
- RES_all["Messages"][PylintMessage] = cls.TryExtractPYReportMetric(line, PylintMessage)
-
- elif ScanState == TScanState.OTHER_REPORT_END:
- if res := re.search(r"(?<=Your code has been rated at )(\d+(?:\.\d+)?)/10", line):
- RES_all["GlobalScore"] = float(res.group(1))
- print(RES_all["GlobalScore"])
- else:
- raise RuntimeError("Invalid ScanState")
- Outfile.write(JsonContent)
-
- with open(cls.get_result_dir() / "metrics.json", "w") as json_file:
- json.dump(RES_all, json_file)
-
- # exporting all Data in one csv, unused atm because jenkins seems not able to select columns from csv an keep displaying all...
- # => to export a working full csv we need to a 'flat' dict (no more nested dict)
- RES_all_trim = copy.deepcopy(RES_all)
- del RES_all_trim["Messages"]
- flat_RES_all = pandas.json_normalize(RES_all_trim, sep="_").to_dict(orient="records")[0]
-
- with open(cls.get_result_dir() / "metrics.csv", "w", newline="") as csv_file:
- writer = csv.DictWriter(csv_file, fieldnames=flat_RES_all.keys())
- writer.writeheader()
- writer.writerow(flat_RES_all)
-
- # splited csv exports for jenkins plots: RawMetricsPercent
- RES_all_percent = RES_all["RawMetricsPercent"]
- with open(cls.get_result_dir() / "metrics_rawpercent.csv", "w", newline="") as csv_file:
- writer = csv.DictWriter(csv_file, fieldnames=RES_all_percent.keys())
- writer.writeheader()
- writer.writerow(RES_all_percent)
-
- # splited csv exports for jenkins plots: Statistics + Duplication + NbAnalysedStatments + NbAnalysedLines
- RES_all_stats = copy.deepcopy(RES_all["Statistics"])
- RES_all_stats["NbDupLines"] = RES_all["Duplication"]["NbDupLines"]
- RES_all_stats["PersentDuplicatedLines"] = RES_all["Duplication"]["PersentDuplicatedLines"]
- RES_all_stats["NbAnalysedStatments"] = RES_all["NbAnalysedStatments"]
- RES_all_stats["NbAnalysedLines"] = RES_all["NbAnalysedLines"]
- with open(cls.get_result_dir() / "metrics_Statistics.csv", "w", newline="") as csv_file:
- writer = csv.DictWriter(csv_file, fieldnames=RES_all_stats.keys())
- writer.writeheader()
- writer.writerow(RES_all_stats)
-
- # splited csv exports for jenkins plots: Statistics + Duplication
- RES_all_MessagesCat = RES_all["MessagesCat"]
- with open(cls.get_result_dir() / "metrics_MessagesCat.csv", "w", newline="") as csv_file:
- writer = csv.DictWriter(csv_file, fieldnames=RES_all_MessagesCat.keys())
- writer.writeheader()
- writer.writerow(RES_all_MessagesCat)
-
- # splited csv exports for jenkins plots: GlobalScore
- RES_GlobalScore = {"GlobalScore": RES_all["GlobalScore"]}
- with open(cls.get_result_dir() / "metrics_GlobalScore.csv", "w", newline="") as csv_file:
- writer = csv.DictWriter(csv_file, fieldnames=RES_GlobalScore.keys())
- writer.writeheader()
- writer.writerow(RES_GlobalScore)
-
- # converting the report using pylint_json2html (/!\ internal API, but as their is no leading '_' ...)
- with open(cls.get_result_dir() / "report.html", "w+", encoding="utf-8") as Outfile:
- raw_data = json.loads(JsonContent)
- report = pylint_json2html.Report(raw_data)
- Outfile.write(report.render())
-
- print("Done")
diff --git a/helpers/types_check.py b/helpers/types_check.py
deleted file mode 100644
index 26b7942..0000000
--- a/helpers/types_check.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# pyChaChaDummyProject (c) by chacha
-#
-# pyChaChaDummyProject is licensed under a
-# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
-#
-# You should have received a copy of the license along with this
-# work. If not, see .
-
-from __future__ import annotations
-from typing import TYPE_CHECKING
-
-from pathlib import Path
-
-from mypy import api
-
-from .helper_base import helper_withresults_base
-
-
-class types_check(helper_withresults_base):
- JUnitReportName = "junit.xml"
-
- @classmethod
- def do_job(cls):
- print("checking code typing ...")
- result = api.run(
- [ # project path
- "-p",
- "src." + cls.pyproject["project"]["name"],
- # analysis configuration
- # "--show-traceback",
- "--explicit-package-bases",
- # "--strict-equality",
- # "--check-untyped-defs",
- # reports generation
- "--cobertura-xml-report",
- str(cls.get_result_dir()),
- "--html-report",
- str(cls.get_result_dir()),
- "--txt-report",
- str(cls.get_result_dir()),
- "--xml-report",
- str(cls.get_result_dir()),
- "--junit-xml",
- str(cls.get_result_dir()) + "/" + cls.JUnitReportName,
- ]
- )
-
- if result[0]:
- print("\nType checking report:\n")
- print(result[0]) # stdout
- # converting the report using pylint_json2html (/!\ internal API, but as their is no leading '_' ...)
- with open(cls.get_result_dir() / "raw_eport.txt", "w+", encoding="utf-8") as Outfile:
- Outfile.write(result[0])
-
- if result[1]:
- print("\nError report:\n")
- print(result[1]) # stderr
-
- print("\nExit status:", result[2])
- print("Done")
diff --git a/helpers/unit_test.py b/helpers/unit_test.py
deleted file mode 100644
index 4d9d6a3..0000000
--- a/helpers/unit_test.py
+++ /dev/null
@@ -1,81 +0,0 @@
-# pyChaChaDummyProject (c) by chacha
-#
-# pyChaChaDummyProject is licensed under a
-# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
-#
-# You should have received a copy of the license along with this
-# work. If not, see .
-
-from __future__ import annotations
-from typing import TYPE_CHECKING
-
-from pathlib import Path
-import os
-import datetime
-
-import unittest
-import xmlrunner
-from junitparser import JUnitXml
-from junit2htmlreport import parser as junit2html_parser
-
-from .helper_base import helper_withresults_base
-
-
-class unit_test(helper_withresults_base):
- enable_coverage_check: bool = False
- enable_xml_export: bool = True
- enable_full_xml_export: bool = True
- FullReportName: str = "full_report"
- CoverageReportName: str = "test_coverage"
-
- @classmethod
- def do_job(cls):
- if cls.enable_coverage_check == True:
- import coverage
-
- # preparing unittest framework
- test_loader = unittest.TestLoader()
-
- if cls.enable_coverage_check == True:
- # we start coverage now because module files discovery is part of the coverage measurement
- CoverageReportPath = Path(str(cls.get_result_dir()) + "_coverage")
- cls._reset_dir(CoverageReportPath)
- cov = coverage.Coverage(cover_pylib=False, branch=True, source_pkgs=["src." + cls.pyproject["project"]["name"]])
- cov.start()
-
- package_tests = test_loader.discover(
- start_dir=str(cls.project_rootdir_path / "test"), top_level_dir=str(cls.project_rootdir_path / "test")
- )
- if cls.enable_xml_export:
- testRunner = xmlrunner.XMLTestRunner(output=str(str(cls.get_result_dir())))
- else:
- testRunner = unittest.TextTestRunner()
-
- # running the test
- testRunner.run(package_tests)
-
- print("Test Finished")
- if cls.enable_coverage_check == True:
- cov.stop()
- cov.save()
- cov.html_report(directory=str(CoverageReportPath))
- cov.xml_report(outfile=(CoverageReportPath / f"{cls.CoverageReportName}.xml"))
-
- # computing results (Only if xml available)
- if cls.enable_full_xml_export == True:
- print("Full reports generation...")
- FullReportPath = Path(str(cls.get_result_dir()) + "_full")
- cls._reset_dir(FullReportPath)
-
- FullJUnitReport = JUnitXml()
- for fname in [fname for fname in os.listdir(cls.get_result_dir()) if fname.endswith(".xml")]:
- FullJUnitReport += JUnitXml.fromfile(str(cls.get_result_dir() / fname))
-
- current_datetime = datetime.datetime.utcnow().strftime("%Y%m%dT%H%M%SZ")
- full_report_base_name = f'{cls.pyproject["project"]["name"]}-{cls.FullReportName}-{current_datetime}'
- FullJUnitReport.write(str(FullReportPath / f"{full_report_base_name}.xml"))
- report = junit2html_parser.Junit(FullReportPath / f"{full_report_base_name}.xml")
- html = report.html()
- with open(FullReportPath / f"{full_report_base_name}.html", "wb") as outfile:
- outfile.write(html.encode("utf-8"))
- print("Done")
diff --git a/helpers_proxy/__main__.py b/helpers_proxy/__main__.py
new file mode 100644
index 0000000..b39dc60
--- /dev/null
+++ b/helpers_proxy/__main__.py
@@ -0,0 +1,5 @@
+from chacha_cicd_helper.__main__ import fct_main
+import sys
+
+if __name__ == "__main__":
+ fct_main(sys.argv[1:])
diff --git a/pyproject.toml b/pyproject.toml
index d430840..e2b0898 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -57,12 +57,12 @@ Documentation = "https://chacha.ddns.net/mkdocs-web/chacha/pygamecfg/master/la
Tracker = "https://chacha.ddns.net/gitea/chacha/pygamecfg/issues"
[project.optional-dependencies]
-test = ["junitparser>=2.8","junit2html>=30.1","xmlrunner>=1.7","mypy>=0.99" ]
-coverage-check = ["coverage>=7.0"]
-complexity-check = ["radon>=5.1"]
-quality-check = ["pylint>=2.15","pylint-json2html>=0.4","pandas>=1.5"]
-type-check = ["mypy[reports]>=0.99" ]
-doc-gen = ["mkdocs>=1.4.0", "mkdocs-material>=8.5","mkdocs-material-extensions","mkdocs-pymdownx-material-extras", "mkdocs-localsearch>=0.9.0", "mkdocstrings[python]>=0.19", "mkdocs-with-pdf>=0.9.3","pyyaml>=6.0","pymdown-extensions>=9","mkdocs-markdownextradata-plugin","mkdocs-mermaid2-plugin","mkdocs-autorefs"]
+test = ["chacha_cicd_helper@git+https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper.git@master"]
+coverage-check = ["chacha_cicd_helper@git+https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper.git@master"]
+complexity-check = ["chacha_cicd_helper@git+https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper.git@master"]
+quality-check = ["chacha_cicd_helper@git+https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper.git@master"]
+type-check = ["chacha_cicd_helper@git+https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper.git@master"]
+doc-gen = ["chacha_cicd_helper@git+https://chacha.ddns.net/gitea/chacha/chacha_cicd_helper.git@master"]
# [project.scripts]
# my-script = "my_package.module:function"
diff --git a/pyproject.toml.bak b/pyproject.toml.bak
deleted file mode 100644
index 1fb8af4..0000000
--- a/pyproject.toml.bak
+++ /dev/null
@@ -1,68 +0,0 @@
-# pyChaChaDummyProject (c) by chacha
-#
-# pyChaChaDummyProject is licensed under a
-# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
-#
-# You should have received a copy of the license along with this
-# work. If not, see .
-
-[build-system]
-requires = ["setuptools>=63", "wheel", "setuptools_scm"]
-build-backend = "setuptools.build_meta"
-
-[tool.setuptools_scm]
-version_scheme= "post-release"
-
-[project]
-name = "pygamecfg"
-description = "A simple game config tool that provide bash API to read / write game config files (cod, ut ...)"
-readme = "README.md"
-requires-python = ">=3.9"
-keywords = ["chacha","chacha","template","pygamecfg"]
-license = { file = "LICENSE.md" }
-
-authors = [
- {name="chacha",email="1000CHACHA0001@gmail.com"},
-]
-maintainers = [
- {name="chacha",email="1000CHACHA0001@gmail.com"},
-]
-classifiers = [
- "Development Status :: 4 - Beta",
- "Programming Language :: Python :: 3 :: Only",
- "Programming Language :: Python :: 3.9",
-]
-dependencies = [
- 'importlib-metadata; python_version<"3.9"',
- 'packaging',
- 'pysimpleini>=0.3.1',
- 'typed-argument-parser==1.*'
-]
-dynamic = ["version"]
-
-[tool.setuptools]
-platforms = ["any"]
-include-package-data = true
-
-[tool.setuptools.packages.find]
-where = ["src"]
-
-[tool.setuptools.package-data]
-"pygamecfg.data" = ["*.*"]
-
-[project.urls]
-Homepage = "https://chacha.ddns.net/gitea/chacha/pygamecfg"
-Documentation = "https://chacha.ddns.net/mkdocs-web/chacha/pygamecfg/master/latest/"
-Tracker = "https://chacha.ddns.net/gitea/chacha/pygamecfg/issues"
-
-[project.optional-dependencies]
-test = ["junitparser>=2.8","junit2html>=30.1","xmlrunner>=1.7","mypy>=0.99" ]
-coverage-check = ["coverage>=7.0"]
-complexity-check = ["radon>=5.1"]
-quality-check = ["pylint>=2.15","pylint-json2html>=0.4","pandas>=1.5"]
-type-check = ["mypy[reports]>=0.99" ]
-doc-gen = ["mkdocs>=1.4.0", "mkdocs-material>=8.5","mkdocs-material-extensions","mkdocs-pymdownx-material-extras", "mkdocs-localsearch>=0.9.0", "mkdocstrings[python]>=0.19", "mkdocs-with-pdf>=0.9.3","pyyaml>=6.0","pymdown-extensions>=9","mkdocs-markdownextradata-plugin","mkdocs-mermaid2-plugin","mkdocs-autorefs"]
-
-# [project.scripts]
-# my-script = "my_package.module:function"
-
diff --git a/src/pygamecfg/core_gamecfg.py b/src/pygamecfg/core_gamecfg.py
index fbd7d51..915c5f8 100644
--- a/src/pygamecfg/core_gamecfg.py
+++ b/src/pygamecfg/core_gamecfg.py
@@ -19,6 +19,14 @@ from abc import ABCMeta, abstractmethod
from enum import Enum
+class GameCfgException(Exception):
+ """Standard Exception to catch non existing key in configuration file"""
+
+
+class OptionNotFoundError(GameCfgException):
+ """Standard Exception to catch non existing configuration option"""
+
+
class OptionType(Enum):
"""Supported option data type"""
@@ -145,7 +153,7 @@ class GameOptions_Factory:
with _option(self.GameRootDir, self.ConfigFileRelPath) as _optionInst:
_optionInst.set(_optionInst.format(value))
return
- raise RuntimeError("Option not found")
+ raise OptionNotFoundError("Option not found")
def rem(self, OptionName: str, value: Union[None, str]) -> None:
"""generic rem function (API call)"""
@@ -154,7 +162,7 @@ class GameOptions_Factory:
with _option(self.GameRootDir, self.ConfigFileRelPath) as _optionInst:
_optionInst.rem(value)
return
- raise RuntimeError("Option not found")
+ raise OptionNotFoundError("Option not found")
def get(self, OptionName: str) -> Union[str, list[str]]:
"""generic get function (API call)"""
@@ -162,7 +170,7 @@ class GameOptions_Factory:
if _option.szOptionName == OptionName:
with _option(self.GameRootDir, self.ConfigFileRelPath) as _optionInst:
return _optionInst.get()
- raise RuntimeError("Option not found")
+ raise OptionNotFoundError("Option not found")
def GameOptions_Factory_Register(cls: type[GameOption]) -> type[GameOption]:
diff --git a/src/pygamecfg/game_cod4.py b/src/pygamecfg/game_cod4.py
index 08aa516..15db995 100644
--- a/src/pygamecfg/game_cod4.py
+++ b/src/pygamecfg/game_cod4.py
@@ -17,7 +17,11 @@ import re
from os.path import join
from os import linesep
-from .core_gamecfg import GameOptions_Factory_Register, GameOption, OptionType
+from .core_gamecfg import GameOptions_Factory_Register, GameOption, OptionType, GameCfgException
+
+
+class COD4KeyNotFoundError(GameCfgException):
+ """Exception to catch non existing configuration key in COD4 configuration file"""
class GameOption_COD4(GameOption):
@@ -27,7 +31,7 @@ class GameOption_COD4(GameOption):
szOptionName: str = ""
szKeyName: str = ""
bDblQuoted: bool = False
- szPrefix = ""
+ szPrefix: str = ""
def __init__(self, GameRootDir: str, ConfigFileRelPath: str) -> None:
super().__init__(GameRootDir, ConfigFileRelPath)
@@ -47,9 +51,8 @@ class GameOption_COD4(GameOption):
FinalValue: str = value
if self.bDblQuoted:
FinalValue = '"' + FinalValue + '"'
- if self.szPrefix:
+ if self.szPrefix != "":
FinalValue = self.szPrefix + " " + self.szKeyName + " " + FinalValue + linesep
-
bfound = False
newFile = ""
@@ -66,7 +69,7 @@ class GameOption_COD4(GameOption):
if not bfound:
# write new key at the top of the file to be sure we do not erase the map / map_rotate cmd
- newFile = value + newFile
+ newFile = FinalValue + newFile
self.cfgfile.close()
with open(self.mainConfigFilePath, "w", encoding="utf8") as ofile:
@@ -89,7 +92,7 @@ class GameOption_COD4(GameOption):
else:
newFile += line
if not bfound:
- raise RuntimeError("Option not found in file")
+ raise COD4KeyNotFoundError("Option not found in file")
self.cfgfile.close()
with open(self.mainConfigFilePath, "w", encoding="utf8") as ofile:
@@ -113,7 +116,7 @@ class GameOption_COD4(GameOption):
res = result.groupdict()["value"]
bfound = True
if not bfound:
- raise RuntimeError("Option not found in file")
+ raise COD4KeyNotFoundError("Option not found in file")
return res
diff --git a/test/data/COD4/main/server.cfg b/test/data/COD4/main/server.cfg
index c91ce60..1b4ac75 100644
--- a/test/data/COD4/main/server.cfg
+++ b/test/data/COD4/main/server.cfg
@@ -24,7 +24,7 @@ set g_log "games_mp.log"
set sv_log_damage "1"
set sv_statusfile "serverstatus.xml"
-set net_port 28960
+//set net_port 28960
set sv_minPing "0"
diff --git a/test/test_cod4.py b/test/test_cod4.py
index c90dc03..ee586ae 100644
--- a/test/test_cod4.py
+++ b/test/test_cod4.py
@@ -15,14 +15,12 @@ import shutil
from src import pygamecfg
from src.pygamecfg.__main__ import fct_main
+from src.pygamecfg.game_cod4 import COD4KeyNotFoundError
testdir_path = Path(__file__).parent.resolve()
class Testtest_cod4(unittest.TestCase):
- def tearDown(self) -> None:
- self.CleanTmp()
-
def setUp(self) -> None:
chdir(testdir_path.parent.resolve())
self.CleanTmp()
@@ -65,3 +63,14 @@ class Testtest_cod4(unittest.TestCase):
self.assertEqual("", capted_stderr.getvalue())
# check if other key still there / untouched
self.test_normal_READ_sv_mapRotation()
+
+ def test_defect_READ_net_port_NONEXISTS(self):
+ with self.assertRaises(COD4KeyNotFoundError):
+ fct_main(["-g", "cod4", "-b", "test/tmp/COD4", "GetOption", "net_port"])
+
+ def test_normal_WRITE_net_port_NONEXISTS(self):
+ fct_main(["-g", "cod4", "-b", "test/tmp/COD4", "SetOption", "net_port", "132"])
+ with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr:
+ fct_main(["-g", "cod4", "-b", "test/tmp/COD4", "GetOption", "net_port"])
+ self.assertEqual("132\n", capted_stdout.getvalue())
+ self.assertEqual("", capted_stderr.getvalue())
diff --git a/test/test_ut99.py b/test/test_ut99.py
index 39ee258..369962c 100644
--- a/test/test_ut99.py
+++ b/test/test_ut99.py
@@ -20,9 +20,6 @@ testdir_path = Path(__file__).parent.resolve()
class Testtest_ut99(unittest.TestCase):
- def tearDown(self) -> None:
- self.CleanTmp()
-
def setUp(self) -> None:
chdir(testdir_path.parent.resolve())
self.CleanTmp()