psf / black

The uncompromising Python code formatter
https://black.readthedocs.io/en/stable/
MIT License
38.85k stars 2.45k forks source link

Fix Formatting Errors on black-primer CI #1446

Closed cooperlees closed 3 years ago

cooperlees commented 4 years ago

Black Primer (black-primer) is now running on Black's CI. It git clone's some popular Python projects that use Black and ensure we don't hit errors. Today this is not true, and we hit invalid formatting on 3 projects. They are:

They all return error 123.

Repro:

cd black-repo
python3 -m venv /tmp/b
source /tmp/b/bin/activate
pip install --upgrade setuptools pip wheel
pip install -e .[d]
hugovk commented 4 years ago

pytest is the same as #1452, here's the relevant snippet from pytest/testing/test_capture.py. It's the double quote just before the docstring ends:

class TestTeeStdCapture(TestStdCapture):
    captureclass = staticmethod(TeeStdCapture)

    def test_capturing_error_recursive(self):
        """ for TeeStdCapture since we passthrough stderr/stdout, cap1
        should get all output, while cap2 should only get "cap2\n" """

        with self.getcapture() as cap1:
            print("cap1")
            with self.getcapture() as cap2:
                print("cap2")
                out2, err2 = cap2.readouterr()
                out1, err1 = cap1.readouterr()
        assert out1 == "cap1\ncap2\n"
        assert out2 == "cap2\n"
error: cannot format /Users/hugo/github/pytest/testing/test_capture.py: INTERNAL ERROR: Black produced invalid code: invalid syntax (<unknown>, line 418). Please report a bug on https://github.com/psf/black/issues.  This invalid output might be helpful: /var/folders/kt/j77sf4_n6fnbx6pg199rbx700000gn/T/blk_1n8s7tln.log
hugovk commented 4 years ago

pandas has 3 errors:

1

error: cannot format /private/tmp/pandas/pandas/core/tools/datetimes.py: INTERNAL ERROR: Black produced code that is not equivalent to the source.  Please report a bug on https://github.com/psf/black/issues.  This diff might be helpful: /var/folders/kt/j77sf4_n6fnbx6pg199rbx700000gn/T/blk_kd9k1jqa.log
--- src
+++ dst
@@ -7269,11 +7269,11 @@
       body=
         Expr(
           value=
             Constant(
               value=
-                'Convert argument to datetime.\n\n Parameters\n ----------\n arg : int, float, str, datetime, list, tuple, 1-d array, Series, DataFrame/dict-like\n The object to convert to a datetime.\n errors : {\'ignore\', \'raise\', \'coerce\'}, default \'raise\'\n - If \'raise\', then invalid parsing will raise an exception.\n - If \'coerce\', then invalid parsing will be set as NaT.\n - If \'ignore\', then invalid parsing will return the input.\n dayfirst : bool, default False\n Specify a date parse order if `arg` is str or its list-likes.\n If True, parses dates with the day first, eg 10/11/12 is parsed as\n 2012-11-10.\n Warning: dayfirst=True is not strict, but will prefer to parse\n with day first (this is a known bug, based on dateutil behavior).\n yearfirst : bool, default False\n Specify a date parse order if `arg` is str or its list-likes.\n\n - If True parses dates with the year first, eg 10/11/12 is parsed as\n 2010-11-12.\n - If both dayfirst and yearfirst are True, yearfirst is preceded (same\n as dateutil).\n\n Warning: yearfirst=True is not strict, but will prefer to parse\n with year first (this is a known bug, based on dateutil behavior).\n utc : bool, default None\n Return UTC DatetimeIndex if True (converting any tz-aware\n datetime.datetime objects as well).\n format : str, default None\n The strftime to parse time, eg "%d/%m/%Y", note that "%f" will parse\n all the way up to nanoseconds.\n See strftime documentation for more information on choices:\n https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior.\n exact : bool, True by default\n Behaves as:\n - If True, require an exact format match.\n - If False, allow the format to match anywhere in the target string.\n\n unit : str, default \'ns\'\n The unit of the arg (D,s,ms,us,ns) denote the unit, which is an\n integer or float number. This will be based off the origin.\n Example, with unit=\'ms\' and origin=\'unix\' (the default), this\n would calculate the number of milliseconds to the unix epoch start.\n infer_datetime_format : bool, default False\n If True and no `format` is given, attempt to infer the format of the\n datetime strings based on the first non-NaN element,\n and if it can be inferred, switch to a faster method of parsing them.\n In some cases this can increase the parsing speed by ~5-10x.\n origin : scalar, default \'unix\'\n Define the reference date. The numeric values would be parsed as number\n of units (defined by `unit`) since this reference date.\n\n - If \'unix\' (or POSIX) time; origin is set to 1970-01-01.\n - If \'julian\', unit must be \'D\', and origin is set to beginning of\n Julian Calendar. Julian day number 0 is assigned to the day starting\n at noon on January 1, 4713 BC.\n - If Timestamp convertible, origin is set to Timestamp identified by\n origin.\n cache : bool, default True\n If True, use a cache of unique, converted dates to apply the datetime\n conversion. May produce significant speed-up when parsing duplicate\n date strings, especially ones with timezone offsets. The cache is only\n used when there are at least 50 values. The presence of out-of-bounds\n values will render the cache unusable and may slow down parsing.\n\n .. versionadded:: 0.23.0\n\n .. versionchanged:: 0.25.0\n - changed default value from False to True.\n\n Returns\n -------\n datetime\n If parsing succeeded.\n Return type depends on input:\n\n - list-like: DatetimeIndex\n - Series: Series of datetime64 dtype\n - scalar: Timestamp\n\n In case when it is not possible to return designated types (e.g. when\n any element of input is before Timestamp.min or after Timestamp.max)\n return will have datetime.datetime type (or corresponding\n array/Series).\n\n See Also\n --------\n DataFrame.astype : Cast argument to a specified dtype.\n to_timedelta : Convert argument to timedelta.\n convert_dtypes : Convert dtypes.\n\n Examples\n --------\n Assembling a datetime from multiple columns of a DataFrame. The keys can be\n common abbreviations like [\'year\', \'month\', \'day\', \'minute\', \'second\',\n \'ms\', \'us\', \'ns\']) or plurals of the same\n\n >>> df = pd.DataFrame({\'year\': [2015, 2016],\n ...                    \'month\': [2, 3],\n ...                    \'day\': [4, 5]})\n >>> pd.to_datetime(df)\n 0   2015-02-04\n 1   2016-03-05\n dtype: datetime64[ns]\n\n If a date does not meet the `timestamp limitations\n <https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html\n #timeseries-timestamp-limits>`_, passing errors=\'ignore\'\n will return the original input instead of raising any exception.\n\n Passing errors=\'coerce\' will force an out-of-bounds date to NaT,\n in addition to forcing non-dates (or non-parseable dates) to NaT.\n\n >>> pd.to_datetime(\'13000101\', format=\'%Y%m%d\', errors=\'ignore\')\n datetime.datetime(1300, 1, 1, 0, 0)\n >>> pd.to_datetime(\'13000101\', format=\'%Y%m%d\', errors=\'coerce\')\n NaT\n\n Passing infer_datetime_format=True can often-times speedup a parsing\n if its not an ISO8601 format exactly, but in a regular format.\n\n >>> s = pd.Series([\'3/11/2000\', \'3/12/2000\', \'3/13/2000\'] * 1000)\n >>> s.head()\n 0    3/11/2000\n 1    3/12/2000\n 2    3/13/2000\n 3    3/11/2000\n 4    3/12/2000\n dtype: object\n\n >>> %timeit pd.to_datetime(s, infer_datetime_format=True)  # doctest: +SKIP\n 100 loops, best of 3: 10.4 ms per loop\n\n >>> %timeit pd.to_datetime(s, infer_datetime_format=False)  # doctest: +SKIP\n 1 loop, best of 3: 471 ms per loop\n\n Using a unix epoch time\n\n >>> pd.to_datetime(1490195805, unit=\'s\')\n Timestamp(\'2017-03-22 15:16:45\')\n >>> pd.to_datetime(1490195805433502912, unit=\'ns\')\n Timestamp(\'2017-03-22 15:16:45.433502912\')\n\n .. warning:: For float arg, precision rounding might happen. To prevent\n unexpected behavior use a fixed-width exact type.\n\n Using a non-unix epoch origin\n\n >>> pd.to_datetime([1, 2, 3], unit=\'D\',\n ...                origin=pd.Timestamp(\'1960-01-01\'))\n DatetimeIndex([\'1960-01-02\', \'1960-01-03\', \'1960-01-04\'], dtype=\'datetime64[ns]\', freq=None)',  # str
+                'Convert argument to datetime.\n\n Parameters\n ----------\n arg : int, float, str, datetime, list, tuple, 1-d array, Series, DataFrame/dict-like\n The object to convert to a datetime.\n errors : {\'ignore\', \'raise\', \'coerce\'}, default \'raise\'\n - If \'raise\', then invalid parsing will raise an exception.\n - If \'coerce\', then invalid parsing will be set as NaT.\n - If \'ignore\', then invalid parsing will return the input.\n dayfirst : bool, default False\n Specify a date parse order if `arg` is str or its list-likes.\n If True, parses dates with the day first, eg 10/11/12 is parsed as\n 2012-11-10.\n Warning: dayfirst=True is not strict, but will prefer to parse\n with day first (this is a known bug, based on dateutil behavior).\n yearfirst : bool, default False\n Specify a date parse order if `arg` is str or its list-likes.\n\n - If True parses dates with the year first, eg 10/11/12 is parsed as\n 2010-11-12.\n - If both dayfirst and yearfirst are True, yearfirst is preceded (same\n as dateutil).\n\n Warning: yearfirst=True is not strict, but will prefer to parse\n with year first (this is a known bug, based on dateutil behavior).\n utc : bool, default None\n Return UTC DatetimeIndex if True (converting any tz-aware\n datetime.datetime objects as well).\n format : str, default None\n The strftime to parse time, eg "%d/%m/%Y", note that "%f" will parse\n all the way up to nanoseconds.\n See strftime documentation for more information on choices:\n https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior.\n exact : bool, True by default\n Behaves as:\n - If True, require an exact format match.\n - If False, allow the format to match anywhere in the target string.\n\n unit : str, default \'ns\'\n The unit of the arg (D,s,ms,us,ns) denote the unit, which is an\n integer or float number. This will be based off the origin.\n Example, with unit=\'ms\' and origin=\'unix\' (the default), this\n would calculate the number of milliseconds to the unix epoch start.\n infer_datetime_format : bool, default False\n If True and no `format` is given, attempt to infer the format of the\n datetime strings based on the first non-NaN element,\n and if it can be inferred, switch to a faster method of parsing them.\n In some cases this can increase the parsing speed by ~5-10x.\n origin : scalar, default \'unix\'\n Define the reference date. The numeric values would be parsed as number\n of units (defined by `unit`) since this reference date.\n\n - If \'unix\' (or POSIX) time; origin is set to 1970-01-01.\n - If \'julian\', unit must be \'D\', and origin is set to beginning of\n Julian Calendar. Julian day number 0 is assigned to the day starting\n at noon on January 1, 4713 BC.\n - If Timestamp convertible, origin is set to Timestamp identified by\n origin.\n cache : bool, default True\n If True, use a cache of unique, converted dates to apply the datetime\n conversion. May produce significant speed-up when parsing duplicate\n date strings, especially ones with timezone offsets. The cache is only\n used when there are at least 50 values. The presence of out-of-bounds\n values will render the cache unusable and may slow down parsing.\n\n .. versionadded:: 0.23.0\n\n .. versionchanged:: 0.25.0\n - changed default value from False to True.\n\n Returns\n -------\n datetime\n If parsing succeeded.\n Return type depends on input:\n\n - list-like: DatetimeIndex\n - Series: Series of datetime64 dtype\n - scalar: Timestamp\n\n In case when it is not possible to return designated types (e.g. when\n any element of input is before Timestamp.min or after Timestamp.max)\n return will have datetime.datetime type (or corresponding\n array/Series).\n\n See Also\n --------\n DataFrame.astype : Cast argument to a specified dtype.\n to_timedelta : Convert argument to timedelta.\n convert_dtypes : Convert dtypes.\n\n Examples\n --------\n Assembling a datetime from multiple columns of a DataFrame. The keys can be\n common abbreviations like [\'year\', \'month\', \'day\', \'minute\', \'second\',\n \'ms\', \'us\', \'ns\']) or plurals of the same\n\n >>> df = pd.DataFrame({\'year\': [2015, 2016],\n ...                    \'month\': [2, 3],\n ...                    \'day\': [4, 5]})\n >>> pd.to_datetime(df)\n 0   2015-02-04\n 1   2016-03-05\n dtype: datetime64[ns]\n\n If a date does not meet the `timestamp limitations\n <https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html\n #timeseries-timestamp-limits>`_, passing errors=\'ignore\'\n will return the original input instead of raising any exception.\n\n Passing errors=\'coerce\' will force an out-of-bounds date to NaT,\n in addition to forcing non-dates (or non-parseable dates) to NaT.\n\n >>> pd.to_datetime(\'13000101\', format=\'%Y%m%d\', errors=\'ignore\')\n datetime.datetime(1300, 1, 1, 0, 0)\n >>> pd.to_datetime(\'13000101\', format=\'%Y%m%d\', errors=\'coerce\')\n NaT\n\n Passing infer_datetime_format=True can often-times speedup a parsing\n if its not an ISO8601 format exactly, but in a regular format.\n\n >>> s = pd.Series([\'3/11/2000\', \'3/12/2000\', \'3/13/2000\'] * 1000)\n >>> s.head()\n 0    3/11/2000\n 1    3/12/2000\n 2    3/13/2000\n 3    3/11/2000\n 4    3/12/2000\n dtype: object\n\n >>> %timeit pd.to_datetime(s, infer_datetime_format=True)  # doctest: +SKIP\n 100 loops, best of 3: 10.4 ms per loop\n\n >>> %timeit pd.to_datetime(s, infer_datetime_format=False)  # doctest: +SKIP\n 1 loop, best of 3: 471 ms per loop\n\n Using a unix epoch time\n\n >>> pd.to_datetime(1490195805, unit=\'s\')\n Timestamp(\'2017-03-22 15:16:45\')\n >>> pd.to_datetime(1490195805433502912, unit=\'ns\')\n Timestamp(\'2017-03-22 15:16:45.433502912\')\n\n .. warning:: For float arg, precision rounding might happen. To prevent\n unexpected behavior use a fixed-width exact type.\n\n Using a non-unix epoch origin\n\n >>> pd.to_datetime([1, 2, 3], unit=\'D\',\n ...                origin=pd.Timestamp(\'1960-01-01\'))\n DatetimeIndex([\'1960-01-02\', \'1960-01-03\', \'1960-01-04\'],     dtype=\'datetime64[ns]\', freq=None)',  # str
             )  # /Constant
         )  # /Expr
         If(
           body=
             Return(

2

error: cannot format /private/tmp/pandas/pandas/core/arrays/datetimes.py: INTERNAL ERROR: Black produced code that is not equivalent to the source.  Please report a bug on https://github.com/psf/black/issues.  This diff might be helpful: /var/folders/kt/j77sf4_n6fnbx6pg199rbx700000gn/T/blk_4dzg5_i5.log
--- src
+++ dst
@@ -12384,11 +12384,11 @@
           body=
             Expr(
               value=
                 Constant(
                   value=
-                    "Localize tz-naive Datetime Array/Index to tz-aware\n Datetime Array/Index.\n\n This method takes a time zone (tz) naive Datetime Array/Index object\n and makes this time zone aware. It does not move the time to another\n time zone.\n Time zone localization helps to switch from time zone aware to time\n zone unaware objects.\n\n Parameters\n ----------\n tz : str, pytz.timezone, dateutil.tz.tzfile or None\n Time zone to convert timestamps to. Passing ``None`` will\n remove the time zone information preserving local time.\n ambiguous : 'infer', 'NaT', bool array, default 'raise'\n When clocks moved backward due to DST, ambiguous times may arise.\n For example in Central European Time (UTC+01), when going from\n 03:00 DST to 02:00 non-DST, 02:30:00 local time occurs both at\n 00:30:00 UTC and at 01:30:00 UTC. In such a situation, the\n `ambiguous` parameter dictates how ambiguous times should be\n handled.\n\n - 'infer' will attempt to infer fall dst-transition hours based on\n order\n - bool-ndarray where True signifies a DST time, False signifies a\n non-DST time (note that this flag is only applicable for\n ambiguous times)\n - 'NaT' will return NaT where there are ambiguous times\n - 'raise' will raise an AmbiguousTimeError if there are ambiguous\n times.\n\n nonexistent : 'shift_forward', 'shift_backward, 'NaT', timedelta, default 'raise'\n A nonexistent time does not exist in a particular timezone\n where clocks moved forward due to DST.\n\n - 'shift_forward' will shift the nonexistent time forward to the\n closest existing time\n - 'shift_backward' will shift the nonexistent time backward to the\n closest existing time\n - 'NaT' will return NaT where there are nonexistent times\n - timedelta objects will shift nonexistent times by the timedelta\n - 'raise' will raise an NonExistentTimeError if there are\n nonexistent times.\n\n .. versionadded:: 0.24.0\n\n Returns\n -------\n Same type as self\n Array/Index converted to the specified time zone.\n\n Raises\n ------\n TypeError\n If the Datetime Array/Index is tz-aware and tz is not None.\n\n See Also\n --------\n DatetimeIndex.tz_convert : Convert tz-aware DatetimeIndex from\n one time zone to another.\n\n Examples\n --------\n >>> tz_naive = pd.date_range('2018-03-01 09:00', periods=3)\n >>> tz_naive\n DatetimeIndex(['2018-03-01 09:00:00', '2018-03-02 09:00:00',\n '2018-03-03 09:00:00'],\n dtype='datetime64[ns]', freq='D')\n\n Localize DatetimeIndex in US/Eastern time zone:\n\n >>> tz_aware = tz_naive.tz_localize(tz='US/Eastern')\n >>> tz_aware\n DatetimeIndex(['2018-03-01 09:00:00-05:00',\n '2018-03-02 09:00:00-05:00',\n '2018-03-03 09:00:00-05:00'],\n dtype='datetime64[ns, US/Eastern]', freq=None)\n\n With the ``tz=None``, we can remove the time zone information\n while keeping the local time (not converted to UTC):\n\n >>> tz_aware.tz_localize(None)\n DatetimeIndex(['2018-03-01 09:00:00', '2018-03-02 09:00:00',\n '2018-03-03 09:00:00'],\n dtype='datetime64[ns]', freq=None)\n\n Be careful with DST changes. When there is sequential data, pandas can\n infer the DST time:\n\n >>> s = pd.to_datetime(pd.Series(['2018-10-28 01:30:00',\n ...                               '2018-10-28 02:00:00',\n ...                               '2018-10-28 02:30:00',\n ...                               '2018-10-28 02:00:00',\n ...                               '2018-10-28 02:30:00',\n ...                               '2018-10-28 03:00:00',\n ...                               '2018-10-28 03:30:00']))\n >>> s.dt.tz_localize('CET', ambiguous='infer')\n 0   2018-10-28 01:30:00+02:00\n 1   2018-10-28 02:00:00+02:00\n 2   2018-10-28 02:30:00+02:00\n 3   2018-10-28 02:00:00+01:00\n 4   2018-10-28 02:30:00+01:00\n 5   2018-10-28 03:00:00+01:00\n 6   2018-10-28 03:30:00+01:00\n dtype: datetime64[ns, CET]\n\n In some cases, inferring the DST is impossible. In such cases, you can\n pass an ndarray to the ambiguous parameter to set the DST explicitly\n\n >>> s = pd.to_datetime(pd.Series(['2018-10-28 01:20:00',\n ...                               '2018-10-28 02:36:00',\n ...                               '2018-10-28 03:46:00']))\n >>> s.dt.tz_localize('CET', ambiguous=np.array([True, True, False]))\n 0   2018-10-28 01:20:00+02:00\n 1   2018-10-28 02:36:00+02:00\n 2   2018-10-28 03:46:00+01:00\n dtype: datetime64[ns, CET]\n\n If the DST transition causes nonexistent times, you can shift these\n dates forward or backwards with a timedelta object or `'shift_forward'`\n or `'shift_backwards'`.\n\n >>> s = pd.to_datetime(pd.Series(['2015-03-29 02:30:00',\n ...                               '2015-03-29 03:30:00']))\n >>> s.dt.tz_localize('Europe/Warsaw', nonexistent='shift_forward')\n 0   2015-03-29 03:00:00+02:00\n 1   2015-03-29 03:30:00+02:00\n dtype: datetime64[ns, Europe/Warsaw]\n\n >>> s.dt.tz_localize('Europe/Warsaw', nonexistent='shift_backward')\n 0   2015-03-29 01:59:59.999999999+01:00\n 1   2015-03-29 03:30:00+02:00\n dtype: datetime64[ns, Europe/Warsaw]\n\n >>> s.dt.tz_localize('Europe/Warsaw', nonexistent=pd.Timedelta('1H'))\n 0   2015-03-29 03:30:00+02:00\n 1   2015-03-29 03:30:00+02:00\n dtype: datetime64[ns, Europe/Warsaw]",  # str
+                    "Localize tz-naive Datetime Array/Index to tz-aware\n Datetime Array/Index.\n\n This method takes a time zone (tz) naive Datetime Array/Index object\n and makes this time zone aware. It does not move the time to another\n time zone.\n Time zone localization helps to switch from time zone aware to time\n zone unaware objects.\n\n Parameters\n ----------\n tz : str, pytz.timezone, dateutil.tz.tzfile or None\n Time zone to convert timestamps to. Passing ``None`` will\n remove the time zone information preserving local time.\n ambiguous : 'infer', 'NaT', bool array, default 'raise'\n When clocks moved backward due to DST, ambiguous times may arise.\n For example in Central European Time (UTC+01), when going from\n 03:00 DST to 02:00 non-DST, 02:30:00 local time occurs both at\n 00:30:00 UTC and at 01:30:00 UTC. In such a situation, the\n `ambiguous` parameter dictates how ambiguous times should be\n handled.\n\n - 'infer' will attempt to infer fall dst-transition hours based on\n order\n - bool-ndarray where True signifies a DST time, False signifies a\n non-DST time (note that this flag is only applicable for\n ambiguous times)\n - 'NaT' will return NaT where there are ambiguous times\n - 'raise' will raise an AmbiguousTimeError if there are ambiguous\n times.\n\n nonexistent : 'shift_forward', 'shift_backward, 'NaT', timedelta,         default 'raise'\n A nonexistent time does not exist in a particular timezone\n where clocks moved forward due to DST.\n\n - 'shift_forward' will shift the nonexistent time forward to the\n closest existing time\n - 'shift_backward' will shift the nonexistent time backward to the\n closest existing time\n - 'NaT' will return NaT where there are nonexistent times\n - timedelta objects will shift nonexistent times by the timedelta\n - 'raise' will raise an NonExistentTimeError if there are\n nonexistent times.\n\n .. versionadded:: 0.24.0\n\n Returns\n -------\n Same type as self\n Array/Index converted to the specified time zone.\n\n Raises\n ------\n TypeError\n If the Datetime Array/Index is tz-aware and tz is not None.\n\n See Also\n --------\n DatetimeIndex.tz_convert : Convert tz-aware DatetimeIndex from\n one time zone to another.\n\n Examples\n --------\n >>> tz_naive = pd.date_range('2018-03-01 09:00', periods=3)\n >>> tz_naive\n DatetimeIndex(['2018-03-01 09:00:00', '2018-03-02 09:00:00',\n '2018-03-03 09:00:00'],\n dtype='datetime64[ns]', freq='D')\n\n Localize DatetimeIndex in US/Eastern time zone:\n\n >>> tz_aware = tz_naive.tz_localize(tz='US/Eastern')\n >>> tz_aware\n DatetimeIndex(['2018-03-01 09:00:00-05:00',\n '2018-03-02 09:00:00-05:00',\n '2018-03-03 09:00:00-05:00'],\n dtype='datetime64[ns, US/Eastern]', freq=None)\n\n With the ``tz=None``, we can remove the time zone information\n while keeping the local time (not converted to UTC):\n\n >>> tz_aware.tz_localize(None)\n DatetimeIndex(['2018-03-01 09:00:00', '2018-03-02 09:00:00',\n '2018-03-03 09:00:00'],\n dtype='datetime64[ns]', freq=None)\n\n Be careful with DST changes. When there is sequential data, pandas can\n infer the DST time:\n\n >>> s = pd.to_datetime(pd.Series(['2018-10-28 01:30:00',\n ...                               '2018-10-28 02:00:00',\n ...                               '2018-10-28 02:30:00',\n ...                               '2018-10-28 02:00:00',\n ...                               '2018-10-28 02:30:00',\n ...                               '2018-10-28 03:00:00',\n ...                               '2018-10-28 03:30:00']))\n >>> s.dt.tz_localize('CET', ambiguous='infer')\n 0   2018-10-28 01:30:00+02:00\n 1   2018-10-28 02:00:00+02:00\n 2   2018-10-28 02:30:00+02:00\n 3   2018-10-28 02:00:00+01:00\n 4   2018-10-28 02:30:00+01:00\n 5   2018-10-28 03:00:00+01:00\n 6   2018-10-28 03:30:00+01:00\n dtype: datetime64[ns, CET]\n\n In some cases, inferring the DST is impossible. In such cases, you can\n pass an ndarray to the ambiguous parameter to set the DST explicitly\n\n >>> s = pd.to_datetime(pd.Series(['2018-10-28 01:20:00',\n ...                               '2018-10-28 02:36:00',\n ...                               '2018-10-28 03:46:00']))\n >>> s.dt.tz_localize('CET', ambiguous=np.array([True, True, False]))\n 0   2018-10-28 01:20:00+02:00\n 1   2018-10-28 02:36:00+02:00\n 2   2018-10-28 03:46:00+01:00\n dtype: datetime64[ns, CET]\n\n If the DST transition causes nonexistent times, you can shift these\n dates forward or backwards with a timedelta object or `'shift_forward'`\n or `'shift_backwards'`.\n\n >>> s = pd.to_datetime(pd.Series(['2015-03-29 02:30:00',\n ...                               '2015-03-29 03:30:00']))\n >>> s.dt.tz_localize('Europe/Warsaw', nonexistent='shift_forward')\n 0   2015-03-29 03:00:00+02:00\n 1   2015-03-29 03:30:00+02:00\n dtype: datetime64[ns, Europe/Warsaw]\n\n >>> s.dt.tz_localize('Europe/Warsaw', nonexistent='shift_backward')\n 0   2015-03-29 01:59:59.999999999+01:00\n 1   2015-03-29 03:30:00+02:00\n dtype: datetime64[ns, Europe/Warsaw]\n\n >>> s.dt.tz_localize('Europe/Warsaw', nonexistent=pd.Timedelta('1H'))\n 0   2015-03-29 03:30:00+02:00\n 1   2015-03-29 03:30:00+02:00\n dtype: datetime64[ns, Europe/Warsaw]",  # str
                 )  # /Constant
             )  # /Expr
             Assign(
               targets=
                 Name(

3

error: cannot format /private/tmp/pandas/pandas/core/frame.py: INTERNAL ERROR: Black produced code that is not equivalent to the source.  Please report a bug on https://github.com/psf/black/issues.  This diff might be helpful: /var/folders/kt/j77sf4_n6fnbx6pg199rbx700000gn/T/blk_qn00rm3v.log
--- src
+++ dst
@@ -52354,11 +52354,11 @@
           body=
             Expr(
               value=
                 Constant(
                   value=
-                    'Return the first `n` rows ordered by `columns` in ascending order.\n\n Return the first `n` rows with the smallest values in `columns`, in\n ascending order. The columns that are not specified are returned as\n well, but not used for ordering.\n\n This method is equivalent to\n ``df.sort_values(columns, ascending=True).head(n)``, but more\n performant.\n\n Parameters\n ----------\n n : int\n Number of items to retrieve.\n columns : list or str\n Column name or names to order by.\n keep : {\'first\', \'last\', \'all\'}, default \'first\'\n Where there are duplicate values:\n\n - ``first`` : take the first occurrence.\n - ``last`` : take the last occurrence.\n - ``all`` : do not drop any duplicates, even it means\n selecting more than `n` items.\n\n .. versionadded:: 0.24.0\n\n Returns\n -------\n DataFrame\n\n See Also\n --------\n DataFrame.nlargest : Return the first `n` rows ordered by `columns` in\n descending order.\n DataFrame.sort_values : Sort DataFrame by the values.\n DataFrame.head : Return the first `n` rows without re-ordering.\n\n Examples\n --------\n >>> df = pd.DataFrame({\'population\': [59000000, 65000000, 434000,\n ...                                   434000, 434000, 337000, 337000,\n ...                                   11300, 11300],\n ...                    \'GDP\': [1937894, 2583560 , 12011, 4520, 12128,\n ...                            17036, 182, 38, 311],\n ...                    \'alpha-2\': ["IT", "FR", "MT", "MV", "BN",\n ...                                "IS", "NR", "TV", "AI"]},\n ...                   index=["Italy", "France", "Malta",\n ...                          "Maldives", "Brunei", "Iceland",\n ...                          "Nauru", "Tuvalu", "Anguilla"])\n >>> df\n population      GDP alpha-2\n Italy       59000000  1937894      IT\n France      65000000  2583560      FR\n Malta         434000    12011      MT\n Maldives      434000     4520      MV\n Brunei        434000    12128      BN\n Iceland       337000    17036      IS\n Nauru         337000      182      NR\n Tuvalu         11300       38      TV\n Anguilla       11300      311      AI\n\n In the following example, we will use ``nsmallest`` to select the\n three rows having the smallest values in column "population".\n\n >>> df.nsmallest(3, \'population\')\n population    GDP alpha-2\n Tuvalu         11300     38      TV\n Anguilla       11300    311      AI\n Iceland       337000  17036\t     IS\n\n When using ``keep=\'last\'``, ties are resolved in reverse order:\n\n >>> df.nsmallest(3, \'population\', keep=\'last\')\n population  GDP alpha-2\n Anguilla       11300  311      AI\n Tuvalu         11300   38      TV\n Nauru         337000  182      NR\n\n When using ``keep=\'all\'``, all duplicate items are maintained:\n\n >>> df.nsmallest(3, \'population\', keep=\'all\')\n population    GDP alpha-2\n Tuvalu         11300     38      TV\n Anguilla       11300    311      AI\n Iceland       337000  17036      IS\n Nauru         337000    182      NR\n\n To order by the smallest values in column "population" and then "GDP", we can\n specify multiple columns like in the next example.\n\n >>> df.nsmallest(3, [\'population\', \'GDP\'])\n population  GDP alpha-2\n Tuvalu         11300   38      TV\n Anguilla       11300  311      AI\n Nauru         337000  182      NR',  # str
+                    'Return the first `n` rows ordered by `columns` in ascending order.\n\n Return the first `n` rows with the smallest values in `columns`, in\n ascending order. The columns that are not specified are returned as\n well, but not used for ordering.\n\n This method is equivalent to\n ``df.sort_values(columns, ascending=True).head(n)``, but more\n performant.\n\n Parameters\n ----------\n n : int\n Number of items to retrieve.\n columns : list or str\n Column name or names to order by.\n keep : {\'first\', \'last\', \'all\'}, default \'first\'\n Where there are duplicate values:\n\n - ``first`` : take the first occurrence.\n - ``last`` : take the last occurrence.\n - ``all`` : do not drop any duplicates, even it means\n selecting more than `n` items.\n\n .. versionadded:: 0.24.0\n\n Returns\n -------\n DataFrame\n\n See Also\n --------\n DataFrame.nlargest : Return the first `n` rows ordered by `columns` in\n descending order.\n DataFrame.sort_values : Sort DataFrame by the values.\n DataFrame.head : Return the first `n` rows without re-ordering.\n\n Examples\n --------\n >>> df = pd.DataFrame({\'population\': [59000000, 65000000, 434000,\n ...                                   434000, 434000, 337000, 337000,\n ...                                   11300, 11300],\n ...                    \'GDP\': [1937894, 2583560 , 12011, 4520, 12128,\n ...                            17036, 182, 38, 311],\n ...                    \'alpha-2\': ["IT", "FR", "MT", "MV", "BN",\n ...                                "IS", "NR", "TV", "AI"]},\n ...                   index=["Italy", "France", "Malta",\n ...                          "Maldives", "Brunei", "Iceland",\n ...                          "Nauru", "Tuvalu", "Anguilla"])\n >>> df\n population      GDP alpha-2\n Italy       59000000  1937894      IT\n France      65000000  2583560      FR\n Malta         434000    12011      MT\n Maldives      434000     4520      MV\n Brunei        434000    12128      BN\n Iceland       337000    17036      IS\n Nauru         337000      182      NR\n Tuvalu         11300       38      TV\n Anguilla       11300      311      AI\n\n In the following example, we will use ``nsmallest`` to select the\n three rows having the smallest values in column "population".\n\n >>> df.nsmallest(3, \'population\')\n population    GDP alpha-2\n Tuvalu         11300     38      TV\n Anguilla       11300    311      AI\n Iceland       337000  17036          IS\n\n When using ``keep=\'last\'``, ties are resolved in reverse order:\n\n >>> df.nsmallest(3, \'population\', keep=\'last\')\n population  GDP alpha-2\n Anguilla       11300  311      AI\n Tuvalu         11300   38      TV\n Nauru         337000  182      NR\n\n When using ``keep=\'all\'``, all duplicate items are maintained:\n\n >>> df.nsmallest(3, \'population\', keep=\'all\')\n population    GDP alpha-2\n Tuvalu         11300     38      TV\n Anguilla       11300    311      AI\n Iceland       337000  17036      IS\n Nauru         337000    182      NR\n\n To order by the smallest values in column "population" and then "GDP", we can\n specify multiple columns like in the next example.\n\n >>> df.nsmallest(3, [\'population\', \'GDP\'])\n population  GDP alpha-2\n Tuvalu         11300   38      TV\n Anguilla       11300  311      AI\n Nauru         337000  182      NR',  # str
                 )  # /Constant
             )  # /Expr
             Return(
               value=
                 Call(
hugovk commented 4 years ago

Django has 2 errors:

1

error: cannot format /private/tmp/django/tests/gis_tests/test_spatialrefsys.py: INTERNAL ERROR: Black produced invalid code: invalid syntax (<unknown>, line 56). Please report a bug on https://github.com/psf/black/issues.  This invalid output might be helpful: /var/folders/kt/j77sf4_n6fnbx6pg199rbx700000gn/T/blk_86rr3nm9.log
  File "/Users/hugo/github/black/src/black/__init__.py", line 6037, in assert_equivalent
    dst_ast = parse_ast(dst)
  File "/Users/hugo/github/black/src/black/__init__.py", line 5948, in parse_ast
    return ast27.parse(src)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/typed_ast/ast27.py", line 50, in parse
    return _ast27.parse(source, filename, mode)
import re

from django.test import TestCase, skipUnlessDBFeature

from .utils import SpatialRefSys, oracle, postgis, spatialite

test_srs = (
    {
        "srid": 4326,
        "auth_name": ("EPSG", True),
        "auth_srid": 4326,
        # Only the beginning, because there are differences depending on installed libs
        "srtext": 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84"',
        # +ellps=WGS84 has been removed in the 4326 proj string in proj-4.8
        "proj_re": (
            r"\+proj=longlat (\+ellps=WGS84 )?(\+datum=WGS84 |\+towgs84=0,0,0,0,0,0,0"
            r" )\+no_defs ?"
        ),
        "spheroid": "WGS 84",
        "name": "WGS 84",
        "geographic": True,
        "projected": False,
        "spatialite": True,
        # From proj's "cs2cs -le" and Wikipedia (semi-minor only)
        "ellipsoid": (6378137.0, 6356752.3, 298.257223563),
        "eprec": (1, 1, 9),
        "wkt": re.sub(
            r"[\s+]",
            "",
            """
        GEOGCS["WGS 84",
    DATUM["WGS_1984",
        SPHEROID["WGS 84",6378137,298.257223563,
            AUTHORITY["EPSG","7030"]],
        AUTHORITY["EPSG","6326"]],
    PRIMEM["Greenwich",0,
        AUTHORITY["EPSG","8901"]],
    UNIT["degree",0.01745329251994328,
        AUTHORITY["EPSG","9122"]],
    AUTHORITY["EPSG","4326"]]
    """,
        ),
    },
    {
        "srid": 32140,
        "auth_name": ("EPSG", False),
        "auth_srid": 32140,
        "srtext": (
            'PROJCS["NAD83 / Texas South Central",GEOGCS["NAD83",'
            'DATUM["North_American_Datum_1983",SPHEROID["GRS 1980"'
        ),
        "proj_re": (
            r"\+proj=lcc (\+lat_1=30.28333333333333? |\+lat_2=28.38333333333333?"
            r" |\+lat_0=27.83333333333333? |"
        )
        r"\+lon_0=-99 ){4}\+x_0=600000 \+y_0=4000000 (\+ellps=GRS80 )?"
        r"(\+datum=NAD83 |\+towgs84=0,0,0,0,0,0,0 )?\+units=m \+no_defs ?",
        "spheroid": "GRS 1980",
        "name": "NAD83 / Texas South Central",
        "geographic": False,
        "projected": True,
        "spatialite": False,
        # From proj's "cs2cs -le" and Wikipedia (semi-minor only)
        "ellipsoid": (6378137.0, 6356752.31414, 298.257222101),
        "eprec": (1, 5, 10),
    },
)

@skipUnlessDBFeature("has_spatialrefsys_table")
class SpatialRefSysTest(TestCase):
    def test_get_units(self):
        epsg_4326 = next(f for f in test_srs if f["srid"] == 4326)
        unit, unit_name = SpatialRefSys().get_units(epsg_4326["wkt"])
        self.assertEqual(unit_name, "degree")
        self.assertAlmostEqual(unit, 0.01745329251994328)

    def test_retrieve(self):
        """
        Test retrieval of SpatialRefSys model objects.
        """
        for sd in test_srs:
            srs = SpatialRefSys.objects.get(srid=sd["srid"])
            self.assertEqual(sd["srid"], srs.srid)

            # Some of the authority names are borked on Oracle, e.g., SRID=32140.
            #  also, Oracle Spatial seems to add extraneous info to fields, hence the
            #  the testing with the 'startswith' flag.
            auth_name, oracle_flag = sd["auth_name"]
            if postgis or (oracle and oracle_flag):
                self.assertTrue(srs.auth_name.startswith(auth_name))

            self.assertEqual(sd["auth_srid"], srs.auth_srid)

            # No PROJ and different srtext on oracle backends :(
            if postgis:
                self.assertTrue(srs.wkt.startswith(sd["srtext"]))
                self.assertRegex(srs.proj4text, sd["proj_re"])

    def test_osr(self):
        """
        Test getting OSR objects from SpatialRefSys model objects.
        """
        for sd in test_srs:
            sr = SpatialRefSys.objects.get(srid=sd["srid"])
            self.assertTrue(sr.spheroid.startswith(sd["spheroid"]))
            self.assertEqual(sd["geographic"], sr.geographic)
            self.assertEqual(sd["projected"], sr.projected)

            if not (spatialite and not sd["spatialite"]):
                # Can't get 'NAD83 / Texas South Central' from PROJ string
                # on SpatiaLite
                self.assertTrue(sr.name.startswith(sd["name"]))

            # Testing the SpatialReference object directly.
            if postgis or spatialite:
                srs = sr.srs
                self.assertRegex(srs.proj, sd["proj_re"])
                self.assertTrue(srs.wkt.startswith(sd["srtext"]))

    def test_ellipsoid(self):
        """
        Test the ellipsoid property.
        """
        for sd in test_srs:
            # Getting the ellipsoid and precision parameters.
            ellps1 = sd["ellipsoid"]
            prec = sd["eprec"]

            # Getting our spatial reference and its ellipsoid
            srs = SpatialRefSys.objects.get(srid=sd["srid"])
            ellps2 = srs.ellipsoid

            for i in range(3):
                self.assertAlmostEqual(ellps1[i], ellps2[i], prec[i])

    @skipUnlessDBFeature("supports_add_srs_entry")
    def test_add_entry(self):
        """
        Test adding a new entry in the SpatialRefSys model using the
        add_srs_entry utility.
        """
        from django.contrib.gis.utils import add_srs_entry

        add_srs_entry(3857)
        self.assertTrue(SpatialRefSys.objects.filter(srid=3857).exists())
        srs = SpatialRefSys.objects.get(srid=3857)
        self.assertTrue(SpatialRefSys.get_spheroid(srs.wkt).startswith("SPHEROID["))

2

error: cannot format /private/tmp/django/tests/auth_tests/test_views.py: INTERNAL ERROR: Black produced different code on the second pass of the formatter.  Please report a bug on https://github.com/psf/black/issues.  This diff might be helpful: /var/folders/kt/j77sf4_n6fnbx6pg199rbx700000gn/T/blk_qsbqbcow.log
--- source
+++ first pass
@@ -8,18 +8,25 @@

 from django.apps import apps
 from django.conf import settings
 from django.contrib.admin.models import LogEntry
 from django.contrib.auth import (
-    BACKEND_SESSION_KEY, HASH_SESSION_KEY, REDIRECT_FIELD_NAME, SESSION_KEY,
+    BACKEND_SESSION_KEY,
+    HASH_SESSION_KEY,
+    REDIRECT_FIELD_NAME,
+    SESSION_KEY,
 )
 from django.contrib.auth.forms import (
-    AuthenticationForm, PasswordChangeForm, SetPasswordForm,
+    AuthenticationForm,
+    PasswordChangeForm,
+    SetPasswordForm,
 )
 from django.contrib.auth.models import Permission, User
 from django.contrib.auth.views import (
-    INTERNAL_RESET_SESSION_TOKEN, LoginView, logout_then_login,
+    INTERNAL_RESET_SESSION_TOKEN,
+    LoginView,
+    logout_then_login,
     redirect_to_login,
 )
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.sessions.middleware import SessionMiddleware
 from django.contrib.sites.requests import RequestSite
@@ -36,87 +43,95 @@
 from .models import CustomUser, UUIDUser
 from .settings import AUTH_TEMPLATES

 @override_settings(
-    LANGUAGES=[('en', 'English')],
-    LANGUAGE_CODE='en',
+    LANGUAGES=[("en", "English")],
+    LANGUAGE_CODE="en",
     TEMPLATES=AUTH_TEMPLATES,
-    ROOT_URLCONF='auth_tests.urls',
+    ROOT_URLCONF="auth_tests.urls",
 )
 class AuthViewsTestCase(TestCase):
     """
     Helper base class for all the follow test cases.
     """

     @classmethod
     def setUpTestData(cls):
-        cls.u1 = User.objects.create_user(username='testclient', password='password', email='testclient@example.com')
-        cls.u3 = User.objects.create_user(username='staff', password='password', email='staffmember@example.com')
-
-    def login(self, username='testclient', password='password'):
-        response = self.client.post('/login/', {
-            'username': username,
-            'password': password,
-        })
+        cls.u1 = User.objects.create_user(
+            username="testclient", password="password", email="testclient@example.com"
+        )
+        cls.u3 = User.objects.create_user(
+            username="staff", password="password", email="staffmember@example.com"
+        )
+
+    def login(self, username="testclient", password="password"):
+        response = self.client.post(
+            "/login/", {"username": username, "password": password,}
+        )
         self.assertIn(SESSION_KEY, self.client.session)
         return response

     def logout(self):
-        response = self.client.get('/admin/logout/')
+        response = self.client.get("/admin/logout/")
         self.assertEqual(response.status_code, 200)
         self.assertNotIn(SESSION_KEY, self.client.session)

     def assertFormError(self, response, error):
         """Assert that error is found in response.context['form'] errors"""
-        form_errors = list(itertools.chain(*response.context['form'].errors.values()))
+        form_errors = list(itertools.chain(*response.context["form"].errors.values()))
         self.assertIn(str(error), form_errors)

-@override_settings(ROOT_URLCONF='django.contrib.auth.urls')
+@override_settings(ROOT_URLCONF="django.contrib.auth.urls")
 class AuthViewNamedURLTests(AuthViewsTestCase):
-
     def test_named_urls(self):
         "Named URLs should be reversible"
         expected_named_urls = [
-            ('login', [], {}),
-            ('logout', [], {}),
-            ('password_change', [], {}),
-            ('password_change_done', [], {}),
-            ('password_reset', [], {}),
-            ('password_reset_done', [], {}),
-            ('password_reset_confirm', [], {
-                'uidb64': 'aaaaaaa',
-                'token': '1111-aaaaa',
-            }),
-            ('password_reset_complete', [], {}),
+            ("login", [], {}),
+            ("logout", [], {}),
+            ("password_change", [], {}),
+            ("password_change_done", [], {}),
+            ("password_reset", [], {}),
+            ("password_reset_done", [], {}),
+            (
+                "password_reset_confirm",
+                [],
+                {"uidb64": "aaaaaaa", "token": "1111-aaaaa",},
+            ),
+            ("password_reset_complete", [], {}),
         ]
         for name, args, kwargs in expected_named_urls:
             with self.subTest(name=name):
                 try:
                     reverse(name, args=args, kwargs=kwargs)
                 except NoReverseMatch:
-                    self.fail("Reversal of url named '%s' failed with NoReverseMatch" % name)
+                    self.fail(
+                        "Reversal of url named '%s' failed with NoReverseMatch" % name
+                    )

 class PasswordResetTest(AuthViewsTestCase):
-
     def setUp(self):
         self.client = PasswordResetConfirmClient()

     def test_email_not_found(self):
         """If the provided email is not registered, don't raise any error but
         also don't send any email."""
-        response = self.client.get('/password_reset/')
+        response = self.client.get("/password_reset/")
         self.assertEqual(response.status_code, 200)
-        response = self.client.post('/password_reset/', {'email': 'not_a_real_email@email.com'})
+        response = self.client.post(
+            "/password_reset/", {"email": "not_a_real_email@email.com"}
+        )
         self.assertEqual(response.status_code, 302)
         self.assertEqual(len(mail.outbox), 0)

     def test_email_found(self):
         "Email is sent if a valid email address is provided for password reset"
-        response = self.client.post('/password_reset/', {'email': 'staffmember@example.com'})
+        response = self.client.post(
+            "/password_reset/", {"email": "staffmember@example.com"}
+        )
         self.assertEqual(response.status_code, 302)
         self.assertEqual(len(mail.outbox), 1)
         self.assertIn("http://", mail.outbox[0].body)
         self.assertEqual(settings.DEFAULT_FROM_EMAIL, mail.outbox[0].from_email)
         # optional multipart text/html email has been added.  Make sure original,
@@ -126,37 +141,41 @@
     def test_extra_email_context(self):
         """
         extra_email_context should be available in the email template context.
         """
         response = self.client.post(
-            '/password_reset_extra_email_context/',
-            {'email': 'staffmember@example.com'},
+            "/password_reset_extra_email_context/",
+            {"email": "staffmember@example.com"},
         )
         self.assertEqual(response.status_code, 302)
         self.assertEqual(len(mail.outbox), 1)
         self.assertIn('Email email context: "Hello!"', mail.outbox[0].body)
-        self.assertIn('http://custom.example.com/reset/', mail.outbox[0].body)
+        self.assertIn("http://custom.example.com/reset/", mail.outbox[0].body)

     def test_html_mail_template(self):
         """
         A multipart email with text/plain and text/html is sent
         if the html_email_template parameter is passed to the view
         """
-        response = self.client.post('/password_reset/html_email_template/', {'email': 'staffmember@example.com'})
+        response = self.client.post(
+            "/password_reset/html_email_template/", {"email": "staffmember@example.com"}
+        )
         self.assertEqual(response.status_code, 302)
         self.assertEqual(len(mail.outbox), 1)
         message = mail.outbox[0].message()
         self.assertEqual(len(message.get_payload()), 2)
         self.assertTrue(message.is_multipart())
-        self.assertEqual(message.get_payload(0).get_content_type(), 'text/plain')
-        self.assertEqual(message.get_payload(1).get_content_type(), 'text/html')
-        self.assertNotIn('<html>', message.get_payload(0).get_payload())
-        self.assertIn('<html>', message.get_payload(1).get_payload())
+        self.assertEqual(message.get_payload(0).get_content_type(), "text/plain")
+        self.assertEqual(message.get_payload(1).get_content_type(), "text/html")
+        self.assertNotIn("<html>", message.get_payload(0).get_payload())
+        self.assertIn("<html>", message.get_payload(1).get_payload())

     def test_email_found_custom_from(self):
         "Email is sent if a valid email address is provided for password reset when a custom from_email is provided."
-        response = self.client.post('/password_reset_from_email/', {'email': 'staffmember@example.com'})
+        response = self.client.post(
+            "/password_reset_from_email/", {"email": "staffmember@example.com"}
+        )
         self.assertEqual(response.status_code, 302)
         self.assertEqual(len(mail.outbox), 1)
         self.assertEqual("staffmember@example.com", mail.outbox[0].from_email)

     # Skip any 500 handler action (like sending more mail...)
@@ -168,35 +187,35 @@
         # the colon is interpreted as part of a username for login purposes,
         # making 'evil.com' the request domain. Since HTTP_HOST is used to
         # produce a meaningful reset URL, we need to be certain that the
         # HTTP_HOST header isn't poisoned. This is done as a check when get_host()
         # is invoked, but we check here as a practical consequence.
-        with self.assertLogs('django.security.DisallowedHost', 'ERROR'):
+        with self.assertLogs("django.security.DisallowedHost", "ERROR"):
             response = self.client.post(
-                '/password_reset/',
-                {'email': 'staffmember@example.com'},
-                HTTP_HOST='www.example:dr.frankenstein@evil.tld'
+                "/password_reset/",
+                {"email": "staffmember@example.com"},
+                HTTP_HOST="www.example:dr.frankenstein@evil.tld",
             )
         self.assertEqual(response.status_code, 400)
         self.assertEqual(len(mail.outbox), 0)

     # Skip any 500 handler action (like sending more mail...)
     @override_settings(DEBUG_PROPAGATE_EXCEPTIONS=True)
     def test_poisoned_http_host_admin_site(self):
         "Poisoned HTTP_HOST headers can't be used for reset emails on admin views"
-        with self.assertLogs('django.security.DisallowedHost', 'ERROR'):
+        with self.assertLogs("django.security.DisallowedHost", "ERROR"):
             response = self.client.post(
-                '/admin_password_reset/',
-                {'email': 'staffmember@example.com'},
-                HTTP_HOST='www.example:dr.frankenstein@evil.tld'
+                "/admin_password_reset/",
+                {"email": "staffmember@example.com"},
+                HTTP_HOST="www.example:dr.frankenstein@evil.tld",
             )
         self.assertEqual(response.status_code, 400)
         self.assertEqual(len(mail.outbox), 0)

     def _test_confirm_start(self):
         # Start by creating the email
-        self.client.post('/password_reset/', {'email': 'staffmember@example.com'})
+        self.client.post("/password_reset/", {"email": "staffmember@example.com"})
         self.assertEqual(len(mail.outbox), 1)
         return self._read_signup_email(mail.outbox[0])

     def _read_signup_email(self, email):
         urlmatch = re.search(r"https?://[^/]*(/.*reset/\S*)", email.body)
@@ -218,197 +237,226 @@
         response = self.client.get(path)
         self.assertContains(response, "The password reset link was invalid")

     def test_confirm_invalid_user(self):
         # A nonexistent user returns a 200 response, not a 404.
-        response = self.client.get('/reset/123456/1-1/')
+        response = self.client.get("/reset/123456/1-1/")
         self.assertContains(response, "The password reset link was invalid")

     def test_confirm_overflow_user(self):
         # A base36 user id that overflows int returns a 200 response.
-        response = self.client.get('/reset/zzzzzzzzzzzzz/1-1/')
+        response = self.client.get("/reset/zzzzzzzzzzzzz/1-1/")
         self.assertContains(response, "The password reset link was invalid")

     def test_confirm_invalid_post(self):
         # Same as test_confirm_invalid, but trying to do a POST instead.
         url, path = self._test_confirm_start()
         path = path[:-5] + ("0" * 4) + path[-1]

-        self.client.post(path, {
-            'new_password1': 'anewpassword',
-            'new_password2': ' anewpassword',
-        })
+        self.client.post(
+            path, {"new_password1": "anewpassword", "new_password2": " anewpassword",}
+        )
         # Check the password has not been changed
-        u = User.objects.get(email='staffmember@example.com')
+        u = User.objects.get(email="staffmember@example.com")
         self.assertTrue(not u.check_password("anewpassword"))

     def test_confirm_invalid_hash(self):
         """A POST with an invalid token is rejected."""
-        u = User.objects.get(email='staffmember@example.com')
+        u = User.objects.get(email="staffmember@example.com")
         original_password = u.password
         url, path = self._test_confirm_start()
-        path_parts = path.split('-')
-        path_parts[-1] = ("0") * 20 + '/'
-        path = '-'.join(path_parts)
-
-        response = self.client.post(path, {
-            'new_password1': 'anewpassword',
-            'new_password2': 'anewpassword',
-        })
-        self.assertIs(response.context['validlink'], False)
+        path_parts = path.split("-")
+        path_parts[-1] = "0" * 20 + "/"
+        path = "-".join(path_parts)
+
+        response = self.client.post(
+            path, {"new_password1": "anewpassword", "new_password2": "anewpassword",}
+        )
+        self.assertIs(response.context["validlink"], False)
         u.refresh_from_db()
         self.assertEqual(original_password, u.password)  # password hasn't changed

     def test_confirm_complete(self):
         url, path = self._test_confirm_start()
-        response = self.client.post(path, {'new_password1': 'anewpassword', 'new_password2': 'anewpassword'})
+        response = self.client.post(
+            path, {"new_password1": "anewpassword", "new_password2": "anewpassword"}
+        )
         # Check the password has been changed
-        u = User.objects.get(email='staffmember@example.com')
+        u = User.objects.get(email="staffmember@example.com")
         self.assertTrue(u.check_password("anewpassword"))
         # The reset token is deleted from the session.
         self.assertNotIn(INTERNAL_RESET_SESSION_TOKEN, self.client.session)

         # Check we can't use the link again
         response = self.client.get(path)
         self.assertContains(response, "The password reset link was invalid")

     def test_confirm_different_passwords(self):
         url, path = self._test_confirm_start()
-        response = self.client.post(path, {'new_password1': 'anewpassword', 'new_password2': 'x'})
-        self.assertFormError(response, SetPasswordForm.error_messages['password_mismatch'])
+        response = self.client.post(
+            path, {"new_password1": "anewpassword", "new_password2": "x"}
+        )
+        self.assertFormError(
+            response, SetPasswordForm.error_messages["password_mismatch"]
+        )

     def test_reset_redirect_default(self):
-        response = self.client.post('/password_reset/', {'email': 'staffmember@example.com'})
-        self.assertRedirects(response, '/password_reset/done/', fetch_redirect_response=False)
+        response = self.client.post(
+            "/password_reset/", {"email": "staffmember@example.com"}
+        )
+        self.assertRedirects(
+            response, "/password_reset/done/", fetch_redirect_response=False
+        )

     def test_reset_custom_redirect(self):
-        response = self.client.post('/password_reset/custom_redirect/', {'email': 'staffmember@example.com'})
-        self.assertRedirects(response, '/custom/', fetch_redirect_response=False)
+        response = self.client.post(
+            "/password_reset/custom_redirect/", {"email": "staffmember@example.com"}
+        )
+        self.assertRedirects(response, "/custom/", fetch_redirect_response=False)

     def test_reset_custom_redirect_named(self):
-        response = self.client.post('/password_reset/custom_redirect/named/', {'email': 'staffmember@example.com'})
-        self.assertRedirects(response, '/password_reset/', fetch_redirect_response=False)
+        response = self.client.post(
+            "/password_reset/custom_redirect/named/",
+            {"email": "staffmember@example.com"},
+        )
+        self.assertRedirects(
+            response, "/password_reset/", fetch_redirect_response=False
+        )

     def test_confirm_redirect_default(self):
         url, path = self._test_confirm_start()
-        response = self.client.post(path, {'new_password1': 'anewpassword', 'new_password2': 'anewpassword'})
-        self.assertRedirects(response, '/reset/done/', fetch_redirect_response=False)
+        response = self.client.post(
+            path, {"new_password1": "anewpassword", "new_password2": "anewpassword"}
+        )
+        self.assertRedirects(response, "/reset/done/", fetch_redirect_response=False)

     def test_confirm_redirect_custom(self):
         url, path = self._test_confirm_start()
-        path = path.replace('/reset/', '/reset/custom/')
-        response = self.client.post(path, {'new_password1': 'anewpassword', 'new_password2': 'anewpassword'})
-        self.assertRedirects(response, '/custom/', fetch_redirect_response=False)
+        path = path.replace("/reset/", "/reset/custom/")
+        response = self.client.post(
+            path, {"new_password1": "anewpassword", "new_password2": "anewpassword"}
+        )
+        self.assertRedirects(response, "/custom/", fetch_redirect_response=False)

     def test_confirm_redirect_custom_named(self):
         url, path = self._test_confirm_start()
-        path = path.replace('/reset/', '/reset/custom/named/')
-        response = self.client.post(path, {'new_password1': 'anewpassword', 'new_password2': 'anewpassword'})
-        self.assertRedirects(response, '/password_reset/', fetch_redirect_response=False)
+        path = path.replace("/reset/", "/reset/custom/named/")
+        response = self.client.post(
+            path, {"new_password1": "anewpassword", "new_password2": "anewpassword"}
+        )
+        self.assertRedirects(
+            response, "/password_reset/", fetch_redirect_response=False
+        )

     def test_confirm_custom_reset_url_token(self):
         url, path = self._test_confirm_start()
-        path = path.replace('/reset/', '/reset/custom/token/')
-        self.client.reset_url_token = 'set-passwordcustom'
-        response = self.client.post(
-            path,
-            {'new_password1': 'anewpassword', 'new_password2': 'anewpassword'},
-        )
-        self.assertRedirects(response, '/reset/done/', fetch_redirect_response=False)
+        path = path.replace("/reset/", "/reset/custom/token/")
+        self.client.reset_url_token = "set-passwordcustom"
+        response = self.client.post(
+            path, {"new_password1": "anewpassword", "new_password2": "anewpassword"},
+        )
+        self.assertRedirects(response, "/reset/done/", fetch_redirect_response=False)

     def test_confirm_login_post_reset(self):
         url, path = self._test_confirm_start()
-        path = path.replace('/reset/', '/reset/post_reset_login/')
-        response = self.client.post(path, {'new_password1': 'anewpassword', 'new_password2': 'anewpassword'})
-        self.assertRedirects(response, '/reset/done/', fetch_redirect_response=False)
+        path = path.replace("/reset/", "/reset/post_reset_login/")
+        response = self.client.post(
+            path, {"new_password1": "anewpassword", "new_password2": "anewpassword"}
+        )
+        self.assertRedirects(response, "/reset/done/", fetch_redirect_response=False)
         self.assertIn(SESSION_KEY, self.client.session)

     @override_settings(
         AUTHENTICATION_BACKENDS=[
-            'django.contrib.auth.backends.ModelBackend',
-            'django.contrib.auth.backends.AllowAllUsersModelBackend',
+            "django.contrib.auth.backends.ModelBackend",
+            "django.contrib.auth.backends.AllowAllUsersModelBackend",
         ]
     )
     def test_confirm_login_post_reset_custom_backend(self):
         # This backend is specified in the URL pattern.
-        backend = 'django.contrib.auth.backends.AllowAllUsersModelBackend'
-        url, path = self._test_confirm_start()
-        path = path.replace('/reset/', '/reset/post_reset_login_custom_backend/')
-        response = self.client.post(path, {'new_password1': 'anewpassword', 'new_password2': 'anewpassword'})
-        self.assertRedirects(response, '/reset/done/', fetch_redirect_response=False)
+        backend = "django.contrib.auth.backends.AllowAllUsersModelBackend"
+        url, path = self._test_confirm_start()
+        path = path.replace("/reset/", "/reset/post_reset_login_custom_backend/")
+        response = self.client.post(
+            path, {"new_password1": "anewpassword", "new_password2": "anewpassword"}
+        )
+        self.assertRedirects(response, "/reset/done/", fetch_redirect_response=False)
         self.assertIn(SESSION_KEY, self.client.session)
         self.assertEqual(self.client.session[BACKEND_SESSION_KEY], backend)

     def test_confirm_login_post_reset_already_logged_in(self):
         url, path = self._test_confirm_start()
-        path = path.replace('/reset/', '/reset/post_reset_login/')
-        self.login()
-        response = self.client.post(path, {'new_password1': 'anewpassword', 'new_password2': 'anewpassword'})
-        self.assertRedirects(response, '/reset/done/', fetch_redirect_response=False)
+        path = path.replace("/reset/", "/reset/post_reset_login/")
+        self.login()
+        response = self.client.post(
+            path, {"new_password1": "anewpassword", "new_password2": "anewpassword"}
+        )
+        self.assertRedirects(response, "/reset/done/", fetch_redirect_response=False)
         self.assertIn(SESSION_KEY, self.client.session)

     def test_confirm_display_user_from_form(self):
         url, path = self._test_confirm_start()
         response = self.client.get(path)
         # The password_reset_confirm() view passes the user object to the
         # SetPasswordForm``, even on GET requests (#16919). For this test,
         # {{ form.user }}`` is rendered in the template
         # registration/password_reset_confirm.html.
-        username = User.objects.get(email='staffmember@example.com').username
+        username = User.objects.get(email="staffmember@example.com").username
         self.assertContains(response, "Hello, %s." % username)
         # However, the view should NOT pass any user object on a form if the
         # password reset link was invalid.
-        response = self.client.get('/reset/zzzzzzzzzzzzz/1-1/')
+        response = self.client.get("/reset/zzzzzzzzzzzzz/1-1/")
         self.assertContains(response, "Hello, .")

     def test_confirm_link_redirects_to_set_password_page(self):
         url, path = self._test_confirm_start()
         # Don't use PasswordResetConfirmClient (self.client) here which
         # automatically fetches the redirect page.
         client = Client()
         response = client.get(path)
-        token = response.resolver_match.kwargs['token']
-        uuidb64 = response.resolver_match.kwargs['uidb64']
-        self.assertRedirects(response, '/reset/%s/set-password/' % uuidb64)
-        self.assertEqual(client.session['_password_reset_token'], token)
+        token = response.resolver_match.kwargs["token"]
+        uuidb64 = response.resolver_match.kwargs["uidb64"]
+        self.assertRedirects(response, "/reset/%s/set-password/" % uuidb64)
+        self.assertEqual(client.session["_password_reset_token"], token)

     def test_confirm_custom_reset_url_token_link_redirects_to_set_password_page(self):
         url, path = self._test_confirm_start()
-        path = path.replace('/reset/', '/reset/custom/token/')
+        path = path.replace("/reset/", "/reset/custom/token/")
         client = Client()
         response = client.get(path)
-        token = response.resolver_match.kwargs['token']
-        uuidb64 = response.resolver_match.kwargs['uidb64']
-        self.assertRedirects(response, '/reset/custom/token/%s/set-passwordcustom/' % uuidb64)
-        self.assertEqual(client.session['_password_reset_token'], token)
+        token = response.resolver_match.kwargs["token"]
+        uuidb64 = response.resolver_match.kwargs["uidb64"]
+        self.assertRedirects(
+            response, "/reset/custom/token/%s/set-passwordcustom/" % uuidb64
+        )
+        self.assertEqual(client.session["_password_reset_token"], token)

     def test_invalid_link_if_going_directly_to_the_final_reset_password_url(self):
         url, path = self._test_confirm_start()
-        _, uuidb64, _ = path.strip('/').split('/')
-        response = Client().get('/reset/%s/set-password/' % uuidb64)
-        self.assertContains(response, 'The password reset link was invalid')
-
-
-@override_settings(AUTH_USER_MODEL='auth_tests.CustomUser')
+        _, uuidb64, _ = path.strip("/").split("/")
+        response = Client().get("/reset/%s/set-password/" % uuidb64)
+        self.assertContains(response, "The password reset link was invalid")
+
+
+@override_settings(AUTH_USER_MODEL="auth_tests.CustomUser")
 class CustomUserPasswordResetTest(AuthViewsTestCase):
-    user_email = 'staffmember@example.com'
+    user_email = "staffmember@example.com"

     @classmethod
     def setUpTestData(cls):
         cls.u1 = CustomUser.custom_objects.create(
-            email='staffmember@example.com',
-            date_of_birth=datetime.date(1976, 11, 8),
-        )
-        cls.u1.set_password('password')
+            email="staffmember@example.com", date_of_birth=datetime.date(1976, 11, 8),
+        )
+        cls.u1.set_password("password")
         cls.u1.save()

     def setUp(self):
         self.client = PasswordResetConfirmClient()

     def _test_confirm_start(self):
         # Start by creating the email
-        response = self.client.post('/password_reset/', {'email': self.user_email})
+        response = self.client.post("/password_reset/", {"email": self.user_email})
         self.assertEqual(response.status_code, 302)
         self.assertEqual(len(mail.outbox), 1)
         return self._read_signup_email(mail.outbox[0])

     def _read_signup_email(self, email):
@@ -420,238 +468,276 @@
         url, path = self._test_confirm_start()
         response = self.client.get(path)
         # redirect to a 'complete' page:
         self.assertContains(response, "Please enter your new password")
         # then submit a new password
-        response = self.client.post(path, {
-            'new_password1': 'anewpassword',
-            'new_password2': 'anewpassword',
-        })
-        self.assertRedirects(response, '/reset/done/')
-
-
-@override_settings(AUTH_USER_MODEL='auth_tests.UUIDUser')
+        response = self.client.post(
+            path, {"new_password1": "anewpassword", "new_password2": "anewpassword",}
+        )
+        self.assertRedirects(response, "/reset/done/")
+
+
+@override_settings(AUTH_USER_MODEL="auth_tests.UUIDUser")
 class UUIDUserPasswordResetTest(CustomUserPasswordResetTest):
-
     def _test_confirm_start(self):
         # instead of fixture
         UUIDUser.objects.create_user(
-            email=self.user_email,
-            username='foo',
-            password='foo',
+            email=self.user_email, username="foo", password="foo",
         )
         return super()._test_confirm_start()

     def test_confirm_invalid_uuid(self):
         """A uidb64 that decodes to a non-UUID doesn't crash."""
         _, path = self._test_confirm_start()
-        invalid_uidb64 = urlsafe_base64_encode(b'INVALID_UUID')
-        first, _uuidb64_, second = path.strip('/').split('/')
-        response = self.client.get('/' + '/'.join((first, invalid_uidb64, second)) + '/')
-        self.assertContains(response, 'The password reset link was invalid')
+        invalid_uidb64 = urlsafe_base64_encode(b"INVALID_UUID")
+        first, _uuidb64_, second = path.strip("/").split("/")
+        response = self.client.get(
+            "/" + "/".join((first, invalid_uidb64, second)) + "/"
+        )
+        self.assertContains(response, "The password reset link was invalid")

 class ChangePasswordTest(AuthViewsTestCase):
-
     def fail_login(self):
-        response = self.client.post('/login/', {
-            'username': 'testclient',
-            'password': 'password',
-        })
-        self.assertFormError(response, AuthenticationForm.error_messages['invalid_login'] % {
-            'username': User._meta.get_field('username').verbose_name
-        })
+        response = self.client.post(
+            "/login/", {"username": "testclient", "password": "password",}
+        )
+        self.assertFormError(
+            response,
+            AuthenticationForm.error_messages["invalid_login"]
+            % {"username": User._meta.get_field("username").verbose_name},
+        )

     def logout(self):
-        self.client.get('/logout/')
+        self.client.get("/logout/")

     def test_password_change_fails_with_invalid_old_password(self):
         self.login()
-        response = self.client.post('/password_change/', {
-            'old_password': 'donuts',
-            'new_password1': 'password1',
-            'new_password2': 'password1',
-        })
-        self.assertFormError(response, PasswordChangeForm.error_messages['password_incorrect'])
+        response = self.client.post(
+            "/password_change/",
+            {
+                "old_password": "donuts",
+                "new_password1": "password1",
+                "new_password2": "password1",
+            },
+        )
+        self.assertFormError(
+            response, PasswordChangeForm.error_messages["password_incorrect"]
+        )

     def test_password_change_fails_with_mismatched_passwords(self):
         self.login()
-        response = self.client.post('/password_change/', {
-            'old_password': 'password',
-            'new_password1': 'password1',
-            'new_password2': 'donuts',
-        })
-        self.assertFormError(response, SetPasswordForm.error_messages['password_mismatch'])
+        response = self.client.post(
+            "/password_change/",
+            {
+                "old_password": "password",
+                "new_password1": "password1",
+                "new_password2": "donuts",
+            },
+        )
+        self.assertFormError(
+            response, SetPasswordForm.error_messages["password_mismatch"]
+        )

     def test_password_change_succeeds(self):
         self.login()
-        self.client.post('/password_change/', {
-            'old_password': 'password',
-            'new_password1': 'password1',
-            'new_password2': 'password1',
-        })
+        self.client.post(
+            "/password_change/",
+            {
+                "old_password": "password",
+                "new_password1": "password1",
+                "new_password2": "password1",
+            },
+        )
         self.fail_login()
-        self.login(password='password1')
+        self.login(password="password1")

     def test_password_change_done_succeeds(self):
         self.login()
-        response = self.client.post('/password_change/', {
-            'old_password': 'password',
-            'new_password1': 'password1',
-            'new_password2': 'password1',
-        })
-        self.assertRedirects(response, '/password_change/done/', fetch_redirect_response=False)
-
-    @override_settings(LOGIN_URL='/login/')
+        response = self.client.post(
+            "/password_change/",
+            {
+                "old_password": "password",
+                "new_password1": "password1",
+                "new_password2": "password1",
+            },
+        )
+        self.assertRedirects(
+            response, "/password_change/done/", fetch_redirect_response=False
+        )
+
+    @override_settings(LOGIN_URL="/login/")
     def test_password_change_done_fails(self):
-        response = self.client.get('/password_change/done/')
-        self.assertRedirects(response, '/login/?next=/password_change/done/', fetch_redirect_response=False)
+        response = self.client.get("/password_change/done/")
+        self.assertRedirects(
+            response,
+            "/login/?next=/password_change/done/",
+            fetch_redirect_response=False,
+        )

     def test_password_change_redirect_default(self):
         self.login()
-        response = self.client.post('/password_change/', {
-            'old_password': 'password',
-            'new_password1': 'password1',
-            'new_password2': 'password1',
-        })
-        self.assertRedirects(response, '/password_change/done/', fetch_redirect_response=False)
+        response = self.client.post(
+            "/password_change/",
+            {
+                "old_password": "password",
+                "new_password1": "password1",
+                "new_password2": "password1",
+            },
+        )
+        self.assertRedirects(
+            response, "/password_change/done/", fetch_redirect_response=False
+        )

     def test_password_change_redirect_custom(self):
         self.login()
-        response = self.client.post('/password_change/custom/', {
-            'old_password': 'password',
-            'new_password1': 'password1',
-            'new_password2': 'password1',
-        })
-        self.assertRedirects(response, '/custom/', fetch_redirect_response=False)
+        response = self.client.post(
+            "/password_change/custom/",
+            {
+                "old_password": "password",
+                "new_password1": "password1",
+                "new_password2": "password1",
+            },
+        )
+        self.assertRedirects(response, "/custom/", fetch_redirect_response=False)

     def test_password_change_redirect_custom_named(self):
         self.login()
-        response = self.client.post('/password_change/custom/named/', {
-            'old_password': 'password',
-            'new_password1': 'password1',
-            'new_password2': 'password1',
-        })
-        self.assertRedirects(response, '/password_reset/', fetch_redirect_response=False)
+        response = self.client.post(
+            "/password_change/custom/named/",
+            {
+                "old_password": "password",
+                "new_password1": "password1",
+                "new_password2": "password1",
+            },
+        )
+        self.assertRedirects(
+            response, "/password_reset/", fetch_redirect_response=False
+        )

 class SessionAuthenticationTests(AuthViewsTestCase):
     def test_user_password_change_updates_session(self):
         """
         #21649 - Ensure contrib.auth.views.password_change updates the user's
         session auth hash after a password change so the session isn't logged out.
         """
         self.login()
         original_session_key = self.client.session.session_key
-        response = self.client.post('/password_change/', {
-            'old_password': 'password',
-            'new_password1': 'password1',
-            'new_password2': 'password1',
-        })
+        response = self.client.post(
+            "/password_change/",
+            {
+                "old_password": "password",
+                "new_password1": "password1",
+                "new_password2": "password1",
+            },
+        )
         # if the hash isn't updated, retrieving the redirection page will fail.
-        self.assertRedirects(response, '/password_change/done/')
+        self.assertRedirects(response, "/password_change/done/")
         # The session key is rotated.
         self.assertNotEqual(original_session_key, self.client.session.session_key)

 class LoginTest(AuthViewsTestCase):
-
     def test_current_site_in_context_after_login(self):
-        response = self.client.get(reverse('login'))
+        response = self.client.get(reverse("login"))
         self.assertEqual(response.status_code, 200)
-        if apps.is_installed('django.contrib.sites'):
-            Site = apps.get_model('sites.Site')
+        if apps.is_installed("django.contrib.sites"):
+            Site = apps.get_model("sites.Site")
             site = Site.objects.get_current()
-            self.assertEqual(response.context['site'], site)
-            self.assertEqual(response.context['site_name'], site.name)
+            self.assertEqual(response.context["site"], site)
+            self.assertEqual(response.context["site_name"], site.name)
         else:
-            self.assertIsInstance(response.context['site'], RequestSite)
-        self.assertIsInstance(response.context['form'], AuthenticationForm)
+            self.assertIsInstance(response.context["site"], RequestSite)
+        self.assertIsInstance(response.context["form"], AuthenticationForm)

     def test_security_check(self):
-        login_url = reverse('login')
+        login_url = reverse("login")

         # These URLs should not pass the security check.
         bad_urls = (
-            'http://example.com',
-            'http:///example.com',
-            'https://example.com',
-            'ftp://example.com',
-            '///example.com',
-            '//example.com',
+            "http://example.com",
+            "http:///example.com",
+            "https://example.com",
+            "ftp://example.com",
+            "///example.com",
+            "//example.com",
             'javascript:alert("XSS")',
         )
         for bad_url in bad_urls:
             with self.subTest(bad_url=bad_url):
-                nasty_url = '%(url)s?%(next)s=%(bad_url)s' % {
-                    'url': login_url,
-                    'next': REDIRECT_FIELD_NAME,
-                    'bad_url': quote(bad_url),
+                nasty_url = "%(url)s?%(next)s=%(bad_url)s" % {
+                    "url": login_url,
+                    "next": REDIRECT_FIELD_NAME,
+                    "bad_url": quote(bad_url),
                 }
-                response = self.client.post(nasty_url, {
-                    'username': 'testclient',
-                    'password': 'password',
-                })
+                response = self.client.post(
+                    nasty_url, {"username": "testclient", "password": "password",}
+                )
                 self.assertEqual(response.status_code, 302)
-                self.assertNotIn(bad_url, response.url, '%s should be blocked' % bad_url)
+                self.assertNotIn(
+                    bad_url, response.url, "%s should be blocked" % bad_url
+                )

         # These URLs should pass the security check.
         good_urls = (
-            '/view/?param=http://example.com',
-            '/view/?param=https://example.com',
-            '/view?param=ftp://example.com',
-            'view/?param=//example.com',
-            'https://testserver/',
-            'HTTPS://testserver/',
-            '//testserver/',
-            '/url%20with%20spaces/',
+            "/view/?param=http://example.com",
+            "/view/?param=https://example.com",
+            "/view?param=ftp://example.com",
+            "view/?param=//example.com",
+            "https://testserver/",
+            "HTTPS://testserver/",
+            "//testserver/",
+            "/url%20with%20spaces/",
         )
         for good_url in good_urls:
             with self.subTest(good_url=good_url):
-                safe_url = '%(url)s?%(next)s=%(good_url)s' % {
-                    'url': login_url,
-                    'next': REDIRECT_FIELD_NAME,
-                    'good_url': quote(good_url),
+                safe_url = "%(url)s?%(next)s=%(good_url)s" % {
+                    "url": login_url,
+                    "next": REDIRECT_FIELD_NAME,
+                    "good_url": quote(good_url),
                 }
-                response = self.client.post(safe_url, {
-                    'username': 'testclient',
-                    'password': 'password',
-                })
+                response = self.client.post(
+                    safe_url, {"username": "testclient", "password": "password",}
+                )
                 self.assertEqual(response.status_code, 302)
-                self.assertIn(good_url, response.url, '%s should be allowed' % good_url)
+                self.assertIn(good_url, response.url, "%s should be allowed" % good_url)

     def test_security_check_https(self):
-        login_url = reverse('login')
-        non_https_next_url = 'http://testserver/path'
-        not_secured_url = '%(url)s?%(next)s=%(next_url)s' % {
-            'url': login_url,
-            'next': REDIRECT_FIELD_NAME,
-            'next_url': quote(non_https_next_url),
+        login_url = reverse("login")
+        non_https_next_url = "http://testserver/path"
+        not_secured_url = "%(url)s?%(next)s=%(next_url)s" % {
+            "url": login_url,
+            "next": REDIRECT_FIELD_NAME,
+            "next_url": quote(non_https_next_url),
         }
         post_data = {
-            'username': 'testclient',
-            'password': 'password',
+            "username": "testclient",
+            "password": "password",
         }
         response = self.client.post(not_secured_url, post_data, secure=True)
         self.assertEqual(response.status_code, 302)
         self.assertNotEqual(response.url, non_https_next_url)
         self.assertEqual(response.url, settings.LOGIN_REDIRECT_URL)

     def test_login_form_contains_request(self):
         # The custom authentication form for this login requires a request to
         # initialize it.
-        response = self.client.post('/custom_request_auth_login/', {
-            'username': 'testclient',
-            'password': 'password',
-        })
+        response = self.client.post(
+            "/custom_request_auth_login/",
+            {"username": "testclient", "password": "password",},
+        )
         # The login was successful.
-        self.assertRedirects(response, settings.LOGIN_REDIRECT_URL, fetch_redirect_response=False)
+        self.assertRedirects(
+            response, settings.LOGIN_REDIRECT_URL, fetch_redirect_response=False
+        )

     def test_login_csrf_rotate(self):
         """
         Makes sure that a login rotates the currently-used CSRF token.
         """
+
         def get_response(request):
             return HttpResponse()

         # Do a GET to establish a CSRF token
         # The test client isn't used here as it's a test for middleware.
@@ -665,16 +751,22 @@

         # Prepare the POST request
         req = HttpRequest()
         req.COOKIES[settings.CSRF_COOKIE_NAME] = token1
         req.method = "POST"
-        req.POST = {'username': 'testclient', 'password': 'password', 'csrfmiddlewaretoken': token1}
+        req.POST = {
+            "username": "testclient",
+            "password": "password",
+            "csrfmiddlewaretoken": token1,
+        }

         # Use POST request to log in
         SessionMiddleware(get_response).process_request(req)
         CsrfViewMiddleware(get_response).process_view(req, LoginView.as_view(), (), {})
-        req.META["SERVER_NAME"] = "testserver"  # Required to have redirect work in login view
+        req.META["SERVER_NAME"] = (  # Required to have redirect work in login view
+            "testserver"
+        )
         req.META["SERVER_PORT"] = 80
         resp = CsrfViewMiddleware(LoginView.as_view())(req)
         csrf_cookie = resp.cookies.get(settings.CSRF_COOKIE_NAME, None)
         token2 = csrf_cookie.coded_value

@@ -688,11 +780,11 @@
         user.
         """
         self.login()
         original_session_key = self.client.session.session_key

-        self.login(username='staff')
+        self.login(username="staff")
         self.assertNotEqual(original_session_key, self.client.session.session_key)

     def test_session_key_flushed_on_login_after_password_change(self):
         """
         As above, but same user logging in after a password change.
@@ -702,20 +794,20 @@

         # If no password change, session key should not be flushed.
         self.login()
         self.assertEqual(original_session_key, self.client.session.session_key)

-        user = User.objects.get(username='testclient')
-        user.set_password('foobar')
+        user = User.objects.get(username="testclient")
+        user.set_password("foobar")
         user.save()

-        self.login(password='foobar')
+        self.login(password="foobar")
         self.assertNotEqual(original_session_key, self.client.session.session_key)

     def test_legacy_session_key_flushed_on_login(self):
         # RemovedInDjango40Warning.
-        user = User.objects.get(username='testclient')
+        user = User.objects.get(username="testclient")
         engine = import_module(settings.SESSION_ENGINE)
         session = engine.SessionStore()
         session[SESSION_KEY] = user.id
         session[HASH_SESSION_KEY] = user._legacy_get_session_auth_hash()
         session.save()
@@ -723,23 +815,23 @@
         self.client.cookies[settings.SESSION_COOKIE_NAME] = original_session_key
         # Legacy session key is flushed on login.
         self.login()
         self.assertNotEqual(original_session_key, self.client.session.session_key)
         # Legacy session key is flushed after a password change.
-        user.set_password('password_2')
+        user.set_password("password_2")
         user.save()
         original_session_key = session.session_key
         self.client.cookies[settings.SESSION_COOKIE_NAME] = original_session_key
-        self.login(password='password_2')
+        self.login(password="password_2")
         self.assertNotEqual(original_session_key, self.client.session.session_key)

     def test_login_session_without_hash_session_key(self):
         """
         Session without django.contrib.auth.HASH_SESSION_KEY should login
         without an exception.
         """
-        user = User.objects.get(username='testclient')
+        user = User.objects.get(username="testclient")
         engine = import_module(settings.SESSION_ENGINE)
         session = engine.SessionStore()
         session[SESSION_KEY] = user.id
         session.save()
         original_session_key = session.session_key
@@ -749,147 +841,152 @@
         self.assertNotEqual(original_session_key, self.client.session.session_key)

 class LoginURLSettings(AuthViewsTestCase):
     """Tests for settings.LOGIN_URL."""
+
     def assertLoginURLEquals(self, url):
-        response = self.client.get('/login_required/')
+        response = self.client.get("/login_required/")
         self.assertRedirects(response, url, fetch_redirect_response=False)

-    @override_settings(LOGIN_URL='/login/')
+    @override_settings(LOGIN_URL="/login/")
     def test_standard_login_url(self):
-        self.assertLoginURLEquals('/login/?next=/login_required/')
-
-    @override_settings(LOGIN_URL='login')
+        self.assertLoginURLEquals("/login/?next=/login_required/")
+
+    @override_settings(LOGIN_URL="login")
     def test_named_login_url(self):
-        self.assertLoginURLEquals('/login/?next=/login_required/')
-
-    @override_settings(LOGIN_URL='http://remote.example.com/login')
+        self.assertLoginURLEquals("/login/?next=/login_required/")
+
+    @override_settings(LOGIN_URL="http://remote.example.com/login")
     def test_remote_login_url(self):
-        quoted_next = quote('http://testserver/login_required/')
-        expected = 'http://remote.example.com/login?next=%s' % quoted_next
+        quoted_next = quote("http://testserver/login_required/")
+        expected = "http://remote.example.com/login?next=%s" % quoted_next
         self.assertLoginURLEquals(expected)

-    @override_settings(LOGIN_URL='https:///login/')
+    @override_settings(LOGIN_URL="https:///login/")
     def test_https_login_url(self):
-        quoted_next = quote('http://testserver/login_required/')
-        expected = 'https:///login/?next=%s' % quoted_next
+        quoted_next = quote("http://testserver/login_required/")
+        expected = "https:///login/?next=%s" % quoted_next
         self.assertLoginURLEquals(expected)

-    @override_settings(LOGIN_URL='/login/?pretty=1')
+    @override_settings(LOGIN_URL="/login/?pretty=1")
     def test_login_url_with_querystring(self):
-        self.assertLoginURLEquals('/login/?pretty=1&next=/login_required/')
-
-    @override_settings(LOGIN_URL='http://remote.example.com/login/?next=/default/')
+        self.assertLoginURLEquals("/login/?pretty=1&next=/login_required/")
+
+    @override_settings(LOGIN_URL="http://remote.example.com/login/?next=/default/")
     def test_remote_login_url_with_next_querystring(self):
-        quoted_next = quote('http://testserver/login_required/')
-        expected = 'http://remote.example.com/login/?next=%s' % quoted_next
+        quoted_next = quote("http://testserver/login_required/")
+        expected = "http://remote.example.com/login/?next=%s" % quoted_next
         self.assertLoginURLEquals(expected)

-    @override_settings(LOGIN_URL=reverse_lazy('login'))
+    @override_settings(LOGIN_URL=reverse_lazy("login"))
     def test_lazy_login_url(self):
-        self.assertLoginURLEquals('/login/?next=/login_required/')
+        self.assertLoginURLEquals("/login/?next=/login_required/")

 class LoginRedirectUrlTest(AuthViewsTestCase):
     """Tests for settings.LOGIN_REDIRECT_URL."""
+
     def assertLoginRedirectURLEqual(self, url):
         response = self.login()
         self.assertRedirects(response, url, fetch_redirect_response=False)

     def test_default(self):
-        self.assertLoginRedirectURLEqual('/accounts/profile/')
-
-    @override_settings(LOGIN_REDIRECT_URL='/custom/')
+        self.assertLoginRedirectURLEqual("/accounts/profile/")
+
+    @override_settings(LOGIN_REDIRECT_URL="/custom/")
     def test_custom(self):
-        self.assertLoginRedirectURLEqual('/custom/')
-
-    @override_settings(LOGIN_REDIRECT_URL='password_reset')
+        self.assertLoginRedirectURLEqual("/custom/")
+
+    @override_settings(LOGIN_REDIRECT_URL="password_reset")
     def test_named(self):
-        self.assertLoginRedirectURLEqual('/password_reset/')
-
-    @override_settings(LOGIN_REDIRECT_URL='http://remote.example.com/welcome/')
+        self.assertLoginRedirectURLEqual("/password_reset/")
+
+    @override_settings(LOGIN_REDIRECT_URL="http://remote.example.com/welcome/")
     def test_remote(self):
-        self.assertLoginRedirectURLEqual('http://remote.example.com/welcome/')
+        self.assertLoginRedirectURLEqual("http://remote.example.com/welcome/")

 class RedirectToLoginTests(AuthViewsTestCase):
     """Tests for the redirect_to_login view"""
-    @override_settings(LOGIN_URL=reverse_lazy('login'))
+
+    @override_settings(LOGIN_URL=reverse_lazy("login"))
     def test_redirect_to_login_with_lazy(self):
-        login_redirect_response = redirect_to_login(next='/else/where/')
-        expected = '/login/?next=/else/where/'
+        login_redirect_response = redirect_to_login(next="/else/where/")
+        expected = "/login/?next=/else/where/"
         self.assertEqual(expected, login_redirect_response.url)

-    @override_settings(LOGIN_URL=reverse_lazy('login'))
+    @override_settings(LOGIN_URL=reverse_lazy("login"))
     def test_redirect_to_login_with_lazy_and_unicode(self):
-        login_redirect_response = redirect_to_login(next='/else/where/झ/')
-        expected = '/login/?next=/else/where/%E0%A4%9D/'
+        login_redirect_response = redirect_to_login(next="/else/where/झ/")
+        expected = "/login/?next=/else/where/%E0%A4%9D/"
         self.assertEqual(expected, login_redirect_response.url)

 class LogoutThenLoginTests(AuthViewsTestCase):
     """Tests for the logout_then_login view"""

     def confirm_logged_out(self):
         self.assertNotIn(SESSION_KEY, self.client.session)

-    @override_settings(LOGIN_URL='/login/')
+    @override_settings(LOGIN_URL="/login/")
     def test_default_logout_then_login(self):
         self.login()
         req = HttpRequest()
-        req.method = 'GET'
+        req.method = "GET"
         req.session = self.client.session
         response = logout_then_login(req)
         self.confirm_logged_out()
-        self.assertRedirects(response, '/login/', fetch_redirect_response=False)
+        self.assertRedirects(response, "/login/", fetch_redirect_response=False)

     def test_logout_then_login_with_custom_login(self):
         self.login()
         req = HttpRequest()
-        req.method = 'GET'
+        req.method = "GET"
         req.session = self.client.session
-        response = logout_then_login(req, login_url='/custom/')
+        response = logout_then_login(req, login_url="/custom/")
         self.confirm_logged_out()
-        self.assertRedirects(response, '/custom/', fetch_redirect_response=False)
+        self.assertRedirects(response, "/custom/", fetch_redirect_response=False)

 class LoginRedirectAuthenticatedUser(AuthViewsTestCase):
-    dont_redirect_url = '/login/redirect_authenticated_user_default/'
-    do_redirect_url = '/login/redirect_authenticated_user/'
+    dont_redirect_url = "/login/redirect_authenticated_user_default/"
+    do_redirect_url = "/login/redirect_authenticated_user/"

     def test_default(self):
         """Stay on the login page by default."""
         self.login()
         response = self.client.get(self.dont_redirect_url)
         self.assertEqual(response.status_code, 200)
-        self.assertEqual(response.context['next'], '')
+        self.assertEqual(response.context["next"], "")

     def test_guest(self):
         """If not logged in, stay on the same page."""
         response = self.client.get(self.do_redirect_url)
         self.assertEqual(response.status_code, 200)

     def test_redirect(self):
         """If logged in, go to default redirected URL."""
         self.login()
         response = self.client.get(self.do_redirect_url)
-        self.assertRedirects(response, '/accounts/profile/', fetch_redirect_response=False)
-
-    @override_settings(LOGIN_REDIRECT_URL='/custom/')
+        self.assertRedirects(
+            response, "/accounts/profile/", fetch_redirect_response=False
+        )
+
+    @override_settings(LOGIN_REDIRECT_URL="/custom/")
     def test_redirect_url(self):
         """If logged in, go to custom redirected URL."""
         self.login()
         response = self.client.get(self.do_redirect_url)
-        self.assertRedirects(response, '/custom/', fetch_redirect_response=False)
+        self.assertRedirects(response, "/custom/", fetch_redirect_response=False)

     def test_redirect_param(self):
         """If next is specified as a GET parameter, go there."""
         self.login()
-        url = self.do_redirect_url + '?next=/custom_next/'
+        url = self.do_redirect_url + "?next=/custom_next/"
         response = self.client.get(url)
-        self.assertRedirects(response, '/custom_next/', fetch_redirect_response=False)
+        self.assertRedirects(response, "/custom_next/", fetch_redirect_response=False)

     def test_redirect_loop(self):
         """
         Detect a redirect loop if LOGIN_REDIRECT_URL is not correctly set,
         with and without custom parameters.
@@ -901,426 +998,470 @@
         )
         with self.settings(LOGIN_REDIRECT_URL=self.do_redirect_url):
             with self.assertRaisesMessage(ValueError, msg):
                 self.client.get(self.do_redirect_url)

-            url = self.do_redirect_url + '?bla=2'
+            url = self.do_redirect_url + "?bla=2"
             with self.assertRaisesMessage(ValueError, msg):
                 self.client.get(url)

     def test_permission_required_not_logged_in(self):
         # Not logged in ...
         with self.settings(LOGIN_URL=self.do_redirect_url):
             # redirected to login.
-            response = self.client.get('/permission_required_redirect/', follow=True)
+            response = self.client.get("/permission_required_redirect/", follow=True)
             self.assertEqual(response.status_code, 200)
             # exception raised.
-            response = self.client.get('/permission_required_exception/', follow=True)
+            response = self.client.get("/permission_required_exception/", follow=True)
             self.assertEqual(response.status_code, 403)
             # redirected to login.
-            response = self.client.get('/login_and_permission_required_exception/', follow=True)
+            response = self.client.get(
+                "/login_and_permission_required_exception/", follow=True
+            )
             self.assertEqual(response.status_code, 200)

     def test_permission_required_logged_in(self):
         self.login()
         # Already logged in...
         with self.settings(LOGIN_URL=self.do_redirect_url):
             # redirect loop encountered.
-            with self.assertRaisesMessage(RedirectCycleError, 'Redirect loop detected.'):
-                self.client.get('/permission_required_redirect/', follow=True)
+            with self.assertRaisesMessage(
+                RedirectCycleError, "Redirect loop detected."
+            ):
+                self.client.get("/permission_required_redirect/", follow=True)
             # exception raised.
-            response = self.client.get('/permission_required_exception/', follow=True)
+            response = self.client.get("/permission_required_exception/", follow=True)
             self.assertEqual(response.status_code, 403)
             # exception raised.
-            response = self.client.get('/login_and_permission_required_exception/', follow=True)
+            response = self.client.get(
+                "/login_and_permission_required_exception/", follow=True
+            )
             self.assertEqual(response.status_code, 403)

 class LoginSuccessURLAllowedHostsTest(AuthViewsTestCase):
     def test_success_url_allowed_hosts_same_host(self):
-        response = self.client.post('/login/allowed_hosts/', {
-            'username': 'testclient',
-            'password': 'password',
-            'next': 'https://testserver/home',
-        })
+        response = self.client.post(
+            "/login/allowed_hosts/",
+            {
+                "username": "testclient",
+                "password": "password",
+                "next": "https://testserver/home",
+            },
+        )
         self.assertIn(SESSION_KEY, self.client.session)
-        self.assertRedirects(response, 'https://testserver/home', fetch_redirect_response=False)
+        self.assertRedirects(
+            response, "https://testserver/home", fetch_redirect_response=False
+        )

     def test_success_url_allowed_hosts_safe_host(self):
-        response = self.client.post('/login/allowed_hosts/', {
-            'username': 'testclient',
-            'password': 'password',
-            'next': 'https://otherserver/home',
-        })
+        response = self.client.post(
+            "/login/allowed_hosts/",
+            {
+                "username": "testclient",
+                "password": "password",
+                "next": "https://otherserver/home",
+            },
+        )
         self.assertIn(SESSION_KEY, self.client.session)
-        self.assertRedirects(response, 'https://otherserver/home', fetch_redirect_response=False)
+        self.assertRedirects(
+            response, "https://otherserver/home", fetch_redirect_response=False
+        )

     def test_success_url_allowed_hosts_unsafe_host(self):
-        response = self.client.post('/login/allowed_hosts/', {
-            'username': 'testclient',
-            'password': 'password',
-            'next': 'https://evil/home',
-        })
+        response = self.client.post(
+            "/login/allowed_hosts/",
+            {
+                "username": "testclient",
+                "password": "password",
+                "next": "https://evil/home",
+            },
+        )
         self.assertIn(SESSION_KEY, self.client.session)
-        self.assertRedirects(response, '/accounts/profile/', fetch_redirect_response=False)
+        self.assertRedirects(
+            response, "/accounts/profile/", fetch_redirect_response=False
+        )

 class LogoutTest(AuthViewsTestCase):
-
     def confirm_logged_out(self):
         self.assertNotIn(SESSION_KEY, self.client.session)

     def test_logout_default(self):
         "Logout without next_page option renders the default template"
         self.login()
-        response = self.client.get('/logout/')
-        self.assertContains(response, 'Logged out')
+        response = self.client.get("/logout/")
+        self.assertContains(response, "Logged out")
         self.confirm_logged_out()

     def test_logout_with_post(self):
         self.login()
-        response = self.client.post('/logout/')
-        self.assertContains(response, 'Logged out')
+        response = self.client.post("/logout/")
+        self.assertContains(response, "Logged out")
         self.confirm_logged_out()

     def test_14377(self):
         # Bug 14377
         self.login()
-        response = self.client.get('/logout/')
-        self.assertIn('site', response.context)
+        response = self.client.get("/logout/")
+        self.assertIn("site", response.context)

     def test_logout_doesnt_cache(self):
         """
         The logout() view should send "no-cache" headers for reasons described
         in #25490.
         """
-        response = self.client.get('/logout/')
-        self.assertIn('no-store', response['Cache-Control'])
+        response = self.client.get("/logout/")
+        self.assertIn("no-store", response["Cache-Control"])

     def test_logout_with_overridden_redirect_url(self):
         # Bug 11223
         self.login()
-        response = self.client.get('/logout/next_page/')
-        self.assertRedirects(response, '/somewhere/', fetch_redirect_response=False)
-
-        response = self.client.get('/logout/next_page/?next=/login/')
-        self.assertRedirects(response, '/login/', fetch_redirect_response=False)
+        response = self.client.get("/logout/next_page/")
+        self.assertRedirects(response, "/somewhere/", fetch_redirect_response=False)
+
+        response = self.client.get("/logout/next_page/?next=/login/")
+        self.assertRedirects(response, "/login/", fetch_redirect_response=False)

         self.confirm_logged_out()

     def test_logout_with_next_page_specified(self):
         "Logout with next_page option given redirects to specified resource"
         self.login()
-        response = self.client.get('/logout/next_page/')
-        self.assertRedirects(response, '/somewhere/', fetch_redirect_response=False)
+        response = self.client.get("/logout/next_page/")
+        self.assertRedirects(response, "/somewhere/", fetch_redirect_response=False)
         self.confirm_logged_out()

     def test_logout_with_redirect_argument(self):
         "Logout with query string redirects to specified resource"
         self.login()
-        response = self.client.get('/logout/?next=/login/')
-        self.assertRedirects(response, '/login/', fetch_redirect_response=False)
+        response = self.client.get("/logout/?next=/login/")
+        self.assertRedirects(response, "/login/", fetch_redirect_response=False)
         self.confirm_logged_out()

     def test_logout_with_custom_redirect_argument(self):
         "Logout with custom query string redirects to specified resource"
         self.login()
-        response = self.client.get('/logout/custom_query/?follow=/somewhere/')
-        self.assertRedirects(response, '/somewhere/', fetch_redirect_response=False)
+        response = self.client.get("/logout/custom_query/?follow=/somewhere/")
+        self.assertRedirects(response, "/somewhere/", fetch_redirect_response=False)
         self.confirm_logged_out()

     def test_logout_with_named_redirect(self):
         "Logout resolves names or URLs passed as next_page."
         self.login()
-        response = self.client.get('/logout/next_page/named/')
-        self.assertRedirects(response, '/password_reset/', fetch_redirect_response=False)
+        response = self.client.get("/logout/next_page/named/")
+        self.assertRedirects(
+            response, "/password_reset/", fetch_redirect_response=False
+        )
         self.confirm_logged_out()

     def test_success_url_allowed_hosts_same_host(self):
         self.login()
-        response = self.client.get('/logout/allowed_hosts/?next=https://testserver/')
-        self.assertRedirects(response, 'https://testserver/', fetch_redirect_response=False)
+        response = self.client.get("/logout/allowed_hosts/?next=https://testserver/")
+        self.assertRedirects(
+            response, "https://testserver/", fetch_redirect_response=False
+        )
         self.confirm_logged_out()

     def test_success_url_allowed_hosts_safe_host(self):
         self.login()
-        response = self.client.get('/logout/allowed_hosts/?next=https://otherserver/')
-        self.assertRedirects(response, 'https://otherserver/', fetch_redirect_response=False)
+        response = self.client.get("/logout/allowed_hosts/?next=https://otherserver/")
+        self.assertRedirects(
+            response, "https://otherserver/", fetch_redirect_response=False
+        )
         self.confirm_logged_out()

     def test_success_url_allowed_hosts_unsafe_host(self):
         self.login()
-        response = self.client.get('/logout/allowed_hosts/?next=https://evil/')
-        self.assertRedirects(response, '/logout/allowed_hosts/', fetch_redirect_response=False)
+        response = self.client.get("/logout/allowed_hosts/?next=https://evil/")
+        self.assertRedirects(
+            response, "/logout/allowed_hosts/", fetch_redirect_response=False
+        )
         self.confirm_logged_out()

     def test_security_check(self):
-        logout_url = reverse('logout')
+        logout_url = reverse("logout")

         # These URLs should not pass the security check.
         bad_urls = (
-            'http://example.com',
-            'http:///example.com',
-            'https://example.com',
-            'ftp://example.com',
-            '///example.com',
-            '//example.com',
+            "http://example.com",
+            "http:///example.com",
+            "https://example.com",
+            "ftp://example.com",
+            "///example.com",
+            "//example.com",
             'javascript:alert("XSS")',
         )
         for bad_url in bad_urls:
             with self.subTest(bad_url=bad_url):
-                nasty_url = '%(url)s?%(next)s=%(bad_url)s' % {
-                    'url': logout_url,
-                    'next': REDIRECT_FIELD_NAME,
-                    'bad_url': quote(bad_url),
+                nasty_url = "%(url)s?%(next)s=%(bad_url)s" % {
+                    "url": logout_url,
+                    "next": REDIRECT_FIELD_NAME,
+                    "bad_url": quote(bad_url),
                 }
                 self.login()
                 response = self.client.get(nasty_url)
                 self.assertEqual(response.status_code, 302)
-                self.assertNotIn(bad_url, response.url, '%s should be blocked' % bad_url)
+                self.assertNotIn(
+                    bad_url, response.url, "%s should be blocked" % bad_url
+                )
                 self.confirm_logged_out()

         # These URLs should pass the security check.
         good_urls = (
-            '/view/?param=http://example.com',
-            '/view/?param=https://example.com',
-            '/view?param=ftp://example.com',
-            'view/?param=//example.com',
-            'https://testserver/',
-            'HTTPS://testserver/',
-            '//testserver/',
-            '/url%20with%20spaces/',
+            "/view/?param=http://example.com",
+            "/view/?param=https://example.com",
+            "/view?param=ftp://example.com",
+            "view/?param=//example.com",
+            "https://testserver/",
+            "HTTPS://testserver/",
+            "//testserver/",
+            "/url%20with%20spaces/",
         )
         for good_url in good_urls:
             with self.subTest(good_url=good_url):
-                safe_url = '%(url)s?%(next)s=%(good_url)s' % {
-                    'url': logout_url,
-                    'next': REDIRECT_FIELD_NAME,
-                    'good_url': quote(good_url),
+                safe_url = "%(url)s?%(next)s=%(good_url)s" % {
+                    "url": logout_url,
+                    "next": REDIRECT_FIELD_NAME,
+                    "good_url": quote(good_url),
                 }
                 self.login()
                 response = self.client.get(safe_url)
                 self.assertEqual(response.status_code, 302)
-                self.assertIn(good_url, response.url, '%s should be allowed' % good_url)
+                self.assertIn(good_url, response.url, "%s should be allowed" % good_url)
                 self.confirm_logged_out()

     def test_security_check_https(self):
-        logout_url = reverse('logout')
-        non_https_next_url = 'http://testserver/'
-        url = '%(url)s?%(next)s=%(next_url)s' % {
-            'url': logout_url,
-            'next': REDIRECT_FIELD_NAME,
-            'next_url': quote(non_https_next_url),
+        logout_url = reverse("logout")
+        non_https_next_url = "http://testserver/"
+        url = "%(url)s?%(next)s=%(next_url)s" % {
+            "url": logout_url,
+            "next": REDIRECT_FIELD_NAME,
+            "next_url": quote(non_https_next_url),
         }
         self.login()
         response = self.client.get(url, secure=True)
         self.assertRedirects(response, logout_url, fetch_redirect_response=False)
         self.confirm_logged_out()

     def test_logout_preserve_language(self):
         """Language is preserved after logout."""
         self.login()
-        self.client.post('/setlang/', {'language': 'pl'})
-        self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, 'pl')
-        self.client.get('/logout/')
-        self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, 'pl')
-
-    @override_settings(LOGOUT_REDIRECT_URL='/custom/')
+        self.client.post("/setlang/", {"language": "pl"})
+        self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, "pl")
+        self.client.get("/logout/")
+        self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, "pl")
+
+    @override_settings(LOGOUT_REDIRECT_URL="/custom/")
     def test_logout_redirect_url_setting(self):
         self.login()
-        response = self.client.get('/logout/')
-        self.assertRedirects(response, '/custom/', fetch_redirect_response=False)
-
-    @override_settings(LOGOUT_REDIRECT_URL='logout')
+        response = self.client.get("/logout/")
+        self.assertRedirects(response, "/custom/", fetch_redirect_response=False)
+
+    @override_settings(LOGOUT_REDIRECT_URL="logout")
     def test_logout_redirect_url_named_setting(self):
         self.login()
-        response = self.client.get('/logout/')
-        self.assertRedirects(response, '/logout/', fetch_redirect_response=False)
+        response = self.client.get("/logout/")
+        self.assertRedirects(response, "/logout/", fetch_redirect_response=False)

 def get_perm(Model, perm):
     ct = ContentType.objects.get_for_model(Model)
     return Permission.objects.get(content_type=ct, codename=perm)

 # Redirect in test_user_change_password will fail if session auth hash
 # isn't updated after password change (#21649)
-@override_settings(ROOT_URLCONF='auth_tests.urls_admin')
+@override_settings(ROOT_URLCONF="auth_tests.urls_admin")
 class ChangelistTests(AuthViewsTestCase):
-
     @classmethod
     def setUpTestData(cls):
         super().setUpTestData()
         # Make me a superuser before logging in.
-        User.objects.filter(username='testclient').update(is_staff=True, is_superuser=True)
+        User.objects.filter(username="testclient").update(
+            is_staff=True, is_superuser=True
+        )

     def setUp(self):
         self.login()
         # Get the latest last_login value.
         self.admin = User.objects.get(pk=self.u1.pk)

     def get_user_data(self, user):
         return {
-            'username': user.username,
-            'password': user.password,
-            'email': user.email,
-            'is_active': user.is_active,
-            'is_staff': user.is_staff,
-            'is_superuser': user.is_superuser,
-            'last_login_0': user.last_login.strftime('%Y-%m-%d'),
-            'last_login_1': user.last_login.strftime('%H:%M:%S'),
-            'initial-last_login_0': user.last_login.strftime('%Y-%m-%d'),
-            'initial-last_login_1': user.last_login.strftime('%H:%M:%S'),
-            'date_joined_0': user.date_joined.strftime('%Y-%m-%d'),
-            'date_joined_1': user.date_joined.strftime('%H:%M:%S'),
-            'initial-date_joined_0': user.date_joined.strftime('%Y-%m-%d'),
-            'initial-date_joined_1': user.date_joined.strftime('%H:%M:%S'),
-            'first_name': user.first_name,
-            'last_name': user.last_name,
+            "username": user.username,
+            "password": user.password,
+            "email": user.email,
+            "is_active": user.is_active,
+            "is_staff": user.is_staff,
+            "is_superuser": user.is_superuser,
+            "last_login_0": user.last_login.strftime("%Y-%m-%d"),
+            "last_login_1": user.last_login.strftime("%H:%M:%S"),
+            "initial-last_login_0": user.last_login.strftime("%Y-%m-%d"),
+            "initial-last_login_1": user.last_login.strftime("%H:%M:%S"),
+            "date_joined_0": user.date_joined.strftime("%Y-%m-%d"),
+            "date_joined_1": user.date_joined.strftime("%H:%M:%S"),
+            "initial-date_joined_0": user.date_joined.strftime("%Y-%m-%d"),
+            "initial-date_joined_1": user.date_joined.strftime("%H:%M:%S"),
+            "first_name": user.first_name,
+            "last_name": user.last_name,
         }

     # #20078 - users shouldn't be allowed to guess password hashes via
     # repeated password__startswith queries.
     def test_changelist_disallows_password_lookups(self):
         # A lookup that tries to filter on password isn't OK
-        with self.assertLogs('django.security.DisallowedModelAdminLookup', 'ERROR'):
-            response = self.client.get(reverse('auth_test_admin:auth_user_changelist') + '?password__startswith=sha1$')
+        with self.assertLogs("django.security.DisallowedModelAdminLookup", "ERROR"):
+            response = self.client.get(
+                reverse("auth_test_admin:auth_user_changelist")
+                + "?password__startswith=sha1$"
+            )
         self.assertEqual(response.status_code, 400)

     def test_user_change_email(self):
         data = self.get_user_data(self.admin)
-        data['email'] = 'new_' + data['email']
-        response = self.client.post(
-            reverse('auth_test_admin:auth_user_change', args=(self.admin.pk,)),
-            data
-        )
-        self.assertRedirects(response, reverse('auth_test_admin:auth_user_changelist'))
-        row = LogEntry.objects.latest('id')
-        self.assertEqual(row.get_change_message(), 'Changed Email address.')
+        data["email"] = "new_" + data["email"]
+        response = self.client.post(
+            reverse("auth_test_admin:auth_user_change", args=(self.admin.pk,)), data
+        )
+        self.assertRedirects(response, reverse("auth_test_admin:auth_user_changelist"))
+        row = LogEntry.objects.latest("id")
+        self.assertEqual(row.get_change_message(), "Changed Email address.")

     def test_user_not_change(self):
         response = self.client.post(
-            reverse('auth_test_admin:auth_user_change', args=(self.admin.pk,)),
-            self.get_user_data(self.admin)
-        )
-        self.assertRedirects(response, reverse('auth_test_admin:auth_user_changelist'))
-        row = LogEntry.objects.latest('id')
-        self.assertEqual(row.get_change_message(), 'No fields changed.')
+            reverse("auth_test_admin:auth_user_change", args=(self.admin.pk,)),
+            self.get_user_data(self.admin),
+        )
+        self.assertRedirects(response, reverse("auth_test_admin:auth_user_changelist"))
+        row = LogEntry.objects.latest("id")
+        self.assertEqual(row.get_change_message(), "No fields changed.")

     def test_user_change_password(self):
-        user_change_url = reverse('auth_test_admin:auth_user_change', args=(self.admin.pk,))
-        password_change_url = reverse('auth_test_admin:auth_user_password_change', args=(self.admin.pk,))
+        user_change_url = reverse(
+            "auth_test_admin:auth_user_change", args=(self.admin.pk,)
+        )
+        password_change_url = reverse(
+            "auth_test_admin:auth_user_password_change", args=(self.admin.pk,)
+        )

         response = self.client.get(user_change_url)
         # Test the link inside password field help_text.
         rel_link = re.search(
             r'you can change the password using <a href="([^"]*)">this form</a>',
-            response.content.decode()
+            response.content.decode(),
         )[1]
         self.assertEqual(
             os.path.normpath(user_change_url + rel_link),
-            os.path.normpath(password_change_url)
-        )
-
-        response = self.client.post(
-            password_change_url,
-            {
-                'password1': 'password1',
-                'password2': 'password1',
-            }
+            os.path.normpath(password_change_url),
+        )
+
+        response = self.client.post(
+            password_change_url, {"password1": "password1", "password2": "password1",}
         )
         self.assertRedirects(response, user_change_url)
-        row = LogEntry.objects.latest('id')
-        self.assertEqual(row.get_change_message(), 'Changed password.')
+        row = LogEntry.objects.latest("id")
+        self.assertEqual(row.get_change_message(), "Changed password.")
         self.logout()
-        self.login(password='password1')
+        self.login(password="password1")

     def test_user_change_different_user_password(self):
-        u = User.objects.get(email='staffmember@example.com')
-        response = self.client.post(
-            reverse('auth_test_admin:auth_user_password_change', args=(u.pk,)),
-            {
-                'password1': 'password1',
-                'password2': 'password1',
-            }
-        )
-        self.assertRedirects(response, reverse('auth_test_admin:auth_user_change', args=(u.pk,)))
-        row = LogEntry.objects.latest('id')
+        u = User.objects.get(email="staffmember@example.com")
+        response = self.client.post(
+            reverse("auth_test_admin:auth_user_password_change", args=(u.pk,)),
+            {"password1": "password1", "password2": "password1",},
+        )
+        self.assertRedirects(
+            response, reverse("auth_test_admin:auth_user_change", args=(u.pk,))
+        )
+        row = LogEntry.objects.latest("id")
         self.assertEqual(row.user_id, self.admin.pk)
         self.assertEqual(row.object_id, str(u.pk))
-        self.assertEqual(row.get_change_message(), 'Changed password.')
+        self.assertEqual(row.get_change_message(), "Changed password.")

     def test_password_change_bad_url(self):
-        response = self.client.get(reverse('auth_test_admin:auth_user_password_change', args=('foobar',)))
+        response = self.client.get(
+            reverse("auth_test_admin:auth_user_password_change", args=("foobar",))
+        )
         self.assertEqual(response.status_code, 404)

-    @mock.patch('django.contrib.auth.admin.UserAdmin.has_change_permission')
-    def test_user_change_password_passes_user_to_has_change_permission(self, has_change_permission):
-        url = reverse('auth_test_admin:auth_user_password_change', args=(self.admin.pk,))
-        self.client.post(url, {'password1': 'password1', 'password2': 'password1'})
+    @mock.patch("django.contrib.auth.admin.UserAdmin.has_change_permission")
+    def test_user_change_password_passes_user_to_has_change_permission(
+        self, has_change_permission
+    ):
+        url = reverse(
+            "auth_test_admin:auth_user_password_change", args=(self.admin.pk,)
+        )
+        self.client.post(url, {"password1": "password1", "password2": "password1"})
         (_request, user), _kwargs = has_change_permission.call_args
         self.assertEqual(user.pk, self.admin.pk)

     def test_view_user_password_is_readonly(self):
-        u = User.objects.get(username='testclient')
+        u = User.objects.get(username="testclient")
         u.is_superuser = False
         u.save()
         original_password = u.password
-        u.user_permissions.add(get_perm(User, 'view_user'))
-        response = self.client.get(reverse('auth_test_admin:auth_user_change', args=(u.pk,)),)
-        algo, salt, hash_string = (u.password.split('$'))
+        u.user_permissions.add(get_perm(User, "view_user"))
+        response = self.client.get(
+            reverse("auth_test_admin:auth_user_change", args=(u.pk,)),
+        )
+        algo, salt, hash_string = u.password.split("$")
         self.assertContains(response, '<div class="readonly">testclient</div>')
         # ReadOnlyPasswordHashWidget is used to render the field.
         self.assertContains(
             response,
-            '<strong>algorithm</strong>: %s\n\n'
-            '<strong>salt</strong>: %s**********\n\n'
-            '<strong>hash</strong>: %s**************************\n\n' % (
-                algo, salt[:2], hash_string[:6],
-            ),
+            "<strong>algorithm</strong>: %s\n\n"
+            "<strong>salt</strong>: %s**********\n\n"
+            "<strong>hash</strong>: %s**************************\n\n"
+            % (algo, salt[:2], hash_string[:6],),
             html=True,
         )
         # Value in POST data is ignored.
         data = self.get_user_data(u)
-        data['password'] = 'shouldnotchange'
-        change_url = reverse('auth_test_admin:auth_user_change', args=(u.pk,))
+        data["password"] = "shouldnotchange"
+        change_url = reverse("auth_test_admin:auth_user_change", args=(u.pk,))
         response = self.client.post(change_url, data)
         self.assertEqual(response.status_code, 403)
         u.refresh_from_db()
         self.assertEqual(u.password, original_password)

 @override_settings(
-    AUTH_USER_MODEL='auth_tests.UUIDUser',
-    ROOT_URLCONF='auth_tests.urls_custom_user_admin',
+    AUTH_USER_MODEL="auth_tests.UUIDUser",
+    ROOT_URLCONF="auth_tests.urls_custom_user_admin",
 )
 class UUIDUserTests(TestCase):
-
     def test_admin_password_change(self):
-        u = UUIDUser.objects.create_superuser(username='uuid', email='foo@bar.com', password='test')
-        self.assertTrue(self.client.login(username='uuid', password='test'))
-
-        user_change_url = reverse('custom_user_admin:auth_tests_uuiduser_change', args=(u.pk,))
+        u = UUIDUser.objects.create_superuser(
+            username="uuid", email="foo@bar.com", password="test"
+        )
+        self.assertTrue(self.client.login(username="uuid", password="test"))
+
+        user_change_url = reverse(
+            "custom_user_admin:auth_tests_uuiduser_change", args=(u.pk,)
+        )
         response = self.client.get(user_change_url)
         self.assertEqual(response.status_code, 200)

-        password_change_url = reverse('custom_user_admin:auth_user_password_change', args=(u.pk,))
+        password_change_url = reverse(
+            "custom_user_admin:auth_user_password_change", args=(u.pk,)
+        )
         response = self.client.get(password_change_url)
         # The action attribute is omitted.
         self.assertContains(response, '<form method="post" id="uuiduser_form">')

         # A LogEntry is created with pk=1 which breaks a FK constraint on MySQL
         with connection.constraint_checks_disabled():
-            response = self.client.post(password_change_url, {
-                'password1': 'password1',
-                'password2': 'password1',
-            })
+            response = self.client.post(
+                password_change_url,
+                {"password1": "password1", "password2": "password1",},
+            )
         self.assertRedirects(response, user_change_url)
-        row = LogEntry.objects.latest('id')
+        row = LogEntry.objects.latest("id")
         self.assertEqual(row.user_id, 1)  # hardcoded in CustomUserAdmin.log_change()
         self.assertEqual(row.object_id, str(u.pk))
-        self.assertEqual(row.get_change_message(), 'Changed password.')
+        self.assertEqual(row.get_change_message(), "Changed password.")

         # The LogEntry.user column isn't altered to a UUID type so it's set to
         # an integer manually in CustomUserAdmin to avoid an error. To avoid a
         # constraint error, delete the entry before constraints are checked
         # after the test.
--- first pass
+++ second pass
@@ -760,13 +760,13 @@
         }

         # Use POST request to log in
         SessionMiddleware(get_response).process_request(req)
         CsrfViewMiddleware(get_response).process_view(req, LoginView.as_view(), (), {})
-        req.META["SERVER_NAME"] = (  # Required to have redirect work in login view
-            "testserver"
-        )
+        req.META[
+            "SERVER_NAME"
+        ] = "testserver"  # Required to have redirect work in login view
         req.META["SERVER_PORT"] = 80
         resp = CsrfViewMiddleware(LoginView.as_view())(req)
         csrf_cookie = resp.cookies.get(settings.CSRF_COOKIE_NAME, None)
         token2 = csrf_cookie.coded_value
hugovk commented 4 years ago

Git bisecting pandas:

error commit PR notes
1 a4c11a75e12300abfbe4c36854e450d42bdd1ee7 Re-indent the contents of docstrings (#1053) Same root as https://github.com/psf/black/issues/1452
2 544ea9c217cad9459d7b60665db787e94b52f93d Improve String Handling (#1132)
3 a4c11a75e12300abfbe4c36854e450d42bdd1ee7 Re-indent the contents of docstrings (#1053) Same root as https://github.com/psf/black/issues/1452
hugovk commented 4 years ago

Git bisecting Django:

error commit PR
1 544ea9c217cad9459d7b60665db787e94b52f93d Improve String Handling (#1132)
2 544ea9c217cad9459d7b60665db787e94b52f93d Improve String Handling (#1132)
JelleZijlstra commented 4 years ago

Thanks for looking into this @hugovk! The Django ones look weird—how could the attrs/dataclasses switch have caused those?

hugovk commented 4 years ago

Ah, let me double check these, was doing black --check filename.py which will error with 1 for a successful "1 file would be reformatted."

Will redo by letting it reformat the file (and reset with an original each time).

hugovk commented 4 years ago

Sorry about that, it wasn't the attrs/dataclasses switch, but #1053 or #1132. I've updated the tables.

ichard26 commented 3 years ago

This has been resolved since https://github.com/psf/black/commit/c1c2418368cfcaa4f49edd7ec599fa45cce2d47d :tada: