Browse Source

17.12

master
Mai Gillmann 5 years ago
parent
commit
4791d00a43
100 changed files with 27218 additions and 0 deletions
  1. 76
    0
      venv/bin/activate
  2. 37
    0
      venv/bin/activate.csh
  3. 11
    0
      venv/bin/automat-visualize
  4. 11
    0
      venv/bin/django-admin
  5. 12
    0
      venv/bin/mailmail
  6. 12
    0
      venv/bin/pip
  7. 12
    0
      venv/bin/pip3.7
  8. 12
    0
      venv/bin/trial
  9. 12
    0
      venv/bin/twist
  10. 11
    0
      venv/bin/wamp
  11. 1
    0
      venv/lib/python3.7/site-packages/Automat-0.8.0.dist-info/INSTALLER
  12. 21
    0
      venv/lib/python3.7/site-packages/Automat-0.8.0.dist-info/LICENSE
  13. 486
    0
      venv/lib/python3.7/site-packages/Automat-0.8.0.dist-info/METADATA
  14. 3
    0
      venv/lib/python3.7/site-packages/Automat-0.8.0.dist-info/entry_points.txt
  15. 1
    0
      venv/lib/python3.7/site-packages/Automat-0.8.0.dist-info/top_level.txt
  16. 27
    0
      venv/lib/python3.7/site-packages/Django-2.2.6.dist-info/LICENSE
  17. 4212
    0
      venv/lib/python3.7/site-packages/Django-2.2.6.dist-info/RECORD
  18. 3
    0
      venv/lib/python3.7/site-packages/Django-2.2.6.dist-info/entry_points.txt
  19. 20
    0
      venv/lib/python3.7/site-packages/OpenSSL/__init__.py
  20. 42
    0
      venv/lib/python3.7/site-packages/OpenSSL/debug.py
  21. 22
    0
      venv/lib/python3.7/site-packages/OpenSSL/version.py
  22. 322
    0
      venv/lib/python3.7/site-packages/PyHamcrest-1.9.0.dist-info/DESCRIPTION.rst
  23. 353
    0
      venv/lib/python3.7/site-packages/PyHamcrest-1.9.0.dist-info/METADATA
  24. 120
    0
      venv/lib/python3.7/site-packages/PyHamcrest-1.9.0.dist-info/RECORD
  25. 6
    0
      venv/lib/python3.7/site-packages/PyHamcrest-1.9.0.dist-info/WHEEL
  26. 1
    0
      venv/lib/python3.7/site-packages/PyHamcrest-1.9.0.dist-info/metadata.json
  27. 1
    0
      venv/lib/python3.7/site-packages/PyJWT-1.7.1.dist-info/INSTALLER
  28. 35
    0
      venv/lib/python3.7/site-packages/PyJWT-1.7.1.dist-info/RECORD
  29. 6
    0
      venv/lib/python3.7/site-packages/PyJWT-1.7.1.dist-info/WHEEL
  30. 135
    0
      venv/lib/python3.7/site-packages/Twisted-19.10.0-py3.7.egg-info/PKG-INFO
  31. 1479
    0
      venv/lib/python3.7/site-packages/Twisted-19.10.0-py3.7.egg-info/SOURCES.txt
  32. 1
    0
      venv/lib/python3.7/site-packages/Twisted-19.10.0-py3.7.egg-info/dependency_links.txt
  33. 1
    0
      venv/lib/python3.7/site-packages/Twisted-19.10.0-py3.7.egg-info/not-zip-safe
  34. 1
    0
      venv/lib/python3.7/site-packages/Twisted-19.10.0-py3.7.egg-info/top_level.txt
  35. 119
    0
      venv/lib/python3.7/site-packages/Werkzeug-0.16.0.dist-info/RECORD
  36. 6
    0
      venv/lib/python3.7/site-packages/Werkzeug-0.16.0.dist-info/WHEEL
  37. 27
    0
      venv/lib/python3.7/site-packages/asgiref-3.2.3.dist-info/LICENSE
  38. 225
    0
      venv/lib/python3.7/site-packages/asgiref-3.2.3.dist-info/METADATA
  39. 86
    0
      venv/lib/python3.7/site-packages/asgiref/current_thread_executor.py
  40. 154
    0
      venv/lib/python3.7/site-packages/asgiref/server.py
  41. 304
    0
      venv/lib/python3.7/site-packages/asgiref/sync.py
  42. 128
    0
      venv/lib/python3.7/site-packages/asgiref/timeout.py
  43. 278
    0
      venv/lib/python3.7/site-packages/attr/__init__.pyi
  44. 230
    0
      venv/lib/python3.7/site-packages/attr/_compat.py
  45. 23
    0
      venv/lib/python3.7/site-packages/attr/_config.py
  46. 2168
    0
      venv/lib/python3.7/site-packages/attr/_make.py
  47. 78
    0
      venv/lib/python3.7/site-packages/attr/converters.py
  48. 12
    0
      venv/lib/python3.7/site-packages/attr/converters.pyi
  49. 15
    0
      venv/lib/python3.7/site-packages/attr/exceptions.pyi
  50. 52
    0
      venv/lib/python3.7/site-packages/attr/filters.py
  51. 1
    0
      venv/lib/python3.7/site-packages/attrs-19.3.0.dist-info/INSTALLER
  52. 21
    0
      venv/lib/python3.7/site-packages/attrs-19.3.0.dist-info/LICENSE
  53. 229
    0
      venv/lib/python3.7/site-packages/attrs-19.3.0.dist-info/METADATA
  54. 21
    0
      venv/lib/python3.7/site-packages/autobahn-19.11.1.dist-info/LICENSE
  55. 347
    0
      venv/lib/python3.7/site-packages/autobahn-19.11.1.dist-info/RECORD
  56. 27
    0
      venv/lib/python3.7/site-packages/autobahn/_version.py
  57. 505
    0
      venv/lib/python3.7/site-packages/autobahn/asyncio/rawsocket.py
  58. 396
    0
      venv/lib/python3.7/site-packages/autobahn/asyncio/websocket.py
  59. 41
    0
      venv/lib/python3.7/site-packages/autobahn/exception.py
  60. 646
    0
      venv/lib/python3.7/site-packages/autobahn/nvx/_utf8validator.c
  61. 357
    0
      venv/lib/python3.7/site-packages/autobahn/nvx/test/test_utf8validator.py
  62. 126
    0
      venv/lib/python3.7/site-packages/autobahn/rawsocket/test/test_rawsocket_url.py
  63. 111
    0
      venv/lib/python3.7/site-packages/autobahn/test/test_rng.py
  64. 48
    0
      venv/lib/python3.7/site-packages/autobahn/test/test_util.py
  65. 89
    0
      venv/lib/python3.7/site-packages/autobahn/twisted/__init__.py
  66. 870
    0
      venv/lib/python3.7/site-packages/autobahn/util.py
  67. 83
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/__init__.py
  68. 314
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/exception.py
  69. BIN
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/schema/session.bfbs
  70. 38
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/Map.py
  71. 22
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/Void.py
  72. 11
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/AuthFactor.py
  73. 8
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/AuthMode.py
  74. 22
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/AuthTicketChallenge.py
  75. 22
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/AuthTicketRequest.py
  76. 102
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/CalleeFeatures.py
  77. 70
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/CallerFeatures.py
  78. 9
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/CancelMode.py
  79. 42
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/Challenge.py
  80. 8
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/ChannelBinding.py
  81. 126
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/DealerFeatures.py
  82. 110
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/Error.py
  83. 223
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/Event.py
  84. 94
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/EventReceived.py
  85. 118
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/Hello.py
  86. 38
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/Interrupt.py
  87. 9
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/Kdf.py
  88. 9
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/Match.py
  89. 70
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/PublisherFeatures.py
  90. 13
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/Serializer.py
  91. 94
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/Yield.py
  92. 0
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/__init__.py
  93. 5947
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/message.py
  94. 1958
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/protocol.py
  95. 39
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/test/test_cryptobox.py
  96. 127
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/test/test_cryptosign.py
  97. 580
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/test/test_uri_pattern.py
  98. 1371
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/types.py
  99. 296
    0
      venv/lib/python3.7/site-packages/autobahn/wamp/websocket.py
  100. 0
    0
      venv/lib/python3.7/site-packages/autobahn/websocket/compress_bzip2.py

+ 76
- 0
venv/bin/activate View File

@@ -0,0 +1,76 @@
# This file must be used with "source bin/activate" *from bash*
# you cannot run it directly

deactivate () {
# reset old environment variables
if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
PATH="${_OLD_VIRTUAL_PATH:-}"
export PATH
unset _OLD_VIRTUAL_PATH
fi
if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
export PYTHONHOME
unset _OLD_VIRTUAL_PYTHONHOME
fi

# This should detect bash and zsh, which have a hash command that must
# be called to get it to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
hash -r
fi

if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
PS1="${_OLD_VIRTUAL_PS1:-}"
export PS1
unset _OLD_VIRTUAL_PS1
fi

unset VIRTUAL_ENV
if [ ! "$1" = "nondestructive" ] ; then
# Self destruct!
unset -f deactivate
fi
}

# unset irrelevant variables
deactivate nondestructive

VIRTUAL_ENV="/Users/gillmannma68984/PycharmProjects/git/demoweb/venv"
export VIRTUAL_ENV

_OLD_VIRTUAL_PATH="$PATH"
PATH="$VIRTUAL_ENV/bin:$PATH"
export PATH

# unset PYTHONHOME if set
# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
# could use `if (set -u; : $PYTHONHOME) ;` in bash
if [ -n "${PYTHONHOME:-}" ] ; then
_OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
unset PYTHONHOME
fi

if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
_OLD_VIRTUAL_PS1="${PS1:-}"
if [ "x(venv) " != x ] ; then
PS1="(venv) ${PS1:-}"
else
if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then
# special case for Aspen magic directories
# see http://www.zetadev.com/software/aspen/
PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1"
else
PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1"
fi
fi
export PS1
fi

# This should detect bash and zsh, which have a hash command that must
# be called to get it to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
hash -r
fi

+ 37
- 0
venv/bin/activate.csh View File

@@ -0,0 +1,37 @@
# This file must be used with "source bin/activate.csh" *from csh*.
# You cannot run it directly.
# Created by Davide Di Blasi <davidedb@gmail.com>.
# Ported to Python 3.3 venv by Andrew Svetlov <andrew.svetlov@gmail.com>

alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate'

# Unset irrelevant variables.
deactivate nondestructive

setenv VIRTUAL_ENV "/Users/gillmannma68984/PycharmProjects/git/demoweb/venv"

set _OLD_VIRTUAL_PATH="$PATH"
setenv PATH "$VIRTUAL_ENV/bin:$PATH"


set _OLD_VIRTUAL_PROMPT="$prompt"

if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
if ("venv" != "") then
set env_name = "venv"
else
if (`basename "VIRTUAL_ENV"` == "__") then
# special case for Aspen magic directories
# see http://www.zetadev.com/software/aspen/
set env_name = `basename \`dirname "$VIRTUAL_ENV"\``
else
set env_name = `basename "$VIRTUAL_ENV"`
endif
endif
set prompt = "[$env_name] $prompt"
unset env_name
endif

alias pydoc python -m pydoc

rehash

+ 11
- 0
venv/bin/automat-visualize View File

@@ -0,0 +1,11 @@
#!/Users/gillmannma68984/PycharmProjects/git/demoweb/venv/bin/python

# -*- coding: utf-8 -*-
import re
import sys

from automat._visualize import tool

if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(tool())

+ 11
- 0
venv/bin/django-admin View File

@@ -0,0 +1,11 @@
#!/Users/gillmannma68984/PycharmProjects/git/demoweb/venv/bin/python

# -*- coding: utf-8 -*-
import re
import sys

from django.core.management import execute_from_command_line

if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(execute_from_command_line())

+ 12
- 0
venv/bin/mailmail View File

@@ -0,0 +1,12 @@
#!/Users/gillmannma68984/PycharmProjects/git/demoweb/venv/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'Twisted==19.10.0','console_scripts','mailmail'
__requires__ = 'Twisted==19.10.0'
import re
import sys
from pkg_resources import load_entry_point

if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(
load_entry_point('Twisted==19.10.0', 'console_scripts', 'mailmail')()
)

+ 12
- 0
venv/bin/pip View File

@@ -0,0 +1,12 @@
#!/Users/gillmannma68984/PycharmProjects/git/demoweb/venv/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'pip==10.0.1','console_scripts','pip'
__requires__ = 'pip==10.0.1'
import re
import sys
from pkg_resources import load_entry_point

if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(
load_entry_point('pip==10.0.1', 'console_scripts', 'pip')()
)

+ 12
- 0
venv/bin/pip3.7 View File

@@ -0,0 +1,12 @@
#!/Users/gillmannma68984/PycharmProjects/git/demoweb/venv/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'pip==10.0.1','console_scripts','pip3.7'
__requires__ = 'pip==10.0.1'
import re
import sys
from pkg_resources import load_entry_point

if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(
load_entry_point('pip==10.0.1', 'console_scripts', 'pip3.7')()
)

+ 12
- 0
venv/bin/trial View File

@@ -0,0 +1,12 @@
#!/Users/gillmannma68984/PycharmProjects/git/demoweb/venv/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'Twisted==19.10.0','console_scripts','trial'
__requires__ = 'Twisted==19.10.0'
import re
import sys
from pkg_resources import load_entry_point

if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(
load_entry_point('Twisted==19.10.0', 'console_scripts', 'trial')()
)

+ 12
- 0
venv/bin/twist View File

@@ -0,0 +1,12 @@
#!/Users/gillmannma68984/PycharmProjects/git/demoweb/venv/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'Twisted==19.10.0','console_scripts','twist'
__requires__ = 'Twisted==19.10.0'
import re
import sys
from pkg_resources import load_entry_point

if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(
load_entry_point('Twisted==19.10.0', 'console_scripts', 'twist')()
)

+ 11
- 0
venv/bin/wamp View File

@@ -0,0 +1,11 @@
#!/Users/gillmannma68984/PycharmProjects/git/demoweb/venv/bin/python

# -*- coding: utf-8 -*-
import re
import sys

from autobahn.__main__ import _main

if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(_main())

+ 1
- 0
venv/lib/python3.7/site-packages/Automat-0.8.0.dist-info/INSTALLER View File

@@ -0,0 +1 @@
pip

+ 21
- 0
venv/lib/python3.7/site-packages/Automat-0.8.0.dist-info/LICENSE View File

@@ -0,0 +1,21 @@
Copyright (c) 2014
Rackspace

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 486
- 0
venv/lib/python3.7/site-packages/Automat-0.8.0.dist-info/METADATA View File

@@ -0,0 +1,486 @@
Metadata-Version: 2.1
Name: Automat
Version: 0.8.0
Summary: Self-service finite-state machines for the programmer on the go.
Home-page: https://github.com/glyph/Automat
Author: Glyph
Author-email: glyph@twistedmatrix.com
License: MIT
Keywords: fsm finite state machine automata
Platform: UNKNOWN
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
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
Requires-Dist: attrs (>=16.1.0)
Requires-Dist: six
Provides-Extra: visualize
Requires-Dist: graphviz (>0.5.1) ; extra == 'visualize'
Requires-Dist: Twisted (>=16.1.1) ; extra == 'visualize'

Automat
=======


.. image:: https://readthedocs.org/projects/automat/badge/?version=latest
:target: http://automat.readthedocs.io/en/latest/
:alt: Documentation Status


.. image:: https://travis-ci.org/glyph/automat.svg?branch=master
:target: https://travis-ci.org/glyph/automat
:alt: Build Status


.. image:: https://coveralls.io/repos/glyph/automat/badge.png
:target: https://coveralls.io/r/glyph/automat
:alt: Coverage Status


Self-service finite-state machines for the programmer on the go.
----------------------------------------------------------------

Automat is a library for concise, idiomatic Python expression of finite-state
automata (particularly deterministic finite-state transducers).

Read more here, or on `Read the Docs <https://automat.readthedocs.io/>`_\ , or watch the following videos for an overview and presentation

Overview and presentation by **Glyph Lefkowitz** at the first talk of the first Pyninsula meetup, on February 21st, 2017:

.. image:: https://img.youtube.com/vi/0wOZBpD1VVk/0.jpg
:target: https://www.youtube.com/watch?v=0wOZBpD1VVk
:alt: Glyph Lefkowitz - Automat - Pyninsula #0


Presentation by **Clinton Roy** at PyCon Australia, on August 6th 2017:

.. image:: https://img.youtube.com/vi/TedUKXhu9kE/0.jpg
:target: https://www.youtube.com/watch?v=TedUKXhu9kE
:alt: Clinton Roy - State Machines - Pycon Australia 2017


Why use state machines?
^^^^^^^^^^^^^^^^^^^^^^^

Sometimes you have to create an object whose behavior varies with its state,
but still wishes to present a consistent interface to its callers.

For example, let's say you're writing the software for a coffee machine. It
has a lid that can be opened or closed, a chamber for water, a chamber for
coffee beans, and a button for "brew".

There are a number of possible states for the coffee machine. It might or
might not have water. It might or might not have beans. The lid might be open
or closed. The "brew" button should only actually attempt to brew coffee in
one of these configurations, and the "open lid" button should only work if the
coffee is not, in fact, brewing.

With diligence and attention to detail, you can implement this correctly using
a collection of attributes on an object; ``has_water``\ , ``has_beans``\ ,
``is_lid_open`` and so on. However, you have to keep all these attributes
consistent. As the coffee maker becomes more complex - perhaps you add an
additional chamber for flavorings so you can make hazelnut coffee, for
example - you have to keep adding more and more checks and more and more
reasoning about which combinations of states are allowed.

Rather than adding tedious 'if' checks to every single method to make sure that
each of these flags are exactly what you expect, you can use a state machine to
ensure that if your code runs at all, it will be run with all the required
values initialized, because they have to be called in the order you declare
them.

You can read about state machines and their advantages for Python programmers
in considerably more detail
`in this excellent series of articles from ClusterHQ <https://clusterhq.com/blog/what-is-a-state-machine/>`_.

What makes Automat different?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

There are
`dozens of libraries on PyPI implementing state machines <https://pypi.org/search/?q=finite+state+machine>`_.
So it behooves me to say why yet another one would be a good idea.

Automat is designed around this principle: while organizing your code around
state machines is a good idea, your callers don't, and shouldn't have to, care
that you've done so. In Python, the "input" to a stateful system is a method
call; the "output" may be a method call, if you need to invoke a side effect,
or a return value, if you are just performing a computation in memory. Most
other state-machine libraries require you to explicitly create an input object,
provide that object to a generic "input" method, and then receive results,
sometimes in terms of that library's interfaces and sometimes in terms of
classes you define yourself.

For example, a snippet of the coffee-machine example above might be implemented
as follows in naive Python:

.. code-block:: python

class CoffeeMachine(object):
def brew_button(self):
if self.has_water and self.has_beans and not self.is_lid_open:
self.heat_the_heating_element()
# ...

With Automat, you'd create a class with a ``MethodicalMachine`` attribute:

.. code-block:: python

from automat import MethodicalMachine

class CoffeeBrewer(object):
_machine = MethodicalMachine()

and then you would break the above logic into two pieces - the ``brew_button``
*input*\ , declared like so:

.. code-block:: python

@_machine.input()
def brew_button(self):
"The user pressed the 'brew' button."

It wouldn't do any good to declare a method *body* on this, however, because
input methods don't actually execute their bodies when called; doing actual
work is the *output*\ 's job:

.. code-block:: python

@_machine.output()
def _heat_the_heating_element(self):
"Heat up the heating element, which should cause coffee to happen."
self._heating_element.turn_on()

As well as a couple of *states* - and for simplicity's sake let's say that the
only two states are ``have_beans`` and ``dont_have_beans``\ :

.. code-block:: python

@_machine.state()
def have_beans(self):
"In this state, you have some beans."
@_machine.state(initial=True)
def dont_have_beans(self):
"In this state, you don't have any beans."

``dont_have_beans`` is the ``initial`` state because ``CoffeeBrewer`` starts without beans
in it.

(And another input to put some beans in:)

.. code-block:: python

@_machine.input()
def put_in_beans(self):
"The user put in some beans."

Finally, you hook everything together with the ``upon`` method of the functions
decorated with ``_machine.state``\ :

.. code-block:: python


# When we don't have beans, upon putting in beans, we will then have beans
# (and produce no output)
dont_have_beans.upon(put_in_beans, enter=have_beans, outputs=[])

# When we have beans, upon pressing the brew button, we will then not have
# beans any more (as they have been entered into the brewing chamber) and
# our output will be heating the heating element.
have_beans.upon(brew_button, enter=dont_have_beans,
outputs=[_heat_the_heating_element])

To *users* of this coffee machine class though, it still looks like a POPO
(Plain Old Python Object):

.. code-block:: python

>>> coffee_machine = CoffeeMachine()
>>> coffee_machine.put_in_beans()
>>> coffee_machine.brew_button()

All of the *inputs* are provided by calling them like methods, all of the
*outputs* are automatically invoked when they are produced according to the
outputs specified to ``upon`` and all of the states are simply opaque tokens -
although the fact that they're defined as methods like inputs and outputs
allows you to put docstrings on them easily to document them.

How do I get the current state of a state machine?
--------------------------------------------------

Don't do that.

One major reason for having a state machine is that you want the callers of the
state machine to just provide the appropriate input to the machine at the
appropriate time, and *not have to check themselves* what state the machine is
in. So if you are tempted to write some code like this:

.. code-block:: python

if connection_state_machine.state == "CONNECTED":
connection_state_machine.send_message()
else:
print("not connected")

Instead, just make your calling code do this:

.. code-block:: python

connection_state_machine.send_message()

and then change your state machine to look like this:

.. code-block:: python

@_machine.state()
def connected(self):
"connected"
@_machine.state()
def not_connected(self):
"not connected"
@_machine.input()
def send_message(self):
"send a message"
@_machine.output()
def _actually_send_message(self):
self._transport.send(b"message")
@_machine.output()
def _report_sending_failure(self):
print("not connected")
connected.upon(send_message, enter=connected, [_actually_send_message])
not_connected.upon(send_message, enter=not_connected, [_report_sending_failure])

so that the responsibility for knowing which state the state machine is in
remains within the state machine itself.

Input for Inputs and Output for Outputs
---------------------------------------

Quite often you want to be able to pass parameters to your methods, as well as
inspecting their results. For example, when you brew the coffee, you might
expect a cup of coffee to result, and you would like to see what kind of coffee
it is. And if you were to put delicious hand-roasted small-batch artisanal
beans into the machine, you would expect a *better* cup of coffee than if you
were to use mass-produced beans. You would do this in plain old Python by
adding a parameter, so that's how you do it in Automat as well.

.. code-block:: python

@_machine.input()
def put_in_beans(self, beans):
"The user put in some beans."

However, one important difference here is that *we can't add any
implementation code to the input method*. Inputs are purely a declaration of
the interface; the behavior must all come from outputs. Therefore, the change
in the state of the coffee machine must be represented as an output. We can
add an output method like this:

.. code-block:: python

@_machine.output()
def _save_beans(self, beans):
"The beans are now in the machine; save them."
self._beans = beans

and then connect it to the ``put_in_beans`` by changing the transition from
``dont_have_beans`` to ``have_beans`` like so:

.. code-block:: python

dont_have_beans.upon(put_in_beans, enter=have_beans,
outputs=[_save_beans])

Now, when you call:

.. code-block:: python

coffee_machine.put_in_beans("real good beans")

the machine will remember the beans for later.

So how do we get the beans back out again? One of our outputs needs to have a
return value. It would make sense if our ``brew_button`` method returned the cup
of coffee that it made, so we should add an output. So, in addition to heating
the heating element, let's add a return value that describes the coffee. First
a new output:

.. code-block:: python

@_machine.output()
def _describe_coffee(self):
return "A cup of coffee made with {}.".format(self._beans)

Note that we don't need to check first whether ``self._beans`` exists or not,
because we can only reach this output method if the state machine says we've
gone through a set of states that sets this attribute.

Now, we need to hook up ``_describe_coffee`` to the process of brewing, so change
the brewing transition to:

.. code-block:: python

have_beans.upon(brew_button, enter=dont_have_beans,
outputs=[_heat_the_heating_element,
_describe_coffee])

Now, we can call it:

.. code-block:: python

>>> coffee_machine.brew_button()
[None, 'A cup of coffee made with real good beans.']

Except... wait a second, what's that ``None`` doing there?

Since every input can produce multiple outputs, in automat, the default return
value from every input invocation is a ``list``. In this case, we have both
``_heat_the_heating_element`` and ``_describe_coffee`` outputs, so we're seeing
both of their return values. However, this can be customized, with the
``collector`` argument to ``upon``\ ; the ``collector`` is a callable which takes an
iterable of all the outputs' return values and "collects" a single return value
to return to the caller of the state machine.

In this case, we only care about the last output, so we can adjust the call to
``upon`` like this:

.. code-block:: python

have_beans.upon(brew_button, enter=dont_have_beans,
outputs=[_heat_the_heating_element,
_describe_coffee],
collector=lambda iterable: list(iterable)[-1]
)

And now, we'll get just the return value we want:

.. code-block:: python

>>> coffee_machine.brew_button()
'A cup of coffee made with real good beans.'

If I can't get the state of the state machine, how can I save it to (a database, an API response, a file on disk...)
--------------------------------------------------------------------------------------------------------------------

There are APIs for serializing the state machine.

First, you have to decide on a persistent representation of each state, via the
``serialized=`` argument to the ``MethodicalMachine.state()`` decorator.

Let's take this very simple "light switch" state machine, which can be on or
off, and flipped to reverse its state:

.. code-block:: python

class LightSwitch(object):
_machine = MethodicalMachine()
@_machine.state(serialized="on")
def on_state(self):
"the switch is on"
@_machine.state(serialized="off", initial=True)
def off_state(self):
"the switch is off"
@_machine.input()
def flip(self):
"flip the switch"
on_state.upon(flip, enter=off_state, outputs=[])
off_state.upon(flip, enter=on_state, outputs=[])

In this case, we've chosen a serialized representation for each state via the
``serialized`` argument. The on state is represented by the string ``"on"``\ , and
the off state is represented by the string ``"off"``.

Now, let's just add an input that lets us tell if the switch is on or not.

.. code-block:: python

@_machine.input()
def query_power(self):
"return True if powered, False otherwise"
@_machine.output()
def _is_powered(self):
return True
@_machine.output()
def _not_powered(self):
return False
on_state.upon(query_power, enter=on_state, outputs=[_is_powered],
collector=next)
off_state.upon(query_power, enter=off_state, outputs=[_not_powered],
collector=next)

To save the state, we have the ``MethodicalMachine.serializer()`` method. A
method decorated with ``@serializer()`` gets an extra argument injected at the
beginning of its argument list: the serialized identifier for the state. In
this case, either ``"on"`` or ``"off"``. Since state machine output methods can
also affect other state on the object, a serializer method is expected to
return *all* relevant state for serialization.

For our simple light switch, such a method might look like this:

.. code-block:: python

@_machine.serializer()
def save(self, state):
return {"is-it-on": state}

Serializers can be public methods, and they can return whatever you like. If
necessary, you can have different serializers - just multiple methods decorated
with ``@_machine.serializer()`` - for different formats; return one data-structure
for JSON, one for XML, one for a database row, and so on.

When it comes time to unserialize, though, you generally want a private method,
because an unserializer has to take a not-fully-initialized instance and
populate it with state. It is expected to *return* the serialized machine
state token that was passed to the serializer, but it can take whatever
arguments you like. Of course, in order to return that, it probably has to
take it somewhere in its arguments, so it will generally take whatever a paired
serializer has returned as an argument.

So our unserializer would look like this:

.. code-block:: python

@_machine.unserializer()
def _restore(self, blob):
return blob["is-it-on"]

Generally you will want a classmethod deserialization constructor which you
write yourself to call this, so that you know how to create an instance of your
own object, like so:

.. code-block:: python

@classmethod
def from_blob(cls, blob):
self = cls()
self._restore(blob)
return self

Saving and loading our ``LightSwitch`` along with its state-machine state can now
be accomplished as follows:

.. code-block:: python

>>> switch1 = LightSwitch()
>>> switch1.query_power()
False
>>> switch1.flip()
[]
>>> switch1.query_power()
True
>>> blob = switch1.save()
>>> switch2 = LightSwitch.from_blob(blob)
>>> switch2.query_power()
True

More comprehensive (tested, working) examples are present in ``docs/examples``.

Go forth and machine all the state!



+ 3
- 0
venv/lib/python3.7/site-packages/Automat-0.8.0.dist-info/entry_points.txt View File

@@ -0,0 +1,3 @@
[console_scripts]
automat-visualize = automat._visualize:tool


+ 1
- 0
venv/lib/python3.7/site-packages/Automat-0.8.0.dist-info/top_level.txt View File

@@ -0,0 +1 @@
automat

+ 27
- 0
venv/lib/python3.7/site-packages/Django-2.2.6.dist-info/LICENSE View File

@@ -0,0 +1,27 @@
Copyright (c) Django Software Foundation and individual contributors.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

3. Neither the name of Django nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 4212
- 0
venv/lib/python3.7/site-packages/Django-2.2.6.dist-info/RECORD
File diff suppressed because it is too large
View File


+ 3
- 0
venv/lib/python3.7/site-packages/Django-2.2.6.dist-info/entry_points.txt View File

@@ -0,0 +1,3 @@
[console_scripts]
django-admin = django.core.management:execute_from_command_line


+ 20
- 0
venv/lib/python3.7/site-packages/OpenSSL/__init__.py View File

@@ -0,0 +1,20 @@
# Copyright (C) AB Strakt
# See LICENSE for details.

"""
pyOpenSSL - A simple wrapper around the OpenSSL library
"""

from OpenSSL import crypto, SSL
from OpenSSL.version import (
__author__, __copyright__, __email__, __license__, __summary__, __title__,
__uri__, __version__,
)


__all__ = [
"SSL", "crypto",

"__author__", "__copyright__", "__email__", "__license__", "__summary__",
"__title__", "__uri__", "__version__",
]

+ 42
- 0
venv/lib/python3.7/site-packages/OpenSSL/debug.py View File

@@ -0,0 +1,42 @@
from __future__ import print_function

import ssl
import sys

import OpenSSL.SSL
import cffi
import cryptography

from . import version


_env_info = u"""\
pyOpenSSL: {pyopenssl}
cryptography: {cryptography}
cffi: {cffi}
cryptography's compiled against OpenSSL: {crypto_openssl_compile}
cryptography's linked OpenSSL: {crypto_openssl_link}
Pythons's OpenSSL: {python_openssl}
Python executable: {python}
Python version: {python_version}
Platform: {platform}
sys.path: {sys_path}""".format(
pyopenssl=version.__version__,
crypto_openssl_compile=OpenSSL._util.ffi.string(
OpenSSL._util.lib.OPENSSL_VERSION_TEXT,
).decode("ascii"),
crypto_openssl_link=OpenSSL.SSL.SSLeay_version(
OpenSSL.SSL.SSLEAY_VERSION
).decode("ascii"),
python_openssl=getattr(ssl, "OPENSSL_VERSION", "n/a"),
cryptography=cryptography.__version__,
cffi=cffi.__version__,
python=sys.executable,
python_version=sys.version,
platform=sys.platform,
sys_path=sys.path,
)


if __name__ == "__main__":
print(_env_info)

+ 22
- 0
venv/lib/python3.7/site-packages/OpenSSL/version.py View File

@@ -0,0 +1,22 @@
# Copyright (C) AB Strakt
# Copyright (C) Jean-Paul Calderone
# See LICENSE for details.

"""
pyOpenSSL - A simple wrapper around the OpenSSL library
"""

__all__ = [
"__author__", "__copyright__", "__email__", "__license__", "__summary__",
"__title__", "__uri__", "__version__",
]

__version__ = "19.1.0"

__title__ = "pyOpenSSL"
__uri__ = "https://pyopenssl.org/"
__summary__ = "Python wrapper module around the OpenSSL library"
__author__ = "The pyOpenSSL developers"
__email__ = "cryptography-dev@python.org"
__license__ = "Apache License, Version 2.0"
__copyright__ = "Copyright 2001-2017 {0}".format(__author__)

+ 322
- 0
venv/lib/python3.7/site-packages/PyHamcrest-1.9.0.dist-info/DESCRIPTION.rst View File

@@ -0,0 +1,322 @@
PyHamcrest
==========

| |docs| |travis| |coveralls| |landscape| |scrutinizer| |codeclimate|
| |version| |downloads| |wheel| |supported-versions| |supported-implementations|

.. |docs| image:: https://readthedocs.org/projects/pyhamcrest/badge/?style=flat
:target: https://pyhamcrest.readthedocs.org/
:alt: Documentation Status

.. |travis| image:: http://img.shields.io/travis/hamcrest/PyHamcrest/master.png?style=flat
:alt: Travis-CI Build Status
:target: https://travis-ci.org/hamcrest/PyHamcrest

.. |appveyor| image:: https://ci.appveyor.com/api/projects/status/github/hamcrest/PyHamcrest?branch=master
:alt: AppVeyor Build Status
:target: https://ci.appveyor.com/project/hamcrest/PyHamcrest

.. |coveralls| image:: http://img.shields.io/coveralls/hamcrest/PyHamcrest/master.png?style=flat
:alt: Coverage Status
:target: https://coveralls.io/r/hamcrest/PyHamcrest

.. |landscape| image:: https://landscape.io/github/hamcrest/PyHamcrest/master/landscape.svg?style=flat
:target: https://landscape.io/github/hamcrest/PyHamcrest/master
:alt: Code Quality Status

.. |codeclimate| image:: https://codeclimate.com/github/hamcrest/PyHamcrest/badges/gpa.svg
:target: https://codeclimate.com/github/hamcrest/PyHamcrest
:alt: Code Climate

.. |version| image:: http://img.shields.io/pypi/v/PyHamcrest.png?style=flat
:alt: PyPI Package latest release
:target: https://pypi.python.org/pypi/PyHamcrest

.. |downloads| image:: http://img.shields.io/pypi/dm/PyHamcrest.png?style=flat
:alt: PyPI Package monthly downloads
:target: https://pypi.python.org/pypi/PyHamcrest

.. |wheel| image:: https://pypip.in/wheel/PyHamcrest/badge.png?style=flat
:alt: PyPI Wheel
:target: https://pypi.python.org/pypi/PyHamcrest

.. |supported-versions| image:: https://pypip.in/py_versions/PyHamcrest/badge.png?style=flat
:alt: Supported versions
:target: https://pypi.python.org/pypi/PyHamcrest

.. |supported-implementations| image:: https://pypip.in/implementation/PyHamcrest/badge.png?style=flat
:alt: Supported imlementations
:target: https://pypi.python.org/pypi/PyHamcrest

.. |scrutinizer| image:: https://img.shields.io/scrutinizer/g/hamcrest/PyHamcrest/master.png?style=flat
:alt: Scrtinizer Status
:target: https://scrutinizer-ci.com/g/hamcrest/PyHamcrest/


Introduction
============

PyHamcrest is a framework for writing matcher objects, allowing you to
declaratively define "match" rules. There are a number of situations where
matchers are invaluable, such as UI validation, or data filtering, but it is in
the area of writing flexible tests that matchers are most commonly used. This
tutorial shows you how to use PyHamcrest for unit testing.

When writing tests it is sometimes difficult to get the balance right between
overspecifying the test (and making it brittle to changes), and not specifying
enough (making the test less valuable since it continues to pass even when the
thing being tested is broken). Having a tool that allows you to pick out
precisely the aspect under test and describe the values it should have, to a
controlled level of precision, helps greatly in writing tests that are "just
right." Such tests fail when the behavior of the aspect under test deviates
from the expected behavior, yet continue to pass when minor, unrelated changes
to the behaviour are made.

Installation
============

Hamcrest can be installed using the usual Python packaging tools. It depends on
distribute, but as long as you have a network connection when you install, the
installation process will take care of that for you.

My first PyHamcrest test
========================

We'll start by writing a very simple PyUnit test, but instead of using PyUnit's
``assertEqual`` method, we'll use PyHamcrest's ``assert_that`` construct and
the standard set of matchers:

.. code:: python

from hamcrest import *
import unittest

class BiscuitTest(unittest.TestCase):
def testEquals(self):
theBiscuit = Biscuit('Ginger')
myBiscuit = Biscuit('Ginger')
assert_that(theBiscuit, equal_to(myBiscuit))

if __name__ == '__main__':
unittest.main()

The ``assert_that`` function is a stylized sentence for making a test
assertion. In this example, the subject of the assertion is the object
``theBiscuit``, which is the first method parameter. The second method
parameter is a matcher for ``Biscuit`` objects, here a matcher that checks one
object is equal to another using the Python ``==`` operator. The test passes
since the ``Biscuit`` class defines an ``__eq__`` method.

If you have more than one assertion in your test you can include an identifier
for the tested value in the assertion:

.. code:: python

assert_that(theBiscuit.getChocolateChipCount(), equal_to(10), 'chocolate chips')
assert_that(theBiscuit.getHazelnutCount(), equal_to(3), 'hazelnuts')

As a convenience, assert_that can also be used to verify a boolean condition:

.. code:: python

assert_that(theBiscuit.isCooked(), 'cooked')

This is equivalent to the ``assert_`` method of unittest.TestCase, but because
it's a standalone function, it offers greater flexibility in test writing.


Predefined matchers
===================

PyHamcrest comes with a library of useful matchers:

* Object

* ``equal_to`` - match equal object
* ``has_length`` - match ``len()``
* ``has_property`` - match value of property with given name
* ``has_properties`` - match an object that has all of the given properties.
* ``has_string`` - match ``str()``
* ``instance_of`` - match object type
* ``none``, ``not_none`` - match ``None``, or not ``None``
* ``same_instance`` - match same object
* ``calling, raises`` - wrap a method call and assert that it raises an exception

* Number

* ``close_to`` - match number close to a given value
* ``greater_than``, ``greater_than_or_equal_to``, ``less_than``,
``less_than_or_equal_to`` - match numeric ordering

* Text

* ``contains_string`` - match part of a string
* ``ends_with`` - match the end of a string
* ``equal_to_ignoring_case`` - match the complete string but ignore case
* ``equal_to_ignoring_whitespace`` - match the complete string but ignore extra whitespace
* ``matches_regexp`` - match a regular expression in a string
* ``starts_with`` - match the beginning of a string
* ``string_contains_in_order`` - match parts of a string, in relative order

* Logical

* ``all_of`` - ``and`` together all matchers
* ``any_of`` - ``or`` together all matchers
* ``anything`` - match anything, useful in composite matchers when you don't care about a particular value
* ``is_not`` - negate the matcher

* Sequence

* ``contains`` - exactly match the entire sequence
* ``contains_inanyorder`` - match the entire sequence, but in any order
* ``has_item`` - match if given item appears in the sequence
* ``has_items`` - match if all given items appear in the sequence, in any order
* ``is_in`` - match if item appears in the given sequence
* ``only_contains`` - match if sequence's items appear in given list
* ``empty`` - match if the sequence is empty

* Dictionary

* ``has_entries`` - match dictionary with list of key-value pairs
* ``has_entry`` - match dictionary containing a key-value pair
* ``has_key`` - match dictionary with a key
* ``has_value`` - match dictionary with a value

* Decorator

* ``calling`` - wrap a callable in a deffered object, for subsequent matching on calling behaviour
* ``raises`` - Ensure that a deferred callable raises as expected
* ``described_as`` - give the matcher a custom failure description
* ``is_`` - decorator to improve readability - see `Syntactic sugar` below

The arguments for many of these matchers accept not just a matching value, but
another matcher, so matchers can be composed for greater flexibility. For
example, ``only_contains(less_than(5))`` will match any sequence where every
item is less than 5.


Syntactic sugar
===============

PyHamcrest strives to make your tests as readable as possible. For example, the
``is_`` matcher is a wrapper that doesn't add any extra behavior to the
underlying matcher. The following assertions are all equivalent:

.. code:: python

assert_that(theBiscuit, equal_to(myBiscuit))
assert_that(theBiscuit, is_(equal_to(myBiscuit)))
assert_that(theBiscuit, is_(myBiscuit))

The last form is allowed since ``is_(value)`` wraps most non-matcher arguments
with ``equal_to``. But if the argument is a type, it is wrapped with
``instance_of``, so the following are also equivalent:

.. code:: python

assert_that(theBiscuit, instance_of(Biscuit))
assert_that(theBiscuit, is_(instance_of(Biscuit)))
assert_that(theBiscuit, is_(Biscuit))

*Note that PyHamcrest's ``is_`` matcher is unrelated to Python's ``is``
operator. The matcher for object identity is ``same_instance``.*


Writing custom matchers
=======================

PyHamcrest comes bundled with lots of useful matchers, but you'll probably find
that you need to create your own from time to time to fit your testing needs.
This commonly occurs when you find a fragment of code that tests the same set
of properties over and over again (and in different tests), and you want to
bundle the fragment into a single assertion. By writing your own matcher you'll
eliminate code duplication and make your tests more readable!

Let's write our own matcher for testing if a calendar date falls on a Saturday.
This is the test we want to write:

.. code:: python

def testDateIsOnASaturday(self):
d = datetime.date(2008, 04, 26)
assert_that(d, is_(on_a_saturday()))

And here's the implementation:

.. code:: python

from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.helpers.hasmethod import hasmethod

class IsGivenDayOfWeek(BaseMatcher):

def __init__(self, day):
self.day = day # Monday is 0, Sunday is 6

def _matches(self, item):
if not hasmethod(item, 'weekday'):
return False
return item.weekday() == self.day

def describe_to(self, description):
day_as_string = ['Monday', 'Tuesday', 'Wednesday', 'Thursday',
'Friday', 'Saturday', 'Sunday']
description.append_text('calendar date falling on ') \
.append_text(day_as_string[self.day])

def on_a_saturday():
return IsGivenDayOfWeek(5)

For our Matcher implementation we implement the ``_matches`` method - which
calls the ``weekday`` method after confirming that the argument (which may not
be a date) has such a method - and the ``describe_to`` method - which is used
to produce a failure message when a test fails. Here's an example of how the
failure message looks:

.. code:: python

assert_that(datetime.date(2008, 04, 06), is_(on_a_saturday()))

fails with the message::

AssertionError:
Expected: is calendar date falling on Saturday
got: <2008-04-06>

Let's say this matcher is saved in a module named ``isgivendayofweek``. We
could use it in our test by importing the factory function ``on_a_saturday``:

.. code:: python

from hamcrest import *
import unittest
from isgivendayofweek import on_a_saturday

class DateTest(unittest.TestCase):
def testDateIsOnASaturday(self):
d = datetime.date(2008, 04, 26)
assert_that(d, is_(on_a_saturday()))

if __name__ == '__main__':
unittest.main()

Even though the ``on_a_saturday`` function creates a new matcher each time it
is called, you should not assume this is the only usage pattern for your
matcher. Therefore you should make sure your matcher is stateless, so a single
instance can be reused between matches.


More resources
==============

* Documentation_
* Package_
* Sources_
* Hamcrest_

.. _Documentation: http://readthedocs.org/docs/pyhamcrest/en/V1.8.2/
.. _Package: http://pypi.python.org/pypi/PyHamcrest
.. _Sources: https://github.com/hamcrest/PyHamcrest
.. _Hamcrest: http://hamcrest.org



+ 353
- 0
venv/lib/python3.7/site-packages/PyHamcrest-1.9.0.dist-info/METADATA View File

@@ -0,0 +1,353 @@
Metadata-Version: 2.0
Name: PyHamcrest
Version: 1.9.0
Summary: Hamcrest framework for matcher objects
Home-page: https://github.com/hamcrest/PyHamcrest
Author: Chris Rose
Author-email: offline@offby1.net
License: New BSD
Download-URL: http://pypi.python.org/packages/source/P/PyHamcrest/PyHamcrest-1.9.0.tar.gz
Keywords: hamcrest matchers pyunit unit test testing unittest unittesting
Platform: All
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD 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.4
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: Jython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Software Development
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Software Development :: Testing
Provides: hamcrest
Requires-Dist: setuptools
Requires-Dist: six

PyHamcrest
==========

| |docs| |travis| |coveralls| |landscape| |scrutinizer| |codeclimate|
| |version| |downloads| |wheel| |supported-versions| |supported-implementations|

.. |docs| image:: https://readthedocs.org/projects/pyhamcrest/badge/?style=flat
:target: https://pyhamcrest.readthedocs.org/
:alt: Documentation Status

.. |travis| image:: http://img.shields.io/travis/hamcrest/PyHamcrest/master.png?style=flat
:alt: Travis-CI Build Status
:target: https://travis-ci.org/hamcrest/PyHamcrest

.. |appveyor| image:: https://ci.appveyor.com/api/projects/status/github/hamcrest/PyHamcrest?branch=master
:alt: AppVeyor Build Status
:target: https://ci.appveyor.com/project/hamcrest/PyHamcrest

.. |coveralls| image:: http://img.shields.io/coveralls/hamcrest/PyHamcrest/master.png?style=flat
:alt: Coverage Status
:target: https://coveralls.io/r/hamcrest/PyHamcrest

.. |landscape| image:: https://landscape.io/github/hamcrest/PyHamcrest/master/landscape.svg?style=flat
:target: https://landscape.io/github/hamcrest/PyHamcrest/master
:alt: Code Quality Status

.. |codeclimate| image:: https://codeclimate.com/github/hamcrest/PyHamcrest/badges/gpa.svg
:target: https://codeclimate.com/github/hamcrest/PyHamcrest
:alt: Code Climate

.. |version| image:: http://img.shields.io/pypi/v/PyHamcrest.png?style=flat
:alt: PyPI Package latest release
:target: https://pypi.python.org/pypi/PyHamcrest

.. |downloads| image:: http://img.shields.io/pypi/dm/PyHamcrest.png?style=flat
:alt: PyPI Package monthly downloads
:target: https://pypi.python.org/pypi/PyHamcrest

.. |wheel| image:: https://pypip.in/wheel/PyHamcrest/badge.png?style=flat
:alt: PyPI Wheel
:target: https://pypi.python.org/pypi/PyHamcrest

.. |supported-versions| image:: https://pypip.in/py_versions/PyHamcrest/badge.png?style=flat
:alt: Supported versions
:target: https://pypi.python.org/pypi/PyHamcrest

.. |supported-implementations| image:: https://pypip.in/implementation/PyHamcrest/badge.png?style=flat
:alt: Supported imlementations
:target: https://pypi.python.org/pypi/PyHamcrest

.. |scrutinizer| image:: https://img.shields.io/scrutinizer/g/hamcrest/PyHamcrest/master.png?style=flat
:alt: Scrtinizer Status
:target: https://scrutinizer-ci.com/g/hamcrest/PyHamcrest/


Introduction
============

PyHamcrest is a framework for writing matcher objects, allowing you to
declaratively define "match" rules. There are a number of situations where
matchers are invaluable, such as UI validation, or data filtering, but it is in
the area of writing flexible tests that matchers are most commonly used. This
tutorial shows you how to use PyHamcrest for unit testing.

When writing tests it is sometimes difficult to get the balance right between
overspecifying the test (and making it brittle to changes), and not specifying
enough (making the test less valuable since it continues to pass even when the
thing being tested is broken). Having a tool that allows you to pick out
precisely the aspect under test and describe the values it should have, to a
controlled level of precision, helps greatly in writing tests that are "just
right." Such tests fail when the behavior of the aspect under test deviates
from the expected behavior, yet continue to pass when minor, unrelated changes
to the behaviour are made.

Installation
============

Hamcrest can be installed using the usual Python packaging tools. It depends on
distribute, but as long as you have a network connection when you install, the
installation process will take care of that for you.

My first PyHamcrest test
========================

We'll start by writing a very simple PyUnit test, but instead of using PyUnit's
``assertEqual`` method, we'll use PyHamcrest's ``assert_that`` construct and
the standard set of matchers:

.. code:: python

from hamcrest import *
import unittest

class BiscuitTest(unittest.TestCase):
def testEquals(self):
theBiscuit = Biscuit('Ginger')
myBiscuit = Biscuit('Ginger')
assert_that(theBiscuit, equal_to(myBiscuit))

if __name__ == '__main__':
unittest.main()

The ``assert_that`` function is a stylized sentence for making a test
assertion. In this example, the subject of the assertion is the object
``theBiscuit``, which is the first method parameter. The second method
parameter is a matcher for ``Biscuit`` objects, here a matcher that checks one
object is equal to another using the Python ``==`` operator. The test passes
since the ``Biscuit`` class defines an ``__eq__`` method.

If you have more than one assertion in your test you can include an identifier
for the tested value in the assertion:

.. code:: python

assert_that(theBiscuit.getChocolateChipCount(), equal_to(10), 'chocolate chips')
assert_that(theBiscuit.getHazelnutCount(), equal_to(3), 'hazelnuts')

As a convenience, assert_that can also be used to verify a boolean condition:

.. code:: python

assert_that(theBiscuit.isCooked(), 'cooked')

This is equivalent to the ``assert_`` method of unittest.TestCase, but because
it's a standalone function, it offers greater flexibility in test writing.


Predefined matchers
===================

PyHamcrest comes with a library of useful matchers:

* Object

* ``equal_to`` - match equal object
* ``has_length`` - match ``len()``
* ``has_property`` - match value of property with given name
* ``has_properties`` - match an object that has all of the given properties.
* ``has_string`` - match ``str()``
* ``instance_of`` - match object type
* ``none``, ``not_none`` - match ``None``, or not ``None``
* ``same_instance`` - match same object
* ``calling, raises`` - wrap a method call and assert that it raises an exception

* Number

* ``close_to`` - match number close to a given value
* ``greater_than``, ``greater_than_or_equal_to``, ``less_than``,
``less_than_or_equal_to`` - match numeric ordering

* Text

* ``contains_string`` - match part of a string
* ``ends_with`` - match the end of a string
* ``equal_to_ignoring_case`` - match the complete string but ignore case
* ``equal_to_ignoring_whitespace`` - match the complete string but ignore extra whitespace
* ``matches_regexp`` - match a regular expression in a string
* ``starts_with`` - match the beginning of a string
* ``string_contains_in_order`` - match parts of a string, in relative order

* Logical

* ``all_of`` - ``and`` together all matchers
* ``any_of`` - ``or`` together all matchers
* ``anything`` - match anything, useful in composite matchers when you don't care about a particular value
* ``is_not`` - negate the matcher

* Sequence

* ``contains`` - exactly match the entire sequence
* ``contains_inanyorder`` - match the entire sequence, but in any order
* ``has_item`` - match if given item appears in the sequence
* ``has_items`` - match if all given items appear in the sequence, in any order
* ``is_in`` - match if item appears in the given sequence
* ``only_contains`` - match if sequence's items appear in given list
* ``empty`` - match if the sequence is empty

* Dictionary

* ``has_entries`` - match dictionary with list of key-value pairs
* ``has_entry`` - match dictionary containing a key-value pair
* ``has_key`` - match dictionary with a key
* ``has_value`` - match dictionary with a value

* Decorator

* ``calling`` - wrap a callable in a deffered object, for subsequent matching on calling behaviour
* ``raises`` - Ensure that a deferred callable raises as expected
* ``described_as`` - give the matcher a custom failure description
* ``is_`` - decorator to improve readability - see `Syntactic sugar` below

The arguments for many of these matchers accept not just a matching value, but
another matcher, so matchers can be composed for greater flexibility. For
example, ``only_contains(less_than(5))`` will match any sequence where every
item is less than 5.


Syntactic sugar
===============

PyHamcrest strives to make your tests as readable as possible. For example, the
``is_`` matcher is a wrapper that doesn't add any extra behavior to the
underlying matcher. The following assertions are all equivalent:

.. code:: python

assert_that(theBiscuit, equal_to(myBiscuit))
assert_that(theBiscuit, is_(equal_to(myBiscuit)))
assert_that(theBiscuit, is_(myBiscuit))

The last form is allowed since ``is_(value)`` wraps most non-matcher arguments
with ``equal_to``. But if the argument is a type, it is wrapped with
``instance_of``, so the following are also equivalent:

.. code:: python

assert_that(theBiscuit, instance_of(Biscuit))
assert_that(theBiscuit, is_(instance_of(Biscuit)))
assert_that(theBiscuit, is_(Biscuit))

*Note that PyHamcrest's ``is_`` matcher is unrelated to Python's ``is``
operator. The matcher for object identity is ``same_instance``.*


Writing custom matchers
=======================

PyHamcrest comes bundled with lots of useful matchers, but you'll probably find
that you need to create your own from time to time to fit your testing needs.
This commonly occurs when you find a fragment of code that tests the same set
of properties over and over again (and in different tests), and you want to
bundle the fragment into a single assertion. By writing your own matcher you'll
eliminate code duplication and make your tests more readable!

Let's write our own matcher for testing if a calendar date falls on a Saturday.
This is the test we want to write:

.. code:: python

def testDateIsOnASaturday(self):
d = datetime.date(2008, 04, 26)
assert_that(d, is_(on_a_saturday()))

And here's the implementation:

.. code:: python

from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.helpers.hasmethod import hasmethod

class IsGivenDayOfWeek(BaseMatcher):

def __init__(self, day):
self.day = day # Monday is 0, Sunday is 6

def _matches(self, item):
if not hasmethod(item, 'weekday'):
return False
return item.weekday() == self.day

def describe_to(self, description):
day_as_string = ['Monday', 'Tuesday', 'Wednesday', 'Thursday',
'Friday', 'Saturday', 'Sunday']
description.append_text('calendar date falling on ') \
.append_text(day_as_string[self.day])

def on_a_saturday():
return IsGivenDayOfWeek(5)

For our Matcher implementation we implement the ``_matches`` method - which
calls the ``weekday`` method after confirming that the argument (which may not
be a date) has such a method - and the ``describe_to`` method - which is used
to produce a failure message when a test fails. Here's an example of how the
failure message looks:

.. code:: python

assert_that(datetime.date(2008, 04, 06), is_(on_a_saturday()))

fails with the message::

AssertionError:
Expected: is calendar date falling on Saturday
got: <2008-04-06>

Let's say this matcher is saved in a module named ``isgivendayofweek``. We
could use it in our test by importing the factory function ``on_a_saturday``:

.. code:: python

from hamcrest import *
import unittest
from isgivendayofweek import on_a_saturday

class DateTest(unittest.TestCase):
def testDateIsOnASaturday(self):
d = datetime.date(2008, 04, 26)
assert_that(d, is_(on_a_saturday()))

if __name__ == '__main__':
unittest.main()

Even though the ``on_a_saturday`` function creates a new matcher each time it
is called, you should not assume this is the only usage pattern for your
matcher. Therefore you should make sure your matcher is stateless, so a single
instance can be reused between matches.


More resources
==============

* Documentation_
* Package_
* Sources_
* Hamcrest_

.. _Documentation: http://readthedocs.org/docs/pyhamcrest/en/V1.8.2/
.. _Package: http://pypi.python.org/pypi/PyHamcrest
.. _Sources: https://github.com/hamcrest/PyHamcrest
.. _Hamcrest: http://hamcrest.org



+ 120
- 0
venv/lib/python3.7/site-packages/PyHamcrest-1.9.0.dist-info/RECORD View File

@@ -0,0 +1,120 @@
hamcrest/__init__.py,sha256=Uo0mxeePyXP9_yIzBBvKqIL6tzEHqBwBO1eSHfAKies,230
hamcrest/core/__init__.py,sha256=nDkYm1E1P7XpHmR8EHu17eahlmC6uYix4HurTyJjhlE,230
hamcrest/core/assert_that.py,sha256=mPdTQQVsjUliK3xp8l_Vn3YmMzg_h5rYhWJk2mstMc0,2428
hamcrest/core/base_description.py,sha256=auvrelro2vGh_A05TQxwbaBJStvfHiFqm0TL56luxEU,2841
hamcrest/core/base_matcher.py,sha256=eRhLv7zFBJGaz68vEsDlvKbrWwU8GRDfZc7pWBNcxwI,1193
hamcrest/core/compat.py,sha256=wUi1u_nIhgUA3kFGJDZLQ2D_cRw79E1SxPDMaI4mzG0,642
hamcrest/core/description.py,sha256=gbVS-ejZJ783o-WEA66bXnXc9DH5cOlQXg0FlzoVGro,1729
hamcrest/core/matcher.py,sha256=BG6e8bIJvwFI0qkaSkt_SOuuLI0VidvoX8GQLadYssU,1851
hamcrest/core/selfdescribing.py,sha256=RzwqHRGg00AJYweGiP8JzSxoHFdBo0Q7m5axYfutfG8,574
hamcrest/core/selfdescribingvalue.py,sha256=OpGLOjdPA9FSgmLZzmkfYrDvpG261TDDiM56muROFqQ,834
hamcrest/core/string_description.py,sha256=Jp-SbuY8LAwPucL4NMrwWqRhkg6CMwYE-pH0ZDMUq8A,908
hamcrest/core/core/__init__.py,sha256=7q_pNO9cmtV3BEixiGcueNdbxRxlKEFZ1RSO-5GP58E,770
hamcrest/core/core/allof.py,sha256=x2ea18Z5cioRybs1heTd3E8zYtpFbuBJg3vIU3vl9k0,1487
hamcrest/core/core/anyof.py,sha256=8j2KAsaToXbv8CA5hed4bqPR3hscODIiaFhAlAyJ2Vs,1097
hamcrest/core/core/described_as.py,sha256=kyy_qRpoebWB1bS2ReAkNDt-79iXu6HqHxOG0GT7PtQ,1623
hamcrest/core/core/is_.py,sha256=C7UCASfr4AIlaaMZnT5d34OthAZQ3rYv8OhszQjz-Eg,2547
hamcrest/core/core/isanything.py,sha256=D2QO5dbDhwlVRGLFrnxOSijTyeKN2iWLRwjpvnumkvg,798
hamcrest/core/core/isequal.py,sha256=TAwF_lWIjVokPruXN8IGS6ajzPGlThanTLPdhktKwRQ,893
hamcrest/core/core/isinstanceof.py,sha256=dnt8YKLhYwGZvDkJ0OTdLd1PN9cB9ZWCg5k8kdnEuqI,1352
hamcrest/core/core/isnone.py,sha256=51ueQKBgg0RzWVLzjFOyt6K0ejk2EbXUlUX90ORPm80,557
hamcrest/core/core/isnot.py,sha256=_z_ynAVUXEUGWoiRlynFa_yaCVh9cK9LIOznDfKVZeo,1533
hamcrest/core/core/issame.py,sha256=8FvAjud4HTuyz7O-XoJbzLtKhChCr1_5JmzMYMeQt1s,1261
hamcrest/core/core/raises.py,sha256=BZXtMlQiEqEjQMYT76HUiuQNRjTECIUmL82_FKYhAvs,3610
hamcrest/core/helpers/__init__.py,sha256=mPsycYI18LoGawOo9BfETa7yKtnM-fDjFOr43BIevUg,146
hamcrest/core/helpers/hasmethod.py,sha256=LPh_WDRuyKYII3G3fX_x2Ql-ECuPJn4tK5eWMLbetLg,325
hamcrest/core/helpers/wrap_matcher.py,sha256=IQTtw98Pp1NXcVTy9boaNh6jayvawKHhX62R3ZwnVwQ,880
hamcrest/library/__init__.py,sha256=2atNiBCC2g3c-7jw53CltNgU4wEao1uRcheUPl1ML50,1014
hamcrest/library/collection/__init__.py,sha256=iJU6WCsf0R22m11fqMA9Ztb161AZAdrsKG-4Cj38lZ0,635
hamcrest/library/collection/is_empty.py,sha256=p3-B7DCmdbVzqiW3D1h3krdeqmu9B0mfYOaa6HehODg,913
hamcrest/library/collection/isdict_containing.py,sha256=6QxDtDp_Z2TK-6om8cHnJDh45YdmaNHAEy5n97rzf00,2056
hamcrest/library/collection/isdict_containingentries.py,sha256=xKtdFjrwLN32rUdRR4PBUSYa3yACa6jXsmlZv0D9YAU,5168
hamcrest/library/collection/isdict_containingkey.py,sha256=aiBpusjpZmkUEMZ_rUFZBB1GxIfsqluMjhXoWNScqZY,1535
hamcrest/library/collection/isdict_containingvalue.py,sha256=N7mHKgMnd7q6HsQekHH6DShNYbLiSXN9cpQgcdMIjlw,1565
hamcrest/library/collection/isin.py,sha256=bcVslW0fUq0pM_SrT9gdltTlNfeJkrVPZAlg6riV2Ys,774
hamcrest/library/collection/issequence_containing.py,sha256=ZwYMm2-Ul_JtvjcgdMjipYdz82yUbGmRNsdPAjO9RX0,3001
hamcrest/library/collection/issequence_containinginanyorder.py,sha256=Px_W2-_0XDOXiL2NTTMp16ZTZvBl4m5rXjlMoR4Ulmw,3613
hamcrest/library/collection/issequence_containinginorder.py,sha256=x7AT_kOCaPY0LmZw28ln8xLLHBtT-I3NneoCWzMJoYA,3219
hamcrest/library/collection/issequence_onlycontaining.py,sha256=Ia17P1HVgb43lZfdUEhmPyUUUWtGLix__fqXIQJTUiI,1626
hamcrest/library/integration/__init__.py,sha256=3aiupojVacPksKTXVhqRs9OwUDoUlUw-bjWItJnRg8Q,254
hamcrest/library/integration/match_equality.py,sha256=0BMth20YLTqjqTLT4qMVldAe2dQV3CJ2j3zLXDIGl9c,1192
hamcrest/library/number/__init__.py,sha256=J3UoFdR9UPq9zXSKe1a9qAlpjaVst8-pnaxsvbCPj78,335
hamcrest/library/number/iscloseto.py,sha256=2lQTw3Xvo5MW-aePxpWVUOwyV_ydXtH6cCAIAxeopk8,2259
hamcrest/library/number/ordering_comparison.py,sha256=8XxVSOzPK29D14h4wtBZYVYKZf6IcABaQEKihEuzlhI,1700
hamcrest/library/object/__init__.py,sha256=pxzCpybBHRaIg7RJUAw7R1Po0llw8QBbVv_R1TXNBhc,319
hamcrest/library/object/haslength.py,sha256=mpYVvrBZV548FwEeqlHWYofv9LPgChvnypZ4RhZDMp0,1681
hamcrest/library/object/hasproperty.py,sha256=9t8upZxjqSQp6IvGyTm4ftGvcpBeyk0dy36HgvlXZBg,5740
hamcrest/library/object/hasstring.py,sha256=_Ht1x-DwV4hk2fRuGo_KoayoLOIoWObKoA30u7HnABU,1250
hamcrest/library/text/__init__.py,sha256=3Uuy1lY2p0VEUy1SAIO6IZgDDgyx8ZsB98k-J2FA_R0,548
hamcrest/library/text/isequal_ignoring_case.py,sha256=VGkR3PNDOVE1MJT9H4a3SjR2SIYNzT80VoV6NEq3aqw,1257
hamcrest/library/text/isequal_ignoring_whitespace.py,sha256=NQzswc7fk5rOhcoHO4zbYSWqn-WQdQ7Hwf0FoDHAwBM,1667
hamcrest/library/text/stringcontains.py,sha256=JbkSxdFkpRrNYJfSUghboxe1jRLfHAJvOn6PYvMx7fQ,953
hamcrest/library/text/stringcontainsinorder.py,sha256=B3qG7TG24_WyVPGJER2iqi7fzOMZN0UsBRJPtWutBkc,1705
hamcrest/library/text/stringendswith.py,sha256=JjukJWSVWgURvTstrbCGCQdQzY0PMWLul__UlDh2NGA,980
hamcrest/library/text/stringmatches.py,sha256=AEBn8NI3q-YzRUdXiAfnw1Kmse-LLxJUluDAuy_D9nU,1151
hamcrest/library/text/stringstartswith.py,sha256=oOro8G3z8nAOUyOjHHkHhUvY-lt7XRTJzDr9dYxxons,1007
hamcrest/library/text/substringmatcher.py,sha256=lSPxE7pTpTJlUkMtd28WgsM1FFm56JVZixSvAldSZXk,695
PyHamcrest-1.9.0.dist-info/DESCRIPTION.rst,sha256=13XTDh2baR2aJ91v_lAOjEXD7Ydush_RHhk0Z3azfs8,11973
PyHamcrest-1.9.0.dist-info/METADATA,sha256=s0naXZHUZhft0MWcUeZVaZYlREKPOqHp3mUQrhUoC6s,13276
PyHamcrest-1.9.0.dist-info/metadata.json,sha256=Jqs-ZSW5kWSnfvxDsRMwSQH6TxEqSJjBJWiQk1G-c_A,1545
PyHamcrest-1.9.0.dist-info/pbr.json,sha256=jdAcCmfO0nnMs9-YKXuwDyKnxc4qGwyUxyGulF9Pam4,47
PyHamcrest-1.9.0.dist-info/RECORD,,
PyHamcrest-1.9.0.dist-info/top_level.txt,sha256=mRc0yPsPQSqFgWBmZBY33u-05Xtm5M4GEve4NjYdloQ,9
PyHamcrest-1.9.0.dist-info/WHEEL,sha256=AvR0WeTpDaxT645bl5FQxUK6NPsTls2ttpcGJg3j1Xg,110
PyHamcrest-1.9.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
hamcrest/core/core/__pycache__/issame.cpython-37.pyc,,
hamcrest/core/core/__pycache__/isinstanceof.cpython-37.pyc,,
hamcrest/core/core/__pycache__/raises.cpython-37.pyc,,
hamcrest/core/core/__pycache__/is_.cpython-37.pyc,,
hamcrest/core/core/__pycache__/isanything.cpython-37.pyc,,
hamcrest/core/core/__pycache__/isnone.cpython-37.pyc,,
hamcrest/core/core/__pycache__/isnot.cpython-37.pyc,,
hamcrest/core/core/__pycache__/anyof.cpython-37.pyc,,
hamcrest/core/core/__pycache__/allof.cpython-37.pyc,,
hamcrest/core/core/__pycache__/__init__.cpython-37.pyc,,
hamcrest/core/core/__pycache__/described_as.cpython-37.pyc,,
hamcrest/core/core/__pycache__/isequal.cpython-37.pyc,,
hamcrest/core/__pycache__/string_description.cpython-37.pyc,,
hamcrest/core/__pycache__/base_matcher.cpython-37.pyc,,
hamcrest/core/__pycache__/compat.cpython-37.pyc,,
hamcrest/core/__pycache__/assert_that.cpython-37.pyc,,
hamcrest/core/__pycache__/selfdescribing.cpython-37.pyc,,
hamcrest/core/__pycache__/selfdescribingvalue.cpython-37.pyc,,
hamcrest/core/__pycache__/matcher.cpython-37.pyc,,
hamcrest/core/__pycache__/base_description.cpython-37.pyc,,
hamcrest/core/__pycache__/description.cpython-37.pyc,,
hamcrest/core/__pycache__/__init__.cpython-37.pyc,,
hamcrest/core/helpers/__pycache__/hasmethod.cpython-37.pyc,,
hamcrest/core/helpers/__pycache__/wrap_matcher.cpython-37.pyc,,
hamcrest/core/helpers/__pycache__/__init__.cpython-37.pyc,,
hamcrest/library/collection/__pycache__/issequence_containinginanyorder.cpython-37.pyc,,
hamcrest/library/collection/__pycache__/issequence_containing.cpython-37.pyc,,
hamcrest/library/collection/__pycache__/issequence_containinginorder.cpython-37.pyc,,
hamcrest/library/collection/__pycache__/isdict_containingentries.cpython-37.pyc,,
hamcrest/library/collection/__pycache__/isdict_containing.cpython-37.pyc,,
hamcrest/library/collection/__pycache__/isdict_containingkey.cpython-37.pyc,,
hamcrest/library/collection/__pycache__/is_empty.cpython-37.pyc,,
hamcrest/library/collection/__pycache__/issequence_onlycontaining.cpython-37.pyc,,
hamcrest/library/collection/__pycache__/isin.cpython-37.pyc,,
hamcrest/library/collection/__pycache__/isdict_containingvalue.cpython-37.pyc,,
hamcrest/library/collection/__pycache__/__init__.cpython-37.pyc,,
hamcrest/library/integration/__pycache__/match_equality.cpython-37.pyc,,
hamcrest/library/integration/__pycache__/__init__.cpython-37.pyc,,
hamcrest/library/__pycache__/__init__.cpython-37.pyc,,
hamcrest/library/number/__pycache__/ordering_comparison.cpython-37.pyc,,
hamcrest/library/number/__pycache__/__init__.cpython-37.pyc,,
hamcrest/library/number/__pycache__/iscloseto.cpython-37.pyc,,
hamcrest/library/object/__pycache__/hasstring.cpython-37.pyc,,
hamcrest/library/object/__pycache__/haslength.cpython-37.pyc,,
hamcrest/library/object/__pycache__/hasproperty.cpython-37.pyc,,
hamcrest/library/object/__pycache__/__init__.cpython-37.pyc,,
hamcrest/library/text/__pycache__/stringendswith.cpython-37.pyc,,
hamcrest/library/text/__pycache__/stringmatches.cpython-37.pyc,,
hamcrest/library/text/__pycache__/stringstartswith.cpython-37.pyc,,
hamcrest/library/text/__pycache__/substringmatcher.cpython-37.pyc,,
hamcrest/library/text/__pycache__/stringcontainsinorder.cpython-37.pyc,,
hamcrest/library/text/__pycache__/isequal_ignoring_whitespace.cpython-37.pyc,,
hamcrest/library/text/__pycache__/stringcontains.cpython-37.pyc,,
hamcrest/library/text/__pycache__/isequal_ignoring_case.cpython-37.pyc,,
hamcrest/library/text/__pycache__/__init__.cpython-37.pyc,,
hamcrest/__pycache__/__init__.cpython-37.pyc,,

+ 6
- 0
venv/lib/python3.7/site-packages/PyHamcrest-1.9.0.dist-info/WHEEL View File

@@ -0,0 +1,6 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.24.0)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any


+ 1
- 0
venv/lib/python3.7/site-packages/PyHamcrest-1.9.0.dist-info/metadata.json View File

@@ -0,0 +1 @@
{"license": "New BSD", "download_url": "http://pypi.python.org/packages/source/P/PyHamcrest/PyHamcrest-1.9.0.tar.gz", "name": "PyHamcrest", "provides": "hamcrest", "test_requires": [{"requires": ["hypothesis (>=1.11)", "pytest (>=2.8)", "mock", "pytest-cov"]}], "extensions": {"python.details": {"project_urls": {"Home": "https://github.com/hamcrest/PyHamcrest"}, "contacts": [{"name": "Chris Rose", "role": "author", "email": "offline@offby1.net"}], "document_names": {"description": "DESCRIPTION.rst"}}}, "run_requires": [{"requires": ["setuptools", "six"]}], "generator": "bdist_wheel (0.24.0)", "summary": "Hamcrest framework for matcher objects", "extras": [], "classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: BSD 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.4", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: Jython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development", "Topic :: Software Development :: Quality Assurance", "Topic :: Software Development :: Testing"], "version": "1.9.0", "metadata_version": "2.0", "keywords": ["hamcrest", "matchers", "pyunit", "unit", "test", "testing", "unittest", "unittesting"], "platform": "All"}

+ 1
- 0
venv/lib/python3.7/site-packages/PyJWT-1.7.1.dist-info/INSTALLER View File

@@ -0,0 +1 @@
pip

+ 35
- 0
venv/lib/python3.7/site-packages/PyJWT-1.7.1.dist-info/RECORD View File

@@ -0,0 +1,35 @@
jwt/__init__.py,sha256=zzpUkNjnVRNWZKLBgn-t3fR3IWVdCWekrAKtsZWkCoQ,810
jwt/__main__.py,sha256=_rMsGakpyw1N023P8QOjCgbCxhXSCNIg92YpmUhQGMk,4162
jwt/algorithms.py,sha256=kL1ARjxNL8JeuxEpWS8On14qJWomMX_A_ncIrnZhBrA,13336
jwt/api_jws.py,sha256=wQxbg_cYR4hAJl4-9Ijf29B46NrOKhruXS7ANPFqkZ8,8095
jwt/api_jwt.py,sha256=NKRiCsTcMd0B5N-74zvqBYpQuxBxC4f6TCLM6P0jxVU,7905
jwt/compat.py,sha256=VG2zhmZFQ5spP0AThSVumRogymUXORz6fxA1jTew-cA,1624
jwt/exceptions.py,sha256=kGq96NMkyPBmx7-RXvLXq9ddTo2_SJPKPTpPscvGUuA,986
jwt/help.py,sha256=w9sYBatZK8-DIAxLPsdxQBVHXnqjOTETJ4dFY5hhEHs,1609
jwt/utils.py,sha256=RraFiloy_xsB8NA1CrlHxS9lR73If8amInQ3P1mKXeM,2629
jwt/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
jwt/contrib/algorithms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
jwt/contrib/algorithms/py_ecdsa.py,sha256=tSTUrwx-u14DJcqAChRzJG-wf7bEY2Gv2hI5xSZZNjk,1771
jwt/contrib/algorithms/pycrypto.py,sha256=mU3vRfk9QKj06ky3XXKXNkxv8-R4mBHbFR3EvbOgJ6k,1249
PyJWT-1.7.1.dist-info/AUTHORS,sha256=rahh5ZJ3f4RSF4X1_K1DvxTRm4Hy45QiMP7dDG_-yrE,595
PyJWT-1.7.1.dist-info/LICENSE,sha256=7IKvgVtfnahoWvswDMW-t5SeHCK3m2wcBUeWzv32ysY,1080
PyJWT-1.7.1.dist-info/METADATA,sha256=wIohFuzbkeGUiMkkD5U98z520aUoY6UnmsfDl4vVHRI,3878
PyJWT-1.7.1.dist-info/WHEEL,sha256=_wJFdOYk7i3xxT8ElOkUJvOdOvfNGbR9g-bf6UQT6sU,110
PyJWT-1.7.1.dist-info/entry_points.txt,sha256=Xl_tLkGbTgywYa7PwaEY2xSiCtVtM2PdHTL4CW_n9dM,45
PyJWT-1.7.1.dist-info/top_level.txt,sha256=RP5DHNyJbMq2ka0FmfTgoSaQzh7e3r5XuCWCO8a00k8,4
PyJWT-1.7.1.dist-info/RECORD,,
../../../bin/pyjwt,sha256=_ql8FxEP66OfxPNUZ3I2dUPYQkrWDYSMH2EWsj-symU,265
PyJWT-1.7.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
jwt/__pycache__/help.cpython-37.pyc,,
jwt/__pycache__/exceptions.cpython-37.pyc,,
jwt/__pycache__/algorithms.cpython-37.pyc,,
jwt/__pycache__/compat.cpython-37.pyc,,
jwt/__pycache__/__main__.cpython-37.pyc,,
jwt/__pycache__/utils.cpython-37.pyc,,
jwt/__pycache__/api_jwt.cpython-37.pyc,,
jwt/__pycache__/__init__.cpython-37.pyc,,
jwt/__pycache__/api_jws.cpython-37.pyc,,
jwt/contrib/algorithms/__pycache__/py_ecdsa.cpython-37.pyc,,
jwt/contrib/algorithms/__pycache__/pycrypto.cpython-37.pyc,,
jwt/contrib/algorithms/__pycache__/__init__.cpython-37.pyc,,
jwt/contrib/__pycache__/__init__.cpython-37.pyc,,

+ 6
- 0
venv/lib/python3.7/site-packages/PyJWT-1.7.1.dist-info/WHEEL View File

@@ -0,0 +1,6 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.32.3)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any


+ 135
- 0
venv/lib/python3.7/site-packages/Twisted-19.10.0-py3.7.egg-info/PKG-INFO View File

@@ -0,0 +1,135 @@
Metadata-Version: 2.1
Name: Twisted
Version: 19.10.0
Summary: An asynchronous networking framework written in Python
Home-page: https://twistedmatrix.com/
Author: Twisted Matrix Laboratories
Author-email: twisted-python@twistedmatrix.com
Maintainer: Glyph Lefkowitz
Maintainer-email: glyph@twistedmatrix.com
License: MIT
Project-URL: Documentation, https://twistedmatrix.com/documents/current/
Project-URL: Source, https://github.com/twisted/twisted
Project-URL: Issues, https://twistedmatrix.com/trac/report
Description: Twisted
=======
|pypi|_
|travis|_
|circleci|_
For information on changes in this release, see the `NEWS <https://github.com/twisted/twisted/blob/trunk/NEWS.rst>`_ file.
What is this?
-------------
Twisted is an event-based framework for internet applications, supporting Python 2.7 and Python 3.5+.
It includes modules for many different purposes, including the following:
- ``twisted.web``: HTTP clients and servers, HTML templating, and a WSGI server
- ``twisted.conch``: SSHv2 and Telnet clients and servers and terminal emulators
- ``twisted.words``: Clients and servers for IRC, XMPP, and other IM protocols
- ``twisted.mail``: IMAPv4, POP3, SMTP clients and servers
- ``twisted.positioning``: Tools for communicating with NMEA-compatible GPS receivers
- ``twisted.names``: DNS client and tools for making your own DNS servers
- ``twisted.trial``: A unit testing framework that integrates well with Twisted-based code.
Twisted supports all major system event loops -- ``select`` (all platforms), ``poll`` (most POSIX platforms), ``epoll`` (Linux), ``kqueue`` (FreeBSD, macOS), IOCP (Windows), and various GUI event loops (GTK+2/3, Qt, wxWidgets).
Third-party reactors can plug into Twisted, and provide support for additional event loops.
Installing
----------
To install the latest version of Twisted using pip::
$ pip install twisted
Additional instructions for installing this software are in `the installation instructions <https://github.com/twisted/twisted/blob/trunk/INSTALL.rst>`_.
Documentation and Support
-------------------------
Twisted's documentation is available from the `Twisted Matrix website <https://twistedmatrix.com/documents/current/>`_.
This documentation contains how-tos, code examples, and an API reference.
Help is also available on the `Twisted mailing list <https://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python>`_.
There is also a pair of very lively IRC channels, ``#twisted`` (for general Twisted questions) and ``#twisted.web`` (for Twisted Web), on ``chat.freenode.net``.
Unit Tests
----------
Twisted has a comprehensive test suite, which can be run by ``tox``::
$ tox -l # to view all test environments
$ tox -e py27-tests # to run the tests for Python 2.7
$ tox -e py35-tests # to run the tests for Python 3.5
You can test running the test suite under the different reactors with the ``TWISTED_REACTOR`` environment variable::
$ env TWISTED_REACTOR=epoll tox -e py27-tests
Some of these tests may fail if you:
* don't have the dependencies required for a particular subsystem installed,
* have a firewall blocking some ports (or things like Multicast, which Linux NAT has shown itself to do), or
* run them as root.
Copyright
---------
All of the code in this distribution is Copyright (c) 2001-2019 Twisted Matrix Laboratories.
Twisted is made available under the MIT license.
The included `LICENSE <https://github.com/twisted/twisted/blob/trunk/LICENSE>`_ file describes this in detail.
Warranty
--------
THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE USE OF THIS SOFTWARE IS WITH YOU.
IN NO EVENT WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY, BE LIABLE TO YOU FOR ANY DAMAGES, EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
Again, see the included `LICENSE <https://github.com/twisted/twisted/blob/trunk/LICENSE>`_ file for specific legal details.
.. |pypi| image:: http://img.shields.io/pypi/v/twisted.svg
.. _pypi: https://pypi.python.org/pypi/twisted
.. |travis| image:: https://travis-ci.org/twisted/twisted.svg?branch=trunk
.. _travis: https://travis-ci.org/twisted/twisted
.. |circleci| image:: https://circleci.com/gh/twisted/twisted.svg?style=svg
.. _circleci: https://circleci.com/gh/twisted/twisted
Platform: UNKNOWN
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
Description-Content-Type: text/x-rst
Provides-Extra: soap
Provides-Extra: conch
Provides-Extra: windows_platform
Provides-Extra: tls
Provides-Extra: dev
Provides-Extra: all_non_platform
Provides-Extra: macos_platform
Provides-Extra: serial
Provides-Extra: osx_platform
Provides-Extra: http2

+ 1479
- 0
venv/lib/python3.7/site-packages/Twisted-19.10.0-py3.7.egg-info/SOURCES.txt
File diff suppressed because it is too large
View File


+ 1
- 0
venv/lib/python3.7/site-packages/Twisted-19.10.0-py3.7.egg-info/dependency_links.txt View File

@@ -0,0 +1 @@


+ 1
- 0
venv/lib/python3.7/site-packages/Twisted-19.10.0-py3.7.egg-info/not-zip-safe View File

@@ -0,0 +1 @@


+ 1
- 0
venv/lib/python3.7/site-packages/Twisted-19.10.0-py3.7.egg-info/top_level.txt View File

@@ -0,0 +1 @@
twisted

+ 119
- 0
venv/lib/python3.7/site-packages/Werkzeug-0.16.0.dist-info/RECORD View File

@@ -0,0 +1,119 @@
werkzeug/__init__.py,sha256=tTlHx8lI6FpqB_X9x_zICTy3Rgikur6yIUJr8AE2XTs,7141
werkzeug/_compat.py,sha256=oBEVVrJT4sqYdIZbUWmgV9T9w257RhTSDBlTjh0Zbb0,6431
werkzeug/_internal.py,sha256=Wx7cpTRWqeBd0LAqobo0lCO4pNUW4oav6XKf7Taumgk,14590
werkzeug/_reloader.py,sha256=I3mg3oRQ0lLzl06oEoVopN3bN7CtINuuUQdqDcmTnEs,11531
werkzeug/datastructures.py,sha256=yVH4r-XD8CjOo18tDGVJYiAfezng6pK9hWzzLFy5a94,91761
werkzeug/exceptions.py,sha256=7wl3ufZZU23sASp0ciPe8GJssGND9DX6sDbjxvPuGYU,23437
werkzeug/filesystem.py,sha256=HzKl-j0Hd8Jl66j778UbPTAYNnY6vUZgYLlBZ0e7uw0,2101
werkzeug/formparser.py,sha256=Sto0jZid9im9ZVIf56vilCdyX-arK33wSftkYsLCnzo,21788
werkzeug/http.py,sha256=L6r2ehiorjOtsXITW-01zJsvtVa8Emkpkftu9di_cSk,41628
werkzeug/local.py,sha256=USVEcgIg-oCiUJFPIecFIW9jkIejfw4Fjf1u5yN-Np4,14456
werkzeug/posixemulation.py,sha256=gSSiv1SCmOyzOM_nq1ZaZCtxP__C5MeDJl_4yXJmi4Q,3541
werkzeug/routing.py,sha256=BSgjrYNwj2j5dAHQtK4INEp2TOf4OJP8hBncYSRO2ps,73410
werkzeug/security.py,sha256=81149MplFq7-hD4RK4sKp9kzXXejjV9D4lWBzaRyeQ8,8106
werkzeug/serving.py,sha256=qqdsTMILMt_B8ffBtROWK3RRpZeyTkQ9g-jhtpJodrY,36607
werkzeug/test.py,sha256=Cnb5xa3vLDL0hzFCH1fkG_YRpndViGQgCh4D744iSQk,40645
werkzeug/testapp.py,sha256=bHekqMsqRfVxwgFbvOMem-DYa_sdB7R47yUXpt1RUTo,9329
werkzeug/urls.py,sha256=hWZMk4ABiJmQPP_B5rRibWTp9gOyNLQpTqq6cmQAfeE,39322
werkzeug/useragents.py,sha256=0A_Ip74edPv_hy6CouBTpGumi2uyOci01COuzYFOm3U,5622
werkzeug/utils.py,sha256=KxCOHhsox7tAVe0m-ZyOGPoCaIbBIy7TxhocaUEHrd4,25050
werkzeug/wsgi.py,sha256=iXOR9l1fDd2IgqeTRQZPR6LnBBBx7Xsy97_i2n5HPUo,34666
werkzeug/contrib/__init__.py,sha256=EvNyiiCF49j5P0fZYJ3ZGe82ofXdSBvUNqWFwwBMibQ,553
werkzeug/contrib/atom.py,sha256=KpPJcTfzNW1J0VNQckCbVtVGBe3V8s451tOUya4qByI,15415
werkzeug/contrib/cache.py,sha256=AEh5UIw-Ui7sHZnlpvrD7ueOKUhCaAD55FXiPtXbbRs,32115
werkzeug/contrib/fixers.py,sha256=peEtAiIWYT5bh00EWEPOGKzGZXivOzVhhzKPvvzk1RM,9193
werkzeug/contrib/iterio.py,sha256=KKHa_8aCF_uhoeQVyPGUwrivuB6y6nNdXYo2D2vzOA8,10928
werkzeug/contrib/lint.py,sha256=NdIxP0E2kVt1xDIxoaIz3Rcl8ZdgmHaFbGTOaybGpN4,296
werkzeug/contrib/profiler.py,sha256=k_oMLU-AtsVvQ9TxNdermY6FuzSTYr-WE-ZmWb_DMyU,1229
werkzeug/contrib/securecookie.py,sha256=xbtElskGmtbiApgOJ5WhGgqGDs_68_PcWzqDIAY_QZY,13076
werkzeug/contrib/sessions.py,sha256=CkJ4IWvNqIaZCP83FMKYFszKL7E6Y1m6YEii7RaTYWs,13040
werkzeug/contrib/wrappers.py,sha256=ZmNk0wpzD66yomPnQxapndZQs4c0kNJaRzqI-BVxeQk,13199
werkzeug/debug/__init__.py,sha256=Bo3HvgTNY4NQ_2jROTSk3r1ScZcT_g_4EnuHTjKyrKM,18275
werkzeug/debug/console.py,sha256=HoBL21bbcmtiCLqiLDJLZi1LYnWMZxjoXYH5WaZB1XY,5469
werkzeug/debug/repr.py,sha256=lIwuhbyrMwVe3P_cFqNyqzHL7P93TLKod7lw9clydEw,9621
werkzeug/debug/tbtools.py,sha256=SkAAA4KKfwsXJinUbf-AEP4GqONTsR4uU7WPUloXcSE,20318
werkzeug/debug/shared/FONT_LICENSE,sha256=LwAVEI1oYnvXiNMT9SnCH_TaLCxCpeHziDrMg0gPkAI,4673
werkzeug/debug/shared/console.png,sha256=bxax6RXXlvOij_KeqvSNX0ojJf83YbnZ7my-3Gx9w2A,507
werkzeug/debug/shared/debugger.js,sha256=rOhqZMRfpZnnu6_XCGn6wMWPhtfwRAcyZKksdIxPJas,6400
werkzeug/debug/shared/jquery.js,sha256=CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo,88145
werkzeug/debug/shared/less.png,sha256=-4-kNRaXJSONVLahrQKUxMwXGm9R4OnZ9SxDGpHlIR4,191
werkzeug/debug/shared/more.png,sha256=GngN7CioHQoV58rH6ojnkYi8c_qED2Aka5FO5UXrReY,200
werkzeug/debug/shared/source.png,sha256=RoGcBTE4CyCB85GBuDGTFlAnUqxwTBiIfDqW15EpnUQ,818
werkzeug/debug/shared/style.css,sha256=gZ9uhmb5zj3XLuT9RvnMp6jMINgQ-VVBCp-2AZbG3YQ,6604
werkzeug/debug/shared/ubuntu.ttf,sha256=1eaHFyepmy4FyDvjLVzpITrGEBu_CZYY94jE0nED1c0,70220
werkzeug/middleware/__init__.py,sha256=f1SFZo67IlW4k1uqKzNHxYQlsakUS-D6KK_j0e3jjwQ,549
werkzeug/middleware/dispatcher.py,sha256=_-KoMzHtcISHS7ouWKAOraqlCLprdh83YOAn_8DjLp8,2240
werkzeug/middleware/http_proxy.py,sha256=lRjTdMmghHiZuZrS7_UJ3gZc-vlFizhBbFZ-XZPLwIA,7117
werkzeug/middleware/lint.py,sha256=ItTwuWJnflF8xMT1uqU_Ty1ryhux-CjeUfskqaUpxsw,12967
werkzeug/middleware/profiler.py,sha256=8B_s23d6BGrU_q54gJsm6kcCbOJbTSqrXCsioHON0Xs,4471
werkzeug/middleware/proxy_fix.py,sha256=1hi6AJH-J2uh2hMm1g0u7XfjRiTOoUeIOOmwWZ2n9t0,8670
werkzeug/middleware/shared_data.py,sha256=WtSphPrsUdpEk4E-_09CAILhfOBJ1YtcX1LrxcQfIzw,8224
werkzeug/wrappers/__init__.py,sha256=S4VioKAmF_av9Ec9zQvG71X1EOkYfPx1TYck9jyDiyY,1384
werkzeug/wrappers/accept.py,sha256=TIvjUc0g73fhTWX54wg_D9NNzKvpnG1X8u1w26tK1o8,1760
werkzeug/wrappers/auth.py,sha256=Pmn6iaGHBrUyHbJpW0lZhO_q9RVoAa5QalaTqcavdAI,1158
werkzeug/wrappers/base_request.py,sha256=aknREwqVT7WJUxm4weUGdBj90H6rDR3DvsIvmYhaC8A,26943
werkzeug/wrappers/base_response.py,sha256=ZA1XlxtsbvG4SpbdOEMT5--z7aZM0w6C5y33W8wOXa4,27906
werkzeug/wrappers/common_descriptors.py,sha256=OJ8jOwMun4L-BxCuFPkK1vaefx_-Y5IndVXvvn_ems4,12089
werkzeug/wrappers/etag.py,sha256=TwMO1fvluXbBqnFTj2DvrCNa3mYhbHYe1UZAVzfXvuU,12533
werkzeug/wrappers/json.py,sha256=HvK_A4NpO0sLqgb10sTJcoZydYOwyNiPCJPV7SVgcgE,4343
werkzeug/wrappers/request.py,sha256=qPo2zmmBv4HxboywtWZb2pJL8OPXo07BUXBKw2j9Fi8,1338
werkzeug/wrappers/response.py,sha256=vDZFEGzDOG0jjmS0uVVjeT3hqRt1hFaf15npnx7RD28,2329
werkzeug/wrappers/user_agent.py,sha256=YJb-vr12cujG7sQMG9V89VsJa-03SWSenhg1W4cT0EY,435
Werkzeug-0.16.0.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475
Werkzeug-0.16.0.dist-info/METADATA,sha256=BH9_q8z1IK2FbYDS7tSWLsd07z7GDReBgRumclV7T08,4712
Werkzeug-0.16.0.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110
Werkzeug-0.16.0.dist-info/top_level.txt,sha256=QRyj2VjwJoQkrwjwFIOlB8Xg3r9un0NtqVHQF-15xaw,9
Werkzeug-0.16.0.dist-info/RECORD,,
Werkzeug-0.16.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
werkzeug/middleware/__pycache__/http_proxy.cpython-37.pyc,,
werkzeug/middleware/__pycache__/lint.cpython-37.pyc,,
werkzeug/middleware/__pycache__/dispatcher.cpython-37.pyc,,
werkzeug/middleware/__pycache__/profiler.cpython-37.pyc,,
werkzeug/middleware/__pycache__/shared_data.cpython-37.pyc,,
werkzeug/middleware/__pycache__/proxy_fix.cpython-37.pyc,,
werkzeug/middleware/__pycache__/__init__.cpython-37.pyc,,
werkzeug/wrappers/__pycache__/response.cpython-37.pyc,,
werkzeug/wrappers/__pycache__/base_response.cpython-37.pyc,,
werkzeug/wrappers/__pycache__/request.cpython-37.pyc,,
werkzeug/wrappers/__pycache__/base_request.cpython-37.pyc,,
werkzeug/wrappers/__pycache__/auth.cpython-37.pyc,,
werkzeug/wrappers/__pycache__/user_agent.cpython-37.pyc,,
werkzeug/wrappers/__pycache__/etag.cpython-37.pyc,,
werkzeug/wrappers/__pycache__/json.cpython-37.pyc,,
werkzeug/wrappers/__pycache__/__init__.cpython-37.pyc,,
werkzeug/wrappers/__pycache__/common_descriptors.cpython-37.pyc,,
werkzeug/wrappers/__pycache__/accept.cpython-37.pyc,,
werkzeug/__pycache__/posixemulation.cpython-37.pyc,,
werkzeug/__pycache__/datastructures.cpython-37.pyc,,
werkzeug/__pycache__/exceptions.cpython-37.pyc,,
werkzeug/__pycache__/useragents.cpython-37.pyc,,
werkzeug/__pycache__/filesystem.cpython-37.pyc,,
werkzeug/__pycache__/serving.cpython-37.pyc,,
werkzeug/__pycache__/_internal.cpython-37.pyc,,
werkzeug/__pycache__/security.cpython-37.pyc,,
werkzeug/__pycache__/_compat.cpython-37.pyc,,
werkzeug/__pycache__/testapp.cpython-37.pyc,,
werkzeug/__pycache__/local.cpython-37.pyc,,
werkzeug/__pycache__/_reloader.cpython-37.pyc,,
werkzeug/__pycache__/routing.cpython-37.pyc,,
werkzeug/__pycache__/wsgi.cpython-37.pyc,,
werkzeug/__pycache__/utils.cpython-37.pyc,,
werkzeug/__pycache__/http.cpython-37.pyc,,
werkzeug/__pycache__/formparser.cpython-37.pyc,,
werkzeug/__pycache__/urls.cpython-37.pyc,,
werkzeug/__pycache__/test.cpython-37.pyc,,
werkzeug/__pycache__/__init__.cpython-37.pyc,,
werkzeug/contrib/__pycache__/sessions.cpython-37.pyc,,
werkzeug/contrib/__pycache__/lint.cpython-37.pyc,,
werkzeug/contrib/__pycache__/iterio.cpython-37.pyc,,
werkzeug/contrib/__pycache__/profiler.cpython-37.pyc,,
werkzeug/contrib/__pycache__/fixers.cpython-37.pyc,,
werkzeug/contrib/__pycache__/securecookie.cpython-37.pyc,,
werkzeug/contrib/__pycache__/cache.cpython-37.pyc,,
werkzeug/contrib/__pycache__/wrappers.cpython-37.pyc,,
werkzeug/contrib/__pycache__/__init__.cpython-37.pyc,,
werkzeug/contrib/__pycache__/atom.cpython-37.pyc,,
werkzeug/debug/__pycache__/repr.cpython-37.pyc,,
werkzeug/debug/__pycache__/console.cpython-37.pyc,,
werkzeug/debug/__pycache__/tbtools.cpython-37.pyc,,
werkzeug/debug/__pycache__/__init__.cpython-37.pyc,,

+ 6
- 0
venv/lib/python3.7/site-packages/Werkzeug-0.16.0.dist-info/WHEEL View File

@@ -0,0 +1,6 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.33.6)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any


+ 27
- 0
venv/lib/python3.7/site-packages/asgiref-3.2.3.dist-info/LICENSE View File

@@ -0,0 +1,27 @@
Copyright (c) Django Software Foundation and individual contributors.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

3. Neither the name of Django nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 225
- 0
venv/lib/python3.7/site-packages/asgiref-3.2.3.dist-info/METADATA View File

@@ -0,0 +1,225 @@
Metadata-Version: 2.1
Name: asgiref
Version: 3.2.3
Summary: ASGI specs, helper code, and adapters
Home-page: http://github.com/django/asgiref/
Author: Django Software Foundation
Author-email: foundation@djangoproject.com
License: BSD
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
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: Topic :: Internet :: WWW/HTTP
Description-Content-Type: text/x-rst
Provides-Extra: tests
Requires-Dist: pytest (~=4.3.0) ; extra == 'tests'
Requires-Dist: pytest-asyncio (~=0.10.0) ; extra == 'tests'

asgiref
=======

.. image:: https://api.travis-ci.org/django/asgiref.svg
:target: https://travis-ci.org/django/asgiref

.. image:: https://img.shields.io/pypi/v/asgiref.svg
:target: https://pypi.python.org/pypi/asgiref

ASGI is a standard for Python asynchronous web apps and servers to communicate
with each other, and positioned as an asynchronous successor to WSGI. You can
read more at https://asgi.readthedocs.io/en/latest/

This package includes ASGI base libraries, such as:

* Sync-to-async and async-to-sync function wrappers, ``asgiref.sync``
* Server base classes, ``asgiref.server``
* A WSGI-to-ASGI adapter, in ``asgiref.wsgi``


Function wrappers
-----------------

These allow you to wrap or decorate async or sync functions to call them from
the other style (so you can call async functions from a synchronous thread,
or vice-versa).

In particular:

* AsyncToSync lets a synchronous subthread stop and wait while the async
function is called on the main thread's event loop, and then control is
returned to the thread when the async function is finished.

* SyncToAsync lets async code call a synchronous function, which is run in
a threadpool and control returned to the async coroutine when the synchronous
function completes.

The idea is to make it easier to call synchronous APIs from async code and
asynchronous APIs from synchronous code so it's easier to transition code from
one style to the other. In the case of Channels, we wrap the (synchronous)
Django view system with SyncToAsync to allow it to run inside the (asynchronous)
ASGI server.

Note that exactly what threads things run in is very specific, and aimed to
keep maximum compatibility with old synchronous code. See
"Synchronous code & Threads" below for a full explanation.


Threadlocal replacement
-----------------------

This is a drop-in replacement for ``threading.local`` that works with both
threads and asyncio Tasks. Even better, it will proxy values through from a
task-local context to a thread-local context when you use ``sync_to_async``
to run things in a threadpool, and vice-versa for ``async_to_sync``.

If you instead want true thread- and task-safety, you can set
``thread_critical`` on the Local object to ensure this instead.


Server base classes
-------------------

Includes a ``StatelessServer`` class which provides all the hard work of
writing a stateless server (as in, does not handle direct incoming sockets
but instead consumes external streams or sockets to work out what is happening).

An example of such a server would be a chatbot server that connects out to
a central chat server and provides a "connection scope" per user chatting to
it. There's only one actual connection, but the server has to separate things
into several scopes for easier writing of the code.

You can see an example of this being used in `frequensgi <https://github.com/andrewgodwin/frequensgi>`_.


WSGI-to-ASGI adapter
--------------------

Allows you to wrap a WSGI application so it appears as a valid ASGI application.

Simply wrap it around your WSGI application like so::

asgi_application = WsgiToAsgi(wsgi_application)

The WSGI application will be run in a synchronous threadpool, and the wrapped
ASGI application will be one that accepts ``http`` class messages.

Please note that not all extended features of WSGI may be supported (such as
file handles for incoming POST bodies).


Dependencies
------------

``asgiref`` requires Python 3.5 or higher.


Contributing
------------

Please refer to the
`main Channels contributing docs <https://github.com/django/channels/blob/master/CONTRIBUTING.rst>`_.


Testing
'''''''

To run tests, make sure you have installed the ``tests`` extra with the package::

cd asgiref/
pip install -e .[tests]
pytest


Building the documentation
''''''''''''''''''''''''''

The documentation uses `Sphinx <http://www.sphinx-doc.org>`_::

cd asgiref/docs/
pip install sphinx

To build the docs, you can use the default tools::

sphinx-build -b html . _build/html # or `make html`, if you've got make set up
cd _build/html
python -m http.server

...or you can use ``sphinx-autobuild`` to run a server and rebuild/reload
your documentation changes automatically::

pip install sphinx-autobuild
sphinx-autobuild . _build/html


Implementation Details
----------------------

Synchronous code & threads
''''''''''''''''''''''''''

The ``asgiref.sync`` module provides two wrappers that let you go between
asynchronous and synchronous code at will, while taking care of the rough edges
for you.

Unfortunately, the rough edges are numerous, and the code has to work especially
hard to keep things in the same thread as much as possible. Notably, the
restrictions we are working with are:

* All synchronous code called through ``SyncToAsync`` and marked with
``thread_sensitive`` should run in the same thread as each other (and if the
outer layer of the program is synchronous, the main thread)

* If a thread already has a running async loop, ``AsyncToSync`` can't run things
on that loop if it's blocked on synchronous code that is above you in the
call stack.

The first compromise you get to might be that ``thread_sensitive`` code should
just run in the same thread and not spawn in a sub-thread, fulfilling the first
restriction, but that immediately runs you into the second restriction.

The only real solution is to essentially have a variant of ThreadPoolExecutor
that executes any ``thread_sensitive`` code on the outermost synchronous
thread - either the main thread, or a single spawned subthread.

This means you now have two basic states:

* If the outermost layer of your program is synchronous, then all async code
run through ``AsyncToSync`` will run in a per-call event loop in arbitary
sub-threads, while all ``thread_sensitive`` code will run in the main thread.

* If the outermost layer of your program is asynchronous, then all async code
runs on the main thread's event loop, and all ``thread_sensitive`` synchronous
code will run in a single shared sub-thread.

Cruicially, this means that in both cases there is a thread which is a shared
resource that all ``thread_sensitive`` code must run on, and there is a chance
that this thread is currently blocked on its own ``AsyncToSync`` call. Thus,
``AsyncToSync`` needs to act as an executor for thread code while it's blocking.

The ``CurrentThreadExecutor`` class provides this functionality; rather than
simply waiting on a Future, you can call its ``run_until_future`` method and
it will run submitted code until that Future is done. This means that code
inside the call can then run code on your thread.


Maintenance and Security
------------------------

To report security issues, please contact security@djangoproject.com. For GPG
signatures and more security process information, see
https://docs.djangoproject.com/en/dev/internals/security/.

To report bugs or request new features, please open a new GitHub issue.

This repository is part of the Channels project. For the shepherd and maintenance team, please see the
`main Channels readme <https://github.com/django/channels/blob/master/README.rst>`_.



+ 86
- 0
venv/lib/python3.7/site-packages/asgiref/current_thread_executor.py View File

@@ -0,0 +1,86 @@
import queue
import threading
import time
from concurrent.futures import Executor, Future


class _WorkItem(object):
"""
Represents an item needing to be run in the executor.
Copied from ThreadPoolExecutor (but it's private, so we're not going to rely on importing it)
"""

def __init__(self, future, fn, args, kwargs):
self.future = future
self.fn = fn
self.args = args
self.kwargs = kwargs

def run(self):
if not self.future.set_running_or_notify_cancel():
return
try:
result = self.fn(*self.args, **self.kwargs)
except BaseException as exc:
self.future.set_exception(exc)
# Break a reference cycle with the exception 'exc'
self = None
else:
self.future.set_result(result)


class CurrentThreadExecutor(Executor):
"""
An Executor that actually runs code in the thread it is instantiated in.
Passed to other threads running async code, so they can run sync code in
the thread they came from.
"""

def __init__(self):
self._work_thread = threading.current_thread()
self._work_queue = queue.Queue()
self._broken = False

def run_until_future(self, future):
"""
Runs the code in the work queue until a result is available from the future.
Should be run from the thread the executor is initialised in.
"""
# Check we're in the right thread
if threading.current_thread() != self._work_thread:
raise RuntimeError(
"You cannot run CurrentThreadExecutor from a different thread"
)
# Keep getting work items and checking the future
try:
while True:
# Get a work item and run it
try:
work_item = self._work_queue.get(block=False)
except queue.Empty:
# See if the future is done (we only exit if the work queue is empty)
if future.done():
return
# Prevent hot-looping on nothing
time.sleep(0.001)
else:
work_item.run()
del work_item
finally:
self._broken = True

def submit(self, fn, *args, **kwargs):
# Check they're not submitting from the same thread
if threading.current_thread() == self._work_thread:
raise RuntimeError(
"You cannot submit onto CurrentThreadExecutor from its own thread"
)
# Check they're not too late or the executor errored
if self._broken:
raise RuntimeError("CurrentThreadExecutor already quit or is broken")
# Add to work queue
f = Future()
work_item = _WorkItem(f, fn, args, kwargs)
self._work_queue.put(work_item)
# Return the future
return f

+ 154
- 0
venv/lib/python3.7/site-packages/asgiref/server.py View File

@@ -0,0 +1,154 @@
import asyncio
import logging
import time
import traceback

logger = logging.getLogger(__name__)


class StatelessServer:
"""
Base server class that handles basic concepts like application instance
creation/pooling, exception handling, and similar, for stateless protocols
(i.e. ones without actual incoming connections to the process)

Your code should override the handle() method, doing whatever it needs to,
and calling get_or_create_application_instance with a unique `scope_id`
and `scope` for the scope it wants to get.

If an application instance is found with the same `scope_id`, you are
given its input queue, otherwise one is made for you with the scope provided
and you are given that fresh new input queue. Either way, you should do
something like:

input_queue = self.get_or_create_application_instance(
"user-123456",
{"type": "testprotocol", "user_id": "123456", "username": "andrew"},
)
input_queue.put_nowait(message)

If you try and create an application instance and there are already
`max_application` instances, the oldest/least recently used one will be
reclaimed and shut down to make space.

Application coroutines that error will be found periodically (every 100ms
by default) and have their exceptions printed to the console. Override
application_exception() if you want to do more when this happens.

If you override run(), make sure you handle things like launching the
application checker.
"""

application_checker_interval = 0.1

def __init__(self, application, max_applications=1000):
# Parameters
self.application = application
self.max_applications = max_applications
# Initialisation
self.application_instances = {}

### Mainloop and handling

def run(self):
"""
Runs the asyncio event loop with our handler loop.
"""
event_loop = asyncio.get_event_loop()
asyncio.ensure_future(self.application_checker())
try:
event_loop.run_until_complete(self.handle())
except KeyboardInterrupt:
logger.info("Exiting due to Ctrl-C/interrupt")

async def handle(self):
raise NotImplementedError("You must implement handle()")

async def application_send(self, scope, message):
"""
Receives outbound sends from applications and handles them.
"""
raise NotImplementedError("You must implement application_send()")

### Application instance management

def get_or_create_application_instance(self, scope_id, scope):
"""
Creates an application instance and returns its queue.
"""
if scope_id in self.application_instances:
self.application_instances[scope_id]["last_used"] = time.time()
return self.application_instances[scope_id]["input_queue"]
# See if we need to delete an old one
while len(self.application_instances) > self.max_applications:
self.delete_oldest_application_instance()
# Make an instance of the application
input_queue = asyncio.Queue()
application_instance = self.application(scope=scope)
# Run it, and stash the future for later checking
future = asyncio.ensure_future(
application_instance(
receive=input_queue.get,
send=lambda message: self.application_send(scope, message),
)
)
self.application_instances[scope_id] = {
"input_queue": input_queue,
"future": future,
"scope": scope,
"last_used": time.time(),
}
return input_queue

def delete_oldest_application_instance(self):
"""
Finds and deletes the oldest application instance
"""
oldest_time = min(
details["last_used"] for details in self.application_instances.values()
)
for scope_id, details in self.application_instances.items():
if details["last_used"] == oldest_time:
self.delete_application_instance(scope_id)
# Return to make sure we only delete one in case two have
# the same oldest time
return

def delete_application_instance(self, scope_id):
"""
Removes an application instance (makes sure its task is stopped,
then removes it from the current set)
"""
details = self.application_instances[scope_id]
del self.application_instances[scope_id]
if not details["future"].done():
details["future"].cancel()

async def application_checker(self):
"""
Goes through the set of current application instance Futures and cleans up
any that are done/prints exceptions for any that errored.
"""
while True:
await asyncio.sleep(self.application_checker_interval)
for scope_id, details in list(self.application_instances.items()):
if details["future"].done():
exception = details["future"].exception()
if exception:
await self.application_exception(exception, details)
try:
del self.application_instances[scope_id]
except KeyError:
# Exception handling might have already got here before us. That's fine.
pass

async def application_exception(self, exception, application_details):
"""
Called whenever an application coroutine has an exception.
"""
logging.error(
"Exception inside application: %s\n%s%s",
exception,
"".join(traceback.format_tb(exception.__traceback__)),
" {}".format(exception),
)

+ 304
- 0
venv/lib/python3.7/site-packages/asgiref/sync.py View File

@@ -0,0 +1,304 @@
import asyncio
import asyncio.coroutines
import functools
import os
import sys
import threading
from concurrent.futures import Future, ThreadPoolExecutor

from .current_thread_executor import CurrentThreadExecutor
from .local import Local

try:
import contextvars # Python 3.7+ only.
except ImportError:
contextvars = None


class AsyncToSync:
"""
Utility class which turns an awaitable that only works on the thread with
the event loop into a synchronous callable that works in a subthread.

If the call stack contains an async loop, the code runs there.
Otherwise, the code runs in a new loop in a new thread.

Either way, this thread then pauses and waits to run any thread_sensitive
code called from further down the call stack using SyncToAsync, before
finally exiting once the async task returns.
"""

# Maps launched Tasks to the threads that launched them (for locals impl)
launch_map = {}

# Keeps track of which CurrentThreadExecutor to use. This uses an asgiref
# Local, not a threadlocal, so that tasks can work out what their parent used.
executors = Local()

def __init__(self, awaitable, force_new_loop=False):
self.awaitable = awaitable
if force_new_loop:
# They have asked that we always run in a new sub-loop.
self.main_event_loop = None
else:
try:
self.main_event_loop = asyncio.get_event_loop()
except RuntimeError:
# There's no event loop in this thread. Look for the threadlocal if
# we're inside SyncToAsync
self.main_event_loop = getattr(
SyncToAsync.threadlocal, "main_event_loop", None
)

def __call__(self, *args, **kwargs):
# You can't call AsyncToSync from a thread with a running event loop
try:
event_loop = asyncio.get_event_loop()
except RuntimeError:
pass
else:
if event_loop.is_running():
raise RuntimeError(
"You cannot use AsyncToSync in the same thread as an async event loop - "
"just await the async function directly."
)
# Make a future for the return information
call_result = Future()
# Get the source thread
source_thread = threading.current_thread()
# Make a CurrentThreadExecutor we'll use to idle in this thread - we
# need one for every sync frame, even if there's one above us in the
# same thread.
if hasattr(self.executors, "current"):
old_current_executor = self.executors.current
else:
old_current_executor = None
current_executor = CurrentThreadExecutor()
self.executors.current = current_executor
# Use call_soon_threadsafe to schedule a synchronous callback on the
# main event loop's thread if it's there, otherwise make a new loop
# in this thread.
try:
if not (self.main_event_loop and self.main_event_loop.is_running()):
# Make our own event loop - in a new thread - and run inside that.
loop = asyncio.new_event_loop()
loop_executor = ThreadPoolExecutor(max_workers=1)
loop_future = loop_executor.submit(
self._run_event_loop,
loop,
self.main_wrap(
args, kwargs, call_result, source_thread, sys.exc_info()
),
)
if current_executor:
# Run the CurrentThreadExecutor until the future is done
current_executor.run_until_future(loop_future)
# Wait for future and/or allow for exception propagation
loop_future.result()
else:
# Call it inside the existing loop
self.main_event_loop.call_soon_threadsafe(
self.main_event_loop.create_task,
self.main_wrap(
args, kwargs, call_result, source_thread, sys.exc_info()
),
)
if current_executor:
# Run the CurrentThreadExecutor until the future is done
current_executor.run_until_future(call_result)
finally:
# Clean up any executor we were running
if hasattr(self.executors, "current"):
del self.executors.current
if old_current_executor:
self.executors.current = old_current_executor
# Wait for results from the future.
return call_result.result()

def _run_event_loop(self, loop, coro):
"""
Runs the given event loop (designed to be called in a thread).
"""
asyncio.set_event_loop(loop)
try:
loop.run_until_complete(coro)
finally:
try:
if hasattr(loop, "shutdown_asyncgens"):
loop.run_until_complete(loop.shutdown_asyncgens())
finally:
loop.close()
asyncio.set_event_loop(self.main_event_loop)

def __get__(self, parent, objtype):
"""
Include self for methods
"""
func = functools.partial(self.__call__, parent)
return functools.update_wrapper(func, self.awaitable)

async def main_wrap(self, args, kwargs, call_result, source_thread, exc_info):
"""
Wraps the awaitable with something that puts the result into the
result/exception future.
"""
current_task = SyncToAsync.get_current_task()
self.launch_map[current_task] = source_thread
try:
# If we have an exception, run the function inside the except block
# after raising it so exc_info is correctly populated.
if exc_info[1]:
try:
raise exc_info[1]
except:
result = await self.awaitable(*args, **kwargs)
else:
result = await self.awaitable(*args, **kwargs)
except Exception as e:
call_result.set_exception(e)
else:
call_result.set_result(result)
finally:
del self.launch_map[current_task]


class SyncToAsync:
"""
Utility class which turns a synchronous callable into an awaitable that
runs in a threadpool. It also sets a threadlocal inside the thread so
calls to AsyncToSync can escape it.

If thread_sensitive is passed, the code will run in the same thread as any
outer code. This is needed for underlying Python code that is not
threadsafe (for example, code which handles SQLite database connections).

If the outermost program is async (i.e. SyncToAsync is outermost), then
this will be a dedicated single sub-thread that all sync code runs in,
one after the other. If the outermost program is sync (i.e. AsyncToSync is
outermost), this will just be the main thread. This is achieved by idling
with a CurrentThreadExecutor while AsyncToSync is blocking its sync parent,
rather than just blocking.
"""

# If they've set ASGI_THREADS, update the default asyncio executor for now
if "ASGI_THREADS" in os.environ:
loop = asyncio.get_event_loop()
loop.set_default_executor(
ThreadPoolExecutor(max_workers=int(os.environ["ASGI_THREADS"]))
)

# Maps launched threads to the coroutines that spawned them
launch_map = {}

# Storage for main event loop references
threadlocal = threading.local()

# Single-thread executor for thread-sensitive code
single_thread_executor = ThreadPoolExecutor(max_workers=1)

def __init__(self, func, thread_sensitive=False):
self.func = func
self._thread_sensitive = thread_sensitive
self._is_coroutine = asyncio.coroutines._is_coroutine
try:
self.__self__ = func.__self__
except AttributeError:
pass

async def __call__(self, *args, **kwargs):
loop = asyncio.get_event_loop()

# Work out what thread to run the code in
if self._thread_sensitive:
if hasattr(AsyncToSync.executors, "current"):
# If we have a parent sync thread above somewhere, use that
executor = AsyncToSync.executors.current
else:
# Otherwise, we run it in a fixed single thread
executor = self.single_thread_executor
else:
executor = None # Use default

if contextvars is not None:
context = contextvars.copy_context()
child = functools.partial(self.func, *args, **kwargs)
func = context.run
args = (child,)
kwargs = {}
else:
func = self.func

# Run the code in the right thread
future = loop.run_in_executor(
executor,
functools.partial(
self.thread_handler,
loop,
self.get_current_task(),
sys.exc_info(),
func,
*args,
**kwargs
),
)
return await asyncio.wait_for(future, timeout=None)

def __get__(self, parent, objtype):
"""
Include self for methods
"""
return functools.partial(self.__call__, parent)

def thread_handler(self, loop, source_task, exc_info, func, *args, **kwargs):
"""
Wraps the sync application with exception handling.
"""
# Set the threadlocal for AsyncToSync
self.threadlocal.main_event_loop = loop
# Set the task mapping (used for the locals module)
current_thread = threading.current_thread()
if AsyncToSync.launch_map.get(source_task) == current_thread:
# Our parent task was launched from this same thread, so don't make
# a launch map entry - let it shortcut over us! (and stop infinite loops)
parent_set = False
else:
self.launch_map[current_thread] = source_task
parent_set = True
# Run the function
try:
# If we have an exception, run the function inside the except block
# after raising it so exc_info is correctly populated.
if exc_info[1]:
try:
raise exc_info[1]
except:
return func(*args, **kwargs)
else:
return func(*args, **kwargs)
finally:
# Only delete the launch_map parent if we set it, otherwise it is
# from someone else.
if parent_set:
del self.launch_map[current_thread]

@staticmethod
def get_current_task():
"""
Cross-version implementation of asyncio.current_task()

Returns None if there is no task.
"""
try:
if hasattr(asyncio, "current_task"):
# Python 3.7 and up
return asyncio.current_task()
else:
# Python 3.6
return asyncio.Task.current_task()
except RuntimeError:
return None


# Lowercase is more sensible for most things
sync_to_async = SyncToAsync
async_to_sync = AsyncToSync

+ 128
- 0
venv/lib/python3.7/site-packages/asgiref/timeout.py View File

@@ -0,0 +1,128 @@
# This code is originally sourced from the aio-libs project "async_timeout",
# under the Apache 2.0 license. You may see the original project at
# https://github.com/aio-libs/async-timeout

# It is vendored here to reduce chain-dependencies on this library, and
# modified slightly to remove some features we don't use.


import asyncio
import sys
from types import TracebackType
from typing import Any, Optional, Type # noqa

PY_37 = sys.version_info >= (3, 7)


class timeout:
"""timeout context manager.

Useful in cases when you want to apply timeout logic around block
of code or in cases when asyncio.wait_for is not suitable. For example:

>>> with timeout(0.001):
... async with aiohttp.get('https://github.com') as r:
... await r.text()


timeout - value in seconds or None to disable timeout logic
loop - asyncio compatible event loop
"""

def __init__(
self,
timeout: Optional[float],
*,
loop: Optional[asyncio.AbstractEventLoop] = None
) -> None:
self._timeout = timeout
if loop is None:
loop = asyncio.get_event_loop()
self._loop = loop
self._task = None # type: Optional[asyncio.Task[Any]]
self._cancelled = False
self._cancel_handler = None # type: Optional[asyncio.Handle]
self._cancel_at = None # type: Optional[float]

def __enter__(self) -> "timeout":
return self._do_enter()

def __exit__(
self,
exc_type: Type[BaseException],
exc_val: BaseException,
exc_tb: TracebackType,
) -> Optional[bool]:
self._do_exit(exc_type)
return None

async def __aenter__(self) -> "timeout":
return self._do_enter()

async def __aexit__(
self,
exc_type: Type[BaseException],
exc_val: BaseException,
exc_tb: TracebackType,
) -> None:
self._do_exit(exc_type)

@property
def expired(self) -> bool:
return self._cancelled

@property
def remaining(self) -> Optional[float]:
if self._cancel_at is not None:
return max(self._cancel_at - self._loop.time(), 0.0)
else:
return None

def _do_enter(self) -> "timeout":
# Support Tornado 5- without timeout
# Details: https://github.com/python/asyncio/issues/392
if self._timeout is None:
return self

self._task = current_task(self._loop)
if self._task is None:
raise RuntimeError(
"Timeout context manager should be used " "inside a task"
)

if self._timeout <= 0:
self._loop.call_soon(self._cancel_task)
return self

self._cancel_at = self._loop.time() + self._timeout
self._cancel_handler = self._loop.call_at(self._cancel_at, self._cancel_task)
return self

def _do_exit(self, exc_type: Type[BaseException]) -> None:
if exc_type is asyncio.CancelledError and self._cancelled:
self._cancel_handler = None
self._task = None
raise asyncio.TimeoutError
if self._timeout is not None and self._cancel_handler is not None:
self._cancel_handler.cancel()
self._cancel_handler = None
self._task = None
return None

def _cancel_task(self) -> None:
if self._task is not None:
self._task.cancel()
self._cancelled = True


def current_task(loop: asyncio.AbstractEventLoop) -> "asyncio.Task[Any]":
if PY_37:
task = asyncio.current_task(loop=loop) # type: ignore
else:
task = asyncio.Task.current_task(loop=loop)
if task is None:
# this should be removed, tokio must use register_task and family API
if hasattr(loop, "current_task"):
task = loop.current_task() # type: ignore

return task

+ 278
- 0
venv/lib/python3.7/site-packages/attr/__init__.pyi View File

@@ -0,0 +1,278 @@
from typing import (
Any,
Callable,
Dict,
Generic,
List,
Optional,
Sequence,
Mapping,
Tuple,
Type,
TypeVar,
Union,
overload,
)

# `import X as X` is required to make these public
from . import exceptions as exceptions
from . import filters as filters
from . import converters as converters
from . import validators as validators

from ._version_info import VersionInfo

__version__: str
__version_info__: VersionInfo
__title__: str
__description__: str
__url__: str
__uri__: str
__author__: str
__email__: str
__license__: str
__copyright__: str

_T = TypeVar("_T")
_C = TypeVar("_C", bound=type)

_ValidatorType = Callable[[Any, Attribute[_T], _T], Any]
_ConverterType = Callable[[Any], _T]
_FilterType = Callable[[Attribute[_T], _T], bool]
_ReprType = Callable[[Any], str]
_ReprArgType = Union[bool, _ReprType]
# FIXME: in reality, if multiple validators are passed they must be in a list or tuple,
# but those are invariant and so would prevent subtypes of _ValidatorType from working
# when passed in a list or tuple.
_ValidatorArgType = Union[_ValidatorType[_T], Sequence[_ValidatorType[_T]]]

# _make --

NOTHING: object

# NOTE: Factory lies about its return type to make this possible: `x: List[int] = Factory(list)`
# Work around mypy issue #4554 in the common case by using an overload.
@overload
def Factory(factory: Callable[[], _T]) -> _T: ...
@overload
def Factory(
factory: Union[Callable[[Any], _T], Callable[[], _T]],
takes_self: bool = ...,
) -> _T: ...

class Attribute(Generic[_T]):
name: str
default: Optional[_T]
validator: Optional[_ValidatorType[_T]]
repr: _ReprArgType
cmp: bool
eq: bool
order: bool
hash: Optional[bool]
init: bool
converter: Optional[_ConverterType[_T]]
metadata: Dict[Any, Any]
type: Optional[Type[_T]]
kw_only: bool

# NOTE: We had several choices for the annotation to use for type arg:
# 1) Type[_T]
# - Pros: Handles simple cases correctly
# - Cons: Might produce less informative errors in the case of conflicting TypeVars
# e.g. `attr.ib(default='bad', type=int)`
# 2) Callable[..., _T]
# - Pros: Better error messages than #1 for conflicting TypeVars
# - Cons: Terrible error messages for validator checks.
# e.g. attr.ib(type=int, validator=validate_str)
# -> error: Cannot infer function type argument
# 3) type (and do all of the work in the mypy plugin)
# - Pros: Simple here, and we could customize the plugin with our own errors.
# - Cons: Would need to write mypy plugin code to handle all the cases.
# We chose option #1.

# `attr` lies about its return type to make the following possible:
# attr() -> Any
# attr(8) -> int
# attr(validator=<some callable>) -> Whatever the callable expects.
# This makes this type of assignments possible:
# x: int = attr(8)
#
# This form catches explicit None or no default but with no other arguments returns Any.
@overload
def attrib(
default: None = ...,
validator: None = ...,
repr: _ReprArgType = ...,
cmp: Optional[bool] = ...,
hash: Optional[bool] = ...,
init: bool = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: None = ...,
converter: None = ...,
factory: None = ...,
kw_only: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> Any: ...

# This form catches an explicit None or no default and infers the type from the other arguments.
@overload
def attrib(
default: None = ...,
validator: Optional[_ValidatorArgType[_T]] = ...,
repr: _ReprArgType = ...,
cmp: Optional[bool] = ...,
hash: Optional[bool] = ...,
init: bool = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: Optional[Type[_T]] = ...,
converter: Optional[_ConverterType[_T]] = ...,
factory: Optional[Callable[[], _T]] = ...,
kw_only: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> _T: ...

# This form catches an explicit default argument.
@overload
def attrib(
default: _T,
validator: Optional[_ValidatorArgType[_T]] = ...,
repr: _ReprArgType = ...,
cmp: Optional[bool] = ...,
hash: Optional[bool] = ...,
init: bool = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: Optional[Type[_T]] = ...,
converter: Optional[_ConverterType[_T]] = ...,
factory: Optional[Callable[[], _T]] = ...,
kw_only: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> _T: ...

# This form covers type=non-Type: e.g. forward references (str), Any
@overload
def attrib(
default: Optional[_T] = ...,
validator: Optional[_ValidatorArgType[_T]] = ...,
repr: _ReprArgType = ...,
cmp: Optional[bool] = ...,
hash: Optional[bool] = ...,
init: bool = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: object = ...,
converter: Optional[_ConverterType[_T]] = ...,
factory: Optional[Callable[[], _T]] = ...,
kw_only: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> Any: ...
@overload
def attrs(
maybe_cls: _C,
these: Optional[Dict[str, Any]] = ...,
repr_ns: Optional[str] = ...,
repr: bool = ...,
cmp: Optional[bool] = ...,
hash: Optional[bool] = ...,
init: bool = ...,
slots: bool = ...,
frozen: bool = ...,
weakref_slot: bool = ...,
str: bool = ...,
auto_attribs: bool = ...,
kw_only: bool = ...,
cache_hash: bool = ...,
auto_exc: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> _C: ...
@overload
def attrs(
maybe_cls: None = ...,
these: Optional[Dict[str, Any]] = ...,
repr_ns: Optional[str] = ...,
repr: bool = ...,
cmp: Optional[bool] = ...,
hash: Optional[bool] = ...,
init: bool = ...,
slots: bool = ...,
frozen: bool = ...,
weakref_slot: bool = ...,
str: bool = ...,
auto_attribs: bool = ...,
kw_only: bool = ...,
cache_hash: bool = ...,
auto_exc: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> Callable[[_C], _C]: ...

# TODO: add support for returning NamedTuple from the mypy plugin
class _Fields(Tuple[Attribute[Any], ...]):
def __getattr__(self, name: str) -> Attribute[Any]: ...

def fields(cls: type) -> _Fields: ...
def fields_dict(cls: type) -> Dict[str, Attribute[Any]]: ...
def validate(inst: Any) -> None: ...

# TODO: add support for returning a proper attrs class from the mypy plugin
# we use Any instead of _CountingAttr so that e.g. `make_class('Foo', [attr.ib()])` is valid
def make_class(
name: str,
attrs: Union[List[str], Tuple[str, ...], Dict[str, Any]],
bases: Tuple[type, ...] = ...,
repr_ns: Optional[str] = ...,
repr: bool = ...,
cmp: Optional[bool] = ...,
hash: Optional[bool] = ...,
init: bool = ...,
slots: bool = ...,
frozen: bool = ...,
weakref_slot: bool = ...,
str: bool = ...,
auto_attribs: bool = ...,
kw_only: bool = ...,
cache_hash: bool = ...,
auto_exc: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
) -> type: ...

# _funcs --

# TODO: add support for returning TypedDict from the mypy plugin
# FIXME: asdict/astuple do not honor their factory args. waiting on one of these:
# https://github.com/python/mypy/issues/4236
# https://github.com/python/typing/issues/253
def asdict(
inst: Any,
recurse: bool = ...,
filter: Optional[_FilterType[Any]] = ...,
dict_factory: Type[Mapping[Any, Any]] = ...,
retain_collection_types: bool = ...,
) -> Dict[str, Any]: ...

# TODO: add support for returning NamedTuple from the mypy plugin
def astuple(
inst: Any,
recurse: bool = ...,
filter: Optional[_FilterType[Any]] = ...,
tuple_factory: Type[Sequence[Any]] = ...,
retain_collection_types: bool = ...,
) -> Tuple[Any, ...]: ...
def has(cls: type) -> bool: ...
def assoc(inst: _T, **changes: Any) -> _T: ...
def evolve(inst: _T, **changes: Any) -> _T: ...

# _config --

def set_run_validators(run: bool) -> None: ...
def get_run_validators() -> bool: ...

# aliases --

s = attributes = attrs
ib = attr = attrib
dataclass = attrs # Technically, partial(attrs, auto_attribs=True) ;)

+ 230
- 0
venv/lib/python3.7/site-packages/attr/_compat.py View File

@@ -0,0 +1,230 @@
from __future__ import absolute_import, division, print_function

import platform
import sys
import types
import warnings


PY2 = sys.version_info[0] == 2
PYPY = platform.python_implementation() == "PyPy"


if PYPY or sys.version_info[:2] >= (3, 6):
ordered_dict = dict
else:
from collections import OrderedDict

ordered_dict = OrderedDict


if PY2:
from UserDict import IterableUserDict
from collections import Mapping, Sequence

# We 'bundle' isclass instead of using inspect as importing inspect is
# fairly expensive (order of 10-15 ms for a modern machine in 2016)
def isclass(klass):
return isinstance(klass, (type, types.ClassType))

# TYPE is used in exceptions, repr(int) is different on Python 2 and 3.
TYPE = "type"

def iteritems(d):
return d.iteritems()

# Python 2 is bereft of a read-only dict proxy, so we make one!
class ReadOnlyDict(IterableUserDict):
"""
Best-effort read-only dict wrapper.
"""

def __setitem__(self, key, val):
# We gently pretend we're a Python 3 mappingproxy.
raise TypeError(
"'mappingproxy' object does not support item assignment"
)

def update(self, _):
# We gently pretend we're a Python 3 mappingproxy.
raise AttributeError(
"'mappingproxy' object has no attribute 'update'"
)

def __delitem__(self, _):
# We gently pretend we're a Python 3 mappingproxy.
raise TypeError(
"'mappingproxy' object does not support item deletion"
)

def clear(self):
# We gently pretend we're a Python 3 mappingproxy.
raise AttributeError(
"'mappingproxy' object has no attribute 'clear'"
)

def pop(self, key, default=None):
# We gently pretend we're a Python 3 mappingproxy.
raise AttributeError(
"'mappingproxy' object has no attribute 'pop'"
)

def popitem(self):
# We gently pretend we're a Python 3 mappingproxy.
raise AttributeError(
"'mappingproxy' object has no attribute 'popitem'"
)

def setdefault(self, key, default=None):
# We gently pretend we're a Python 3 mappingproxy.
raise AttributeError(
"'mappingproxy' object has no attribute 'setdefault'"
)

def __repr__(self):
# Override to be identical to the Python 3 version.
return "mappingproxy(" + repr(self.data) + ")"

def metadata_proxy(d):
res = ReadOnlyDict()
res.data.update(d) # We blocked update, so we have to do it like this.
return res

def just_warn(*args, **kw): # pragma: nocover
"""
We only warn on Python 3 because we are not aware of any concrete
consequences of not setting the cell on Python 2.
"""


else: # Python 3 and later.
from collections.abc import Mapping, Sequence # noqa

def just_warn(*args, **kw):
"""
We only warn on Python 3 because we are not aware of any concrete
consequences of not setting the cell on Python 2.
"""
warnings.warn(
"Running interpreter doesn't sufficiently support code object "
"introspection. Some features like bare super() or accessing "
"__class__ will not work with slotted classes.",
RuntimeWarning,
stacklevel=2,
)

def isclass(klass):
return isinstance(klass, type)

TYPE = "class"

def iteritems(d):
return d.items()

def metadata_proxy(d):
return types.MappingProxyType(dict(d))


def make_set_closure_cell():
"""Return a function of two arguments (cell, value) which sets
the value stored in the closure cell `cell` to `value`.
"""
# pypy makes this easy. (It also supports the logic below, but
# why not do the easy/fast thing?)
if PYPY: # pragma: no cover

def set_closure_cell(cell, value):
cell.__setstate__((value,))

return set_closure_cell

# Otherwise gotta do it the hard way.

# Create a function that will set its first cellvar to `value`.
def set_first_cellvar_to(value):
x = value
return

# This function will be eliminated as dead code, but
# not before its reference to `x` forces `x` to be
# represented as a closure cell rather than a local.
def force_x_to_be_a_cell(): # pragma: no cover
return x

try:
# Extract the code object and make sure our assumptions about
# the closure behavior are correct.
if PY2:
co = set_first_cellvar_to.func_code
else:
co = set_first_cellvar_to.__code__
if co.co_cellvars != ("x",) or co.co_freevars != ():
raise AssertionError # pragma: no cover

# Convert this code object to a code object that sets the
# function's first _freevar_ (not cellvar) to the argument.
if sys.version_info >= (3, 8):
# CPython 3.8+ has an incompatible CodeType signature
# (added a posonlyargcount argument) but also added
# CodeType.replace() to do this without counting parameters.
set_first_freevar_code = co.replace(
co_cellvars=co.co_freevars, co_freevars=co.co_cellvars
)
else:
args = [co.co_argcount]
if not PY2:
args.append(co.co_kwonlyargcount)
args.extend(
[
co.co_nlocals,
co.co_stacksize,
co.co_flags,
co.co_code,
co.co_consts,
co.co_names,
co.co_varnames,
co.co_filename,
co.co_name,
co.co_firstlineno,
co.co_lnotab,
# These two arguments are reversed:
co.co_cellvars,
co.co_freevars,
]
)
set_first_freevar_code = types.CodeType(*args)

def set_closure_cell(cell, value):
# Create a function using the set_first_freevar_code,
# whose first closure cell is `cell`. Calling it will
# change the value of that cell.
setter = types.FunctionType(
set_first_freevar_code, {}, "setter", (), (cell,)
)
# And call it to set the cell.
setter(value)

# Make sure it works on this interpreter:
def make_func_with_cell():
x = None

def func():
return x # pragma: no cover

return func

if PY2:
cell = make_func_with_cell().func_closure[0]
else:
cell = make_func_with_cell().__closure__[0]
set_closure_cell(cell, 100)
if cell.cell_contents != 100:
raise AssertionError # pragma: no cover

except Exception:
return just_warn
else:
return set_closure_cell


set_closure_cell = make_set_closure_cell()

+ 23
- 0
venv/lib/python3.7/site-packages/attr/_config.py View File

@@ -0,0 +1,23 @@
from __future__ import absolute_import, division, print_function


__all__ = ["set_run_validators", "get_run_validators"]

_run_validators = True


def set_run_validators(run):
"""
Set whether or not validators are run. By default, they are run.
"""
if not isinstance(run, bool):
raise TypeError("'run' must be bool.")
global _run_validators
_run_validators = run


def get_run_validators():
"""
Return whether or not validators are run.
"""
return _run_validators

+ 2168
- 0
venv/lib/python3.7/site-packages/attr/_make.py
File diff suppressed because it is too large
View File


+ 78
- 0
venv/lib/python3.7/site-packages/attr/converters.py View File

@@ -0,0 +1,78 @@
"""
Commonly useful converters.
"""

from __future__ import absolute_import, division, print_function

from ._make import NOTHING, Factory


def optional(converter):
"""
A converter that allows an attribute to be optional. An optional attribute
is one which can be set to ``None``.

:param callable converter: the converter that is used for non-``None``
values.

.. versionadded:: 17.1.0
"""

def optional_converter(val):
if val is None:
return None
return converter(val)

return optional_converter


def default_if_none(default=NOTHING, factory=None):
"""
A converter that allows to replace ``None`` values by *default* or the
result of *factory*.

:param default: Value to be used if ``None`` is passed. Passing an instance
of `attr.Factory` is supported, however the ``takes_self`` option
is *not*.
:param callable factory: A callable that takes not parameters whose result
is used if ``None`` is passed.

:raises TypeError: If **neither** *default* or *factory* is passed.
:raises TypeError: If **both** *default* and *factory* are passed.
:raises ValueError: If an instance of `attr.Factory` is passed with
``takes_self=True``.

.. versionadded:: 18.2.0
"""
if default is NOTHING and factory is None:
raise TypeError("Must pass either `default` or `factory`.")

if default is not NOTHING and factory is not None:
raise TypeError(
"Must pass either `default` or `factory` but not both."
)

if factory is not None:
default = Factory(factory)

if isinstance(default, Factory):
if default.takes_self:
raise ValueError(
"`takes_self` is not supported by default_if_none."
)

def default_if_none_converter(val):
if val is not None:
return val

return default.factory()

else:

def default_if_none_converter(val):
if val is not None:
return val

return default

return default_if_none_converter

+ 12
- 0
venv/lib/python3.7/site-packages/attr/converters.pyi View File

@@ -0,0 +1,12 @@
from typing import TypeVar, Optional, Callable, overload
from . import _ConverterType

_T = TypeVar("_T")

def optional(
converter: _ConverterType[_T]
) -> _ConverterType[Optional[_T]]: ...
@overload
def default_if_none(default: _T) -> _ConverterType[_T]: ...
@overload
def default_if_none(*, factory: Callable[[], _T]) -> _ConverterType[_T]: ...

+ 15
- 0
venv/lib/python3.7/site-packages/attr/exceptions.pyi View File

@@ -0,0 +1,15 @@
from typing import Any

class FrozenInstanceError(AttributeError):
msg: str = ...

class AttrsAttributeNotFoundError(ValueError): ...
class NotAnAttrsClassError(ValueError): ...
class DefaultAlreadySetError(RuntimeError): ...
class UnannotatedAttributeError(RuntimeError): ...
class PythonTooOldError(RuntimeError): ...

class NotCallableError(TypeError):
msg: str = ...
value: Any = ...
def __init__(self, msg: str, value: Any) -> None: ...

+ 52
- 0
venv/lib/python3.7/site-packages/attr/filters.py View File

@@ -0,0 +1,52 @@
"""
Commonly useful filters for `attr.asdict`.
"""

from __future__ import absolute_import, division, print_function

from ._compat import isclass
from ._make import Attribute


def _split_what(what):
"""
Returns a tuple of `frozenset`s of classes and attributes.
"""
return (
frozenset(cls for cls in what if isclass(cls)),
frozenset(cls for cls in what if isinstance(cls, Attribute)),
)


def include(*what):
"""
Whitelist *what*.

:param what: What to whitelist.
:type what: `list` of `type` or `attr.Attribute`\\ s

:rtype: `callable`
"""
cls, attrs = _split_what(what)

def include_(attribute, value):
return value.__class__ in cls or attribute in attrs

return include_


def exclude(*what):
"""
Blacklist *what*.

:param what: What to blacklist.
:type what: `list` of classes or `attr.Attribute`\\ s.

:rtype: `callable`
"""
cls, attrs = _split_what(what)

def exclude_(attribute, value):
return value.__class__ not in cls and attribute not in attrs

return exclude_

+ 1
- 0
venv/lib/python3.7/site-packages/attrs-19.3.0.dist-info/INSTALLER View File

@@ -0,0 +1 @@
pip

+ 21
- 0
venv/lib/python3.7/site-packages/attrs-19.3.0.dist-info/LICENSE View File

@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2015 Hynek Schlawack

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

+ 229
- 0
venv/lib/python3.7/site-packages/attrs-19.3.0.dist-info/METADATA View File

@@ -0,0 +1,229 @@
Metadata-Version: 2.1
Name: attrs
Version: 19.3.0
Summary: Classes Without Boilerplate
Home-page: https://www.attrs.org/
Author: Hynek Schlawack
Author-email: hs@ox.cx
Maintainer: Hynek Schlawack
Maintainer-email: hs@ox.cx
License: MIT
Project-URL: Documentation, https://www.attrs.org/
Project-URL: Bug Tracker, https://github.com/python-attrs/attrs/issues
Project-URL: Source Code, https://github.com/python-attrs/attrs
Keywords: class,attribute,boilerplate
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Natural Language :: English
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
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 :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
Description-Content-Type: text/x-rst
Provides-Extra: azure-pipelines
Requires-Dist: coverage ; extra == 'azure-pipelines'
Requires-Dist: hypothesis ; extra == 'azure-pipelines'
Requires-Dist: pympler ; extra == 'azure-pipelines'
Requires-Dist: pytest (>=4.3.0) ; extra == 'azure-pipelines'
Requires-Dist: six ; extra == 'azure-pipelines'
Requires-Dist: zope.interface ; extra == 'azure-pipelines'
Requires-Dist: pytest-azurepipelines ; extra == 'azure-pipelines'
Provides-Extra: dev
Requires-Dist: coverage ; extra == 'dev'
Requires-Dist: hypothesis ; extra == 'dev'
Requires-Dist: pympler ; extra == 'dev'
Requires-Dist: pytest (>=4.3.0) ; extra == 'dev'
Requires-Dist: six ; extra == 'dev'
Requires-Dist: zope.interface ; extra == 'dev'
Requires-Dist: sphinx ; extra == 'dev'
Requires-Dist: pre-commit ; extra == 'dev'
Provides-Extra: docs
Requires-Dist: sphinx ; extra == 'docs'
Requires-Dist: zope.interface ; extra == 'docs'
Provides-Extra: tests
Requires-Dist: coverage ; extra == 'tests'
Requires-Dist: hypothesis ; extra == 'tests'
Requires-Dist: pympler ; extra == 'tests'
Requires-Dist: pytest (>=4.3.0) ; extra == 'tests'
Requires-Dist: six ; extra == 'tests'
Requires-Dist: zope.interface ; extra == 'tests'

.. image:: https://www.attrs.org/en/latest/_static/attrs_logo.png
:alt: attrs Logo

======================================
``attrs``: Classes Without Boilerplate
======================================

.. image:: https://readthedocs.org/projects/attrs/badge/?version=stable
:target: https://www.attrs.org/en/stable/?badge=stable
:alt: Documentation Status

.. image:: https://attrs.visualstudio.com/attrs/_apis/build/status/python-attrs.attrs?branchName=master
:target: https://attrs.visualstudio.com/attrs/_build/latest?definitionId=1&branchName=master
:alt: CI Status

.. image:: https://codecov.io/github/python-attrs/attrs/branch/master/graph/badge.svg
:target: https://codecov.io/github/python-attrs/attrs
:alt: Test Coverage

.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/psf/black
:alt: Code style: black

.. teaser-begin

``attrs`` is the Python package that will bring back the **joy** of **writing classes** by relieving you from the drudgery of implementing object protocols (aka `dunder <https://nedbatchelder.com/blog/200605/dunder.html>`_ methods).

Its main goal is to help you to write **concise** and **correct** software without slowing down your code.

.. -spiel-end-

For that, it gives you a class decorator and a way to declaratively define the attributes on that class:

.. -code-begin-

.. code-block:: pycon

>>> import attr

>>> @attr.s
... class SomeClass(object):
... a_number = attr.ib(default=42)
... list_of_numbers = attr.ib(factory=list)
...
... def hard_math(self, another_number):
... return self.a_number + sum(self.list_of_numbers) * another_number


>>> sc = SomeClass(1, [1, 2, 3])
>>> sc
SomeClass(a_number=1, list_of_numbers=[1, 2, 3])

>>> sc.hard_math(3)
19
>>> sc == SomeClass(1, [1, 2, 3])
True
>>> sc != SomeClass(2, [3, 2, 1])
True

>>> attr.asdict(sc)
{'a_number': 1, 'list_of_numbers': [1, 2, 3]}

>>> SomeClass()
SomeClass(a_number=42, list_of_numbers=[])

>>> C = attr.make_class("C", ["a", "b"])
>>> C("foo", "bar")
C(a='foo', b='bar')


After *declaring* your attributes ``attrs`` gives you:

- a concise and explicit overview of the class's attributes,
- a nice human-readable ``__repr__``,
- a complete set of comparison methods (equality and ordering),
- an initializer,
- and much more,

*without* writing dull boilerplate code again and again and *without* runtime performance penalties.

On Python 3.6 and later, you can often even drop the calls to ``attr.ib()`` by using `type annotations <https://www.attrs.org/en/latest/types.html>`_.

This gives you the power to use actual classes with actual types in your code instead of confusing ``tuple``\ s or `confusingly behaving <https://www.attrs.org/en/stable/why.html#namedtuples>`_ ``namedtuple``\ s.
Which in turn encourages you to write *small classes* that do `one thing well <https://www.destroyallsoftware.com/talks/boundaries>`_.
Never again violate the `single responsibility principle <https://en.wikipedia.org/wiki/Single_responsibility_principle>`_ just because implementing ``__init__`` et al is a painful drag.


.. -testimonials-

Testimonials
============

**Amber Hawkie Brown**, Twisted Release Manager and Computer Owl:

Writing a fully-functional class using attrs takes me less time than writing this testimonial.


**Glyph Lefkowitz**, creator of `Twisted <https://twistedmatrix.com/>`_, `Automat <https://pypi.org/project/Automat/>`_, and other open source software, in `The One Python Library Everyone Needs <https://glyph.twistedmatrix.com/2016/08/attrs.html>`_:

I’m looking forward to is being able to program in Python-with-attrs everywhere.
It exerts a subtle, but positive, design influence in all the codebases I’ve see it used in.


**Kenneth Reitz**, creator of `Requests <https://github.com/psf/requests>`_ (`on paper no less <https://twitter.com/hynek/status/866817877650751488>`_!):

attrs—classes for humans. I like it.


**Łukasz Langa**, creator of `Black <https://github.com/psf/black>`_, prolific Python core developer, and release manager for Python 3.8 and 3.9:

I'm increasingly digging your attr.ocity. Good job!


.. -end-

.. -project-information-

Getting Help
============

Please use the ``python-attrs`` tag on `StackOverflow <https://stackoverflow.com/questions/tagged/python-attrs>`_ to get help.

Answering questions of your fellow developers is also great way to help the project!


Project Information
===================

``attrs`` is released under the `MIT <https://choosealicense.com/licenses/mit/>`_ license,
its documentation lives at `Read the Docs <https://www.attrs.org/>`_,
the code on `GitHub <https://github.com/python-attrs/attrs>`_,
and the latest release on `PyPI <https://pypi.org/project/attrs/>`_.
It’s rigorously tested on Python 2.7, 3.4+, and PyPy.

We collect information on **third-party extensions** in our `wiki <https://github.com/python-attrs/attrs/wiki/Extensions-to-attrs>`_.
Feel free to browse and add your own!

If you'd like to contribute to ``attrs`` you're most welcome and we've written `a little guide <https://www.attrs.org/en/latest/contributing.html>`_ to get you started!


Release Information
===================

19.3.0 (2019-10-15)
-------------------

Changes
^^^^^^^

- Fixed ``auto_attribs`` usage when default values cannot be compared directly with ``==``, such as ``numpy`` arrays.
`#585 <https://github.com/python-attrs/attrs/issues/585>`_

`Full changelog <https://www.attrs.org/en/stable/changelog.html>`_.

Credits
=======

``attrs`` is written and maintained by `Hynek Schlawack <https://hynek.me/>`_.

The development is kindly supported by `Variomedia AG <https://www.variomedia.de/>`_.

A full list of contributors can be found in `GitHub's overview <https://github.com/python-attrs/attrs/graphs/contributors>`_.

It’s the spiritual successor of `characteristic <https://characteristic.readthedocs.io/>`_ and aspires to fix some of it clunkiness and unfortunate decisions.
Both were inspired by Twisted’s `FancyEqMixin <https://twistedmatrix.com/documents/current/api/twisted.python.util.FancyEqMixin.html>`_ but both are implemented using class decorators because `subclassing is bad for you <https://www.youtube.com/watch?v=3MNVP9-hglc>`_, m’kay?



+ 21
- 0
venv/lib/python3.7/site-packages/autobahn-19.11.1.dist-info/LICENSE View File

@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) Crossbar.io Technologies GmbH

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

+ 347
- 0
venv/lib/python3.7/site-packages/autobahn-19.11.1.dist-info/RECORD View File

@@ -0,0 +1,347 @@
autobahn/__init__.py,sha256=uCdcBR1rNLDCosowHs3ea1A1lH10lrbC_aPjM5YGjOM,1399
autobahn/__main__.py,sha256=vMSMsxDkAWFpIv-53lNBn9k7iFIstouSfLmJcTZPTtc,11114
autobahn/_version.py,sha256=nAupaY5VTtY8dIxAKX-Xn8RL_GqiKBfOKcwKZ7Ii_XM,1319
autobahn/exception.py,sha256=zJG4u2Y7iQdvBocW6EA0WYCCjB4s50lJw7nTUwwbKDA,1614
autobahn/util.py,sha256=Cu68EMPBGYN85_AvrVBY0E2StDiUwHVngCk1U9IfuGs,27599
autobahn/asyncio/__init__.py,sha256=EfiMPwA8Ivr-QPWKr1iuM5xpeb7S-n1UJyFeihRUnfA,2055
autobahn/asyncio/component.py,sha256=5BNTpptXPv1y4UfDURJ-nxX0BC2RfdT1nizBgo4VaME,16045
autobahn/asyncio/rawsocket.py,sha256=TVXD_CaJaWZ9Vfb7TiNiXNWoSZTSyu6-jlhpatw7Xd8,17259
autobahn/asyncio/util.py,sha256=GvrzlbVwIRU7v4EIt2AhPyK_p2eQ8TmyUZw7UqsTDdA,3297
autobahn/asyncio/wamp.py,sha256=2R7wr7VRYyknKID58ZHPAeTTSgBTrB-uiwLJPl7omDY,11247
autobahn/asyncio/websocket.py,sha256=EzHkmuQcPC8IdzbCddtAHh_FfIyOrpZ7BoLd-lpRh8o,12134
autobahn/asyncio/xbr.py,sha256=DSnL-qHXyU9O9Tz6QpguGDxN5t8vJDpaEwB_Y2OLNzg,3465
autobahn/asyncio/test/README,sha256=LB9qc37yrpi15mmHeOw9sJ7yu9Bzo0xxcXJD2IvNYjM,951
autobahn/asyncio/test/test_asyncio_rawsocket.py,sha256=SXo4IwYrka9jf_gl2bg4Gn7p5yfOXOEyj98hoGbSrbM,7713
autobahn/asyncio/test/test_asyncio_websocket.py,sha256=9MPJoVTWrYHBoI0dnB4wQYihU9Uu9hDL-GP3fzwXEIk,2401
autobahn/nvx/__init__.py,sha256=E2gqYZ596EK-HPfki680pP3KFimqfCCWVhQdzDYtH3c,1426
autobahn/nvx/_utf8validator.c,sha256=C6mpS9BVrkwyrfmhqnbdQXn8nMF_fpo8ZYGekaZreUA,17063
autobahn/nvx/_utf8validator.py,sha256=ADlNAm_kIUiOkKQnWfywd9d2JOEmJGeyGh0GF4bFcpk,2543
autobahn/nvx/test/test_utf8validator.py,sha256=_pAJPTbIW9hogD44BvsKXcGdUPswV811NptiFnITnLU,14213
autobahn/rawsocket/__init__.py,sha256=NhWjNyqDKUs_FqdWfLdMN5-ddQ8OrWaYok3_FRZSbJU,1293
autobahn/rawsocket/util.py,sha256=7TuuTgPyKcFNQkpPmxy2GYUcQAMagx7dKPIuODifLtk,5931
autobahn/rawsocket/test/__init__.py,sha256=NhWjNyqDKUs_FqdWfLdMN5-ddQ8OrWaYok3_FRZSbJU,1293
autobahn/rawsocket/test/test_rawsocket_url.py,sha256=orFompUzrWUw7QtgcrIDFss-ZycfYgUnfBsw-Utf6Zg,4982
autobahn/test/__init__.py,sha256=_drclixbeIOutvlA9xEKpg1NUa9t6ZVcRFkl8JIToBA,2471
autobahn/test/test_rng.py,sha256=J7_nux44GBRcvBHU3INgaglkEUDK_lreE91sLnl9XXQ,3873
autobahn/test/test_util.py,sha256=dBT7j-sca67xfI9lCUctjeRtELK_NwIwFDU-0F3h6Mg,1850
autobahn/twisted/__init__.py,sha256=af4M9V4yMKhAoAA9cZCNjBLOhccbi_0BSwk8YeZJVE0,3110
autobahn/twisted/choosereactor.py,sha256=8-kEWvufaLmlAxvYbHiLxR6CIezuzp_P1a3gdY72fCA,9042
autobahn/twisted/component.py,sha256=NJBsvuGn5OVog0KM7QLoFb6oDVmZKuGlHrgzF4uPfqo,15052
autobahn/twisted/cryptosign.py,sha256=FCi4fRGDDOJJZQqGyo32MypQzuLdQs-2Moz4SarY7Cs,5856
autobahn/twisted/forwarder.py,sha256=HGW35hGYBBHrRTzU9-K-EJth8uzriEgxAhscohfdzok,4695
autobahn/twisted/rawsocket.py,sha256=szK49XxxpeoSOBHQqB5uJtPLDBBSTSyfl8W1aLJ4zOQ,22903
autobahn/twisted/resource.py,sha256=Uobz7135OXu8ljkj6Kh1aBFydu7uUg7zrKTSQX7YFZA,7208
autobahn/twisted/util.py,sha256=mGaVwPAplcnd3ggtOYywpqUzwO9RhDsB3-kqaaM-2FE,5192
autobahn/twisted/wamp.py,sha256=iHrowZDebCnQ_G9mBmR2gu-f9nvDLQkNaPRxQlFDgOY,32347
autobahn/twisted/websocket.py,sha256=tEZ0sHI9d4cn9iHmyFdne1nKtd-Tw_0bF4VPSUm4vos,30162
autobahn/twisted/xbr.py,sha256=vAK3mNAGBJLQ-IBT16M3QL4l4VgoRhOu--PVP9I2va4,3834
autobahn/twisted/testing/__init__.py,sha256=JKkTGvbTkmEPNG5Eh83RcA27Tylmu0ZTUQa_Vx5fmhw,10000
autobahn/wamp/__init__.py,sha256=PezDFOWF7GIM63pZRXnsD6LgC8fhaaTHgrmFwBvY8vI,2317
autobahn/wamp/auth.py,sha256=r5mcqTTxe3lBineC-cz9hrD3qFeNqxilaLs5T-1U2zg,20164
autobahn/wamp/component.py,sha256=O5LrREX6CePgRmDUAYg07uj1U-s3e4Paz8hPhgoD1kI,37093
autobahn/wamp/cryptobox.py,sha256=lfo_cUTrqMq3imNY1uVp5eoZ_025W75V7wA6m-QlpBs,10673
autobahn/wamp/cryptosign.py,sha256=wFUeN99vN4qLJbMVNAkUnzST3Dhap16J7FwvkLMmjXg,21198
autobahn/wamp/exception.py,sha256=9teqpFXPJ3Gjlb0S7_irsCpXCLMLpUksiM8EEuAIpyw,10115
autobahn/wamp/interfaces.py,sha256=iXad4yNp4ul440jS534MzxWMtV7wW2iupwEw08Xidng,26914
autobahn/wamp/message.py,sha256=_oAsii5xTLDPG2AmQqIGu021fGz8TGmrEpX8foeoZs4,215716
autobahn/wamp/message_fbs.py,sha256=6NFttrOPlGdtSNBQ-375JezbDOo14kYR-vKrUhbjBFQ,4649
autobahn/wamp/protocol.py,sha256=uyEns1_ul27nkpTKFe8_hyhfVquxkPWUsRTeNAeP0ak,85576
autobahn/wamp/request.py,sha256=u0dk4eMIlMkKSe2BU2_SKyT_ds5PoqSVIItWjriRZAg,9559
autobahn/wamp/role.py,sha256=ojL8hqeyDB1fecD7GH5VGjo94rfg3NWBYtbblFz4CXM,10986
autobahn/wamp/serializer.py,sha256=2cSw2jeCZ5FHkaptt5O0ArFhVN8IXTs98qs9T2EnOdY,26307
autobahn/wamp/types.py,sha256=YL-qf_owVahxVpDKIbYhBC4Rr6itQq_d4aTxJV3Sv1o,52400
autobahn/wamp/uri.py,sha256=-fEI4eYF01S4p4U-2KJoQqIqKFNVs7L1ca0cQ2lv3P4,11613
autobahn/wamp/websocket.py,sha256=3yO5qrD3Yx2C0ya7BAWA542XXC3Lv_yIq3KsoAC1oqQ,11165
autobahn/wamp/gen/__init__.py,sha256=NhWjNyqDKUs_FqdWfLdMN5-ddQ8OrWaYok3_FRZSbJU,1293
autobahn/wamp/gen/schema/auth.bfbs,sha256=5NohfPH8xErVkCRyH00Rvj5vYXOyKt4B44-rvVWiFiM,12792
autobahn/wamp/gen/schema/pubsub.bfbs,sha256=SpSvTkNV_dlFIat08VO4-SojyJWRY0qyhszV2oBmDV8,8840
autobahn/wamp/gen/schema/roles.bfbs,sha256=Sjyzs0tFLDrbxNUvJov9Tyx_of7z9k2SHYYElsFer_8,8240
autobahn/wamp/gen/schema/rpc.bfbs,sha256=XZbU-v1BFD9tBT7Al4GuCWdAJOpVinHxXLwRfvw0Lp8,7664
autobahn/wamp/gen/schema/session.bfbs,sha256=Q-9TWiilL6qYGiNOewRoyeNx2BKAdUTBh2w017Ejtz0,15944
autobahn/wamp/gen/schema/types.bfbs,sha256=ih3tez-Jdgwx0V0N07jp4ordvJEiS-11SoHRuEQVndE,3736
autobahn/wamp/gen/schema/wamp.bfbs,sha256=QENoUkeKlGH2zrDDQOEaschawHAvGNKZvMySQPrdgQk,26856
autobahn/wamp/gen/wamp/Map.py,sha256=tAF0s5-5-g7YNOKintFpR1d4lUt2gEgYi0R7wRyDF1k,1208
autobahn/wamp/gen/wamp/Void.py,sha256=S9gG7Z1qe-c0bToR6c2OzhSU8ljvCksqiBFB6s9iljs,550
autobahn/wamp/gen/wamp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
autobahn/wamp/gen/wamp/proto/Abort.py,sha256=4zEG4LxLduCzuz-bi-vIHNltK1rANazICQiWZE3miUc,1249
autobahn/wamp/gen/wamp/proto/AnyMessage.py,sha256=GmCjxk29SVpDJIqklYkizaCnh2XTgMNq1HLx8IujnYQ,605
autobahn/wamp/gen/wamp/proto/AuthCraChallenge.py,sha256=SZVi5fJxDH3k6hEBmuH6TD3hLx2V8szcDIIi2P47iA8,2062
autobahn/wamp/gen/wamp/proto/AuthCraRequest.py,sha256=-GzXW3MeE3guUaHI6Mnvj6NClIwRFYHToaoP9Aq9jHk,611
autobahn/wamp/gen/wamp/proto/AuthCraWelcome.py,sha256=CscxVwes4tfiwJMHiFDjV8mDTWsmuSoEJI8DE-QOJXQ,611
autobahn/wamp/gen/wamp/proto/AuthCryptosignChallenge.py,sha256=_s6rx58ftx5Otl8vrjRRRz6xd4jpmhCKczzUzU8TXNQ,1049
autobahn/wamp/gen/wamp/proto/AuthCryptosignRequest.py,sha256=TEXT0Hr1XkSl0z5U48CiLl4gEovieIDumcCBoR2PlJU,1409
autobahn/wamp/gen/wamp/proto/AuthCryptosignWelcome.py,sha256=39bZjIyQNrGRx2-veF71fnC4zThO00pjrpDI1UQmbtI,653
autobahn/wamp/gen/wamp/proto/AuthFactor.py,sha256=Y1zNCZNRMeWV8IvsaNt-uxLI8-yDFZ2Uc0lzKt6mqIg,234
autobahn/wamp/gen/wamp/proto/AuthMethod.py,sha256=ZwkdO8-aitDwJLGY2vLbIrbrlg6gnyI5o86SMFXkiK8,222
autobahn/wamp/gen/wamp/proto/AuthMode.py,sha256=UWgMyhyNUPeu2xw4aqI-ow_a0cvBOfVQ4L0EdOjnvwg,149
autobahn/wamp/gen/wamp/proto/AuthScramChallenge.py,sha256=77CBgc_3tqNUb3yH80Icq003598p17GmN7KWxWzGTwc,2774
autobahn/wamp/gen/wamp/proto/AuthScramRequest.py,sha256=aQQye797PXkm1RjldhI0uCW6QvqVHkO4WkkbyuSwzSM,1355
autobahn/wamp/gen/wamp/proto/AuthScramWelcome.py,sha256=28xHstHV7V-Tu6-N9AnjmvxJSbnLm58k0sFCblyzAnw,997
autobahn/wamp/gen/wamp/proto/AuthTicketChallenge.py,sha256=90DIv5T_ccz_PjDww7mL5Rk3VIV9N4xvsOFcQXP4rhc,641
autobahn/wamp/gen/wamp/proto/AuthTicketRequest.py,sha256=ZrFj2sEItg5sYqimyfNMntPtBLfVUjrDuK80X1gjVSc,629
autobahn/wamp/gen/wamp/proto/AuthTicketWelcome.py,sha256=AxVrC6XudwUDaDZOUCFvPYoENszNWW53lPnnigDt1QY,629
autobahn/wamp/gen/wamp/proto/Authenticate.py,sha256=cPm08hvSQFrWJqOYfu_fTaaXY1j14a0gtRH6W4DSlq4,1443
autobahn/wamp/gen/wamp/proto/BrokerFeatures.py,sha256=U1VL0LMW4txZ9f0N27LsVJpzbdsrBjNeTYgKuS3jUJw,6251
autobahn/wamp/gen/wamp/proto/Call.py,sha256=VmrWRA5DBfA4gSjXn1-QKz4gnY4t4Wv9b8zZF0sKIM8,4541
autobahn/wamp/gen/wamp/proto/CalleeFeatures.py,sha256=wIYgWCA099izQKDEs6EPX8x6nsQqufeM7dIiAfej6UY,4559
autobahn/wamp/gen/wamp/proto/CallerFeatures.py,sha256=0BPek4PnoFDEMz4WegcfZFc_705ZEtKks1WhXO0sbnI,2966
autobahn/wamp/gen/wamp/proto/Cancel.py,sha256=P0-5iW6et2HXnj9AQDzGsp7gbWHflfJMA4TzUvkZS5E,1197
autobahn/wamp/gen/wamp/proto/CancelMode.py,sha256=vh5uzg0R1hO4R2WCQ4TzMjxqwwhp86Tc5mUCoEc_tlM,157
autobahn/wamp/gen/wamp/proto/Challenge.py,sha256=49tA5J4B5mKGT1kTodPZxEDn4SH7DuT8WHTzwesLwRc,1373
autobahn/wamp/gen/wamp/proto/ChannelBinding.py,sha256=M8qp-JHRwVu_AC_4fWdKor7rmNNRHw1iRETx_rOPvOE,153
autobahn/wamp/gen/wamp/proto/ClientRoles.py,sha256=2NUgfetpclNCFOJOl3wg5Q_N6dAy26sa3sVXvilonaY,2679
autobahn/wamp/gen/wamp/proto/DealerFeatures.py,sha256=GINWcy2mK4wiQT17mA1zLSc8ljVSNMAa2OcsPbwM0sE,5715
autobahn/wamp/gen/wamp/proto/Error.py,sha256=GIwH1ssVtK7nHuL9yl__gFj_lXRe063EwUqggfUdxek,4210
autobahn/wamp/gen/wamp/proto/Event.py,sha256=U-NF3jWWrtKrKCdqpVc3ozEKJpC5RbVZaYhUcieZSy4,9087
autobahn/wamp/gen/wamp/proto/EventReceived.py,sha256=XZHvzQyjdTzVOx9KPlJ1FFMHzFkMG2QEjyxq0ctBtZA,3720
autobahn/wamp/gen/wamp/proto/Goodbye.py,sha256=CuJ6K4g3DhsN31Rxq2gNm2BdCMo2Fsitc8sk2_Z-UVM,1609
autobahn/wamp/gen/wamp/proto/Hello.py,sha256=gwApzTi6xiFGW3E39zsZGkSm9WuzR8JpJgy82KBbAN0,4627
autobahn/wamp/gen/wamp/proto/HelloNew.py,sha256=7jnNPBeiT8ZMFkrnuCvsawo5CL-0svoG9RT7gTsewaw,5989
autobahn/wamp/gen/wamp/proto/Interrupt.py,sha256=Vr4NuGUVzh-F2AZUsCU60w4Aghult6w-AUQnttjtc54,1227
autobahn/wamp/gen/wamp/proto/Invocation.py,sha256=Mqcjaex_KNOzWRKUTrkUnyVGMPXs0pomHDFOHdNU6o0,6160
autobahn/wamp/gen/wamp/proto/InvocationPolicy.py,sha256=PzKHYeKYTt3vuPUyj260cPSGgXtMZZE0H0JiyMKkeGw,199
autobahn/wamp/gen/wamp/proto/Kdf.py,sha256=x9AXogMyCtV9pfBqBXEF6MAQhmQCuhm4koeGnEpfEm8,153
autobahn/wamp/gen/wamp/proto/Match.py,sha256=xPyjrehsQXn7qjSIPON2k1-XrigZj2u-R4iNNZSpoqQ,158
autobahn/wamp/gen/wamp/proto/Message.py,sha256=LsYjfelutuVJpPH5Wu5w9JyEjuptHb8uZ38bmRVtC5A,1321
autobahn/wamp/gen/wamp/proto/MessageType.py,sha256=aluiW50TmyPljbCDBtz6slTC75Qrx2KA28OSXylS_hE,610
autobahn/wamp/gen/wamp/proto/Payload.py,sha256=fmB6dDCwB-yVlGjWEYmK6affoF6rxVKcnFeuvDQdIvM,161
autobahn/wamp/gen/wamp/proto/Principal.py,sha256=8kLZEH-513EViBkB60XMaou-4meeF3h6_-0S6pp2PxE,1623
autobahn/wamp/gen/wamp/proto/Publish.py,sha256=smmlHJN8pXzMl6nkUKLL3kyG3Oby1BIdd0Aw3Inf9So,13155
autobahn/wamp/gen/wamp/proto/Published.py,sha256=Ih51BbhQWSSPQdoNjX-0NQYFFUpIlFmH0QXgXdQMy64,1257
autobahn/wamp/gen/wamp/proto/PublisherFeatures.py,sha256=uSoS1JazH32tEI082RZH5-8Iqa56Yzx5Z49oOCJWcAo,3124
autobahn/wamp/gen/wamp/proto/Register.py,sha256=9cTBlJpuKqdvegS0Bf5BElgDWUKNNqw8Pu_0WWYd_uM,2618
autobahn/wamp/gen/wamp/proto/Registered.py,sha256=THhRcMZzj0r-cDXaUT2k15KPEUvoE9H0_NGjP5oMfRg,1271
autobahn/wamp/gen/wamp/proto/Result.py,sha256=bReDBODwihT8ZKeZHjRgHTHA-oJtVy6dfC5yXVOJg_o,3885
autobahn/wamp/gen/wamp/proto/RouterRoles.py,sha256=9xco2KbV5qgAGmaKq7wsNJIrLgdMc1hFa663hqBscDk,1611
autobahn/wamp/gen/wamp/proto/Serializer.py,sha256=64D2_OlFMfiOTJpbY3PHqBeu7qcUVzGmFnOkXHOC6AA,227
autobahn/wamp/gen/wamp/proto/Subscribe.py,sha256=OgPOofEt6CRBIrx8oWBQWTAI1ct0SFCZ7Ec-2Mf-ABA,1932
autobahn/wamp/gen/wamp/proto/Subscribed.py,sha256=EXs_Q3-TXiA5NIidjLlnVTeSXmm7ddoVAOpx7ppPC7s,1271
autobahn/wamp/gen/wamp/proto/SubscriberFeatures.py,sha256=FWbBVXTBsYfNA1AyzkF11EseZOKJ75Xxw5h19wVTnb0,3956
autobahn/wamp/gen/wamp/proto/SubscriberReceived.py,sha256=TVZNMQu-jao1Beaw8S9bS7isXD4V67Ne5CePrBzbf_o,5023
autobahn/wamp/gen/wamp/proto/Unregister.py,sha256=n3fSOimgjCYVUTTC-I7XerGbaEhI3vCuv8C7TvFoDhI,1271
autobahn/wamp/gen/wamp/proto/Unregistered.py,sha256=5oRn_dWavEEo0hLfsIvzge6JEs41drZPICFEYnFhTvU,1649
autobahn/wamp/gen/wamp/proto/Unsubscribe.py,sha256=Rv0YhU2DlmhfvVaBfdL3yqcickQCeHEXVRX3mbWAdEU,1281
autobahn/wamp/gen/wamp/proto/Unsubscribed.py,sha256=sD6BlUodQMBWsB5XXqTRoHdOdJjPNsWL1JNqQHYvkjQ,1649
autobahn/wamp/gen/wamp/proto/Welcome.py,sha256=MMkF8ebOTgnNhG_draW6WwdwhgN022UHPtpGWECRDNY,4669
autobahn/wamp/gen/wamp/proto/Yield.py,sha256=bZmFHORjHR3NhOB5UJ4K3rbyUSAzP2KViKRPA3p8A_0,3528
autobahn/wamp/gen/wamp/proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
autobahn/wamp/test/__init__.py,sha256=NhWjNyqDKUs_FqdWfLdMN5-ddQ8OrWaYok3_FRZSbJU,1293
autobahn/wamp/test/test_auth.py,sha256=mHdNWCu46tY9ziMDMrxMYLaqpWclLRIZ8HynBHy4xQ0,9982
autobahn/wamp/test/test_component.py,sha256=U0F5vQcVMRIbsW5M-A_lbVGt7fTGVpMm6jc0R8b272s,7636
autobahn/wamp/test/test_component_aio.py,sha256=AhmADJBd4kbPJaHfDgdj9cLHffC3GB0eiqUjn-L32i8,6133
autobahn/wamp/test/test_cryptobox.py,sha256=8us4P5Qb382rmAPX9HJlbjSothufX_w-Axi_Glpm2Co,1594
autobahn/wamp/test/test_cryptosign.py,sha256=_jAyfjR2gUKvZoDv5J28hYMIoBJeKoX_A4mgkDna_rY,5056
autobahn/wamp/test/test_exception.py,sha256=SxaFxSKNqxL0sCXIkpgfX17WaGWIPnhFkmCnMwhD6m4,2277
autobahn/wamp/test/test_message.py,sha256=-oj55oc_8DIDLxHoB0UWfux_DiafVDkWPdH7HsIguGk,48434
autobahn/wamp/test/test_protocol.py,sha256=mY3UNpX17BrRgd3MsoAeqctIPDdX9SRtfj2jTUm-suc,41982
autobahn/wamp/test/test_protocol_peer.py,sha256=hDfL36jafVG1ni3QrUu9j0oKYZd3bFt3cy-dhtXlY8U,4484
autobahn/wamp/test/test_runner.py,sha256=fbzE6RSXWnH6KNDYR8OSVC7h0w9HKJC37zgVVh_915s,9280
autobahn/wamp/test/test_serializer.py,sha256=0RzcU-AsgVQ-lxTeyUxmsBVE9ggspoj61IRlXDNVuSw,11222
autobahn/wamp/test/test_uri_pattern.py,sha256=8RermiOXm_KKNfCF5BsTbE6mXYhUABX0b8V0rjuaKwY,24728
autobahn/wamp/test/test_user_handler_errors.py,sha256=mjVdWnRPkxoocmmk4cTsJO_ppnXquOwEnPmepWkMIVY,16020
autobahn/wamp/test/test_websocket.py,sha256=gYNEzVKthy8PhWiBGxUrwLNKlxtG_izlIKnA1w9YTWE,1783
autobahn/websocket/__init__.py,sha256=psmYUAHzor87GFkLEegMXfi0M_QxtliaTBo0yL278WA,1751
autobahn/websocket/compress.py,sha256=oijEK_PGQ0WB1dRmVAn8_8hm3Q8Sb29_9CY34JZe2JQ,4606
autobahn/websocket/compress_base.py,sha256=1mx7Chhonb2SjgAbtDCRp2_6wSQYlrNnwn5xrBzmNHU,2146
autobahn/websocket/compress_bzip2.py,sha256=uXH6ABvkdHe4heIUUbdSIHAyG3h7j4YLHmyvgKDWyng,18368
autobahn/websocket/compress_deflate.py,sha256=_6CIpzYZY95jDstXVGFICvSuDsWfGQO0TnVhVsEDZMg,29930
autobahn/websocket/compress_snappy.py,sha256=NR-a90iCb1wwybLvdRxCJSkeHtmcGSZWucD6gltMreA,16979
autobahn/websocket/interfaces.py,sha256=5kNhHo7qbZNG0gMmEMwJySxj4quBvU1MBtcG6H0_B4A,30069
autobahn/websocket/protocol.py,sha256=Yo5sYF-LdgYDXZ-mAyvBPu2CM2pOaZ9aLFmT6DRRqzY,162502
autobahn/websocket/types.py,sha256=Pbw7sNulOg3xKiDcmy8qOHUhfBh4WCNLzC0ZyRJd898,15313
autobahn/websocket/utf8validator.py,sha256=zrWgsbNqnOJ5_DolmUJ4q_lyM748sNu6z7goOlQfRTQ,10472
autobahn/websocket/util.py,sha256=XVBGXR4ayMYvvX29sHwPhz4meWwHcI-0gmUWy834eHI,6734
autobahn/websocket/xormasker.py,sha256=XF9idKxou9DHNFYuRlossm_XLQW2SBydWa43skf2gbI,4546
autobahn/websocket/test/__init__.py,sha256=NhWjNyqDKUs_FqdWfLdMN5-ddQ8OrWaYok3_FRZSbJU,1293
autobahn/websocket/test/test_protocol.py,sha256=cEm2g69azxh_oNKnBW2rtZFjhoRvt9isoqCshGWlyhM,9523
autobahn/websocket/test/test_websocket.py,sha256=oz-V1T31euVBqDgc6JOPRdVheBWpOU4Uy1GZfIvV8Ck,14095
autobahn/websocket/test/test_websocket_url.py,sha256=1XU_f6LXYIzIc35M0RpdJ02jNTy_nZ10uqneEGnPieY,5455
autobahn/xbr/__init__.py,sha256=KqqlDFiim1xYbwkRdkC_MZRFvbIsmq5l0n7EcUZXFcc,6543
autobahn/xbr/_abi.py,sha256=ZbdUEKmwKcB3Q3Ls-O5zsX8MlsC2BPub32piymQ5was,3169
autobahn/xbr/_blockchain.py,sha256=K5Yw4p0XzM2GHhtSifOkOdN9MtpZxqFxn8exz2DC9xU,7314
autobahn/xbr/_buyer.py,sha256=t_OTeSWVJqvDi8tu4JouhRfKrFHRg7T2x_rngUzZQ3M,25629
autobahn/xbr/_interfaces.py,sha256=KH3GryyUnnwmiYuXOQ9tcrSRJYNN-MI_8gPq8cC_FhQ,4572
autobahn/xbr/_mnemonic.py,sha256=omcP6F5W3S_j9d636EBuQUtJRol79F8U4sqDuIsac2Q,6112
autobahn/xbr/_seller.py,sha256=-cYXjmwg0mCTkSJjtqjGFudUqW8A2vmaZkxqXo2Th2c,31311
autobahn/xbr/_util.py,sha256=9KtQBAU42MyqIdKlJJvffYPaPc_SDMxLo3Bv2hN9e0s,7775
autobahn/xbr/contracts/ECDSA.json,sha256=EVvH_fkEzyji3VSDgq88_YzJf2d-iAzuBCde_PWN9Bo,102692
autobahn/xbr/contracts/ERC20.json,sha256=WE4H06FGvmOUUoJXpafU3OAuu5QOqXTOV6Uz4uFwqgE,485849
autobahn/xbr/contracts/ERC20Detailed.json,sha256=EKI-ACQu6D5kUELGLv13aqg6Qg3z5lSgHHWivIpBR_o,54285
autobahn/xbr/contracts/IERC20.json,sha256=0H34Yqdivc9wuqCfcUWfYhleEZXNKScn_jhjEFCsqJE,69299
autobahn/xbr/contracts/Migrations.json,sha256=-y8tyFGmlIpxiQ8UVnsVXyqog_Z8PstMjkQkEIOkfm8,54004
autobahn/xbr/contracts/Roles.json,sha256=VE1FmcWS0sIZhExrlVQSjYgvbMEWrK_iOe_yuB080Qw,90764
autobahn/xbr/contracts/SafeMath.json,sha256=ZGXMQAWIl8PbPKCS4fGk6zorp2YU0uWiunSamk7m05M,145860
autobahn/xbr/contracts/XBRChannel.json,sha256=lyf2lGIviSAipky82hISfmJtyhYkmhu7YVhRtD8FbFo,785283
autobahn/xbr/contracts/XBRMaintained.json,sha256=M_ORh2fC3PrLxls7ppyeAJIjqRcTqDPN3MqIrFdXd6s,97235
autobahn/xbr/contracts/XBRNetwork.json,sha256=Kb-yQCubto1yWZeYnxRTA41EofAkeBkGf3yiC2uq8mU,2294558
autobahn/xbr/contracts/XBRNetworkProxy.json,sha256=80LV0bjKi4_plCXZD--S7-fq8glRwG1S32qeXx9UZXQ,28872
autobahn/xbr/contracts/XBRToken.json,sha256=eBux5eHKi_ZZqAq4-CEOBWDsVUhCzQxa_t6GyDDriuU,68488
twisted/plugins/autobahn_endpoints.py,sha256=PwwMP1IYX-2KVAzxm4LYpVc8rpSaPGlcgSKfEFrKiYc,6389
twisted/plugins/autobahn_twistd.py,sha256=9mccXpFlai3XpoYHAtxAynedzogaLb6XM7-Qb9IF5yQ,1566
autobahn-19.11.1.dist-info/LICENSE,sha256=A4fu_OVwRT2qpgYz8oZ2ADcx7soostCgBxxijjoABO8,1091
autobahn-19.11.1.dist-info/METADATA,sha256=TZrnK8k_AAaXCE7n_tSLnKy-AdUk96rc3KnW0yXEKSw,16840
autobahn-19.11.1.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110
autobahn-19.11.1.dist-info/entry_points.txt,sha256=pOQzqt1oaJ0ZAex4ZEdquHVbriLGGB6DicT_1O1Y96w,50
autobahn-19.11.1.dist-info/top_level.txt,sha256=i67H6_FOEnZCuafCKor2-4scMopj2B4VZiqG_K2709g,17
autobahn-19.11.1.dist-info/RECORD,,
../../../bin/wamp,sha256=f5CNfXC8MlqzFh6qfB3IICZmkBsawPVDZSpwxSPZIWU,272
autobahn-19.11.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
autobahn/websocket/test/__pycache__/test_protocol.cpython-37.pyc,,
autobahn/websocket/test/__pycache__/test_websocket_url.cpython-37.pyc,,
autobahn/websocket/test/__pycache__/__init__.cpython-37.pyc,,
autobahn/websocket/test/__pycache__/test_websocket.cpython-37.pyc,,
autobahn/websocket/__pycache__/util.cpython-37.pyc,,
autobahn/websocket/__pycache__/interfaces.cpython-37.pyc,,
autobahn/websocket/__pycache__/compress_base.cpython-37.pyc,,
autobahn/websocket/__pycache__/types.cpython-37.pyc,,
autobahn/websocket/__pycache__/compress.cpython-37.pyc,,
autobahn/websocket/__pycache__/compress_bzip2.cpython-37.pyc,,
autobahn/websocket/__pycache__/protocol.cpython-37.pyc,,
autobahn/websocket/__pycache__/compress_deflate.cpython-37.pyc,,
autobahn/websocket/__pycache__/xormasker.cpython-37.pyc,,
autobahn/websocket/__pycache__/__init__.cpython-37.pyc,,
autobahn/websocket/__pycache__/utf8validator.cpython-37.pyc,,
autobahn/websocket/__pycache__/compress_snappy.cpython-37.pyc,,
autobahn/test/__pycache__/test_rng.cpython-37.pyc,,
autobahn/test/__pycache__/test_util.cpython-37.pyc,,
autobahn/test/__pycache__/__init__.cpython-37.pyc,,
autobahn/xbr/__pycache__/_interfaces.cpython-37.pyc,,
autobahn/xbr/__pycache__/_util.cpython-37.pyc,,
autobahn/xbr/__pycache__/_seller.cpython-37.pyc,,
autobahn/xbr/__pycache__/_blockchain.cpython-37.pyc,,
autobahn/xbr/__pycache__/_abi.cpython-37.pyc,,
autobahn/xbr/__pycache__/_mnemonic.cpython-37.pyc,,
autobahn/xbr/__pycache__/__init__.cpython-37.pyc,,
autobahn/xbr/__pycache__/_buyer.cpython-37.pyc,,
autobahn/rawsocket/test/__pycache__/test_rawsocket_url.cpython-37.pyc,,
autobahn/rawsocket/test/__pycache__/__init__.cpython-37.pyc,,
autobahn/rawsocket/__pycache__/util.cpython-37.pyc,,
autobahn/rawsocket/__pycache__/__init__.cpython-37.pyc,,
autobahn/twisted/__pycache__/util.cpython-37.pyc,,
autobahn/twisted/__pycache__/forwarder.cpython-37.pyc,,
autobahn/twisted/__pycache__/websocket.cpython-37.pyc,,
autobahn/twisted/__pycache__/resource.cpython-37.pyc,,
autobahn/twisted/__pycache__/rawsocket.cpython-37.pyc,,
autobahn/twisted/__pycache__/wamp.cpython-37.pyc,,
autobahn/twisted/__pycache__/component.cpython-37.pyc,,
autobahn/twisted/__pycache__/xbr.cpython-37.pyc,,
autobahn/twisted/__pycache__/choosereactor.cpython-37.pyc,,
autobahn/twisted/__pycache__/cryptosign.cpython-37.pyc,,
autobahn/twisted/__pycache__/__init__.cpython-37.pyc,,
autobahn/twisted/testing/__pycache__/__init__.cpython-37.pyc,,
autobahn/__pycache__/util.cpython-37.pyc,,
autobahn/__pycache__/_version.cpython-37.pyc,,
autobahn/__pycache__/__main__.cpython-37.pyc,,
autobahn/__pycache__/exception.cpython-37.pyc,,
autobahn/__pycache__/__init__.cpython-37.pyc,,
autobahn/nvx/test/__pycache__/test_utf8validator.cpython-37.pyc,,
autobahn/nvx/__pycache__/_utf8validator.cpython-37.pyc,,
autobahn/nvx/__pycache__/__init__.cpython-37.pyc,,
autobahn/wamp/test/__pycache__/test_message.cpython-37.pyc,,
autobahn/wamp/test/__pycache__/test_exception.cpython-37.pyc,,
autobahn/wamp/test/__pycache__/test_runner.cpython-37.pyc,,
autobahn/wamp/test/__pycache__/test_cryptobox.cpython-37.pyc,,
autobahn/wamp/test/__pycache__/test_component_aio.cpython-37.pyc,,
autobahn/wamp/test/__pycache__/test_protocol.cpython-37.pyc,,
autobahn/wamp/test/__pycache__/test_component.cpython-37.pyc,,
autobahn/wamp/test/__pycache__/test_auth.cpython-37.pyc,,
autobahn/wamp/test/__pycache__/test_cryptosign.cpython-37.pyc,,
autobahn/wamp/test/__pycache__/test_protocol_peer.cpython-37.pyc,,
autobahn/wamp/test/__pycache__/test_serializer.cpython-37.pyc,,
autobahn/wamp/test/__pycache__/test_user_handler_errors.cpython-37.pyc,,
autobahn/wamp/test/__pycache__/test_uri_pattern.cpython-37.pyc,,
autobahn/wamp/test/__pycache__/__init__.cpython-37.pyc,,
autobahn/wamp/test/__pycache__/test_websocket.cpython-37.pyc,,
autobahn/wamp/__pycache__/serializer.cpython-37.pyc,,
autobahn/wamp/__pycache__/interfaces.cpython-37.pyc,,
autobahn/wamp/__pycache__/uri.cpython-37.pyc,,
autobahn/wamp/__pycache__/websocket.cpython-37.pyc,,
autobahn/wamp/__pycache__/request.cpython-37.pyc,,
autobahn/wamp/__pycache__/message.cpython-37.pyc,,
autobahn/wamp/__pycache__/message_fbs.cpython-37.pyc,,
autobahn/wamp/__pycache__/types.cpython-37.pyc,,
autobahn/wamp/__pycache__/component.cpython-37.pyc,,
autobahn/wamp/__pycache__/auth.cpython-37.pyc,,
autobahn/wamp/__pycache__/role.cpython-37.pyc,,
autobahn/wamp/__pycache__/cryptosign.cpython-37.pyc,,
autobahn/wamp/__pycache__/exception.cpython-37.pyc,,
autobahn/wamp/__pycache__/protocol.cpython-37.pyc,,
autobahn/wamp/__pycache__/__init__.cpython-37.pyc,,
autobahn/wamp/__pycache__/cryptobox.cpython-37.pyc,,
autobahn/wamp/gen/__pycache__/__init__.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Payload.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Publish.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/AuthScramChallenge.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Principal.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/BrokerFeatures.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Unsubscribe.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Hello.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Register.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Serializer.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/ClientRoles.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/ChannelBinding.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/AuthTicketRequest.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/AuthTicketWelcome.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Event.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/CalleeFeatures.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Result.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Invocation.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Welcome.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Message.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Call.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Published.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Abort.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/AuthScramRequest.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Unregister.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/AuthScramWelcome.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/AuthTicketChallenge.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/AuthMode.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Yield.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/InvocationPolicy.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/AuthMethod.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Unregistered.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Subscribed.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/SubscriberFeatures.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/DealerFeatures.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/RouterRoles.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Registered.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Unsubscribed.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/AuthCraWelcome.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/AuthCraRequest.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Match.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/MessageType.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/EventReceived.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Challenge.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/PublisherFeatures.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/AuthCryptosignChallenge.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/CallerFeatures.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Subscribe.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Interrupt.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/HelloNew.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Authenticate.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/AuthCraChallenge.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Kdf.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/AnyMessage.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/AuthCryptosignRequest.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/AuthCryptosignWelcome.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/AuthFactor.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Goodbye.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/CancelMode.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Error.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/__init__.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/SubscriberReceived.cpython-37.pyc,,
autobahn/wamp/gen/wamp/proto/__pycache__/Cancel.cpython-37.pyc,,
autobahn/wamp/gen/wamp/__pycache__/Map.cpython-37.pyc,,
autobahn/wamp/gen/wamp/__pycache__/Void.cpython-37.pyc,,
autobahn/wamp/gen/wamp/__pycache__/__init__.cpython-37.pyc,,
autobahn/asyncio/test/__pycache__/test_asyncio_websocket.cpython-37.pyc,,
autobahn/asyncio/test/__pycache__/test_asyncio_rawsocket.cpython-37.pyc,,
autobahn/asyncio/__pycache__/util.cpython-37.pyc,,
autobahn/asyncio/__pycache__/websocket.cpython-37.pyc,,
autobahn/asyncio/__pycache__/rawsocket.cpython-37.pyc,,
autobahn/asyncio/__pycache__/wamp.cpython-37.pyc,,
autobahn/asyncio/__pycache__/component.cpython-37.pyc,,
autobahn/asyncio/__pycache__/xbr.cpython-37.pyc,,
autobahn/asyncio/__pycache__/__init__.cpython-37.pyc,,
twisted/plugins/__pycache__/autobahn_endpoints.cpython-37.pyc,,
twisted/plugins/__pycache__/autobahn_twistd.cpython-37.pyc,,

+ 27
- 0
venv/lib/python3.7/site-packages/autobahn/_version.py View File

@@ -0,0 +1,27 @@
###############################################################################
#
# The MIT License (MIT)
#
# Copyright (c) Crossbar.io Technologies GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################

__version__ = u'19.11.1'

+ 505
- 0
venv/lib/python3.7/site-packages/autobahn/asyncio/rawsocket.py View File

@@ -0,0 +1,505 @@
###############################################################################
#
# The MIT License (MIT)
#
# Copyright (c) Crossbar.io Technologies GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################

from __future__ import absolute_import

try:
import asyncio
except ImportError:
# trollious for py2 support - however it has been deprecated
import trollius as asyncio
import struct
import math

from autobahn.util import public, _LazyHexFormatter
from autobahn.wamp.exception import ProtocolError, SerializationError, TransportLost
from autobahn.asyncio.util import peer2str, get_serializers
import txaio

__all__ = (
'WampRawSocketServerProtocol',
'WampRawSocketClientProtocol',
'WampRawSocketServerFactory',
'WampRawSocketClientFactory'
)

txaio.use_asyncio()

FRAME_TYPE_DATA = 0
FRAME_TYPE_PING = 1
FRAME_TYPE_PONG = 2

MAGIC_BYTE = 0x7F


class PrefixProtocol(asyncio.Protocol):

prefix_format = '!L'
prefix_length = struct.calcsize(prefix_format)
max_length = 16 * 1024 * 1024
max_length_send = max_length
log = txaio.make_logger() # @UndefinedVariable

def connection_made(self, transport):
self.transport = transport
peer = transport.get_extra_info('peername')
self.peer = peer2str(peer)
self.log.debug('RawSocker Asyncio: Connection made with peer {peer}', peer=self.peer)
self._buffer = b''
self._header = None
self._wait_closed = txaio.create_future()

@property
def is_closed(self):
if hasattr(self, '_wait_closed'):
return self._wait_closed
else:
f = txaio.create_future()
f.set_result(True)
return f

def connection_lost(self, exc):
self.log.debug('RawSocker Asyncio: Connection lost')
self.transport = None
self._wait_closed.set_result(True)
self._on_connection_lost(exc)

def _on_connection_lost(self, exc):
pass

def protocol_error(self, msg):
self.log.error(msg)
self.transport.close()

def sendString(self, data):
l = len(data)
if l > self.max_length_send:
raise ValueError('Data too big')
header = struct.pack(self.prefix_format, len(data))
self.transport.write(header)
self.transport.write(data)

def ping(self, data):
raise NotImplementedError()

def pong(self, data):
raise NotImplementedError()

def data_received(self, data):
self._buffer += data
pos = 0
remaining = len(self._buffer)
while remaining >= self.prefix_length:
# do not recalculate header if available from previous call
if self._header:
frame_type, frame_length = self._header
else:
header = self._buffer[pos:pos + self.prefix_length]
frame_type = ord(header[0:1]) & 0b00000111
if frame_type > FRAME_TYPE_PONG:
self.protocol_error('Invalid frame type')
return
frame_length = struct.unpack(self.prefix_format, b'\0' + header[1:])[0]
if frame_length > self.max_length:
self.protocol_error('Frame too big')
return

if remaining - self.prefix_length >= frame_length:
self._header = None
pos += self.prefix_length
remaining -= self.prefix_length
data = self._buffer[pos:pos + frame_length]
pos += frame_length
remaining -= frame_length

if frame_type == FRAME_TYPE_DATA:
self.stringReceived(data)
elif frame_type == FRAME_TYPE_PING:
self.ping(data)
elif frame_type == FRAME_TYPE_PONG:
self.pong(data)
else:
# save heaader
self._header = frame_type, frame_length
break

self._buffer = self._buffer[pos:]

def stringReceived(self, data):
raise NotImplementedError()


class RawSocketProtocol(PrefixProtocol):

def __init__(self):
max_size = None
if max_size:
exp = int(math.ceil(math.log(max_size, 2))) - 9
if exp > 15:
raise ValueError('Maximum length is 16M')
self.max_length = 2**(exp + 9)
self._length_exp = exp
else:
self._length_exp = 15
self.max_length = 2**24

def connection_made(self, transport):
PrefixProtocol.connection_made(self, transport)
self._handshake_done = False

def _on_handshake_complete(self):
raise NotImplementedError()

def parse_handshake(self):
buf = bytearray(self._buffer[:4])
if buf[0] != MAGIC_BYTE:
raise HandshakeError('Invalid magic byte in handshake')
return
ser = buf[1] & 0x0F
lexp = buf[1] >> 4
self.max_length_send = 2**(lexp + 9)
if buf[2] != 0 or buf[3] != 0:
raise HandshakeError('Reserved bytes must be zero')
return ser, lexp

def process_handshake(self):
raise NotImplementedError()

def data_received(self, data):
self.log.debug('RawSocker Asyncio: data received {data}', data=_LazyHexFormatter(data))
if self._handshake_done:
return PrefixProtocol.data_received(self, data)
else:
self._buffer += data
if len(self._buffer) >= 4:
try:
self.process_handshake()
except HandshakeError as e:
self.protocol_error('Handshake error : {err}'.format(err=e))
return
self._handshake_done = True
self._on_handshake_complete()
data = self._buffer[4:]
self._buffer = b''
if data:
PrefixProtocol.data_received(self, data)


ERR_SERIALIZER_UNSUPPORTED = 1

ERRMAP = {
0: "illegal (must not be used)",
1: "serializer unsupported",
2: "maximum message length unacceptable",
3: "use of reserved bits (unsupported feature)",
4: "maximum connection count reached"
}


class HandshakeError(Exception):
def __init__(self, msg, code=0):
Exception.__init__(self, msg if not code else msg + ' : %s' % ERRMAP.get(code))


class RawSocketClientProtocol(RawSocketProtocol):

def check_serializer(self, ser_id):
return True

def process_handshake(self):
ser_id, err = self.parse_handshake()
if ser_id == 0:
raise HandshakeError('Server returned handshake error', err)
if self.serializer_id != ser_id:
raise HandshakeError('Server returned different serializer {0} then requested {1}'
.format(ser_id, self.serializer_id))

@property
def serializer_id(self):
raise NotImplementedError()

def connection_made(self, transport):
RawSocketProtocol.connection_made(self, transport)
# start handshake
hs = bytes(bytearray([MAGIC_BYTE,
self._length_exp << 4 | self.serializer_id,
0, 0]))
transport.write(hs)
self.log.debug('RawSocket Asyncio: Client handshake sent')


class RawSocketServerProtocol(RawSocketProtocol):

def supports_serializer(self, ser_id):
raise NotImplementedError()

def process_handshake(self):
def send_response(lexp, ser_id):
b2 = lexp << 4 | (ser_id & 0x0f)
self.transport.write(bytes(bytearray([MAGIC_BYTE, b2, 0, 0])))
ser_id, _lexp = self.parse_handshake()
if not self.supports_serializer(ser_id):
send_response(ERR_SERIALIZER_UNSUPPORTED, 0)
raise HandshakeError('Serializer unsupported : {ser_id}'.format(ser_id=ser_id))
send_response(self._length_exp, ser_id)


# this is transport independent part of WAMP protocol
class WampRawSocketMixinGeneral(object):

def _on_handshake_complete(self):
self.log.debug("WampRawSocketProtocol: Handshake complete")
try:
self._session = self.factory._factory()
self._session.onOpen(self)
except Exception as e:
# Exceptions raised in onOpen are fatal ..
self.log.warn("WampRawSocketProtocol: ApplicationSession constructor / onOpen raised ({err})", err=e)
self.abort()
else:
self.log.info("ApplicationSession started.")

def stringReceived(self, payload):
self.log.debug("WampRawSocketProtocol: RX octets: {octets}", octets=_LazyHexFormatter(payload))
try:
for msg in self._serializer.unserialize(payload):
self.log.debug("WampRawSocketProtocol: RX WAMP message: {msg}", msg=msg)
self._session.onMessage(msg)

except ProtocolError as e:
self.log.warn("WampRawSocketProtocol: WAMP Protocol Error ({err}) - aborting connection", err=e)
self.abort()

except Exception as e:
self.log.warn("WampRawSocketProtocol: WAMP Internal Error ({err}) - aborting connection", err=e)
self.abort()

def send(self, msg):
"""
Implements :func:`autobahn.wamp.interfaces.ITransport.send`
"""
if self.isOpen():
self.log.debug("WampRawSocketProtocol: TX WAMP message: {msg}", msg=msg)
try:
payload, _ = self._serializer.serialize(msg)
except Exception as e:
# all exceptions raised from above should be serialization errors ..
raise SerializationError("WampRawSocketProtocol: unable to serialize WAMP application payload ({0})"
.format(e))
else:
self.sendString(payload)
self.log.debug("WampRawSocketProtocol: TX octets: {octets}", octets=_LazyHexFormatter(payload))
else:
raise TransportLost()

def isOpen(self):
"""
Implements :func:`autobahn.wamp.interfaces.ITransport.isOpen`
"""
return hasattr(self, '_session') and self._session is not None


# this is asyncio dependent part of WAMP protocol
class WampRawSocketMixinAsyncio(object):
"""
Base class for asyncio-based WAMP-over-RawSocket protocols.
"""

def _on_connection_lost(self, exc):
try:
wasClean = exc is None
self._session.onClose(wasClean)
except Exception as e:
# silently ignore exceptions raised here ..
self.log.warn("WampRawSocketProtocol: ApplicationSession.onClose raised ({err})", err=e)
self._session = None

def close(self):
"""
Implements :func:`autobahn.wamp.interfaces.ITransport.close`
"""
if self.isOpen():
self.transport.close()
else:
raise TransportLost()

def abort(self):
"""
Implements :func:`autobahn.wamp.interfaces.ITransport.abort`
"""
if self.isOpen():
if hasattr(self.transport, 'abort'):
# ProcessProtocol lacks abortConnection()
self.transport.abort()
else:
self.transport.close()
else:
raise TransportLost()


@public
class WampRawSocketServerProtocol(WampRawSocketMixinGeneral, WampRawSocketMixinAsyncio, RawSocketServerProtocol):
"""
asyncio-based WAMP-over-RawSocket server protocol.

Implements:

* :class:`autobahn.wamp.interfaces.ITransport`
"""

def supports_serializer(self, ser_id):
if ser_id in self.factory._serializers:
self._serializer = self.factory._serializers[ser_id]()
self.log.debug(
"WampRawSocketProtocol: client wants to use serializer '{serializer}'",
serializer=ser_id,
)
return True
else:
self.log.debug(
"WampRawSocketProtocol: opening handshake - no suitable serializer found (client requested {serializer}, and we have {serializers}",
serializer=ser_id,
serializers=self.factory._serializers.keys(),
)
self.abort()
return False

def get_channel_id(self, channel_id_type=u'tls-unique'):
"""
Implements :func:`autobahn.wamp.interfaces.ITransport.get_channel_id`
"""
return None
# return transport_channel_id(self.transport, is_server=True, channel_id_type=channel_id_type)


@public
class WampRawSocketClientProtocol(WampRawSocketMixinGeneral, WampRawSocketMixinAsyncio, RawSocketClientProtocol):
"""
asyncio-based WAMP-over-RawSocket client protocol.

Implements:

* :class:`autobahn.wamp.interfaces.ITransport`
"""

@property
def serializer_id(self):
if not hasattr(self, '_serializer'):
self._serializer = self.factory._serializer
return self._serializer.RAWSOCKET_SERIALIZER_ID

def get_channel_id(self, channel_id_type=u'tls-unique'):
"""
Implements :func:`autobahn.wamp.interfaces.ITransport.get_channel_id`
"""
return None
# return transport_channel_id(self.transport, is_server=False, channel_id_type=channel_id_type)


class WampRawSocketFactory(object):
"""
Adapter class for asyncio-based WebSocket client and server factories.def dataReceived(self, data):
"""

log = txaio.make_logger()

@public
def __call__(self):
proto = self.protocol()
proto.factory = self
return proto


@public
class WampRawSocketServerFactory(WampRawSocketFactory):
"""
asyncio-based WAMP-over-RawSocket server protocol factory.
"""
protocol = WampRawSocketServerProtocol

def __init__(self, factory, serializers=None):
"""

:param factory: A callable that produces instances that implement
:class:`autobahn.wamp.interfaces.ITransportHandler`
:type factory: callable

:param serializers: A list of WAMP serializers to use (or ``None``
for all available serializers).
:type serializers: list of objects implementing
:class:`autobahn.wamp.interfaces.ISerializer`
"""
if callable(factory):
self._factory = factory
else:
self._factory = lambda: factory

# when no serializers were requested specifically, then support
# all that are available
if serializers is None:
serializers = get_serializers()

if not serializers:
raise Exception("could not import any WAMP serializers")

self._serializers = {ser.RAWSOCKET_SERIALIZER_ID: ser for ser in serializers}


@public
class WampRawSocketClientFactory(WampRawSocketFactory):
"""
asyncio-based WAMP-over-RawSocket client factory.
"""
protocol = WampRawSocketClientProtocol

def __init__(self, factory, serializer=None):
"""

:param factory: A callable that produces instances that implement
:class:`autobahn.wamp.interfaces.ITransportHandler`
:type factory: callable

:param serializer: The WAMP serializer to use (or ``None`` for
"best" serializer, chosen as the first serializer available from
this list: CBOR, MessagePack, UBJSON, JSON).
:type serializer: object implementing :class:`autobahn.wamp.interfaces.ISerializer`
"""
if callable(factory):
self._factory = factory
else:
self._factory = lambda: factory

# when no serializer was requested specifically, use the first
# one available
if serializer is None:
serializers = get_serializers()
if serializers:
serializer = serializers[0]()

if serializer is None:
raise Exception("could not import any WAMP serializer")

self._serializer = serializer

+ 396
- 0
venv/lib/python3.7/site-packages/autobahn/asyncio/websocket.py View File

@@ -0,0 +1,396 @@
###############################################################################
#
# The MIT License (MIT)
#
# Copyright (c) Crossbar.io Technologies GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################

from __future__ import absolute_import

from collections import deque

import txaio
txaio.use_asyncio()

from autobahn.util import public
from autobahn.asyncio.util import transport_channel_id, peer2str
from autobahn.wamp import websocket
from autobahn.websocket import protocol
from autobahn.websocket.types import TransportDetails

try:
import asyncio
from asyncio import iscoroutine
from asyncio import Future
except ImportError:
# Trollius >= 0.3 was renamed
# noinspection PyUnresolvedReferences
import trollius as asyncio
from trollius import iscoroutine
from trollius import Future

if hasattr(asyncio, 'ensure_future'):
ensure_future = asyncio.ensure_future
else: # Deprecated since Python 3.4.4
ensure_future = getattr(asyncio, 'async')

__all__ = (
'WebSocketServerProtocol',
'WebSocketClientProtocol',
'WebSocketServerFactory',
'WebSocketClientFactory',
'WampWebSocketServerProtocol',
'WampWebSocketClientProtocol',
'WampWebSocketServerFactory',
'WampWebSocketClientFactory',
)


def yields(value):
"""
Returns ``True`` iff the value yields.

.. seealso:: http://stackoverflow.com/questions/20730248/maybedeferred-analog-with-asyncio
"""
return isinstance(value, Future) or iscoroutine(value)


class WebSocketAdapterProtocol(asyncio.Protocol):
"""
Adapter class for asyncio-based WebSocket client and server protocols.
"""

def connection_made(self, transport):
self.transport = transport

self.receive_queue = deque()
self._consume()

try:
self.peer = peer2str(transport.get_extra_info('peername'))
except:
self.peer = u"?"

self._connectionMade()

def connection_lost(self, exc):
self._connectionLost(exc)
# according to asyncio docs, connection_lost(None) is called
# if something else called transport.close()
if exc is not None:
self.transport.close()
self.transport = None

def _consume(self):
self.waiter = Future(loop=self.factory.loop or txaio.config.loop)

def process(_):
while len(self.receive_queue):
data = self.receive_queue.popleft()
if self.transport:
self._dataReceived(data)
self._consume()

self.waiter.add_done_callback(process)

def data_received(self, data):
self.receive_queue.append(data)
if not self.waiter.done():
self.waiter.set_result(None)

def _closeConnection(self, abort=False):
if abort and hasattr(self.transport, 'abort'):
self.transport.abort()
else:
self.transport.close()

def _onOpen(self):
res = self.onOpen()
if yields(res):
ensure_future(res)

def _onMessageBegin(self, isBinary):
res = self.onMessageBegin(isBinary)
if yields(res):
ensure_future(res)

def _onMessageFrameBegin(self, length):
res = self.onMessageFrameBegin(length)
if yields(res):
ensure_future(res)

def _onMessageFrameData(self, payload):
res = self.onMessageFrameData(payload)
if yields(res):
ensure_future(res)

def _onMessageFrameEnd(self):
res = self.onMessageFrameEnd()
if yields(res):
ensure_future(res)

def _onMessageFrame(self, payload):
res = self.onMessageFrame(payload)
if yields(res):
ensure_future(res)

def _onMessageEnd(self):
res = self.onMessageEnd()
if yields(res):
ensure_future(res)

def _onMessage(self, payload, isBinary):
res = self.onMessage(payload, isBinary)
if yields(res):
ensure_future(res)

def _onPing(self, payload):
res = self.onPing(payload)
if yields(res):
ensure_future(res)

def _onPong(self, payload):
res = self.onPong(payload)
if yields(res):
ensure_future(res)

def _onClose(self, wasClean, code, reason):
res = self.onClose(wasClean, code, reason)
if yields(res):
ensure_future(res)

def registerProducer(self, producer, streaming):
raise Exception("not implemented")

def unregisterProducer(self):
# note that generic websocket/protocol.py code calls
# .unregisterProducer whenever we dropConnection -- that's
# correct behavior on Twisted so either we'd have to
# try/except there, or special-case Twisted, ..or just make
# this "not an error"
pass


@public
class WebSocketServerProtocol(WebSocketAdapterProtocol, protocol.WebSocketServerProtocol):
"""
Base class for asyncio-based WebSocket server protocols.

Implements:

* :class:`autobahn.websocket.interfaces.IWebSocketChannel`
"""

log = txaio.make_logger()

def get_channel_id(self, channel_id_type=u'tls-unique'):
"""
Implements :func:`autobahn.wamp.interfaces.ITransport.get_channel_id`
"""
return transport_channel_id(self.transport, True, channel_id_type)


@public
class WebSocketClientProtocol(WebSocketAdapterProtocol, protocol.WebSocketClientProtocol):
"""
Base class for asyncio-based WebSocket client protocols.

Implements:

* :class:`autobahn.websocket.interfaces.IWebSocketChannel`
"""

log = txaio.make_logger()

def _onConnect(self, response):
res = self.onConnect(response)
if yields(res):
ensure_future(res)

def startTLS(self):
raise Exception("WSS over explicit proxies not implemented")

def get_channel_id(self, channel_id_type=u'tls-unique'):
"""
Implements :func:`autobahn.wamp.interfaces.ITransport.get_channel_id`
"""
return transport_channel_id(self.transport, False, channel_id_type)

def _create_transport_details(self):
"""
Internal helper.
Base class calls this to create a TransportDetails
"""
is_secure = self.transport.get_extra_info('peercert', None) is not None
if is_secure:
secure_channel_id = {
u'tls-unique': transport_channel_id(self.transport, False, 'tls-unique'),
}
else:
secure_channel_id = {}
return TransportDetails(peer=self.peer, is_secure=is_secure, secure_channel_id=secure_channel_id)


class WebSocketAdapterFactory(object):
"""
Adapter class for asyncio-based WebSocket client and server factories.
"""
log = txaio.make_logger()

def __call__(self):
proto = self.protocol()
proto.factory = self
return proto


@public
class WebSocketServerFactory(WebSocketAdapterFactory, protocol.WebSocketServerFactory):
"""
Base class for asyncio-based WebSocket server factories.

Implements:

* :class:`autobahn.websocket.interfaces.IWebSocketServerChannelFactory`
"""

protocol = WebSocketServerProtocol

def __init__(self, *args, **kwargs):
"""
.. note::
In addition to all arguments to the constructor of
:meth:`autobahn.websocket.interfaces.IWebSocketServerChannelFactory`,
you can supply a ``loop`` keyword argument to specify the
asyncio event loop to be used.
"""
loop = kwargs.pop('loop', None)
self.loop = loop or asyncio.get_event_loop()

protocol.WebSocketServerFactory.__init__(self, *args, **kwargs)


@public
class WebSocketClientFactory(WebSocketAdapterFactory, protocol.WebSocketClientFactory):
"""
Base class for asyncio-based WebSocket client factories.

Implements:

* :class:`autobahn.websocket.interfaces.IWebSocketClientChannelFactory`
"""

def __init__(self, *args, **kwargs):
"""

.. note::
In addition to all arguments to the constructor of
:meth:`autobahn.websocket.interfaces.IWebSocketClientChannelFactory`,
you can supply a ``loop`` keyword argument to specify the
asyncio event loop to be used.
"""
loop = kwargs.pop('loop', None)
self.loop = loop or asyncio.get_event_loop()

protocol.WebSocketClientFactory.__init__(self, *args, **kwargs)


@public
class WampWebSocketServerProtocol(websocket.WampWebSocketServerProtocol, WebSocketServerProtocol):
"""
asyncio-based WAMP-over-WebSocket server protocol.

Implements:

* :class:`autobahn.wamp.interfaces.ITransport`
"""


@public
class WampWebSocketServerFactory(websocket.WampWebSocketServerFactory, WebSocketServerFactory):
"""
asyncio-based WAMP-over-WebSocket server factory.
"""

protocol = WampWebSocketServerProtocol

def __init__(self, factory, *args, **kwargs):
"""

:param factory: A callable that produces instances that implement
:class:`autobahn.wamp.interfaces.ITransportHandler`
:type factory: callable

:param serializers: A list of WAMP serializers to use (or ``None``
for all available serializers).
:type serializers: list of objects implementing
:class:`autobahn.wamp.interfaces.ISerializer`
"""

serializers = kwargs.pop('serializers', None)

websocket.WampWebSocketServerFactory.__init__(self, factory, serializers)

kwargs['protocols'] = self._protocols

# noinspection PyCallByClass
WebSocketServerFactory.__init__(self, *args, **kwargs)


@public
class WampWebSocketClientProtocol(websocket.WampWebSocketClientProtocol, WebSocketClientProtocol):
"""
asyncio-based WAMP-over-WebSocket client protocols.

Implements:

* :class:`autobahn.wamp.interfaces.ITransport`
"""


@public
class WampWebSocketClientFactory(websocket.WampWebSocketClientFactory, WebSocketClientFactory):
"""
asyncio-based WAMP-over-WebSocket client factory.
"""

protocol = WampWebSocketClientProtocol

def __init__(self, factory, *args, **kwargs):
"""

:param factory: A callable that produces instances that implement
:class:`autobahn.wamp.interfaces.ITransportHandler`
:type factory: callable

:param serializer: The WAMP serializer to use (or ``None`` for
"best" serializer, chosen as the first serializer available from
this list: CBOR, MessagePack, UBJSON, JSON).
:type serializer: object implementing :class:`autobahn.wamp.interfaces.ISerializer`
"""

serializers = kwargs.pop('serializers', None)

websocket.WampWebSocketClientFactory.__init__(self, factory, serializers)

kwargs['protocols'] = self._protocols

WebSocketClientFactory.__init__(self, *args, **kwargs)

+ 41
- 0
venv/lib/python3.7/site-packages/autobahn/exception.py View File

@@ -0,0 +1,41 @@
###############################################################################
#
# The MIT License (MIT)
#
# Copyright (c) Crossbar.io Technologies GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################

from __future__ import absolute_import

from autobahn.util import public

__all__ = (
'PayloadExceededError',
)


@public
class PayloadExceededError(RuntimeError):
"""
Exception raised when the serialized and framed (eg WebSocket/RawSocket) WAMP payload
exceeds the transport message size limit.
"""

+ 646
- 0
venv/lib/python3.7/site-packages/autobahn/nvx/_utf8validator.c View File

@@ -0,0 +1,646 @@
///////////////////////////////////////////////////////////////////////////////
//
// The MIT License (MIT)
//
// Copyright (c) Crossbar.io Technologies GmbH
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////

#include <stdlib.h>
#include <stdint.h>

// http://stackoverflow.com/questions/11228855/header-files-for-simd-intrinsics
#include <x86intrin.h>


#define UTF8_ACCEPT 0
#define UTF8_REJECT 1


typedef struct {
size_t current_index;
size_t total_index;
int state;
int impl;
} utf8_validator_t;


#define UTF8_VALIDATOR_OPTIMAL 0
#define UTF8_VALIDATOR_TABLE_DFA 1
#define UTF8_VALIDATOR_UNROLLED_DFA 2
#define UTF8_VALIDATOR_SSE2_DFA 3
#define UTF8_VALIDATOR_SSE41_DFA 4


int nvx_utf8vld_get_impl (void* utf8vld) {
utf8_validator_t* vld = (utf8_validator_t*) utf8vld;

return vld->impl;
}

int nvx_utf8vld_set_impl (void* utf8vld, int impl) {
utf8_validator_t* vld = (utf8_validator_t*) utf8vld;

if (impl) {
// set requested implementation
//
#ifndef __SSE4_1__
# ifdef __SSE2__
if (impl <= UTF8_VALIDATOR_SSE2_DFA) {
vld->impl = impl;
}
# else
if (impl <= UTF8_VALIDATOR_UNROLLED_DFA) {
vld->impl = impl;
}
# endif
#else
if (impl <= UTF8_VALIDATOR_SSE41_DFA) {
vld->impl = impl;
}
#endif

} else {
// set optimal implementation
//
#ifndef __SSE4_1__
# ifdef __SSE2__
vld->impl = UTF8_VALIDATOR_SSE2_DFA;
# else
vld->impl = UTF8_VALIDATOR_UNROLLED_DFA;
# endif
#else
vld->impl = UTF8_VALIDATOR_SSE41_DFA;
#endif

}
return vld->impl;
}


void nvx_utf8vld_reset (void* utf8vld) {
utf8_validator_t* vld = (utf8_validator_t*) utf8vld;

vld->state = 0;
vld->current_index = -1;
vld->total_index = -1;
}


void* nvx_utf8vld_new () {
void* p = malloc(sizeof(utf8_validator_t));
nvx_utf8vld_reset(p);
nvx_utf8vld_set_impl(p, 0);
return p;
}


void nvx_utf8vld_free (void* utf8vld) {
free (utf8vld);
}


// unrolled DFA from http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
//
static const uint8_t UTF8VALIDATOR_DFA[] __attribute__((aligned(64))) =
{
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df

0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1 // s7..s8
};


int _nvx_utf8vld_validate_table (void* utf8vld, const uint8_t* data, size_t length) {

utf8_validator_t* vld = (utf8_validator_t*) utf8vld;

int state = vld->state;

const uint8_t* end = data + length;

while (data < end && state != 1) {
state = UTF8VALIDATOR_DFA[256 + state * 16 + UTF8VALIDATOR_DFA[*data++]];
}

vld->state = state;

if (state == 0) {
// UTF8 is valid and ends on codepoint
return 0;
} else {
if (state == 1) {
// UTF8 is invalid
return -1;
} else {
// UTF8 is valid, but does not end on codepoint (needs more data)
return 1;
}
}
}


// unrolled DFA from http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
//
#define DFA_TRANSITION(state, octet) \
if (state == 0) { \
if (octet >= 0x00 && octet <= 0x7f) { \
/* reflective state 0 */ \
} else if (octet >= 0xc2 && octet <= 0xdf) { \
state = 2; \
} else if ((octet >= 0xe1 && octet <= 0xec) || octet == 0xee || octet == 0xef) { \
state = 3; \
} else if (octet == 0xe0) { \
state = 4; \
} else if (octet == 0xed) { \
state = 5; \
} else if (octet == 0xf4) { \
state = 8; \
} else if (octet == 0xf1 || octet == 0xf2 || octet == 0xf3) { \
state = 7; \
} else if (octet == 0xf0) { \
state = 6; \
} else { \
state = 1; \
} \
} else if (state == 2) { \
if (octet >= 0x80 && octet <= 0xbf) { \
state = 0; \
} else { \
state = 1; \
} \
} else if (state == 3) { \
if (octet >= 0x80 && octet <= 0xbf) { \
state = 2; \
} else { \
state = 1; \
} \
} else if (state == 4) { \
if (octet >= 0xa0 && octet <= 0xbf) { \
state = 2; \
} else { \
state = 1; \
} \
} else if (state == 5) { \
if (octet >= 0x80 && octet <= 0x9f) { \
state = 2; \
} else { \
state = 1; \
} \
} else if (state == 6) { \
if (octet >= 0x90 && octet <= 0xbf) { \
state = 3; \
} else { \
state = 1; \
} \
} else if (state == 7) { \
if (octet >= 0x80 && octet <= 0xbf) { \
state = 3; \
} else { \
state = 1; \
} \
} else if (state == 8) { \
if (octet >= 0x80 && octet <= 0x8f) { \
state = 3; \
} else { \
state = 1; \
} \
} else if (state == 1) { \
/* refective state 1 */ \
} else { \
/* should not arrive here */ \
}


int _nvx_utf8vld_validate_unrolled (void* utf8vld, const uint8_t* data, size_t length) {

utf8_validator_t* vld = (utf8_validator_t*) utf8vld;

int state = vld->state;

const uint8_t* tail_end = data + length;

while (data < tail_end && state != 1) {

// get tail octet
int octet = *data;

// do the DFA
DFA_TRANSITION(state, octet);

++data;
}

vld->state = state;

if (state == 0) {
// UTF8 is valid and ends on codepoint
return 0;
} else {
if (state == 1) {
// UTF8 is invalid
return -1;
} else {
// UTF8 is valid, but does not end on codepoint (needs more data)
return 1;
}
}
}


/*
__m128i _mm_load_si128 (__m128i const* mem_addr)
#include "emmintrin.h"
Instruction: movdqa
CPUID Feature Flag: SSE2

int _mm_movemask_epi8 (__m128i a)
#include "emmintrin.h"
Instruction: pmovmskb
CPUID Feature Flag: SSE2

__m128i _mm_srli_si128 (__m128i a, int imm)
#include "emmintrin.h"
Instruction: psrldq
CPUID Feature Flag: SSE2

int _mm_cvtsi128_si32 (__m128i a)
#include "emmintrin.h"
Instruction: movd
CPUID Feature Flag: SSE2

int _mm_extract_epi16 (__m128i a, int imm)
#include "emmintrin.h"
Instruction: pextrw
CPUID Feature Flag: SSE2

int _mm_extract_epi8 (__m128i a, const int imm)
#include "smmintrin.h"
Instruction: pextrb
CPUID Feature Flag: SSE4.1
*/

#ifdef __SSE2__
int _nvx_utf8vld_validate_sse2 (void* utf8vld, const uint8_t* data, size_t length) {

utf8_validator_t* vld = (utf8_validator_t*) utf8vld;

int state = vld->state;

const uint8_t* tail_end = data + length;

// process unaligned head (sub 16 octets)
//
size_t head_len = ((size_t) data) % sizeof(__m128i);
if (head_len) {

const uint8_t* head_end = data + head_len;

while (data < head_end && state != UTF8_REJECT) {

// get head octet
int octet = *data;

// do the DFA
DFA_TRANSITION(state, octet);

++data;
}
}

// process aligned middle (16 octet chunks)
//
const __m128i* ptr = ((const __m128i*) data);
const __m128i* end = ((const __m128i*) data) + ((length - head_len) / sizeof(__m128i));

while (ptr < end && state != UTF8_REJECT) {

__builtin_prefetch(ptr + 1, 0, 3);
//__builtin_prefetch(ptr + 4, 0, 3); // 16*4=64: cache-line prefetch

__m128i xmm1 = _mm_load_si128(ptr);

if (__builtin_expect(state || _mm_movemask_epi8(xmm1), 0)) {

// copy to different reg - this allows the prefetching to
// do its job in the meantime (I guess ..)

// SSE2 variant
//
int octet;

// octet 0
octet = 0xff & _mm_cvtsi128_si32(xmm1);
DFA_TRANSITION(state, octet);

// octet 1
xmm1 = _mm_srli_si128(xmm1, 1);
octet = 0xff & _mm_cvtsi128_si32(xmm1);
DFA_TRANSITION(state, octet);

// octet 2
xmm1 = _mm_srli_si128(xmm1, 1);
octet = 0xff & _mm_cvtsi128_si32(xmm1);
DFA_TRANSITION(state, octet);

// octet 3
xmm1 = _mm_srli_si128(xmm1, 1);
octet = 0xff & _mm_cvtsi128_si32(xmm1);
DFA_TRANSITION(state, octet);

// octet 4
xmm1 = _mm_srli_si128(xmm1, 1);
octet = 0xff & _mm_cvtsi128_si32(xmm1);
DFA_TRANSITION(state, octet);

// octet 5
xmm1 = _mm_srli_si128(xmm1, 1);
octet = 0xff & _mm_cvtsi128_si32(xmm1);
DFA_TRANSITION(state, octet);

// octet 6
xmm1 = _mm_srli_si128(xmm1, 1);
octet = 0xff & _mm_cvtsi128_si32(xmm1);
DFA_TRANSITION(state, octet);

// octet 7
xmm1 = _mm_srli_si128(xmm1, 1);
octet = 0xff & _mm_cvtsi128_si32(xmm1);
DFA_TRANSITION(state, octet);

// octet 8
xmm1 = _mm_srli_si128(xmm1, 1);
octet = 0xff & _mm_cvtsi128_si32(xmm1);
DFA_TRANSITION(state, octet);

// octet 9
xmm1 = _mm_srli_si128(xmm1, 1);
octet = 0xff & _mm_cvtsi128_si32(xmm1);
DFA_TRANSITION(state, octet);

// octet 10
xmm1 = _mm_srli_si128(xmm1, 1);
octet = 0xff & _mm_cvtsi128_si32(xmm1);
DFA_TRANSITION(state, octet);

// octet 11
xmm1 = _mm_srli_si128(xmm1, 1);
octet = 0xff & _mm_cvtsi128_si32(xmm1);
DFA_TRANSITION(state, octet);

// octet 12
xmm1 = _mm_srli_si128(xmm1, 1);
octet = 0xff & _mm_cvtsi128_si32(xmm1);
DFA_TRANSITION(state, octet);

// octet 13
xmm1 = _mm_srli_si128(xmm1, 1);
octet = 0xff & _mm_cvtsi128_si32(xmm1);
DFA_TRANSITION(state, octet);

// octet 14
xmm1 = _mm_srli_si128(xmm1, 1);
octet = 0xff & _mm_cvtsi128_si32(xmm1);
DFA_TRANSITION(state, octet);

// octet 15
xmm1 = _mm_srli_si128(xmm1, 1);
octet = 0xff & _mm_cvtsi128_si32(xmm1);
DFA_TRANSITION(state, octet);
}
++ptr;
}

// process unaligned tail (sub 16 octets)
//
const uint8_t* tail_ptr = (const uint8_t*) ptr;

while (tail_ptr < tail_end && state != UTF8_REJECT) {

// get tail octet
int octet = *tail_ptr;

// do the DFA
DFA_TRANSITION(state, octet);

++tail_ptr;
}

vld->state = state;

if (state == UTF8_ACCEPT) {
// UTF8 is valid and ends on codepoint
return 0;
} else {
if (state == UTF8_REJECT) {
// UTF8 is invalid
return -1;
} else {
// UTF8 is valid, but does not end on codepoint (needs more data)
return 1;
}
}
}
#endif


#ifdef __SSE4_1__
int _nvx_utf8vld_validate_sse4 (void* utf8vld, const uint8_t* data, size_t length) {

utf8_validator_t* vld = (utf8_validator_t*) utf8vld;

int state = vld->state;

const uint8_t* tail_end = data + length;

// process unaligned head (sub 16 octets)
//
size_t head_len = ((size_t) data) % sizeof(__m128i);
if (head_len) {

const uint8_t* head_end = data + head_len;

while (data < head_end && state != UTF8_REJECT) {

// get head octet
int octet = *data;

// do the DFA
DFA_TRANSITION(state, octet);

++data;
}
}

// process aligned middle (16 octet chunks)
//
const __m128i* ptr = ((const __m128i*) data);
const __m128i* end = ((const __m128i*) data) + ((length - head_len) / sizeof(__m128i));

while (ptr < end && state != UTF8_REJECT) {

__builtin_prefetch(ptr + 1, 0, 3);
//__builtin_prefetch(ptr + 4, 0, 3); // 16*4=64: cache-line prefetch

__m128i xmm1 = _mm_load_si128(ptr);


if (__builtin_expect(state || _mm_movemask_epi8(xmm1), 0)) {

// copy to different reg - this allows the prefetching to
// do its job in the meantime (I guess ..)

// SSE4.1 variant
//
int octet;

// octet 0
octet = _mm_extract_epi8(xmm1, 0);
DFA_TRANSITION(state, octet);

// octet 1
octet = _mm_extract_epi8(xmm1, 1);
DFA_TRANSITION(state, octet);

// octet 2
octet = _mm_extract_epi8(xmm1, 2);
DFA_TRANSITION(state, octet);

// octet 3
octet = _mm_extract_epi8(xmm1, 3);
DFA_TRANSITION(state, octet);

// octet 4
octet = _mm_extract_epi8(xmm1, 4);
DFA_TRANSITION(state, octet);

// octet 5
octet = _mm_extract_epi8(xmm1, 5);
DFA_TRANSITION(state, octet);

// octet 6
octet = _mm_extract_epi8(xmm1, 6);
DFA_TRANSITION(state, octet);

// octet 7
octet = _mm_extract_epi8(xmm1, 7);
DFA_TRANSITION(state, octet);

// octet 8
octet = _mm_extract_epi8(xmm1, 8);
DFA_TRANSITION(state, octet);

// octet 9
octet = _mm_extract_epi8(xmm1, 9);
DFA_TRANSITION(state, octet);

// octet 10
octet = _mm_extract_epi8(xmm1, 10);
DFA_TRANSITION(state, octet);

// octet 11
octet = _mm_extract_epi8(xmm1, 11);
DFA_TRANSITION(state, octet);

// octet 12
octet = _mm_extract_epi8(xmm1, 12);
DFA_TRANSITION(state, octet);

// octet 13
octet = _mm_extract_epi8(xmm1, 13);
DFA_TRANSITION(state, octet);

// octet 14
octet = _mm_extract_epi8(xmm1, 14);
DFA_TRANSITION(state, octet);

// octet 15
octet = _mm_extract_epi8(xmm1, 15);
DFA_TRANSITION(state, octet);
}
++ptr;
}

// process unaligned tail (sub 16 octets)
//
const uint8_t* tail_ptr = (const uint8_t*) ptr;

while (tail_ptr < tail_end && state != UTF8_REJECT) {

// get tail octet
int octet = *tail_ptr;

// do the DFA
DFA_TRANSITION(state, octet);

++tail_ptr;
}

vld->state = state;

if (state == UTF8_ACCEPT) {
// UTF8 is valid and ends on codepoint
return 0;
} else {
if (state == UTF8_REJECT) {
// UTF8 is invalid
return -1;
} else {
// UTF8 is valid, but does not end on codepoint (needs more data)
return 1;
}
}
}
#endif


int nvx_utf8vld_validate (void* utf8vld, const uint8_t* data, size_t length) {

utf8_validator_t* vld = (utf8_validator_t*) utf8vld;

switch (vld->impl) {
case UTF8_VALIDATOR_TABLE_DFA:
return _nvx_utf8vld_validate_table(utf8vld, data, length);
case UTF8_VALIDATOR_UNROLLED_DFA:
return _nvx_utf8vld_validate_unrolled(utf8vld, data, length);
#ifdef __SSE2__
case UTF8_VALIDATOR_SSE2_DFA:
return _nvx_utf8vld_validate_table(utf8vld, data, length);
#endif
#ifdef __SSE4_1__
case UTF8_VALIDATOR_SSE41_DFA:
return _nvx_utf8vld_validate_table(utf8vld, data, length);
#endif
default:
return _nvx_utf8vld_validate_table(utf8vld, data, length);
}
}

+ 357
- 0
venv/lib/python3.7/site-packages/autobahn/nvx/test/test_utf8validator.py View File

@@ -0,0 +1,357 @@
# coding=utf-8

###############################################################################
#
# The MIT License (MIT)
#
# Copyright (c) Crossbar.io Technologies GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################

from __future__ import absolute_import

import six
import struct
import unittest

from autobahn.websocket.utf8validator import Utf8Validator as StandardUtf8Validator

try:
from _nvx_utf8validator import lib # noqa
from autobahn.nvx import Utf8Validator as NvxUtf8Validator
except ImportError:
HAS_NVX = False
else:
HAS_NVX = True


def _create_utf8_test_sequences():
"""
Create test sequences for UTF-8 decoder tests from
http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
"""

UTF8_TEST_SEQUENCES = []

# 1 Some correct UTF-8 text
vss = b'\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5'
vs = [b"Some valid UTF-8 sequences", []]
vs[1].append((True, b'hello\x24world')) # U+0024
vs[1].append((True, b'hello\xC2\xA2world')) # U+00A2
vs[1].append((True, b'hello\xE2\x82\xACworld')) # U+20AC
vs[1].append((True, b'hello\xF0\xA4\xAD\xA2world')) # U+24B62
vs[1].append((True, vss))
UTF8_TEST_SEQUENCES.append(vs)

# All prefixes of correct UTF-8 text
vs = [
b"All prefixes of a valid UTF-8 string that contains multi-byte code points",
[]]
v = StandardUtf8Validator()
for i in range(1, len(vss) + 1):
v.reset()
res = v.validate(vss[:i])
vs[1].append((res[0] and res[1], vss[:i]))
UTF8_TEST_SEQUENCES.append(vs)

# 2.1 First possible sequence of a certain length
vs = [b"First possible sequence of a certain length", []]
vs[1].append((True, b'\x00'))
vs[1].append((True, b'\xc2\x80'))
vs[1].append((True, b'\xe0\xa0\x80'))
vs[1].append((True, b'\xf0\x90\x80\x80'))
UTF8_TEST_SEQUENCES.append(vs)

# the following conform to the UTF-8 integer encoding scheme, but
# valid UTF-8 only allows for Unicode code points up to U+10FFFF
vs = [b"First possible sequence length 5/6 (invalid codepoints)", []]
vs[1].append((False, b'\xf8\x88\x80\x80\x80'))
vs[1].append((False, b'\xfc\x84\x80\x80\x80\x80'))
UTF8_TEST_SEQUENCES.append(vs)

# 2.2 Last possible sequence of a certain length
vs = [b"Last possible sequence of a certain length", []]
vs[1].append((True, b'\x7f'))
vs[1].append((True, b'\xdf\xbf'))
vs[1].append((True, b'\xef\xbf\xbf'))
vs[1].append((True, b'\xf4\x8f\xbf\xbf'))
UTF8_TEST_SEQUENCES.append(vs)

# the following conform to the UTF-8 integer encoding scheme, but
# valid UTF-8 only allows for Unicode code points up to U+10FFFF
vs = [b"Last possible sequence length 4/5/6 (invalid codepoints)", []]
vs[1].append((False, b'\xf7\xbf\xbf\xbf'))
vs[1].append((False, b'\xfb\xbf\xbf\xbf\xbf'))
vs[1].append((False, b'\xfd\xbf\xbf\xbf\xbf\xbf'))
UTF8_TEST_SEQUENCES.append(vs)

# 2.3 Other boundary conditions
vs = [b"Other boundary conditions", []]
vs[1].append((True, b'\xed\x9f\xbf'))
vs[1].append((True, b'\xee\x80\x80'))
vs[1].append((True, b'\xef\xbf\xbd'))
vs[1].append((True, b'\xf4\x8f\xbf\xbf'))
vs[1].append((False, b'\xf4\x90\x80\x80'))
UTF8_TEST_SEQUENCES.append(vs)

# 3.1 Unexpected continuation bytes
vs = [b"Unexpected continuation bytes", []]
vs[1].append((False, b'\x80'))
vs[1].append((False, b'\xbf'))
vs[1].append((False, b'\x80\xbf'))
vs[1].append((False, b'\x80\xbf\x80'))
vs[1].append((False, b'\x80\xbf\x80\xbf'))
vs[1].append((False, b'\x80\xbf\x80\xbf\x80'))
vs[1].append((False, b'\x80\xbf\x80\xbf\x80\xbf'))
s = b''

# 3.2 Lonely start characters
vs = [b"Lonely start characters", []]
m = [(0xc0, 0xdf), (0xe0, 0xef), (0xf0, 0xf7), (0xf8, 0xfb), (0xfc, 0xfd)]
for mm in m:
s = b''
for i in range(mm[0], mm[1]):
s += struct.pack('BB', i, 0x20)
# s += chr(i)
# s += chr(0x20)
vs[1].append((False, s))
UTF8_TEST_SEQUENCES.append(vs)

# 3.3 Sequences with last continuation byte missing
vs = [b"Sequences with last continuation byte missing", []]
k = [b'\xc0', b'\xe0\x80', b'\xf0\x80\x80', b'\xf8\x80\x80\x80', b'\xfc\x80\x80\x80\x80',
b'\xdf', b'\xef\xbf', b'\xf7\xbf\xbf', b'\xfb\xbf\xbf\xbf', b'\xfd\xbf\xbf\xbf\xbf']
for kk in k:
vs[1].append((False, kk))
UTF8_TEST_SEQUENCES.append(vs)

# 3.4 Concatenation of incomplete sequences
vs = [b"Concatenation of incomplete sequences", []]
vs[1].append((False, b''.join(k)))
UTF8_TEST_SEQUENCES.append(vs)

# 3.5 Impossible bytes
vs = [b"Impossible bytes", []]
vs[1].append((False, b'\xfe'))
vs[1].append((False, b'\xff'))
vs[1].append((False, b'\xfe\xfe\xff\xff'))
UTF8_TEST_SEQUENCES.append(vs)

# 4.1 Examples of an overlong ASCII character
vs = [b"Examples of an overlong ASCII character", []]
vs[1].append((False, b'\xc0\xaf'))
vs[1].append((False, b'\xe0\x80\xaf'))
vs[1].append((False, b'\xf0\x80\x80\xaf'))
vs[1].append((False, b'\xf8\x80\x80\x80\xaf'))
vs[1].append((False, b'\xfc\x80\x80\x80\x80\xaf'))
UTF8_TEST_SEQUENCES.append(vs)

# 4.2 Maximum overlong sequences
vs = [b"Maximum overlong sequences", []]
vs[1].append((False, b'\xc1\xbf'))
vs[1].append((False, b'\xe0\x9f\xbf'))
vs[1].append((False, b'\xf0\x8f\xbf\xbf'))
vs[1].append((False, b'\xf8\x87\xbf\xbf\xbf'))
vs[1].append((False, b'\xfc\x83\xbf\xbf\xbf\xbf'))
UTF8_TEST_SEQUENCES.append(vs)

# 4.3 Overlong representation of the NUL character
vs = [b"Overlong representation of the NUL character", []]
vs[1].append((False, b'\xc0\x80'))
vs[1].append((False, b'\xe0\x80\x80'))
vs[1].append((False, b'\xf0\x80\x80\x80'))
vs[1].append((False, b'\xf8\x80\x80\x80\x80'))
vs[1].append((False, b'\xfc\x80\x80\x80\x80\x80'))
UTF8_TEST_SEQUENCES.append(vs)

# 5.1 Single UTF-16 surrogates
vs = [b"Single UTF-16 surrogates", []]
vs[1].append((False, b'\xed\xa0\x80'))
vs[1].append((False, b'\xed\xad\xbf'))
vs[1].append((False, b'\xed\xae\x80'))
vs[1].append((False, b'\xed\xaf\xbf'))
vs[1].append((False, b'\xed\xb0\x80'))
vs[1].append((False, b'\xed\xbe\x80'))
vs[1].append((False, b'\xed\xbf\xbf'))
UTF8_TEST_SEQUENCES.append(vs)

# 5.2 Paired UTF-16 surrogates
vs = [b"Paired UTF-16 surrogates", []]
vs[1].append((False, b'\xed\xa0\x80\xed\xb0\x80'))
vs[1].append((False, b'\xed\xa0\x80\xed\xbf\xbf'))
vs[1].append((False, b'\xed\xad\xbf\xed\xb0\x80'))
vs[1].append((False, b'\xed\xad\xbf\xed\xbf\xbf'))
vs[1].append((False, b'\xed\xae\x80\xed\xb0\x80'))
vs[1].append((False, b'\xed\xae\x80\xed\xbf\xbf'))
vs[1].append((False, b'\xed\xaf\xbf\xed\xb0\x80'))
vs[1].append((False, b'\xed\xaf\xbf\xed\xbf\xbf'))
UTF8_TEST_SEQUENCES.append(vs)

# 5.3 Other illegal code positions
# Those are non-character code points and valid UTF-8 by RFC 3629
vs = [b"Non-character code points (valid UTF-8)", []]
# https://bug686312.bugzilla.mozilla.org/attachment.cgi?id=561257
# non-characters: EF BF [BE-BF]
vs[1].append((True, b'\xef\xbf\xbe'))
vs[1].append((True, b'\xef\xbf\xbf'))
# non-characters: F[0-7] [89AB]F BF [BE-BF]
for z1 in [b'\xf0', b'\xf1', b'\xf2', b'\xf3', b'\xf4']:
for z2 in [b'\x8f', b'\x9f', b'\xaf', b'\xbf']:
# those encode codepoints >U+10FFFF
if not (z1 == b'\xf4' and z2 != b'\x8f'):
for z3 in [b'\xbe', b'\xbf']:
zz = z1 + z2 + b'\xbf' + z3
if zz not in [b'\xf0\x8f\xbf\xbe',
b'\xf0\x8f\xbf\xbf']: # filter overlong sequences
vs[1].append((True, zz))
UTF8_TEST_SEQUENCES.append(vs)

# Unicode "specials", such as replacement char etc
# http://en.wikipedia.org/wiki/Specials_%28Unicode_block%29
vs = [b"Unicode specials (i.e. replacement char)", []]
vs[1].append((True, b'\xef\xbf\xb9'))
vs[1].append((True, b'\xef\xbf\xba'))
vs[1].append((True, b'\xef\xbf\xbb'))
vs[1].append((True, b'\xef\xbf\xbc'))
vs[1].append((True, b'\xef\xbf\xbd')) # replacement char
vs[1].append((True, b'\xef\xbf\xbe'))
vs[1].append((True, b'\xef\xbf\xbf'))
UTF8_TEST_SEQUENCES.append(vs)

return UTF8_TEST_SEQUENCES


def _create_valid_utf8_test_sequences():
"""
Generate some exotic, but valid UTF8 test strings.
"""
VALID_UTF8_TEST_SEQUENCES = []
for test in _create_utf8_test_sequences():
valids = [x[1] for x in test[1] if x[0]]
if len(valids) > 0:
VALID_UTF8_TEST_SEQUENCES.append([test[0], valids])
return VALID_UTF8_TEST_SEQUENCES


@unittest.skipIf(not HAS_NVX, 'NVX native extensions not present')
class TestNvxUtf8Validator(unittest.TestCase):

def setUp(self):
# These tests verify the UTF-8 decoder/validator on the various test cases from
# http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
vs = []
for k in _create_utf8_test_sequences():
vs.extend(k[1])

# All Unicode code points
for i in range(
0, 0xffff): # should by 0x10ffff, but non-wide Python build is limited to 16-bits
if i < 0xD800 or i > 0xDFFF: # filter surrogate code points, which are disallowed to encode in UTF-8
vs.append((True, six.unichr(i).encode("utf-8")))

# FIXME: UnicodeEncodeError: 'utf-8' codec can't encode character '\ud800'
# in position 0: surrogates not allowed
if False:
# 5.1 Single UTF-16 surrogates
for i in range(0xD800, 0xDBFF): # high-surrogate
ss = six.unichr(i).encode("utf-8")
vs.append((False, ss))
for i in range(0xDC00, 0xDFFF): # low-surrogate
ss = six.unichr(i).encode("utf-8")
vs.append((False, ss))

# 5.2 Paired UTF-16 surrogates
for i in range(0xD800, 0xDBFF): # high-surrogate
for j in range(0xDC00, 0xDFFF): # low-surrogate
ss1 = six.unichr(i).encode("utf-8")
ss2 = six.unichr(j).encode("utf-8")
vs.append((False, ss1 + ss2))
vs.append((False, ss2 + ss1))

self._TEST_SEQUENCES = vs

def test_standard_utf8validator(self):
"""
Test standard implementation of UTF8 validator.
"""
validator = StandardUtf8Validator()
return self._test_utf8(validator)

def test_nvx_utf8validator(self):
"""
Test NVX implementation of UTF8 validator.
"""
validator = NvxUtf8Validator()
return self._test_utf8(validator)

def test_standard_utf8validator_incremental(self):
"""
Test standard implementation of UTF8 validator in incremental mode.
"""
validator = StandardUtf8Validator()
return self._test_utf8_incremental(validator)

# NVX UTF8 validator lack incremental mode implementation
@unittest.expectedFailure
def test_nvx_utf8validator_incremental(self):
"""
Test NVX implementation of UTF8 validator in incremental mode.
"""
validator = NvxUtf8Validator()
return self._test_utf8_incremental(validator)

def _test_utf8(self, validator):
for s in self._TEST_SEQUENCES:
validator.reset()
r = validator.validate(s[1])

# no UTF-8 decode error _and_ everything consumed
res = r[0] and r[1]

self.assertEqual(res, s[0])

def _test_utf8_incremental(self, validator, withPositions=True):
# These tests verify that the UTF-8 decoder/validator can operate incrementally.
if withPositions:
# testing validator 4 on incremental detection with positions
k = 4
else:
# testing validator 2 on incremental detection without positions
k = 2

validator.reset()
self.assertEqual((True, True, 15, 15)[:k], validator.validate(u'µ@ßöäüàá'.encode('utf8'))[:k])

validator.reset()
self.assertEqual((False, False, 0, 0)[:k], validator.validate(b"\xF5")[:k])

# the following 3 all fail on eating byte 7 (0xA0)
validator.reset()
self.assertEqual((True, True, 6, 6)[:k], validator.validate(b"\x65\x64\x69\x74\x65\x64")[:k])
self.assertEqual((False, False, 1, 7)[:k], validator.validate(b"\xED\xA0\x80")[:k])

validator.reset()
self.assertEqual((True, True, 4, 4)[:k], validator.validate(b"\x65\x64\x69\x74")[:k])
self.assertEqual((False, False, 3, 7)[:k], validator.validate(b"\x65\x64\xED\xA0\x80")[:k])

validator.reset()
self.assertEqual((True, False, 7, 7)[:k], validator.validate(b"\x65\x64\x69\x74\x65\x64\xED")[:k])
self.assertEqual((False, False, 0, 7)[:k], validator.validate(b"\xA0\x80")[:k])

+ 126
- 0
venv/lib/python3.7/site-packages/autobahn/rawsocket/test/test_rawsocket_url.py View File

@@ -0,0 +1,126 @@
###############################################################################
#
# The MIT License (MIT)
#
# Copyright (c) Crossbar.io Technologies GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################

from __future__ import absolute_import

import unittest

from autobahn.rawsocket.util import create_url, parse_url


class TestCreateRsUrl(unittest.TestCase):

def test_create_url01(self):
self.assertEqual(create_url("localhost"), "rs://localhost:80")

def test_create_url02(self):
self.assertEqual(create_url("localhost", port=8090), "rs://localhost:8090")

def test_create_url03(self):
self.assertEqual(create_url("localhost", isSecure=True), "rss://localhost:443")

def test_create_url04(self):
self.assertEqual(create_url("localhost", isSecure=True, port=443), "rss://localhost:443")

def test_create_url05(self):
self.assertEqual(create_url("localhost", isSecure=True, port=80), "rss://localhost:80")

def test_create_url06(self):
self.assertEqual(create_url("unix", port="file.sock"), "rs://unix:file.sock")

def test_create_url07(self):
self.assertEqual(create_url("unix", port="/tmp/file.sock"), "rs://unix:/tmp/file.sock")

def test_create_url08(self):
self.assertEqual(create_url("unix", port="../file.sock"), "rs://unix:../file.sock")

def test_create_url09(self):
self.assertEqual(create_url("unix", isSecure=True, port="file.sock"), "rss://unix:file.sock")

def test_create_url10(self):
self.assertEqual(create_url("unix", isSecure=True, port="/tmp/file.sock"), "rss://unix:/tmp/file.sock")

def test_create_url11(self):
self.assertEqual(create_url("unix", isSecure=True, port="../file.sock"), "rss://unix:../file.sock")


class TestParseWsUrl(unittest.TestCase):

# parse_url -> (isSecure, host, port)

def test_parse_url01(self):
self.assertEqual(parse_url("rs://localhost"), (False, 'localhost', 80))

def test_parse_url02(self):
self.assertEqual(parse_url("rss://localhost"), (True, 'localhost', 443))

def test_parse_url03(self):
self.assertEqual(parse_url("rs://localhost:9000"), (False, 'localhost', 9000))

def test_parse_url04(self):
self.assertEqual(parse_url("rss://localhost:9000"), (True, 'localhost', 9000))

def test_parse_url05(self):
self.assertRaises(Exception, parse_url, "ws://localhost")

def test_parse_url06(self):
self.assertRaises(Exception, parse_url, "wss://localhost")

def test_parse_url07(self):
self.assertRaises(Exception, parse_url, "ws://localhost:80")

def test_parse_url08(self):
self.assertRaises(Exception, parse_url, "rs://localhost/somepath")

def test_parse_url09(self):
self.assertRaises(Exception, parse_url, "rs://localhost#somefrag")

def test_parse_url10(self):
self.assertRaises(Exception, parse_url, "rs://localhost?foo=bar")

def test_parse_url11(self):
self.assertRaises(Exception, parse_url, "rss://")

def test_parse_url12(self):
self.assertRaises(Exception, parse_url, "rs://")

def test_parse_url13(self):
self.assertEqual(parse_url("rs://unix:file.sock"), (False, 'unix', 'file.sock'))

def test_parse_url14(self):
self.assertEqual(parse_url("rs://unix:/tmp/file.sock"), (False, 'unix', '/tmp/file.sock'))

def test_parse_url15(self):
self.assertEqual(parse_url("rs://unix:../file.sock"), (False, 'unix', '../file.sock'))

def test_parse_url16(self):
self.assertEqual(parse_url("rss://unix:file.sock"), (True, 'unix', 'file.sock'))

def test_parse_url17(self):
self.assertEqual(parse_url("rss://unix:/tmp/file.sock"), (True, 'unix', '/tmp/file.sock'))

def test_parse_url18(self):
self.assertEqual(parse_url("rss://unix:../file.sock"), (True, 'unix', '../file.sock'))

+ 111
- 0
venv/lib/python3.7/site-packages/autobahn/test/test_rng.py View File

@@ -0,0 +1,111 @@
###############################################################################
#
# The MIT License (MIT)
#
# Copyright (c) Crossbar.io Technologies GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################

from __future__ import absolute_import

import sys
import unittest

import uuid
import random
from nacl import utils, public

from autobahn import util


@unittest.skipIf(not sys.platform.startswith('linux'), 'entropy depletion tests only available on Linux')
class TestEntropy(unittest.TestCase):

def test_non_depleting(self):
res = {}

with open('/dev/urandom', 'rb') as rng:
for i in range(1000):
for j in range(100):

# "reseed" (seems pointless, but ..)
random.seed()

# random UUIDs
v1 = uuid.uuid4() # noqa

# stdlib random
v2 = random.random() # noqa
v3 = random.getrandbits(32) # noqa
v4 = random.randint(0, 9007199254740992) # noqa
v5 = random.normalvariate(10, 100) # noqa
v6 = random.choice(range(100)) # noqa

# PyNaCl
v7 = utils.random(public.Box.NONCE_SIZE) # noqa

# Autobahn utils
v8 = util.generate_token(4, 4) # noqa
v9 = util.id() # noqa
v10 = util.rid() # noqa
v11 = util.newid() # noqa

# direct procfs access to PRNG
d = rng.read(1000) # noqa

# check available entropy
with open('/proc/sys/kernel/random/entropy_avail', 'r') as ent:
ea = int(ent.read()) // 100
if ea not in res:
res[ea] = 0
res[ea] += 1

skeys = sorted(res.keys())

print('\nsystem entropy depletion stats:')
for k in skeys:
print('{}: {}'.format(k, res[k]))

self.assertTrue(skeys[0] > 10)

def test_depleting(self):
res = {}

with open('/dev/random', 'rb') as rng:
for i in range(10000):

# direct procfs access to "real" RNG
d = rng.read(1000) # noqa

# check available entropy
with open('/proc/sys/kernel/random/entropy_avail', 'r') as ent:
ea = int(ent.read()) // 100
if ea not in res:
res[ea] = 0
res[ea] += 1

skeys = sorted(res.keys())

print('\nsystem entropy depletion stats:')
for k in skeys:
print('{}: {}'.format(k, res[k]))

self.assertTrue(skeys[0] == 0)

+ 48
- 0
venv/lib/python3.7/site-packages/autobahn/test/test_util.py View File

@@ -0,0 +1,48 @@
###############################################################################
#
# The MIT License (MIT)
#
# Copyright (c) Crossbar.io Technologies GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################

from __future__ import absolute_import

import unittest

from autobahn.util import IdGenerator


class TestIdGenerator(unittest.TestCase):
def test_idgenerator_is_generator(self):
"IdGenerator follows the generator protocol"
g = IdGenerator()
self.assertEqual(1, next(g))
self.assertEqual(2, next(g))

def test_generator_wrap(self):
g = IdGenerator()
g._next = 2 ** 53 - 1 # cheat a little

v = next(g)
self.assertEqual(v, 2 ** 53)
v = next(g)
self.assertEqual(v, 1)

+ 89
- 0
venv/lib/python3.7/site-packages/autobahn/twisted/__init__.py View File

@@ -0,0 +1,89 @@
###############################################################################
#
# The MIT License (MIT)
#
# Copyright (c) Crossbar.io Technologies GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################


from __future__ import absolute_import

import sys
import platform

import twisted

import autobahn

# Twisted specific utilities (these should really be in Twisted, but
# they aren't, and we use these in example code, so it must be part of
# the public API)
from autobahn.twisted.util import sleep
from autobahn.twisted.choosereactor import install_reactor

# WebSocket protocol support
from autobahn.twisted.websocket import \
WebSocketServerProtocol, \
WebSocketClientProtocol, \
WebSocketServerFactory, \
WebSocketClientFactory

# support for running Twisted stream protocols over WebSocket
from autobahn.twisted.websocket import WrappingWebSocketServerFactory, \
WrappingWebSocketClientFactory

# Twisted Web support - FIXME: these imports trigger import of Twisted reactor!
# from autobahn.twisted.resource import WebSocketResource, WSGIRootResource

# WAMP support
from autobahn.twisted.wamp import ApplicationSession


__all__ = (
# this should really be in Twisted
'sleep',
'install_reactor',

# WebSocket
'WebSocketServerProtocol',
'WebSocketClientProtocol',
'WebSocketServerFactory',
'WebSocketClientFactory',

# wrapping stream protocols in WebSocket
'WrappingWebSocketServerFactory',
'WrappingWebSocketClientFactory',

# Twisted Web - FIXME: see comment for import above
# 'WebSocketResource',

# this should really be in Twisted - FIXME: see comment for import above
# 'WSGIRootResource',

# WAMP support
'ApplicationSession',
)

__ident__ = u'Autobahn/{}-Twisted/{}-{}/{}'.format(autobahn.__version__, twisted.__version__, platform.python_implementation(), '.'.join([str(x) for x in list(sys.version_info[:3])]))
"""
AutobahnPython library implementation (eg. "Autobahn/0.13.0-Twisted/15.5.0-CPython/3.5.1")
"""

+ 870
- 0
venv/lib/python3.7/site-packages/autobahn/util.py View File

@@ -0,0 +1,870 @@
###############################################################################
#
# The MIT License (MIT)
#
# Copyright (c) Crossbar.io Technologies GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", fWITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################

from __future__ import absolute_import

import os
import time
import struct
import sys
import re
import base64
import math
import random
import binascii
from datetime import datetime, timedelta
from pprint import pformat
from array import array

import six

import txaio

try:
_TLS = True
from OpenSSL import SSL
except ImportError:
_TLS = False


__all__ = ("public",
"encode_truncate",
"xor",
"utcnow",
"utcstr",
"id",
"rid",
"newid",
"rtime",
"Stopwatch",
"Tracker",
"EqualityMixin",
"ObservableMixin",
"IdGenerator",
"generate_token",
"generate_activation_code",
"generate_serial_number",
"generate_user_password")


def public(obj):
"""
The public user API of Autobahn is marked using this decorator.
Everything that is not decorated @public is library internal, can
change at any time and should not be used in user program code.
"""
try:
obj._is_public = True
except AttributeError:
# FIXME: exceptions.AttributeError: 'staticmethod' object has no attribute '_is_public'
pass
return obj


@public
def encode_truncate(text, limit, encoding='utf8', return_encoded=True):
"""
Given a string, return a truncated version of the string such that
the UTF8 encoding of the string is smaller than the given limit.

This function correctly truncates even in the presence of Unicode code
points that encode to multi-byte encodings which must not be truncated
in the middle.

:param text: The (Unicode) string to truncate.
:type text: str
:param limit: The number of bytes to limit the UTF8 encoding to.
:type limit: int
:param encoding: Truncate the string in this encoding (default is ``utf-8``).
:type encoding: str
:param return_encoded: If ``True``, return the string encoded into bytes
according to the specified encoding, else return the string as a string.
:type return_encoded: bool

:returns: The truncated string.
:rtype: str or bytes
"""
assert(text is None or type(text) == six.text_type)
assert(type(limit) in six.integer_types)
assert(limit >= 0)

if text is None:
return

# encode the given string in the specified encoding
s = text.encode(encoding)

# when the resulting byte string is longer than the given limit ..
if len(s) > limit:
# .. truncate, and
s = s[:limit]

# decode back, ignoring errors that result from truncation
# in the middle of multi-byte encodings
text = s.decode(encoding, 'ignore')

if return_encoded:
s = text.encode(encoding)

if return_encoded:
return s
else:
return text


@public
def xor(d1, d2):
"""
XOR two binary strings of arbitrary (equal) length.

:param d1: The first binary string.
:type d1: binary
:param d2: The second binary string.
:type d2: binary

:returns: XOR of the binary strings (``XOR(d1, d2)``)
:rtype: bytes
"""
if type(d1) != six.binary_type:
raise Exception("invalid type {} for d1 - must be binary".format(type(d1)))
if type(d2) != six.binary_type:
raise Exception("invalid type {} for d2 - must be binary".format(type(d2)))
if len(d1) != len(d2):
raise Exception("cannot XOR binary string of differing length ({} != {})".format(len(d1), len(d2)))

d1 = array('B', d1)
d2 = array('B', d2)

for i in range(len(d1)):
d1[i] ^= d2[i]

if six.PY3:
return d1.tobytes()
else:
return d1.tostring()


@public
def utcstr(ts=None):
"""
Format UTC timestamp in ISO 8601 format.

Note: to parse an ISO 8601 formatted string, use the **iso8601**
module instead (e.g. ``iso8601.parse_date("2014-05-23T13:03:44.123Z")``).

:param ts: The timestamp to format.
:type ts: instance of :py:class:`datetime.datetime` or ``None``

:returns: Timestamp formatted in ISO 8601 format.
:rtype: str
"""
assert(ts is None or isinstance(ts, datetime))
if ts is None:
ts = datetime.utcnow()
return u"{0}Z".format(ts.strftime(u"%Y-%m-%dT%H:%M:%S.%f")[:-3])


@public
def utcnow():
"""
Get current time in UTC as ISO 8601 string.

:returns: Current time as string in ISO 8601 format.
:rtype: str
"""
return utcstr()


class IdGenerator(object):
"""
ID generator for WAMP request IDs.

WAMP request IDs are sequential per WAMP session, starting at 1 and
wrapping around at 2**53 (both value are inclusive [1, 2**53]).

The upper bound **2**53** is chosen since it is the maximum integer that can be
represented as a IEEE double such that all smaller integers are representable as well.

Hence, IDs can be safely used with languages that use IEEE double as their
main (or only) number type (JavaScript, Lua, etc).

See https://github.com/wamp-proto/wamp-proto/blob/master/spec/basic.md#ids
"""

def __init__(self):
self._next = 0 # starts at 1; next() pre-increments

def next(self):
"""
Returns next ID.

:returns: The next ID.
:rtype: int
"""
self._next += 1
if self._next > 9007199254740992:
self._next = 1
return self._next

# generator protocol
def __next__(self):
return self.next()


#
# Performance comparison of IdGenerator.next(), id() and rid().
#
# All tests were performed on:
#
# - Ubuntu 14.04 LTS x86-64
# - Intel Core i7 920 @ 3.3GHz
#
# The tests generated 100 mio. IDs and run-time was measured
# as wallclock from Unix "time" command. In each run, a single CPU
# core was essentially at 100% load all the time (though the sys/usr
# ratio was different).
#
# PyPy 2.6.1:
#
# IdGenerator.next() 0.5s
# id() 29.4s
# rid() 106.1s
#
# CPython 2.7.10:
#
# IdGenerator.next() 49.0s
# id() 370.5s
# rid() 196.4s
#

#
# Note on the ID range [0, 2**53]. We once reduced the range to [0, 2**31].
# This lead to extremely hard to track down issues due to ID collisions!
# Here: https://github.com/crossbario/autobahn-python/issues/419#issue-90483337
#


# 8 byte mask with 53 LSBs set (WAMP requires IDs from [0, 2**53]
_WAMP_ID_MASK = struct.unpack(">Q", b"\x00\x1f\xff\xff\xff\xff\xff\xff")[0]


def rid():
"""
Generate a new random integer ID from range **[0, 2**53]**.

The generated ID is uniformly distributed over the whole range, doesn't have
a period (no pseudo-random generator is used) and cryptographically strong.

The upper bound **2**53** is chosen since it is the maximum integer that can be
represented as a IEEE double such that all smaller integers are representable as well.

Hence, IDs can be safely used with languages that use IEEE double as their
main (or only) number type (JavaScript, Lua, etc).

:returns: A random integer ID.
:rtype: int
"""
return struct.unpack("@Q", os.urandom(8))[0] & _WAMP_ID_MASK


# noinspection PyShadowingBuiltins
def id():
"""
Generate a new random integer ID from range **[0, 2**53]**.

The generated ID is based on a pseudo-random number generator (Mersenne Twister,
which has a period of 2**19937-1). It is NOT cryptographically strong, and
hence NOT suitable to generate e.g. secret keys or access tokens.

The upper bound **2**53** is chosen since it is the maximum integer that can be
represented as a IEEE double such that all smaller integers are representable as well.

Hence, IDs can be safely used with languages that use IEEE double as their
main (or only) number type (JavaScript, Lua, etc).

:returns: A random integer ID.
:rtype: int
"""
return random.randint(0, 9007199254740992)


def newid(length=16):
"""
Generate a new random string ID.

The generated ID is uniformly distributed and cryptographically strong. It is
hence usable for things like secret keys and access tokens.

:param length: The length (in chars) of the ID to generate.
:type length: int

:returns: A random string ID.
:rtype: str
"""
l = int(math.ceil(float(length) * 6. / 8.))
return base64.b64encode(os.urandom(l))[:length].decode('ascii')


# a standard base36 character set
# DEFAULT_TOKEN_CHARS = string.digits + string.ascii_uppercase

# we take out the following 9 chars (leaving 27), because there
# is visual ambiguity: 0/O/D, 1/I, 8/B, 2/Z
DEFAULT_TOKEN_CHARS = u'345679ACEFGHJKLMNPQRSTUVWXY'
"""
Default set of characters to create rtokens from.
"""

DEFAULT_ZBASE32_CHARS = u'13456789abcdefghijkmnopqrstuwxyz'
"""
Our choice of confusing characters to eliminate is: `0', `l', `v', and `2'. Our
reasoning is that `0' is potentially mistaken for `o', that `l' is potentially
mistaken for `1' or `i', that `v' is potentially mistaken for `u' or `r'
(especially in handwriting) and that `2' is potentially mistaken for `z'
(especially in handwriting).

Note that we choose to focus on typed and written transcription more than on
vocal, since humans already have a well-established system of disambiguating
spoken alphanumerics, such as the United States military's "Alpha Bravo Charlie
Delta" and telephone operators' "Is that 'd' as in 'dog'?".

* http://philzimmermann.com/docs/human-oriented-base-32-encoding.txt
"""


@public
def generate_token(char_groups, chars_per_group, chars=None, sep=None, lower_case=False):
"""
Generate cryptographically strong tokens, which are strings like `M6X5-YO5W-T5IK`.
These can be used e.g. for used-only-once activation tokens or the like.

The returned token has an entropy of
``math.log(len(chars), 2.) * chars_per_group * char_groups``
bits.

With the default charset and 4 characters per group, ``generate_token()`` produces
strings with the following entropy:

================ =================== ========================================
character groups entropy (at least) recommended use
================ =================== ========================================
2 38 bits
3 57 bits one-time activation or pairing code
4 76 bits secure user password
5 95 bits
6 114 bits globally unique serial / product code
7 133 bits
================ =================== ========================================

Here are some examples:

* token(3): ``9QXT-UXJW-7R4H``
* token(4): ``LPNN-JMET-KWEP-YK45``
* token(6): ``NXW9-74LU-6NUH-VLPV-X6AG-QUE3``

:param char_groups: Number of character groups (or characters if chars_per_group == 1).
:type char_groups: int

:param chars_per_group: Number of characters per character group (or 1 to return a token with no grouping).
:type chars_per_group: int

:param chars: Characters to choose from. Default is 27 character subset
of the ISO basic Latin alphabet (see: ``DEFAULT_TOKEN_CHARS``).
:type chars: str or None

:param sep: When separating groups in the token, the separater string.
:type sep: str

:param lower_case: If ``True``, generate token in lower-case.
:type lower_case: bool

:returns: The generated token.
:rtype: str
"""
assert(type(char_groups) in six.integer_types)
assert(type(chars_per_group) in six.integer_types)
assert(chars is None or type(chars) == six.text_type)
chars = chars or DEFAULT_TOKEN_CHARS
if lower_case:
chars = chars.lower()
sep = sep or u'-'
rng = random.SystemRandom()
token_value = u''.join(rng.choice(chars) for _ in range(char_groups * chars_per_group))
if chars_per_group > 1:
return sep.join(map(u''.join, zip(*[iter(token_value)] * chars_per_group)))
else:
return token_value


@public
def generate_activation_code():
"""
Generate a one-time activation code or token of the form ``u'W97F-96MJ-YGJL'``.
The generated value is cryptographically strong and has (at least) 57 bits of entropy.

:returns: The generated activation code.
:rtype: str
"""
return generate_token(char_groups=3, chars_per_group=4, chars=DEFAULT_TOKEN_CHARS, sep=u'-', lower_case=False)


@public
def generate_user_password():
"""
Generate a secure, random user password of the form ``u'kgojzi61dn5dtb6d'``.
The generated value is cryptographically strong and has (at least) 76 bits of entropy.

:returns: The generated password.
:rtype: str
"""
return generate_token(char_groups=16, chars_per_group=1, chars=DEFAULT_ZBASE32_CHARS, sep=u'-', lower_case=True)


@public
def generate_serial_number():
"""
Generate a globally unique serial / product code of the form ``u'YRAC-EL4X-FQQE-AW4T-WNUV-VN6T'``.
The generated value is cryptographically strong and has (at least) 114 bits of entropy.

:returns: The generated serial number / product code.
:rtype: str
"""
return generate_token(char_groups=6, chars_per_group=4, chars=DEFAULT_TOKEN_CHARS, sep=u'-', lower_case=False)


# Select the most precise walltime measurement function available
# on the platform
#
if sys.platform.startswith('win'):
# On Windows, this function returns wall-clock seconds elapsed since the
# first call to this function, as a floating point number, based on the
# Win32 function QueryPerformanceCounter(). The resolution is typically
# better than one microsecond
if sys.version_info >= (3, 8):
_rtime = time.perf_counter
else:
_rtime = time.clock
_ = _rtime() # this starts wallclock
else:
# On Unix-like platforms, this used the first available from this list:
# (1) gettimeofday() -- resolution in microseconds
# (2) ftime() -- resolution in milliseconds
# (3) time() -- resolution in seconds
_rtime = time.time


@public
def rtime():
"""
Precise, fast wallclock time.

:returns: The current wallclock in seconds. Returned values are only guaranteed
to be meaningful relative to each other.
:rtype: float
"""
return _rtime()


class Stopwatch(object):
"""
Stopwatch based on walltime.

This can be used to do code timing and uses the most precise walltime measurement
available on the platform. This is a very light-weight object,
so create/dispose is very cheap.
"""

def __init__(self, start=True):
"""

:param start: If ``True``, immediately start the stopwatch.
:type start: bool
"""
self._elapsed = 0
if start:
self._started = rtime()
self._running = True
else:
self._started = None
self._running = False

def elapsed(self):
"""
Return total time elapsed in seconds during which the stopwatch was running.

:returns: The elapsed time in seconds.
:rtype: float
"""
if self._running:
now = rtime()
return self._elapsed + (now - self._started)
else:
return self._elapsed

def pause(self):
"""
Pauses the stopwatch and returns total time elapsed in seconds during which
the stopwatch was running.

:returns: The elapsed time in seconds.
:rtype: float
"""
if self._running:
now = rtime()
self._elapsed += now - self._started
self._running = False
return self._elapsed
else:
return self._elapsed

def resume(self):
"""
Resumes a paused stopwatch and returns total elapsed time in seconds
during which the stopwatch was running.

:returns: The elapsed time in seconds.
:rtype: float
"""
if not self._running:
self._started = rtime()
self._running = True
return self._elapsed
else:
now = rtime()
return self._elapsed + (now - self._started)

def stop(self):
"""
Stops the stopwatch and returns total time elapsed in seconds during which
the stopwatch was (previously) running.

:returns: The elapsed time in seconds.
:rtype: float
"""
elapsed = self.pause()
self._elapsed = 0
self._started = None
self._running = False
return elapsed


class Tracker(object):
"""
A key-based statistics tracker.
"""

def __init__(self, tracker, tracked):
"""
"""
self.tracker = tracker
self.tracked = tracked
self._timings = {}
self._offset = rtime()
self._dt_offset = datetime.utcnow()

def track(self, key):
"""
Track elapsed for key.

:param key: Key under which to track the timing.
:type key: str
"""
self._timings[key] = rtime()

def diff(self, start_key, end_key, formatted=True):
"""
Get elapsed difference between two previously tracked keys.

:param start_key: First key for interval (older timestamp).
:type start_key: str
:param end_key: Second key for interval (younger timestamp).
:type end_key: str
:param formatted: If ``True``, format computed time period and return string.
:type formatted: bool

:returns: Computed time period in seconds (or formatted string).
:rtype: float or str
"""
if end_key in self._timings and start_key in self._timings:
d = self._timings[end_key] - self._timings[start_key]
if formatted:
if d < 0.00001: # 10us
s = "%d ns" % round(d * 1000000000.)
elif d < 0.01: # 10ms
s = "%d us" % round(d * 1000000.)
elif d < 10: # 10s
s = "%d ms" % round(d * 1000.)
else:
s = "%d s" % round(d)
return s.rjust(8)
else:
return d
else:
if formatted:
return "n.a.".rjust(8)
else:
return None

def absolute(self, key):
"""
Return the UTC wall-clock time at which a tracked event occurred.

:param key: The key
:type key: str

:returns: Timezone-naive datetime.
:rtype: instance of :py:class:`datetime.datetime`
"""
elapsed = self[key]
if elapsed is None:
raise KeyError("No such key \"%s\"." % elapsed)
return self._dt_offset + timedelta(seconds=elapsed)

def __getitem__(self, key):
if key in self._timings:
return self._timings[key] - self._offset
else:
return None

def __iter__(self):
return self._timings.__iter__()

def __str__(self):
return pformat(self._timings)


class EqualityMixin(object):
"""
Mixing to add equality comparison operators to a class.

Two objects are identical under this mixin, if and only if:

1. both object have the same class
2. all non-private object attributes are equal
"""

def __eq__(self, other):
"""
Compare this object to another object for equality.

:param other: The other object to compare with.
:type other: obj

:returns: ``True`` iff the objects are equal.
:rtype: bool
"""
if not isinstance(other, self.__class__):
return False
# we only want the actual message data attributes (not eg _serialize)
for k in self.__dict__:
if not k.startswith('_'):
if not self.__dict__[k] == other.__dict__[k]:
return False
return True
# return (isinstance(other, self.__class__) and self.__dict__ == other.__dict__)

def __ne__(self, other):
"""
Compare this object to another object for inequality.

:param other: The other object to compare with.
:type other: obj

:returns: ``True`` iff the objects are not equal.
:rtype: bool
"""
return not self.__eq__(other)


def wildcards2patterns(wildcards):
"""
Compute a list of regular expression patterns from a list of
wildcard strings. A wildcard string uses '*' as a wildcard character
matching anything.

:param wildcards: List of wildcard strings to compute regular expression patterns for.
:type wildcards: list of str

:returns: Computed regular expressions.
:rtype: list of obj
"""
# note that we add the ^ and $ so that the *entire* string must
# match. Without this, e.g. a prefix will match:
# re.match('.*good\\.com', 'good.com.evil.com') # match!
# re.match('.*good\\.com$', 'good.com.evil.com') # no match!
return [re.compile('^' + wc.replace('.', r'\.').replace('*', '.*') + '$') for wc in wildcards]


class ObservableMixin(object):
"""
Internal utility for enabling event-listeners on particular objects
"""

# A "helper" style composable class (as opposed to a mix-in) might
# be a lot easier to deal with here. Having an __init__ method
# with a "mix in" style class can be fragile and error-prone,
# especially if it takes arguments. Since we don't use the
# "parent" beavior anywhere, I didn't add a .set_parent() (yet?)

# these are class-level globals; individual instances are
# initialized as-needed (e.g. the first .on() call adds a
# _listeners dict). Thus, subclasses don't have to call super()
# properly etc.
_parent = None
_valid_events = None
_listeners = None

def set_valid_events(self, valid_events=None):
"""
:param valid_events: if non-None, .on() or .fire() with an event
not listed in valid_events raises an exception.
"""
self._valid_events = list(valid_events)

def _check_event(self, event):
"""
Internal helper. Throws RuntimeError if we have a valid_events
list, and the given event isnt' in it. Does nothing otherwise.
"""
if self._valid_events and event not in self._valid_events:
raise RuntimeError(
"Invalid event '{event}'. Expected one of: {events}".format(
event=event,
events=', '.join(self._valid_events),
)
)

def on(self, event, handler):
"""
Add a handler for an event.

:param event: the name of the event

:param handler: a callable thats invoked when .fire() is
called for this events. Arguments will be whatever are given
to .fire()
"""
# print("adding '{}' to '{}': {}".format(event, hash(self), handler))
self._check_event(event)
if self._listeners is None:
self._listeners = dict()
if event not in self._listeners:
self._listeners[event] = []
self._listeners[event].append(handler)

def off(self, event=None, handler=None):
"""
Stop listening for a single event, or all events.

:param event: if None, remove all listeners. Otherwise, remove
listeners for the single named event.

:param handler: if None, remove all handlers for the named
event; otherwise remove just the given handler.
"""
if event is None:
if handler is not None:
# maybe this should mean "remove the given handler
# from any event at all that contains it"...?
raise RuntimeError(
"Can't specificy a specific handler without an event"
)
self._listeners = dict()
else:
if self._listeners is None:
return
self._check_event(event)
if event in self._listeners:
if handler is None:
del self._listeners[event]
else:
self._listeners[event].discard(handler)

def fire(self, event, *args, **kwargs):
"""
Fire a particular event.

:param event: the event to fire. All other args and kwargs are
passed on to the handler(s) for the event.

:return: a Deferred/Future gathering all async results from
all handlers and/or parent handlers.
"""
# print("firing '{}' from '{}'".format(event, hash(self)))
if self._listeners is None:
return txaio.create_future(result=[])

self._check_event(event)
res = []
for handler in self._listeners.get(event, []):
future = txaio.as_future(handler, *args, **kwargs)
res.append(future)
if self._parent is not None:
res.append(self._parent.fire(event, *args, **kwargs))
return txaio.gather(res, consume_exceptions=False)


class _LazyHexFormatter(object):
"""
This is used to avoid calling binascii.hexlify() on data given to
log.debug() calls unless debug is active (for example). Like::

self.log.debug(
"Some data: {octets}",
octets=_LazyHexFormatter(os.urandom(32)),
)
"""
__slots__ = ('obj',)

def __init__(self, obj):
self.obj = obj

def __str__(self):
return binascii.hexlify(self.obj).decode('ascii')


def _is_tls_error(instance):
"""
:returns: True if we have TLS support and 'instance' is an
instance of :class:`OpenSSL.SSL.Error` otherwise False
"""
if _TLS:
return isinstance(instance, SSL.Error)
return False


def _maybe_tls_reason(instance):
"""
:returns: a TLS error-message, or empty-string if 'instance' is
not a TLS error.
"""
if _is_tls_error(instance):
ssl_error = instance.args[0][0]
return u"SSL error: {msg} (in {func})".format(
func=ssl_error[1],
msg=ssl_error[2],
)
return u""

+ 83
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/__init__.py View File

@@ -0,0 +1,83 @@
###############################################################################
#
# The MIT License (MIT)
#
# Copyright (c) Crossbar.io Technologies GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################

from __future__ import absolute_import

from autobahn.wamp.types import \
ComponentConfig, \
SessionDetails, \
CloseDetails, \
RegisterOptions, \
CallOptions, \
CallDetails, \
CallResult, \
SubscribeOptions, \
PublishOptions, \
EventDetails

from autobahn.wamp.exception import \
Error, \
SessionNotReady, \
SerializationError, \
ProtocolError, \
TransportLost, \
ApplicationError, \
InvalidUri

from autobahn.wamp.interfaces import ISession

from autobahn.wamp.uri import \
error, \
register, \
subscribe


__all__ = (
'ComponentConfig',
'SessionDetails',
'CloseDetails',
'RegisterOptions',
'CallOptions',
'CallDetails',
'CallResult',
'SubscribeOptions',
'PublishOptions',
'EventDetails',

'Error',
'SessionNotReady',
'SerializationError',
'ProtocolError',
'TransportLost',
'ApplicationError',
'InvalidUri',

'ISession',

'error',
'register',
'subscribe',
)

+ 314
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/exception.py View File

@@ -0,0 +1,314 @@
###############################################################################
#
# The MIT License (MIT)
#
# Copyright (c) Crossbar.io Technologies GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################

from __future__ import absolute_import

import six

from autobahn.util import public
from autobahn.wamp.uri import error

__all__ = (
'Error',
'SessionNotReady',
'SerializationError',
'ProtocolError',
'TransportLost',
'ApplicationError',
'NotAuthorized',
'InvalidUri',
)


@public
class Error(RuntimeError):
"""
Base class for all exceptions related to WAMP.
"""


@public
class SessionNotReady(Error):
"""
The application tried to perform a WAMP interaction, but the
session is not yet fully established.
"""


@public
class SerializationError(Error):
"""
Exception raised when the WAMP serializer could not serialize the
application payload (``args`` or ``kwargs`` for ``CALL``, ``PUBLISH``, etc).
"""


@public
class InvalidUriError(Error):
"""
Exception raised when an invalid WAMP URI was used.
"""


@public
class ProtocolError(Error):
"""
Exception raised when WAMP protocol was violated. Protocol errors
are fatal and are handled by the WAMP implementation. They are
not supposed to be handled at the application level.
"""


@public
class TransportLost(Error):
"""
Exception raised when the transport underlying the WAMP session
was lost or is not connected.
"""


@public
class ApplicationError(Error):
"""
Base class for all exceptions that can/may be handled
at the application level.
"""

INVALID_URI = u"wamp.error.invalid_uri"
"""
Peer provided an incorrect URI for a URI-based attribute of a WAMP message
such as a realm, topic or procedure.
"""

INVALID_PAYLOAD = u"wamp.error.invalid_payload"
"""
The application payload could not be serialized.
"""

PAYLOAD_SIZE_EXCEEDED = u"wamp.error.payload_size_exceeded"
"""
The application payload could not be transported becuase the serialized/framed payload
exceeds the transport limits.
"""

NO_SUCH_PROCEDURE = u"wamp.error.no_such_procedure"
"""
A Dealer could not perform a call, since not procedure is currently registered
under the given URI.
"""

PROCEDURE_ALREADY_EXISTS = u"wamp.error.procedure_already_exists"
"""
A procedure could not be registered, since a procedure with the given URI is
already registered.
"""

PROCEDURE_EXISTS_INVOCATION_POLICY_CONFLICT = u"wamp.error.procedure_exists_with_different_invocation_policy"
"""
A procedure could not be registered, since a procedure with the given URI is
already registered, and the registration has a conflicting invocation policy.
"""

NO_SUCH_REGISTRATION = u"wamp.error.no_such_registration"
"""
A Dealer could not perform a unregister, since the given registration is not active.
"""

NO_SUCH_SUBSCRIPTION = u"wamp.error.no_such_subscription"
"""
A Broker could not perform a unsubscribe, since the given subscription is not active.
"""

NO_SUCH_SESSION = u"wamp.error.no_such_session"
"""
A router could not perform an operation, since a session ID specified was non-existant.
"""

INVALID_ARGUMENT = u"wamp.error.invalid_argument"
"""
A call failed, since the given argument types or values are not acceptable to the
called procedure - in which case the *Callee* may throw this error. Or a Router
performing *payload validation* checked the payload (``args`` / ``kwargs``) of a call,
call result, call error or publish, and the payload did not conform.
"""

# FIXME: this currently isn't used neither in Autobahn nor Crossbar. Check!
SYSTEM_SHUTDOWN = u"wamp.error.system_shutdown"
"""
The *Peer* is shutting down completely - used as a ``GOODBYE`` (or ``ABORT``) reason.
"""

# FIXME: this currently isn't used neither in Autobahn nor Crossbar. Check!
CLOSE_REALM = u"wamp.error.close_realm"
"""
The *Peer* want to leave the realm - used as a ``GOODBYE`` reason.
"""

# FIXME: this currently isn't used neither in Autobahn nor Crossbar. Check!
GOODBYE_AND_OUT = u"wamp.error.goodbye_and_out"
"""
A *Peer* acknowledges ending of a session - used as a ``GOOBYE`` reply reason.
"""

NOT_AUTHORIZED = u"wamp.error.not_authorized"
"""
A call, register, publish or subscribe failed, since the session is not authorized
to perform the operation.
"""

AUTHORIZATION_FAILED = u"wamp.error.authorization_failed"
"""
A Dealer or Broker could not determine if the *Peer* is authorized to perform
a join, call, register, publish or subscribe, since the authorization operation
*itself* failed. E.g. a custom authorizer did run into an error.
"""

AUTHENTICATION_FAILED = u"wamp.error.authentication_failed"
"""
Something failed with the authentication itself, that is, authentication could
not run to end.
"""

NO_AUTH_METHOD = u"wamp.error.no_auth_method"
"""
No authentication method the peer offered is available or active.
"""

NO_SUCH_REALM = u"wamp.error.no_such_realm"
"""
Peer wanted to join a non-existing realm (and the *Router* did not allow to auto-create
the realm).
"""

NO_SUCH_ROLE = u"wamp.error.no_such_role"
"""
A *Peer* was to be authenticated under a Role that does not (or no longer) exists on the Router.
For example, the *Peer* was successfully authenticated, but the Role configured does not
exists - hence there is some misconfiguration in the Router.
"""

NO_SUCH_PRINCIPAL = u"wamp.error.no_such_principal"
"""
A *Peer* was authenticated for an authid that does not or longer exists.
"""

CANCELED = u"wamp.error.canceled"
"""
A Dealer or Callee canceled a call previously issued (WAMP AP).
"""

TIMEOUT = u"wamp.error.timeout"
"""
A pending (in-flight) call was timed out.
"""

# FIXME: this currently isn't used neither in Autobahn nor Crossbar. Check!
NO_ELIGIBLE_CALLEE = u"wamp.error.no_eligible_callee"
"""
A *Dealer* could not perform a call, since a procedure with the given URI is registered,
but *Callee Black- and Whitelisting* and/or *Caller Exclusion* lead to the
exclusion of (any) *Callee* providing the procedure (WAMP AP).
"""

ENC_NO_PAYLOAD_CODEC = u"wamp.error.no_payload_codec"
"""
WAMP message in payload transparency mode received, but no codec set
or codec did not decode the payload.
"""

ENC_TRUSTED_URI_MISMATCH = u"wamp.error.encryption.trusted_uri_mismatch"
"""
WAMP-cryptobox application payload end-to-end encryption error.
"""

ENC_DECRYPT_ERROR = u"wamp.error.encryption.decrypt_error"
"""
WAMP-cryptobox application payload end-to-end encryption error.
"""

def __init__(self, error, *args, **kwargs):
"""

:param error: The URI of the error that occurred, e.g. ``wamp.error.not_authorized``.
:type error: str
"""
Exception.__init__(self, *args)
self.kwargs = kwargs
self.error = error
self.enc_algo = kwargs.pop('enc_algo', None)
self.callee = kwargs.pop('callee', None)
self.callee_authid = kwargs.pop('callee_authid', None)
self.callee_authrole = kwargs.pop('callee_authrole', None)
self.forward_for = kwargs.pop('forward_for', None)

@public
def error_message(self):
"""
Get the error message of this exception.

:returns: The error message.
:rtype: str
"""
return u'{0}: {1}'.format(
self.error,
u' '.join([six.text_type(a) for a in self.args]),
)

def __unicode__(self):
if self.kwargs and 'traceback' in self.kwargs:
tb = u':\n' + u'\n'.join(self.kwargs.pop('traceback')) + u'\n'
self.kwargs['traceback'] = u'...'
else:
tb = u''
return u"ApplicationError(error=<{0}>, args={1}, kwargs={2}, enc_algo={3}, callee={4}, callee_authid={5}, callee_authrole={6}, forward_for={7}){8}".format(
self.error, list(self.args), self.kwargs, self.enc_algo, self.callee, self.callee_authid, self.callee_authrole, self.forward_for, tb)

def __str__(self):
if six.PY3:
return self.__unicode__()
else:
return self.__unicode__().encode('utf8')


@error(ApplicationError.NOT_AUTHORIZED)
class NotAuthorized(Exception):
"""
Not authorized to perform the respective action.
"""


@error(ApplicationError.INVALID_URI)
class InvalidUri(Exception):
"""
The URI for a topic, procedure or error is not a valid WAMP URI.
"""


@error(ApplicationError.INVALID_PAYLOAD)
class InvalidPayload(Exception):
"""
The URI for a topic, procedure or error is not a valid WAMP URI.
"""

BIN
venv/lib/python3.7/site-packages/autobahn/wamp/gen/schema/session.bfbs View File


+ 38
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/Map.py View File

@@ -0,0 +1,38 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: wamp

import flatbuffers

class Map(object):
__slots__ = ['_tab']

@classmethod
def GetRootAsMap(cls, buf, offset):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = Map()
x.Init(buf, n + offset)
return x

# Map
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)

# Map
def Key(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return self._tab.String(o + self._tab.Pos)
return None

# Map
def Value(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
if o != 0:
return self._tab.String(o + self._tab.Pos)
return None

def MapStart(builder): builder.StartObject(2)
def MapAddKey(builder, key): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(key), 0)
def MapAddValue(builder, value): builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(value), 0)
def MapEnd(builder): return builder.EndObject()

+ 22
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/Void.py View File

@@ -0,0 +1,22 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: wamp

import flatbuffers

class Void(object):
__slots__ = ['_tab']

@classmethod
def GetRootAsVoid(cls, buf, offset):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = Void()
x.Init(buf, n + offset)
return x

# Void
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)

def VoidStart(builder): builder.StartObject(0)
def VoidEnd(builder): return builder.EndObject()

+ 11
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/AuthFactor.py View File

@@ -0,0 +1,11 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

class AuthFactor(object):
NONE = 0
AuthTicketRequest = 1
AuthCraRequest = 2
AuthScramRequest = 3
AuthCryptosignRequest = 4


+ 8
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/AuthMode.py View File

@@ -0,0 +1,8 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

class AuthMode(object):
FIRST = 0
MULTIFACTOR = 1


+ 22
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/AuthTicketChallenge.py View File

@@ -0,0 +1,22 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

import flatbuffers

class AuthTicketChallenge(object):
__slots__ = ['_tab']

@classmethod
def GetRootAsAuthTicketChallenge(cls, buf, offset):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = AuthTicketChallenge()
x.Init(buf, n + offset)
return x

# AuthTicketChallenge
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)

def AuthTicketChallengeStart(builder): builder.StartObject(0)
def AuthTicketChallengeEnd(builder): return builder.EndObject()

+ 22
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/AuthTicketRequest.py View File

@@ -0,0 +1,22 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

import flatbuffers

class AuthTicketRequest(object):
__slots__ = ['_tab']

@classmethod
def GetRootAsAuthTicketRequest(cls, buf, offset):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = AuthTicketRequest()
x.Init(buf, n + offset)
return x

# AuthTicketRequest
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)

def AuthTicketRequestStart(builder): builder.StartObject(0)
def AuthTicketRequestEnd(builder): return builder.EndObject()

+ 102
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/CalleeFeatures.py View File

@@ -0,0 +1,102 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

import flatbuffers

class CalleeFeatures(object):
__slots__ = ['_tab']

@classmethod
def GetRootAsCalleeFeatures(cls, buf, offset):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = CalleeFeatures()
x.Init(buf, n + offset)
return x

# CalleeFeatures
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)

# CalleeFeatures
def CallerIdentification(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# CalleeFeatures
def CallTrustlevels(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# CalleeFeatures
def CallTimeout(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# CalleeFeatures
def CallCanceling(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# CalleeFeatures
def ProgressiveCallResults(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# CalleeFeatures
def RegistrationRevocation(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# CalleeFeatures
def PatternBasedRegistration(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(16))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# CalleeFeatures
def SharedRegistration(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(18))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# CalleeFeatures
def PayloadTransparency(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(20))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# CalleeFeatures
def PayloadEncryptionCryptobox(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(22))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

def CalleeFeaturesStart(builder): builder.StartObject(10)
def CalleeFeaturesAddCallerIdentification(builder, callerIdentification): builder.PrependBoolSlot(0, callerIdentification, 0)
def CalleeFeaturesAddCallTrustlevels(builder, callTrustlevels): builder.PrependBoolSlot(1, callTrustlevels, 0)
def CalleeFeaturesAddCallTimeout(builder, callTimeout): builder.PrependBoolSlot(2, callTimeout, 0)
def CalleeFeaturesAddCallCanceling(builder, callCanceling): builder.PrependBoolSlot(3, callCanceling, 0)
def CalleeFeaturesAddProgressiveCallResults(builder, progressiveCallResults): builder.PrependBoolSlot(4, progressiveCallResults, 0)
def CalleeFeaturesAddRegistrationRevocation(builder, registrationRevocation): builder.PrependBoolSlot(5, registrationRevocation, 0)
def CalleeFeaturesAddPatternBasedRegistration(builder, patternBasedRegistration): builder.PrependBoolSlot(6, patternBasedRegistration, 0)
def CalleeFeaturesAddSharedRegistration(builder, sharedRegistration): builder.PrependBoolSlot(7, sharedRegistration, 0)
def CalleeFeaturesAddPayloadTransparency(builder, payloadTransparency): builder.PrependBoolSlot(8, payloadTransparency, 0)
def CalleeFeaturesAddPayloadEncryptionCryptobox(builder, payloadEncryptionCryptobox): builder.PrependBoolSlot(9, payloadEncryptionCryptobox, 0)
def CalleeFeaturesEnd(builder): return builder.EndObject()

+ 70
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/CallerFeatures.py View File

@@ -0,0 +1,70 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

import flatbuffers

class CallerFeatures(object):
__slots__ = ['_tab']

@classmethod
def GetRootAsCallerFeatures(cls, buf, offset):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = CallerFeatures()
x.Init(buf, n + offset)
return x

# CallerFeatures
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)

# CallerFeatures
def CallerIdentification(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# CallerFeatures
def CallTimeout(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# CallerFeatures
def CallCanceling(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# CallerFeatures
def ProgressiveCallResults(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# CallerFeatures
def PayloadTransparency(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# CallerFeatures
def PayloadEncryptionCryptobox(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

def CallerFeaturesStart(builder): builder.StartObject(6)
def CallerFeaturesAddCallerIdentification(builder, callerIdentification): builder.PrependBoolSlot(0, callerIdentification, 0)
def CallerFeaturesAddCallTimeout(builder, callTimeout): builder.PrependBoolSlot(1, callTimeout, 0)
def CallerFeaturesAddCallCanceling(builder, callCanceling): builder.PrependBoolSlot(2, callCanceling, 0)
def CallerFeaturesAddProgressiveCallResults(builder, progressiveCallResults): builder.PrependBoolSlot(3, progressiveCallResults, 0)
def CallerFeaturesAddPayloadTransparency(builder, payloadTransparency): builder.PrependBoolSlot(4, payloadTransparency, 0)
def CallerFeaturesAddPayloadEncryptionCryptobox(builder, payloadEncryptionCryptobox): builder.PrependBoolSlot(5, payloadEncryptionCryptobox, 0)
def CallerFeaturesEnd(builder): return builder.EndObject()

+ 9
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/CancelMode.py View File

@@ -0,0 +1,9 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

class CancelMode(object):
SKIP = 0
ABORT = 1
KILL = 2


+ 42
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/Challenge.py View File

@@ -0,0 +1,42 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

import flatbuffers

class Challenge(object):
__slots__ = ['_tab']

@classmethod
def GetRootAsChallenge(cls, buf, offset):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = Challenge()
x.Init(buf, n + offset)
return x

# Challenge
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)

# Challenge
def Method(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
return 0

# Challenge
def Extra(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
if o != 0:
x = self._tab.Indirect(o + self._tab.Pos)
from .Map import Map
obj = Map()
obj.Init(self._tab.Bytes, x)
return obj
return None

def ChallengeStart(builder): builder.StartObject(2)
def ChallengeAddMethod(builder, method): builder.PrependUint8Slot(0, method, 0)
def ChallengeAddExtra(builder, extra): builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(extra), 0)
def ChallengeEnd(builder): return builder.EndObject()

+ 8
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/ChannelBinding.py View File

@@ -0,0 +1,8 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

class ChannelBinding(object):
NONE = 0
TLS_UNIQUE = 1


+ 126
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/DealerFeatures.py View File

@@ -0,0 +1,126 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

import flatbuffers

class DealerFeatures(object):
__slots__ = ['_tab']

@classmethod
def GetRootAsDealerFeatures(cls, buf, offset):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = DealerFeatures()
x.Init(buf, n + offset)
return x

# DealerFeatures
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)

# DealerFeatures
def CallerIdentification(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# DealerFeatures
def CallTrustlevels(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# DealerFeatures
def CallTimeout(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# DealerFeatures
def CallCanceling(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# DealerFeatures
def ProgressiveCallResults(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# DealerFeatures
def RegistrationRevocation(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# DealerFeatures
def PatternBasedRegistration(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(16))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# DealerFeatures
def SharedRegistration(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(18))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# DealerFeatures
def SessionMetaApi(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(20))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# DealerFeatures
def RegistrationMetaApi(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(22))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# DealerFeatures
def TestamentMetaApi(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(24))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# DealerFeatures
def PayloadTransparency(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(26))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# DealerFeatures
def PayloadEncryptionCryptobox(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(28))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

def DealerFeaturesStart(builder): builder.StartObject(13)
def DealerFeaturesAddCallerIdentification(builder, callerIdentification): builder.PrependBoolSlot(0, callerIdentification, 0)
def DealerFeaturesAddCallTrustlevels(builder, callTrustlevels): builder.PrependBoolSlot(1, callTrustlevels, 0)
def DealerFeaturesAddCallTimeout(builder, callTimeout): builder.PrependBoolSlot(2, callTimeout, 0)
def DealerFeaturesAddCallCanceling(builder, callCanceling): builder.PrependBoolSlot(3, callCanceling, 0)
def DealerFeaturesAddProgressiveCallResults(builder, progressiveCallResults): builder.PrependBoolSlot(4, progressiveCallResults, 0)
def DealerFeaturesAddRegistrationRevocation(builder, registrationRevocation): builder.PrependBoolSlot(5, registrationRevocation, 0)
def DealerFeaturesAddPatternBasedRegistration(builder, patternBasedRegistration): builder.PrependBoolSlot(6, patternBasedRegistration, 0)
def DealerFeaturesAddSharedRegistration(builder, sharedRegistration): builder.PrependBoolSlot(7, sharedRegistration, 0)
def DealerFeaturesAddSessionMetaApi(builder, sessionMetaApi): builder.PrependBoolSlot(8, sessionMetaApi, 0)
def DealerFeaturesAddRegistrationMetaApi(builder, registrationMetaApi): builder.PrependBoolSlot(9, registrationMetaApi, 0)
def DealerFeaturesAddTestamentMetaApi(builder, testamentMetaApi): builder.PrependBoolSlot(10, testamentMetaApi, 0)
def DealerFeaturesAddPayloadTransparency(builder, payloadTransparency): builder.PrependBoolSlot(11, payloadTransparency, 0)
def DealerFeaturesAddPayloadEncryptionCryptobox(builder, payloadEncryptionCryptobox): builder.PrependBoolSlot(12, payloadEncryptionCryptobox, 0)
def DealerFeaturesEnd(builder): return builder.EndObject()

+ 110
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/Error.py View File

@@ -0,0 +1,110 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

import flatbuffers

class Error(object):
__slots__ = ['_tab']

@classmethod
def GetRootAsError(cls, buf, offset):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = Error()
x.Init(buf, n + offset)
return x

# Error
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)

# Error
def RequestType(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint16Flags, o + self._tab.Pos)
return 0

# Error
def Request(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
return 0

# Error
def Error(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
if o != 0:
return self._tab.String(o + self._tab.Pos)
return None

# Error
def Payload(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
if o != 0:
a = self._tab.Vector(o)
return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
return 0

# Error
def PayloadAsNumpy(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
if o != 0:
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
return 0

# Error
def PayloadLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
if o != 0:
return self._tab.VectorLen(o)
return 0

# Error
def EncAlgo(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
return 0

# Error
def EncSerializer(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
return 0

# Error
def EncKey(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(16))
if o != 0:
a = self._tab.Vector(o)
return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
return 0

# Error
def EncKeyAsNumpy(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(16))
if o != 0:
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
return 0

# Error
def EncKeyLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(16))
if o != 0:
return self._tab.VectorLen(o)
return 0

def ErrorStart(builder): builder.StartObject(7)
def ErrorAddRequestType(builder, requestType): builder.PrependUint16Slot(0, requestType, 0)
def ErrorAddRequest(builder, request): builder.PrependUint64Slot(1, request, 0)
def ErrorAddError(builder, error): builder.PrependUOffsetTRelativeSlot(2, flatbuffers.number_types.UOffsetTFlags.py_type(error), 0)
def ErrorAddPayload(builder, payload): builder.PrependUOffsetTRelativeSlot(3, flatbuffers.number_types.UOffsetTFlags.py_type(payload), 0)
def ErrorStartPayloadVector(builder, numElems): return builder.StartVector(1, numElems, 1)
def ErrorAddEncAlgo(builder, encAlgo): builder.PrependUint8Slot(4, encAlgo, 0)
def ErrorAddEncSerializer(builder, encSerializer): builder.PrependUint8Slot(5, encSerializer, 0)
def ErrorAddEncKey(builder, encKey): builder.PrependUOffsetTRelativeSlot(6, flatbuffers.number_types.UOffsetTFlags.py_type(encKey), 0)
def ErrorStartEncKeyVector(builder, numElems): return builder.StartVector(1, numElems, 1)
def ErrorEnd(builder): return builder.EndObject()

+ 223
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/Event.py View File

@@ -0,0 +1,223 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

import flatbuffers

class Event(object):
__slots__ = ['_tab']

@classmethod
def GetRootAsEvent(cls, buf, offset):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = Event()
x.Init(buf, n + offset)
return x

# Event
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)

# Event
def Subscription(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
return 0

# Event
def Publication(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
return 0

# /// Positional values for application-defined event payload.
# Event
def Args(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
if o != 0:
a = self._tab.Vector(o)
return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
return 0

# Event
def ArgsAsNumpy(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
if o != 0:
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
return 0

# Event
def ArgsLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
if o != 0:
return self._tab.VectorLen(o)
return 0

# /// Keyword values for application-defined event payload.
# Event
def Kwargs(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
if o != 0:
a = self._tab.Vector(o)
return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
return 0

# Event
def KwargsAsNumpy(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
if o != 0:
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
return 0

# Event
def KwargsLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
if o != 0:
return self._tab.VectorLen(o)
return 0

# /// Alternative, transparent payload. If given, ``args`` and ``kwargs`` must be left unset.
# Event
def Payload(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
if o != 0:
a = self._tab.Vector(o)
return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
return 0

# Event
def PayloadAsNumpy(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
if o != 0:
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
return 0

# Event
def PayloadLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
if o != 0:
return self._tab.VectorLen(o)
return 0

# Event
def EncAlgo(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
return 0

# Event
def EncSerializer(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(16))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
return 0

# Event
def EncKey(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(18))
if o != 0:
a = self._tab.Vector(o)
return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
return 0

# Event
def EncKeyAsNumpy(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(18))
if o != 0:
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
return 0

# Event
def EncKeyLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(18))
if o != 0:
return self._tab.VectorLen(o)
return 0

# Event
def Publisher(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(20))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
return 0

# Event
def PublisherAuthid(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(22))
if o != 0:
return self._tab.String(o + self._tab.Pos)
return None

# Event
def PublisherAuthrole(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(24))
if o != 0:
return self._tab.String(o + self._tab.Pos)
return None

# Event
def Topic(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(26))
if o != 0:
return self._tab.String(o + self._tab.Pos)
return None

# Event
def Retained(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(28))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# Event
def Acknowledge(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(30))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# Event
def ForwardFor(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(32))
if o != 0:
x = self._tab.Vector(o)
x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4
x = self._tab.Indirect(x)
from .Principal import Principal
obj = Principal()
obj.Init(self._tab.Bytes, x)
return obj
return None

# Event
def ForwardForLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(32))
if o != 0:
return self._tab.VectorLen(o)
return 0

def EventStart(builder): builder.StartObject(15)
def EventAddSubscription(builder, subscription): builder.PrependUint64Slot(0, subscription, 0)
def EventAddPublication(builder, publication): builder.PrependUint64Slot(1, publication, 0)
def EventAddArgs(builder, args): builder.PrependUOffsetTRelativeSlot(2, flatbuffers.number_types.UOffsetTFlags.py_type(args), 0)
def EventStartArgsVector(builder, numElems): return builder.StartVector(1, numElems, 1)
def EventAddKwargs(builder, kwargs): builder.PrependUOffsetTRelativeSlot(3, flatbuffers.number_types.UOffsetTFlags.py_type(kwargs), 0)
def EventStartKwargsVector(builder, numElems): return builder.StartVector(1, numElems, 1)
def EventAddPayload(builder, payload): builder.PrependUOffsetTRelativeSlot(4, flatbuffers.number_types.UOffsetTFlags.py_type(payload), 0)
def EventStartPayloadVector(builder, numElems): return builder.StartVector(1, numElems, 1)
def EventAddEncAlgo(builder, encAlgo): builder.PrependUint8Slot(5, encAlgo, 0)
def EventAddEncSerializer(builder, encSerializer): builder.PrependUint8Slot(6, encSerializer, 0)
def EventAddEncKey(builder, encKey): builder.PrependUOffsetTRelativeSlot(7, flatbuffers.number_types.UOffsetTFlags.py_type(encKey), 0)
def EventStartEncKeyVector(builder, numElems): return builder.StartVector(1, numElems, 1)
def EventAddPublisher(builder, publisher): builder.PrependUint64Slot(8, publisher, 0)
def EventAddPublisherAuthid(builder, publisherAuthid): builder.PrependUOffsetTRelativeSlot(9, flatbuffers.number_types.UOffsetTFlags.py_type(publisherAuthid), 0)
def EventAddPublisherAuthrole(builder, publisherAuthrole): builder.PrependUOffsetTRelativeSlot(10, flatbuffers.number_types.UOffsetTFlags.py_type(publisherAuthrole), 0)
def EventAddTopic(builder, topic): builder.PrependUOffsetTRelativeSlot(11, flatbuffers.number_types.UOffsetTFlags.py_type(topic), 0)
def EventAddRetained(builder, retained): builder.PrependBoolSlot(12, retained, 0)
def EventAddAcknowledge(builder, acknowledge): builder.PrependBoolSlot(13, acknowledge, 0)
def EventAddForwardFor(builder, forwardFor): builder.PrependUOffsetTRelativeSlot(14, flatbuffers.number_types.UOffsetTFlags.py_type(forwardFor), 0)
def EventStartForwardForVector(builder, numElems): return builder.StartVector(4, numElems, 4)
def EventEnd(builder): return builder.EndObject()

+ 94
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/EventReceived.py View File

@@ -0,0 +1,94 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

import flatbuffers

class EventReceived(object):
__slots__ = ['_tab']

@classmethod
def GetRootAsEventReceived(cls, buf, offset):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = EventReceived()
x.Init(buf, n + offset)
return x

# EventReceived
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)

# EventReceived
def Publication(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
return 0

# EventReceived
def Payload(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
if o != 0:
a = self._tab.Vector(o)
return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
return 0

# EventReceived
def PayloadAsNumpy(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
if o != 0:
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
return 0

# EventReceived
def PayloadLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
if o != 0:
return self._tab.VectorLen(o)
return 0

# EventReceived
def EncAlgo(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
return 0

# EventReceived
def EncSerializer(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
return 0

# EventReceived
def EncKey(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
if o != 0:
a = self._tab.Vector(o)
return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
return 0

# EventReceived
def EncKeyAsNumpy(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
if o != 0:
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
return 0

# EventReceived
def EncKeyLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
if o != 0:
return self._tab.VectorLen(o)
return 0

def EventReceivedStart(builder): builder.StartObject(5)
def EventReceivedAddPublication(builder, publication): builder.PrependUint64Slot(0, publication, 0)
def EventReceivedAddPayload(builder, payload): builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(payload), 0)
def EventReceivedStartPayloadVector(builder, numElems): return builder.StartVector(1, numElems, 1)
def EventReceivedAddEncAlgo(builder, encAlgo): builder.PrependUint8Slot(2, encAlgo, 0)
def EventReceivedAddEncSerializer(builder, encSerializer): builder.PrependUint8Slot(3, encSerializer, 0)
def EventReceivedAddEncKey(builder, encKey): builder.PrependUOffsetTRelativeSlot(4, flatbuffers.number_types.UOffsetTFlags.py_type(encKey), 0)
def EventReceivedStartEncKeyVector(builder, numElems): return builder.StartVector(1, numElems, 1)
def EventReceivedEnd(builder): return builder.EndObject()

+ 118
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/Hello.py View File

@@ -0,0 +1,118 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

import flatbuffers

class Hello(object):
__slots__ = ['_tab']

@classmethod
def GetRootAsHello(cls, buf, offset):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = Hello()
x.Init(buf, n + offset)
return x

# Hello
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)

# Hello
def Roles(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
x = self._tab.Indirect(o + self._tab.Pos)
from .ClientRoles import ClientRoles
obj = ClientRoles()
obj.Init(self._tab.Bytes, x)
return obj
return None

# Hello
def Realm(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
if o != 0:
return self._tab.String(o + self._tab.Pos)
return None

# Hello
def Authmethods(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
if o != 0:
a = self._tab.Vector(o)
return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
return 0

# Hello
def AuthmethodsAsNumpy(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
if o != 0:
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
return 0

# Hello
def AuthmethodsLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
if o != 0:
return self._tab.VectorLen(o)
return 0

# Hello
def Authid(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
if o != 0:
return self._tab.String(o + self._tab.Pos)
return None

# Hello
def Authrole(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
if o != 0:
return self._tab.String(o + self._tab.Pos)
return None

# Hello
def Authextra(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
if o != 0:
x = self._tab.Indirect(o + self._tab.Pos)
from .Map import Map
obj = Map()
obj.Init(self._tab.Bytes, x)
return obj
return None

# Hello
def Resumable(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(16))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# Hello
def ResumeSession(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(18))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
return 0

# Hello
def ResumeToken(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(20))
if o != 0:
return self._tab.String(o + self._tab.Pos)
return None

def HelloStart(builder): builder.StartObject(9)
def HelloAddRoles(builder, roles): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(roles), 0)
def HelloAddRealm(builder, realm): builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(realm), 0)
def HelloAddAuthmethods(builder, authmethods): builder.PrependUOffsetTRelativeSlot(2, flatbuffers.number_types.UOffsetTFlags.py_type(authmethods), 0)
def HelloStartAuthmethodsVector(builder, numElems): return builder.StartVector(1, numElems, 1)
def HelloAddAuthid(builder, authid): builder.PrependUOffsetTRelativeSlot(3, flatbuffers.number_types.UOffsetTFlags.py_type(authid), 0)
def HelloAddAuthrole(builder, authrole): builder.PrependUOffsetTRelativeSlot(4, flatbuffers.number_types.UOffsetTFlags.py_type(authrole), 0)
def HelloAddAuthextra(builder, authextra): builder.PrependUOffsetTRelativeSlot(5, flatbuffers.number_types.UOffsetTFlags.py_type(authextra), 0)
def HelloAddResumable(builder, resumable): builder.PrependBoolSlot(6, resumable, 0)
def HelloAddResumeSession(builder, resumeSession): builder.PrependUint64Slot(7, resumeSession, 0)
def HelloAddResumeToken(builder, resumeToken): builder.PrependUOffsetTRelativeSlot(8, flatbuffers.number_types.UOffsetTFlags.py_type(resumeToken), 0)
def HelloEnd(builder): return builder.EndObject()

+ 38
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/Interrupt.py View File

@@ -0,0 +1,38 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

import flatbuffers

class Interrupt(object):
__slots__ = ['_tab']

@classmethod
def GetRootAsInterrupt(cls, buf, offset):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = Interrupt()
x.Init(buf, n + offset)
return x

# Interrupt
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)

# Interrupt
def Request(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
return 0

# Interrupt
def Mode(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
return 1

def InterruptStart(builder): builder.StartObject(2)
def InterruptAddRequest(builder, request): builder.PrependUint64Slot(0, request, 0)
def InterruptAddMode(builder, mode): builder.PrependUint8Slot(1, mode, 1)
def InterruptEnd(builder): return builder.EndObject()

+ 9
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/Kdf.py View File

@@ -0,0 +1,9 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

class Kdf(object):
NONE = 0
PBKDF2 = 1
ARGON2 = 2


+ 9
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/Match.py View File

@@ -0,0 +1,9 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

class Match(object):
EXACT = 0
PREFIX = 1
WILDCARD = 2


+ 70
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/PublisherFeatures.py View File

@@ -0,0 +1,70 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

import flatbuffers

class PublisherFeatures(object):
__slots__ = ['_tab']

@classmethod
def GetRootAsPublisherFeatures(cls, buf, offset):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = PublisherFeatures()
x.Init(buf, n + offset)
return x

# PublisherFeatures
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)

# PublisherFeatures
def PublisherIdentification(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# PublisherFeatures
def PublisherExclusion(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# PublisherFeatures
def SubscriberBlackwhiteListing(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# PublisherFeatures
def AcknowledgeEventReceived(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# PublisherFeatures
def PayloadTransparency(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

# PublisherFeatures
def PayloadEncryptionCryptobox(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
if o != 0:
return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
return False

def PublisherFeaturesStart(builder): builder.StartObject(6)
def PublisherFeaturesAddPublisherIdentification(builder, publisherIdentification): builder.PrependBoolSlot(0, publisherIdentification, 0)
def PublisherFeaturesAddPublisherExclusion(builder, publisherExclusion): builder.PrependBoolSlot(1, publisherExclusion, 0)
def PublisherFeaturesAddSubscriberBlackwhiteListing(builder, subscriberBlackwhiteListing): builder.PrependBoolSlot(2, subscriberBlackwhiteListing, 0)
def PublisherFeaturesAddAcknowledgeEventReceived(builder, acknowledgeEventReceived): builder.PrependBoolSlot(3, acknowledgeEventReceived, 0)
def PublisherFeaturesAddPayloadTransparency(builder, payloadTransparency): builder.PrependBoolSlot(4, payloadTransparency, 0)
def PublisherFeaturesAddPayloadEncryptionCryptobox(builder, payloadEncryptionCryptobox): builder.PrependBoolSlot(5, payloadEncryptionCryptobox, 0)
def PublisherFeaturesEnd(builder): return builder.EndObject()

+ 13
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/Serializer.py View File

@@ -0,0 +1,13 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

class Serializer(object):
TRANSPORT = 0
JSON = 1
MSGPACK = 2
CBOR = 3
UBJSON = 4
OPAQUE = 5
FLATBUFFERS = 6


+ 94
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/Yield.py View File

@@ -0,0 +1,94 @@
# automatically generated by the FlatBuffers compiler, do not modify

# namespace: proto

import flatbuffers

class Yield(object):
__slots__ = ['_tab']

@classmethod
def GetRootAsYield(cls, buf, offset):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = Yield()
x.Init(buf, n + offset)
return x

# Yield
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)

# Yield
def Request(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
return 0

# Yield
def Payload(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
if o != 0:
a = self._tab.Vector(o)
return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
return 0

# Yield
def PayloadAsNumpy(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
if o != 0:
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
return 0

# Yield
def PayloadLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
if o != 0:
return self._tab.VectorLen(o)
return 0

# Yield
def EncAlgo(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
return 0

# Yield
def EncSerializer(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
return 0

# Yield
def EncKey(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
if o != 0:
a = self._tab.Vector(o)
return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
return 0

# Yield
def EncKeyAsNumpy(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
if o != 0:
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
return 0

# Yield
def EncKeyLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
if o != 0:
return self._tab.VectorLen(o)
return 0

def YieldStart(builder): builder.StartObject(5)
def YieldAddRequest(builder, request): builder.PrependUint64Slot(0, request, 0)
def YieldAddPayload(builder, payload): builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(payload), 0)
def YieldStartPayloadVector(builder, numElems): return builder.StartVector(1, numElems, 1)
def YieldAddEncAlgo(builder, encAlgo): builder.PrependUint8Slot(2, encAlgo, 0)
def YieldAddEncSerializer(builder, encSerializer): builder.PrependUint8Slot(3, encSerializer, 0)
def YieldAddEncKey(builder, encKey): builder.PrependUOffsetTRelativeSlot(4, flatbuffers.number_types.UOffsetTFlags.py_type(encKey), 0)
def YieldStartEncKeyVector(builder, numElems): return builder.StartVector(1, numElems, 1)
def YieldEnd(builder): return builder.EndObject()

+ 0
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/gen/wamp/proto/__init__.py View File


+ 5947
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/message.py
File diff suppressed because it is too large
View File


+ 1958
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/protocol.py
File diff suppressed because it is too large
View File


+ 39
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/test/test_cryptobox.py View File

@@ -0,0 +1,39 @@
###############################################################################
#
# The MIT License (MIT)
#
# Copyright (c) Crossbar.io Technologies GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################

from __future__ import absolute_import

from autobahn.wamp import cryptobox

import unittest


@unittest.skipIf(not cryptobox.HAS_CRYPTOBOX, 'no cryptobox support present')
class TestCryptoBox(unittest.TestCase):

def test_create_keyring(self):
kr = cryptobox.KeyRing()
assert kr

+ 127
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/test/test_cryptosign.py View File

@@ -0,0 +1,127 @@
###############################################################################
#
# The MIT License (MIT)
#
# Copyright (c) Crossbar.io Technologies GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################

from __future__ import absolute_import

import hashlib
import os

from mock import Mock

import txaio

if os.environ.get('USE_TWISTED', False):
txaio.use_twisted()
elif os.environ.get('USE_ASYNCIO', False):
txaio.use_asyncio()
else:
raise Exception('no networking framework selected')

from autobahn.wamp.cryptosign import _makepad, HAS_CRYPTOSIGN
from autobahn.wamp import types
from autobahn.wamp.auth import create_authenticator

if HAS_CRYPTOSIGN:
from autobahn.wamp.cryptosign import SigningKey
from nacl.encoding import HexEncoder

import tempfile

import unittest

keybody = '''-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACAa38i/4dNWFuZN/72QAJbyOwZvkUyML/u2b2B1uW4RbQAAAJj4FLyB+BS8
gQAAAAtzc2gtZWQyNTUxOQAAACAa38i/4dNWFuZN/72QAJbyOwZvkUyML/u2b2B1uW4RbQ
AAAEBNV9l6aPVVaWYgpthJwM5YJWhRjXKet1PcfHMt4oBFEBrfyL/h01YW5k3/vZAAlvI7
Bm+RTIwv+7ZvYHW5bhFtAAAAFXNvbWV1c2VyQGZ1bmt0aGF0LmNvbQ==
-----END OPENSSH PRIVATE KEY-----'''

pubkey = '''ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJVp3hjHwIQyEladzd8mFcf0YSXcmyKS3qMLB7VqTQKm someuser@example.com
'''


@unittest.skipIf(not HAS_CRYPTOSIGN, 'nacl library not present')
class TestAuth(unittest.TestCase):

def setUp(self):
self.key = SigningKey.from_ssh_data(keybody)
self.privkey_hex = self.key._key.encode(encoder=HexEncoder)
m = hashlib.sha256()
m.update("some TLS message".encode())
self.channel_id = m.digest()

def test_valid(self):
session = Mock()
session._transport.get_channel_id = Mock(return_value=self.channel_id)
challenge = types.Challenge(u"ticket", dict(challenge="ff" * 32))
signed = yield self.key.sign_challenge(session, challenge)
self.assertEqual(
u'9b6f41540c9b95b4b7b281c3042fa9c54cef43c842d62ea3fd6030fcb66e70b3e80d49d44c29d1635da9348d02ec93f3ed1ef227dfb59a07b580095c2b82f80f9d16ca518aa0c2b707f2b2a609edeca73bca8dd59817a633f35574ac6fd80d00',
signed.result,
)

def test_authenticator(self):
authenticator = create_authenticator(
u"cryptosign",
authid="someone",
privkey=self.privkey_hex,
)
session = Mock()
session._transport.get_channel_id = Mock(return_value=self.channel_id)
challenge = types.Challenge(u"cryptosign", dict(challenge="ff" * 32))
reply = yield authenticator.on_challenge(session, challenge)
self.assertEqual(
reply.result,
u'9b6f41540c9b95b4b7b281c3042fa9c54cef43c842d62ea3fd6030fcb66e70b3e80d49d44c29d1635da9348d02ec93f3ed1ef227dfb59a07b580095c2b82f80f9d16ca518aa0c2b707f2b2a609edeca73bca8dd59817a633f35574ac6fd80d00',
)


class TestKey(unittest.TestCase):

def test_pad(self):
self.assertEqual(_makepad(0), '')
self.assertEqual(_makepad(2), '\x01\x02')
self.assertEqual(_makepad(3), '\x01\x02\x03')

@unittest.skipIf(not HAS_CRYPTOSIGN, 'nacl library not present')
def test_key(self):
with tempfile.NamedTemporaryFile('w+t') as fp:
fp.write(keybody)
fp.seek(0)

key = SigningKey.from_ssh_key(fp.name)
self.assertEqual(key.public_key(), '1adfc8bfe1d35616e64dffbd900096f23b066f914c8c2ffbb66f6075b96e116d')

@unittest.skipIf(not HAS_CRYPTOSIGN, 'nacl library not present')
def test_pubkey(self):
with tempfile.NamedTemporaryFile('w+t') as fp:
fp.write(pubkey)
fp.seek(0)

key = SigningKey.from_ssh_key(fp.name)
self.assertEqual(key.public_key(), '9569de18c7c0843212569dcddf2615c7f46125dc9b2292dea30b07b56a4d02a6')
self.assertEqual(key.comment(), 'someuser@example.com')

+ 580
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/test/test_uri_pattern.py View File

@@ -0,0 +1,580 @@
###############################################################################
#
# The MIT License (MIT)
#
# Copyright (c) Crossbar.io Technologies GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################

from __future__ import absolute_import

from autobahn import wamp
from autobahn.wamp.uri import Pattern, RegisterOptions, SubscribeOptions

import unittest


class TestUris(unittest.TestCase):

def test_invalid_uris(self):
for u in [u"",
u"com.myapp.<product:foo>.update",
u"com.myapp.<123:int>.update",
u"com.myapp.<:product>.update",
u"com.myapp.<product:>.update",
u"com.myapp.<int:>.update",
]:
self.assertRaises(Exception, Pattern, u, Pattern.URI_TARGET_ENDPOINT)

def test_valid_uris(self):
for u in [u"com.myapp.proc1",
u"123",
u"com.myapp.<product:int>.update",
u"com.myapp.<category:string>.<subcategory>.list"
u"com.myapp.something..update"
]:
p = Pattern(u, Pattern.URI_TARGET_ENDPOINT)
self.assertIsInstance(p, Pattern)

def test_parse_uris(self):
tests = [
(u"com.myapp.<product:int>.update", [
(u"com.myapp.0.update", {u'product': 0}),
(u"com.myapp.123456.update", {u'product': 123456}),
(u"com.myapp.aaa.update", None),
(u"com.myapp..update", None),
(u"com.myapp.0.delete", None),
]
),
(u"com.myapp.<product:string>.update", [
(u"com.myapp.box.update", {u'product': u'box'}),
(u"com.myapp.123456.update", {u'product': u'123456'}),
(u"com.myapp..update", None),
]
),
(u"com.myapp.<product>.update", [
(u"com.myapp.0.update", {u'product': u'0'}),
(u"com.myapp.abc.update", {u'product': u'abc'}),
(u"com.myapp..update", None),
]
),
(u"com.myapp.<category:string>.<subcategory:string>.list", [
(u"com.myapp.cosmetic.shampoo.list", {u'category': u'cosmetic', u'subcategory': u'shampoo'}),
(u"com.myapp...list", None),
(u"com.myapp.cosmetic..list", None),
(u"com.myapp..shampoo.list", None),
]
)
]
for test in tests:
pat = Pattern(test[0], Pattern.URI_TARGET_ENDPOINT)
for ptest in test[1]:
uri = ptest[0]
kwargs_should = ptest[1]
if kwargs_should is not None:
args_is, kwargs_is = pat.match(uri)
self.assertEqual(kwargs_is, kwargs_should)
else:
self.assertRaises(Exception, pat.match, uri)


class TestDecorators(unittest.TestCase):

def test_decorate_endpoint(self):

@wamp.register(u"com.calculator.square")
def square(_):
"""Do nothing."""

self.assertTrue(hasattr(square, '_wampuris'))
self.assertTrue(type(square._wampuris) == list)
self.assertEqual(len(square._wampuris), 1)
self.assertIsInstance(square._wampuris[0], Pattern)
self.assertTrue(square._wampuris[0].is_endpoint())
self.assertFalse(square._wampuris[0].is_handler())
self.assertFalse(square._wampuris[0].is_exception())
self.assertEqual(square._wampuris[0].uri(), u"com.calculator.square")
self.assertEqual(square._wampuris[0]._type, Pattern.URI_TYPE_EXACT)

@wamp.register(u"com.myapp.product.<product:int>.update")
def update_product(product=None, label=None):
"""Do nothing."""

self.assertTrue(hasattr(update_product, '_wampuris'))
self.assertTrue(type(update_product._wampuris) == list)
self.assertEqual(len(update_product._wampuris), 1)
self.assertIsInstance(update_product._wampuris[0], Pattern)
self.assertTrue(update_product._wampuris[0].is_endpoint())
self.assertFalse(update_product._wampuris[0].is_handler())
self.assertFalse(update_product._wampuris[0].is_exception())
self.assertEqual(update_product._wampuris[0].uri(), u"com.myapp.product.<product:int>.update")
self.assertEqual(update_product._wampuris[0]._type, Pattern.URI_TYPE_WILDCARD)

@wamp.register(u"com.myapp.<category:string>.<cid:int>.update")
def update(category=None, cid=None):
"""Do nothing."""

self.assertTrue(hasattr(update, '_wampuris'))
self.assertTrue(type(update._wampuris) == list)
self.assertEqual(len(update._wampuris), 1)
self.assertIsInstance(update._wampuris[0], Pattern)
self.assertTrue(update._wampuris[0].is_endpoint())
self.assertFalse(update._wampuris[0].is_handler())
self.assertFalse(update._wampuris[0].is_exception())
self.assertEqual(update._wampuris[0].uri(), u"com.myapp.<category:string>.<cid:int>.update")
self.assertEqual(update._wampuris[0]._type, Pattern.URI_TYPE_WILDCARD)

@wamp.register(u"com.myapp.circle.<name:string>",
RegisterOptions(match=u"wildcard", details_arg="details"))
def circle(name=None, details=None):
""" Do nothing. """

self.assertTrue(hasattr(circle, '_wampuris'))
self.assertTrue(type(circle._wampuris) == list)
self.assertEqual(len(circle._wampuris), 1)
self.assertIsInstance(circle._wampuris[0], Pattern)
self.assertIsInstance(circle._wampuris[0].options, RegisterOptions)
self.assertEqual(circle._wampuris[0].options.match, u"wildcard")
self.assertEqual(circle._wampuris[0].options.details_arg, "details")
self.assertTrue(circle._wampuris[0].is_endpoint())
self.assertFalse(circle._wampuris[0].is_handler())
self.assertFalse(circle._wampuris[0].is_exception())
self.assertEqual(circle._wampuris[0].uri(), u"com.myapp.circle.<name:string>")
self.assertEqual(circle._wampuris[0]._type, Pattern.URI_TYPE_WILDCARD)

@wamp.register(u"com.myapp.something..update",
RegisterOptions(match=u"wildcard", details_arg="details"))
def something(dynamic=None, details=None):
""" Do nothing. """
self.assertTrue(hasattr(something, '_wampuris'))
self.assertTrue(type(something._wampuris) == list)
self.assertEqual(len(something._wampuris), 1)
self.assertIsInstance(something._wampuris[0], Pattern)
self.assertIsInstance(something._wampuris[0].options, RegisterOptions)
self.assertEqual(something._wampuris[0].options.match, u"wildcard")
self.assertEqual(something._wampuris[0].options.details_arg, "details")
self.assertTrue(something._wampuris[0].is_endpoint())
self.assertFalse(something._wampuris[0].is_handler())
self.assertFalse(something._wampuris[0].is_exception())
self.assertEqual(something._wampuris[0].uri(), u"com.myapp.something..update")
self.assertEqual(something._wampuris[0]._type, Pattern.URI_TYPE_WILDCARD)

def test_decorate_handler(self):

@wamp.subscribe(u"com.myapp.on_shutdown")
def on_shutdown():
"""Do nothing."""

self.assertTrue(hasattr(on_shutdown, '_wampuris'))
self.assertTrue(type(on_shutdown._wampuris) == list)
self.assertEqual(len(on_shutdown._wampuris), 1)
self.assertIsInstance(on_shutdown._wampuris[0], Pattern)
self.assertFalse(on_shutdown._wampuris[0].is_endpoint())
self.assertTrue(on_shutdown._wampuris[0].is_handler())
self.assertFalse(on_shutdown._wampuris[0].is_exception())
self.assertEqual(on_shutdown._wampuris[0].uri(), u"com.myapp.on_shutdown")
self.assertEqual(on_shutdown._wampuris[0]._type, Pattern.URI_TYPE_EXACT)

@wamp.subscribe(u"com.myapp.product.<product:int>.on_update")
def on_product_update(product=None, label=None):
"""Do nothing."""

self.assertTrue(hasattr(on_product_update, '_wampuris'))
self.assertTrue(type(on_product_update._wampuris) == list)
self.assertEqual(len(on_product_update._wampuris), 1)
self.assertIsInstance(on_product_update._wampuris[0], Pattern)
self.assertFalse(on_product_update._wampuris[0].is_endpoint())
self.assertTrue(on_product_update._wampuris[0].is_handler())
self.assertFalse(on_product_update._wampuris[0].is_exception())
self.assertEqual(on_product_update._wampuris[0].uri(), u"com.myapp.product.<product:int>.on_update")
self.assertEqual(on_product_update._wampuris[0]._type, Pattern.URI_TYPE_WILDCARD)

@wamp.subscribe(u"com.myapp.<category:string>.<cid:int>.on_update")
def on_update(category=None, cid=None, label=None):
"""Do nothing."""

self.assertTrue(hasattr(on_update, '_wampuris'))
self.assertTrue(type(on_update._wampuris) == list)
self.assertEqual(len(on_update._wampuris), 1)
self.assertIsInstance(on_update._wampuris[0], Pattern)
self.assertFalse(on_update._wampuris[0].is_endpoint())
self.assertTrue(on_update._wampuris[0].is_handler())
self.assertFalse(on_update._wampuris[0].is_exception())
self.assertEqual(on_update._wampuris[0].uri(), u"com.myapp.<category:string>.<cid:int>.on_update")
self.assertEqual(on_update._wampuris[0]._type, Pattern.URI_TYPE_WILDCARD)

@wamp.subscribe(u"com.myapp.on.<event:string>",
SubscribeOptions(match=u"wildcard", details_arg="details"))
def on_event(event=None, details=None):
""" Do nothing. """

self.assertTrue(hasattr(on_event, '_wampuris'))
self.assertTrue(type(on_event._wampuris) == list)
self.assertEqual(len(on_event._wampuris), 1)
self.assertIsInstance(on_event._wampuris[0], Pattern)
self.assertIsInstance(on_event._wampuris[0].options, SubscribeOptions)
self.assertEqual(on_event._wampuris[0].options.match, u"wildcard")
self.assertEqual(on_event._wampuris[0].options.details_arg, "details")
self.assertFalse(on_event._wampuris[0].is_endpoint())
self.assertTrue(on_event._wampuris[0].is_handler())
self.assertFalse(on_event._wampuris[0].is_exception())
self.assertEqual(on_event._wampuris[0].uri(), u"com.myapp.on.<event:string>")
self.assertEqual(on_event._wampuris[0]._type, Pattern.URI_TYPE_WILDCARD)

def test_decorate_exception(self):

@wamp.error(u"com.myapp.error")
class AppError(Exception):
"""Do nothing."""

self.assertTrue(hasattr(AppError, '_wampuris'))
self.assertTrue(type(AppError._wampuris) == list)
self.assertEqual(len(AppError._wampuris), 1)
self.assertIsInstance(AppError._wampuris[0], Pattern)
self.assertFalse(AppError._wampuris[0].is_endpoint())
self.assertFalse(AppError._wampuris[0].is_handler())
self.assertTrue(AppError._wampuris[0].is_exception())
self.assertEqual(AppError._wampuris[0].uri(), u"com.myapp.error")
self.assertEqual(AppError._wampuris[0]._type, Pattern.URI_TYPE_EXACT)

@wamp.error(u"com.myapp.product.<product:int>.product_inactive")
class ProductInactiveError(Exception):
"""Do nothing."""

self.assertTrue(hasattr(ProductInactiveError, '_wampuris'))
self.assertTrue(type(ProductInactiveError._wampuris) == list)
self.assertEqual(len(ProductInactiveError._wampuris), 1)
self.assertIsInstance(ProductInactiveError._wampuris[0], Pattern)
self.assertFalse(ProductInactiveError._wampuris[0].is_endpoint())
self.assertFalse(ProductInactiveError._wampuris[0].is_handler())
self.assertTrue(ProductInactiveError._wampuris[0].is_exception())
self.assertEqual(ProductInactiveError._wampuris[0].uri(), u"com.myapp.product.<product:int>.product_inactive")
self.assertEqual(ProductInactiveError._wampuris[0]._type, Pattern.URI_TYPE_WILDCARD)

@wamp.error(u"com.myapp.<category:string>.<product:int>.inactive")
class ObjectInactiveError(Exception):
"""Do nothing."""

self.assertTrue(hasattr(ObjectInactiveError, '_wampuris'))
self.assertTrue(type(ObjectInactiveError._wampuris) == list)
self.assertEqual(len(ObjectInactiveError._wampuris), 1)
self.assertIsInstance(ObjectInactiveError._wampuris[0], Pattern)
self.assertFalse(ObjectInactiveError._wampuris[0].is_endpoint())
self.assertFalse(ObjectInactiveError._wampuris[0].is_handler())
self.assertTrue(ObjectInactiveError._wampuris[0].is_exception())
self.assertEqual(ObjectInactiveError._wampuris[0].uri(), u"com.myapp.<category:string>.<product:int>.inactive")
self.assertEqual(ObjectInactiveError._wampuris[0]._type, Pattern.URI_TYPE_WILDCARD)

def test_match_decorated_endpoint(self):

@wamp.register(u"com.calculator.square")
def square(x):
return x

args, kwargs = square._wampuris[0].match(u"com.calculator.square")
self.assertEqual(square(666, **kwargs), 666)

@wamp.register(u"com.myapp.product.<product:int>.update")
def update_product(product=None, label=None):
return product, label

args, kwargs = update_product._wampuris[0].match(u"com.myapp.product.123456.update")
kwargs['label'] = "foobar"
self.assertEqual(update_product(**kwargs), (123456, "foobar"))

@wamp.register(u"com.myapp.<category:string>.<cid:int>.update")
def update(category=None, cid=None, label=None):
return category, cid, label

args, kwargs = update._wampuris[0].match(u"com.myapp.product.123456.update")
kwargs['label'] = "foobar"
self.assertEqual(update(**kwargs), ("product", 123456, "foobar"))

def test_match_decorated_handler(self):

@wamp.subscribe(u"com.myapp.on_shutdown")
def on_shutdown():
pass

args, kwargs = on_shutdown._wampuris[0].match(u"com.myapp.on_shutdown")
self.assertEqual(on_shutdown(**kwargs), None)

@wamp.subscribe(u"com.myapp.product.<product:int>.on_update")
def on_product_update(product=None, label=None):
return product, label

args, kwargs = on_product_update._wampuris[0].match(u"com.myapp.product.123456.on_update")
kwargs['label'] = "foobar"
self.assertEqual(on_product_update(**kwargs), (123456, "foobar"))

@wamp.subscribe(u"com.myapp.<category:string>.<cid:int>.on_update")
def on_update(category=None, cid=None, label=None):
return category, cid, label

args, kwargs = on_update._wampuris[0].match(u"com.myapp.product.123456.on_update")
kwargs['label'] = "foobar"
self.assertEqual(on_update(**kwargs), ("product", 123456, "foobar"))

def test_match_decorated_exception(self):

@wamp.error(u"com.myapp.error")
class AppError(Exception):

def __init__(self, msg):
Exception.__init__(self, msg)

def __eq__(self, other):
return self.__class__ == other.__class__ and \
self.args == other.args

args, kwargs = AppError._wampuris[0].match(u"com.myapp.error")
# noinspection PyArgumentList
self.assertEqual(AppError(u"fuck", **kwargs), AppError(u"fuck"))

@wamp.error(u"com.myapp.product.<product:int>.product_inactive")
class ProductInactiveError(Exception):

def __init__(self, msg, product=None):
Exception.__init__(self, msg)
self.product = product

def __eq__(self, other):
return self.__class__ == other.__class__ and \
self.args == other.args and \
self.product == other.product

args, kwargs = ProductInactiveError._wampuris[0].match(u"com.myapp.product.123456.product_inactive")
self.assertEqual(ProductInactiveError("fuck", **kwargs), ProductInactiveError("fuck", 123456))

@wamp.error(u"com.myapp.<category:string>.<product:int>.inactive")
class ObjectInactiveError(Exception):

def __init__(self, msg, category=None, product=None):
Exception.__init__(self, msg)
self.category = category
self.product = product

def __eq__(self, other):
return self.__class__ == other.__class__ and \
self.args == other.args and \
self.category == other.category and \
self.product == other.product

args, kwargs = ObjectInactiveError._wampuris[0].match(u"com.myapp.product.123456.inactive")
self.assertEqual(ObjectInactiveError("fuck", **kwargs), ObjectInactiveError("fuck", "product", 123456))


class KwException(Exception):
def __init__(self, *args, **kwargs):
Exception.__init__(self, *args)
self.kwargs = kwargs

# what if the WAMP error message received
# contains args/kwargs that cannot be
# consumed by the constructor of the exception
# class defined for the WAMP error URI?

# 1. we can bail out (but we are already signaling an error)
# 2. we can require a generic constructor
# 3. we can map only unconsumed args/kwargs to generic attributes
# 4. we can silently drop unconsumed args/kwargs


class MockSession(object):

def __init__(self):
self._ecls_to_uri_pat = {}
self._uri_to_ecls = {}

def define(self, exception, error=None):
if error is None:
assert(hasattr(exception, '_wampuris'))
self._ecls_to_uri_pat[exception] = exception._wampuris
self._uri_to_ecls[exception._wampuris[0].uri()] = exception
else:
assert(not hasattr(exception, '_wampuris'))
self._ecls_to_uri_pat[exception] = [Pattern(error, Pattern.URI_TARGET_HANDLER)]
self._uri_to_ecls[error] = exception

def map_error(self, error, args=None, kwargs=None):

# FIXME:
# 1. map to ecls based on error URI wildcard/prefix
# 2. extract additional args/kwargs from error URI

if error in self._uri_to_ecls:
ecls = self._uri_to_ecls[error]
try:
# the following might fail, eg. TypeError when
# signature of exception constructor is incompatible
# with args/kwargs or when the exception constructor raises
if kwargs:
if args:
exc = ecls(*args, **kwargs)
else:
exc = ecls(**kwargs)
else:
if args:
exc = ecls(*args)
else:
exc = ecls()
except Exception:
# FIXME: log e
exc = KwException(error, *args, **kwargs)
else:
# this never fails
args = args or []
kwargs = kwargs or {}
exc = KwException(error, *args, **kwargs)
return exc


class TestDecoratorsAdvanced(unittest.TestCase):

def test_decorate_exception_non_exception(self):

def test():
# noinspection PyUnusedLocal
@wamp.error(u"com.test.error")
class Foo(object):
pass

self.assertRaises(Exception, test)

def test_decorate_endpoint_multiple(self):

# noinspection PyUnusedLocal
@wamp.register(u"com.oldapp.oldproc")
@wamp.register(u"com.calculator.square")
def square(x):
"""Do nothing."""

self.assertTrue(hasattr(square, '_wampuris'))
self.assertTrue(type(square._wampuris) == list)
self.assertEqual(len(square._wampuris), 2)

for i in range(2):
self.assertIsInstance(square._wampuris[i], Pattern)
self.assertTrue(square._wampuris[i].is_endpoint())
self.assertFalse(square._wampuris[i].is_handler())
self.assertFalse(square._wampuris[i].is_exception())
self.assertEqual(square._wampuris[i]._type, Pattern.URI_TYPE_EXACT)

self.assertEqual(square._wampuris[0].uri(), u"com.calculator.square")
self.assertEqual(square._wampuris[1].uri(), u"com.oldapp.oldproc")

def test_marshal_decorated_exception(self):

@wamp.error(u"com.myapp.error")
class AppError(Exception):
pass

try:
raise AppError("fuck")
except Exception as e:
self.assertEqual(e._wampuris[0].uri(), u"com.myapp.error")

@wamp.error(u"com.myapp.product.<product:int>.product_inactive")
class ProductInactiveError(Exception):

def __init__(self, msg, product=None):
Exception.__init__(self, msg)
self.product = product

try:
raise ProductInactiveError("fuck", 123456)
except Exception as e:
self.assertEqual(e._wampuris[0].uri(), u"com.myapp.product.<product:int>.product_inactive")

session = MockSession()
session.define(AppError)

def test_define_exception_undecorated(self):

session = MockSession()

class AppError(Exception):
pass

# defining an undecorated exception requires
# an URI to be provided
self.assertRaises(Exception, session.define, AppError)

session.define(AppError, u"com.myapp.error")

exc = session.map_error(u"com.myapp.error")
self.assertIsInstance(exc, AppError)

def test_define_exception_decorated(self):

session = MockSession()

@wamp.error(u"com.myapp.error")
class AppError(Exception):
pass

# when defining a decorated exception
# an URI must not be provided
self.assertRaises(Exception, session.define, AppError, u"com.myapp.error")

session.define(AppError)

exc = session.map_error(u"com.myapp.error")
self.assertIsInstance(exc, AppError)

def test_map_exception_undefined(self):

session = MockSession()

exc = session.map_error(u"com.myapp.error")
self.assertIsInstance(exc, Exception)

def test_map_exception_args(self):

session = MockSession()

@wamp.error(u"com.myapp.error")
class AppError(Exception):
pass

@wamp.error(u"com.myapp.error.product_inactive")
class ProductInactiveError(Exception):
def __init__(self, product=None):
self.product = product

# define exceptions in mock session
session.define(AppError)
session.define(ProductInactiveError)

for test in [
# (u"com.myapp.foo.error", [], {}, KwException),
(u"com.myapp.error", [], {}, AppError),
(u"com.myapp.error", ["you are doing it wrong"], {}, AppError),
(u"com.myapp.error", ["you are doing it wrong", 1, 2, 3], {}, AppError),

(u"com.myapp.error.product_inactive", [], {}, ProductInactiveError),
(u"com.myapp.error.product_inactive", [], {"product": 123456}, ProductInactiveError),
]:
error, args, kwargs, ecls = test
exc = session.map_error(error, args, kwargs)

self.assertIsInstance(exc, ecls)
self.assertEqual(list(exc.args), args)

+ 1371
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/types.py
File diff suppressed because it is too large
View File


+ 296
- 0
venv/lib/python3.7/site-packages/autobahn/wamp/websocket.py View File

@@ -0,0 +1,296 @@
###############################################################################
#
# The MIT License (MIT)
#
# Copyright (c) Crossbar.io Technologies GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################

from __future__ import absolute_import

import traceback

from autobahn.websocket import protocol
from autobahn.websocket.types import ConnectionDeny
from autobahn.wamp.interfaces import ITransport
from autobahn.wamp.exception import ProtocolError, SerializationError, TransportLost

__all__ = ('WampWebSocketServerProtocol',
'WampWebSocketClientProtocol',
'WampWebSocketServerFactory',
'WampWebSocketClientFactory')


class WampWebSocketProtocol(object):
"""
Base class for WAMP-over-WebSocket transport mixins.
"""

_session = None # default; self.session is set in onOpen

def _bailout(self, code, reason=None):
self.log.debug('Failing WAMP-over-WebSocket transport: code={code}, reason="{reason}"', code=code, reason=reason)
self._fail_connection(code, reason)

def onOpen(self):
"""
Callback from :func:`autobahn.websocket.interfaces.IWebSocketChannel.onOpen`
"""
# WebSocket connection established. Now let the user WAMP session factory
# create a new WAMP session and fire off session open callback.
try:
self._session = self.factory._factory()
self._session.onOpen(self)
except Exception as e:
self.log.critical("{tb}", tb=traceback.format_exc())
reason = u'WAMP Internal Error ({0})'.format(e)
self._bailout(protocol.WebSocketProtocol.CLOSE_STATUS_CODE_INTERNAL_ERROR, reason=reason)

def onClose(self, wasClean, code, reason):
"""
Callback from :func:`autobahn.websocket.interfaces.IWebSocketChannel.onClose`
"""
# WAMP session might never have been established in the first place .. guard this!
self._onclose_reason = reason
if self._session is not None:
# WebSocket connection lost - fire off the WAMP
# session close callback
# noinspection PyBroadException
try:
self.log.debug('WAMP-over-WebSocket transport lost: wasClean={wasClean}, code={code}, reason="{reason}"', wasClean=wasClean, code=code, reason=reason)
self._session.onClose(wasClean)
except Exception:
self.log.critical("{tb}", tb=traceback.format_exc())
self._session = None

def onMessage(self, payload, isBinary):
"""
Callback from :func:`autobahn.websocket.interfaces.IWebSocketChannel.onMessage`
"""
try:
for msg in self._serializer.unserialize(payload, isBinary):
self.log.trace(
"WAMP RECV: message={message}, session={session}, authid={authid}",
authid=self._session._authid,
session=self._session._session_id,
message=msg,
)
self._session.onMessage(msg)

except ProtocolError as e:
self.log.critical("{tb}", tb=traceback.format_exc())
reason = u'WAMP Protocol Error ({0})'.format(e)
self._bailout(protocol.WebSocketProtocol.CLOSE_STATUS_CODE_PROTOCOL_ERROR, reason=reason)

except Exception as e:
self.log.critical("{tb}", tb=traceback.format_exc())
reason = u'WAMP Internal Error ({0})'.format(e)
self._bailout(protocol.WebSocketProtocol.CLOSE_STATUS_CODE_INTERNAL_ERROR, reason=reason)

def send(self, msg):
"""
Implements :func:`autobahn.wamp.interfaces.ITransport.send`
"""
if self.isOpen():
try:
self.log.trace(
"WAMP SEND: message={message}, session={session}, authid={authid}",
authid=self._session._authid,
session=self._session._session_id,
message=msg,
)
payload, isBinary = self._serializer.serialize(msg)
except Exception as e:
self.log.error("WAMP message serialization error: {}".format(e))
# all exceptions raised from above should be serialization errors ..
raise SerializationError(u"WAMP message serialization error: {0}".format(e))
else:
self.sendMessage(payload, isBinary)
else:
raise TransportLost()

def isOpen(self):
"""
Implements :func:`autobahn.wamp.interfaces.ITransport.isOpen`
"""
return self._session is not None

def close(self):
"""
Implements :func:`autobahn.wamp.interfaces.ITransport.close`
"""
if self.isOpen():
self.sendClose(protocol.WebSocketProtocol.CLOSE_STATUS_CODE_NORMAL)
else:
raise TransportLost()

def abort(self):
"""
Implements :func:`autobahn.wamp.interfaces.ITransport.abort`
"""
if self.isOpen():
self._bailout(protocol.WebSocketProtocol.CLOSE_STATUS_CODE_GOING_AWAY)
else:
raise TransportLost()


ITransport.register(WampWebSocketProtocol)


def parseSubprotocolIdentifier(subprotocol):
try:
s = subprotocol.split(u'.')
if s[0] != u'wamp':
raise Exception(u'WAMP WebSocket subprotocol identifier must start with "wamp", not "{}"'.format(s[0]))
version = int(s[1])
serializerId = u'.'.join(s[2:])
return version, serializerId
except:
return None, None


class WampWebSocketServerProtocol(WampWebSocketProtocol):
"""
Mixin for WAMP-over-WebSocket server transports.
"""

STRICT_PROTOCOL_NEGOTIATION = True

def onConnect(self, request):
"""
Callback from :func:`autobahn.websocket.interfaces.IWebSocketChannel.onConnect`
"""
headers = {}
for subprotocol in request.protocols:
version, serializerId = parseSubprotocolIdentifier(subprotocol)
if version == 2 and serializerId in self.factory._serializers.keys():
self._serializer = self.factory._serializers[serializerId]
return subprotocol, headers

if self.STRICT_PROTOCOL_NEGOTIATION:
raise ConnectionDeny(ConnectionDeny.BAD_REQUEST, u'This server only speaks WebSocket subprotocols {}'.format(u', '.join(self.factory.protocols)))
else:
# assume wamp.2.json
self._serializer = self.factory._serializers[u'json']
return None, headers


class WampWebSocketClientProtocol(WampWebSocketProtocol):
"""
Mixin for WAMP-over-WebSocket client transports.
"""

STRICT_PROTOCOL_NEGOTIATION = True

def onConnect(self, response):
"""
Callback from :func:`autobahn.websocket.interfaces.IWebSocketChannel.onConnect`
"""
if response.protocol not in self.factory.protocols:
if self.STRICT_PROTOCOL_NEGOTIATION:
raise Exception(u'The server does not speak any of the WebSocket subprotocols {} we requested.'.format(u', '.join(self.factory.protocols)))
else:
# assume wamp.2.json
serializerId = u'json'
else:
version, serializerId = parseSubprotocolIdentifier(response.protocol)

self._serializer = self.factory._serializers[serializerId]


class WampWebSocketFactory(object):
"""
Base class for WAMP-over-WebSocket transport factory mixins.
"""

def __init__(self, factory, serializers=None):
"""
Ctor.

:param factory: A callable that produces instances that implement
:class:`autobahn.wamp.interfaces.ITransportHandler`
:type factory: callable

:param serializers: A list of WAMP serializers to use (or None for default
serializers). Serializers must implement
:class:`autobahn.wamp.interfaces.ISerializer`.
:type serializers: list
"""
if callable(factory):
self._factory = factory
else:
self._factory = lambda: factory

if serializers is None:
serializers = []

# try CBOR WAMP serializer
try:
from autobahn.wamp.serializer import CBORSerializer
serializers.append(CBORSerializer(batched=True))
serializers.append(CBORSerializer())
except ImportError:
pass

# try MsgPack WAMP serializer
try:
from autobahn.wamp.serializer import MsgPackSerializer
serializers.append(MsgPackSerializer(batched=True))
serializers.append(MsgPackSerializer())
except ImportError:
pass

# try UBJSON WAMP serializer
try:
from autobahn.wamp.serializer import UBJSONSerializer
serializers.append(UBJSONSerializer(batched=True))
serializers.append(UBJSONSerializer())
except ImportError:
pass

# try JSON WAMP serializer
try:
from autobahn.wamp.serializer import JsonSerializer
serializers.append(JsonSerializer(batched=True))
serializers.append(JsonSerializer())
except ImportError:
pass

if not serializers:
raise Exception(u'Could not import any WAMP serializer')

self._serializers = {}
for ser in serializers:
self._serializers[ser.SERIALIZER_ID] = ser

self._protocols = [u'wamp.2.{}'.format(ser.SERIALIZER_ID) for ser in serializers]


class WampWebSocketServerFactory(WampWebSocketFactory):
"""
Mixin for WAMP-over-WebSocket server transport factories.
"""


class WampWebSocketClientFactory(WampWebSocketFactory):
"""
Mixin for WAMP-over-WebSocket client transport factories.
"""

+ 0
- 0
venv/lib/python3.7/site-packages/autobahn/websocket/compress_bzip2.py View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save