Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moved TODOs into github issues #32

Merged
merged 1 commit into from
May 13, 2024
Merged

Moved TODOs into github issues #32

merged 1 commit into from
May 13, 2024

Conversation

madeddie
Copy link
Owner

@madeddie madeddie commented May 13, 2024

Summary by CodeRabbit

  • Refactor
    • Improved code organization and functionality by removing outdated TODO comments and restructuring functions.
    • Enhanced argument parsing and file handling to prevent overwrites and improve error management.

Copy link
Contributor

coderabbitai bot commented May 13, 2024

Walkthrough

The recent updates to the codebase reflect a shift towards enhanced functionality and cleaner code. Major improvements include the removal of outdated TODO comments, the integration of better argument parsing mechanisms, and enhanced file handling processes. These changes suggest a move towards a more robust and user-friendly system.

Changes

File Path Change Summary
.../moocfi_cses.py Removed TODO comments, enhanced argument parsing with potential click integration, improved file overwrite handling, and function restructuring.

Poem

🐰✨
In the land of code, where the snippets play,
Changes abound in a most delightful way.
TODOs vanish, functions align,
With every commit, the code does shine.
Hoppity hop, on paths anew,
CodeRabbit's joy, shared with you! 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@senior-dev-bot senior-dev-bot bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feedback from Senior Dev Bot

Comment on lines 35 to 40
login_text = login_link.get("text") or ""
return self.username in login_text

# TODO: create custom exceptions
def login(self) -> None:
"""Logs into the site using webscraping

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CODE REVIEW

The removal of the comment "TODO: create custom exceptions" suggests you might have addressed custom exception handling elsewhere. However, it's crucial to ensure that exception handling, especially custom exceptions, is implemented for robust error management. Custom exceptions could improve clarity and maintainability.

Consider defining exceptions like LoginError:

class LoginError(Exception):
    """Exception raised for errors during login."""
    pass

And using it in your login method:

def login(self) -> None:
    try:
        # login logic here
        pass
    except Exception as e:
        raise LoginError("Failed to log in") from e

Comment on lines 288 to 293
return task_list


# TODO: This should be part of a UI class or module
def print_task_list(
task_list: list[Task], filter: Optional[str] = None, limit: Optional[int] = None
) -> None:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CODE REVIEW

The refactoring into a UI class or module is a great idea for code organization and readability. However, consider implementing type hinting for list[Task] more explicitly if Task is a custom class. Use from typing import List and define the type of elements within the list for improved clarity.

from typing import List, Optional
from your_project.task import Task  # Assuming Task is a custom class

class UITaskManager:
    @staticmethod
    def print_task_list(
        task_list: List[Task], filter: Optional[str] = None, limit: Optional[int] = None
    ) -> None:
        # Implementation here

This change facilitates readability and future maintenance by clarifying that task_list is a list of Task instances.

Comment on lines 149 to 154


def create_config() -> dict[str, str]:
# TODO: try to read an existing config file and give the values as default values
username = input("Your tmc.mooc.fi username: ")
password = getpass("Your tmc.mooc.fi password: ")
config = {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CODE REVIEW

The removed TODO comment suggests implementing functionality to read an existing config file for default values. It's crucial to provide a fallback or initialization from existing configurations to enhance user experience and prevent unnecessary reconfigurations.

Consider using a function to attempt reading an existing config file, and if it exists, load these values as defaults:

import json

def read_existing_config() -> dict[str, str]:
    try:
        with open('config.json', 'r') as file:
            return json.load(file)
    except FileNotFoundError:
        return {}

def create_config() -> dict[str, str]:
    existing_config = read_existing_config()
    username = input("Your tmc.mooc.fi username: ") or existing_config.get('username', '')
    password = getpass("Your tmc.mooc.fi password: ") or existing_config.get('password', '')
    config = {

This approach improves the function by providing a smoother setup or re-setup experience.

Comment on lines 100 to 105
return res.text


# TODO: replace with click
def parse_args(args: Optional[list[str]] = None) -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Interact with mooc.fi CSES instance")
parser.add_argument("--username", help="tmc.mooc.fi username")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CODE REVIEW

This change suggests an intent to replace argparse with click but hasn't been implemented yet. While argparse is a robust option for command-line interface creation, click can offer a more straightforward syntax and automatic help page generation. Since the code changes are minimal and the transition to click isn't shown, I recommend:

  1. Implement click to see the benefits of cleaner syntax and easier command line options handling.

Example with click:

import click

@click.command()
@click.option('--username', help='tmc.mooc.fi username')
def main(username):
    click.echo(f"Hello, {username}")
  1. Complete the TODO before merging.

Comment on lines 159 to 175
return config


# TODO: check if file exists and ask permission to overwrite
def write_config(configfile: str, config: dict[str, str]) -> None:
file_path = Path(configfile).expanduser()
if file_path.exists():
# TODO: check if file exists and ask permission to overwrite
# Prompt user or handle file overwrite scenario
# TODO: https://github.com/madeddie/moocfi_cses/issues/28
...
file_path.parent.mkdir(parents=True, exist_ok=True) # Ensure directory exists
print("Writing config to file")
with open(file_path, "w") as f:
json.dump(config, f)


# TODO: check if path exists
# TODO: try/except around open and json.load, return empty dict on failure
def read_config(configfile: str) -> dict[str, str]:
config = dict()
file_path = Path(configfile).expanduser()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CODE REVIEW

The change replacing specific TODO comments with a link to an issue is a good practice for tracking, but ensure the issue contains clear instructions or code examples on the solution. For the write_config function, handling file overwrite by asking for user permission is crucial for user experience and preventing accidental data loss.

Instead of a placeholder or generic comments, consider implementing an interactive prompt or a mechanism to backup before overwriting, e.g.:

from shutil import copy

if file_path.exists():
    overwrite = input(f"{file_path} exists. Overwrite? (y/n): ").strip().lower()
    if overwrite == 'y':
        backup_path = f"{file_path}.bak"
        copy(file_path, backup_path)
        print(f"Backup created at {backup_path}")
    else:
        print("Operation cancelled.")
        return

For read_config, indeed adding try/except around file opening and loading is important for robustness:

try:
    with open(file_path, 'r') as f:
        config = json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
    return {}

Comment on lines 341 to 346
print(f"\nSubmission file name: {task.submit_file}")


# TODO: Implement function that posts the submit form with the correct file
def submit_task(task_id: str, filename: str) -> None:
"""submit file to the submit form or task_id"""
# NOTE: use parse_form

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CODE REVIEW

It seems you intend to implement a feature to submit tasks. A few suggestions to improve the current changes:

  1. Docstring Improvement: Ensure your docstring accurately describes the function, including its parameters and what it returns or accomplishes. Since the function is not yet implemented, consider noting that it's a work in progress.

  2. Use of TODOs: It's good you've noted the need to implement the function but ensure in subsequent commits the implementation follows soon after for maintainability.

  3. Function Implementation Placeholder: If the function is incomplete, perhaps raise a NotImplementedError as a placeholder to avoid silent failures if the function is mistakenly called.

Example:

def submit_task(task_id: str, filename: str) -> None:
    """
    Submit file to the submit form for a given task_id.
    
    Parameters:
    - task_id: The ID of the task to submit to.
    - filename: The name of the file to submit.
    
    Returns:
    None. Submits the task and handles the submission process.
    """
    raise NotImplementedError("Function submit_task is not yet implemented.")

Comment on lines 1 to 3
import argparse
from dataclasses import dataclass, field
from enum import Enum

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CODE REVIEW

Your changes indicate the removal of several TODO comments and the import of argparse, dataclasses, and enum. It seems like you're preparing for some argument parsing and structured data handling. A few suggestions:

  1. Comment Removal: If these TODOs were removed because they've been implemented, consider ensuring there's clear documentation or comments in place where each task was addressed.
  2. Data Handling: Using dataclass and Enum is a good choice for clean and efficient data representation. Ensure each dataclass and Enum is well-defined and includes type hints for clarity.

Example:

from enum import Enum
from dataclasses import dataclass

class Status(Enum):
    TODO = "TODO"
    IN_PROGRESS = "IN_PROGRESS"
    DONE = "DONE"

@dataclass
class Exercise:
    name: str
    status: Status
    week: int = field(default=0)
    deadline: str = field(default="")
  1. Argument Parsing: It's great you're setting up for command-line interaction. Make sure to define clear, user-friendly arguments with argparse, including help descriptions for each argument.

Remember, well-commented code and clear structure are key to maintainability and overall project health.

Comment on lines 300 to 305
return


# TODO: Implement function that parser the specific task page into Task object
# TODO: should we split up this function in a bunch of smaller ones? or will beautifulsoup make it simpler?
def parse_task(html: AnyStr) -> Task:
root = htmlement.fromstring(html)
task_link_element = root.find('.//div[@class="nav sidebar"]/a')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CODE REVIEW

The implementation of parse_task is a good start. However, there are a few points to consider:

  1. The removal of TODO comments without apparent implementation hints at unfinished work or missing functionality. Ensure all intended features are implemented or tracked elsewhere.

  2. For readability and future maintenance, adding type annotations for the return type of htmlement.fromstring(html) would be helpful, assuming root has a specific type that could be annotated.

  3. It might be beneficial to consider error handling if .find does not locate the element, preventing potential runtime errors.

Here's a potential improvement:

from typing import Optional  # If not already imported

def parse_task(html: AnyStr) -> Optional[Task]:
    try:
        root = htmlement.fromstring(html)  # Assuming root's type can be more specifically annotated
        task_link_element = root.find('.//div[@class="nav sidebar"]/a')
        if not task_link_element:
            return None  # Or handle absence in another way
        # Process task_link_element into a Task object...
    except Exception as e:
        # Properly handle or log the exception
        return None

This adjustment adds robustness against potential parsing failures and clarifies the handling of cases where elements are not found.

Comment on lines 256 to 261
submit_file: str = "N/A"


# TODO: this should be part of a client class or module
def parse_task_list(html: AnyStr) -> list[Task]:
"""Parse html to find tasks and their status, return something useful, possibly a specific data class"""
content_element = htmlement.fromstring(html).find('.//div[@class="content"]')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CODE REVIEW

The code correctly identifies the need for organizing the parse_task_list function into a client class or module for better structure. This change encapsulates functionality and could enable easy maintenance and scalability.

However, ensure AnyStr from typing is used appropriately to accept both str and bytes types. If only one is expected, use str or bytes instead for clarity.

Consider introducing a data class for Task to ensure the returned list has a well-defined structure, improving code readability and safety.

Example improvement:

from typing import List
from dataclasses import dataclass

@dataclass
class Task:
    # Assuming tasks attributes here
    id: int
    status: str

class TaskParser:
    @staticmethod
    def parse_task_list(html: str) -> List[Task]:
        content_element = htmlement.fromstring(html).find('.//div[@class="content"]')
        # Parsing logic here
        return [Task(id=1, status='Complete')]  # Example return

Copy link

============================= test session starts ==============================
platform linux -- Python 3.10.14, pytest-8.2.0, pluggy-1.5.0
rootdir: /home/runner/work/moocfi_cses/moocfi_cses
plugins: requests-mock-1.12.1, cov-5.0.0
collected 11 items

tests/test_moocfi_cses.py ...........                                    [100%]

---------- coverage: platform linux, python 3.10.14-final-0 ----------
Name                        Stmts   Miss  Cover
-----------------------------------------------
moocfi_cses.py                219    118    46%
tests/__init__.py               0      0   100%
tests/test_moocfi_cses.py      48      0   100%
-----------------------------------------------
TOTAL                         267    118    56%


============================== 11 passed in 0.10s ==============================

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between b5bf07c and 68aa9aa.
Files selected for processing (1)
  • moocfi_cses.py (9 hunks)
Files skipped from review due to trivial changes (1)
  • moocfi_cses.py

@madeddie madeddie merged commit 63f2c3d into main May 13, 2024
1 check passed
@madeddie madeddie deleted the remove_todos branch May 13, 2024 18:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant