From 04c640ca339f4c0605d025d841f726b7b4cfc0e1 Mon Sep 17 00:00:00 2001 From: Skythrew Date: Tue, 1 Aug 2023 17:26:34 +0200 Subject: [PATCH 01/17] add Comment class --- pronotepy/dataClasses.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pronotepy/dataClasses.py b/pronotepy/dataClasses.py index 578051a..14c63ab 100644 --- a/pronotepy/dataClasses.py +++ b/pronotepy/dataClasses.py @@ -634,6 +634,21 @@ def to_dict( ) +class Comment(Object): + """ + Represents a comment (usually found in a report) + + Attributes: + id (str): The id of the comment (used internally) + comment (str): The actual comment + """ + + def __init__(self, json_dict: dict) -> None: + super().__init__(json_dict) + + self.id = self._resolver(str, "N") + self.comment = self._resolver(str, "L") + class Attachment(Object): """ Represents a attachment to homework for example From d44f15f1b5fcd1c81c7ad0141454c643cbd7318e Mon Sep 17 00:00:00 2001 From: Skythrew Date: Wed, 2 Aug 2023 12:22:32 +0200 Subject: [PATCH 02/17] Add ReportSubject class --- pronotepy/dataClasses.py | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/pronotepy/dataClasses.py b/pronotepy/dataClasses.py index 14c63ab..0f2bcfb 100644 --- a/pronotepy/dataClasses.py +++ b/pronotepy/dataClasses.py @@ -318,8 +318,34 @@ def __init__(self, parsed_json: dict) -> None: self.name: str = self._resolver(str, "L") self.groups: bool = self._resolver(bool, "estServiceGroupe", default=False) - del self._resolver +class ReportSubject(Subject): + """ + Represents a subject found in a report. You shouldn't have to create this class manually. + + Attributes: + color (str): the color of the subject + comments (List[Comment]): the list of the subject's comments + class_average (str): the average of the class + student_average (str): the average of the student + min_average (str): the lowest average of the class + max_average (str): the highest average of the class + coefficient (str): the coefficient of the subject + teachers (List[str]): the subject's teachers' names + """ + + def __init__(self, parsed_json: dict) -> None: + super().__init__(parsed_json) + self.color: str = self._resolver(str, "couleur") + self.comments: List[Comment] = self._resolver(lambda l: [Comment(i) for i in l], "ListeAppreciations", "V") + self.class_average: str = self._resolver(Util.grade_parse, "MoyenneClasse", "V") + self.student_average: str = self._resolver(Util.grade_parse, "MoyenneEleve", "V") + self.min_average: str = self._resolver(Util.grade_parse, "MoyenneInf", "V") + self.max_average: str = self._resolver(Util.grade_parse, "MoyenneSup", "V") + self.coefficient: str = self._resolver(str, "Coefficient", "V") + self.teachers: List[str] = self._resolver(lambda l: [i["L"] for i in l], "ListeProfesseurs", "V") + + del self._resolver class Absence(Object): """ @@ -648,7 +674,7 @@ def __init__(self, json_dict: dict) -> None: self.id = self._resolver(str, "N") self.comment = self._resolver(str, "L") - + class Attachment(Object): """ Represents a attachment to homework for example From d729f779454e4aecd49d053b4006954d51b8f7c2 Mon Sep 17 00:00:00 2001 From: Skythrew Date: Wed, 2 Aug 2023 12:41:10 +0200 Subject: [PATCH 03/17] Add Report class --- pronotepy/dataClasses.py | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/pronotepy/dataClasses.py b/pronotepy/dataClasses.py index 0f2bcfb..04c03ff 100644 --- a/pronotepy/dataClasses.py +++ b/pronotepy/dataClasses.py @@ -343,10 +343,24 @@ def __init__(self, parsed_json: dict) -> None: self.min_average: str = self._resolver(Util.grade_parse, "MoyenneInf", "V") self.max_average: str = self._resolver(Util.grade_parse, "MoyenneSup", "V") self.coefficient: str = self._resolver(str, "Coefficient", "V") - self.teachers: List[str] = self._resolver(lambda l: [i["L"] for i in l], "ListeProfesseurs", "V") + self.teachers: List[str] = self._resolver(lambda l: [i["L"] for i in l], "ListeProfesseurs", "V", default=False) del self._resolver +class Report(Object): + """Represents a student report. You shouldn't have to create this class manually. + + Attributes: + subjects (List[ReportSubject]): the subjects that are present in the report + comments (List[Comment]): the global report comments + """ + + def __init__(self, parsed_json: dict) -> None: + super().__init__(parsed_json) + + self.subjects: List[ReportSubject] = self._resolver(lambda l: [ReportSubject(s) for s in l], "ListeServices", "V") + self.comments: List[ReportComment] = self._resolver(lambda l: [ReportComment(c) for c in l], "ObjetListeAppreciations", "V", "ListeAppreciations", "V") + class Absence(Object): """ Represents an absence with a given period. You shouldn't have to create this class manually. @@ -672,8 +686,22 @@ class Comment(Object): def __init__(self, json_dict: dict) -> None: super().__init__(json_dict) - self.id = self._resolver(str, "N") - self.comment = self._resolver(str, "L") + self.id = self._resolver(str, "N", default=False) + self.comment = self._resolver(str, "L", default=False) + +class ReportComment(Comment): + """ + Represents a report global comment. + + Attributes: + title (str): The title of the comment + """ + def __init__(self, json_dict: dict) -> None: + super().__init__(json_dict) + + self.title: str = self._resolver(str, "Intitule", default=False) + + del self._resolver class Attachment(Object): """ From a1fe7183f9eddd9c5fef3a8d66a853b61a170b64 Mon Sep 17 00:00:00 2001 From: Skythrew Date: Wed, 2 Aug 2023 12:45:43 +0200 Subject: [PATCH 04/17] Add report method --- pronotepy/clients.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pronotepy/clients.py b/pronotepy/clients.py index a10d72e..61b6d6d 100644 --- a/pronotepy/clients.py +++ b/pronotepy/clients.py @@ -354,6 +354,25 @@ def __init__( ) -> None: super().__init__(pronote_url, username, password, ent, qr_code) + def report( + self, + period: dataClasses.Period + ) -> dataClasses.Report: + """Gets a report from a period + + Args: + period (Period): the report period + + Returns: + Report: the report of the given period + """ + + json_data = {"periode": {"G": 2, "N": period.id, "L": period.name}} + + response = self.post("PageBulletins", 13, json_data) + + return dataClasses.Report(response["donneesSec"]["donnees"]) + def lessons( self, date_from: Union[datetime.date, datetime.datetime], From 13f32684219d7ca02cb9573172c1dccb9e0e2fe7 Mon Sep 17 00:00:00 2001 From: Skythrew Date: Wed, 2 Aug 2023 13:20:23 +0200 Subject: [PATCH 05/17] add published property in Report class --- pronotepy/dataClasses.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pronotepy/dataClasses.py b/pronotepy/dataClasses.py index 04c03ff..b2e8c11 100644 --- a/pronotepy/dataClasses.py +++ b/pronotepy/dataClasses.py @@ -351,15 +351,17 @@ class Report(Object): """Represents a student report. You shouldn't have to create this class manually. Attributes: + published (bool): Is the report published ? subjects (List[ReportSubject]): the subjects that are present in the report comments (List[Comment]): the global report comments """ def __init__(self, parsed_json: dict) -> None: super().__init__(parsed_json) - - self.subjects: List[ReportSubject] = self._resolver(lambda l: [ReportSubject(s) for s in l], "ListeServices", "V") - self.comments: List[ReportComment] = self._resolver(lambda l: [ReportComment(c) for c in l], "ObjetListeAppreciations", "V", "ListeAppreciations", "V") + + self.subjects: List[ReportSubject] = self._resolver(lambda l: [ReportSubject(s) for s in l], "ListeServices", "V", default=False) + self.comments: List[ReportComment] = self._resolver(lambda l: [ReportComment(c) for c in l], "ObjetListeAppreciations", "V", "ListeAppreciations", "V", default=False) + self.published: bool = bool(self.comments) class Absence(Object): """ From d6772262110bb0c10219fb44da04790961d0c695 Mon Sep 17 00:00:00 2001 From: Skythrew Date: Wed, 2 Aug 2023 13:21:10 +0200 Subject: [PATCH 06/17] add Report class in class list --- pronotepy/dataClasses.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pronotepy/dataClasses.py b/pronotepy/dataClasses.py index b2e8c11..5b6a2f7 100644 --- a/pronotepy/dataClasses.py +++ b/pronotepy/dataClasses.py @@ -61,6 +61,7 @@ "Menu", "Punishment", "Delay", + "Report" ) log = logging.getLogger(__name__) From 08bc806854499e81451fdb7b910d81cb443c201d Mon Sep 17 00:00:00 2001 From: Skythrew Date: Wed, 2 Aug 2023 14:07:31 +0200 Subject: [PATCH 07/17] add tests for reports --- pronotepy/test_pronotepy.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pronotepy/test_pronotepy.py b/pronotepy/test_pronotepy.py index f967789..92ab915 100644 --- a/pronotepy/test_pronotepy.py +++ b/pronotepy/test_pronotepy.py @@ -84,6 +84,16 @@ def test_refresh(self) -> None: client.refresh() self.assertEqual(client.session_check(), True) + def test_report(self) -> None: + report = client.report(client.periods[0]) + + self.assertIsInstance(self, report, pronotepy.Report) + + def test_not_published_report(self) -> None: + report = client.report(client.periods[3]) + + self.assertFalse(report.published) + class TestPeriod(unittest.TestCase): period: pronotepy.Period From ccefce35c949efac556663f7d397533739be8caf Mon Sep 17 00:00:00 2001 From: Skythrew Date: Wed, 2 Aug 2023 15:14:05 +0200 Subject: [PATCH 08/17] fix test_report --- pronotepy/test_pronotepy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pronotepy/test_pronotepy.py b/pronotepy/test_pronotepy.py index 92ab915..1f2f8db 100644 --- a/pronotepy/test_pronotepy.py +++ b/pronotepy/test_pronotepy.py @@ -87,7 +87,7 @@ def test_refresh(self) -> None: def test_report(self) -> None: report = client.report(client.periods[0]) - self.assertIsInstance(self, report, pronotepy.Report) + self.assertIsInstance(report, pronotepy.Report) def test_not_published_report(self) -> None: report = client.report(client.periods[3]) From 58f0ee25bad721721f1443880092d276a6dbe113 Mon Sep 17 00:00:00 2001 From: Skythrew Date: Wed, 2 Aug 2023 15:14:20 +0200 Subject: [PATCH 09/17] fixes after mypy --- pronotepy/dataClasses.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pronotepy/dataClasses.py b/pronotepy/dataClasses.py index 5b6a2f7..cb1474c 100644 --- a/pronotepy/dataClasses.py +++ b/pronotepy/dataClasses.py @@ -344,7 +344,7 @@ def __init__(self, parsed_json: dict) -> None: self.min_average: str = self._resolver(Util.grade_parse, "MoyenneInf", "V") self.max_average: str = self._resolver(Util.grade_parse, "MoyenneSup", "V") self.coefficient: str = self._resolver(str, "Coefficient", "V") - self.teachers: List[str] = self._resolver(lambda l: [i["L"] for i in l], "ListeProfesseurs", "V", default=False) + self.teachers: List[str] = self._resolver(lambda l: [i["L"] for i in l], "ListeProfesseurs", "V", default=[]) del self._resolver @@ -360,8 +360,8 @@ class Report(Object): def __init__(self, parsed_json: dict) -> None: super().__init__(parsed_json) - self.subjects: List[ReportSubject] = self._resolver(lambda l: [ReportSubject(s) for s in l], "ListeServices", "V", default=False) - self.comments: List[ReportComment] = self._resolver(lambda l: [ReportComment(c) for c in l], "ObjetListeAppreciations", "V", "ListeAppreciations", "V", default=False) + self.subjects: List[ReportSubject] = self._resolver(lambda l: [ReportSubject(s) for s in l], "ListeServices", "V", default=[]) + self.comments: List[ReportComment] = self._resolver(lambda l: [ReportComment(c) for c in l], "ObjetListeAppreciations", "V", "ListeAppreciations", "V", default=[]) self.published: bool = bool(self.comments) class Absence(Object): @@ -689,8 +689,8 @@ class Comment(Object): def __init__(self, json_dict: dict) -> None: super().__init__(json_dict) - self.id = self._resolver(str, "N", default=False) - self.comment = self._resolver(str, "L", default=False) + self.id: str = self._resolver(str, "N", default="") + self.comment: str = self._resolver(str, "L", default="") class ReportComment(Comment): """ @@ -702,7 +702,7 @@ class ReportComment(Comment): def __init__(self, json_dict: dict) -> None: super().__init__(json_dict) - self.title: str = self._resolver(str, "Intitule", default=False) + self.title: str = self._resolver(str, "Intitule", default="") del self._resolver From fc5dc539ed890d50a4ff8421765ff8abde2e5208 Mon Sep 17 00:00:00 2001 From: Skythrew Date: Wed, 2 Aug 2023 15:15:58 +0200 Subject: [PATCH 10/17] fix format (black) --- pronotepy/clients.py | 11 ++++------- pronotepy/dataClasses.py | 39 ++++++++++++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/pronotepy/clients.py b/pronotepy/clients.py index 61b6d6d..acf5937 100644 --- a/pronotepy/clients.py +++ b/pronotepy/clients.py @@ -354,15 +354,12 @@ def __init__( ) -> None: super().__init__(pronote_url, username, password, ent, qr_code) - def report( - self, - period: dataClasses.Period - ) -> dataClasses.Report: + def report(self, period: dataClasses.Period) -> dataClasses.Report: """Gets a report from a period - + Args: period (Period): the report period - + Returns: Report: the report of the given period """ @@ -370,7 +367,7 @@ def report( json_data = {"periode": {"G": 2, "N": period.id, "L": period.name}} response = self.post("PageBulletins", 13, json_data) - + return dataClasses.Report(response["donneesSec"]["donnees"]) def lessons( diff --git a/pronotepy/dataClasses.py b/pronotepy/dataClasses.py index cb1474c..b29862e 100644 --- a/pronotepy/dataClasses.py +++ b/pronotepy/dataClasses.py @@ -61,7 +61,7 @@ "Menu", "Punishment", "Delay", - "Report" + "Report", ) log = logging.getLogger(__name__) @@ -319,6 +319,7 @@ def __init__(self, parsed_json: dict) -> None: self.name: str = self._resolver(str, "L") self.groups: bool = self._resolver(bool, "estServiceGroupe", default=False) + class ReportSubject(Subject): """ Represents a subject found in a report. You shouldn't have to create this class manually. @@ -338,19 +339,26 @@ def __init__(self, parsed_json: dict) -> None: super().__init__(parsed_json) self.color: str = self._resolver(str, "couleur") - self.comments: List[Comment] = self._resolver(lambda l: [Comment(i) for i in l], "ListeAppreciations", "V") + self.comments: List[Comment] = self._resolver( + lambda l: [Comment(i) for i in l], "ListeAppreciations", "V" + ) self.class_average: str = self._resolver(Util.grade_parse, "MoyenneClasse", "V") - self.student_average: str = self._resolver(Util.grade_parse, "MoyenneEleve", "V") + self.student_average: str = self._resolver( + Util.grade_parse, "MoyenneEleve", "V" + ) self.min_average: str = self._resolver(Util.grade_parse, "MoyenneInf", "V") self.max_average: str = self._resolver(Util.grade_parse, "MoyenneSup", "V") self.coefficient: str = self._resolver(str, "Coefficient", "V") - self.teachers: List[str] = self._resolver(lambda l: [i["L"] for i in l], "ListeProfesseurs", "V", default=[]) - + self.teachers: List[str] = self._resolver( + lambda l: [i["L"] for i in l], "ListeProfesseurs", "V", default=[] + ) + del self._resolver + class Report(Object): """Represents a student report. You shouldn't have to create this class manually. - + Attributes: published (bool): Is the report published ? subjects (List[ReportSubject]): the subjects that are present in the report @@ -360,10 +368,20 @@ class Report(Object): def __init__(self, parsed_json: dict) -> None: super().__init__(parsed_json) - self.subjects: List[ReportSubject] = self._resolver(lambda l: [ReportSubject(s) for s in l], "ListeServices", "V", default=[]) - self.comments: List[ReportComment] = self._resolver(lambda l: [ReportComment(c) for c in l], "ObjetListeAppreciations", "V", "ListeAppreciations", "V", default=[]) + self.subjects: List[ReportSubject] = self._resolver( + lambda l: [ReportSubject(s) for s in l], "ListeServices", "V", default=[] + ) + self.comments: List[ReportComment] = self._resolver( + lambda l: [ReportComment(c) for c in l], + "ObjetListeAppreciations", + "V", + "ListeAppreciations", + "V", + default=[], + ) self.published: bool = bool(self.comments) + class Absence(Object): """ Represents an absence with a given period. You shouldn't have to create this class manually. @@ -680,7 +698,7 @@ def to_dict( class Comment(Object): """ Represents a comment (usually found in a report) - + Attributes: id (str): The id of the comment (used internally) comment (str): The actual comment @@ -692,6 +710,7 @@ def __init__(self, json_dict: dict) -> None: self.id: str = self._resolver(str, "N", default="") self.comment: str = self._resolver(str, "L", default="") + class ReportComment(Comment): """ Represents a report global comment. @@ -699,6 +718,7 @@ class ReportComment(Comment): Attributes: title (str): The title of the comment """ + def __init__(self, json_dict: dict) -> None: super().__init__(json_dict) @@ -706,6 +726,7 @@ def __init__(self, json_dict: dict) -> None: del self._resolver + class Attachment(Object): """ Represents a attachment to homework for example From bab2ed92543979176c58fcf3893bb7a05ebaeb3c Mon Sep 17 00:00:00 2001 From: Skythrew Date: Thu, 3 Aug 2023 11:12:02 +0200 Subject: [PATCH 11/17] move report method to Period class --- pronotepy/clients.py | 16 ---------------- pronotepy/dataClasses.py | 7 +++++++ pronotepy/test_pronotepy.py | 4 ++-- 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/pronotepy/clients.py b/pronotepy/clients.py index acf5937..a10d72e 100644 --- a/pronotepy/clients.py +++ b/pronotepy/clients.py @@ -354,22 +354,6 @@ def __init__( ) -> None: super().__init__(pronote_url, username, password, ent, qr_code) - def report(self, period: dataClasses.Period) -> dataClasses.Report: - """Gets a report from a period - - Args: - period (Period): the report period - - Returns: - Report: the report of the given period - """ - - json_data = {"periode": {"G": 2, "N": period.id, "L": period.name}} - - response = self.post("PageBulletins", 13, json_data) - - return dataClasses.Report(response["donneesSec"]["donnees"]) - def lessons( self, date_from: Union[datetime.date, datetime.datetime], diff --git a/pronotepy/dataClasses.py b/pronotepy/dataClasses.py index b29862e..5c9dd3f 100644 --- a/pronotepy/dataClasses.py +++ b/pronotepy/dataClasses.py @@ -476,6 +476,13 @@ def __init__(self, client: ClientBase, json_dict: dict) -> None: del self._resolver + @property + def report(self) -> Report: + """Gets a report from a period""" + json_data = {"periode": {"G": 2, "N": self.id, "L": self.name}} + response = self._client.post("PageBulletins", 13, json_data) + return Report(response["donneesSec"]["donnees"]) + @property def grades(self) -> List["Grade"]: """Get grades from the period.""" diff --git a/pronotepy/test_pronotepy.py b/pronotepy/test_pronotepy.py index 1f2f8db..eaf600e 100644 --- a/pronotepy/test_pronotepy.py +++ b/pronotepy/test_pronotepy.py @@ -85,12 +85,12 @@ def test_refresh(self) -> None: self.assertEqual(client.session_check(), True) def test_report(self) -> None: - report = client.report(client.periods[0]) + report = client.periods[0].report self.assertIsInstance(report, pronotepy.Report) def test_not_published_report(self) -> None: - report = client.report(client.periods[3]) + report = client.periods[3].report self.assertFalse(report.published) From 6b8d971b1bc04508fbf4ce944709436fca5f79ce Mon Sep 17 00:00:00 2001 From: Skythrew Date: Thu, 3 Aug 2023 11:30:10 +0200 Subject: [PATCH 12/17] convert Comment and ReportComment classes to simple strings --- pronotepy/dataClasses.py | 114 ++++++++++++++------------------------- 1 file changed, 41 insertions(+), 73 deletions(-) diff --git a/pronotepy/dataClasses.py b/pronotepy/dataClasses.py index 5c9dd3f..d9160bb 100644 --- a/pronotepy/dataClasses.py +++ b/pronotepy/dataClasses.py @@ -319,60 +319,61 @@ def __init__(self, parsed_json: dict) -> None: self.name: str = self._resolver(str, "L") self.groups: bool = self._resolver(bool, "estServiceGroupe", default=False) - -class ReportSubject(Subject): - """ - Represents a subject found in a report. You shouldn't have to create this class manually. +class Report(Object): + """Represents a student report. You shouldn't have to create this class manually. Attributes: - color (str): the color of the subject - comments (List[Comment]): the list of the subject's comments - class_average (str): the average of the class - student_average (str): the average of the student - min_average (str): the lowest average of the class - max_average (str): the highest average of the class - coefficient (str): the coefficient of the subject - teachers (List[str]): the subject's teachers' names + published (bool): Is the report published ? + subjects (List[ReportSubject]): the subjects that are present in the report + comments (List[str]): the global report comments """ - def __init__(self, parsed_json: dict) -> None: - super().__init__(parsed_json) + class ReportSubject(Subject): + """ + Represents a subject found in a report. You shouldn't have to create this class manually. - self.color: str = self._resolver(str, "couleur") - self.comments: List[Comment] = self._resolver( - lambda l: [Comment(i) for i in l], "ListeAppreciations", "V" - ) - self.class_average: str = self._resolver(Util.grade_parse, "MoyenneClasse", "V") - self.student_average: str = self._resolver( - Util.grade_parse, "MoyenneEleve", "V" - ) - self.min_average: str = self._resolver(Util.grade_parse, "MoyenneInf", "V") - self.max_average: str = self._resolver(Util.grade_parse, "MoyenneSup", "V") - self.coefficient: str = self._resolver(str, "Coefficient", "V") - self.teachers: List[str] = self._resolver( - lambda l: [i["L"] for i in l], "ListeProfesseurs", "V", default=[] - ) + Attributes: + color (str): the color of the subject + comments (List[str]): the list of the subject's comments + class_average (str): the average of the class + student_average (str): the average of the student + min_average (str): the lowest average of the class + max_average (str): the highest average of the class + coefficient (str): the coefficient of the subject + teachers (List[str]): the subject's teachers' names + """ - del self._resolver + def __init__(self, parsed_json: dict) -> None: + super().__init__(parsed_json) + self.color: str = self._resolver(str, "couleur") + self.comments = [] + + for c in parsed_json["ListeAppreciations"]["V"]: + if "L" in c: + self.comments.append(c["L"]) -class Report(Object): - """Represents a student report. You shouldn't have to create this class manually. + self.class_average: str = self._resolver(Util.grade_parse, "MoyenneClasse", "V") + self.student_average: str = self._resolver( + Util.grade_parse, "MoyenneEleve", "V" + ) + self.min_average: str = self._resolver(Util.grade_parse, "MoyenneInf", "V") + self.max_average: str = self._resolver(Util.grade_parse, "MoyenneSup", "V") + self.coefficient: str = self._resolver(str, "Coefficient", "V") + self.teachers: List[str] = self._resolver( + lambda l: [i["L"] for i in l], "ListeProfesseurs", "V", default=[] + ) - Attributes: - published (bool): Is the report published ? - subjects (List[ReportSubject]): the subjects that are present in the report - comments (List[Comment]): the global report comments - """ + del self._resolver def __init__(self, parsed_json: dict) -> None: super().__init__(parsed_json) - self.subjects: List[ReportSubject] = self._resolver( - lambda l: [ReportSubject(s) for s in l], "ListeServices", "V", default=[] + self.subjects: List[self.ReportSubject] = self._resolver( + lambda l: [self.ReportSubject(s) for s in l], "ListeServices", "V", default=[] ) - self.comments: List[ReportComment] = self._resolver( - lambda l: [ReportComment(c) for c in l], + self.comments: List[str] = self._resolver( + lambda l: [c["L"] for c in l], "ObjetListeAppreciations", "V", "ListeAppreciations", @@ -701,39 +702,6 @@ def to_dict( include_properties=include_properties, ) - -class Comment(Object): - """ - Represents a comment (usually found in a report) - - Attributes: - id (str): The id of the comment (used internally) - comment (str): The actual comment - """ - - def __init__(self, json_dict: dict) -> None: - super().__init__(json_dict) - - self.id: str = self._resolver(str, "N", default="") - self.comment: str = self._resolver(str, "L", default="") - - -class ReportComment(Comment): - """ - Represents a report global comment. - - Attributes: - title (str): The title of the comment - """ - - def __init__(self, json_dict: dict) -> None: - super().__init__(json_dict) - - self.title: str = self._resolver(str, "Intitule", default="") - - del self._resolver - - class Attachment(Object): """ Represents a attachment to homework for example From 6c63840a0cd3cc66bc606a17d648bf58a7d196de Mon Sep 17 00:00:00 2001 From: Skythrew Date: Thu, 3 Aug 2023 11:33:21 +0200 Subject: [PATCH 13/17] add docs entry for Report class --- docs/source/api/data.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/source/api/data.rst b/docs/source/api/data.rst index 72b0cc5..4f089cf 100644 --- a/docs/source/api/data.rst +++ b/docs/source/api/data.rst @@ -81,3 +81,6 @@ from PRONOTE. It also includes a useful :class:`.Util` class. .. autoclass:: Punishment :members: + +.. autoclass:: Report + :members: \ No newline at end of file From afdcb31b3b1beee83d838521c71df38c591f6a9b Mon Sep 17 00:00:00 2001 From: Skythrew Date: Thu, 3 Aug 2023 14:51:28 +0200 Subject: [PATCH 14/17] convert for loop to resolver call --- pronotepy/dataClasses.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/pronotepy/dataClasses.py b/pronotepy/dataClasses.py index d9160bb..ac584a8 100644 --- a/pronotepy/dataClasses.py +++ b/pronotepy/dataClasses.py @@ -319,6 +319,7 @@ def __init__(self, parsed_json: dict) -> None: self.name: str = self._resolver(str, "L") self.groups: bool = self._resolver(bool, "estServiceGroupe", default=False) + class Report(Object): """Represents a student report. You shouldn't have to create this class manually. @@ -347,13 +348,12 @@ def __init__(self, parsed_json: dict) -> None: super().__init__(parsed_json) self.color: str = self._resolver(str, "couleur") - self.comments = [] - - for c in parsed_json["ListeAppreciations"]["V"]: - if "L" in c: - self.comments.append(c["L"]) - - self.class_average: str = self._resolver(Util.grade_parse, "MoyenneClasse", "V") + self.comments: List[str] = self._resolver( + lambda l: [c["L"] for c in l if "L" in c], "ListeAppreciations", "V" + ) + self.class_average: str = self._resolver( + Util.grade_parse, "MoyenneClasse", "V" + ) self.student_average: str = self._resolver( Util.grade_parse, "MoyenneEleve", "V" ) @@ -369,8 +369,11 @@ def __init__(self, parsed_json: dict) -> None: def __init__(self, parsed_json: dict) -> None: super().__init__(parsed_json) - self.subjects: List[self.ReportSubject] = self._resolver( - lambda l: [self.ReportSubject(s) for s in l], "ListeServices", "V", default=[] + self.subjects: List[Report.ReportSubject] = self._resolver( + lambda l: [Report.ReportSubject(s) for s in l], + "ListeServices", + "V", + default=[], ) self.comments: List[str] = self._resolver( lambda l: [c["L"] for c in l], @@ -380,7 +383,6 @@ def __init__(self, parsed_json: dict) -> None: "V", default=[], ) - self.published: bool = bool(self.comments) class Absence(Object): @@ -483,7 +485,7 @@ def report(self) -> Report: json_data = {"periode": {"G": 2, "N": self.id, "L": self.name}} response = self._client.post("PageBulletins", 13, json_data) return Report(response["donneesSec"]["donnees"]) - + @property def grades(self) -> List["Grade"]: """Get grades from the period.""" @@ -702,6 +704,7 @@ def to_dict( include_properties=include_properties, ) + class Attachment(Object): """ Represents a attachment to homework for example From 358655f19ff08868c0363d54fbb49fddeb1584c3 Mon Sep 17 00:00:00 2001 From: Skythrew Date: Thu, 3 Aug 2023 14:57:54 +0200 Subject: [PATCH 15/17] remove report "published" property test --- pronotepy/test_pronotepy.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pronotepy/test_pronotepy.py b/pronotepy/test_pronotepy.py index eaf600e..e9810b3 100644 --- a/pronotepy/test_pronotepy.py +++ b/pronotepy/test_pronotepy.py @@ -89,12 +89,6 @@ def test_report(self) -> None: self.assertIsInstance(report, pronotepy.Report) - def test_not_published_report(self) -> None: - report = client.periods[3].report - - self.assertFalse(report.published) - - class TestPeriod(unittest.TestCase): period: pronotepy.Period From 22c9da82ea6d341f4a38b96d2d340a87276ca9b1 Mon Sep 17 00:00:00 2001 From: bain Date: Thu, 3 Aug 2023 15:33:41 +0200 Subject: [PATCH 16/17] reformat test_pronotepy.py --- pronotepy/test_pronotepy.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pronotepy/test_pronotepy.py b/pronotepy/test_pronotepy.py index e9810b3..0285c44 100644 --- a/pronotepy/test_pronotepy.py +++ b/pronotepy/test_pronotepy.py @@ -89,6 +89,7 @@ def test_report(self) -> None: self.assertIsInstance(report, pronotepy.Report) + class TestPeriod(unittest.TestCase): period: pronotepy.Period From 7648d29424337daaf3103b76f48527208f1e44ba Mon Sep 17 00:00:00 2001 From: bain Date: Thu, 3 Aug 2023 19:58:43 +0200 Subject: [PATCH 17/17] change Report data classs and fetching behaviour Most fields on ReportSubject can be disabled by the supervisor, so they're Optional. Instead of having a Report.published attribute, the Period.report property can directly return none, since the report has no data anyway. --- pronotepy/dataClasses.py | 60 +++++++++++++++++++++++++------------ pronotepy/test_pronotepy.py | 9 +++--- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/pronotepy/dataClasses.py b/pronotepy/dataClasses.py index ac584a8..8d895fb 100644 --- a/pronotepy/dataClasses.py +++ b/pronotepy/dataClasses.py @@ -324,42 +324,56 @@ class Report(Object): """Represents a student report. You shouldn't have to create this class manually. Attributes: - published (bool): Is the report published ? subjects (List[ReportSubject]): the subjects that are present in the report comments (List[str]): the global report comments """ - class ReportSubject(Subject): + class ReportSubject(Object): """ Represents a subject found in a report. You shouldn't have to create this class manually. Attributes: + id (str): the id of the subject (used internally) + name (str): name of the subject color (str): the color of the subject comments (List[str]): the list of the subject's comments - class_average (str): the average of the class - student_average (str): the average of the student - min_average (str): the lowest average of the class - max_average (str): the highest average of the class - coefficient (str): the coefficient of the subject + class_average (Optional[str]): the average of the class + student_average (Optional[str]): the average of the student + min_average (Optional[str]): the lowest average of the class + max_average (Optional[str]): the highest average of the class + coefficient (Optional[str]): the coefficient of the subject teachers (List[str]): the subject's teachers' names """ def __init__(self, parsed_json: dict) -> None: super().__init__(parsed_json) + self.id: str = self._resolver(str, "N") + self.name: str = self._resolver(str, "L") + self.color: str = self._resolver(str, "couleur") self.comments: List[str] = self._resolver( lambda l: [c["L"] for c in l if "L" in c], "ListeAppreciations", "V" ) - self.class_average: str = self._resolver( - Util.grade_parse, "MoyenneClasse", "V" + + def grade_or_none(grade: Any) -> Optional[str]: + return Util.grade_parse(grade) if grade else None + + self.class_average: Optional[str] = self._resolver( + grade_or_none, "MoyenneClasse", "V", strict=False + ) + self.student_average: Optional[str] = self._resolver( + grade_or_none, "MoyenneEleve", "V", strict=False + ) + self.min_average: Optional[str] = self._resolver( + grade_or_none, "MoyenneInf", "V", strict=False ) - self.student_average: str = self._resolver( - Util.grade_parse, "MoyenneEleve", "V" + self.max_average: Optional[str] = self._resolver( + grade_or_none, "MoyenneSup", "V", strict=False + ) + self.coefficient: Optional[str] = self._resolver( + str, "Coefficient", "V", strict=False ) - self.min_average: str = self._resolver(Util.grade_parse, "MoyenneInf", "V") - self.max_average: str = self._resolver(Util.grade_parse, "MoyenneSup", "V") - self.coefficient: str = self._resolver(str, "Coefficient", "V") self.teachers: List[str] = self._resolver( lambda l: [i["L"] for i in l], "ListeProfesseurs", "V", default=[] ) @@ -376,7 +390,7 @@ def __init__(self, parsed_json: dict) -> None: default=[], ) self.comments: List[str] = self._resolver( - lambda l: [c["L"] for c in l], + lambda l: [c["L"] for c in l if "L" in c], "ObjetListeAppreciations", "V", "ListeAppreciations", @@ -480,11 +494,19 @@ def __init__(self, client: ClientBase, json_dict: dict) -> None: del self._resolver @property - def report(self) -> Report: - """Gets a report from a period""" + def report(self) -> Optional[Report]: + """ + Gets a report from a period. + + Returns: + Optional[Report]: + When ``None``, then the report is not yet published or is unavailable for any other reason + """ json_data = {"periode": {"G": 2, "N": self.id, "L": self.name}} - response = self._client.post("PageBulletins", 13, json_data) - return Report(response["donneesSec"]["donnees"]) + data = self._client.post("PageBulletins", 13, json_data)["donneesSec"][ + "donnees" + ] + return Report(data) if "Message" not in data else None @property def grades(self) -> List["Grade"]: diff --git a/pronotepy/test_pronotepy.py b/pronotepy/test_pronotepy.py index 0285c44..ae522c3 100644 --- a/pronotepy/test_pronotepy.py +++ b/pronotepy/test_pronotepy.py @@ -84,11 +84,6 @@ def test_refresh(self) -> None: client.refresh() self.assertEqual(client.session_check(), True) - def test_report(self) -> None: - report = client.periods[0].report - - self.assertIsInstance(report, pronotepy.Report) - class TestPeriod(unittest.TestCase): period: pronotepy.Period @@ -138,6 +133,10 @@ def test_class_overall_average(self) -> None: a = self.period.class_overall_average self.assertTrue(type(a) is str or a is None) + def test_report(self) -> None: + report = self.period.report + self.assertTrue(report is None or isinstance(report, pronotepy.Report)) + class TestInformation(unittest.TestCase): def test_unread(self) -> None: