Add pre-commit to automatically run formatting when committing

This commit is contained in:
Vincent Emonet 2023-07-23 13:24:15 +02:00
parent 7d07967574
commit 25168ba6e1
14 changed files with 74 additions and 34 deletions

28
.pre-commit-config.yaml Normal file
View file

@ -0,0 +1,28 @@
# See https://pre-commit.com for more information
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: check-added-large-files
name: " 🐘 Check for added large files"
- id: check-toml
name: " ✔️ Check TOML"
- id: check-yaml
name: " ✔️ Check YAML"
args:
- --unsafe
- id: check-json
name: " ✔️ Check JSON"
- id: trailing-whitespace
name: " ✂️ Trim trailing whitespaces"
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.277
hooks:
- id: ruff
name: " ⚡️ Formatting code with Ruff"
args:
- --fix
ci:
autofix_commit_msg: 🎨 [pre-commit] Auto format
autoupdate_commit_msg: ⬆ [pre-commit] pre-commit auto update

View file

@ -33,6 +33,8 @@ git clone https://github.com/LibreTranslate/LibreTranslate.git
cd LibreTranslate cd LibreTranslate
``` ```
Hatch will automatically install the required dependencies in a virtual environment, and enable [`pre-commit`](https://pre-commit.com/), which will run before each commit to run formatting.
Run in development: Run in development:
```bash ```bash
@ -72,6 +74,12 @@ You can also run the tests on multiple python versions:
hatch run all:test hatch run all:test
``` ```
You can clean the virtual environment with:
```bash
hatch env prune
```
## Run with Docker ## Run with Docker
Linux/macOS: `./run.sh [args]` Linux/macOS: `./run.sh [args]`
@ -125,4 +133,4 @@ This occurs when your operating system depends on and manages Python for core fu
This prevents pip packages from being installed system-wide. This way, there are no risks of pip packages conflicting between multiple projects or the operating system. This prevents pip packages from being installed system-wide. This way, there are no risks of pip packages conflicting between multiple projects or the operating system.
References: References:
* [Python venv documentation](https://docs.python.org/library/venv.html) * [Python venv documentation](https://docs.python.org/library/venv.html)

View file

@ -1,4 +1,4 @@
# kubernetes deployment template # kubernetes deployment template
# prepare a namespace on your cluster first like libretranslate-prod # prepare a namespace on your cluster first like libretranslate-prod
apiVersion: v1 apiVersion: v1
kind: ConfigMap kind: ConfigMap
@ -41,7 +41,7 @@ spec:
valueFrom: valueFrom:
configMapKeyRef: configMapKeyRef:
name: libretranslate-config name: libretranslate-config
key: ltapikey key: ltapikey
--- ---
apiVersion: v1 apiVersion: v1
kind: Service kind: Service

View file

@ -170,7 +170,7 @@ _default_options_objects = [
'name': 'UPDATE_MODELS', 'name': 'UPDATE_MODELS',
'default_value': False, 'default_value': False,
'value_type': 'bool' 'value_type': 'bool'
}, },
{ {
'name': 'METRICS', 'name': 'METRICS',
'default_value': False, 'default_value': False,

View file

@ -44,7 +44,7 @@ def get_alternate_locale_links():
tmpl = os.environ.get("LT_LOCALE_LINK_TEMPLATE") tmpl = os.environ.get("LT_LOCALE_LINK_TEMPLATE")
if tmpl is None: if tmpl is None:
return [] return []
locales = get_available_locale_codes() locales = get_available_locale_codes()
result = [] result = []
for l in locales: for l in locales:

View file

@ -8,6 +8,6 @@ class Limiter:
return f(*args, **kwargs) return f(*args, **kwargs)
return wrapper return wrapper
def init_app(self, app): def init_app(self, app):
pass pass

View file

@ -18,7 +18,7 @@ def setup(args):
if args.api_keys and args.require_api_key_secret: if args.api_keys and args.require_api_key_secret:
scheduler.add_job(func=rotate_secrets, trigger="interval", minutes=30) scheduler.add_job(func=rotate_secrets, trigger="interval", minutes=30)
scheduler.start() scheduler.start()
# Shut down the scheduler when exiting the app # Shut down the scheduler when exiting the app

View file

@ -12,7 +12,7 @@ def rotate_secrets():
secret_1 = s.get_str("secret_1") secret_1 = s.get_str("secret_1")
s.set_str("secret_0", secret_1) s.set_str("secret_0", secret_1)
s.set_str("secret_1", generate_secret()) s.set_str("secret_1", generate_secret())
def secret_match(secret): def secret_match(secret):
s = get_storage() s = get_storage()

View file

@ -31,22 +31,22 @@ class Storage:
raise Exception("not implemented") raise Exception("not implemented")
def dec_hash_int(self, ns, key): def dec_hash_int(self, ns, key):
raise Exception("not implemented") raise Exception("not implemented")
def get_hash_keys(self, ns): def get_hash_keys(self, ns):
raise Exception("not implemented") raise Exception("not implemented")
def del_hash(self, ns, key): def del_hash(self, ns, key):
raise Exception("not implemented") raise Exception("not implemented")
class MemoryStorage(Storage): class MemoryStorage(Storage):
def __init__(self): def __init__(self):
self.store = {} self.store = {}
def exists(self, key): def exists(self, key):
return key in self.store return key in self.store
def set_bool(self, key, value): def set_bool(self, key, value):
self.store[key] = bool(value) self.store[key] = bool(value)
def get_bool(self, key): def get_bool(self, key):
return bool(self.store[key]) return bool(self.store[key])
@ -55,10 +55,10 @@ class MemoryStorage(Storage):
def get_int(self, key): def get_int(self, key):
return int(self.store.get(key, 0)) return int(self.store.get(key, 0))
def set_str(self, key, value): def set_str(self, key, value):
self.store[key] = value self.store[key] = value
def get_str(self, key): def get_str(self, key):
return str(self.store.get(key, "")) return str(self.store.get(key, ""))
@ -74,7 +74,7 @@ class MemoryStorage(Storage):
def inc_hash_int(self, ns, key): def inc_hash_int(self, ns, key):
if ns not in self.store: if ns not in self.store:
self.store[ns] = {} self.store[ns] = {}
if key not in self.store[ns]: if key not in self.store[ns]:
self.store[ns][key] = 0 self.store[ns][key] = 0
else: else:
@ -83,7 +83,7 @@ class MemoryStorage(Storage):
def dec_hash_int(self, ns, key): def dec_hash_int(self, ns, key):
if ns not in self.store: if ns not in self.store:
self.store[ns] = {} self.store[ns] = {}
if key not in self.store[ns]: if key not in self.store[ns]:
self.store[ns][key] = 0 self.store[ns][key] = 0
else: else:
@ -103,13 +103,13 @@ class RedisStorage(Storage):
def __init__(self, redis_uri): def __init__(self, redis_uri):
self.conn = redis.from_url(redis_uri) self.conn = redis.from_url(redis_uri)
self.conn.ping() self.conn.ping()
def exists(self, key): def exists(self, key):
return bool(self.conn.exists(key)) return bool(self.conn.exists(key))
def set_bool(self, key, value): def set_bool(self, key, value):
self.conn.set(key, "1" if value else "0") self.conn.set(key, "1" if value else "0")
def get_bool(self, key): def get_bool(self, key):
return bool(self.conn.get(key)) return bool(self.conn.get(key))
@ -122,24 +122,24 @@ class RedisStorage(Storage):
return 0 return 0
else: else:
return v return v
def set_str(self, key, value): def set_str(self, key, value):
self.conn.set(key, value) self.conn.set(key, value)
def get_str(self, key): def get_str(self, key):
v = self.conn.get(key) v = self.conn.get(key)
if v is None: if v is None:
return "" return ""
else: else:
return v.decode('utf-8') return v.decode('utf-8')
def get_hash_int(self, ns, key): def get_hash_int(self, ns, key):
v = self.conn.hget(ns, key) v = self.conn.hget(ns, key)
if v is None: if v is None:
return 0 return 0
else: else:
return int(v) return int(v)
def set_hash_int(self, ns, key, value): def set_hash_int(self, ns, key, value):
self.conn.hset(ns, key, value) self.conn.hset(ns, key, value)

View file

@ -65,7 +65,7 @@ ltmanage = "libretranslate.manage:manage"
test = [ test = [
"pytest >=7.2.0", "pytest >=7.2.0",
"pytest-cov", "pytest-cov",
"ruff ==0.0.277", "pre-commit >=3.0.0",
"types-requests", "types-requests",
] ]
@ -83,13 +83,16 @@ History = "https://github.com/LibreTranslate/LibreTranslate/releases"
features = [ features = [
"test", "test",
] ]
post-install-commands = [
"pre-commit install",
]
[tool.hatch.envs.default.scripts] [tool.hatch.envs.default.scripts]
dev = "python main.py {args}" dev = "python main.py {args}"
locales = "python scripts/compile_locales.py" locales = "python scripts/compile_locales.py"
fmt = [ fmt = [
"ruff libretranslate scripts --fix", "pre-commit run --all --all-files",
] ]
test = [ test = [
"fmt", "fmt",

View file

@ -36,7 +36,7 @@ def on_starting(server):
sys.argv.append(kwargs[k]) sys.argv.append(kwargs[k])
args = get_args() args = get_args()
from libretranslate import flood, scheduler, secret, storage from libretranslate import flood, scheduler, secret, storage
storage.setup(args.shared_storage) storage.setup(args.shared_storage)
scheduler.setup(args) scheduler.setup(args)

View file

@ -25,19 +25,19 @@ if __name__ == "__main__":
con = sqlite3.connect(args.db, check_same_thread=False) con = sqlite3.connect(args.db, check_same_thread=False)
cur = con.cursor() cur = con.cursor()
with open(output_file, 'w', encoding="utf-8") as f: with open(output_file, 'w', encoding="utf-8") as f:
for row in cur.execute('SELECT q, s, source, target FROM suggestions WHERE source != "auto" ORDER BY source'): for row in cur.execute('SELECT q, s, source, target FROM suggestions WHERE source != "auto" ORDER BY source'):
q, s, source, target = row q, s, source, target = row
obj = { obj = {
'q': q, 'q': q,
's': s, 's': s,
'source': source, 'source': source,
'target': target 'target': target
} }
json.dump(obj, f, ensure_ascii=False) json.dump(obj, f, ensure_ascii=False)
f.write('\n') f.write('\n')
print("Wrote %s" % output_file) print("Wrote %s" % output_file)
if args.clear: if args.clear:

View file

@ -54,7 +54,7 @@ if __name__ == "__main__":
messagespot = os.path.join(locales_dir, "messages.pot") messagespot = os.path.join(locales_dir, "messages.pot")
print("Updating %s" % messagespot) print("Updating %s" % messagespot)
sys.argv = ["", "extract", "-F", "babel.cfg", "-k", "_e _h", sys.argv = ["", "extract", "-F", "babel.cfg", "-k", "_e _h",
"--copyright-holder", "LibreTranslate Authors", "--copyright-holder", "LibreTranslate Authors",
"--project", "LibreTranslate", "--project", "LibreTranslate",
"--version", get_version(), "--version", get_version(),
@ -80,7 +80,7 @@ if __name__ == "__main__":
'reviewed': False 'reviewed': False
}, indent=4)) }, indent=4))
print("Wrote %s" % meta_file) print("Wrote %s" % meta_file)
# Automatically translate strings with libretranslate # Automatically translate strings with libretranslate
# when a language model is available and a string is empty # when a language model is available and a string is empty
@ -103,10 +103,10 @@ if __name__ == "__main__":
print("Translating '%s'" % locale) print("Translating '%s'" % locale)
pofile = polib.pofile(messages_file) pofile = polib.pofile(messages_file)
c = 0 c = 0
for entry in pofile.untranslated_entries(): for entry in pofile.untranslated_entries():
text = entry.msgid text = entry.msgid
# Extract placeholders # Extract placeholders
placeholders = re.findall(r'%\(?[^\)]*\)?s', text) placeholders = re.findall(r'%\(?[^\)]*\)?s', text)
@ -126,11 +126,11 @@ if __name__ == "__main__":
else: else:
# Meh, append # Meh, append
translated += " " + placeholders[p] translated += " " + placeholders[p]
print(entry.msgid, " --> ", translated) print(entry.msgid, " --> ", translated)
entry.msgstr = translated entry.msgstr = translated
c += 1 c += 1
if c > 0: if c > 0:
pofile.save(messages_file) pofile.save(messages_file)
print("Saved %s" % messages_file) print("Saved %s" % messages_file)

View file

@ -1,5 +1,6 @@
from libretranslate import main from libretranslate import main
def app(*args, **kwargs): def app(*args, **kwargs):
import sys import sys
sys.argv = ['--wsgi'] sys.argv = ['--wsgi']