New Upstream Snapshot - python-rfc6555
Ready changes
Summary
Merged new upstream version: 0.1.0 (was: 0.0~git20190913.1a181b4).
Resulting package
Built on 2022-10-23T22:34 (took 6m28s)
The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:
apt install -t fresh-snapshots python3-rfc6555
Lintian Result
Diff
diff --git a/.appveyor/install.ps1 b/.appveyor/install.ps1
deleted file mode 100644
index 94d6f01..0000000
--- a/.appveyor/install.ps1
+++ /dev/null
@@ -1,229 +0,0 @@
-# Sample script to install Python and pip under Windows
-# Authors: Olivier Grisel, Jonathan Helmus, Kyle Kastner, and Alex Willmer
-# License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/
-
-$MINICONDA_URL = "http://repo.continuum.io/miniconda/"
-$BASE_URL = "https://www.python.org/ftp/python/"
-$GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py"
-$GET_PIP_PATH = "C:\get-pip.py"
-
-$PYTHON_PRERELEASE_REGEX = @"
-(?x)
-(?<major>\d+)
-\.
-(?<minor>\d+)
-\.
-(?<micro>\d+)
-(?<prerelease>[a-z]{1,2}\d+)
-"@
-
-
-function Download ($filename, $url) {
- $webclient = New-Object System.Net.WebClient
-
- $basedir = $pwd.Path + "\"
- $filepath = $basedir + $filename
- if (Test-Path $filename) {
- Write-Host "Reusing" $filepath
- return $filepath
- }
-
- # Download and retry up to 3 times in case of network transient errors.
- Write-Host "Downloading" $filename "from" $url
- $retry_attempts = 2
- for ($i = 0; $i -lt $retry_attempts; $i++) {
- try {
- $webclient.DownloadFile($url, $filepath)
- break
- }
- Catch [Exception]{
- Start-Sleep 1
- }
- }
- if (Test-Path $filepath) {
- Write-Host "File saved at" $filepath
- } else {
- # Retry once to get the error message if any at the last try
- $webclient.DownloadFile($url, $filepath)
- }
- return $filepath
-}
-
-
-function ParsePythonVersion ($python_version) {
- if ($python_version -match $PYTHON_PRERELEASE_REGEX) {
- return ([int]$matches.major, [int]$matches.minor, [int]$matches.micro,
- $matches.prerelease)
- }
- $version_obj = [version]$python_version
- return ($version_obj.major, $version_obj.minor, $version_obj.build, "")
-}
-
-
-function DownloadPython ($python_version, $platform_suffix) {
- $major, $minor, $micro, $prerelease = ParsePythonVersion $python_version
-
- if (($major -le 2 -and $micro -eq 0) `
- -or ($major -eq 3 -and $minor -le 2 -and $micro -eq 0) `
- ) {
- $dir = "$major.$minor"
- $python_version = "$major.$minor$prerelease"
- } else {
- $dir = "$major.$minor.$micro"
- }
-
- if ($prerelease) {
- if (($major -le 2) `
- -or ($major -eq 3 -and $minor -eq 1) `
- -or ($major -eq 3 -and $minor -eq 2) `
- -or ($major -eq 3 -and $minor -eq 3) `
- ) {
- $dir = "$dir/prev"
- }
- }
-
- if (($major -le 2) -or ($major -le 3 -and $minor -le 4)) {
- $ext = "msi"
- if ($platform_suffix) {
- $platform_suffix = ".$platform_suffix"
- }
- } else {
- $ext = "exe"
- if ($platform_suffix) {
- $platform_suffix = "-$platform_suffix"
- }
- }
-
- $filename = "python-$python_version$platform_suffix.$ext"
- $url = "$BASE_URL$dir/$filename"
- $filepath = Download $filename $url
- return $filepath
-}
-
-
-function InstallPython ($python_version, $architecture, $python_home) {
- Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home
- if (Test-Path $python_home) {
- Write-Host $python_home "already exists, skipping."
- return $false
- }
- if ($architecture -eq "32") {
- $platform_suffix = ""
- } else {
- $platform_suffix = "amd64"
- }
- $installer_path = DownloadPython $python_version $platform_suffix
- $installer_ext = [System.IO.Path]::GetExtension($installer_path)
- Write-Host "Installing $installer_path to $python_home"
- $install_log = $python_home + ".log"
- if ($installer_ext -eq '.msi') {
- InstallPythonMSI $installer_path $python_home $install_log
- } else {
- InstallPythonEXE $installer_path $python_home $install_log
- }
- if (Test-Path $python_home) {
- Write-Host "Python $python_version ($architecture) installation complete"
- } else {
- Write-Host "Failed to install Python in $python_home"
- Get-Content -Path $install_log
- Exit 1
- }
-}
-
-
-function InstallPythonEXE ($exepath, $python_home, $install_log) {
- $install_args = "/quiet InstallAllUsers=1 TargetDir=$python_home"
- RunCommand $exepath $install_args
-}
-
-
-function InstallPythonMSI ($msipath, $python_home, $install_log) {
- $install_args = "/qn /log $install_log /i $msipath TARGETDIR=$python_home"
- $uninstall_args = "/qn /x $msipath"
- RunCommand "msiexec.exe" $install_args
- if (-not(Test-Path $python_home)) {
- Write-Host "Python seems to be installed else-where, reinstalling."
- RunCommand "msiexec.exe" $uninstall_args
- RunCommand "msiexec.exe" $install_args
- }
-}
-
-function RunCommand ($command, $command_args) {
- Write-Host $command $command_args
- Start-Process -FilePath $command -ArgumentList $command_args -Wait -Passthru
-}
-
-
-function InstallPip ($python_home) {
- $pip_path = $python_home + "\Scripts\pip.exe"
- $python_path = $python_home + "\python.exe"
- if (-not(Test-Path $pip_path)) {
- Write-Host "Installing pip..."
- $webclient = New-Object System.Net.WebClient
- $webclient.DownloadFile($GET_PIP_URL, $GET_PIP_PATH)
- Write-Host "Executing:" $python_path $GET_PIP_PATH
- & $python_path $GET_PIP_PATH
- } else {
- Write-Host "pip already installed."
- }
-}
-
-
-function DownloadMiniconda ($python_version, $platform_suffix) {
- if ($python_version -eq "3.4") {
- $filename = "Miniconda3-3.5.5-Windows-" + $platform_suffix + ".exe"
- } else {
- $filename = "Miniconda-3.5.5-Windows-" + $platform_suffix + ".exe"
- }
- $url = $MINICONDA_URL + $filename
- $filepath = Download $filename $url
- return $filepath
-}
-
-
-function InstallMiniconda ($python_version, $architecture, $python_home) {
- Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home
- if (Test-Path $python_home) {
- Write-Host $python_home "already exists, skipping."
- return $false
- }
- if ($architecture -eq "32") {
- $platform_suffix = "x86"
- } else {
- $platform_suffix = "x86_64"
- }
- $filepath = DownloadMiniconda $python_version $platform_suffix
- Write-Host "Installing" $filepath "to" $python_home
- $install_log = $python_home + ".log"
- $args = "/S /D=$python_home"
- Write-Host $filepath $args
- Start-Process -FilePath $filepath -ArgumentList $args -Wait -Passthru
- if (Test-Path $python_home) {
- Write-Host "Python $python_version ($architecture) installation complete"
- } else {
- Write-Host "Failed to install Python in $python_home"
- Get-Content -Path $install_log
- Exit 1
- }
-}
-
-
-function InstallMinicondaPip ($python_home) {
- $pip_path = $python_home + "\Scripts\pip.exe"
- $conda_path = $python_home + "\Scripts\conda.exe"
- if (-not(Test-Path $pip_path)) {
- Write-Host "Installing pip..."
- $args = "install --yes pip"
- Write-Host $conda_path $args
- Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait -Passthru
- } else {
- Write-Host "pip already installed."
- }
-}
-
-function main () {
- InstallPython $env:PYTHON_VERSION $env:PYTHON_ARCH $env:PYTHON
- InstallPip $env:PYTHON
-}
-
-main
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index b4764a9..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,95 +0,0 @@
-# Created by .ignore support plugin (hsz.mobi)
-### Python template
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-env/
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-*.egg-info/
-.installed.cfg
-*.egg
-
-# PyInstaller
-# Usually these files are written by a python script from a template
-# before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*,cover
-.hypothesis/
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-local_settings.py
-
-# Flask stuff:
-instance/
-.webassets-cache
-
-# Scrapy stuff:
-.scrapy
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-target/
-
-# IPython Notebook
-.ipynb_checkpoints
-
-# pyenv
-.python-version
-
-# celery beat schedule file
-celerybeat-schedule
-
-# dotenv
-.env
-
-# virtualenv
-venv/
-ENV/
-
-# Spyder project settings
-.spyderproject
-
-# Rope project settings
-.ropeproject
-
-# PyCharm
-.idea/
-
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index fcf216d..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,45 +0,0 @@
-language: python
-sudo: false
-
-matrix:
- include:
- # Miscellaneous Builds
- - python: 3.6
- env: TOXENV=lint
- - python: 3.6
- env: TOXENV=packaging
-
- # Linux Builds
- - python: 2.6
- env: TOXENV=py26
- - python: 2.7
- env: TOXENV=py27
- - python: 3.3
- env: TOXENV=py33
- - python: 3.4
- env: TOXENV=py34
- - python: 3.5
- env: TOXENV=py35
- - python: 3.6
- env: TOXENV=py36
- - python: nightly
- env: TOXENV=py37
-
-cache:
- - pip
- - directories:
- - ${HOME}/.cache
-
-install:
- - pip install tox
-
-script:
- - tox
-
-after_success:
- - source .tox/${TOXENV}/bin/activate
- - pip install codecov
- - codecov --env TRAVIS_OS_NAME,TOXENV
-
-notifications:
- email: false
diff --git a/CHANGES.rst b/CHANGES.rst
index 72dc027..8f1f789 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,7 +1,8 @@
Changelog
=========
-1.0.0
+0.1.0
-----
-- Initial release of ``rfc6555``.
+- Use ``selectors`` instead of ``selectors2`` for Python 3.5+
+- Dropped support for Python 2.6, 3.3, and 3.4
diff --git a/MANIFEST.in b/MANIFEST.in
index e188e8a..57dae7a 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,14 +1,3 @@
-include *.md
include *.rst
-include *.txt
include LICENSE
include .coveragerc
-include tox.ini
-include artisanci/packages/virtualbox/LICENSE
-include artisanci/packages/README.md
-exclude build_docs.py
-exclude .mention-bot
-recursive-include docs *
-recursive-exclude docs/build *
-recursive-include docs Makefile
-recursive-include tests *.py
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..4a45a13
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,112 @@
+Metadata-Version: 2.1
+Name: rfc6555
+Version: 0.1.0
+Summary: Python implementation of the Happy Eyeballs Algorithm described in RFC 6555.
+Home-page: https://www.github.com/sethmlarson/rfc6555
+Author: Seth Michael Larson
+Author-email: sethmichaellarson@gmail.com
+Maintainer: Seth Michael Larson
+Maintainer-email: sethmichaellarson@gmail.com
+License: Apache-2.0
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Natural Language :: English
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Topic :: Internet
+Classifier: Topic :: System :: Networking
+License-File: LICENSE
+
+Happy Eyeballs in Python (RFC 6555)
+===================================
+
+.. image:: https://github.com/sethmlarson/rfc6555/actions/workflows/ci.yml/badge.svg
+ :target: https://github.com/sethmlarson/rfc6555/actions/workflows/ci.yml
+
+.. image:: https://codecov.io/gh/sethmlarson/rfc6555/branch/master/graph/badge.svg?token=Xn7oQWErjc
+ :target: https://codecov.io/gh/sethmlarson/rfc6555
+
+.. image:: https://img.shields.io/pypi/v/rfc6555.svg?style=flat-square
+ :target: https://pypi.python.org/pypi/rfc6555
+
+Synchronous Python implementation of the Happy Eyeballs Algorithm described in `RFC 6555 <https://tools.ietf.org/html/rfc6555>`_.
+Provided with a single file and dead-simple API to allow easy vendoring
+and integration into other projects.
+
+Abstract
+--------
+
+When a server's IPv4 path and protocol are working, but the server's
+IPv6 path and protocol are not working, a dual-stack client
+application experiences significant connection delay compared to an
+IPv4-only client. This is undesirable because it causes the dual-
+stack client to have a worse user experience. This document
+specifies requirements for algorithms that reduce this user-visible
+delay and provides an algorithm.
+
+Installation
+------------
+
+ .. code-block:: bash
+
+ $ python -m pip install rfc6555
+
+Usage
+-----
+
+The main API for the ``rfc6555`` module is via ``rfc6555.create_connection()`` which
+functions identically to ``socket.create_connection()`` with the same arguments.
+This function will automatically fall back on a ``socket.create_connection()`` call if
+RFC 6555 is not supported (for instance on platforms not capable of IPv6) or if
+RFC 6555 is disabled via setting ``rfc6555.RFC6555_ENABLED`` equal to ``False``.
+
+**IMPORTANT:** Caching is **NOT** thread-safe by default. If you require thread-safe caching
+one should create their own implementation of ``rfc6555._RFC6555CacheManager`` object that
+is thread-safe and assign an instance to ``rfc6555.cache``.
+
+ .. code-block:: python
+
+ import rfc6555
+ sock = rfc6555.create_connection(('www.google.com', 80), timeout=10, source_address=('::1', 0))
+
+ # This will disable the Happy Eyeballs algorithm for future
+ # calls to create_connection()
+ rfc6555.RFC6555_ENABLED = False
+
+ # Use this to set a different duration for cache entries.
+ rfc6555.cache.validity_duration = 10 # 10 second validity time.
+
+ # Use this to disable caching.
+ rfc6555.cache.enabled = False
+
+Support
+-------
+
+This module supports Python 2.7 or newer and supports all major platforms.
+Additionally if you have ``selectors2>=2.0.0`` installed this module will
+also support Jython in addition to CPython.
+
+License
+-------
+
+The ``rfc6555`` package is released under the ``Apache-2.0`` license.
+
+See `full license text in LICENSE file <https://github.com/sethmlarson/rfc6555/blob/master/LICENSE>`_ for more information.
+
+
+Changelog
+=========
+
+0.1.0
+-----
+
+- Use ``selectors`` instead of ``selectors2`` for Python 3.5+
+- Dropped support for Python 2.6, 3.3, and 3.4
diff --git a/README.rst b/README.rst
index ad99647..cbdf10b 100644
--- a/README.rst
+++ b/README.rst
@@ -1,22 +1,16 @@
-rfc6555
-=======
+Happy Eyeballs in Python (RFC 6555)
+===================================
-.. image:: https://img.shields.io/travis/SethMichaelLarson/rfc6555/master.svg?style=flat-square
- :target: https://travis-ci.org/SethMichaelLarson/rfc6555
+.. image:: https://github.com/sethmlarson/rfc6555/actions/workflows/ci.yml/badge.svg
+ :target: https://github.com/sethmlarson/rfc6555/actions/workflows/ci.yml
-.. image:: https://img.shields.io/appveyor/ci/SethMichaelLarson/rfc6555/master.svg?style=flat-square
- :target: https://ci.appveyor.com/project/SethMichaelLarson/rfc6555
-
-.. image:: https://img.shields.io/codecov/c/github/SethMichaelLarson/rfc6555/master.svg?style=flat-square
- :target: https://codecov.io/gh/SethMichaelLarson/rfc6555
+.. image:: https://codecov.io/gh/sethmlarson/rfc6555/branch/master/graph/badge.svg?token=Xn7oQWErjc
+ :target: https://codecov.io/gh/sethmlarson/rfc6555
.. image:: https://img.shields.io/pypi/v/rfc6555.svg?style=flat-square
:target: https://pypi.python.org/pypi/rfc6555
-.. image:: https://img.shields.io/badge/say-thanks-ff69b4.svg?style=flat-square
- :target: https://saythanks.io/to/SethMichaelLarson
-
-Python implementation of the Happy Eyeballs Algorithm described in `RFC 6555 <https://tools.ietf.org/html/rfc6555>`_.
+Synchronous Python implementation of the Happy Eyeballs Algorithm described in `RFC 6555 <https://tools.ietf.org/html/rfc6555>`_.
Provided with a single file and dead-simple API to allow easy vendoring
and integration into other projects.
@@ -31,12 +25,12 @@ stack client to have a worse user experience. This document
specifies requirements for algorithms that reduce this user-visible
delay and provides an algorithm.
-~ `Abstract from RFC 6555 <https://tools.ietf.org/html/rfc6555>`_
-
Installation
------------
-``$ python -m pip install rfc6555``
+ .. code-block:: bash
+
+ $ python -m pip install rfc6555
Usage
-----
@@ -69,7 +63,7 @@ is thread-safe and assign an instance to ``rfc6555.cache``.
Support
-------
-This module supports Python 2.6 or newer and supports all major platforms.
+This module supports Python 2.7 or newer and supports all major platforms.
Additionally if you have ``selectors2>=2.0.0`` installed this module will
also support Jython in addition to CPython.
@@ -78,25 +72,4 @@ License
The ``rfc6555`` package is released under the ``Apache-2.0`` license.
-See `full license text in LICENSE file <https://github.com/SethMichaelLarson/rfc6555/blob/master/LICENSE>`_ for more information.
-
- .. code-block::
-
- Copyright 2017 Seth Michael Larson
-
- Licensed 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.
-
-Alternatives
-------------
-
-For asyncio support check out https://pypi.org/project/async-stagger/
+See `full license text in LICENSE file <https://github.com/sethmlarson/rfc6555/blob/master/LICENSE>`_ for more information.
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index ab361ed..0000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,70 +0,0 @@
-# AppVeyor.yml from https://github.com/ogrisel/python-appveyor-demo
-# License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/
-
-build: off
-
-environment:
- matrix:
- - PYTHON: "C:\\Python266-x64"
- PYTHON_VERSION: "2.6.6"
- PYTHON_ARCH: "64"
- TOXENV: "py26"
-
- - PYTHON: "C:\\Python27-x64"
- PYTHON_VERSION: "2.7.x"
- PYTHON_ARCH: "64"
- TOXENV: "py27"
-
- - PYTHON: "C:\\Python33-x64"
- PYTHON_VERSION: "3.3.x"
- PYTHON_ARCH: "64"
- TOXENV: "py33"
-
- - PYTHON: "C:\\Python34-x64"
- PYTHON_VERSION: "3.4.x"
- PYTHON_ARCH: "64"
- TOXENV: "py34"
-
- - PYTHON: "C:\\Python35-x64"
- PYTHON_VERSION: "3.5.x"
- PYTHON_ARCH: "64"
- TOXENV: "py35"
-
- - PYTHON: "C:\\Python36-x64"
- PYTHON_VERSION: "3.6.x"
- PYTHON_ARCH: "64"
- TOXENV: "py36"
-
-install:
- # Install Python (from the official .msi of http://python.org) and pip when
- # not already installed.
- - ps: if (-not(Test-Path($env:PYTHON))) { & .appveyor\install.ps1 }
-
- # Prepend newly installed Python to the PATH of this build (this cannot be
- # done from inside the powershell script as it would require to restart
- # the parent CMD process).
- - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
-
- # Check that we have the expected version and architecture for Python
- - "python --version"
- - "python -c \"import struct; print(struct.calcsize('P') * 8)\""
-
- # Upgrade to the latest version of pip to avoid it displaying warnings
- # about it being out of date.
- - "pip install --disable-pip-version-check --user --upgrade pip"
- - "pip install tox"
-
- - "python setup.py install"
-
-test_script:
- - "tox"
-
-on_success:
- - ".tox\\%TOXENV%\\Scripts\\activate"
- - "pip install codecov"
- - "codecov --env PLATFORM,TOXENV"
-
-branches:
- only:
- - master
- - release
diff --git a/debian/changelog b/debian/changelog
index 8d0428d..c95ed40 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+python-rfc6555 (0.1.0-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk> Sun, 23 Oct 2022 22:28:36 -0000
+
python-rfc6555 (0.0~git20190913.1a181b4-3) unstable; urgency=medium
[ Debian Janitor ]
diff --git a/dev-requirements.txt b/dev-requirements.txt
deleted file mode 100644
index 036dbb4..0000000
--- a/dev-requirements.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-pytest==3.1.1
-check-manifest==0.35
-readme_renderer==17.2
-mock==2.0.0
-codecov==2.0.9
diff --git a/rfc6555.egg-info/PKG-INFO b/rfc6555.egg-info/PKG-INFO
new file mode 100644
index 0000000..4a45a13
--- /dev/null
+++ b/rfc6555.egg-info/PKG-INFO
@@ -0,0 +1,112 @@
+Metadata-Version: 2.1
+Name: rfc6555
+Version: 0.1.0
+Summary: Python implementation of the Happy Eyeballs Algorithm described in RFC 6555.
+Home-page: https://www.github.com/sethmlarson/rfc6555
+Author: Seth Michael Larson
+Author-email: sethmichaellarson@gmail.com
+Maintainer: Seth Michael Larson
+Maintainer-email: sethmichaellarson@gmail.com
+License: Apache-2.0
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Natural Language :: English
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Topic :: Internet
+Classifier: Topic :: System :: Networking
+License-File: LICENSE
+
+Happy Eyeballs in Python (RFC 6555)
+===================================
+
+.. image:: https://github.com/sethmlarson/rfc6555/actions/workflows/ci.yml/badge.svg
+ :target: https://github.com/sethmlarson/rfc6555/actions/workflows/ci.yml
+
+.. image:: https://codecov.io/gh/sethmlarson/rfc6555/branch/master/graph/badge.svg?token=Xn7oQWErjc
+ :target: https://codecov.io/gh/sethmlarson/rfc6555
+
+.. image:: https://img.shields.io/pypi/v/rfc6555.svg?style=flat-square
+ :target: https://pypi.python.org/pypi/rfc6555
+
+Synchronous Python implementation of the Happy Eyeballs Algorithm described in `RFC 6555 <https://tools.ietf.org/html/rfc6555>`_.
+Provided with a single file and dead-simple API to allow easy vendoring
+and integration into other projects.
+
+Abstract
+--------
+
+When a server's IPv4 path and protocol are working, but the server's
+IPv6 path and protocol are not working, a dual-stack client
+application experiences significant connection delay compared to an
+IPv4-only client. This is undesirable because it causes the dual-
+stack client to have a worse user experience. This document
+specifies requirements for algorithms that reduce this user-visible
+delay and provides an algorithm.
+
+Installation
+------------
+
+ .. code-block:: bash
+
+ $ python -m pip install rfc6555
+
+Usage
+-----
+
+The main API for the ``rfc6555`` module is via ``rfc6555.create_connection()`` which
+functions identically to ``socket.create_connection()`` with the same arguments.
+This function will automatically fall back on a ``socket.create_connection()`` call if
+RFC 6555 is not supported (for instance on platforms not capable of IPv6) or if
+RFC 6555 is disabled via setting ``rfc6555.RFC6555_ENABLED`` equal to ``False``.
+
+**IMPORTANT:** Caching is **NOT** thread-safe by default. If you require thread-safe caching
+one should create their own implementation of ``rfc6555._RFC6555CacheManager`` object that
+is thread-safe and assign an instance to ``rfc6555.cache``.
+
+ .. code-block:: python
+
+ import rfc6555
+ sock = rfc6555.create_connection(('www.google.com', 80), timeout=10, source_address=('::1', 0))
+
+ # This will disable the Happy Eyeballs algorithm for future
+ # calls to create_connection()
+ rfc6555.RFC6555_ENABLED = False
+
+ # Use this to set a different duration for cache entries.
+ rfc6555.cache.validity_duration = 10 # 10 second validity time.
+
+ # Use this to disable caching.
+ rfc6555.cache.enabled = False
+
+Support
+-------
+
+This module supports Python 2.7 or newer and supports all major platforms.
+Additionally if you have ``selectors2>=2.0.0`` installed this module will
+also support Jython in addition to CPython.
+
+License
+-------
+
+The ``rfc6555`` package is released under the ``Apache-2.0`` license.
+
+See `full license text in LICENSE file <https://github.com/sethmlarson/rfc6555/blob/master/LICENSE>`_ for more information.
+
+
+Changelog
+=========
+
+0.1.0
+-----
+
+- Use ``selectors`` instead of ``selectors2`` for Python 3.5+
+- Dropped support for Python 2.6, 3.3, and 3.4
diff --git a/rfc6555.egg-info/SOURCES.txt b/rfc6555.egg-info/SOURCES.txt
new file mode 100644
index 0000000..1acd639
--- /dev/null
+++ b/rfc6555.egg-info/SOURCES.txt
@@ -0,0 +1,14 @@
+.coveragerc
+CHANGES.rst
+LICENSE
+MANIFEST.in
+README.rst
+rfc6555.py
+setup.cfg
+setup.py
+rfc6555.egg-info/PKG-INFO
+rfc6555.egg-info/SOURCES.txt
+rfc6555.egg-info/dependency_links.txt
+rfc6555.egg-info/not-zip-safe
+rfc6555.egg-info/requires.txt
+rfc6555.egg-info/top_level.txt
\ No newline at end of file
diff --git a/rfc6555.egg-info/dependency_links.txt b/rfc6555.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/rfc6555.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/rfc6555.egg-info/not-zip-safe b/rfc6555.egg-info/not-zip-safe
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/rfc6555.egg-info/not-zip-safe
@@ -0,0 +1 @@
+
diff --git a/rfc6555.egg-info/requires.txt b/rfc6555.egg-info/requires.txt
new file mode 100644
index 0000000..cc33fd5
--- /dev/null
+++ b/rfc6555.egg-info/requires.txt
@@ -0,0 +1,3 @@
+
+[:python_version < "3.4"]
+selectors2
diff --git a/rfc6555.egg-info/top_level.txt b/rfc6555.egg-info/top_level.txt
new file mode 100644
index 0000000..21c6a4b
--- /dev/null
+++ b/rfc6555.egg-info/top_level.txt
@@ -0,0 +1 @@
+rfc6555
diff --git a/rfc6555.py b/rfc6555.py
index 222fe6c..1a93f14 100644
--- a/rfc6555.py
+++ b/rfc6555.py
@@ -1,6 +1,4 @@
-""" Python implementation of the Happy Eyeballs Algorithm described in RFC 6555. """
-
-# Copyright 2017 Seth Michael Larson
+# Copyright 2021 Seth Michael Larson
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,12 +12,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+"""Python implementation of the Happy Eyeballs Algorithm described in RFC 6555"""
+
import errno
import socket
+
try:
- from selectors import DefaultSelector, EVENT_WRITE
+ from selectors import EVENT_WRITE, DefaultSelector
except (ImportError, AttributeError):
- from selectors2 import DefaultSelector, EVENT_WRITE
+ from selectors2 import EVENT_WRITE, DefaultSelector
# time.perf_counter() is defined in Python 3.3
try:
@@ -35,11 +36,11 @@ _SOCKET_ERRORS = (socket.error, OSError, IOError)
# Detects whether an IPv6 socket can be allocated.
def _detect_ipv6():
- if getattr(socket, 'has_ipv6', False) and hasattr(socket, 'AF_INET6'):
+ if getattr(socket, "has_ipv6", False) and hasattr(socket, "AF_INET6"):
_sock = None
try:
_sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
- _sock.bind(('::1', 0))
+ _sock.bind(("::1", 0))
return True
except _SOCKET_ERRORS:
if _sock:
@@ -51,10 +52,8 @@ _HAS_IPV6 = _detect_ipv6()
# These are error numbers for asynchronous operations which can
# be safely ignored by RFC 6555 as being non-errors.
-_ASYNC_ERRNOS = set([errno.EINPROGRESS,
- errno.EAGAIN,
- errno.EWOULDBLOCK])
-if hasattr(errno, 'WSAWOULDBLOCK'):
+_ASYNC_ERRNOS = set([errno.EINPROGRESS, errno.EAGAIN, errno.EWOULDBLOCK])
+if hasattr(errno, "WSAWOULDBLOCK"):
_ASYNC_ERRNOS.add(errno.WSAWOULDBLOCK)
_DEFAULT_CACHE_DURATION = 60 * 10 # 10 minutes according to the RFC.
@@ -62,14 +61,12 @@ _DEFAULT_CACHE_DURATION = 60 * 10 # 10 minutes according to the RFC.
# This value that can be used to disable RFC 6555 globally.
RFC6555_ENABLED = _HAS_IPV6
-__all__ = ['RFC6555_ENABLED',
- 'create_connection',
- 'cache']
+__all__ = ["RFC6555_ENABLED", "create_connection", "cache"]
-__version__ = '1.0.0'
-__author__ = 'Seth Michael Larson'
-__email__ = 'sethmichaellarson@protonmail.com'
-__license__ = 'Apache-2.0'
+__version__ = "0.1.0"
+__author__ = "Seth Michael Larson"
+__email__ = "sethmichaellarson@gmail.com"
+__license__ = "Apache-2.0"
class _RFC6555CacheManager(object):
@@ -102,7 +99,9 @@ cache = _RFC6555CacheManager()
class _RFC6555ConnectionManager(object):
- def __init__(self, address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None):
+ def __init__(
+ self, address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None
+ ):
self.address = address
self.timeout = timeout
self.source_address = source_address
@@ -128,7 +127,7 @@ class _RFC6555ConnectionManager(object):
# If we don't get any results back then just skip to the end.
if not addr_info:
- raise socket.error('getaddrinfo returns an empty list')
+ raise socket.error("getaddrinfo returns an empty list")
sock = self._attempt_connect_with_addr_info(addr_info)
@@ -283,7 +282,9 @@ class _RFC6555ConnectionManager(object):
self._sockets = []
-def create_connection(address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None):
+def create_connection(
+ address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None
+):
if RFC6555_ENABLED and _HAS_IPV6:
manager = _RFC6555ConnectionManager(address, timeout, source_address)
return manager.create_connection()
@@ -296,7 +297,7 @@ def create_connection(address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_ad
host, port = address
err = None
for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
- af, socktype, proto, canonname, sa = res
+ af, socktype, proto, _, sa = res
sock = None
try:
sock = socket.socket(af, socktype, proto)
diff --git a/setup.cfg b/setup.cfg
index 2a9acf1..adf5ed7 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,2 +1,7 @@
[bdist_wheel]
universal = 1
+
+[egg_info]
+tag_build =
+tag_date = 0
+
diff --git a/setup.py b/setup.py
index f6f087a..899241a 100644
--- a/setup.py
+++ b/setup.py
@@ -1,45 +1,48 @@
import os
import re
+
from setuptools import setup
# Get the version (borrowed from SQLAlchemy)
base_path = os.path.dirname(os.path.abspath(__file__))
-with open(os.path.join(base_path, 'rfc6555.py')) as f:
- VERSION = re.compile(r'.*__version__ = \'(.*?)\'', re.S).match(f.read()).group(1)
+with open(os.path.join(base_path, "rfc6555.py")) as f:
+ VERSION = re.compile(r".*__version__ = \"(.*?)\"", re.S).match(f.read()).group(1)
-with open(os.path.join(base_path, 'README.rst')) as f:
+with open(os.path.join(base_path, "README.rst")) as f:
long_description = f.read()
-with open(os.path.join(base_path, 'CHANGES.rst')) as f:
+with open(os.path.join(base_path, "CHANGES.rst")) as f:
changes = f.read()
-if __name__ == '__main__':
- setup(name='rfc6555',
- description='Python implementation of the Happy Eyeballs Algorithm described in RFC 6555.',
- long_description=long_description + '\n\n' + changes,
- license='Apache-2.0',
- url='https://www.github.com/SethMichaelLarson/rfc6555',
- version=VERSION,
- author='Seth Michael Larson',
- author_email='sethmichaellarson@protonmail.com',
- maintainer='Seth Michael Larson',
- maintainer_email='sethmichaellarson@protonmail.com',
- install_requires=[
- 'selectors2;python_version<"3.4"'
- ],
- py_modules=['rfc6555'],
- zip_safe=False,
- classifiers=['Intended Audience :: Developers',
- 'License :: OSI Approved :: Apache Software License',
- 'Natural Language :: English',
- 'Operating System :: OS Independent',
- 'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.6',
- 'Programming Language :: Python :: 2.7',
- 'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.3',
- 'Programming Language :: Python :: 3.4',
- 'Programming Language :: Python :: 3.5',
- 'Programming Language :: Python :: 3.6',
- 'Topic :: Internet',
- 'Topic :: System :: Networking'])
+setup(
+ name="rfc6555",
+ description="Python implementation of the Happy Eyeballs Algorithm described in RFC 6555.",
+ long_description=long_description + "\n\n" + changes,
+ license="Apache-2.0",
+ url="https://www.github.com/sethmlarson/rfc6555",
+ version=VERSION,
+ author="Seth Michael Larson",
+ author_email="sethmichaellarson@gmail.com",
+ maintainer="Seth Michael Larson",
+ maintainer_email="sethmichaellarson@gmail.com",
+ install_requires=['selectors2;python_version<"3.4"'],
+ py_modules=["rfc6555"],
+ zip_safe=False,
+ classifiers=[
+ "Intended Audience :: Developers",
+ "License :: OSI Approved :: Apache Software License",
+ "Natural Language :: English",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python :: 2",
+ "Programming Language :: Python :: 2.7",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.5",
+ "Programming Language :: Python :: 3.6",
+ "Programming Language :: Python :: 3.7",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Topic :: Internet",
+ "Topic :: System :: Networking",
+ ],
+)
diff --git a/tests/__init__.py b/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/test_create_connection.py b/tests/test_create_connection.py
deleted file mode 100644
index 0603546..0000000
--- a/tests/test_create_connection.py
+++ /dev/null
@@ -1,63 +0,0 @@
-try:
- from unittest import mock
-except (ImportError, AttributeError):
- import mock
-
-import pytest
-import socket
-import rfc6555
-from .test_utils import requires_network
-
-
-class _BasicCreateConnectionTests(object):
- @requires_network
- def test_create_connection_google(self):
- sock = rfc6555.create_connection(('www.google.com', 80))
-
- @pytest.mark.parametrize('timeout', [None, 5.0])
- def test_create_connection_has_proper_timeout(self, timeout):
- sock = rfc6555.create_connection(('www.google.com', 80), timeout=timeout)
-
- assert sock.gettimeout() == timeout
-
- def test_create_connection_with_source_address_calls_bind(self):
- sock = mock.Mock()
- with mock.patch('socket.socket') as fake_socket:
- fake_socket.return_value = sock
-
- sock.getsockopt.return_value = 0
- sock.connect_ex.return_value = 0
- sock.gettimeout.return_value = None
-
- try:
- rfc6555.create_connection(('::1', 0), source_address=('::1', 123))
- except Exception:
- pass
-
- sock.bind.assert_called_with(('::1', 123))
-
- def test_getaddr_info_empty_list(self):
- with mock.patch('socket.getaddrinfo') as fake_getaddrinfo:
- fake_getaddrinfo.return_value = []
-
- with pytest.raises(socket.error):
- rfc6555.create_connection(('::1', 0))
-
- @requires_network
- def test_create_connection_cached_value(self):
- sock = rfc6555.create_connection(('www.google.com', 80))
- sock2 = rfc6555.create_connection(('www.google.com', 80))
-
-
-class TestCreateConnectionTestRFC6555Default(_BasicCreateConnectionTests):
- pass
-
-
-class TestCreateConnectionTestRFC6555Enabled(_BasicCreateConnectionTests):
- def setup_method(self, test_method):
- rfc6555.RFC6555_ENABLED = True
-
-
-class TestCreateConnectionTestRFC6555Disabled(_BasicCreateConnectionTests):
- def setup_method(self, test_method):
- rfc6555.RFC6555_ENABLED = False
diff --git a/tests/test_ipv6.py b/tests/test_ipv6.py
deleted file mode 100644
index d58286c..0000000
--- a/tests/test_ipv6.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import socket
-import rfc6555
-
-try:
- from unittest import mock
-except (ImportError, AttributeError):
- import mock
-
-
-def test_ipv6_available():
- assert rfc6555._detect_ipv6()
-
-
-def test_ipv6_not_available_socket_has_ipv6_false():
- old_has_ipv6 = socket.has_ipv6
- socket.has_ipv6 = False
- assert not rfc6555._detect_ipv6()
- socket.has_ipv6 = old_has_ipv6
-
-
-def test_ipv6_not_available_socket_exception_on_init():
- with mock.patch('socket.socket') as fake_socket:
- fake_socket.side_effect = OSError
-
- assert not rfc6555._detect_ipv6()
-
-
-def test_ipv6_not_available_socket_exception_on_bind():
- sock = mock.Mock()
- with mock.patch('socket.socket') as fake_socket:
- fake_socket.return_value = sock
- sock.bind.side_effect = OSError
-
- assert not rfc6555._detect_ipv6()
-
-
-def test_ipv6_not_available_socket_AF_INET6_not_defined():
- old_AF_INET6 = socket.AF_INET6
- try:
- delattr(socket, 'AF_INET6')
- assert not rfc6555._detect_ipv6()
- finally:
- socket.AF_INET6 = old_AF_INET6
diff --git a/tests/test_utils.py b/tests/test_utils.py
deleted file mode 100644
index e2f84ec..0000000
--- a/tests/test_utils.py
+++ /dev/null
@@ -1,17 +0,0 @@
-import pytest
-import socket
-
-
-def _check_network():
- sock = None
- try:
- sock = socket.create_connection(('www.google.com', 80))
- sock.close()
- return True
- except Exception:
- if sock:
- sock.close()
- return False
-
-
-requires_network = pytest.mark.skipif(not _check_network(), reason='This test requires a network connection.')
diff --git a/tox.ini b/tox.ini
deleted file mode 100644
index 29a7f2f..0000000
--- a/tox.ini
+++ /dev/null
@@ -1,27 +0,0 @@
-[tox]
-envlist = lint, packaging, py26, py27, py33, py34, py35, py36, py37
-skip_missing_interpreters = true
-
-[testenv]
-deps= -r{toxinidir}/dev-requirements.txt
-commands=
- coverage run -m pytest tests/
- coverage report -m
- coverage html
-passenv = TRAVIS APPVEYOR
-
-[testenv:py26]
-# Additional dependency on unittest2 for Python 2.6
-deps=
- {[testenv]deps}
- unittest2
-
-[testenv:lint]
-commands =
- python -m pip install flake8
- flake8 --max-line-length 100 rfc6555.py
-
-[testenv:packaging]
-commands =
- check-manifest --ignore *.yml,.mention-bot,.appveyor*,.travis*,.github*
- python setup.py check --metadata --restructuredtext --strict
Debdiff
[The following lists of changes regard files as different if they have different names, permissions or owners.]
Files in second set of .debs but not in first
-rw-r--r-- root/root /usr/lib/python3/dist-packages/rfc6555-0.1.0.egg-info/PKG-INFO -rw-r--r-- root/root /usr/lib/python3/dist-packages/rfc6555-0.1.0.egg-info/dependency_links.txt -rw-r--r-- root/root /usr/lib/python3/dist-packages/rfc6555-0.1.0.egg-info/not-zip-safe -rw-r--r-- root/root /usr/lib/python3/dist-packages/rfc6555-0.1.0.egg-info/requires.txt -rw-r--r-- root/root /usr/lib/python3/dist-packages/rfc6555-0.1.0.egg-info/top_level.txt
Files in first set of .debs but not in second
-rw-r--r-- root/root /usr/lib/python3/dist-packages/rfc6555-1.0.0.egg-info/PKG-INFO -rw-r--r-- root/root /usr/lib/python3/dist-packages/rfc6555-1.0.0.egg-info/dependency_links.txt -rw-r--r-- root/root /usr/lib/python3/dist-packages/rfc6555-1.0.0.egg-info/not-zip-safe -rw-r--r-- root/root /usr/lib/python3/dist-packages/rfc6555-1.0.0.egg-info/requires.txt -rw-r--r-- root/root /usr/lib/python3/dist-packages/rfc6555-1.0.0.egg-info/top_level.txt
No differences were encountered in the control files