<feed xmlns='http://www.w3.org/2005/Atom'>
<title>unit.git/test, branch 1.30.0</title>
<subtitle>Universal Web Application Server</subtitle>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/'/>
<entry>
<title>Tests: added tests for NJS loadable modules.</title>
<updated>2023-05-10T12:02:52+00:00</updated>
<author>
<name>Andrei Zeliankou</name>
<email>zelenkov@nginx.com</email>
</author>
<published>2023-05-10T12:02:52+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=e88e16d11e8d197f27d292540a015cf05af6277f'/>
<id>e88e16d11e8d197f27d292540a015cf05af6277f</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Tests: added tests for the URI rewrite.</title>
<updated>2023-05-09T12:52:09+00:00</updated>
<author>
<name>Andrei Zeliankou</name>
<email>zelenkov@nginx.com</email>
</author>
<published>2023-05-09T12:52:09+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=56af7bb825c286e1a397f780bff9da275e5602ad'/>
<id>56af7bb825c286e1a397f780bff9da275e5602ad</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>HTTP: optimizing $request_line.</title>
<updated>2023-04-12T09:50:56+00:00</updated>
<author>
<name>Alejandro Colomar</name>
<email>alx@nginx.com</email>
</author>
<published>2023-03-31T12:08:41+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=fcff55acb61be0b9818075e8fb9d3cc80dd97b31'/>
<id>fcff55acb61be0b9818075e8fb9d3cc80dd97b31</id>
<content type='text'>
Don't reconstruct a new string for the $request_line from the parsed
method, target, and HTTP version, but rather keep a pointer to the
original memory where the request line was received.

This will be necessary for implementing URI rewrites, since we want to
log the original request line, and not one constructed from the
rewritten target.

This implementation changes behavior (only for invalid requests) in the
following way:

Previous behavior was to log as many tokens from the request line as
were parsed validly, thus:

Request              -&gt; access log              ; error log

"GET / HTTP/1.1"     -&gt; "GET / HTTP/1.1"     OK ; =
"GET   / HTTP/1.1"   -&gt; "GET / HTTP/1.1"    [1] ; =
"GET / HTTP/2.1"     -&gt; "GET / HTTP/2.1"     OK ; =
"GET / HTTP/1."      -&gt; "GET / HTTP/1."     [2] ; "GET / HTTP/1. [null]"
"GET / food"         -&gt; "GET / food"        [2] ; "GET / food [null]"
"GET / / HTTP/1.1"   -&gt; "GET / / HTTP/1.1"  [2] ; =
"GET /  / HTTP/1.1"  -&gt; "GET /  / HTTP/1.1" [2] ; =
"GET food HTTP/1.1"  -&gt; "GET"                   ; "GET [null] [null]"
"OPTIONS * HTTP/1.1" -&gt; "OPTIONS"           [3] ; "OPTIONS [null] [null]"
"FOOBAR baz HTTP/1.1"-&gt; "FOOBAR"                ; "FOOBAR [null] [null]"
"FOOBAR / HTTP/1.1"  -&gt; "FOOBAR / HTTP/1.1"     ; =
"get / HTTP/1.1"     -&gt; "-"                     ; " [null] [null]"
""                   -&gt; "-"                     ; " [null] [null]"

This behavior was rather inconsistent.  We have several options to go
forward with this patch:

-  NGINX behavior.

   Log the entire request line, up to '\r' | '\n', even if it was
   invalid.

   This is the most informative alternative.  However, RFC-complying
   requests will probably not send invalid requests.

   This information would be interesting to users where debugging
   requests constructed manually via netcat(1) or a similar tool, or
   maybe for debugging a client, are important.  It might be interesting
   to support this in the future if our users are interested; for now,
   since this approach requires looping over invalid requests twice,
   that's an overhead that we better avoid.

-  Previous Unit behavior

   This is relatively fast (almost as fast as the next alternative, the
   one we chose), but the implementation is ugly, in that we need to
   perform the same operation in many places around the code.

   If we want performance, probably the next alternative is better; if
   we want to be informative, then the first one is better (maybe in
   combination with the third one too).

