Python - Making A Valid Date Checker - using Regular Expressions Date Detection:
Write a regular expression that can detect dates in the DD/MM/YYYY format.
Assume that the days range from 01 to 31, the months range from 01
to 12, and the years range from 1000 to 2999. Note that if the day or month
is a single digit, it’ll have a leading zero.
Then store these strings into variables named month, day, and
year, and write additional code that can detect if it is a valid date.
April,
June, September, and November have 30 days, February has 28 days, and
the rest of the months have 31 days. February has 29 days in leap years.
Leap years are every year evenly divisible by 4, except for years evenly divisible by 100, unless the year is also evenly divisible by 400. Note how this calculation makes it impossible to make a reasonably sized regular expression
that can detect a valid date.
import re
def check_date(day, month, year):
    # April, June, September, November = 30 days/ February = 28 days, unless leapyear so 29/ rest has 31 days
    month_dict = {4: 30, 6: 30, 9: 30, 11: 30, 2: 28}
    day_bound = month_dict.get(month, 31)

    # month is february
    if day_bound == 28:
        # checks if the year is a leap year
        if year % 4 == 0:
            if year % 100 == 0:
                if year % 400 == 0:
                    day_bound = 29
            else:
                day_bound = 29

    # if the day is in the range of possible days
    if day &lt;= day_bound:
        return True
    return False
        


# DD/MM/YYYY
string = &quot;31/02/2020&quot;
date_regex = re.compile(r&quot;([0-2]\d|3[01])/(0\d|1[0-2])/([12]\d{3})&quot;)
match = date_regex.search(string)
valid = False
if match:
    day = int(match.group(1))
    month = int(match.group(2))
    year = int(match.group(3))
    valid = check_date(day, month, year)

if valid:
    print(f'Day: {day}, Month: {month}, Year: {year}')
else:
    print('Invalid Date!')
Docstrings / Type hints
These allow you to describe how your code works in a pythonic manner. Docstrings allow IDE's and other documentation tools to see what your function/class does. Type hints allow you to show what types of parameters are accepted, and what types of values are returned.
check_date
Instead of calculating a leap year yourself, you can use calendar.isleap from the calendar module.
Return comparisons, not raw booleans
Instead of
if day &lt;= day_bound:
    return True
return False

do this
return day &lt;= day_bound

Does the exact same thing, but looks a lot nicer.
Split code into functions
You've done a good job splitting your code into functions, but I think you could use one more. Instead of parsing the date in the &quot;main&quot; code, put that code in another function, and pass it the date string.
def get_date_values(...) -&gt; ...:
   ...

With all these changes, your final code would look something like this:
import re
import calendar
from typing import Tuple, Union

def check_date(day: int, month: int, year: int) -&gt; bool:
    &quot;&quot;&quot;
    Returns a bool based on if the date passed is a valid date.

    :param int day: Day.
    :param int month: Month.
    :param int year: Year.

    :return: True if a valid date, False otherwise.
    &quot;&quot;&quot;
    # April, June, September, November = 30 days/ February = 28 days, unless leapyear so 29/ rest has 31 days
    month_dict = {4: 30, 6: 30, 9: 30, 11: 30, 2: 28}
    day_bound = month_dict.get(month, 31)

    if day_bound == 28:
        if calendar.isleap(year):
            day_bound = 29

    return day &lt;= day_bound


def get_date_values(date: str) -&gt; Union[Tuple[int, int, int], None]:
    &quot;&quot;&quot;
    Returns a tuple containing the day, month, and year of the passed date.

    :param str date: Date to parse and retrieve values.

    :return: Either a Tuple, or for an invalid date, None.
    &quot;&quot;&quot;
    date_regex = re.compile(r&quot;([0-2]\d|3[01])/(0\d|1[0-2])/([12]\d{3})&quot;)
    match = date_regex.search(date)
    if match:
        return (int(match.group(1)), int(match.group(2)), int(match.group(3)))
    return None


if __name__ == &quot;__main__&quot;:
    date = &quot;31/02/2020&quot; #DD/MM/YYYY
    if check_date(*get_date_values(date)):
        print('Valid Date!')
    else:
        print('Invalid Date!')

I'll explain a bit more since I made some changes I haven't mentioned already.
Unpacking
if check_date(*get_date_values(date)):

This line unpacks each item from the tuple returned by get_date_values and passes them to the function. Since the tuple has three values, and check_date accepts three parameters, the * unpacks the tuple and passes each value to the function.