Skip to content

Commit

Permalink
package: Add online updates for explanations
Browse files Browse the repository at this point in the history
  • Loading branch information
BorysekOndrej committed Sep 17, 2023
1 parent 3bb4057 commit 38fe1b0
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 3 deletions.
2 changes: 1 addition & 1 deletion edulint/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@
"get_explanations",
]

__version__ = "3.2.1"
__version__ = "3.3.0"
__version_info__ = tuple(map(int, __version__.split(".")))
8 changes: 8 additions & 0 deletions edulint/edulint.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from edulint.linting.problem import Problem
from edulint.linting.linting import lint_many, sort, EduLintLinterFailedException
from edulint.versions.version_checker import PackageInfoManager
from edulint.explanations import update_explanations
from typing import List, Optional, Dict, Tuple, Any
import argparse
import os
Expand Down Expand Up @@ -80,6 +81,12 @@ def setup_argparse(option_parses: Dict[Option, OptionParse]) -> argparse.Namespa
default=False,
help="EduLint checks for a newer version at most once per hour. If newer version is available in pip it will print a message to stderr. Specifying this flag disables the check completely.",
)
parser.add_argument(
"--disable-explanations-update",
action='store_true',
default=False,
help="EduLint periodically updates explanations. Specifying this flag disables the updates.",
)
return parser.parse_args()


Expand Down Expand Up @@ -129,6 +136,7 @@ def main() -> int:
option_parses = get_option_parses()
args = setup_argparse(option_parses)
check_for_updates(args.disable_version_check)
update_explanations(args.disable_explanations_update)
cmd_args = get_cmd_args(args)

files = extract_files(args.files_or_dirs)
Expand Down
60 changes: 58 additions & 2 deletions edulint/explanations.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,74 @@
from typing import Dict
import os
from threading import Thread
from pathlib import Path
from typing import Optional, Dict
import dbm
import time

import tomli
import requests
from platformdirs import PlatformDirs
from loguru import logger


SCRIPT_PATH = os.path.dirname(os.path.abspath(__file__))
EXPLANATIONS_FILENAME = os.path.join(SCRIPT_PATH, "explanations.toml")
EXPLANATIONS_PIP_DISTRIBUTED_FILEPATH = os.path.join(SCRIPT_PATH, "explanations.toml")

EXPLANATIONS_ONLINE_DISTRIBUTED_FILEPATH = os.path.join(PlatformDirs(appname="edulint").user_data_dir, "explanations_online.toml")
EXPLANATIONS_DBM = os.path.join(PlatformDirs(appname="edulint").user_data_dir, "explanations.dbm")
GITHUB_URL = "https://raw.githubusercontent.com/GiraffeReversed/edulint/main/edulint/explanations.toml"


# --- Read explanations
def get_explanations() -> Dict[str, Dict[str, str]]:
with open(EXPLANATIONS_FILENAME, "rb") as f:
updated_explanations = _load_updated_explanations()
if updated_explanations:
return updated_explanations

with open(EXPLANATIONS_PIP_DISTRIBUTED_FILEPATH, "rb") as f:
parsed_toml = tomli.load(f)
return parsed_toml


def _load_updated_explanations() -> Optional[Dict[str, str]]:
path_for_online_file = Path(EXPLANATIONS_ONLINE_DISTRIBUTED_FILEPATH)
if not path_for_online_file.exists():
return
try:
with open(EXPLANATIONS_PIP_DISTRIBUTED_FILEPATH, "rb") as f:
return tomli.load(f)
except:
logger.warning("Updated explanations seem to be corrupted. Falling back to those distributed with the pip package.")


# --- Update explanation
def current_timestamp() -> int:
return int(time.time())


def update_explanations(disable_explanations_update: bool = False):
if disable_explanations_update:
return
Thread(target=_thread_update_explanations).start()


def _thread_update_explanations(ttl: int = 600):
with dbm.open(EXPLANATIONS_DBM, 'c') as db:
if current_timestamp() < int(db.get('last_update', b'0')) + ttl:
return
db['last_update'] = str(current_timestamp()) # We're counting any update attempt, not just the succesfull ones

try:
resp = requests.get(GITHUB_URL, timeout=3)
if resp.status_code != 200:
return

with open(EXPLANATIONS_ONLINE_DISTRIBUTED_FILEPATH, "w", encoding="utf8") as f:
f.write(resp.text)
except Exception as e:
logger.debug("Update of explanations failed with {e}.")

# todo: add test to load explanantions (toml parser is sensitive to small mistakes)

if __name__ == "__main__":
Expand Down

0 comments on commit 38fe1b0

Please sign in to comment.