opensource-nepal / py-nepali

py-nepali is a python package containing features that will be useful for Nepali projects.
MIT License
22 stars 13 forks source link

Fix flake8 C901 on datetime.parser.validators.transform #45

Closed aj3sh closed 1 year ago

aj3sh commented 1 year ago

While running the flake8 linting on this repo through the GitHub actions, an error C901 is raised. Below is the detailed error log.

./nepali/datetime/parser/validators.py:141:1: C901 'transform' is too complex (21)
1     C901 'transform' is too complex (21)

The file nepali/datetime/parser/validators.py contains the logic for date parsing and the transform method is part of it.

Major Flake8 issues were fixed through PR #44, but a cognitive complexity issue was still detected and left to be addressed in this issue.

Here is the code.

def transform(data: dict):
    """
    transforms different format data to uniform data

    eg.
    INPUT:
    data = {
        "Y": 2078,
        "b": "Mangsir",
        "d": 12,
        ...
    }

    OUTPUT:
    {
        "year": 2078,
        "month": 8,
        "day": 12,
        ...
    }
    """

    year = None
    month = day = 1
    hour = minute = second = fraction = 0
    weekday = None

    for date_key in data.keys():
        if date_key == "y":
            year = int(data["y"])
            year += 2000
        elif date_key == "Y":
            year = int(data["Y"])
        elif date_key == "m":
            month = int(data["m"])
        elif date_key == "B":
            month = nepalimonth(data["B"])
        elif date_key == "b":
            month = nepalimonth(data["b"])
        elif date_key == "d":
            day = int(data["d"])
        elif date_key == "H":
            hour = int(data["H"])
        elif date_key == "I":
            hour = int(data["I"])
            ampm = data.get("p", "").lower()
            # If there was no AM/PM indicator, we'll treat this like AM
            if ampm in ("", "am"):
                # We're in AM so the hour is correct unless we're
                # looking at 12 midnight.
                # 12 midnight == 12 AM == hour 0
                if hour == 12:
                    hour = 0
            elif ampm == "pm":
                # We're in PM so we need to add 12 to the hour unless
                # we're looking at 12 noon.
                # 12 noon == 12 PM == hour 12
                if hour != 12:
                    hour += 12
        elif date_key == "M":
            minute = int(data["M"])
        elif date_key == "S":
            second = int(data["S"])
        elif date_key == "f":
            s = data["f"]
            # Pad to always return microseconds.
            s += "0" * (6 - len(s))
            fraction = int(s)
        elif date_key == "A":
            weekday = nepaliweek(data["A"])
        elif date_key == "a":
            weekday = nepaliweek(data["a"])
        elif date_key == "w":
            weekday = int(data["w"])
            if weekday == 0:
                weekday = 6
            else:
                weekday -= 1
    return {
        "year": year,
        "month": month,
        "day": day,
        "hour": hour,
        "minute": minute,
        "second": second,
        "microsecond": fraction,
        "weekday": weekday,
    }
aj3sh commented 1 year ago

Here is a similar implementation on cpython's strptime. https://github.com/python/cpython/blob/bf89d4283a28dd00836f2c312a9255f543f93fc7/Lib/_strptime.py#L293

aj3sh commented 1 year ago

The conditions for the keys 'Y', 'm', 'd', 'M', and 'S' in the if statements are the same. Likewise, there are other keys that share the same conditions. We can combine them to reduce cognitive complexity.

aj3sh commented 1 year ago

cc: @sugat009