This is an automated email from the ASF dual-hosted git repository.

tison pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/libcloud.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 5a03f1235 Add prek-based pre-commit setup and normalize whitespace 
(#2101)
5a03f1235 is described below

commit 5a03f1235f2a534df5a76eda92f3c7b932b4a919
Author: Chojan Shang <[email protected]>
AuthorDate: Tue Jan 27 10:12:01 2026 +0800

    Add prek-based pre-commit setup and normalize whitespace (#2101)
---
 .github/workflows/main.yml                         |  2 +-
 .pre-commit-config.yaml                            | 98 ++++++++++++++++++++++
 CHANGES.rst                                        |  6 +-
 contrib/pre-commit.sh                              | 32 -------
 docs/_static/images/provider_logos/scaleway.svg    |  2 +-
 docs/backup/api.rst                                |  2 +-
 docs/compute/drivers/cloudscale.rst                |  8 +-
 docs/compute/drivers/digital_ocean.rst             |  2 +-
 docs/compute/drivers/dimensiondata.rst             |  2 +-
 docs/compute/drivers/nttcis.rst                    |  2 +-
 docs/compute/drivers/openstack.rst                 |  8 +-
 docs/compute/drivers/outscale.rst                  |  2 -
 docs/container/drivers/docker.rst                  |  2 +-
 docs/container/drivers/ecs.rst                     |  4 +-
 docs/container/drivers/index.rst                   |  2 +-
 docs/container/drivers/rancher.rst                 |  2 +-
 docs/container/examples.rst                        |  2 +-
 docs/container/supported_providers.rst             |  2 +-
 docs/development.rst                               | 20 ++---
 docs/dns/drivers/buddyns.rst                       |  2 +-
 docs/dns/drivers/godaddy.rst                       |  4 +-
 docs/dns/drivers/luadns.rst                        |  2 +-
 docs/dns/drivers/rcodezero.rst                     |  6 +-
 docs/faq.rst                                       |  1 -
 docs/getting_started.rst                           |  6 +-
 docs/loadbalancer/drivers/nttcis.rst               |  2 +-
 docs/other/changes_in_2_0.rst                      | 12 +--
 docs/other/ssl-certificate-validation.rst          |  2 +-
 docs/other/using-http-proxy.rst                    |  4 +-
 ...oud-in-multithreaded-and-async-environments.rst |  2 -
 docs/storage/drivers/digitalocean_spaces.rst       |  2 +-
 docs/upgrade_notes.rst                             | 12 +--
 integration/compute/README.rst                     |  1 -
 pyproject.toml                                     |  1 +
 uv.lock                                            | 26 ++++++
 35 files changed, 186 insertions(+), 99 deletions(-)

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 589c39c2e..c1a46f85f 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -229,7 +229,7 @@ jobs:
           # Unpack tarball and verify + run the tests
           tar -xzvf "${TARBALL_FILENAME}"
 
-          cd "apache_libcloud-${VERSION}/" 
+          cd "apache_libcloud-${VERSION}/"
           tox -c tox.ini -epy3.10
 
       - name: Verify Wheel Release Artifact
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 000000000..782344ed9
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,98 @@
+exclude: |
+  (?x)^(
+    docs/(?:.*/)?_supported_.*\.rst$|
+    libcloud/data/pricing\.json$
+  )
+
+repos:
+  - repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: "v5.0.0"
+    hooks:
+      - id: check-case-conflict
+      - id: check-merge-conflict
+      - id: check-toml
+      - id: check-yaml
+      - id: check-json
+        exclude: |
+          (?x)^(
+            libcloud/test/dns/fixtures/pointdns/not_found\.json|
+            
libcloud/test/dns/fixtures/godaddy/v1_domains_purchase_schema_com\.json|
+            libcloud/test/dns/fixtures/gandi_live/get_bad_zone\.json
+          )$
+      - id: end-of-file-fixer
+        files: &text_files |
+          (?x)^(
+            libcloud/|
+            docs/|
+            demos/|
+            integration/|
+            scripts/|
+            contrib/|
+            pylint_plugins/|
+            \.github/|
+            [^/]+\.(py|rst|md|yml|yaml|toml|json|xml|txt|csv|ini|cfg|sh)$
+          )
+        exclude: &fixture_exclude |
+          (?x)^(
+            libcloud/test/.*/fixtures/|
+            integration/.*/fixtures/
+          )
+      - id: trailing-whitespace
+        files: *text_files
+        exclude: *fixture_exclude
+
+  - repo: https://github.com/psf/black
+    rev: "25.1.0"
+    hooks:
+      - id: black
+        args: ["--config=pyproject.toml"]
+        files: &fmt_py_files |
+          (?x)^(
+            libcloud/|
+            docs/examples/|
+            docs/|
+            demos/|
+            contrib/|
+            pylint_plugins/|
+            integration/|
+            [^/]+\.py$
+          )
+
+  - repo: https://github.com/pycqa/isort
+    rev: "6.0.1"
+    hooks:
+      - id: isort
+        args: ["--settings-path=pyproject.toml"]
+        files: *fmt_py_files
+
+  - repo: https://github.com/pycqa/flake8
+    rev: "5.0.4"
+    hooks:
+      - id: flake8
+        args: ["--config=./.flake8"]
+        files: &lint_py_files |
+          (?x)^(
+            libcloud/|
+            libcloud/test/|
+            demos/|
+            integration/|
+            scripts/|
+            docs/examples/|
+            contrib/|
+            pylint_plugins/
+          )
+
+  - repo: https://github.com/asottile/pyupgrade
+    rev: "v3.3.1"
+    hooks:
+      - id: pyupgrade
+        args: ["--py310-plus", "--py3-only"]
+        files: *lint_py_files
+
+  - repo: https://github.com/codespell-project/codespell
+    rev: "v2.4.1"
+    hooks:
+      - id: codespell
+        additional_dependencies: ["tomli"]
+        args: ["--toml", "pyproject.toml"]
+        files: ^libcloud/
diff --git a/CHANGES.rst b/CHANGES.rst
index 54dc86109..b42d87666 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -894,8 +894,8 @@ Compute
   (#1615)
   [Miguel Caballer - @micafer]
 
-- [CloudSigma] Various updates, improvements and new functionality in the 
-  driver (support for new regions, instance types, additional standard API an 
+- [CloudSigma] Various updates, improvements and new functionality in the
+  driver (support for new regions, instance types, additional standard API an
   extension methods, etc.).
 
   (#1558)
@@ -1060,7 +1060,7 @@ Compute
   (#1492)
   [Miguel Caballer - @micafer]
 
-- [EC2] Update supported EC2 regions and instance sizes and add support 
+- [EC2] Update supported EC2 regions and instance sizes and add support
   for eu-north-1 region.
   (#1486)
   [Arturo Noha - @r2ronoha]
diff --git a/contrib/pre-commit.sh b/contrib/pre-commit.sh
deleted file mode 100755
index e271f4085..000000000
--- a/contrib/pre-commit.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/usr/bin/env bash
-#  Licensed to the Apache Software Foundation (ASF) under one
-#  or more contributor license agreements.  See the NOTICE file
-#  distributed with this work for additional information
-#  regarding copyright ownership.  The ASF licenses this file
-#  to you under the Apache License, Version 2.0 (the
-#  "License"); you may not use this file except in compliance
-#  with the License.  You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-#  Unless required by applicable law or agreed to in writing,
-#  software distributed under the License is distributed on an
-#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-#  KIND, either express or implied.  See the License for the
-#  specific language governing permissions and limitations
-#  under the License.
-set -e
-
-files=$(git diff --cached --name-status | grep -v ^D | awk '$1 $2 { print $2}' 
| grep -e .py$)
-# shellcheck disable=SC2206
-array=(${files/// })
-
-for file in "${array[@]}"
-do
-    echo "Processing: ${file}"
-    if [[ ${file} =~ "libcloud/test/" ]]; then
-        flake8 --max-line-length=160 "${file}"
-    else
-        flake8 "${file}"
-    fi
-done
diff --git a/docs/_static/images/provider_logos/scaleway.svg 
b/docs/_static/images/provider_logos/scaleway.svg
index 208a18f1f..07bac670c 100644
--- a/docs/_static/images/provider_logos/scaleway.svg
+++ b/docs/_static/images/provider_logos/scaleway.svg
@@ -18,4 +18,4 @@
             </g>
         </g>
     </g>
-</svg>
\ No newline at end of file
+</svg>
diff --git a/docs/backup/api.rst b/docs/backup/api.rst
index c9de0fe34..e24a08afc 100644
--- a/docs/backup/api.rst
+++ b/docs/backup/api.rst
@@ -19,4 +19,4 @@ Backup Base API
     :members:
 
 .. autoclass:: libcloud.backup.types.BackupTargetJobStatusType
-    :members:
\ No newline at end of file
+    :members:
diff --git a/docs/compute/drivers/cloudscale.rst 
b/docs/compute/drivers/cloudscale.rst
index 9e53d2c7a..668680adf 100644
--- a/docs/compute/drivers/cloudscale.rst
+++ b/docs/compute/drivers/cloudscale.rst
@@ -33,8 +33,8 @@ Most of the `cloudscale.ch` API is covered by the simple 
commands:
 - ``driver.destroy_node(node)``
 - ``driver.create_node(name, size, image, ex_create_attr={})``
 
-In our :ref:`example <cloudscale-examples>` below you can see how you use 
-``ex_create_attr`` when creating servers. Possible dictionary entries in 
+In our :ref:`example <cloudscale-examples>` below you can see how you use
+``ex_create_attr`` when creating servers. Possible dictionary entries in
 ``ex_create_attr`` are:
 
 - ``ssh_keys`` (``list`` of ``str``) - A list of SSH public keys.
@@ -65,10 +65,10 @@ API Docs
 --------
 
 .. autoclass:: libcloud.compute.drivers.cloudscale.CloudscaleNodeDriver
-    :members: create_node, list_images, list_nodes, list_sizes, 
+    :members: create_node, list_images, list_nodes, list_sizes,
               wait_until_running, reboot_node, ex_start_node, ex_stop_node,
               ex_node_by_uuid, destroy_node
-    :undoc-members: 
+    :undoc-members:
 
 .. _`cloudscale.ch`: https://www.cloudscale.ch
 .. _`cloudscale.ch API`: https://www.cloudscale.ch/en/api/v1
diff --git a/docs/compute/drivers/digital_ocean.rst 
b/docs/compute/drivers/digital_ocean.rst
index 558871f11..7d2d14b7c 100644
--- a/docs/compute/drivers/digital_ocean.rst
+++ b/docs/compute/drivers/digital_ocean.rst
@@ -41,4 +41,4 @@ API v2.0
 
 
 .. _`DigitalOcean`: https://www.digitalocean.com/
-.. _`reached end of life on November 9, 2015`: 
https://developers.digitalocean.com/documentation/changelog/api-v1/sunsetting-api-v1/
\ No newline at end of file
+.. _`reached end of life on November 9, 2015`: 
https://developers.digitalocean.com/documentation/changelog/api-v1/sunsetting-api-v1/
diff --git a/docs/compute/drivers/dimensiondata.rst 
b/docs/compute/drivers/dimensiondata.rst
index ac7a94759..49928ea7b 100644
--- a/docs/compute/drivers/dimensiondata.rst
+++ b/docs/compute/drivers/dimensiondata.rst
@@ -87,4 +87,4 @@ Debugging Tips
       ValueError: Invalid attribute name u'xmlns:xsi'
 
     *Solution*:
-    - Upgrade to python version 2.7.12 and above
\ No newline at end of file
+    - Upgrade to python version 2.7.12 and above
diff --git a/docs/compute/drivers/nttcis.rst b/docs/compute/drivers/nttcis.rst
index 973f6feac..de34b7ce5 100644
--- a/docs/compute/drivers/nttcis.rst
+++ b/docs/compute/drivers/nttcis.rst
@@ -86,4 +86,4 @@ Debugging Tips
       ValueError: Invalid attribute name u'xmlns:xsi'
 
     *Solution*:
-    - Upgrade to python version 2.7.12 and above
\ No newline at end of file
+    - Upgrade to python version 2.7.12 and above
diff --git a/docs/compute/drivers/openstack.rst 
b/docs/compute/drivers/openstack.rst
index 92d57f76c..34deba679 100644
--- a/docs/compute/drivers/openstack.rst
+++ b/docs/compute/drivers/openstack.rst
@@ -16,7 +16,7 @@ Among many other private clouds, it also powers Rackspace's 
Public Cloud.
 Selecting the Nova API version
 ------------------------------
 
-Along with your connection criteria, you can specify the Nova version with 
`api_version`, 
+Along with your connection criteria, you can specify the Nova version with 
`api_version`,
 currently supported versions of Nova are:
 
 - 1.0
@@ -94,15 +94,15 @@ Available arguments:
   is provided, this step is skipped and the provided value is used directly.
 * ``ex_force_network_url`` - Base URL to the OpenStack neutron API endpoint. 
By default,
   driver obtains API endpoint URL from the server catalog, but if this argument
-  is provided, this step is skipped and the provided value is used directly. 
Only valid 
+  is provided, this step is skipped and the provided value is used directly. 
Only valid
   in case of api_version >= 2.0.
 * ``ex_force_image_url`` - Base URL to the OpenStack glance API endpoint. By 
default,
   driver obtains API endpoint URL from the server catalog, but if this argument
-  is provided, this step is skipped and the provided value is used directly. 
Only valid 
+  is provided, this step is skipped and the provided value is used directly. 
Only valid
   in case of api_version >= 2.0.
 * ``ex_force_volume_url`` - Base URL to the OpenStack cinder API endpoint. By 
default,
   driver obtains API endpoint URL from the server catalog, but if this argument
-  is provided, this step is skipped and the provided value is used directly. 
Only valid 
+  is provided, this step is skipped and the provided value is used directly. 
Only valid
   in case of api_version >= 2.0.
 * ``ex_force_microversion`` - Microversion of the API to interact with 
OpenStack.
   Only valid in case of api_version >= 2.0.
diff --git a/docs/compute/drivers/outscale.rst 
b/docs/compute/drivers/outscale.rst
index 9494db9b7..ab3ebcfa6 100644
--- a/docs/compute/drivers/outscale.rst
+++ b/docs/compute/drivers/outscale.rst
@@ -355,5 +355,3 @@ API Access Rules
 * ``ex_delete_api_access_rule`` - Returns a ``bool``
 * ``ex_read_api_access_rules`` - Returns a ``list`` of ``dict``
 * ``ex_update_api_access_rule`` - Returns a ``dict``
-
-
diff --git a/docs/container/drivers/docker.rst 
b/docs/container/drivers/docker.rst
index 32cbd2c20..0dc7922d9 100644
--- a/docs/container/drivers/docker.rst
+++ b/docs/container/drivers/docker.rst
@@ -23,4 +23,4 @@ API Docs
     :members:
     :inherited-members:
 
-.. _`Docker`: https://docker.io/
\ No newline at end of file
+.. _`Docker`: https://docker.io/
diff --git a/docs/container/drivers/ecs.rst b/docs/container/drivers/ecs.rst
index 40274d1f8..066ea56a6 100644
--- a/docs/container/drivers/ecs.rst
+++ b/docs/container/drivers/ecs.rst
@@ -14,7 +14,7 @@ To provide API key access, you should apply one of the roles:
 
 Instantiating the driver
 ------------------------
-        
+
 .. literalinclude:: /examples/container/ecs/instantiate_driver.py
    :language: python
 
@@ -55,4 +55,4 @@ API Docs
     :inherited-members:
 
 
-.. _`AWS`: https://aws.amazon.com/
\ No newline at end of file
+.. _`AWS`: https://aws.amazon.com/
diff --git a/docs/container/drivers/index.rst b/docs/container/drivers/index.rst
index fd1145ede..1a25d2887 100644
--- a/docs/container/drivers/index.rst
+++ b/docs/container/drivers/index.rst
@@ -9,4 +9,4 @@ This chapter includes links to driver (provider) specific 
documentation pages.
     :glob:
     :maxdepth: 1
 
-    *
\ No newline at end of file
+    *
diff --git a/docs/container/drivers/rancher.rst 
b/docs/container/drivers/rancher.rst
index c1183974d..293c74faf 100644
--- a/docs/container/drivers/rancher.rst
+++ b/docs/container/drivers/rancher.rst
@@ -69,4 +69,4 @@ For the first version of this driver, Mario Loria of Arroyo 
Networks wrote most
 of the code. He received help from Anthony Shaw, a core libcloud contributor
 and Vincent Fiduccia, software architect at Rancher Labs.
 
-.. _`Rancher`: https://rancher.com/
\ No newline at end of file
+.. _`Rancher`: https://rancher.com/
diff --git a/docs/container/examples.rst b/docs/container/examples.rst
index f35662cdb..00020ae4c 100644
--- a/docs/container/examples.rst
+++ b/docs/container/examples.rst
@@ -30,4 +30,4 @@ Docker Hub Client 
:class:`~libcloud.container.utils.docker.HubClient` is a share
 You can use this class for fetching images to deploy to services like ECS
 
 .. literalinclude:: /examples/container/docker_hub.py
-   :language: python
\ No newline at end of file
+   :language: python
diff --git a/docs/container/supported_providers.rst 
b/docs/container/supported_providers.rst
index c7b8fdc05..e34e5eba2 100644
--- a/docs/container/supported_providers.rst
+++ b/docs/container/supported_providers.rst
@@ -11,4 +11,4 @@ Provider Matrix
 Supported Methods
 -----------------
 
-.. include:: _supported_methods.rst
\ No newline at end of file
+.. include:: _supported_methods.rst
diff --git a/docs/development.rst b/docs/development.rst
index 4e44793eb..eebce5d66 100644
--- a/docs/development.rst
+++ b/docs/development.rst
@@ -78,20 +78,20 @@ And most importantly, follow the existing style in the file 
you are editing and
 Git pre-commit hook
 -------------------
 
-To make complying with our style guide easier, we provide a git pre-commit hook
-which automatically checks modified Python files for violations of our style
-guide.
-
-You can install it by running following command in the root of the repository
-checkout:
+We use `pre-commit` configuration with `prek` to run formatting and linting
+hooks before commits. Install the tooling (including ``prek``) and register the
+git hook from the repository root:
 
 .. sourcecode:: bash
 
-    ln -s contrib/pre-commit.sh .git/hooks/pre-commit
+    uv sync --extra lint
+    uv run prek install
+
+To run all hooks on all files:
+
+.. sourcecode:: bash
 
-After you have installed this hook it will automatically check modified Python
-files for violations before a commit. If a violation is found, commit will be
-aborted.
+    uv run prek run -a
 
 .. _code-conventions:
 
diff --git a/docs/dns/drivers/buddyns.rst b/docs/dns/drivers/buddyns.rst
index d43f7bfee..b4eeb41d7 100644
--- a/docs/dns/drivers/buddyns.rst
+++ b/docs/dns/drivers/buddyns.rst
@@ -20,4 +20,4 @@ API Docs
     :members:
     :inherited-members:
 
-.. https://www.buddyns.com/support/api/v2/
\ No newline at end of file
+.. https://www.buddyns.com/support/api/v2/
diff --git a/docs/dns/drivers/godaddy.rst b/docs/dns/drivers/godaddy.rst
index 50b4be0b4..24865066b 100644
--- a/docs/dns/drivers/godaddy.rst
+++ b/docs/dns/drivers/godaddy.rst
@@ -24,8 +24,8 @@ Instantiating the driver
 
 Before you instantiate a driver, you will need a GoDaddy account.
 
-Once you have an account you need to request a Production key on the GoDaddy 
API website: 
-https://developer.godaddy.com/getstarted#access 
+Once you have an account you need to request a Production key on the GoDaddy 
API website:
+https://developer.godaddy.com/getstarted#access
 
 You can then use these details to instantiate a driver with the arguments:
 
diff --git a/docs/dns/drivers/luadns.rst b/docs/dns/drivers/luadns.rst
index b28ada390..0c1a99618 100644
--- a/docs/dns/drivers/luadns.rst
+++ b/docs/dns/drivers/luadns.rst
@@ -22,4 +22,4 @@ API Docs
     :members:
     :inherited-members:
 
-.. _`Luadns`: http://luadns.com/
\ No newline at end of file
+.. _`Luadns`: http://luadns.com/
diff --git a/docs/dns/drivers/rcodezero.rst b/docs/dns/drivers/rcodezero.rst
index 864871a1c..d383e8edf 100644
--- a/docs/dns/drivers/rcodezero.rst
+++ b/docs/dns/drivers/rcodezero.rst
@@ -6,12 +6,12 @@ RcodeZero DNS Driver Documentation
     :width: 300
     :target: https://www.rcodezero.at/en
 
-`RcodeZero`_ is a European Anycast DNS service provided by nic.at. 
+`RcodeZero`_ is a European Anycast DNS service provided by nic.at.
 
 Supported Features:
 
 - more than 35 nodes
-- two seperate clouds with different ASes 
+- two seperate clouds with different ASes
 - full IPv4/IPv6 support
 - primary as well as secondary Nameservers
 - DNSSEC signing
@@ -38,5 +38,5 @@ API Docs
 
 .. autoclass:: libcloud.dns.drivers.rcodezero.RcodeZeroDNSDriver
     :members:
-    
+
 .. _`RcodeZero`: https://my.rcodezero.at/en
diff --git a/docs/faq.rst b/docs/faq.rst
index 6079553fe..bd46e3ed2 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -103,4 +103,3 @@ Example #2 (code):
 
     import libcloud
     libcloud.__version__
-
diff --git a/docs/getting_started.rst b/docs/getting_started.rst
index ae0d9b083..20b890792 100644
--- a/docs/getting_started.rst
+++ b/docs/getting_started.rst
@@ -41,7 +41,7 @@ with any of the Libcloud drivers.
     from pprint import pprint
 
     import libcloud
-    
+
     cls = libcloud.get_driver(libcloud.DriverType.COMPUTE, 
libcloud.DriverType.COMPUTE.RACKSPACE)
 
 
@@ -71,9 +71,9 @@ see provider-specific documentation and the driver docstrings.
     from pprint import pprint
 
     import libcloud
-    
+
     cls = libcloud.get_driver(libcloud.DriverType.COMPUTE, 
libcloud.DriverType.COMPUTE.RACKSPACE)
-    
+
     driver = cls('my username', 'my api key')
 
     pprint(driver.list_sizes())
diff --git a/docs/loadbalancer/drivers/nttcis.rst 
b/docs/loadbalancer/drivers/nttcis.rst
index c7771e3d5..bc95ce577 100644
--- a/docs/loadbalancer/drivers/nttcis.rst
+++ b/docs/loadbalancer/drivers/nttcis.rst
@@ -61,4 +61,4 @@ API Docs
     :members:
     :inherited-members:
 
-.. _`API`: https://docs.mcp-services.net/display/CCD/API+2
\ No newline at end of file
+.. _`API`: https://docs.mcp-services.net/display/CCD/API+2
diff --git a/docs/other/changes_in_2_0.rst b/docs/other/changes_in_2_0.rst
index 0c127dbe6..16b177fb9 100644
--- a/docs/other/changes_in_2_0.rst
+++ b/docs/other/changes_in_2_0.rst
@@ -7,7 +7,7 @@ Replacement of httplib with `requests`
 --------------------------------------
 
 Apache Libcloud supports Python 2.6, 2.7 - 3.3 and beyond. To achieve this a 
package was written within the
-Libcloud library to create a generic HTTP client for Python 2 and 3. This 
package has a custom implementation of a certificate store, searching and TLS 
preference configuration. One of the first errors to greet new users of 
Libcloud would be "No CA Certificates were found in CA_CERTS_PATH."... 
+Libcloud library to create a generic HTTP client for Python 2 and 3. This 
package has a custom implementation of a certificate store, searching and TLS 
preference configuration. One of the first errors to greet new users of 
Libcloud would be "No CA Certificates were found in CA_CERTS_PATH."...
 
 In 2.0 this implementation has been replaced with the `requests` package, and 
SSL verification should work against any publicly signed HTTPS endpoint by 
default, without having to provide a CA cert store.
 
@@ -70,7 +70,7 @@ This code example would set a HTTP/HTTPS proxy and use a 
client-generated certif
 
   import os
   os.environ.set('http_proxy', 'http://localhost:8888/')
-  
+
   import libcloud.security
   libcloud.security.VERIFY_SSL_CERT = True
   libcloud.security.CA_CERTS_PATH = '/Users/anthonyshaw/charles.pem'
@@ -87,23 +87,23 @@ Performance improvements and introduction of sessions
 
 Each instance of libcloud.common.base.Connection will have a 
LibcloudConnection instance under the `connection` property. In 1.5.0<, there 
would be 2 connection
 class instances, LibcloudHttpConnection and LibcloudHttpsConnection, stored as 
an instance property `conn_classes`. In 2.0.0 this has been replaced with a 
single type,
-:class:`libcloud.common.base.LibcloudHTTPConnection` that handles both HTTP 
and HTTPS connections. 
+:class:`libcloud.common.base.LibcloudHTTPConnection` that handles both HTTP 
and HTTPS connections.
 
 .. code-block:: Python
 
   def test():
       import libcloud
       import libcloud.compute.providers
-      
+
       d = libcloud.get_driver(libcloud.DriverType.COMPUTE, 
libcloud.DriverType.COMPUTE.DIMENSIONDATA)
       instance = d('anthony', 'mypassword!', 'dd-au')
       instance.list_nodes() # is paged
       instance.list_images() # is paged
-  
+
   if __name__ == '__main__':
       import timeit
       print(timeit.timeit("test()", setup="from __main__ import test", 
number=5))
-      
+
 
 This simple test shows a 10% performance improvement between Libcloud 1.5.0 
and 2.0.0.
 
diff --git a/docs/other/ssl-certificate-validation.rst 
b/docs/other/ssl-certificate-validation.rst
index dcb90ab01..fdc83472a 100644
--- a/docs/other/ssl-certificate-validation.rst
+++ b/docs/other/ssl-certificate-validation.rst
@@ -63,7 +63,7 @@ certificate, you can do that using two different approaches:
 
     SSL_CERT_FILE=/home/user/path-to-your-ca-file.crt python my_script.py
 
-2. Setting ``libcloud.security.CA_CERTS_PATH`` variable in your script to 
+2. Setting ``libcloud.security.CA_CERTS_PATH`` variable in your script to
    point to your CA file
 
 .. sourcecode:: python
diff --git a/docs/other/using-http-proxy.rst b/docs/other/using-http-proxy.rst
index f22a9a006..1baf191c3 100644
--- a/docs/other/using-http-proxy.rst
+++ b/docs/other/using-http-proxy.rst
@@ -80,10 +80,10 @@ With basic auth authentication (http proxy):
 
   Some drivers don't correctly pass ``proxy_url`` argument to the connection
   class and don't support ``proxy_url`` constructor argument.
-  
+
   If you pass this argument to the driver constructor, but it doesn't appear
   to be working, it's likely the driver doesn't support this method.
-  
+
   In such scenarios, you are advised to use some other method of setting a
   proxy (e.g. by setting an environment variable or by using
   :meth:`libcloud.common.base.LibcloudConnection.set_http_proxy` method).
diff --git 
a/docs/other/using-libcloud-in-multithreaded-and-async-environments.rst 
b/docs/other/using-libcloud-in-multithreaded-and-async-environments.rst
index 8e6c0fd33..3b3acdec7 100644
--- a/docs/other/using-libcloud-in-multithreaded-and-async-environments.rst
+++ b/docs/other/using-libcloud-in-multithreaded-and-async-environments.rst
@@ -65,5 +65,3 @@ without blocking the whole reactor.
 
 .. literalinclude:: /examples/misc/twisted_create_node.py
    :language: python
-
-
diff --git a/docs/storage/drivers/digitalocean_spaces.rst 
b/docs/storage/drivers/digitalocean_spaces.rst
index b8739fca0..26deb806f 100644
--- a/docs/storage/drivers/digitalocean_spaces.rst
+++ b/docs/storage/drivers/digitalocean_spaces.rst
@@ -53,4 +53,4 @@ API Docs
 
 .. _`Spaces`: https://www.digitalocean.com/products/object-storage/
 .. _`Applications & API`: https://cloud.digitalocean.com/settings/api/tokens
-.. _`S3-interoperable`: 
https://developers.digitalocean.com/documentation/spaces/
\ No newline at end of file
+.. _`S3-interoperable`: 
https://developers.digitalocean.com/documentation/spaces/
diff --git a/docs/upgrade_notes.rst b/docs/upgrade_notes.rst
index 488b2eae7..7d5db2b99 100644
--- a/docs/upgrade_notes.rst
+++ b/docs/upgrade_notes.rst
@@ -29,10 +29,10 @@ Libcloud 3.9.0
   If your code is using those arguments / passing them to the `create_node()`
   method it needs to be updated and those arguments removed.
 
-* [KubeVirt] Changes to the `create_node()` method: 
+* [KubeVirt] Changes to the `create_node()` method:
 
-  - The `ports` argument has been renamed to `ex_ports`. 
-  - The `ex_disks` argument has been redefined to support all volume types. 
+  - The `ports` argument has been renamed to `ex_ports`.
+  - The `ex_disks` argument has been redefined to support all volume types.
 
   The deprecated `ex_disks` format, which only supports 
`PersistentVolumeClaim`,
   is as follows:
@@ -47,9 +47,9 @@ Libcloud 3.9.0
 
     ex_disks=[{"bus": "", "device": "", "disk_type": "", "name": "", 
"volume_spec": {...}}]
 
-  Here, `volume_spec` is the `disk_type` specific settings, which aligns with 
the 
-  KubeVirt user guide on disks and volumes 
-  (https://kubevirt.io/user-guide/virtual_machines/disks_and_volumes). 
+  Here, `volume_spec` is the `disk_type` specific settings, which aligns with 
the
+  KubeVirt user guide on disks and volumes
+  (https://kubevirt.io/user-guide/virtual_machines/disks_and_volumes).
 
   For example, for PVC:
 
diff --git a/integration/compute/README.rst b/integration/compute/README.rst
index eaedd3ba4..b524d5bd7 100644
--- a/integration/compute/README.rst
+++ b/integration/compute/README.rst
@@ -17,4 +17,3 @@ Running the tests
 .. code-block:: bash
 
    python -m integration.compute
-   
diff --git a/pyproject.toml b/pyproject.toml
index 0934c08f5..cdfe43dc3 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -103,6 +103,7 @@ lint = [
     "pyupgrade==3.3.1",
     "rstcheck==6.2.4; python_version >= '3.10'",
     "codespell==2.4.1",
+    "prek>=0.2.17",
     "requests>=2.27.1",
     "paramiko==3.5.1; platform_python_implementation != 'PyPy'",
 ]
diff --git a/uv.lock b/uv.lock
index be094e3c5..4d798f80c 100644
--- a/uv.lock
+++ b/uv.lock
@@ -65,6 +65,7 @@ lint = [
     { name = "isort" },
     { name = "paramiko", marker = "platform_python_implementation != 'PyPy'" },
     { name = "pep8" },
+    { name = "prek" },
     { name = "pylint" },
     { name = "pyupgrade" },
     { name = "requests" },
@@ -123,6 +124,7 @@ requires-dist = [
     { name = "paramiko", marker = "platform_python_implementation != 'PyPy' 
and extra == 'lint'", specifier = "==3.5.1" },
     { name = "paramiko", marker = "platform_python_implementation != 'PyPy' 
and extra == 'test'", specifier = "==3.5.1" },
     { name = "pep8", marker = "extra == 'lint'", specifier = "==1.7.1" },
+    { name = "prek", marker = "extra == 'lint'", specifier = ">=0.2.17" },
     { name = "pylint", marker = "python_full_version >= '3.10' and extra == 
'lint'", specifier = "==3.3.4" },
     { name = "pyopenssl", marker = "extra == 'test'", specifier = "==25.0.0" },
     { name = "pytest", marker = "extra == 'test'", specifier = "==8.3.5" },
@@ -1315,6 +1317,30 @@ wheels = [
     { url = 
"https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl";,
 hash = 
"sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size 
= 20538, upload-time = "2025-05-15T12:30:06.134Z" },
 ]
 
+[[package]]
+name = "prek"
+version = "0.3.0"
+source = { registry = "https://pypi.org/simple"; }
+sdist = { url = 
"https://files.pythonhosted.org/packages/f2/1e/6c23d3470145be1d6ff29d93f2a521864788827d22e509e2b978eb5bb4cb/prek-0.3.0.tar.gz";,
 hash = 
"sha256:e70f16bbaf2803e490b866cfa997ea5cc46e7ada55d61f0cdd84bc90b8d5ca7f", size 
= 316063, upload-time = "2026-01-22T04:00:01.648Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/84/49/469219c19bb00db678806f79fc084ac1ce9952004a183a798db26f6df22b/prek-0.3.0-py3-none-linux_armv6l.whl";,
 hash = 
"sha256:7e5d40b22deff23e36f7ad91e24b8e62edf32f30f6dad420459f7ec7188233c3", size 
= 4317493, upload-time = "2026-01-22T03:59:51.769Z" },
+    { url = 
"https://files.pythonhosted.org/packages/87/9f/f7afc49cc0fd92d1ba492929dc1573cb7004d09b61341aa6ee32a5288657/prek-0.3.0-py3-none-macosx_10_12_x86_64.whl";,
 hash = 
"sha256:6712b58cbb5a7db0aaef180c489ce9f3462e0293d54e54baeedd75fc0d9d8c28", size 
= 4323961, upload-time = "2026-01-22T03:59:56.92Z" },
+    { url = 
"https://files.pythonhosted.org/packages/42/94/ba36dc29e71d476bf71c3bac2b0c89cfcfc4b8973a0a6b20728f429f4560/prek-0.3.0-py3-none-macosx_11_0_arm64.whl";,
 hash = 
"sha256:5f2c446fd9012a98c5690b4badf3f7dfb8d424cf0c6798a2d08ee56511f0a670", size 
= 3970121, upload-time = "2026-01-22T03:59:55.722Z" },
+    { url = 
"https://files.pythonhosted.org/packages/b5/93/6131dd9f6cde3d72815b978b766de21b2ac9cc15fc38f5c22267cc7e574d/prek-0.3.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl";,
 hash = 
"sha256:10f3da7cda2397f7d2f3ff7f2be0d7486c15d4941f7568095b7168e57a9c88c5", size 
= 4307430, upload-time = "2026-01-22T03:59:47.484Z" },
+    { url = 
"https://files.pythonhosted.org/packages/6f/08/7c55a765d96028d38dc984e66a096a969d80e56f66a47801acc86dede856/prek-0.3.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl";,
 hash = 
"sha256:2f747bb4a4322fea35d548cd2c1bd24477f56ed009f3d62a2b97ecbfc88096ac", size 
= 4238032, upload-time = "2026-01-22T04:00:02.606Z" },
+    { url = 
"https://files.pythonhosted.org/packages/dc/a7/59d9bf902b749c8a0cef9e8ac073cc5c886634cd09404c00af4a76470b3b/prek-0.3.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl";,
 hash = 
"sha256:40bd61f11d8caabc0e2a5d4c326639d6ff558b580ef4388aabec293ddb5afd35", size 
= 4493295, upload-time = "2026-01-22T03:59:45.964Z" },
+    { url = 
"https://files.pythonhosted.org/packages/08/dc/902b2e4ddff59ad001ddc2cda3b47e457ab1ee811698a4002b3e4f84faf1/prek-0.3.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl";,
 hash = 
"sha256:1d096b5e273d17a1300b20a7101a9e5a624a8104825eb59659776177f7fccea1", size 
= 5033370, upload-time = "2026-01-22T03:59:44.806Z" },
+    { url = 
"https://files.pythonhosted.org/packages/15/cd/277a3d2768b80bb1ff3c2ea8378687bb4c527d88a8b543bf6f364f8a0dc9/prek-0.3.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl";,
 hash = 
"sha256:df39face5f1298851fbae495267ddf60f1694ea594ed5c6cdb88bdd6de14f6a4", size 
= 4549792, upload-time = "2026-01-22T03:59:41.518Z" },
+    { url = 
"https://files.pythonhosted.org/packages/26/21/53aeabd3822ef7fa350aac66d099d4d97b05e8383a2df35499229389a642/prek-0.3.0-py3-none-manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:9462f80a576d661490aa058d4493a991a34c7532dea76b7b004a17c8bc6b80f2", size 
= 4323158, upload-time = "2026-01-22T03:59:54.284Z" },
+    { url = 
"https://files.pythonhosted.org/packages/27/c2/3a7392b0e7fd07e339d89701b49b12a89d85256a57279877195028215957/prek-0.3.0-py3-none-manylinux_2_31_riscv64.whl";,
 hash = 
"sha256:33d3fa40eecf996ed14bab2d006c39d21ae344677d62599963efd9b27936558e", size 
= 4344632, upload-time = "2026-01-22T04:00:03.71Z" },
+    { url = 
"https://files.pythonhosted.org/packages/71/89/8254ac981d75d0ce2826bcac74fed901540d629cb2d9f4d73ce62f8ce843/prek-0.3.0-py3-none-musllinux_1_1_armv7l.whl";,
 hash = 
"sha256:d8c6abfd53a23718afdf4e6107418db1d74c5d904e9b7ec7900e285f8da90723", size 
= 4216608, upload-time = "2026-01-22T03:59:58.527Z" },
+    { url = 
"https://files.pythonhosted.org/packages/20/f5/854d57d89376fac577ee647a1dba1b87e27b2baeca7edc3d40295adeb7c8/prek-0.3.0-py3-none-musllinux_1_1_i686.whl";,
 hash = 
"sha256:eb4c80c3e7c0e16bf307947809112bfef3715a1b83c2b03f5937707934635617", size 
= 4371174, upload-time = "2026-01-22T03:59:53.088Z" },
+    { url = 
"https://files.pythonhosted.org/packages/03/38/8927619411da8d3f189415c452ec7a463f09dea69e272888723f37b4b18f/prek-0.3.0-py3-none-musllinux_1_1_x86_64.whl";,
 hash = 
"sha256:602bcce070c50900167acd89dcdf95d27894412f8a7b549c8eb66de612a99653", size 
= 4659113, upload-time = "2026-01-22T03:59:43.166Z" },
+    { url = 
"https://files.pythonhosted.org/packages/8c/4d/16baeef633b8b230dde878b858c0e955149c860feef518b5eb5aac640eec/prek-0.3.0-py3-none-win32.whl";,
 hash = 
"sha256:a69229365ce33c68c05db7ae73ad1ef8bc7f0914ab3bc484ab7781256bcdfb7a", size 
= 3937103, upload-time = "2026-01-22T03:59:48.719Z" },
+    { url = 
"https://files.pythonhosted.org/packages/f4/f2/c7395b4afd1bba32cad2b24c30fd7781e94c1e41137348cd150bbef001d6/prek-0.3.0-py3-none-win_amd64.whl";,
 hash = 
"sha256:a0379afd8d31bd5da6ee8977820fdb3c30601bed836b39761e6f605451dbccaa", size 
= 4290763, upload-time = "2026-01-22T03:59:59.938Z" },
+    { url = 
"https://files.pythonhosted.org/packages/df/83/97ed76ab5470025992cd50cb1ebdeb21fcf6c25459f9ffc49ac7bf040cf4/prek-0.3.0-py3-none-win_arm64.whl";,
 hash = 
"sha256:82e2c64f75dc1ea6f2023f4322500eb8da5d0557baf06c88677bddf163e1542a", size 
= 4041580, upload-time = "2026-01-22T03:59:50.082Z" },
+]
+
 [[package]]
 name = "py-cpuinfo"
 version = "9.0.0"


Reply via email to