Compare commits
10 Commits
Author | SHA1 | Date |
---|---|---|
Bertrand Benjamin | 7058c79975 | |
Bertrand Benjamin | d488807c57 | |
Bertrand Benjamin | 7e026bedb2 | |
Bertrand Benjamin | 33117cde71 | |
Bertrand Benjamin | 7d2cde304d | |
Bertrand Benjamin | 409b80994a | |
Bertrand Benjamin | 6fb11cb054 | |
Bertrand Benjamin | 7a0bb4179d | |
Bertrand Benjamin | fe3280b91d | |
Bertrand Benjamin | 3e85c3829d |
|
@ -2,16 +2,16 @@
|
|||
# encoding: utf-8
|
||||
|
||||
NO_ST_COLUMNS = {
|
||||
"term": "Trimestre",
|
||||
"assessment": "Nom",
|
||||
"term": "Trimestre",
|
||||
"date": "Date",
|
||||
"exercise": "Exercice",
|
||||
"question": "Question",
|
||||
"competence": "Competence",
|
||||
"theme": "Domaine",
|
||||
"comment": "Commentaire",
|
||||
"score_rate": "Bareme",
|
||||
"is_leveled": "Est_nivele",
|
||||
"score_rate": "Bareme",
|
||||
}
|
||||
|
||||
COLUMNS = {
|
||||
|
|
|
@ -44,7 +44,8 @@ def score_to_mark(x):
|
|||
if x[COLUMNS["is_leveled"]]:
|
||||
if x[COLUMNS["score"]] not in [0, 1, 2, 3]:
|
||||
raise ValueError(f"The evaluation is out of range: {x[COLUMNS['score']]} at {x}")
|
||||
return round_half_point(x[COLUMNS["score"]] * x[COLUMNS["score_rate"]] / 3)
|
||||
#return round_half_point(x[COLUMNS["score"]] * x[COLUMNS["score_rate"]] / 3)
|
||||
return round(x[COLUMNS["score"]] * x[COLUMNS["score_rate"]] / 3, 2)
|
||||
|
||||
if x[COLUMNS["score"]] > x[COLUMNS["score_rate"]]:
|
||||
raise ValueError(
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
import yaml
|
||||
|
||||
CONFIGPATH = "recoconfig.yml"
|
||||
|
||||
with open(CONFIGPATH, "r") as configfile:
|
||||
config = yaml.load(configfile, Loader=yaml.FullLoader)
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
import click
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from PyInquirer import prompt, print_json
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
|
||||
from .config import config
|
||||
from ..config import NO_ST_COLUMNS
|
||||
|
||||
|
||||
class PromptAbortException(EOFError):
|
||||
def __init__(self, message, errors=None):
|
||||
|
||||
# Call the base class constructor with the parameters it needs
|
||||
super(PromptAbortException, self).__init__("Abort questionnary", errors)
|
||||
|
||||
|
||||
def get_tribes(answers):
|
||||
""" List tribes based on subdirectory of config["source"] which have an "eleves.csv" file inside """
|
||||
return [
|
||||
p.name for p in Path(config["source"]).iterdir() if (p / "eleves.csv").exists()
|
||||
]
|
||||
|
||||
|
||||
def prepare_csv():
|
||||
items = new_eval()
|
||||
|
||||
item = items[0]
|
||||
# item = {"tribe": "308", "date": datetime.today(), "assessment": "plop"}
|
||||
csv_output = (
|
||||
Path(config["source"])
|
||||
/ item["tribe"]
|
||||
/ f"{item['date']:%y%m%d}_{item['assessment']}.csv"
|
||||
)
|
||||
|
||||
students = pd.read_csv(Path(config["source"]) / item["tribe"] / "eleves.csv")["Nom"]
|
||||
|
||||
columns = list(NO_ST_COLUMNS.keys())
|
||||
items = [[it[c] for c in columns] for it in items]
|
||||
columns = list(NO_ST_COLUMNS.values())
|
||||
items_df = pd.DataFrame.from_records(items, columns=columns)
|
||||
for s in students:
|
||||
items_df[s] = np.nan
|
||||
|
||||
items_df.to_csv(csv_output, index=False, date_format="%d/%m/%Y")
|
||||
click.echo(f"Saving csv file to {csv_output}")
|
||||
|
||||
|
||||
def new_eval(answers={}):
|
||||
click.echo(f"Préparation d'un nouveau devoir")
|
||||
|
||||
eval_questions = [
|
||||
{"type": "input", "name": "assessment", "message": "Nom de l'évaluation",},
|
||||
{
|
||||
"type": "list",
|
||||
"name": "tribe",
|
||||
"message": "Classe concernée",
|
||||
"choices": get_tribes,
|
||||
},
|
||||
{
|
||||
"type": "input",
|
||||
"name": "date",
|
||||
"message": "Date du devoir (%y%m%d)",
|
||||
"default": datetime.today().strftime("%y%m%d"),
|
||||
"filter": lambda val: datetime.strptime(val, "%y%m%d"),
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"name": "term",
|
||||
"message": "Trimestre",
|
||||
"choices": ["1", "2", "3"],
|
||||
},
|
||||
]
|
||||
|
||||
eval_ans = prompt(eval_questions)
|
||||
|
||||
items = []
|
||||
add_exo = True
|
||||
while add_exo:
|
||||
ex_items = new_exercice(eval_ans)
|
||||
items += ex_items
|
||||
add_exo = prompt(
|
||||
[
|
||||
{
|
||||
"type": "confirm",
|
||||
"name": "add_exo",
|
||||
"message": "Ajouter un autre exercice",
|
||||
"default": True,
|
||||
}
|
||||
]
|
||||
)["add_exo"]
|
||||
return items
|
||||
|
||||
|
||||
def new_exercice(answers={}):
|
||||
exercise_questions = [
|
||||
{"type": "input", "name": "exercise", "message": "Nom de l'exercice"},
|
||||
]
|
||||
|
||||
click.echo(f"Nouvel exercice")
|
||||
exercise_ans = prompt(exercise_questions, answers=answers)
|
||||
|
||||
items = []
|
||||
|
||||
add_item = True
|
||||
while add_item:
|
||||
try:
|
||||
item_ans = new_item(exercise_ans)
|
||||
except PromptAbortException:
|
||||
click.echo("Création de l'item annulée")
|
||||
else:
|
||||
items.append(item_ans)
|
||||
add_item = prompt(
|
||||
[
|
||||
{
|
||||
"type": "confirm",
|
||||
"name": "add_item",
|
||||
"message": f"Ajouter un autre item pour l'exercice {exercise_ans['exercise']}",
|
||||
"default": True,
|
||||
}
|
||||
]
|
||||
)["add_item"]
|
||||
|
||||
return items
|
||||
|
||||
|
||||
def new_item(answers={}):
|
||||
item_questions = [
|
||||
{"type": "input", "name": "question", "message": "Nom de l'item",},
|
||||
{"type": "input", "name": "comment", "message": "Commentaire",},
|
||||
{
|
||||
"type": "list",
|
||||
"name": "competence",
|
||||
"message": "Competence",
|
||||
"choices": ["Cher", "Rep", "Mod", "Rai", "Cal", "Com"],
|
||||
},
|
||||
{"type": "input", "name": "theme", "message": "Domaine",},
|
||||
{
|
||||
"type": "confirm",
|
||||
"name": "is_leveled",
|
||||
"message": "Évaluation par niveau",
|
||||
"default": True,
|
||||
},
|
||||
{"type": "input", "name": "score_rate", "message": "Bareme"},
|
||||
{
|
||||
"type": "confirm",
|
||||
"name": "correct",
|
||||
"message": "Tout est correct?",
|
||||
"default": True,
|
||||
},
|
||||
]
|
||||
click.echo(f"Nouvelle question pour l'exercice {answers['exercise']}")
|
||||
item_ans = prompt(item_questions, answers=answers)
|
||||
if item_ans["correct"]:
|
||||
return item_ans
|
||||
raise PromptAbortException("Abort item creation")
|
|
@ -8,10 +8,8 @@ import sys
|
|||
import papermill as pm
|
||||
from datetime import datetime
|
||||
|
||||
CONFIGPATH = "recoconfig.yml"
|
||||
|
||||
with open(CONFIGPATH, "r") as config:
|
||||
config = yaml.load(config, Loader=yaml.FullLoader)
|
||||
from .prepare_csv import prepare_csv
|
||||
from .config import config
|
||||
|
||||
|
||||
@click.group()
|
||||
|
@ -26,18 +24,8 @@ def print_config():
|
|||
click.echo(config)
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.argument("csv_file")
|
||||
def report(csv_file):
|
||||
csv = Path(csv_file)
|
||||
if not csv.exists():
|
||||
click.echo(f"{csv_file} does not exists")
|
||||
sys.exit(1)
|
||||
if csv.suffix != ".csv":
|
||||
click.echo(f"{csv_file} has to be a csv file")
|
||||
sys.exit(1)
|
||||
|
||||
csv_file = Path(csv_file)
|
||||
def reporting(csv_file):
|
||||
# csv_file = Path(csv_file)
|
||||
tribe_dir = csv_file.parent
|
||||
csv_filename = csv_file.name.split(".")[0]
|
||||
|
||||
|
@ -46,7 +34,7 @@ def report(csv_file):
|
|||
try:
|
||||
date = datetime.strptime(date, "%y%m%d")
|
||||
except ValueError:
|
||||
date = None
|
||||
date = datetime.today().strptime(date, "%y%m%d")
|
||||
|
||||
tribe = str(tribe_dir).split("/")[-1]
|
||||
|
||||
|
@ -60,22 +48,55 @@ def report(csv_file):
|
|||
str(template),
|
||||
str(dest / f"{assessment}.ipynb"),
|
||||
parameters=dict(
|
||||
tribe=tribe, assessment=assessment, date=f"{date:%d/%m/%y}", csv_file=str(csv_file.absolute())
|
||||
tribe=tribe,
|
||||
assessment=assessment,
|
||||
date=f"{date:%d/%m/%y}",
|
||||
csv_file=str(csv_file.absolute()),
|
||||
),
|
||||
)
|
||||
|
||||
# with open(csv_file.parent / "description.yml") as f:
|
||||
# tribe_desc = yaml.load(f, Loader=yaml.FullLoader)
|
||||
|
||||
# template = Path(config["templates"]) / "tpl_student.ipynb"
|
||||
# dest = Path(config["output"]) / tribe / csv_filename / "students"
|
||||
# dest.mkdir(parents=True, exist_ok=True)
|
||||
@cli.command()
|
||||
@click.argument("target", required=False)
|
||||
def report(target=""):
|
||||
""" Make a report for the eval
|
||||
|
||||
# for st in tribe_desc["students"]:
|
||||
# click.echo(f"Building {st} report on {assessment}")
|
||||
# pm.execute_notebook(
|
||||
# str(template),
|
||||
# str(dest / f"{st}.ipynb"),
|
||||
# parameters=dict(tribe=tribe, student=st, source=str(tribe_dir.absolute())),
|
||||
# )
|
||||
:param target: csv file or a directory where csvs are
|
||||
"""
|
||||
try:
|
||||
if target.endswith(".csv"):
|
||||
csv = Path(target)
|
||||
if not csv.exists():
|
||||
click.echo(f"{target} does not exists")
|
||||
sys.exit(1)
|
||||
if csv.suffix != ".csv":
|
||||
click.echo(f"{target} has to be a csv file")
|
||||
sys.exit(1)
|
||||
csvs = [csv]
|
||||
else:
|
||||
csvs = list(Path(target).glob("**/*.csv"))
|
||||
except AttributeError:
|
||||
csvs = list(Path(config["source"]).glob("**/*.csv"))
|
||||
|
||||
for csv in csvs:
|
||||
click.echo(f"Processing {csv}")
|
||||
try:
|
||||
reporting(csv)
|
||||
except pm.exceptions.PapermillExecutionError as e:
|
||||
click.echo(f"Error with {csv}: {e}")
|
||||
|
||||
|
||||
@cli.command()
|
||||
def prepare():
|
||||
""" Prepare csv file """
|
||||
|
||||
items = prepare_csv()
|
||||
|
||||
click.echo(items)
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.argument("tribe")
|
||||
def random_pick(tribe):
|
||||
""" Randomly pick a student """
|
||||
pass
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
ansiwrap==0.8.4
|
||||
appdirs==1.4.3
|
||||
attrs==19.1.0
|
||||
backcall==0.1.0
|
||||
black==19.10b0
|
||||
bleach==3.1.0
|
||||
certifi==2019.6.16
|
||||
chardet==3.0.4
|
||||
|
@ -13,57 +15,62 @@ entrypoints==0.3
|
|||
future==0.17.1
|
||||
idna==2.8
|
||||
importlib-resources==1.0.2
|
||||
ipykernel==5.1.1
|
||||
ipython==7.7.0
|
||||
ipykernel==5.1.3
|
||||
ipython==7.11.1
|
||||
ipython-genutils==0.2.0
|
||||
ipywidgets==7.5.1
|
||||
jedi==0.14.1
|
||||
Jinja2==2.10.1
|
||||
jsonschema==3.0.2
|
||||
jedi==0.15.2
|
||||
Jinja2==2.10.3
|
||||
jsonschema==3.2.0
|
||||
jupyter==1.0.0
|
||||
jupyter-client==5.3.1
|
||||
jupyter-console==6.0.0
|
||||
jupyter-core==4.5.0
|
||||
jupyter-client==5.3.4
|
||||
jupyter-console==6.1.0
|
||||
jupyter-core==4.6.1
|
||||
jupytex==0.0.3
|
||||
kiwisolver==1.1.0
|
||||
Markdown==3.1.1
|
||||
MarkupSafe==1.1.1
|
||||
matplotlib==3.1.1
|
||||
matplotlib==3.1.2
|
||||
mistune==0.8.4
|
||||
nbconvert==5.5.0
|
||||
nbformat==4.4.0
|
||||
notebook==6.0.0
|
||||
numpy==1.17.0
|
||||
pandas==0.25.0
|
||||
nbconvert==5.6.1
|
||||
nbformat==5.0.3
|
||||
notebook==6.0.3
|
||||
numpy==1.18.1
|
||||
pandas==0.25.3
|
||||
pandocfilters==1.4.2
|
||||
papermill==1.0.1
|
||||
parso==0.5.1
|
||||
pexpect==4.7.0
|
||||
papermill==1.2.1
|
||||
parso==0.5.2
|
||||
pathspec==0.7.0
|
||||
pexpect==4.8.0
|
||||
pickleshare==0.7.5
|
||||
prometheus-client==0.7.1
|
||||
prompt-toolkit==2.0.9
|
||||
prompt-toolkit==1.0.14
|
||||
ptyprocess==0.6.0
|
||||
Pygments==2.4.2
|
||||
pyparsing==2.4.2
|
||||
pyrsistent==0.15.4
|
||||
Pygments==2.5.2
|
||||
PyInquirer==1.0.3
|
||||
pyparsing==2.4.6
|
||||
pyrsistent==0.15.7
|
||||
python-dateutil==2.8.0
|
||||
pytz==2019.2
|
||||
PyYAML==5.1.2
|
||||
pyzmq==18.0.2
|
||||
qtconsole==4.5.2
|
||||
-e git+git_opytex:/lafrite/recopytex.git@e9a8310f151ead60434ae944d726a2fd22b23d06#egg=Recopytex
|
||||
pytz==2019.3
|
||||
PyYAML==5.3
|
||||
pyzmq==18.1.1
|
||||
qtconsole==4.6.0
|
||||
-e git+git_opytex:/lafrite/recopytex.git@7e026bedb24c1ca8bef3b71b3d63f8b0d6916e81#egg=Recopytex
|
||||
regex==2020.1.8
|
||||
requests==2.22.0
|
||||
scipy==1.3.0
|
||||
seaborn==0.9.0
|
||||
scipy==1.4.1
|
||||
Send2Trash==1.5.0
|
||||
six==1.12.0
|
||||
tenacity==5.0.4
|
||||
terminado==0.8.2
|
||||
testpath==0.4.2
|
||||
tenacity==6.0.0
|
||||
terminado==0.8.3
|
||||
testpath==0.4.4
|
||||
textwrap3==0.9.2
|
||||
toml==0.10.0
|
||||
tornado==6.0.3
|
||||
tqdm==4.32.2
|
||||
tqdm==4.41.1
|
||||
traitlets==4.3.2
|
||||
urllib3==1.25.3
|
||||
wcwidth==0.1.7
|
||||
typed-ast==1.4.1
|
||||
urllib3==1.25.8
|
||||
wcwidth==0.1.8
|
||||
webencodings==0.5.1
|
||||
widgetsnbextension==3.5.1
|
||||
|
|
7
setup.py
7
setup.py
|
@ -5,7 +5,7 @@ from setuptools import setup, find_packages
|
|||
|
||||
setup(
|
||||
name='Recopytex',
|
||||
version='0.1',
|
||||
version='1.1.1',
|
||||
description='Assessment analysis',
|
||||
author='Benjamin Bertrand',
|
||||
author_email='',
|
||||
|
@ -13,6 +13,11 @@ setup(
|
|||
include_package_data=True,
|
||||
install_requires=[
|
||||
'Click',
|
||||
'pandas',
|
||||
'numpy',
|
||||
'papermill',
|
||||
'pyyaml',
|
||||
'PyInquirer',
|
||||
],
|
||||
entry_points='''
|
||||
[console_scripts]
|
||||
|
|
Loading…
Reference in New Issue