Skip to content
Snippets Groups Projects
Commit f80f2802 authored by Jan Prachař's avatar Jan Prachař
Browse files

O něco blbuvzdornější import účastníků

parent 3fb128fd
No related branches found
No related tags found
No related merge requests found
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
# - quoting pomocí uvozovek # - quoting pomocí uvozovek
import csv import csv
from difflib import get_close_matches
from enum import auto from enum import auto
from dataclasses import dataclass, fields from dataclasses import dataclass, fields
from typing import Type, List, IO, Sequence from typing import Type, List, IO, Sequence
...@@ -94,6 +95,19 @@ class MissingHeaderError(RuntimeError): ...@@ -94,6 +95,19 @@ class MissingHeaderError(RuntimeError):
pass pass
class UnknownColumnError(RuntimeError):
def __init__(self, unknown_name: str, columns: set):
best_matches = get_close_matches(unknown_name, columns, n=1)
if not best_matches:
self.message = (
"Neznámý sloupec '{}'. Podporovaná množina sloupců je tato: {}".format(
unknown_name, columns))
else:
self.message = (
"Neznámý sloupec '{}', měli jste na mysli '{}'?".format(
unknown_name, best_matches[0]))
def write(file: IO, fmt: FileFormat, row_class: Type[Row], rows: Sequence[Row]): def write(file: IO, fmt: FileFormat, row_class: Type[Row], rows: Sequence[Row]):
writer = csv.writer(file, dialect=fmt.get_dialect()) writer = csv.writer(file, dialect=fmt.get_dialect())
...@@ -120,6 +134,9 @@ def read(file: IO, fmt: FileFormat, row_class: Type[Row]): ...@@ -120,6 +134,9 @@ def read(file: IO, fmt: FileFormat, row_class: Type[Row]):
header = r header = r
if not any(h in columns for h in header): if not any(h in columns for h in header):
raise MissingHeaderError() raise MissingHeaderError()
for h in header:
if not h in columns:
raise UnknownColumnError(h, columns)
else: else:
row = row_class() row = row_class()
not_empty = False not_empty = False
... ...
......
...@@ -7,7 +7,7 @@ from sqlalchemy.orm import joinedload, Query ...@@ -7,7 +7,7 @@ from sqlalchemy.orm import joinedload, Query
from typing import List, Optional, Any, Dict, Type, Union from typing import List, Optional, Any, Dict, Type, Union
import mo.csv import mo.csv
from mo.csv import FileFormat, MissingHeaderError from mo.csv import FileFormat, MissingHeaderError, UnknownColumnError
import mo.db as db import mo.db as db
import mo.rights import mo.rights
import mo.users import mo.users
...@@ -162,13 +162,15 @@ class Import: ...@@ -162,13 +162,15 @@ class Import:
# Ve snaze zabránit Excelu v interpretování ročníku jako kalendářního data # Ve snaze zabránit Excelu v interpretování ročníku jako kalendářního data
# lidé připisují všechny možné i nemožné znaky, které vypadají jako apostrof :) # lidé připisují všechny možné i nemožné znaky, které vypadají jako apostrof :)
rocnik = re.sub('[\'"\u00b4\u2019]', "", rocnik) rocnik = re.sub('^[^\d]', "", rocnik)
if (school.is_ss and re.fullmatch(r'\d/\d', rocnik) if (school.is_ss and not re.fullmatch(r'\d/\d', rocnik)):
or school.is_zs and re.fullmatch(r'\d', rocnik)): return self.error(f'Ročník pro střední školu ({school.place.name}) zapisujte ve formátu číslice/číslice')
return rocnik
if (school.is_zs and not re.fullmatch(r'\d', rocnik)):
return self.error(f'Ročník pro základní školu ({school.place.name}) zapisujte jako číslici 1–9')
return self.error('Ročník neodpovídá typu školy: pro základní je to číslice, pro střední číslice/číslice') return rocnik
def parse_born(self, rok: str) -> Optional[int]: def parse_born(self, rok: str) -> Optional[int]:
if not re.fullmatch(r'\d{4}', rok): if not re.fullmatch(r'\d{4}', rok):
...@@ -379,7 +381,9 @@ class Import: ...@@ -379,7 +381,9 @@ class Import:
try: try:
rows: List[mo.csv.Row] = mo.csv.read(file=file, fmt=self.fmt, row_class=self.row_class) rows: List[mo.csv.Row] = mo.csv.read(file=file, fmt=self.fmt, row_class=self.row_class)
except MissingHeaderError: except MissingHeaderError:
return self.error('Souboru chybí hlavička s názvy sloupců') return self.error('Souboru chybí první řádek s názvy sloupců')
except UnknownColumnError as e:
return self.error(e.message)
except UnicodeDecodeError: except UnicodeDecodeError:
return self.error(f'Soubor není v kódování {self.fmt.get_charset()}') return self.error(f'Soubor není v kódování {self.fmt.get_charset()}')
except Exception as e: except Exception as e:
... ...
......
...@@ -12,11 +12,11 @@ Import dat do {% if contest %}soutěžní oblasti {{ contest.place.name }}{% els ...@@ -12,11 +12,11 @@ Import dat do {% if contest %}soutěžní oblasti {{ contest.place.name }}{% els
{% if errs %} {% if errs %}
<h3>Chyby při importu</h3> <h3>Chyby při importu</h3>
<pre><div class="alert alert-danger" role="alert">{{ "" -}} <div class="alert alert-danger" role="alert" style="white-space: pre">{{ "" -}}
{% for e in errs %} {% for e in errs %}
{{ e }} {{ e }}
{% endfor %} {% endfor %}
</div></pre> </div>
{% endif %} {% endif %}
<p>Zde je možné importovat účastníky soutěže, dozor na soutěžních místech a opravovatele. <p>Zde je možné importovat účastníky soutěže, dozor na soutěžních místech a opravovatele.
... ...
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment