11from leetcode .models import *
22
3- @dataclass
4- class Question ():
5- title : str
6- status : str
7- difficulty : str
8- frontendQuestionId : int
9- questionId : int
10-
113@dataclass
124class QueryResult (JSONWizard ):
5+ @dataclass
6+ class Question ():
7+ title : str
8+ status : str
9+ difficulty : str
10+ frontendQuestionId : int
11+ questionId : int
1312 total : int
1413 questions : List [Question ]
1514
@@ -18,7 +17,7 @@ def from_dict(cls, data):
1817 total = data ['problemsetQuestionList' ]['total' ]
1918 questions_data = data ['problemsetQuestionList' ]['questions' ]
2019 questions = [
21- Question (
20+ cls . Question (
2221 title = item .get ('title' ),
2322 status = item .get ('status' ),
2423 difficulty = item .get ('difficulty' ),
@@ -28,16 +27,13 @@ def from_dict(cls, data):
2827 for item in questions_data
2928 ]
3029 return cls (total = total , questions = questions )
31-
32- @dataclass
33- class TotalCount (JSONWizard ):
34- total : int
30+
3531class ProblemTotalCount (QueryTemplate ):
3632 def __init__ (self , filters = {}):
3733 super ().__init__ ()
3834 self .graphql_query = None
3935 self .result = None
40- self .params = {'categorySlug' : "" , 'skip' : 0 , 'limit' : 10 , 'filters' : filters }
36+ self .params = {'categorySlug' : '' , 'filters' : filters }
4137
4238 self .execute ()
4339
@@ -47,28 +43,110 @@ def execute(self):
4743
4844 def __call__ (self , * args : Any , ** kwds : Any ) -> Any :
4945 return self .result ['data' ]['problemsetQuestionList' ]['total' ]
50-
46+
5147
5248class ProblemsetQuestionList (QueryTemplate ):
49+ """ A class to represent a list of LeetCode problems.
50+
51+ Args:
52+ filters (dict, optional): Filters to apply to the query. Defaults to {}.
53+ - 'difficulty' (str, optional): Difficulty level. Valid values: 'EASY', 'MEDIUM', 'HARD'.
54+ - 'status' (str, optional): Status of the problem. Valid values: 'NOT_STARTED', 'TRIED', 'AC'.
55+ limit (int, optional): Maximum number of problems to retrieve. Defaults to None.
56+ skip (int, optional): Number of problems to skip. Defaults to 0.
57+ """
58+
5359 def __init__ (self , filters = {}, limit = None , skip = 0 ):
5460 super ().__init__ ()
61+
5562 # Instance specific variables
5663 self .page : int = 1
5764 self .max_page : int = 0
5865 self .filters = filters
5966 self .limit = limit or self .config .user_config .get ('question_list_limit' )
6067 self .skip = skip
6168
62- self .params = {'categorySlug' : "" , 'skip' :self .skip , 'limit' : self .limit , 'filters' : self .filters }
69+ self .params = {'categorySlug' : "" ,
70+ 'skip' :self .skip ,
71+ 'limit' : self .limit ,
72+ 'filters' : self .filters }
73+
6374 self .graphql_query = None
6475 self .result = None
6576
66-
67- def parse_args (self , args ):
77+ def fetch_data (self , parameters : Dict = None ) -> QueryResult :
78+ """ Fetches the data from the LeetCode API.
79+
80+ Args:
81+ parameters (dict, optional): Parameters to pass to the query. Defaults to None.
82+
83+ Returns:
84+ QueryResult: The result of the query.
85+ """
86+
87+ if parameters is None :
88+ parameters = self .params
89+ with Loader ('Fetching problems...' , '' ):
90+ self .graphql_query = GraphQLQuery (self .query , parameters )
91+ self .result = self .leet_API .post_query (self .graphql_query ) # Take the response from the API
92+ self .result = QueryResult .from_dict (self .result ['data' ])
93+ return self .result
94+
95+ def _execute (self , args ):
96+ """ Executes the query with the given arguments and displays the result.
97+
98+ Args:
99+ args (argparse.Namespace): The arguments passed to the query.
100+ """
101+
102+ self .__parse_args (args )
103+ self .result = self .fetch_data ()
104+ self .show (self .result )
105+
106+ def show (self , query_result : Optional [QueryResult ] = None ) -> None :
107+ """ Displays the query result in a table.
108+
109+ Args:
110+ query_result (QueryResult, optional): The result of the query. Defaults to None.
111+ If the result is None, the method will try to fetch the data with defauly parameters and than display it.
112+ """
113+
114+ if query_result is None :
115+ query_result = self .fetch_data ()
116+
117+ displayed : int = self .limit * self .page if self .limit * self .page < query_result .total else self .result .total
118+
119+ table = LeetTable (title = f'Total number of problems retrieved: { query_result .total } \n ' ,
120+ caption = f"Page #{ self .page } / ({ displayed } /{ self .result .total } )" )
121+
122+ table .add_column ('ID' )
123+ table .add_column ('Title' )
124+ table .add_column ('Status' )
125+ table .add_column ('Difficulty' )
126+ for item in query_result .questions :
127+ table .add_row (item .questionId , item .title , item .status , item .difficulty )
128+ console .print (table )
129+
130+ def __validate_page (self ):
131+ """ Validates the current page number.
132+ If the number is too large, sets the page number to the last page.
133+ """
134+
135+ count = ProblemTotalCount ().__call__ ()
136+ self .page = min (self .page , - (- count // self .limit ))
137+ self .params ['skip' ] = self .limit * self .page - self .limit # update the skip value
138+
139+ def __parse_args (self , args ):
140+ """ Parses the arguments passed to the query.
141+
142+ Args:
143+ args (argparse.Namespace): The arguments passed to the query.
144+ """
145+
68146 # Parse status argument
69147 status_mapping = {"solved" : "AC" ,
70- "todo" : "NOT_STARTED" ,
71- "attempted" : "TRIED" }
148+ "todo" : "NOT_STARTED" ,
149+ "attempted" : "TRIED" }
72150 status_argument = None
73151 for status_arg in status_mapping .keys ():
74152 if getattr (args , status_arg ):
@@ -81,42 +159,5 @@ def parse_args(self, args):
81159 # Parse the page argument
82160 self .page = getattr (args , 'page' )
83161 self .params ['skip' ] = self .limit * self .page - self .limit
84-
85- def execute (self , args ):
86- with Loader ('Fetching problem list...' , '' ):
87- self .parse_args (args )
88- self .validate_page ()
89-
90- self .graphql_query = GraphQLQuery (self .query , self .params )
91- self .result = self .leet_API .post_query (self .graphql_query ) # Take the response from the API
92- self .result = QueryResult .from_dict (self .result ['data' ]) # Put the response into the dataclass
93-
94- self .show ()
95-
96- def validate_page (self ):
97- """ Method to validate the page number. If number is too large,
98- set the page number to the last page."""
99- count = ProblemTotalCount ().__call__ ()
100- self .page = min (self .page , - (- count // self .limit ))
101- self .params ['skip' ] = self .limit * self .page - self .limit # update the skip value
102-
103- def show (self ):
104- displayed : int = self .limit * self .page if self .limit * self .page < self .result .total else self .result .total
105-
106-
107- table = LeetTable (title = f'Total number of problems retrieved: { self .result .total } \n ' ,
108- caption = f"Page #{ self .page } / ({ displayed } /{ self .result .total } )" )
109-
110- table .add_column ('ID' )
111- table .add_column ('Title' )
112- table .add_column ('Status' )
113- table .add_column ('Difficulty' )
114- for item in self .result .questions :
115- table .add_row (item .questionId , item .title , item .status , item .difficulty )
116- print (table )
117-
118- def get_data (self ):
119- self .graphql_query = GraphQLQuery (self .query , self .params )
120- self .result = self .leet_API .post_query (self .graphql_query )
121162
122- return self .result [ 'data' ]
163+ self .__validate_page ()
0 commit comments