1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-06-09 20:02:11 +03:00

Merge pull request #2094 from HullSeals/enhancement/2051/docs-workflows-utils

[2051] Utilities, Scripts, Workflow Audits
LGTM
This commit is contained in:
Phoebe 2023-11-17 01:49:45 +01:00 committed by GitHub
commit 27dba61ba0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 104 additions and 110 deletions

View File

@ -103,18 +103,11 @@ jobs:
pip install wheel pip install wheel
pip install -r requirements-dev.txt pip install -r requirements-dev.txt
- name: Download latest WinSparkle release - name: Download winsparkle
run: | run: |
$url = "https://api.github.com/repos/vslavik/winsparkle/releases/latest" Invoke-Webrequest -UseBasicParsing https://github.com/vslavik/winsparkle/releases/download/v0.8.0/WinSparkle-0.8.0.zip -OutFile out.zip
$response = Invoke-RestMethod -Uri $url Expand-Archive out.zip
$latestAsset = $response.assets | Where-Object { $_.name -match "WinSparkle.*\.zip" -and $_.name -notmatch "-src" } Move-Item 'out\WinSparkle-0.8.0\Release\*' '.\'
$downloadUrl = $latestAsset.browser_download_url
Invoke-WebRequest -Uri $downloadUrl -OutFile WinSparkle-Latest.zip
Expand-Archive -Path WinSparkle-Latest.zip -DestinationPath .
$extractedFolder = Get-ChildItem -Filter "WinSparkle-*" -Directory
Move-Item -Path "$($extractedFolder.FullName)\Release\*" -Destination .
- name: Build EDMC - name: Build EDMC
run: | run: |

View File

@ -79,7 +79,7 @@ class ClickCounter:
""" """
# You need to cast to `int` here to store *as* an `int`, so that # You need to cast to `int` here to store *as* an `int`, so that
# `config.get_int()` will work for re-loading the value. # `config.get_int()` will work for re-loading the value.
config.set('click_counter_count', int(self.click_count.get())) # type: ignore config.set('click_counter_count', int(self.click_count.get()))
def setup_main_ui(self, parent: tk.Frame) -> tk.Frame: def setup_main_ui(self, parent: tk.Frame) -> tk.Frame:
""" """
@ -95,7 +95,7 @@ class ClickCounter:
button = tk.Button( button = tk.Button(
frame, frame,
text="Count me", text="Count me",
command=lambda: self.click_count.set(str(int(self.click_count.get()) + 1)) # type: ignore command=lambda: self.click_count.set(str(int(self.click_count.get()) + 1))
) )
button.grid(row=current_row) button.grid(row=current_row)
current_row += 1 current_row += 1

View File

@ -44,7 +44,7 @@ class This:
this = This() this = This()
class PluginTest(object): class PluginTest:
"""Class that performs actual tests on bundled modules.""" """Class that performs actual tests on bundled modules."""
def __init__(self, directory: str): def __init__(self, directory: str):
@ -83,7 +83,6 @@ class PluginTest(object):
logger.debug(f'timestamp = "{timestamp}", cmdr = "{cmdrname}", system = "{system}", station = "{station}", event = "{event}"') # noqa: E501 logger.debug(f'timestamp = "{timestamp}", cmdr = "{cmdrname}", system = "{system}", station = "{station}", event = "{event}"') # noqa: E501
self.sqlc.execute('INSERT INTO entries VALUES(?, ?, ?, ?, ?)', (timestamp, cmdrname, system, station, event)) self.sqlc.execute('INSERT INTO entries VALUES(?, ?, ?, ?, ?)', (timestamp, cmdrname, system, station, event))
self.sqlconn.commit() self.sqlconn.commit()
return None
def plugin_start3(plugin_dir: str) -> str: def plugin_start3(plugin_dir: str) -> str:

View File

@ -309,7 +309,7 @@ def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> tk.Fr
this.log = tk.IntVar(value=config.get_int('edsm_out') and 1) this.log = tk.IntVar(value=config.get_int('edsm_out') and 1)
this.log_button = nb.Checkbutton( this.log_button = nb.Checkbutton(
frame, frame,
text=_('Send flight log and Cmdr status to EDSM'), text=_('Send flight log and CMDR status to EDSM'), # LANG: Send flight log and CMDR Status to EDSM
variable=this.log, variable=this.log,
command=prefsvarchanged command=prefsvarchanged
) )
@ -320,7 +320,7 @@ def plugin_prefs(parent: ttk.Notebook, cmdr: str | None, is_beta: bool) -> tk.Fr
this.label = HyperlinkLabel( this.label = HyperlinkLabel(
frame, frame,
text=_('Elite Dangerous Star Map credentials'), text=_('Elite Dangerous Star Map credentials'), # LANG: Elite Dangerous Star Map credentials
background=nb.Label().cget('background'), background=nb.Label().cget('background'),
url='https://www.edsm.net/settings/api', url='https://www.edsm.net/settings/api',
underline=True underline=True

View File

@ -18,24 +18,24 @@ flake8-noqa==1.3.2
flake8-polyfill==1.0.2 flake8-polyfill==1.0.2
flake8-use-fstring==1.4 flake8-use-fstring==1.4
mypy==1.6.1 mypy==1.7.0
pep8-naming==0.13.3 pep8-naming==0.13.3
safety==2.3.5 safety==2.3.5
types-requests==2.31.0.2 types-requests==2.31.0.10
types-pkg-resources==0.1.3 types-pkg-resources==0.1.3
# Code formatting tools # Code formatting tools
autopep8==2.0.4 autopep8==2.0.4
# Git pre-commit checking # Git pre-commit checking
pre-commit==3.3.3 pre-commit==3.5.0
# HTML changelogs # HTML changelogs
grip==4.6.1 grip==4.6.2
# Packaging # Packaging
# We only need py2exe on windows. # We only need py2exe on windows.
py2exe==0.13.0.0; sys_platform == 'win32' py2exe==0.13.0.1; sys_platform == 'win32'
# Testing # Testing
pytest==7.4.3 pytest==7.4.3

View File

@ -1,4 +1,6 @@
"""Search all given paths recursively for localised string calls.""" """Search all given paths recursively for localised string calls."""
from __future__ import annotations
import argparse import argparse
import ast import ast
import dataclasses import dataclasses
@ -6,9 +8,6 @@ import json
import pathlib import pathlib
import re import re
import sys import sys
from typing import Optional
# spell-checker: words dedupe deduping deduped
def get_func_name(thing: ast.AST) -> str: def get_func_name(thing: ast.AST) -> str:
@ -16,11 +15,9 @@ def get_func_name(thing: ast.AST) -> str:
if isinstance(thing, ast.Name): if isinstance(thing, ast.Name):
return thing.id return thing.id
elif isinstance(thing, ast.Attribute): if isinstance(thing, ast.Attribute):
return get_func_name(thing.value) return get_func_name(thing.value)
return ''
else:
return ''
def get_arg(call: ast.Call) -> str: def get_arg(call: ast.Call) -> str:
@ -31,10 +28,9 @@ def get_arg(call: ast.Call) -> str:
arg = call.args[0] arg = call.args[0]
if isinstance(arg, ast.Constant): if isinstance(arg, ast.Constant):
return arg.value return arg.value
elif isinstance(arg, ast.Name): if isinstance(arg, ast.Name):
return f'VARIABLE! CHECK CODE! {arg.id}' return f'VARIABLE! CHECK CODE! {arg.id}'
else: return f'Unknown! {type(arg)=} {ast.dump(arg)} ||| {ast.unparse(arg)}'
return f'Unknown! {type(arg)=} {ast.dump(arg)} ||| {ast.unparse(arg)}'
def find_calls_in_stmt(statement: ast.AST) -> list[ast.Call]: def find_calls_in_stmt(statement: ast.AST) -> list[ast.Call]:
@ -43,9 +39,7 @@ def find_calls_in_stmt(statement: ast.AST) -> list[ast.Call]:
for n in ast.iter_child_nodes(statement): for n in ast.iter_child_nodes(statement):
out.extend(find_calls_in_stmt(n)) out.extend(find_calls_in_stmt(n))
if isinstance(statement, ast.Call) and get_func_name(statement.func) == '_': if isinstance(statement, ast.Call) and get_func_name(statement.func) == '_':
out.append(statement) out.append(statement)
return out return out
@ -62,7 +56,7 @@ COMMENT_SAME_LINE_RE = re.compile(r'^.*?(#.*)$')
COMMENT_OWN_LINE_RE = re.compile(r'^\s*?(#.*)$') COMMENT_OWN_LINE_RE = re.compile(r'^\s*?(#.*)$')
def extract_comments(call: ast.Call, lines: list[str], file: pathlib.Path) -> Optional[str]: # noqa: CCR001 def extract_comments(call: ast.Call, lines: list[str], file: pathlib.Path) -> str | None: # noqa: CCR001
""" """
Extract comments from source code based on the given call. Extract comments from source code based on the given call.
@ -74,16 +68,16 @@ def extract_comments(call: ast.Call, lines: list[str], file: pathlib.Path) -> Op
:param file: The path to the file this call node came from :param file: The path to the file this call node came from
:return: The first comment that matches the rules, or None :return: The first comment that matches the rules, or None
""" """
out: Optional[str] = None out: str | None = None
above = call.lineno - 2 above = call.lineno - 2
current = call.lineno - 1 current = call.lineno - 1
above_line = lines[above].strip() if len(lines) >= above else None above_line = lines[above].strip() if len(lines) >= above else None
above_comment: Optional[str] = None above_comment: str | None = None
current_line = lines[current].strip() current_line = lines[current].strip()
current_comment: Optional[str] = None current_comment: str | None = None
bad_comment: Optional[str] = None bad_comment: str | None = None
if above_line is not None: if above_line is not None:
match = COMMENT_OWN_LINE_RE.match(above_line) match = COMMENT_OWN_LINE_RE.match(above_line)
if match: if match:
@ -108,16 +102,13 @@ def extract_comments(call: ast.Call, lines: list[str], file: pathlib.Path) -> Op
if current_comment is not None: if current_comment is not None:
out = current_comment out = current_comment
elif above_comment is not None: elif above_comment is not None:
out = above_comment out = above_comment
elif bad_comment is not None: elif bad_comment is not None:
print(bad_comment, file=sys.stderr) print(bad_comment, file=sys.stderr)
if out is None: if out is None:
print(f'No comment for {file}:{call.lineno} {current_line}', file=sys.stderr) print(f'No comment for {file}:{call.lineno} {current_line}', file=sys.stderr)
return out return out
@ -146,22 +137,17 @@ def scan_directory(path: pathlib.Path, skip: list[pathlib.Path] | None = None) -
:param path: path to scan :param path: path to scan
:param skip: paths to skip, if any, defaults to None :param skip: paths to skip, if any, defaults to None
""" """
if skip is None:
skip = []
out = {} out = {}
for thing in path.iterdir(): for thing in path.iterdir():
if skip is not None and any(s.name == thing.name for s in skip): if any(same_path.name == thing.name for same_path in skip):
continue continue
if thing.is_file(): if thing.is_file() and thing.suffix == '.py':
if not thing.name.endswith('.py'):
continue
out[thing] = scan_file(thing) out[thing] = scan_file(thing)
elif thing.is_dir(): elif thing.is_dir():
out |= scan_directory(thing) out.update(scan_directory(thing, skip))
else:
raise ValueError(type(thing), thing)
return out return out
@ -174,14 +160,13 @@ def parse_template(path) -> set[str]:
:param path: The path to the lang file :param path: The path to the lang file
""" """
lang_re = re.compile(r'\s*"((?:[^"]|(?:\"))+)"\s*=\s*"((?:[^"]|(?:\"))+)"\s*;\s*$') lang_re = re.compile(r'\s*"([^"]+)"\s*=\s*"([^"]+)"\s*;\s*$')
out = set() out = set()
for line in pathlib.Path(path).read_text(encoding='utf-8').splitlines(): with open(path, encoding='utf-8') as file:
match = lang_re.match(line) for line in file:
if not match: match = lang_re.match(line.strip())
continue if match and match.group(1) != '!Language':
if match.group(1) != '!Language': out.add(match.group(1))
out.add(match.group(1))
return out return out
@ -193,8 +178,8 @@ class FileLocation:
path: pathlib.Path path: pathlib.Path
line_start: int line_start: int
line_start_col: int line_start_col: int
line_end: Optional[int] line_end: int | None
line_end_col: Optional[int] line_end_col: int | None
@staticmethod @staticmethod
def from_call(path: pathlib.Path, c: ast.Call) -> 'FileLocation': def from_call(path: pathlib.Path, c: ast.Call) -> 'FileLocation':
@ -213,18 +198,15 @@ class LangEntry:
locations: list[FileLocation] locations: list[FileLocation]
string: str string: str
comments: list[Optional[str]] comments: list[str | None]
def files(self) -> str: def files(self) -> str:
"""Return a string representation of all the files this LangEntry is in, and its location therein.""" """Return a string representation of all the files this LangEntry is in, and its location therein."""
out = '' file_locations = [
for loc in self.locations: f"{loc.path.name}:{loc.line_start}:{loc.line_end or ''}"
start = loc.line_start for loc in self.locations
end = loc.line_end ]
end_str = f':{end}' if end is not None and end != start else '' return "; ".join(file_locations)
out += f'{loc.path.name}:{start}{end_str}; '
return out
def dedupe_lang_entries(entries: list[LangEntry]) -> list[LangEntry]: def dedupe_lang_entries(entries: list[LangEntry]) -> list[LangEntry]:
@ -237,21 +219,17 @@ def dedupe_lang_entries(entries: list[LangEntry]) -> list[LangEntry]:
:param entries: The list to deduplicate :param entries: The list to deduplicate
:return: The deduplicated list :return: The deduplicated list
""" """
deduped: list[LangEntry] = [] deduped: dict[str, LangEntry] = {}
for e in entries: for e in entries:
cont = False existing = deduped.get(e.string)
for d in deduped: if existing:
if d.string == e.string: existing.locations.extend(e.locations)
cont = True existing.comments.extend(e.comments)
d.locations.append(e.locations[0]) else:
d.comments.extend(e.comments) deduped[e.string] = LangEntry(
locations=e.locations[:], string=e.string, comments=e.comments[:]
if cont: )
continue return list(deduped.values())
deduped.append(e)
return deduped
def generate_lang_template(data: dict[pathlib.Path, list[ast.Call]]) -> str: def generate_lang_template(data: dict[pathlib.Path, list[ast.Call]]) -> str:
@ -269,23 +247,19 @@ def generate_lang_template(data: dict[pathlib.Path, list[ast.Call]]) -> str:
print(f'Done Deduping entries {len(entries)=} {len(deduped)=}', file=sys.stderr) print(f'Done Deduping entries {len(entries)=} {len(deduped)=}', file=sys.stderr)
for entry in deduped: for entry in deduped:
assert len(entry.comments) == len(entry.locations) assert len(entry.comments) == len(entry.locations)
comment = ''
comment_set = set()
for comment, loc in zip(entry.comments, entry.locations):
if comment:
comment_set.add(f'{loc.path.name}: {comment};')
files = 'In files: ' + entry.files() files = 'In files: ' + entry.files()
comment = ' '.join(comment_set).strip()
header = f'{comment} {files}'.strip()
string = f'"{entry.string}"' string = f'"{entry.string}"'
for i in range(len(entry.comments)):
if entry.comments[i] is None:
continue
loc = entry.locations[i]
to_append = f'{loc.path.name}: {entry.comments[i]}; '
if to_append not in comment:
comment += to_append
header = f'{comment.strip()} {files}'.strip()
out += f'/* {header} */\n' out += f'/* {header} */\n'
out += f'{string} = {string};\n' out += f'{string} = {string};\n\n'
out += '\n'
return out return out

View File

@ -116,9 +116,14 @@ if __name__ == '__main__':
if file_name == '-': if file_name == '-':
file = sys.stdin file = sys.stdin
else: else:
file = open(file_name) try:
with open(file_name) as file:
res = json.load(file) res = json.load(file)
file.close() except FileNotFoundError:
print(f"File '{file_name}' not found.")
sys.exit(1)
except json.JSONDecodeError:
print(f"Error decoding JSON in '{file_name}'.")
sys.exit(1)
show_killswitch_set_info(KillSwitchSet(parse_kill_switches(res))) show_killswitch_set_info(KillSwitchSet(parse_kill_switches(res)))

View File

@ -1,11 +1,10 @@
#!/usr/bin/env python """Search for dependencies given a package."""
"""Find the reverse dependencies of a package according to pip."""
import sys import sys
import pkg_resources import pkg_resources
def find_reverse_deps(package_name: str): def find_reverse_deps(package_name: str) -> list[str]:
""" """
Find the packages that depend on the named one. Find the packages that depend on the named one.
@ -19,4 +18,16 @@ def find_reverse_deps(package_name: str):
if __name__ == '__main__': if __name__ == '__main__':
print(find_reverse_deps(sys.argv[1])) if len(sys.argv) != 2:
print("Usage: python reverse_deps.py <package_name>")
sys.exit(1)
package_name = sys.argv[1]
reverse_deps = find_reverse_deps(package_name)
if reverse_deps:
print(f"Reverse dependencies of '{package_name}':")
for dep in reverse_deps:
print(dep)
else:
print(f"No reverse dependencies found for '{package_name}'.")

View File

@ -1,4 +1,10 @@
"""Utilities for dealing with text (and byte representations thereof).""" """
text.py - Dealing with Text and Bytes.
Copyright (c) EDCD, All Rights Reserved
Licensed under the GNU General Public License.
See LICENSE file.
"""
from __future__ import annotations from __future__ import annotations
from gzip import compress from gzip import compress

View File

@ -1,4 +1,10 @@
"""Utility functions relating to ships.""" """
util_ships.py - Ship Utilities.
Copyright (c) EDCD, All Rights Reserved
Licensed under the GNU General Public License.
See LICENSE file.
"""
from edmc_data import ship_name_map from edmc_data import ship_name_map
@ -11,6 +17,6 @@ def ship_file_name(ship_name: str, ship_type: str) -> str:
if name.lower() in ('con', 'prn', 'aux', 'nul', if name.lower() in ('con', 'prn', 'aux', 'nul',
'com0', 'com2', 'com3', 'com4', 'com5', 'com6', 'com7', 'com8', 'com9', 'com0', 'com2', 'com3', 'com4', 'com5', 'com6', 'com7', 'com8', 'com9',
'lpt0', 'lpt2', 'lpt3', 'lpt4', 'lpt5', 'lpt6', 'lpt7', 'lpt8', 'lpt9'): 'lpt0', 'lpt2', 'lpt3', 'lpt4', 'lpt5', 'lpt6', 'lpt7', 'lpt8', 'lpt9'):
name = name + '_' name += '_'
return name.translate({ord(x): u'_' for x in ('\0', '<', '>', ':', '"', '/', '\\', '|', '?', '*')}) return name.translate({ord(x): '_' for x in ('\0', '<', '>', ':', '"', '/', '\\', '|', '?', '*')})