-  Chosen behavior

   Only logging request lines when the request is valid.  For any
   invalid request, or even unsupported ones, the request line will be
   logged as "-".  Thus:

   Request              -&gt; access log [4]

   "GET / HTTP/1.1"     -&gt; "GET / HTTP/1.1"     OK
   "GET   / HTTP/1.1"   -&gt; "GET   / HTTP/1.1"  [1]
   "GET / HTTP/2.1"     -&gt; "-"                 [3]
   "GET / HTTP/1."      -&gt; "-"
   "GET / food"         -&gt; "-"
   "GET / / HTTP/1.1"   -&gt; "GET / / HTTP/1.1"  [2]
   "GET /  / HTTP/1.1"  -&gt; "GET /  / HTTP/1.1" [2]
   "GET food HTTP/1.1"  -&gt; "-"
   "OPTIONS * HTTP/1.1" -&gt; "-"
   "FOOBAR baz HTTP/1.1"-&gt; "-"
   "FOOBAR / HTTP/1.1"  -&gt; "FOOBAR / HTTP/1.1"
   "get / HTTP/1.1"     -&gt; "-"
   ""                   -&gt; "-"

   This is less informative than previous behavior, but considering how
   inconsistent it was, and that RFC-complying agents will probably not
   send us such requests, we're ready to lose that information in the
   log.  This is of course the fastest and simplest implementation we
   can get.

   We've chosen to implement this alternative in this patch.  Since we
   modified the behavior, this patch also changes the affected tests.

[1]:  Multiple successive spaces as a token delimiter is allowed by the
      RFC, but it is discouraged, and considered a security risk.  It is
      currently supported by Unit, but we will probably drop support for
      it in the future.

[2]:  Unit currently supports spaces in the request-target.  This is
      a violation of the relevant RFC (linked below), and will be fixed
      in the future, and consider those targets as invalid, returning
      a 400 (Bad Request), and thus the log lines with the previous
      inconsistent behavior would be changed.

[3]:  Not yet supported.

[4]:  In the error log, regarding the "log_routes" conditional logging
      of the request line, we only need to log the request line if it
      was valid.  It doesn't make sense to log "" or "-" in case that
      the request was invalid, since this is only useful for
      understanding decisions of the router.  In this case, the access
      log is more appropriate, which shows that the request was invalid,
      and a 400 was returned.  When the request line is valid, it is
      printed in the error log exactly as in the access log.

Link: &lt;https://datatracker.ietf.org/doc/html/rfc9112#section-3&gt;
Suggested-by: Liam Crilly &lt;liam@nginx.com&gt;
Reviewed-by: Zhidao Hong &lt;z.hong@f5.com&gt;
Cc: Timo Stark &lt;t.stark@nginx.com&gt;
Cc: Andrei Zeliankou &lt;zelenkov@nginx.com&gt;
Cc: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Cc: Artem Konev &lt;a.konev@f5.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Don't reconstruct a new string for the $request_line from the parsed
method, target, and HTTP version, but rather keep a pointer to the
original memory where the request line was received.

This will be necessary for implementing URI rewrites, since we want to
log the original request line, and not one constructed from the
rewritten target.

This implementation changes behavior (only for invalid requests) in the
following way:

Previous behavior was to log as many tokens from the request line as
were parsed validly, thus:

Request              -&gt; access log              ; error log

"GET / HTTP/1.1"     -&gt; "GET / HTTP/1.1"     OK ; =
"GET   / HTTP/1.1"   -&gt; "GET / HTTP/1.1"    [1] ; =
"GET / HTTP/2.1"     -&gt; "GET / HTTP/2.1"     OK ; =
"GET / HTTP/1."      -&gt; "GET / HTTP/1."     [2] ; "GET / HTTP/1. [null]"
"GET / food"         -&gt; "GET / food"        [2] ; "GET / food [null]"
"GET / / HTTP/1.1"   -&gt; "GET / / HTTP/1.1"  [2] ; =
"GET /  / HTTP/1.1"  -&gt; "GET /  / HTTP/1.1" [2] ; =
"GET food HTTP/1.1"  -&gt; "GET"                   ; "GET [null] [null]"
"OPTIONS * HTTP/1.1" -&gt; "OPTIONS"           [3] ; "OPTIONS [null] [null]"
"FOOBAR baz HTTP/1.1"-&gt; "FOOBAR"                ; "FOOBAR [null] [null]"
"FOOBAR / HTTP/1.1"  -&gt; "FOOBAR / HTTP/1.1"     ; =
"get / HTTP/1.1"     -&gt; "-"                     ; " [null] [null]"
""                   -&gt; "-"                     ; " [null] [null]"

This behavior was rather inconsistent.  We have several options to go
forward with this patch:

-  NGINX behavior.

   Log the entire request line, up to '\r' | '\n', even if it was
   invalid.

   This is the most informative alternative.  However, RFC-complying
   requests will probably not send invalid requests.

   This information would be interesting to users where debugging
   requests constructed manually via netcat(1) or a similar tool, or
   maybe for debugging a client, are important.  It might be interesting
   to support this in the future if our users are interested; for now,
   since this approach requires looping over invalid requests twice,
   that's an overhead that we better avoid.

-  Previous Unit behavior

   This is relatively fast (almost as fast as the next alternative, the
   one we chose), but the implementation is ugly, in that we need to
   perform the same operation in many places around the code.

   If we want performance, probably the next alternative is better; if
   we want to be informative, then the first one is better (maybe in
   combination with the third one too).

-  Chosen behavior

   Only logging request lines when the request is valid.  For any
   invalid request, or even unsupported ones, the request line will be
   logged as "-".  Thus:

   Request              -&gt; access log [4]

   "GET / HTTP/1.1"     -&gt; "GET / HTTP/1.1"     OK
   "GET   / HTTP/1.1"   -&gt; "GET   / HTTP/1.1"  [1]
   "GET / HTTP/2.1"     -&gt; "-"                 [3]
   "GET / HTTP/1."      -&gt; "-"
   "GET / food"         -&gt; "-"
   "GET / / HTTP/1.1"   -&gt; "GET / / HTTP/1.1"  [2]
   "GET /  / HTTP/1.1"  -&gt; "GET /  / HTTP/1.1" [2]
   "GET food HTTP/1.1"  -&gt; "-"
   "OPTIONS * HTTP/1.1" -&gt; "-"
   "FOOBAR baz HTTP/1.1"-&gt; "-"
   "FOOBAR / HTTP/1.1"  -&gt; "FOOBAR / HTTP/1.1"
   "get / HTTP/1.1"     -&gt; "-"
   ""                   -&gt; "-"

   This is less informative than previous behavior, but considering how
   inconsistent it was, and that RFC-complying agents will probably not
   send us such requests, we're ready to lose that information in the
   log.  This is of course the fastest and simplest implementation we
   can get.

   We've chosen to implement this alternative in this patch.  Since we
   modified the behavior, this patch also changes the affected tests.

[1]:  Multiple successive spaces as a token delimiter is allowed by the
      RFC, but it is discouraged, and considered a security risk.  It is
      currently supported by Unit, but we will probably drop support for
      it in the future.

[2]:  Unit currently supports spaces in the request-target.  This is
      a violation of the relevant RFC (linked below), and will be fixed
      in the future, and consider those targets as invalid, returning
      a 400 (Bad Request), and thus the log lines with the previous
      inconsistent behavior would be changed.

[3]:  Not yet supported.

[4]:  In the error log, regarding the "log_routes" conditional logging
      of the request line, we only need to log the request line if it
      was valid.  It doesn't make sense to log "" or "-" in case that
      the request was invalid, since this is only useful for
      understanding decisions of the router.  In this case, the access
      log is more appropriate, which shows that the request was invalid,
      and a 400 was returned.  When the request line is valid, it is
      printed in the error log exactly as in the access log.

Link: &lt;https://datatracker.ietf.org/doc/html/rfc9112#section-3&gt;
Suggested-by: Liam Crilly &lt;liam@nginx.com&gt;
Reviewed-by: Zhidao Hong &lt;z.hong@f5.com&gt;
Cc: Timo Stark &lt;t.stark@nginx.com&gt;
Cc: Andrei Zeliankou &lt;zelenkov@nginx.com&gt;
Cc: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Cc: Artem Konev &lt;a.konev@f5.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Auto: mirroring installation structure in build tree.</title>
<updated>2023-03-28T22:41:08+00:00</updated>
<author>
<name>Alejandro Colomar</name>
<email>alx@nginx.com</email>
</author>
<published>2023-03-22T15:55:02+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=6e16d7ac5bb86140a55ea30a35c69ee0df3eff8d'/>
<id>6e16d7ac5bb86140a55ea30a35c69ee0df3eff8d</id>
<content type='text'>
This makes the build tree more organized, which is good for adding new
stuff.  Now, it's useful for example for adding manual pages in man3/,
but it may be useful in the future for example for extending the build
system to run linters (e.g., clang-tidy(1), Clang analyzer, ...) on the
C source code.

Previously, the build tree was quite flat, and looked like this (after
`./configure &amp;&amp; make`):

    $ tree -I src build
    build
    ├── Makefile
    ├── autoconf.data
    ├── autoconf.err
    ├── echo
    ├── libnxt.a
    ├── nxt_auto_config.h
    ├── nxt_version.h
    ├── unitd
    └── unitd.8

    1 directory, 9 files

And after this patch, it looks like this:

    $ tree -I src build
    build
    ├── Makefile
    ├── autoconf.data
    ├── autoconf.err
    ├── bin
    │   └── echo
    ├── include
    │   ├── nxt_auto_config.h
    │   └── nxt_version.h
    ├── lib
    │   ├── libnxt.a
    │   └── unit
    │       └── modules
    ├── sbin
    │   └── unitd
    ├── share
    │   └── man
    │       └── man8
    │           └── unitd.8
    └── var
        ├── lib
        │   └── unit
        ├── log
        │   └── unit
        └── run
            └── unit

    17 directories, 9 files

It also solves one issue introduced in
5a37171f733f ("Added default values for pathnames.").  Before that
commit, it was possible to run unitd from the build system
(`./build/unitd`).  Now, since it expects files in a very specific
location, that has been broken.  By having a directory structure that
mirrors the installation, it's possible to trick it to believe it's
installed, and run it from there:

    $ ./configure --prefix=./build
    $ make
    $ ./build/sbin/unitd

Fixes: 5a37171f733f ("Added default values for pathnames.")
Reported-by: Liam Crilly &lt;liam@nginx.com&gt;
Reviewed-by: Konstantin Pavlov &lt;thresh@nginx.com&gt;
Reviewed-by: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Cc: Andrei Zeliankou &lt;zelenkov@nginx.com&gt;
Cc: Zhidao Hong &lt;z.hong@f5.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This makes the build tree more organized, which is good for adding new
stuff.  Now, it's useful for example for adding manual pages in man3/,
but it may be useful in the future for example for extending the build
system to run linters (e.g., clang-tidy(1), Clang analyzer, ...) on the
C source code.

Previously, the build tree was quite flat, and looked like this (after
`./configure &amp;&amp; make`):

    $ tree -I src build
    build
    ├── Makefile
    ├── autoconf.data
    ├── autoconf.err
    ├── echo
    ├── libnxt.a
    ├── nxt_auto_config.h
    ├── nxt_version.h
    ├── unitd
    └── unitd.8

    1 directory, 9 files

And after this patch, it looks like this:

    $ tree -I src build
    build
    ├── Makefile
    ├── autoconf.data
    ├── autoconf.err
    ├── bin
    │   └── echo
    ├── include
    │   ├── nxt_auto_config.h
    │   └── nxt_version.h
    ├── lib
    │   ├── libnxt.a
    │   └── unit
    │       └── modules
    ├── sbin
    │   └── unitd
    ├── share
    │   └── man
    │       └── man8
    │           └── unitd.8
    └── var
        ├── lib
        │   └── unit
        ├── log
        │   └── unit
        └── run
            └── unit

    17 directories, 9 files

It also solves one issue introduced in
5a37171f733f ("Added default values for pathnames.").  Before that
commit, it was possible to run unitd from the build system
(`./build/unitd`).  Now, since it expects files in a very specific
location, that has been broken.  By having a directory structure that
mirrors the installation, it's possible to trick it to believe it's
installed, and run it from there:

    $ ./configure --prefix=./build
    $ make
    $ ./build/sbin/unitd

Fixes: 5a37171f733f ("Added default values for pathnames.")
Reported-by: Liam Crilly &lt;liam@nginx.com&gt;
Reviewed-by: Konstantin Pavlov &lt;thresh@nginx.com&gt;
Reviewed-by: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Cc: Andrei Zeliankou &lt;zelenkov@nginx.com&gt;
Cc: Zhidao Hong &lt;z.hong@f5.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Renamed --libstatedir to --statedir.</title>
<updated>2023-03-28T22:40:40+00:00</updated>
<author>
<name>Alejandro Colomar</name>
<email>alx@nginx.com</email>
</author>
<published>2023-03-27T11:43:37+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=5ba79b9b524ef746bc3269520c3f6b893f39275c'/>
<id>5ba79b9b524ef746bc3269520c3f6b893f39275c</id>
<content type='text'>
In BSD systems, it's usually &lt;/var/db&gt; or some other dir under &lt;/var&gt;
that is not &lt;/var/lib&gt;, so $statedir is a more generic name.  See
hier(7).

Reported-by: Andrei Zeliankou &lt;zelenkov@nginx.com&gt;
Reported-by: Zhidao Hong &lt;z.hong@f5.com&gt;
Reviewed-by: Konstantin Pavlov &lt;thresh@nginx.com&gt;
Reviewed-by: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Cc: Liam Crilly &lt;liam@nginx.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
In BSD systems, it's usually &lt;/var/db&gt; or some other dir under &lt;/var&gt;
that is not &lt;/var/lib&gt;, so $statedir is a more generic name.  See
hier(7).

Reported-by: Andrei Zeliankou &lt;zelenkov@nginx.com&gt;
Reported-by: Zhidao Hong &lt;z.hong@f5.com&gt;
Reviewed-by: Konstantin Pavlov &lt;thresh@nginx.com&gt;
Reviewed-by: Andrew Clayton &lt;a.clayton@nginx.com&gt;
Cc: Liam Crilly &lt;liam@nginx.com&gt;
Signed-off-by: Alejandro Colomar &lt;alx@nginx.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Tests: relaxed jar glob.</title>
<updated>2023-03-27T20:16:47+00:00</updated>
<author>
<name>Konstantin Pavlov</name>
<email>thresh@nginx.com</email>
</author>
<published>2023-03-27T20:16:47+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=e242b1454dff7a6be17ed2e2c06884fec528ad1b'/>
<id>e242b1454dff7a6be17ed2e2c06884fec528ad1b</id>
<content type='text'>
We install jars with names like websocket-api-${NXT_JAVA_MODULE}-$NXT_VERSION.jar,
which translates to versioned NXT_JAVA_MODULE in the packaging system, e.g.
websocket-api-java11-1.30.0.jar.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
We install jars with names like websocket-api-${NXT_JAVA_MODULE}-$NXT_VERSION.jar,
which translates to versioned NXT_JAVA_MODULE in the packaging system, e.g.
websocket-api-java11-1.30.0.jar.
</pre>
</div>
</content>
</entry>
<entry>
<title>Tests: added tests for the "log_route" option.</title>
<updated>2023-03-21T19:20:23+00:00</updated>
<author>
<name>Andrei Zeliankou</name>
<email>zelenkov@nginx.com</email>
</author>
<published>2023-03-21T19:20:23+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=b24257c8f6348619595d4ad615a7edc7f565b592'/>
<id>b24257c8f6348619595d4ad615a7edc7f565b592</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Tests: added Perl test with many responses using streaming body.</title>
<updated>2023-03-14T11:06:09+00:00</updated>
<author>
<name>Andrei Zeliankou</name>
<email>zelenkov@nginx.com</email>
</author>
<published>2023-03-14T11:06:09+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=28bdeec614d21d0ff2309431354e8cc389aac208'/>
<id>28bdeec614d21d0ff2309431354e8cc389aac208</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Tests: _clear_temp_dir() function introduced.</title>
<updated>2023-03-07T14:47:39+00:00</updated>
<author>
<name>Andrei Zeliankou</name>
<email>zelenkov@nginx.com</email>
</author>
<published>2023-03-07T14:47:39+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=4ed4283cffe86a9ec942e59a1f686fd8286b7398'/>
<id>4ed4283cffe86a9ec942e59a1f686fd8286b7398</id>
<content type='text'>
Also added temporary directory clearing after checking available
modules to prevent garbage environment when tests start.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Also added temporary directory clearing after checking available
modules to prevent garbage environment when tests start.
</pre>
</div>
</content>
</entry>
<entry>
<title>Tests: switched to using f-strings.</title>
<updated>2023-02-21T17:21:29+00:00</updated>
<author>
<name>Andrei Zeliankou</name>
<email>zelenkov@nginx.com</email>
</author>
<published>2023-02-21T17:21:29+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sigsegv.uk/unit.git/commit/?id=7934dcabbc3c2b585e8d3f8fcee7020ba26f1687'/>
<id>7934dcabbc3c2b585e8d3f8fcee7020ba26f1687</id>
<content type='text'>
Previously, it was necessary to support older versions of Python for
compatibility.  F-strings were released in Python 3.6.  Python 3.5 was
marked as unsupported by the end of 2020, so now it's possible to start
using f-strings safely for better readability and performance.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Previously, it was necessary to support older versions of Python for
compatibility.  F-strings were released in Python 3.6.  Python 3.5 was
marked as unsupported by the end of 2020, so now it's possible to start
using f-strings safely for better readability and performance.
</pre>
</div>
</content>
</entry>
</feed>
