From 79e7728f529e052139b26033b9c942e319f77da1 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Tue, 17 Oct 2023 16:59:47 +0300 Subject: [PATCH 01/12] DF-2333: add commands to delete local & remote branches in repo before creating new one --- check_data_and_create_pr.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index 95e53f5..cae9ec1 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -9,6 +9,13 @@ mv temp/* . mv temp//.git* . rmdir temp + +# remove unused branches before creating new +git checkout master +# delete merged and unmerged remote branches +git branch --merged | egrep -v "(^\*|master)" | xargs -I % sh -c 'git branch -D %; git push --delete origin %'; +git branch --no-merged | egrep -v "(^\*|master)" | xargs -I % sh -c 'git branch -D %; git push --delete origin %'; + # create a new branch for update git checkout master PR_BRANCH_NAME="update_$(git log -n 1 --pretty=format:%H)" From a09d9c28bd3fcfe7f491e565d12ec49e031d2cfb Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Wed, 18 Oct 2023 17:09:15 +0300 Subject: [PATCH 02/12] DF-2333: debug script on GH runner done --- check_data_and_create_pr.sh | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index cae9ec1..a27a2f3 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -1,5 +1,8 @@ #!/bin/bash + +# setted by GitHub set -e +set +o pipefail bash scripts/validate_token.sh @@ -9,13 +12,25 @@ mv temp/* . mv temp//.git* . rmdir temp - +set +e +set +o pipefail # remove unused branches before creating new git checkout master -# delete merged and unmerged remote branches -git branch --merged | egrep -v "(^\*|master)" | xargs -I % sh -c 'git branch -D %; git push --delete origin %'; -git branch --no-merged | egrep -v "(^\*|master)" | xargs -I % sh -c 'git branch -D %; git push --delete origin %'; +git branch --list | cat +merged_branches=$(git branch -r --merged | grep "update_*" -c) +nomerged_branches=$(git branch --no-merged | grep "update_*" -c) +total_branches=$(($merged_branches+$nomerged_branches)) + +# delete all merged and unmerged remote `update_*` branches +if [[ $total_branches > 0 ]] +then + git branch -r --merged | grep "update_*" | cut -d "/" -f 2 | xargs git push --delete origin + git branch --no-merged | grep "update_*" | xargs -I % bash -c 'git branch -D %; git push --delete origin %'; +else + echo "No temporary branch to remove" +fi +set -e # create a new branch for update git checkout master PR_BRANCH_NAME="update_$(git log -n 1 --pretty=format:%H)" @@ -30,5 +45,6 @@ python3 scripts/simple_data_check.py bash scripts/close_pr_if_exists.sh # create new PR +set +e export GH_TOKEN=${ACTION_TOKEN} gh api -X POST /repos/tradingview-pine-seeds/${REPO_NAME}/pulls -f base="master" -f head="${REPO_OWNER}:${PR_BRANCH_NAME}" -f title="Upload data" > /dev/null 2>&1 From 8362b2667e686c875fd114ef3792e0de8a3d572b Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Thu, 26 Oct 2023 17:23:43 +0300 Subject: [PATCH 03/12] DF-2333: add extra command for 0 result code --- check_data_and_create_pr.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index a27a2f3..1f88702 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -48,3 +48,4 @@ bash scripts/close_pr_if_exists.sh set +e export GH_TOKEN=${ACTION_TOKEN} gh api -X POST /repos/tradingview-pine-seeds/${REPO_NAME}/pulls -f base="master" -f head="${REPO_OWNER}:${PR_BRANCH_NAME}" -f title="Upload data" > /dev/null 2>&1 +echo From 79c74b704760f4ea9e0a6d48564bcd5209f7997f Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Wed, 18 Oct 2023 09:11:48 +0300 Subject: [PATCH 04/12] DF-2335: more clear validation errors --- simple_data_check.py | 68 ++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/simple_data_check.py b/simple_data_check.py index 6859995..b18014d 100755 --- a/simple_data_check.py +++ b/simple_data_check.py @@ -4,7 +4,7 @@ the specification: https://github.com/tradingview-pine-seeds/pine-seeds-docs/blob/main/data.md """ - +from __future__ import annotations import glob import json import os @@ -12,18 +12,19 @@ from os.path import exists, isfile from sys import exit as sys_exit, argv from datetime import datetime -from re import compile as re_compile +from re import Pattern, compile as re_compile +from typing import Any, Dict, List, Tuple -TODAY = datetime.now().strftime("%Y%m%dT") -FLOAT_RE = re_compile(r'^[+-]?([0-9]*[.])?[0-9]+$') -SYMBOL_RE = re_compile(r'^[_.0-9A-Z]+$') -DESCRIPTION_RE = re_compile(r'^.+$') -PRICESCALE_RE = re_compile(r'^1(0){0,22}$') -REPORTS_PATH = argv[1] if len(argv) > 1 else None +TODAY: str = datetime.now().strftime("%Y%m%dT") +FLOAT_RE: Pattern[str] = re_compile(r'^[+-]?([0-9]*[.])?[0-9]+$') +SYMBOL_RE: Pattern[str] = re_compile(r'^[_.0-9A-Z]+$') +DESCRIPTION_RE: Pattern[str] = re_compile(r'^.+$') +PRICESCALE_RE: Pattern[str] = re_compile(r'^1(0){0,22}$') +REPORTS_PATH: str = argv[1] if len(argv) > 1 else None -def check_type(values, val_type): +def check_type(values: Any, val_type: type) -> bool: """ check that values is list of types or single type value """ if isinstance(values, list): for val in values: @@ -34,7 +35,7 @@ def check_type(values, val_type): return isinstance(values, val_type) -def check_length(values: any, max_length: int): +def check_length(values: Any, max_length: int) -> bool: """ check length of each element in values. Return True only when all elements have length less or equal to max_length.""" if isinstance(values, list): for val in values: @@ -45,7 +46,7 @@ def check_length(values: any, max_length: int): return True -def check_regexp(values, regexp): +def check_regexp(values: Any, regexp: Pattern[str]) -> bool: """ check that str() of each element in values match to provided regexp """ if isinstance(values, list): for val in values: @@ -56,7 +57,7 @@ def check_regexp(values, regexp): return True -def check_field_data(name, values, val_type, regexp, max_length, quantity, sym_file): +def check_field_data(name: str, values: Any, val_type: type, regexp: Pattern[str], max_length: int, quantity: int, sym_file: str) -> List[str]: """ check the field data according type, max_length and quantity of elements """ errors = [] if not check_type(values, val_type): @@ -78,7 +79,7 @@ def check_field_data(name, values, val_type, regexp, max_length, quantity, sym_f return errors -def get_duplicates(items: list): +def get_duplicates(items: List[Any]) -> set: """ Returns the set of duplicated items in list """ existing = set() dup = set() @@ -90,11 +91,11 @@ def get_duplicates(items: list): return dup -def check_symbol_info(sym_file): +def check_symbol_info(sym_file: str) -> Tuple[List[str], List[str]]: """ check symbol file """ - errors = [] + errors: List[str] = [] with open(sym_file) as file: - sym_data = json.load(file) + sym_data: Dict[str, Any] = json.load(file) expected_fields = set(("symbol", "description", "pricescale")) exists_fields = set(sym_data.keys()) if exists_fields != expected_fields: @@ -103,7 +104,7 @@ def check_symbol_info(sym_file): else: errors.append(F"The {sym_file} file doesn't have required fields: {', '.join(i for i in expected_fields.difference(exists_fields))}") return [], errors - symbols = sym_data["symbol"] + symbols: List[str] = sym_data["symbol"] errors = check_field_data("symbol", symbols, str, SYMBOL_RE, 42, 0, sym_file) if len(set(symbols)) != len(symbols): errors.append(F"The {sym_file} file contain duplicated symbols: {', '.join(get_duplicates(symbols))}. All symbols must have unique names.") @@ -120,10 +121,10 @@ def check_symbol_info(sym_file): return symbols, errors -def check_data_line(data_line, file_path, i): +def check_data_line(data_line: str, file_path: str, i: int) -> Tuple[List[str], str]: """ check values of data file's line """ - messages = [] - date = None + messages: List[str] = [] + date: str = None if data_line.startswith("#"): messages.append(F'{file_path} has comment in line {i}') return messages, date @@ -136,18 +137,27 @@ def check_data_line(data_line, file_path, i): if len(vals) != 6: # YYYYMMDDT, o, h, l, c, v messages.append(F'{file_path}:{i} contains incorrect number of elements (expected: 6, actual: {len(vals)})') return messages, date + + check_ok = True + # validate float try: for val in (vals[i] for i in range(1, 6)): if FLOAT_RE.match(val) is None: raise ValueError + open_price, high_price, low_price, close_price = float(vals[1]), float(vals[2]), float(vals[3]), float(vals[4]) + except ValueError: + check_ok = False + messages.append(F'{file_path}:{i} float values validation error. The float value can\'t be NAN/+INF/-INF') + # validate date + try: if len(vals[0]) != 9: # value '202291T' is considered as correct date 2022/09/01 by datetime.strptime but specification require zero-padded values raise ValueError - open_price, high_price, low_price, close_price = float(vals[1]), float(vals[2]), float(vals[3]), float(vals[4]) _, volume = datetime.strptime(vals[0], '%Y%m%dT'), float(vals[5]) except (ValueError, TypeError): - messages.append(F'{file_path}:{i} contains invalid value types. ' + - 'Types must be: string(YYYYMMDDT), float, float, float, float, float. The float value can\'t be NAN/+INF/-INF') - else: + check_ok = False + messages.append(F'{file_path}:{i} date validation error, date format have to be YYYYMMDDT, for example: 20230101T') + + if check_ok: date = vals[0] if not (open_price <= high_price >= close_price >= low_price <= open_price and high_price >= low_price): messages.append(F'{file_path}:{i} contains invalid OHLC values. Values must comply with the rules: h >= o, h >= l, h >= c, l <= o, l <= c).') @@ -160,7 +170,7 @@ def check_data_line(data_line, file_path, i): return messages, date -def check_datafile(file_path, problems): +def check_datafile(file_path: str, problems: Dict[str, List[Any]]) -> None: """ Check data file """ dates = set() last_date = "" @@ -180,7 +190,7 @@ def check_datafile(file_path, problems): last_date = date dates.add(date) -def check_data_files(sym_file_path, symbols, problems): +def check_data_files(sym_file_path: str, symbols: List[str], problems: Dict[str, List[Any]]) -> None: """ check all files into data/ folder """ sym_set = set(symbols) for file in glob.glob("data/*"): @@ -200,7 +210,7 @@ def check_data_files(sym_file_path, symbols, problems): problems["missed_files"].append(symbol) -def fail(msg): +def fail(msg: str) -> None: """ report about fail and exit with non-zero exit code""" if REPORTS_PATH is None: print(msg) @@ -210,7 +220,7 @@ def fail(msg): sys_exit(0) -def main(): +def main() -> None: """ main routine """ group = getenv("GROUP") if group == "": @@ -224,6 +234,7 @@ def main(): problems["errors"] = sym_errors if len(symbols) > 0: check_data_files(sym_file_path, symbols, problems) + # report warnings if len(problems["missed_files"]) > 0: warning = F'WARNING: the following symbols have no corresponding CSV files in the data folder: {", ".join(problems["missed_files"])}\n' @@ -232,6 +243,7 @@ def main(): else: with open(os.path.join(REPORTS_PATH, "warnings.txt"), "a") as file: file.write(warning) + # report errors if len(problems["errors"]) > 0: problems_list = "\n ".join(problems["errors"]) From 589d09130085018236f1d861492bb2e3e2919fe5 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Fri, 20 Oct 2023 17:52:21 +0300 Subject: [PATCH 05/12] DF-2335: fix bug in float validation --- simple_data_check.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/simple_data_check.py b/simple_data_check.py index b18014d..1d3bfa4 100755 --- a/simple_data_check.py +++ b/simple_data_check.py @@ -144,7 +144,7 @@ def check_data_line(data_line: str, file_path: str, i: int) -> Tuple[List[str], for val in (vals[i] for i in range(1, 6)): if FLOAT_RE.match(val) is None: raise ValueError - open_price, high_price, low_price, close_price = float(vals[1]), float(vals[2]), float(vals[3]), float(vals[4]) + open_price, high_price, low_price, close_price, volume = float(vals[1]), float(vals[2]), float(vals[3]), float(vals[4]), float(vals[5]) except ValueError: check_ok = False messages.append(F'{file_path}:{i} float values validation error. The float value can\'t be NAN/+INF/-INF') @@ -152,7 +152,7 @@ def check_data_line(data_line: str, file_path: str, i: int) -> Tuple[List[str], try: if len(vals[0]) != 9: # value '202291T' is considered as correct date 2022/09/01 by datetime.strptime but specification require zero-padded values raise ValueError - _, volume = datetime.strptime(vals[0], '%Y%m%dT'), float(vals[5]) + _ = datetime.strptime(vals[0], '%Y%m%dT') except (ValueError, TypeError): check_ok = False messages.append(F'{file_path}:{i} date validation error, date format have to be YYYYMMDDT, for example: 20230101T') From 587eb364f342aa6b8920ac3177a142b255108ed1 Mon Sep 17 00:00:00 2001 From: Dmitry Polyakov <147723152+dpoliakov-tv@users.noreply.github.com> Date: Fri, 27 Oct 2023 18:37:46 +0300 Subject: [PATCH 06/12] DF-2472: add check git diff changed files fo GH PR limit (#7) * DF-2472: add check git diff changed files fo GH PR limit --- check_data_and_create_pr.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index 1f88702..327d0c7 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -31,6 +31,7 @@ else fi set -e + # create a new branch for update git checkout master PR_BRANCH_NAME="update_$(git log -n 1 --pretty=format:%H)" From fbc336873deb06dac83a5cd5fd322eeed1d7dabe Mon Sep 17 00:00:00 2001 From: Dmitry Polyakov <147723152+dpoliakov-tv@users.noreply.github.com> Date: Sat, 28 Oct 2023 11:37:55 +0300 Subject: [PATCH 07/12] hotfix: changes compare operator in if statement (#8) --- check_data_and_create_pr.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index 327d0c7..ffdd18b 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -28,6 +28,7 @@ then git branch --no-merged | grep "update_*" | xargs -I % bash -c 'git branch -D %; git push --delete origin %'; else echo "No temporary branch to remove" + fi set -e From 07b157c75e2dc333f7c059d630e42e075e79d326 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Thu, 2 Nov 2023 18:01:38 +0300 Subject: [PATCH 08/12] DF-2455: compress messages to report and warnings files --- simple_data_check.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/simple_data_check.py b/simple_data_check.py index 1d3bfa4..59beb48 100755 --- a/simple_data_check.py +++ b/simple_data_check.py @@ -8,7 +8,6 @@ import glob import json import os -from os import getenv from os.path import exists, isfile from sys import exit as sys_exit, argv from datetime import datetime @@ -22,6 +21,8 @@ DESCRIPTION_RE: Pattern[str] = re_compile(r'^.+$') PRICESCALE_RE: Pattern[str] = re_compile(r'^1(0){0,22}$') REPORTS_PATH: str = argv[1] if len(argv) > 1 else None +MAX_ERRORS_IN_MSG: int = int(os.getenv("MAX_ERRORS_IN_MSG", 50)) # max show errors in console, file or PR message +THRESHOLD_ERR: int = int(os.getenv('THRESHOLD_ERR', 10)) def check_type(values: Any, val_type: type) -> bool: @@ -234,10 +235,15 @@ def main() -> None: problems["errors"] = sym_errors if len(symbols) > 0: check_data_files(sym_file_path, symbols, problems) - + # report warnings - if len(problems["missed_files"]) > 0: - warning = F'WARNING: the following symbols have no corresponding CSV files in the data folder: {", ".join(problems["missed_files"])}\n' + len_problems_missed_files = len(problems["missed_files"]) + if len_problems_missed_files > 0: + if len_problems_missed_files > MAX_ERRORS_IN_MSG + THRESHOLD_ERR: + warning = F'WARNING: the following symbols have no corresponding CSV files in the data folder: {", ".join(problems["missed_files"][:MAX_ERRORS_IN_MSG])} and {len_problems_missed_files - MAX_ERRORS_IN_MSG} other CSV files.\n' + else: + warning = F'WARNING: the following symbols have no corresponding CSV files in the data folder: {", ".join(problems["missed_files"])}\n' + if REPORTS_PATH is None: print(warning) else: @@ -245,9 +251,16 @@ def main() -> None: file.write(warning) # report errors - if len(problems["errors"]) > 0: - problems_list = "\n ".join(problems["errors"]) - fail(F'ERROR: the following issues were found in the repository files:\n {problems_list}\n') + len_problems_errors = len(problems["errors"]) + if len_problems_errors > 0: + if len_problems_errors > MAX_ERRORS_IN_MSG + THRESHOLD_ERR: + problems_list = "\n ".join(problems["errors"][:MAX_ERRORS_IN_MSG]) + error_msg = F'ERROR: the following issues were found in the repository files:\n {problems_list} and {len_problems_errors - MAX_ERRORS_IN_MSG} other errors. \n' + else: + problems_list = "\n ".join(problems["errors"]) + error_msg = F'ERROR: the following issues were found in the repository files:\n {problems_list}\n' + + fail(error_msg) if __name__ == "__main__": From dc2acaca671ce7590554452bea093466a8f6b55f Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Fri, 3 Nov 2023 11:18:43 +0300 Subject: [PATCH 09/12] DF-2455: import fix --- simple_data_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simple_data_check.py b/simple_data_check.py index 59beb48..14e3c88 100755 --- a/simple_data_check.py +++ b/simple_data_check.py @@ -223,7 +223,7 @@ def fail(msg: str) -> None: def main() -> None: """ main routine """ - group = getenv("GROUP") + group = os.getenv("GROUP") if group == "": fail("ERROR: the GROUP environment variable is not set") sym_file_path = F"symbol_info/{group}.json" From 11af4f82973230abcf6eeeacfc37fc5bf4efeaf9 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Thu, 9 Nov 2023 15:44:49 +0300 Subject: [PATCH 10/12] fix counting and removing remote no-merged branches --- check_data_and_create_pr.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index ffdd18b..4aa1f3a 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -18,14 +18,14 @@ set +o pipefail git checkout master git branch --list | cat merged_branches=$(git branch -r --merged | grep "update_*" -c) -nomerged_branches=$(git branch --no-merged | grep "update_*" -c) +nomerged_branches=$(git branch -r --no-merged | grep "update_*" -c) total_branches=$(($merged_branches+$nomerged_branches)) # delete all merged and unmerged remote `update_*` branches if [[ $total_branches > 0 ]] then git branch -r --merged | grep "update_*" | cut -d "/" -f 2 | xargs git push --delete origin - git branch --no-merged | grep "update_*" | xargs -I % bash -c 'git branch -D %; git push --delete origin %'; + git branch -r --no-merged | grep "update_*" | xargs -I % bash -c 'git branch -D %; git push --delete origin %'; else echo "No temporary branch to remove" From 95bc0c31523841824566deb7eceb9e90a1969af6 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Thu, 9 Nov 2023 15:52:42 +0300 Subject: [PATCH 11/12] delete only remote branches --- check_data_and_create_pr.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index 4aa1f3a..d11f100 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -25,7 +25,7 @@ total_branches=$(($merged_branches+$nomerged_branches)) if [[ $total_branches > 0 ]] then git branch -r --merged | grep "update_*" | cut -d "/" -f 2 | xargs git push --delete origin - git branch -r --no-merged | grep "update_*" | xargs -I % bash -c 'git branch -D %; git push --delete origin %'; + git branch -r --no-merged | grep "update_*" | cut -d "/" -f 2| xargs git push --delete origin else echo "No temporary branch to remove" From 1e77d9df688164bc3955062fecf46809e17ab44c Mon Sep 17 00:00:00 2001 From: Dmitriy Kulagin Date: Fri, 17 Nov 2023 18:27:54 +0300 Subject: [PATCH 12/12] DF-2462: remove doubled errors on description field --- simple_data_check.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/simple_data_check.py b/simple_data_check.py index d12bdc7..119b63d 100755 --- a/simple_data_check.py +++ b/simple_data_check.py @@ -20,10 +20,9 @@ SYMBOL_RE: Pattern[str] = re_compile(r'^[_.0-9A-Z]+$') DESCRIPTION_RE: Pattern[str] = re_compile(r'^.+$') PRICESCALE_RE: Pattern[str] = re_compile(r'^1(0){0,22}$') -REPORTS_PATH: str = argv[1] if len(argv) > 1 else None MAX_ERRORS_IN_MSG: int = int(os.getenv("MAX_ERRORS_IN_MSG", 50)) # max show errors in console, file or PR message THRESHOLD_ERR: int = int(os.getenv('THRESHOLD_ERR', 10)) - +REPORTS_PATH: str = argv[1] if len(argv) > 1 else "." def check_type(values: Any, val_type: type) -> bool: @@ -76,7 +75,7 @@ def check_field_data(name: str, values: Any, val_type: type, regexp: Pattern[str else: # "pricescale" errors.append(F'The {sym_file} file contains invalid values for the "pricescale" field. The value should be a power of 10: 1, 10, …, 10000000000000000000000. ' + 'The number of zeros represents the number of decimal places.') - if quantity > 0 and isinstance(values, list) and len(values) != quantity: + if quantity > 0 and (len(values) != quantity if isinstance(values, list) else quantity != 1): errors.append(F'The number of the {name} fields does not match the number of symbols in {sym_file}') return errors @@ -115,18 +114,15 @@ def check_symbol_info(sym_file: str) -> Tuple[List[str], List[str]]: length = len(symbols) if isinstance(symbols, list) else 1 descriptions = sym_data["description"] errors += check_field_data("description", descriptions, str, DESCRIPTION_RE, 128, length, sym_file) - desc_length = len(descriptions) if isinstance(descriptions, list) else 1 - if desc_length != length: # strictly check descriptions length - errors.append(F'The number of symbol descriptions does not match the number of symbols in {sym_file}') pricescale = sym_data["pricescale"] errors += check_field_data("pricescale", pricescale, int, PRICESCALE_RE, 0, length, sym_file) return symbols, errors -def check_data_line(data_line: str, file_path: str, i: int) -> Tuple[List[str], str]: +def check_data_line(data_line: str, file_path: str, i: int) -> Tuple[List[str], str|None]: """ check values of data file's line """ messages: List[str] = [] - date: str = None + date = None if data_line.startswith("#"): messages.append(F'{file_path} has comment in line {i}') return messages, date @@ -142,6 +138,7 @@ def check_data_line(data_line: str, file_path: str, i: int) -> Tuple[List[str], check_ok = True # validate float + open_price, high_price, low_price, close_price, volume = 0.0, 0.0, 0.0, 0.0, 0.0 try: for val in (vals[i] for i in range(1, 6)): if FLOAT_RE.match(val) is None: