From 11ea8ee592117f1c502677de514ace5f03c88e9d Mon Sep 17 00:00:00 2001 From: Laurent Mazuel Date: Tue, 18 Oct 2016 13:36:06 -0700 Subject: [PATCH] Remove Python msrest/msrestazure from Autorest repo (#1518) * Remove msrest from Autorest repo * Remove Python msrest from gulpfile * Remove hack in msrestazure to read ../msrest * Update dependencies of Python msrestazure to get msrest from PyPI * Adding mock in msrestazure tests * Simplify tox config for msrestazure * msrestazure 0.4.4 (#1514) * Remove msrestazure Python --- gulpfile.js | 3 - src/client/Python/.gitignore | 72 - src/client/Python/client_runtime.sln | 24 - src/client/Python/msrest/MANIFEST.in | 1 - src/client/Python/msrest/doc/conf.py | 241 ---- src/client/Python/msrest/doc/index.rst | 65 - src/client/Python/msrest/doc/make.bat | 242 ---- src/client/Python/msrest/doc/modules.rst | 7 - src/client/Python/msrest/doc/msrest.rst | 86 -- .../Python/msrest/doc/operation_config.rst | 21 - src/client/Python/msrest/doc/requirements.txt | 2 - src/client/Python/msrest/msrest.pyproj | 102 -- src/client/Python/msrest/msrest/__init__.py | 39 - .../Python/msrest/msrest/authentication.py | 129 -- .../Python/msrest/msrest/configuration.py | 177 --- src/client/Python/msrest/msrest/exceptions.py | 161 --- .../Python/msrest/msrest/http_logger.py | 91 -- src/client/Python/msrest/msrest/paging.py | 94 -- src/client/Python/msrest/msrest/pipeline.py | 454 ------- .../Python/msrest/msrest/serialization.py | 1164 ---------------- .../Python/msrest/msrest/service_client.py | 361 ----- src/client/Python/msrest/msrest/version.py | 28 - src/client/Python/msrest/readme.rst | 146 -- src/client/Python/msrest/requirements27.txt | 14 - src/client/Python/msrest/requirements35.txt | 12 - src/client/Python/msrest/setup.py | 58 - src/client/Python/msrest/test/__init__.py | 38 - .../Python/msrest/test/unittest_auth.py | 85 -- .../Python/msrest/test/unittest_client.py | 231 ---- .../Python/msrest/test/unittest_pipeline.py | 202 --- .../Python/msrest/test/unittest_runtime.py | 412 ------ .../msrest/test/unittest_serialization.py | 1192 ----------------- src/client/Python/msrest/tox.ini | 34 - src/client/Python/msrest_build.sh | 15 - src/client/Python/msrestazure/MANIFEST.in | 1 - src/client/Python/msrestazure/doc/conf.py | 239 ---- src/client/Python/msrestazure/doc/index.rst | 64 - src/client/Python/msrestazure/doc/make.bat | 242 ---- src/client/Python/msrestazure/doc/modules.rst | 7 - .../Python/msrestazure/doc/msrestazure.rst | 54 - .../Python/msrestazure/msrestazure.pyproj | 78 -- .../msrestazure/msrestazure/__init__.py | 33 - .../msrestazure/azure_active_directory.py | 527 -------- .../msrestazure/azure_configuration.py | 78 -- .../msrestazure/azure_exceptions.py | 198 --- .../msrestazure/azure_operation.py | 559 -------- .../Python/msrestazure/msrestazure/version.py | 27 - src/client/Python/msrestazure/readme.rst | 133 -- .../Python/msrestazure/requirements27.txt | 15 - .../Python/msrestazure/requirements35.txt | 13 - src/client/Python/msrestazure/setup.py | 53 - .../Python/msrestazure/test/__init__.py | 56 - .../Python/msrestazure/test/unittest_auth.py | 361 ----- .../msrestazure/test/unittest_exceptions.py | 204 --- .../msrestazure/test/unittest_operation.py | 312 ----- src/client/Python/msrestazure/tox.ini | 34 - 56 files changed, 9291 deletions(-) delete mode 100644 src/client/Python/.gitignore delete mode 100644 src/client/Python/client_runtime.sln delete mode 100644 src/client/Python/msrest/MANIFEST.in delete mode 100644 src/client/Python/msrest/doc/conf.py delete mode 100644 src/client/Python/msrest/doc/index.rst delete mode 100644 src/client/Python/msrest/doc/make.bat delete mode 100644 src/client/Python/msrest/doc/modules.rst delete mode 100644 src/client/Python/msrest/doc/msrest.rst delete mode 100644 src/client/Python/msrest/doc/operation_config.rst delete mode 100644 src/client/Python/msrest/doc/requirements.txt delete mode 100644 src/client/Python/msrest/msrest.pyproj delete mode 100644 src/client/Python/msrest/msrest/__init__.py delete mode 100644 src/client/Python/msrest/msrest/authentication.py delete mode 100644 src/client/Python/msrest/msrest/configuration.py delete mode 100644 src/client/Python/msrest/msrest/exceptions.py delete mode 100644 src/client/Python/msrest/msrest/http_logger.py delete mode 100644 src/client/Python/msrest/msrest/paging.py delete mode 100644 src/client/Python/msrest/msrest/pipeline.py delete mode 100644 src/client/Python/msrest/msrest/serialization.py delete mode 100644 src/client/Python/msrest/msrest/service_client.py delete mode 100644 src/client/Python/msrest/msrest/version.py delete mode 100644 src/client/Python/msrest/readme.rst delete mode 100644 src/client/Python/msrest/requirements27.txt delete mode 100644 src/client/Python/msrest/requirements35.txt delete mode 100644 src/client/Python/msrest/setup.py delete mode 100644 src/client/Python/msrest/test/__init__.py delete mode 100644 src/client/Python/msrest/test/unittest_auth.py delete mode 100644 src/client/Python/msrest/test/unittest_client.py delete mode 100644 src/client/Python/msrest/test/unittest_pipeline.py delete mode 100644 src/client/Python/msrest/test/unittest_runtime.py delete mode 100644 src/client/Python/msrest/test/unittest_serialization.py delete mode 100644 src/client/Python/msrest/tox.ini delete mode 100644 src/client/Python/msrest_build.sh delete mode 100644 src/client/Python/msrestazure/MANIFEST.in delete mode 100644 src/client/Python/msrestazure/doc/conf.py delete mode 100644 src/client/Python/msrestazure/doc/index.rst delete mode 100644 src/client/Python/msrestazure/doc/make.bat delete mode 100644 src/client/Python/msrestazure/doc/modules.rst delete mode 100644 src/client/Python/msrestazure/doc/msrestazure.rst delete mode 100644 src/client/Python/msrestazure/msrestazure.pyproj delete mode 100644 src/client/Python/msrestazure/msrestazure/__init__.py delete mode 100644 src/client/Python/msrestazure/msrestazure/azure_active_directory.py delete mode 100644 src/client/Python/msrestazure/msrestazure/azure_configuration.py delete mode 100644 src/client/Python/msrestazure/msrestazure/azure_exceptions.py delete mode 100644 src/client/Python/msrestazure/msrestazure/azure_operation.py delete mode 100644 src/client/Python/msrestazure/msrestazure/version.py delete mode 100644 src/client/Python/msrestazure/readme.rst delete mode 100644 src/client/Python/msrestazure/requirements27.txt delete mode 100644 src/client/Python/msrestazure/requirements35.txt delete mode 100644 src/client/Python/msrestazure/setup.py delete mode 100644 src/client/Python/msrestazure/test/__init__.py delete mode 100644 src/client/Python/msrestazure/test/unittest_auth.py delete mode 100644 src/client/Python/msrestazure/test/unittest_exceptions.py delete mode 100644 src/client/Python/msrestazure/test/unittest_operation.py delete mode 100644 src/client/Python/msrestazure/tox.ini diff --git a/gulpfile.js b/gulpfile.js index 572fe1bd85..4dc46cc14c 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -748,15 +748,12 @@ gulp.task('test:clientruntime:ruby', ['syncDependencies:runtime:ruby'], shell.ta gulp.task('test:clientruntime:rubyazure', ['syncDependencies:runtime:rubyazure'], shell.task('bundle exec rspec', { cwd: './src/client/Ruby/ms-rest-azure/', verbosity: 3 })); gulp.task('test:clientruntime:java', shell.task(basePathOrThrow() + '/gradlew :client-runtime:check', { cwd: './', verbosity: 3 })); gulp.task('test:clientruntime:javaazure', shell.task(basePathOrThrow() + '/gradlew :azure-client-runtime:check', { cwd: './', verbosity: 3 })); -gulp.task('test:clientruntime:python', shell.task('tox', { cwd: './src/client/Python/msrest/', verbosity: 3 })); -gulp.task('test:clientruntime:pythonazure', shell.task('tox', { cwd: './src/client/Python/msrestazure/', verbose:true })); gulp.task('test:clientruntime:javaauthjdk', shell.task(basePathOrThrow() + '/gradlew :azure-client-authentication:check', { cwd: './', verbosity: 3 })); gulp.task('test:clientruntime:javaauthandroid', shell.task(basePathOrThrow() + '/gradlew :azure-android-client-authentication:check', { cwd: './', verbosity: 3 })); gulp.task('test:clientruntime', function (cb) { runSequence('test:clientruntime:node', 'test:clientruntime:nodeazure', 'test:clientruntime:ruby', 'test:clientruntime:rubyazure', - 'test:clientruntime:python', 'test:clientruntime:pythonazure', 'test:clientruntime:java', 'test:clientruntime:javaazure', 'test:clientruntime:javaauthjdk', 'test:clientruntime:javaauthandroid', cb); }); diff --git a/src/client/Python/.gitignore b/src/client/Python/.gitignore deleted file mode 100644 index 6ab65f8785..0000000000 --- a/src/client/Python/.gitignore +++ /dev/null @@ -1,72 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -*.egg-info/ -.installed.cfg -*.egg - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*,cover - -# Translations -*.mo -*.pot - -# Django stuff: -*.log - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -ClientRuntimes/Python/Python35-64-ENV/pip-selfcheck.json -ClientRuntimes/Python/Python35-64-ENV/pyvenv.cfg -ClientRuntimes/Python/Python35-64-ENV/Scripts/activate.bat -ClientRuntimes/Python/Python35-64-ENV/Scripts/Activate.ps1 -ClientRuntimes/Python/Python35-64-ENV/Scripts/deactivate.bat -*.pyc - -#tox directory -*.tox - -#python code coverage -*.coverage - diff --git a/src/client/Python/client_runtime.sln b/src/client/Python/client_runtime.sln deleted file mode 100644 index 5a43ffcd18..0000000000 --- a/src/client/Python/client_runtime.sln +++ /dev/null @@ -1,24 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "msrest", "msrest\msrest.pyproj", "{8523BA22-21D4-4F69-A73E-958B617C9D37}" -EndProject -Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "msrestazure", "msrestazure\msrestazure.pyproj", "{B80E5ECC-DCDC-4D31-B3BE-8C32DEA8E864}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8523BA22-21D4-4F69-A73E-958B617C9D37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8523BA22-21D4-4F69-A73E-958B617C9D37}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B80E5ECC-DCDC-4D31-B3BE-8C32DEA8E864}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B80E5ECC-DCDC-4D31-B3BE-8C32DEA8E864}.Release|Any CPU.ActiveCfg = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/src/client/Python/msrest/MANIFEST.in b/src/client/Python/msrest/MANIFEST.in deleted file mode 100644 index f3eb9637aa..0000000000 --- a/src/client/Python/msrest/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -include *.rst \ No newline at end of file diff --git a/src/client/Python/msrest/doc/conf.py b/src/client/Python/msrest/doc/conf.py deleted file mode 100644 index 80afc1e74f..0000000000 --- a/src/client/Python/msrest/doc/conf.py +++ /dev/null @@ -1,241 +0,0 @@ -# -*- coding: utf-8 -*- -# -# azure-sdk-for-python documentation build configuration file, created by -# sphinx-quickstart on Fri Jun 27 15:42:45 2014. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys -import os -import pip -import sphinx_rtd_theme - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.abspath('../')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinx.ext.doctest', - 'sphinx.ext.viewcode', 'sphinx.ext.intersphinx'] - -intersphinx_mapping = { - 'python': ('https://docs.python.org/3.5', None), -} - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'msrest' -copyright = u'2016, Microsoft' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '0.4.4' -# The full version, including alpha/beta/rc tags. -release = '0.4.4' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False - -# -- Options for extensions ---------------------------------------------------- -autoclass_content = 'both' - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -#html_theme = 'default' -html_theme = 'sphinx_rtd_theme' -#html_theme_options = {'collapsiblesidebar': True} - -# Activate the theme. -#pip.main(['install', 'sphinx_bootstrap_theme']) -#import sphinx_bootstrap_theme -#html_theme = 'bootstrap' -#html_theme_path = sphinx_bootstrap_theme.get_html_theme_path() -html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -# html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'msrest-doc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'msrest.tex', u'msrest Documentation', - u'Microsoft', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - diff --git a/src/client/Python/msrest/doc/index.rst b/src/client/Python/msrest/doc/index.rst deleted file mode 100644 index e6e1657017..0000000000 --- a/src/client/Python/msrest/doc/index.rst +++ /dev/null @@ -1,65 +0,0 @@ -msrest -====== - -Installation: -------------- - -From Pypi - - pip install msrest - -System Requirements: --------------------- - -The supported Python versions are 2.7.x, 3.3.x, 3.4.x, and 3.5.x -To download Python, please visit -https://www.python.org/download/ - - -We recommend Python Tools for Visual Studio as a development environment for developing your applications. Please visit http://aka.ms/python for more information. - - -Need Help?: ------------ - -Be sure to check out the Microsoft Azure `Developer Forums on Stack -Overflow `__ if you have -trouble with the provided code. - -Contributing: -------------- -Contribute Code or Provide Feedback: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you would like to become an active contributor to this project please -follow the instructions provided in `Microsoft Azure Projects -Contribution -Guidelines `__. - -If you encounter any bugs with the library please file an issue in the -`Issues `__ -section of the project. - -Learn More -========== - -`Microsoft Azure Python Developer -Center `__ - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - -.. toctree:: - :hidden: - -.. toctree:: - :hidden: - :glob: - - msrest - operation_config diff --git a/src/client/Python/msrest/doc/make.bat b/src/client/Python/msrest/doc/make.bat deleted file mode 100644 index e99e578d5c..0000000000 --- a/src/client/Python/msrest/doc/make.bat +++ /dev/null @@ -1,242 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=_build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . -set I18NSPHINXOPTS=%SPHINXOPTS% . -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% - set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. texinfo to make Texinfo files - echo. gettext to make PO message catalogs - echo. changes to make an overview over all changed/added/deprecated items - echo. xml to make Docutils-native XML files - echo. pseudoxml to make pseudoxml-XML files for display purposes - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - - -%SPHINXBUILD% 2> nul -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\pydocumentdb.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\pydocumentdb.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdf" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf - cd %BUILDDIR%/.. - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdfja" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf-ja - cd %BUILDDIR%/.. - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end -) - -if "%1" == "gettext" ( - %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -if "%1" == "xml" ( - %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The XML files are in %BUILDDIR%/xml. - goto end -) - -if "%1" == "pseudoxml" ( - %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. - goto end -) - -:end diff --git a/src/client/Python/msrest/doc/modules.rst b/src/client/Python/msrest/doc/modules.rst deleted file mode 100644 index 50eaa617cd..0000000000 --- a/src/client/Python/msrest/doc/modules.rst +++ /dev/null @@ -1,7 +0,0 @@ -msrest -====== - -.. toctree:: - :maxdepth: 4 - - msrest diff --git a/src/client/Python/msrest/doc/msrest.rst b/src/client/Python/msrest/doc/msrest.rst deleted file mode 100644 index e8fa300d32..0000000000 --- a/src/client/Python/msrest/doc/msrest.rst +++ /dev/null @@ -1,86 +0,0 @@ -msrest package -============== - -Submodules ----------- - -msrest.authentication module ----------------------------- - -.. automodule:: msrest.authentication - :members: - :undoc-members: - :show-inheritance: - -msrest.configuration module ---------------------------- - -.. automodule:: msrest.configuration - :members: - :undoc-members: - :show-inheritance: - -msrest.exceptions module ------------------------- - -.. automodule:: msrest.exceptions - :members: - :undoc-members: - :show-inheritance: - -msrest.http_logger module -------------------------- - -.. automodule:: msrest.http_logger - :members: - :undoc-members: - :show-inheritance: - -msrest.paging module --------------------- - -.. automodule:: msrest.paging - :members: - :undoc-members: - :show-inheritance: - -msrest.pipeline module ----------------------- - -.. automodule:: msrest.pipeline - :members: - :undoc-members: - :show-inheritance: - -msrest.serialization module ---------------------------- - -.. automodule:: msrest.serialization - :members: - :undoc-members: - :show-inheritance: - -msrest.service_client module ----------------------------- - -.. automodule:: msrest.service_client - :members: - :undoc-members: - :show-inheritance: - -msrest.version module ---------------------- - -.. automodule:: msrest.version - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: msrest - :members: - :undoc-members: - :show-inheritance: diff --git a/src/client/Python/msrest/doc/operation_config.rst b/src/client/Python/msrest/doc/operation_config.rst deleted file mode 100644 index 5482a9ceb4..0000000000 --- a/src/client/Python/msrest/doc/operation_config.rst +++ /dev/null @@ -1,21 +0,0 @@ -.. _optionsforoperations: - -Operation config -================ - -Methods on operations have extra parameters which can be provided in the kwargs. This is called `operation_config`. - -The list of operation configuration is: - -=============== ==== ==== -Parameter name Type Role -=============== ==== ==== -verify bool -cert str -timeout int -allow_redirects bool -max_redirects int -proxies dict -use_env_proxies bool whether to read proxy settings from local env vars -retries int number of retries -=============== ==== ==== diff --git a/src/client/Python/msrest/doc/requirements.txt b/src/client/Python/msrest/doc/requirements.txt deleted file mode 100644 index 82133027c9..0000000000 --- a/src/client/Python/msrest/doc/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -sphinx -sphinx_rtd_theme diff --git a/src/client/Python/msrest/msrest.pyproj b/src/client/Python/msrest/msrest.pyproj deleted file mode 100644 index 6ede93478d..0000000000 --- a/src/client/Python/msrest/msrest.pyproj +++ /dev/null @@ -1,102 +0,0 @@ - - - - Debug - 2.0 - 8523ba22-21d4-4f69-a73e-958b617c9d37 - - - msrest\__init__.py - . - . - . - msrest - msrest - - - - - - - true - false - - - true - false - - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - - - - - - - Code - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets - - - - - - - - - - \ No newline at end of file diff --git a/src/client/Python/msrest/msrest/__init__.py b/src/client/Python/msrest/msrest/__init__.py deleted file mode 100644 index 87271ec8c3..0000000000 --- a/src/client/Python/msrest/msrest/__init__.py +++ /dev/null @@ -1,39 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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 .configuration import Configuration -from .service_client import ServiceClient -from .serialization import Serializer, Deserializer -from .version import msrest_version - -__all__ = [ - "ServiceClient", - "Serializer", - "Deserializer", - "Configuration" - ] - -__version__ = msrest_version diff --git a/src/client/Python/msrest/msrest/authentication.py b/src/client/Python/msrest/msrest/authentication.py deleted file mode 100644 index 48c90ae61b..0000000000 --- a/src/client/Python/msrest/msrest/authentication.py +++ /dev/null @@ -1,129 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -# -------------------------------------------------------------------------- - -import requests -from requests.auth import HTTPBasicAuth -import requests_oauthlib as oauth - - -class Authentication(object): - """Default, simple auth object. - Doesn't actually add any auth headers. - """ - - header = "Authorization" - - def signed_session(self): - """Create requests session with any required auth headers - applied. - - :rtype: requests.Session. - """ - return requests.Session() - - -class BasicAuthentication(Authentication): - """Implmentation of Basic Authentication. - - :param str username: Authentication username. - :param str password: Authentication password. - """ - - def __init__(self, username, password): - self.scheme = 'Basic' - self.username = username - self.password = password - - def signed_session(self): - """Create requests session with any required auth headers - applied. - - :rtype: requests.Session. - """ - session = super(BasicAuthentication, self).signed_session() - session.auth = HTTPBasicAuth(self.username, self.password) - return session - - -class BasicTokenAuthentication(Authentication): - """Simple Token Authentication. - Does not adhere to OAuth, simply adds provided token as a header. - - :param dict token: Authentication token, must have 'access_token' key. - """ - - def __init__(self, token): - self.scheme = 'Bearer' - self.token = token - - def signed_session(self): - """Create requests session with any required auth headers - applied. - - :rtype: requests.Session. - """ - session = super(BasicTokenAuthentication, self).signed_session() - header = "{} {}".format(self.scheme, self.token['access_token']) - session.headers['Authorization'] = header - return session - - -class OAuthTokenAuthentication(Authentication): - """OAuth Token Authentication. - Requires that supplied token contains an expires_in field. - - :param str client_id: Account Client ID. - :param dict token: OAuth2 token. - """ - - def __init__(self, client_id, token): - self.scheme = 'Bearer' - self.id = client_id - self.token = token - self.store_key = self.id - - def construct_auth(self): - """Format token header. - - :rtype: str. - """ - return "{} {}".format(self.scheme, self.token) - - def refresh_session(self): - """Return updated session if token has expired, attempts to - refresh using refresh token. - - :rtype: requests.Session. - """ - return self.signed_session() - - def signed_session(self): - """Create requests session with any required auth headers - applied. - - :rtype: requests.Session. - """ - return oauth.OAuth2Session(self.id, token=self.token) diff --git a/src/client/Python/msrest/msrest/configuration.py b/src/client/Python/msrest/msrest/configuration.py deleted file mode 100644 index f9b4e06d20..0000000000 --- a/src/client/Python/msrest/msrest/configuration.py +++ /dev/null @@ -1,177 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -# -------------------------------------------------------------------------- - - -try: - import configparser - from configparser import NoOptionError -except ImportError: - import ConfigParser as configparser - from ConfigParser import NoOptionError -import platform - -import requests - -from .exceptions import raise_with_traceback -from .pipeline import ( - ClientRetryPolicy, - ClientRedirectPolicy, - ClientProxies, - ClientConnection) -from .version import msrest_version - - -class Configuration(object): - """Client configuration. - - :param str baseurl: REST API base URL. - :param str filepath: Path to existing config file (optional). - """ - - def __init__(self, base_url, filepath=None): - # Service - self.base_url = base_url - - # Communication configuration - self.connection = ClientConnection() - - # ProxyConfiguration - self.proxies = ClientProxies() - - # Retry configuration - self.retry_policy = ClientRetryPolicy() - - # Redirect configuration - self.redirect_policy = ClientRedirectPolicy() - - # User-Agent Header - self._user_agent = "python/{} ({}) requests/{} msrest/{}".format( - platform.python_version(), - platform.platform(), - requests.__version__, - msrest_version) - - self._config = configparser.ConfigParser() - self._config.optionxform = str - - if filepath: - self.load(filepath) - - @property - def user_agent(self): - return self._user_agent - - def add_user_agent(self, value): - self._user_agent = "{} {}".format(self._user_agent, value) - - def _clear_config(self): - """Clearout config object in memory.""" - for section in self._config.sections(): - self._config.remove_section(section) - - def save(self, filepath): - """Save current configuration to file. - - :param str filepath: Path to file where settings will be saved. - :raises: ValueError if supplied filepath cannot be written to. - :rtype: None - """ - sections = [ - "Connection", - "Proxies", - "RetryPolicy", - "RedirectPolicy"] - for section in sections: - self._config.add_section(section) - - self._config.set("Connection", "base_url", self.base_url) - self._config.set("Connection", "timeout", self.connection.timeout) - self._config.set("Connection", "verify", self.connection.verify) - self._config.set("Connection", "cert", self.connection.cert) - - self._config.set("Proxies", "proxies", self.proxies.proxies) - self._config.set("Proxies", "env_settings", - self.proxies.use_env_settings) - - self._config.set("RetryPolicy", "retries", self.retry_policy.retries) - self._config.set("RetryPolicy", "backoff_factor", - self.retry_policy.backoff_factor) - self._config.set("RetryPolicy", "max_backoff", - self.retry_policy.max_backoff) - - self._config.set("RedirectPolicy", "allow", self.redirect_policy.allow) - self._config.set("RedirectPolicy", "max_redirects", - self.redirect_policy.max_redirects) - try: - with open(filepath, 'w') as configfile: - self._config.write(configfile) - except (KeyError, EnvironmentError): - error = "Supplied config filepath invalid." - raise_with_traceback(ValueError, error) - finally: - self._clear_config() - - def load(self, filepath): - """Load configuration from existing file. - - :param str filepath: Path to existing config file. - :raises: ValueError if supplied config file is invalid. - :rtype: None - """ - try: - self._config.read(filepath) - - self.base_url = \ - self._config.get("Connection", "base_url") - self.connection.timeout = \ - self._config.getint("Connection", "timeout") - self.connection.verify = \ - self._config.getboolean("Connection", "verify") - self.connection.cert = \ - self._config.get("Connection", "cert") - - self.proxies.proxies = \ - eval(self._config.get("Proxies", "proxies")) - self.proxies.use_env_settings = \ - self._config.getboolean("Proxies", "env_settings") - - self.retry_policy.retries = \ - self._config.getint("RetryPolicy", "retries") - self.retry_policy.backoff_factor = \ - self._config.getfloat("RetryPolicy", "backoff_factor") - self.retry_policy.max_backoff = \ - self._config.getint("RetryPolicy", "max_backoff") - - self.redirect_policy.allow = \ - self._config.getboolean("RedirectPolicy", "allow") - self.redirect_policy.max_redirects = \ - self._config.set("RedirectPolicy", "max_redirects") - - except (ValueError, EnvironmentError, NoOptionError): - error = "Supplied config file incompatible." - raise_with_traceback(ValueError, error) - finally: - self._clear_config() diff --git a/src/client/Python/msrest/msrest/exceptions.py b/src/client/Python/msrest/msrest/exceptions.py deleted file mode 100644 index 85668a6661..0000000000 --- a/src/client/Python/msrest/msrest/exceptions.py +++ /dev/null @@ -1,161 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -# -------------------------------------------------------------------------- - -import logging -import sys - -from requests import RequestException - - -_LOGGER = logging.getLogger(__name__) - - -def raise_with_traceback(exception, message="", *args, **kwargs): - """Raise exception with a specified traceback. - - :param Exception exception: Error type to be raised. - :param str message: Message to include with error, empty by default. - :param args: Any additional args to be included with exception. - """ - exc_type, exc_value, exc_traceback = sys.exc_info() - exc_msg = "{}, {}: {}".format(message, exc_type.__name__, exc_value) - error = exception(exc_msg, *args, **kwargs) - try: - raise error.with_traceback(exc_traceback) - except AttributeError: - error.__traceback__ = exc_traceback - raise error - - -class ClientException(Exception): - """Base exception for all Client Runtime exceptions.""" - - def __init__(self, message, inner_exception=None, *args, **kwargs): - self.inner_exception = inner_exception - _LOGGER.debug(message) - super(ClientException, self).__init__(message, *args, **kwargs) - - -class SerializationError(ClientException): - """Error raised during request serialization.""" - pass - - -class DeserializationError(ClientException): - """Error raised during response deserialization.""" - pass - - -class TokenExpiredError(ClientException): - """OAuth token expired, request failed.""" - pass - - -class ValidationError(ClientException): - """Request parameter validation failed.""" - - messages = { - "min_length": "must have length greater than {!r}.", - "max_length": "must have length less than {!r}.", - "minimum": "must be greater than {!r}.", - "maximum": "must be less than {!r}.", - "minimum_ex": "must be equal to or greater than {!r}.", - "maximum_ex": "must be equal to or less than {!r}.", - "min_items": "must contain at least {!r} items.", - "max_items": "must contain at most {!r} items.", - "pattern": "must conform to the following pattern: {!r}.", - "unique": "must contain only unique items.", - "multiple": "must be a multiple of {!r}.", - "required": "can not be None." - } - - def __init__(self, rule, target, value, *args, **kwargs): - self.rule = rule - self.target = target - message = "Parameter {!r} ".format(target) - reason = self.messages.get( - rule, "failed to meet validation requirement.") - message += reason.format(value) - super(ValidationError, self).__init__(message, *args, **kwargs) - - -class ClientRequestError(ClientException): - """Client request failed.""" - pass - - -class AuthenticationError(ClientException): - """Client request failed to authentication.""" - pass - - -class HttpOperationError(ClientException): - """Client request failed due to server-specificed HTTP operation error. - Attempts to deserialize response into specific error object. - - :param Deserializer deserialize: Deserializer with data on custom - error objects. - :param requests.Response response: Server response - :param str resp_type: Objects type to deserialize response. - :param args: Additional args to pass to exception object. - """ - - def __str__(self): - return str(self.message) - - def __init__(self, deserialize, response, - resp_type=None, *args, **kwargs): - self.error = None - self.message = None - self.response = response - try: - if resp_type: - self.error = deserialize(resp_type, response) - if self.error is None: - self.error = deserialize.dependencies[resp_type]() - self.message = self.error.message - except (DeserializationError, AttributeError, KeyError): - pass - - if not self.error or not self.message: - try: - response.raise_for_status() - except RequestException as err: - if not self.error: - self.error = err - - if not self.message: - msg = "Operation returned an invalid status code {!r}" - self.message = msg.format(response.reason) - else: - if not self.error: - self.error = response - - if not self.message: - self.message = "Unknown error" - - super(HttpOperationError, self).__init__( - self.message, self.error, *args, **kwargs) diff --git a/src/client/Python/msrest/msrest/http_logger.py b/src/client/Python/msrest/msrest/http_logger.py deleted file mode 100644 index 5159a996a6..0000000000 --- a/src/client/Python/msrest/msrest/http_logger.py +++ /dev/null @@ -1,91 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -# -------------------------------------------------------------------------- - -import logging -import re -import types - - -_LOGGER = logging.getLogger(__name__) - - -def log_request(adapter, request, *args, **kwargs): - """Log a client request. - - :param ClientHTTPAdapter adapter: Adapter making the request. - :param requests.Request request: The request object. - """ - try: - _LOGGER.debug("Request URL: %r", request.url) - _LOGGER.debug("Request method: %r", request.method) - _LOGGER.debug("Request headers:") - for header, value in request.headers.items(): - _LOGGER.debug(" %r: %r", header, value) - _LOGGER.debug("Request body:") - - # We don't want to log the binary data of a file upload. - if isinstance(request.body, types.GeneratorType): - _LOGGER.debug("File upload") - else: - _LOGGER.debug(str(request.body)) - except Exception as err: - _LOGGER.debug("Failed to log request: %r", err) - - -def log_response(adapter, request, response, *args, **kwargs): - """Log a server response. - - :param ClientHTTPAdapter adapter: Adapter making the request. - :param requests.Request request: The request object. - :param requests.Response response: The response object. - """ - try: - result = kwargs['result'] - _LOGGER.debug("Response status: %r", result.status_code) - _LOGGER.debug("Response headers:") - for header, value in result.headers.items(): - _LOGGER.debug(" %r: %r", header, value) - - # We don't want to log binary data if the response is a file. - _LOGGER.debug("Response content:") - pattern = re.compile(r'attachment; ?filename=["\w.]+', re.IGNORECASE) - header = result.headers.get('content-disposition') - - if header and pattern.match(header): - filename = header.partition('=')[2] - _LOGGER.debug("File attachments: " + filename) - elif result.headers.get("content-type", "").endswith("octet-stream"): - _LOGGER.debug("Body contains binary data.") - elif result.headers.get("content-type", "").startswith("image"): - _LOGGER.debug("Body contains image data.") - elif result.headers.get("transfer-encoding") == 'chunked': - _LOGGER.debug("Body contains chunked data.") - else: - _LOGGER.debug(str(result.content)) - return result - except Exception as err: - _LOGGER.debug("Failed to log response: " + repr(err)) - return kwargs['result'] diff --git a/src/client/Python/msrest/msrest/paging.py b/src/client/Python/msrest/msrest/paging.py deleted file mode 100644 index 7c6f6fc135..0000000000 --- a/src/client/Python/msrest/msrest/paging.py +++ /dev/null @@ -1,94 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -# -------------------------------------------------------------------------- - -import collections - -from .serialization import Deserializer -from .pipeline import ClientRawResponse - - -class Paged(collections.Iterable): - """A container for paged REST responses. - - :param requests.Response response: server response object. - :param callable command: Function to retrieve the next page of items. - :param dict classes: A dictionary of class dependencies for - deserialization. - """ - _validation = {} - _attribute_map = {} - - def __init__(self, command, classes, raw_headers=None): - self.next_link = "" - self.current_page = [] - self._derserializer = Deserializer(classes) - self._get_next = command - self._response = None - self._raw_headers = raw_headers - - def __iter__(self): - """Iterate over response items in current page, automatically - retrieves next page. - """ - for i in self.current_page: - yield i - - while self.next_link is not None: - for i in self.next(): - yield i - - @classmethod - def _get_subtype_map(cls): - """Required for parity to Model object for deserialization.""" - return {} - - @property - def raw(self): - raw = ClientRawResponse(self.current_page, self._response) - if self._raw_headers: - raw.add_headers(self._raw_headers) - return raw - - def get(self, url): - """Get arbitrary page. - - :param str url: URL to arbitrary page results. - """ - self.next_link = url - return self.next() - - def reset(self): - """Reset iterator to first page.""" - self.next_link = "" - self.current_page = [] - - def next(self): - """Get next page.""" - if self.next_link is None: - raise GeneratorExit("End of paging") - self._response = self._get_next(self.next_link) - self._derserializer(self, self._response) - return self.current_page diff --git a/src/client/Python/msrest/msrest/pipeline.py b/src/client/Python/msrest/msrest/pipeline.py deleted file mode 100644 index 44d6f22b72..0000000000 --- a/src/client/Python/msrest/msrest/pipeline.py +++ /dev/null @@ -1,454 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -# -------------------------------------------------------------------------- - -import functools -import json -import logging -try: - from urlparse import urlparse -except ImportError: - from urllib.parse import urlparse - -import requests -from requests.packages.urllib3 import Retry -from requests.packages.urllib3 import HTTPConnectionPool - -from .serialization import Deserializer - - -_LOGGER = logging.getLogger(__name__) - - -class ClientHTTPAdapter(requests.adapters.HTTPAdapter): - """HTTP Adapter to customize REST pipeline in Requests. - Handles both request and response objects. - """ - - def __init__(self, config): - self._client_hooks = { - 'request': ClientPipelineHook(), - 'response': ClientPipelineHook()} - - super(ClientHTTPAdapter, self).__init__() - - def _test_pipeline(self, *args, **kwargs): - """ - Custom pipeline manipulation for test framework, - """ - test_hosts = [('http', 'localhost', 3000), - ('http', 'localhost.', 3000)] - for host in test_hosts: - self.poolmanager.pools[host] = \ - ClientHTTPConnectionPool(host[1], port=host[2]) - - def event_hook(event): - """Function decorator to wrap events with hook callbacks.""" - def event_wrapper(func): - - @functools.wraps(func) - def execute_hook(self, *args, **kwargs): - return self._client_hooks[event](func, self, *args, **kwargs) - - return execute_hook - return event_wrapper - - def add_hook(self, event, callback, precall=True, overwrite=False): - """Add an event callback to hook into the REST pipeline. - - :param str event: The event to hook. Currently supports 'request' - and 'response'. - :param callable callback: The function to call. - :param bool precall: Whether the function will be called before or - after the event. - :param bool overwrite: Whether the function will overwrite the - original event. - :raises: TypeError if the callback is not a function. - :raises: KeyError if the event is not supported. - """ - if not callable(callback): - raise TypeError("Callback must be callable.") - - if event not in self._client_hooks: - raise KeyError( - "Event: {!r} is not able to be hooked.".format(event)) - - if precall: - debug = "Adding %r callback before event: %r" - _LOGGER.debug(debug, callback.__name__, event) - self._client_hooks[event].precalls.append(callback) - else: - debug = "Adding %r callback after event: %r" - _LOGGER.debug(debug, callback.__name__, event) - self._client_hooks[event].postcalls.append(callback) - - debug = "Callback to overwrite original call: %r" - _LOGGER.debug(debug, overwrite) - self._client_hooks[event].overwrite_call = overwrite - - def remove_hook(self, event, callback): - """Remove a specified event hook from the pipeline. - - :param str event: The event to hook. Currently supports 'request' - and 'response'. - :param callable callback: The function to remove. - :raises: KeyError if the event is not supported. - """ - try: - hook_event = self._client_hooks[event] - except KeyError: - raise KeyError( - "Event: {!r} is not able to be hooked.".format(event)) - else: - self._client_hooks[event].precalls = [ - c for c in hook_event.precalls if c != callback] - self._client_hooks[event].postcalls = [ - c for c in hook_event.postcalls if c != callback] - - @event_hook("request") - def send(self, request, stream=False, timeout=None, verify=True, - cert=None, proxies=None): - """Sends the request object.""" - return super(ClientHTTPAdapter, self).send( - request, stream, timeout, verify, cert, proxies) - - @event_hook("response") - def build_response(self, req, resp): - """Builds the response object.""" - return super(ClientHTTPAdapter, self).build_response(req, resp) - - -class ClientPipelineHook(object): - """Pipeline hook to wrap a specific event. - - :param bool overwrite: Whether to overwrite the original event. - """ - - def __init__(self, overwrite=False): - self.precalls = [] - self.postcalls = [] - self.overwrite_call = overwrite - - def __call__(self, func, *args, **kwargs): - """Execute event and any wrapping callbacks. - The result of the event is passed into all post-event - callbacks with a 'result' keyword arg. - """ - result = requests.Response() - - for call in self.precalls: - # Execute any pre-event callabcks - call(*args, **kwargs) - - if not self.overwrite_call: - # Execute original event - result = func(*args, **kwargs) - - for call in self.postcalls: - # Execute any post-event callbacks - result = call(result=result, *args, **kwargs) - - return result - - -class ClientRequest(requests.Request): - """Wrapper for requests.Request object.""" - - def add_header(self, header, value): - """Add a header to the single request. - - :param str header: The header name. - :param str value: The header value. - """ - self.headers[header] = value - - def add_headers(self, headers): - """Add multiple headers to the single request. - - :param dict headers: A dictionary of headers. - """ - for key, value in headers.items(): - self.add_header(key, value) - - def format_parameters(self, params): - """Format parameters into a valid query string. - It's assumed all parameters have already been quoted as - valid URL strings. - - :param dict params: A dictionary of parameters. - """ - query = urlparse(self.url).query - if query: - self.url = self.url.partition('?')[0] - existing_params = { - p[0]: p[-1] - for p in [p.partition('=') for p in query.split('&')] - } - params.update(existing_params) - query_params = ["{}={}".format(k, v) for k, v in params.items()] - query = '?' + '&'.join(query_params) - self.url = self.url + query - - def add_content(self, data): - """Add a body to the request. - - :param data: Request body data, can be a json serializable - object (e.g. dictionary) or a generator (e.g. file data). - """ - if data is None: - return - - try: - self.data = json.dumps(data) - self.headers['Content-Length'] = str(len(self.data)) - except TypeError: - self.data = data - - -class ClientRawResponse(object): - """Wrapper for response object. - This allows for additional data to be gathereded from the response, - for example deserialized headers. - It also allows the raw response object to be passed back to the user. - - :param output: Deserialized response object. - :param response: Raw response object. - """ - - def __init__(self, output, response): - self.response = response - self.output = output - self.headers = {} - self._deserialize = Deserializer() - - def add_headers(self, header_dict): - """Deserialize a specific header. - - :param dict header_dict: A dictionary containing the name of the - header and the type to deserialize to. - """ - for name, data_type in header_dict.items(): - value = self.response.headers.get(name) - value = self._deserialize(data_type, value) - self.headers[name] = value - - -class ClientRetry(Retry): - """Wrapper for urllib3 Retry object. - """ - - def __init__(self, **kwargs): - self.retry_cookie = None - - return super(ClientRetry, self).__init__(**kwargs) - - def increment(self, method=None, url=None, response=None, - error=None, _pool=None, _stacktrace=None): - increment = super(ClientRetry, self).increment( - method, url, response, error, _pool, _stacktrace) - - if response: - # Fixes open socket warnings in Python 3. - response.close() - response.release_conn() - - # Collect retry cookie - we only do this for the test server - # at this point, unless we implement a proper cookie policy. - increment.retry_cookie = response.getheader("Set-Cookie") - return increment - - def is_forced_retry(self, method, status_code): - debug = "Received status: %r for method %r" - _LOGGER.debug(debug, status_code, method) - output = super(ClientRetry, self).is_forced_retry(method, status_code) - _LOGGER.debug("Is forced retry: %r", output) - return output - - -class ClientRetryPolicy(object): - """Retry configuration settings. - Container for retry policy object. - """ - - safe_codes = [i for i in range(500) if i != 408] + [501, 505] - - def __init__(self): - self.policy = ClientRetry() - self.policy.total = 3 - self.policy.connect = 3 - self.policy.read = 3 - self.policy.backoff_factor = 0.8 - self.policy.BACKOFF_MAX = 90 - - retry_codes = [i for i in range(999) if i not in self.safe_codes] - self.policy.status_forcelist = retry_codes - self.policy.method_whitelist = ['HEAD', 'TRACE', 'GET', 'PUT', - 'OPTIONS', 'DELETE', 'POST', 'PATCH'] - - def __call__(self): - """Return configuration to be applied to connection.""" - debug = ("Configuring retry: max_retries=%r, " - "backoff_factor=%r, max_backoff=%r") - _LOGGER.debug( - debug, self.retries, self.backoff_factor, self.max_backoff) - return self.policy - - @property - def retries(self): - """Total number of allowed retries.""" - return self.policy.total - - @retries.setter - def retries(self, value): - self.policy.total = value - self.policy.connect = value - self.policy.read = value - - @property - def backoff_factor(self): - """Factor by which back-off delay is incementally increased.""" - return self.policy.backoff_factor - - @backoff_factor.setter - def backoff_factor(self, value): - self.policy.backoff_factor = value - - @property - def max_backoff(self): - """Max retry back-off delay.""" - return self.policy.BACKOFF_MAX - - @max_backoff.setter - def max_backoff(self, value): - self.policy.BACKOFF_MAX = value - - -class ClientRedirectPolicy(object): - """Redirect configuration settings. - """ - - def __init__(self): - self.allow = True - self.max_redirects = 30 - - def __bool__(self): - """Whether redirects are allowed.""" - return self.allow - - def __call__(self): - """Return configuration to be applied to connection.""" - debug = "Configuring redirects: allow=%r, max=%r" - _LOGGER.debug(debug, self.allow, self.max_redirects) - return self.max_redirects - - def check_redirect(self, resp, request): - """Whether redirect policy should be applied based on status code.""" - if resp.status_code in (301, 302) and \ - request.method not in ['GET', 'HEAD']: - return False - return True - - -class ClientProxies(object): - """Proxy configuration settings. - Proxies can also be configured using HTTP_PROXY and HTTPS_PROXY - environment variables, in which case set use_env_settings to True. - """ - - def __init__(self): - self.proxies = {} - self.use_env_settings = True - - def __call__(self): - """Return configuration to be applied to connection.""" - proxy_string = "\n".join( - [" {}: {}".format(k, v) for k, v in self.proxies.items()]) - - _LOGGER.debug("Configuring proxies: %r", proxy_string) - debug = "Evaluate proxies against ENV settings: %r" - _LOGGER.debug(debug, self.use_env_settings) - return self.proxies - - def add(self, protocol, proxy_url): - """Add proxy. - - :param str protocol: Protocol for which proxy is to be applied. Can - be 'http', 'https', etc. Can also include host. - :param str proxy_url: The proxy URL. Where basic auth is required, - use the format: http://user:password@host - """ - self.proxies[protocol] = proxy_url - - -class ClientConnection(object): - """Request connection configuration settings. - """ - - def __init__(self): - self.timeout = 100 - self.verify = True - self.cert = None - self.data_block_size = 4096 - - def __call__(self): - """Return configuration to be applied to connection.""" - debug = "Configuring request: timeout=%r, verify=%r, cert=%r" - _LOGGER.debug(debug, self.timeout, self.verify, self.cert) - return {'timeout': self.timeout, - 'verify': self.verify, - 'cert': self.cert} - - -class ClientHTTPConnectionPool(HTTPConnectionPool): - """Cookie logic only used for test server (localhost)""" - - def _add_test_cookie(self, retries, headers): - host = self.host.strip('.') - if retries.retry_cookie and host == 'localhost': - if headers: - headers['cookie'] = retries.retry_cookie - else: - self.headers['cookie'] = retries.retry_cookie - - def _remove_test_cookie(self, retries, headers): - host = self.host.strip('.') - if retries.retry_cookie and host == 'localhost': - retries.retry_cookie = None - if headers: - del headers['cookie'] - else: - del self.headers['cookie'] - - def urlopen(self, method, url, body=None, headers=None, - retries=None, *args, **kwargs): - if hasattr(retries, 'retry_cookie'): - self._add_test_cookie(retries, headers) - - response = super(ClientHTTPConnectionPool, self).urlopen( - method, url, body, headers, retries, *args, **kwargs) - - if hasattr(retries, 'retry_cookie'): - self._remove_test_cookie(retries, headers) - return response diff --git a/src/client/Python/msrest/msrest/serialization.py b/src/client/Python/msrest/msrest/serialization.py deleted file mode 100644 index 924cb6af6a..0000000000 --- a/src/client/Python/msrest/msrest/serialization.py +++ /dev/null @@ -1,1164 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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 base64 import b64decode, b64encode -import calendar -import datetime -import decimal -from enum import Enum -import json -import logging -import re -try: - from urllib import quote -except ImportError: - from urllib.parse import quote - -import chardet -import isodate - -from .exceptions import ( - ValidationError, - SerializationError, - DeserializationError, - raise_with_traceback) - -try: - basestring -except NameError: - basestring = str - -_LOGGER = logging.getLogger(__name__) - - -class UTC(datetime.tzinfo): - """Time Zone info for handling UTC""" - - def utcoffset(self, dt): - """UTF offset for UTC is 0.""" - return datetime.timedelta(0) - - def tzname(self, dt): - """Timestamp representation.""" - return "Z" - - def dst(self, dt): - """No daylight saving for UTC.""" - return datetime.timedelta(hours=1) - - -try: - from datetime import timezone - TZ_UTC = timezone.utc -except ImportError: - TZ_UTC = UTC() - - -class Model(object): - """Mixin for all client request body/response body models to support - serialization and deserialization. - """ - - _subtype_map = {} - _attribute_map = {} - _validation = {} - - def __init__(self, *args, **kwargs): - """Allow attribute setting via kwargs on initialization.""" - for k in kwargs: - setattr(self, k, kwargs[k]) - - def __eq__(self, other): - """Compare objects by comparing all attributes.""" - if isinstance(other, self.__class__): - return self.__class__.__dict__ == other.__class__.__dict__ - return False - - def __ne__(self, other): - """Compare objects by comparing all attributes.""" - return not self.__eq__(other) - - def __str__(self): - return str(self.__dict__) - - @classmethod - def _get_subtype_map(cls): - attr = '_subtype_map' - parents = cls.__bases__ - for base in parents: - if hasattr(base, attr) and base._subtype_map: - return base._subtype_map - return {} - - @classmethod - def _classify(cls, response, objects): - """Check the class _subtype_map for any child classes. - We want to ignore any inheirited _subtype_maps. - """ - try: - map = cls.__dict__.get('_subtype_map', {}) - - for _type, _classes in map.items(): - classification = response.get(_type) - try: - return objects[_classes[classification]] - except KeyError: - pass - - for c in _classes: - try: - _cls = objects[_classes[c]] - return _cls._classify(response, objects) - except (KeyError, TypeError): - continue - raise TypeError("Object cannot be classified futher.") - except AttributeError: - raise TypeError("Object cannot be classified futher.") - - -def _convert_to_datatype(data, data_type, localtypes): - if data is None: - return data - data_obj = localtypes.get(data_type.strip('{[]}')) - if data_obj: - if data_type.startswith('['): - data = [ - _convert_to_datatype( - param, data_type[1:-1], localtypes) for param in data - ] - elif data_type.startswith('{'): - data = { - key: _convert_to_datatype( - data[key], data_type[1:-1], localtypes) for key in data - } - elif issubclass(data_obj, Enum): - return data - elif not isinstance(data, data_obj): - result = { - key: _convert_to_datatype( - data[key], - data_obj._attribute_map[key]['type'], - localtypes) for key in data - } - data = data_obj(**result) - else: - try: - for attr, map in data._attribute_map.items(): - setattr(data, attr, _convert_to_datatype( - getattr(data, attr), map['type'], localtypes)) - except AttributeError: - pass - return data - - -class Serializer(object): - """Request object model serializer.""" - - basic_types = {str: 'str', int: 'int', bool: 'bool', float: 'float'} - days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", - 4: "Fri", 5: "Sat", 6: "Sun"} - months = {1: "Jan", 2: "Feb", 3: "Mar", 4: "Apr", 5: "May", 6: "Jun", - 7: "Jul", 8: "Aug", 9: "Sep", 10: "Oct", 11: "Nov", 12: "Dec"} - validation = { - "min_length": lambda x, y: len(x) < y, - "max_length": lambda x, y: len(x) > y, - "minimum": lambda x, y: x < y, - "maximum": lambda x, y: x > y, - "minimum_ex": lambda x, y: x <= y, - "maximum_ex": lambda x, y: x >= y, - "min_items": lambda x, y: len(x) < y, - "max_items": lambda x, y: len(x) > y, - "pattern": lambda x, y: not re.match(y, x), - "unique": lambda x, y: len(x) != len(set(x)), - "multiple": lambda x, y: x % y != 0 - } - flattten = re.compile(r"(? 9999 or utc.tm_year < 1: - raise OverflowError("Hit max or min date") - - microseconds = str(float(attr.microsecond)*1e-6)[1:].ljust(4, '0') - date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( - utc.tm_year, utc.tm_mon, utc.tm_mday, - utc.tm_hour, utc.tm_min, utc.tm_sec) - return date + microseconds + 'Z' - except (ValueError, OverflowError) as err: - msg = "Unable to serialize datetime object." - raise_with_traceback(SerializationError, msg, err) - except AttributeError as err: - msg = "ISO-8601 object must be valid Datetime object." - raise_with_traceback(TypeError, msg, err) - - @staticmethod - def serialize_unix(attr, **kwargs): - """Serialize Datetime object into IntTime format. - This is represented as seconds. - - :param Datetime attr: Object to be serialized. - :rtype: int - :raises: SerializationError if format invalid - """ - if isinstance(attr, int): - return attr - try: - if not attr.tzinfo: - _LOGGER.warning( - "Datetime with no tzinfo will be considered UTC.") - return int(calendar.timegm(attr.utctimetuple())) - except AttributeError: - raise TypeError("Unix time object must be valid Datetime object.") - - -class Deserializer(object): - """Response object model deserializer. - - :param dict classes: Class type dictionary for deserializing - complex types. - """ - - basic_types = {str: 'str', int: 'int', bool: 'bool', float: 'float'} - valid_date = re.compile( - r'\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}' - '\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?') - flatten = re.compile(r"(? 1: - decimal = "" - for digit in check_decimal[1]: - if digit.isdigit(): - decimal += digit - else: - break - if len(decimal) > 6: - attr = attr.replace(decimal, decimal[0:-1]) - - date_obj = isodate.parse_datetime(attr) - test_utc = date_obj.utctimetuple() - if test_utc.tm_year > 9999 or test_utc.tm_year < 1: - raise OverflowError("Hit max or min date") - except(ValueError, OverflowError, AttributeError) as err: - msg = "Cannot deserialize datetime object." - raise_with_traceback(DeserializationError, msg, err) - else: - return date_obj - - @staticmethod - def deserialize_unix(attr): - """Serialize Datetime object into IntTime format. - This is represented as seconds. - - :param int attr: Object to be serialized. - :rtype: Datetime - :raises: DeserializationError if format invalid - """ - try: - date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) - except ValueError as err: - msg = "Cannot deserialize to unix datetime object." - raise_with_traceback(DeserializationError, msg, err) - else: - return date_obj diff --git a/src/client/Python/msrest/msrest/service_client.py b/src/client/Python/msrest/msrest/service_client.py deleted file mode 100644 index a204089838..0000000000 --- a/src/client/Python/msrest/msrest/service_client.py +++ /dev/null @@ -1,361 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -# -------------------------------------------------------------------------- - -import contextlib -import logging -import os -try: - from urlparse import urljoin, urlparse -except ImportError: - from urllib.parse import urljoin, urlparse - -from oauthlib import oauth2 -import requests - -from .authentication import Authentication -from .pipeline import ClientHTTPAdapter, ClientRequest -from .http_logger import log_request, log_response -from .exceptions import ( - TokenExpiredError, - ClientRequestError, - raise_with_traceback) - - -_LOGGER = logging.getLogger(__name__) - - -class ServiceClient(object): - """REST Service Client. - Maintains client pipeline and handles all requests and responses. - - :param Configuration config: Service configuration. - :param Authentication creds: Authenticated credentials. - """ - - _protocols = ['http://', 'https://'] - - def __init__(self, creds, config): - self.config = config - self.creds = creds if creds else Authentication() - - self._adapter = ClientHTTPAdapter(config) - self._headers = {} - - self._adapter.add_hook("request", log_request) - self._adapter.add_hook("response", log_response, precall=False) - - def _format_data(self, data): - """Format field data according to whether it is a stream or - a string for a form-data request. - - :param data: The request field data. - :type data: str or file-like object. - """ - content = [None, data] - if hasattr(data, 'read'): - content.append("application/octet-stream") - try: - if data.name[0] != '<' and data.name[-1] != '>': - content[0] = os.path.basename(data.name) - except (AttributeError, TypeError): - pass - return tuple(content) - - def _request(self, url, params): - """Create ClientRequest object. - - :param str url: URL for the request. - :param dict params: URL query parameters. - """ - request = ClientRequest() - - if url: - request.url = self.format_url(url) - - if params: - request.format_parameters(params) - - return request - - def _configure_session(self, session, **config): - """Apply configuration to session. - - :param requests.Session session: Current request session. - :param config: Specific configuration overrides. - """ - kwargs = self.config.connection() - for opt in ['timeout', 'verify', 'cert']: - kwargs[opt] = config.get(opt, kwargs[opt]) - for opt in ['cookies', 'files']: - kwargs[opt] = config.get(opt) - kwargs['stream'] = True - kwargs['allow_redirects'] = config.get( - 'allow_redirects', bool(self.config.redirect_policy)) - - session.headers.update(self._headers) - session.headers['User-Agent'] = self.config.user_agent - session.headers['Accept'] = 'application/json' - session.max_redirects = config.get( - 'max_redirects', self.config.redirect_policy()) - session.proxies = config.get( - 'proxies', self.config.proxies()) - session.trust_env = config.get( - 'use_env_proxies', self.config.proxies.use_env_settings) - redirect_logic = session.resolve_redirects - - def wrapped_redirect(resp, req, **kwargs): - attempt = self.config.redirect_policy.check_redirect(resp, req) - return redirect_logic(resp, req, **kwargs) if attempt else [] - - session.resolve_redirects = wrapped_redirect - self._adapter.max_retries = config.get( - 'retries', self.config.retry_policy()) - for protocol in self._protocols: - session.mount(protocol, self._adapter) - - return kwargs - - def send_formdata(self, request, headers={}, content={}, **config): - """Send data as a multipart form-data request. - We only deal with file-like objects or strings at this point. - The requests is not yet streamed. - - :param ClientRequest request: The request object to be sent. - :param dict headers: Any headers to add to the request. - :param dict content: Dictionary of the fields of the formdata. - :param config: Any specific config overrides. - """ - file_data = {f: self._format_data(d) for f, d in content.items()} - try: - del headers['Content-Type'] - except KeyError: - pass - return self.send(request, headers, None, files=file_data, **config) - - def send(self, request, headers=None, content=None, **config): - """Prepare and send request object according to configuration. - - :param ClientRequest request: The request object to be sent. - :param dict headers: Any headers to add to the request. - :param content: Any body data to add to the request. - :param config: Any specific config overrides - """ - response = None - session = self.creds.signed_session() - kwargs = self._configure_session(session, **config) - - request.add_headers(headers if headers else {}) - if not kwargs.get('files'): - request.add_content(content) - try: - - try: - response = session.request( - request.method, request.url, - data=request.data, - headers=request.headers, - **kwargs) - return response - - except (oauth2.rfc6749.errors.InvalidGrantError, - oauth2.rfc6749.errors.TokenExpiredError) as err: - error = "Token expired or is invalid. Attempting to refresh." - _LOGGER.warning(error) - - try: - session = self.creds.refresh_session() - kwargs = self._configure_session(session) - - response = session.request( - request.method, request.url, - request.data, - request.headers, - **kwargs) - return response - except (oauth2.rfc6749.errors.InvalidGrantError, - oauth2.rfc6749.errors.TokenExpiredError) as err: - msg = "Token expired or is invalid." - raise_with_traceback(TokenExpiredError, msg, err) - - except (requests.RequestException, - oauth2.rfc6749.errors.OAuth2Error) as err: - msg = "Error occurred in request." - raise_with_traceback(ClientRequestError, msg, err) - finally: - if not response or response._content_consumed: - session.close() - - def stream_download(self, data, callback): - """Generator for streaming request body data. - - :param data: A response object to be streamed. - :param callback: Custom callback for monitoring progress. - """ - block = self.config.connection.data_block_size - if not data._content_consumed: - with contextlib.closing(data) as response: - for chunk in response.iter_content(block): - if not chunk: - break - if callback and callable(callback): - callback(chunk, response=response) - yield chunk - else: - for chunk in data.iter_content(block): - if not chunk: - break - if callback and callable(callback): - callback(chunk, response=data) - yield chunk - data.close() - self._adapter.close() - - def stream_upload(self, data, callback): - """Generator for streaming request body data. - - :param data: A file-like object to be streamed. - :param callback: Custom callback for monitoring progress. - """ - while True: - chunk = data.read(self.config.connection.data_block_size) - if not chunk: - break - if callback and callable(callback): - callback(chunk, response=None) - yield chunk - - def format_url(self, url, **kwargs): - """Format request URL with the client base URL, unless the - supplied URL is already absolute. - - :param str url: The request URL to be formatted if necessary. - """ - url = url.format(**kwargs) - parsed = urlparse(url) - if not parsed.scheme or not parsed.netloc: - url = url.lstrip('/') - base = self.config.base_url.format(**kwargs).rstrip('/') - url = urljoin(base + '/', url) - return url - - def add_hook(self, event, hook, precall=True, overwrite=False): - """ - Add event callback. - - :param str event: The pipeline event to hook. Currently supports - 'request' and 'response'. - :param callable hook: The callback function. - """ - self._adapter.add_hook(event, hook, precall, overwrite) - - def remove_hook(self, event, hook): - """ - Remove event callback. - - :param str event: The pipeline event to hook. Currently supports - 'request' and 'response'. - :param callable hook: The callback function. - """ - self._adapter.remove_hook(event, hook) - - def add_header(self, header, value): - """Add a persistent header - this header will be applied to all - requests sent during the current client session. - - :param str header: The header name. - :param str value: The header value. - """ - self._headers[header] = value - - def get(self, url=None, params={}): - """Create a GET request object. - - :param str url: The request URL. - :param dict params: Request URL parameters. - """ - request = self._request(url, params) - request.method = 'GET' - return request - - def put(self, url=None, params={}): - """Create a PUT request object. - - :param str url: The request URL. - :param dict params: Request URL parameters. - """ - request = self._request(url, params) - request.method = 'PUT' - return request - - def post(self, url=None, params={}): - """Create a POST request object. - - :param str url: The request URL. - :param dict params: Request URL parameters. - """ - request = self._request(url, params) - request.method = 'POST' - return request - - def head(self, url=None, params={}): - """Create a HEAD request object. - - :param str url: The request URL. - :param dict params: Request URL parameters. - """ - request = self._request(url, params) - request.method = 'HEAD' - return request - - def patch(self, url=None, params={}): - """Create a PATCH request object. - - :param str url: The request URL. - :param dict params: Request URL parameters. - """ - request = self._request(url, params) - request.method = 'PATCH' - return request - - def delete(self, url=None, params={}): - """Create a DELETE request object. - - :param str url: The request URL. - :param dict params: Request URL parameters. - """ - request = self._request(url, params) - request.method = 'DELETE' - return request - - def merge(self, url=None, params={}): - """Create a MERGE request object. - - :param str url: The request URL. - :param dict params: Request URL parameters. - """ - request = self._request(url, params) - request.method = 'MERGE' - return request diff --git a/src/client/Python/msrest/msrest/version.py b/src/client/Python/msrest/msrest/version.py deleted file mode 100644 index ce637857eb..0000000000 --- a/src/client/Python/msrest/msrest/version.py +++ /dev/null @@ -1,28 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -# -------------------------------------------------------------------------- - - -msrest_version = "0.4.4" diff --git a/src/client/Python/msrest/readme.rst b/src/client/Python/msrest/readme.rst deleted file mode 100644 index c513951371..0000000000 --- a/src/client/Python/msrest/readme.rst +++ /dev/null @@ -1,146 +0,0 @@ -AutoRest: Python Client Runtime -================================ - - -Installation ------------- - -To install: - -.. code-block:: bash - - $ pip install msrest - - -Release History ---------------- - -2016-09-14 Version 0.4.4 -++++++++++++++++++++++++ - -**Bugfixes** - -- Remove paging URL validation, part of fix https://github.com/Azure/autorest/pull/1420 - -**Disclaimer** - -In order to get paging fixes for impacted clients, you need this package and Autorest > 0.17.0 Nightly 20160913 - -2016-09-01 Version 0.4.3 -++++++++++++++++++++++++ - -**Bugfixes** - -- Better exception message (https://github.com/Azure/autorest/pull/1300) - -2016-08-15 Version 0.4.2 -++++++++++++++++++++++++ - -**Bugfixes** - -- Fix serialization if "object" type contains None (https://github.com/Azure/autorest/issues/1353) - -2016-08-08 Version 0.4.1 -++++++++++++++++++++++++ - -**Bugfixes** - -- Fix compatibility issues with requests 2.11.0 (https://github.com/Azure/autorest/issues/1337) -- Allow url of ClientRequest to have parameters (https://github.com/Azure/autorest/issues/1217) - -2016-05-25 Version 0.4.0 -++++++++++++++++++++++++ - -This version has no bug fixes, but implements new features of Autorest: -- Base64 url type -- unixtime type -- x-ms-enum modelAsString flag - -**Behaviour changes** - -- Add Platform information in UserAgent -- Needs Autorest > 0.17.0 Nightly 20160525 - -2016-04-26 Version 0.3.0 -++++++++++++++++++++++++ - -**Bugfixes** - -- Read only values are no longer in __init__ or sent to the server (https://github.com/Azure/autorest/pull/959) -- Useless kwarg removed - -**Behaviour changes** - -- Needs Autorest > 0.16.0 Nightly 20160426 - - -2016-03-25 Version 0.2.0 -++++++++++++++++++++++++ - -**Bugfixes** - -- Manage integer enum values (https://github.com/Azure/autorest/pull/879) -- Add missing application/json Accept HTTP header (https://github.com/Azure/azure-sdk-for-python/issues/553) - -**Behaviour changes** - -- Needs Autorest > 0.16.0 Nightly 20160324 - - -2016-03-21 Version 0.1.3 -++++++++++++++++++++++++ - -**Bugfixes** - -- Deserialisation of generic resource if null in JSON (https://github.com/Azure/azure-sdk-for-python/issues/544) - - -2016-03-14 Version 0.1.2 -++++++++++++++++++++++++ - -**Bugfixes** - -- urllib3 side effect (https://github.com/Azure/autorest/issues/824) - - -2016-03-04 Version 0.1.1 -++++++++++++++++++++++++ - -**Bugfixes** - -- Source package corrupted in Pypi (https://github.com/Azure/autorest/issues/799) - -2016-03-04 Version 0.1.0 -+++++++++++++++++++++++++ - -**Behavioural Changes** - -- Removed custom logging set up and configuration. All loggers are now children of the root logger 'msrest' with no pre-defined configurations. -- Replaced _required attribute in Model class with more extensive _validation dict. - -**Improvement** - -- Removed hierarchy scanning for attribute maps from base Model class - relies on generator to populate attribute - maps according to hierarchy. -- Base class Paged now inherits from collections.Iterable. -- Data validation during serialization using custom parameters (e.g. max, min etc). -- Added ValidationError to be raised if invalid data encountered during serialization. - -2016-02-29 Version 0.0.3 -++++++++++++++++++++++++ - -**Bugfixes** - -- Source package corrupted in Pypi (https://github.com/Azure/autorest/issues/718) - -2016-02-19 Version 0.0.2 -++++++++++++++++++++++++ - -**Bugfixes** - -- Fixed bug in exception logging before logger configured. - -2016-02-19 Version 0.0.1 -++++++++++++++++++++++++ - -- Initial release. \ No newline at end of file diff --git a/src/client/Python/msrest/requirements27.txt b/src/client/Python/msrest/requirements27.txt deleted file mode 100644 index bf78f048b7..0000000000 --- a/src/client/Python/msrest/requirements27.txt +++ /dev/null @@ -1,14 +0,0 @@ -certifi==2015.9.6.2 -enum34==1.0.4 -funcsigs==0.4 -futures==3.0.3 -httpretty==0.8.10 -isodate==0.5.4 -keyring==5.6 -mock==1.3.0 -oauthlib==1.0.3 -pbr==1.8.1 -requests==2.7.0 -requests-oauthlib==0.5.0 -six==1.10.0 -chardet==2.3.0 diff --git a/src/client/Python/msrest/requirements35.txt b/src/client/Python/msrest/requirements35.txt deleted file mode 100644 index 858771f012..0000000000 --- a/src/client/Python/msrest/requirements35.txt +++ /dev/null @@ -1,12 +0,0 @@ -funcsigs==0.4 -futures==3.0.3 -httpretty==0.8.10 -isodate==0.5.4 -keyring==5.6 -mock==1.3.0 -oauthlib==1.0.3 -pbr==1.8.1 -requests==2.7.0 -requests-oauthlib==0.5.0 -six==1.10.0 -chardet==2.3.0 diff --git a/src/client/Python/msrest/setup.py b/src/client/Python/msrest/setup.py deleted file mode 100644 index 00dcfc6be8..0000000000 --- a/src/client/Python/msrest/setup.py +++ /dev/null @@ -1,58 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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 setuptools import setup - -setup( - name='msrest', - version='0.4.4', - author='Microsoft Corporation', - packages=['msrest'], - url=("https://github.com/Azure/autorest/tree/master/" - "src/client/Python/msrest"), - license='MIT License', - description='AutoRest swagger generator Python client runtime.', - long_description=open('readme.rst').read(), - classifiers=[ - 'Development Status :: 4 - Beta', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'License :: OSI Approved :: MIT License', - 'Topic :: Software Development'], - install_requires=[ - "requests>=2.7.0", - "keyring>=5.6", - "requests_oauthlib>=0.5.0", - "isodate>=0.5.4", - "certifi>=2015.9.6.2", - "chardet>=2.3.0", - "enum34>=1.0.4;python_version < '3.4'"], -) diff --git a/src/client/Python/msrest/test/__init__.py b/src/client/Python/msrest/test/__init__.py deleted file mode 100644 index 9fbaeb2447..0000000000 --- a/src/client/Python/msrest/test/__init__.py +++ /dev/null @@ -1,38 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -# -------------------------------------------------------------------------- - -import os -from unittest import TestLoader, TextTestRunner - - -if __name__ == '__main__': - - runner = TextTestRunner(verbosity=2) - test_dir = os.path.dirname(__file__) - - test_loader = TestLoader() - suite = test_loader.discover(test_dir, pattern="unittest_*.py") - runner.run(suite) diff --git a/src/client/Python/msrest/test/unittest_auth.py b/src/client/Python/msrest/test/unittest_auth.py deleted file mode 100644 index e573a02d2d..0000000000 --- a/src/client/Python/msrest/test/unittest_auth.py +++ /dev/null @@ -1,85 +0,0 @@ -#-------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -#-------------------------------------------------------------------------- - -import os -import sys -import json -import isodate -from datetime import datetime -import base64 -from base64 import b64decode -import unittest -try: - from unittest import mock -except ImportError: - import mock - -from msrest.authentication import ( - BasicAuthentication, - OAuthTokenAuthentication) - -from requests import Request - - -class TestAuthentication(unittest.TestCase): - - def setUp(self): - - self.request = mock.create_autospec(Request) - self.request.headers = {} - self.request.cookies = {} - self.request.auth = None - self.request.url = "http://my_endpoint.com" - self.request.method = 'GET' - self.request.files = None - self.request.data = None - self.request.json = None - self.request.params = {} - self.request.hooks = {} - - return super(TestAuthentication, self).setUp() - - def test_basic_auth(self): - - basic = BasicAuthentication("username", "password") - session = basic.signed_session() - - req = session.auth(self.request) - self.assertTrue('Authorization' in req.headers) - self.assertTrue(req.headers['Authorization'].startswith('Basic ')) - - def test_token_auth(self): - - token = {"my_token":123} - auth = OAuthTokenAuthentication("client_id", token) - session = auth.signed_session() - - self.assertEqual(session.token, token) - - -if __name__ == '__main__': - unittest.main() - diff --git a/src/client/Python/msrest/test/unittest_client.py b/src/client/Python/msrest/test/unittest_client.py deleted file mode 100644 index c22b13edba..0000000000 --- a/src/client/Python/msrest/test/unittest_client.py +++ /dev/null @@ -1,231 +0,0 @@ -#-------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -#-------------------------------------------------------------------------- - -import io -import json -import unittest -try: - from unittest import mock -except ImportError: - import mock - -import requests -from oauthlib import oauth2 - -from msrest import ServiceClient -from msrest.authentication import OAuthTokenAuthentication -from msrest.pipeline import ( - ClientHTTPAdapter, - ClientPipelineHook, - ClientRequest) - -from msrest import Configuration -from msrest.exceptions import ClientRequestError, TokenExpiredError -from msrest.pipeline import ClientRequest - - -class TestServiceClient(unittest.TestCase): - - def setUp(self): - self.cfg = Configuration("https://my_endpoint.com") - self.creds = mock.create_autospec(OAuthTokenAuthentication) - return super(TestServiceClient, self).setUp() - - def test_client_request(self): - - client = ServiceClient(self.creds, self.cfg) - obj = client.get() - self.assertEqual(obj.method, 'GET') - self.assertIsNone(obj.url) - self.assertEqual(obj.params, {}) - - obj = client.get("/service", {'param':"testing"}) - self.assertEqual(obj.method, 'GET') - self.assertEqual(obj.url, "https://my_endpoint.com/service?param=testing") - self.assertEqual(obj.params, {}) - - obj = client.get("service 2") - self.assertEqual(obj.method, 'GET') - self.assertEqual(obj.url, "https://my_endpoint.com/service 2") - - self.cfg.base_url = "https://my_endpoint.com/" - obj = client.get("//service3") - self.assertEqual(obj.method, 'GET') - self.assertEqual(obj.url, "https://my_endpoint.com/service3") - - obj = client.put() - self.assertEqual(obj.method, 'PUT') - - obj = client.post() - self.assertEqual(obj.method, 'POST') - - obj = client.head() - self.assertEqual(obj.method, 'HEAD') - - obj = client.merge() - self.assertEqual(obj.method, 'MERGE') - - obj = client.patch() - self.assertEqual(obj.method, 'PATCH') - - obj = client.delete() - self.assertEqual(obj.method, 'DELETE') - - def test_client_header(self): - client = ServiceClient(self.creds, self.cfg) - client.add_header("test", "value") - - self.assertEqual(client._headers.get('test'), 'value') - - def test_client_add_hook(self): - - client = ServiceClient(self.creds, self.cfg) - - def hook(): - pass - - client.add_hook("request", hook) - self.assertTrue(hook in client._adapter._client_hooks['request'].precalls) - - client.add_hook("request", hook, precall=False) - self.assertTrue(hook in client._adapter._client_hooks['request'].postcalls) - - client.remove_hook("request", hook) - self.assertFalse(hook in client._adapter._client_hooks['request'].precalls) - self.assertFalse(hook in client._adapter._client_hooks['request'].postcalls) - - def test_format_url(self): - - url = "/bool/test true" - - mock_client = mock.create_autospec(ServiceClient) - mock_client.config = mock.Mock(base_url="http://localhost:3000") - - formatted = ServiceClient.format_url(mock_client, url) - self.assertEqual(formatted, "http://localhost:3000/bool/test true") - - mock_client.config = mock.Mock(base_url="http://localhost:3000/") - formatted = ServiceClient.format_url(mock_client, url, foo=123, bar="value") - self.assertEqual(formatted, "http://localhost:3000/bool/test true") - - url = "https://absolute_url.com/my/test/path" - formatted = ServiceClient.format_url(mock_client, url) - self.assertEqual(formatted, "https://absolute_url.com/my/test/path") - formatted = ServiceClient.format_url(mock_client, url, foo=123, bar="value") - self.assertEqual(formatted, "https://absolute_url.com/my/test/path") - - url = "test" - formatted = ServiceClient.format_url(mock_client, url) - self.assertEqual(formatted, "http://localhost:3000/test") - - mock_client.config = mock.Mock(base_url="http://{hostname}:{port}/{foo}/{bar}") - formatted = ServiceClient.format_url(mock_client, url, hostname="localhost", port="3000", foo=123, bar="value") - self.assertEqual(formatted, "http://localhost:3000/123/value/test") - - mock_client.config = mock.Mock(base_url="https://my_endpoint.com/") - formatted = ServiceClient.format_url(mock_client, url, foo=123, bar="value") - self.assertEqual(formatted, "https://my_endpoint.com/test") - - - def test_client_send(self): - - mock_client = mock.create_autospec(ServiceClient) - mock_client.config = self.cfg - mock_client.creds = self.creds - mock_client._configure_session.return_value = {} - session = mock.create_autospec(requests.Session) - mock_client.creds.signed_session.return_value = session - mock_client.creds.refresh_session.return_value = session - - request = ClientRequest('GET') - ServiceClient.send(mock_client, request) - session.request.call_count = 0 - mock_client._configure_session.assert_called_with(session) - session.request.assert_called_with('GET', None, data=[], headers={}) - session.close.assert_called_with() - - ServiceClient.send(mock_client, request, headers={'id':'1234'}, content={'Test':'Data'}) - mock_client._configure_session.assert_called_with(session) - session.request.assert_called_with('GET', None, data='{"Test": "Data"}', headers={'Content-Length': '16', 'id':'1234'}) - self.assertEqual(session.request.call_count, 1) - session.request.call_count = 0 - session.close.assert_called_with() - - session.request.side_effect = requests.RequestException("test") - with self.assertRaises(ClientRequestError): - ServiceClient.send(mock_client, request, headers={'id':'1234'}, content={'Test':'Data'}, test='value') - mock_client._configure_session.assert_called_with(session, test='value') - session.request.assert_called_with('GET', None, data='{"Test": "Data"}', headers={'Content-Length': '16', 'id':'1234'}) - self.assertEqual(session.request.call_count, 1) - session.request.call_count = 0 - session.close.assert_called_with() - - session.request.side_effect = oauth2.rfc6749.errors.InvalidGrantError("test") - with self.assertRaises(TokenExpiredError): - ServiceClient.send(mock_client, request, headers={'id':'1234'}, content={'Test':'Data'}, test='value') - self.assertEqual(session.request.call_count, 2) - session.request.call_count = 0 - session.close.assert_called_with() - - session.request.side_effect = ValueError("test") - with self.assertRaises(ValueError): - ServiceClient.send(mock_client, request, headers={'id':'1234'}, content={'Test':'Data'}, test='value') - session.close.assert_called_with() - - def test_client_formdata_send(self): - - mock_client = mock.create_autospec(ServiceClient) - mock_client._format_data.return_value = "formatted" - request = ClientRequest('GET') - ServiceClient.send_formdata(mock_client, request) - mock_client.send.assert_called_with(request, {}, None, files={}) - - ServiceClient.send_formdata(mock_client, request, {'id':'1234'}, {'Test':'Data'}) - mock_client.send.assert_called_with(request, {'id':'1234'}, None, files={'Test':'formatted'}) - - ServiceClient.send_formdata(mock_client, request, {'Content-Type':'1234'}, {'1':'1', '2':'2'}) - mock_client.send.assert_called_with(request, {}, None, files={'1':'formatted', '2':'formatted'}) - - def test_format_data(self): - - mock_client = mock.create_autospec(ServiceClient) - data = ServiceClient._format_data(mock_client, None) - self.assertEqual(data, (None, None)) - - data = ServiceClient._format_data(mock_client, "Test") - self.assertEqual(data, (None, "Test")) - - mock_stream = mock.create_autospec(io.BytesIO) - data = ServiceClient._format_data(mock_client, mock_stream) - self.assertEqual(data, (None, mock_stream, "application/octet-stream")) - - mock_stream.name = "file_name" - data = ServiceClient._format_data(mock_client, mock_stream) - self.assertEqual(data, ("file_name", mock_stream, "application/octet-stream")) - - -if __name__ == '__main__': - unittest.main() \ No newline at end of file diff --git a/src/client/Python/msrest/test/unittest_pipeline.py b/src/client/Python/msrest/test/unittest_pipeline.py deleted file mode 100644 index f608fe316f..0000000000 --- a/src/client/Python/msrest/test/unittest_pipeline.py +++ /dev/null @@ -1,202 +0,0 @@ -#-------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -#-------------------------------------------------------------------------- - -import json -import requests -import datetime -from enum import Enum -import unittest -try: - from unittest import mock -except ImportError: - import mock - -from msrest.pipeline import ( - ClientHTTPAdapter, - ClientPipelineHook, - ClientRequest, - ClientRawResponse) - -from msrest import Configuration - - -class TestPipelineHooks(unittest.TestCase): - - def event_hook(event): - def event_wrapper(func): - def execute_hook(self, *args, **kwargs): - return self.adp._client_hooks[event](func, self, *args, **kwargs) - return execute_hook - return event_wrapper - - @event_hook('request') - def mock_send(*args, **kwargs): - return "Not a real response" - - @event_hook('response') - def mock_response(*args, **kwargs): - resp = mock.MagicMock(result=200, headers={"a":1, "b":False}) - return resp - - def setUp(self): - - self.cfg = mock.create_autospec(Configuration) - self.cfg.log_name = "test_log" - self.adp = ClientHTTPAdapter(self.cfg) - self.adp.send = self.mock_send - self.adp.build_response = self.mock_response - - return super(TestPipelineHooks, self).setUp() - - def test_adding_hook(self): - - self.assertTrue('request' in self.adp._client_hooks) - self.assertTrue('response' in self.adp._client_hooks) - - with self.assertRaises(TypeError): - self.adp.add_hook('request', None) - - with self.assertRaises(TypeError): - self.adp.add_hook('response', 'NotCallable') - - with self.assertRaises(KeyError): - self.adp.add_hook('Something', lambda a:True) - - def hook(*args, **kwargs): - pass - - self.adp.add_hook('request', hook) - self.assertTrue(hook in self.adp._client_hooks['request'].precalls) - self.assertFalse(hook in self.adp._client_hooks['request'].postcalls) - - def hook2(*args, **kwargs): - pass - - self.adp.add_hook('response', hook2, precall=False) - self.assertFalse(hook2 in self.adp._client_hooks['response'].precalls) - self.assertTrue(hook2 in self.adp._client_hooks['response'].postcalls) - - def test_pre_event_callback(self): - - class TestEvent(Exception): - pass - - def hook(*args, **kwargs): - raise TestEvent("Entered hook function") - - self.adp.add_hook('request', hook) - - with self.assertRaises(TestEvent): - self.adp.send("request_obj") - - def test_overwrite_event_hook(self): - - resp = self.adp.send("request_obj") - self.assertEqual(resp, "Not a real response") - - def hook(*args, **kwargs): - self.assertEqual(args[1], "request_obj") - return None - - self.adp.add_hook('request', hook, precall=False, overwrite=True) - resp = self.adp.send("request_obj") - self.assertIsNone(resp) - - def test_post_event_callback(self): - - def hook(*args, **kwargs): - self.assertTrue('result' in kwargs) - self.assertEqual(kwargs['result'].result, 200) - return kwargs['result'] - - self.adp.add_hook('response', hook, precall=False) - resp = self.adp.build_response('request_obj') - self.assertEqual(resp.result, 200) - - def test_alter_response_callback(self): - - def hook(*args, **kwargs): - kwargs['result'].headers['a'] = "Changed!" - return kwargs['result'] - - self.adp.add_hook('response', hook, precall=False) - resp = self.adp.build_response('request_obj') - self.assertEqual(resp.headers['a'], "Changed!") - self.assertEqual(resp.headers['b'], False) - - -class TestClientRequest(unittest.TestCase): - - def test_request_headers(self): - - request = ClientRequest() - request.add_header("a", 1) - request.add_headers({'b':2, 'c':3}) - - self.assertEqual(request.headers, {'a':1, 'b':2, 'c':3}) - - def test_request_data(self): - - request = ClientRequest() - data = "Lots of dataaaa" - request.add_content(data) - - self.assertEqual(request.data, json.dumps(data)) - self.assertEqual(request.headers.get('Content-Length'), '17') - - def test_request_url_with_params(self): - - request = ClientRequest() - request.url = "a/b/c?t=y" - request.format_parameters({'g': 'h'}) - - self.assertIn(request.url, [ - 'a/b/c?g=h&t=y', - 'a/b/c?t=y&g=h' - ]) - -class TestClientResponse(unittest.TestCase): - - class Colors(Enum): - red = 'red' - blue = 'blue' - - def test_raw_response(self): - - response = mock.create_autospec(requests.Response) - response.headers = {} - response.headers["my-test"] = '1999-12-31T23:59:59-23:59' - response.headers["colour"] = "red" - - raw = ClientRawResponse([], response) - - raw.add_headers({'my-test': 'iso-8601', - 'another_header': 'str', - 'colour': TestClientResponse.Colors}) - self.assertIsInstance(raw.headers['my-test'], datetime.datetime) - -if __name__ == '__main__': - unittest.main() diff --git a/src/client/Python/msrest/test/unittest_runtime.py b/src/client/Python/msrest/test/unittest_runtime.py deleted file mode 100644 index fbdad6791f..0000000000 --- a/src/client/Python/msrest/test/unittest_runtime.py +++ /dev/null @@ -1,412 +0,0 @@ -#-------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -#-------------------------------------------------------------------------- - -import json -import httpretty -try: - from http.server import( - HTTPServer, - BaseHTTPRequestHandler) -except ImportError: - from BaseHTTPServer import HTTPServer - from BaseHTTPServer import BaseHTTPRequestHandler -import os -import requests -import re -import unittest -try: - from unittest import mock -except ImportError: - import mock - -from msrest.authentication import ( - Authentication, - OAuthTokenAuthentication) -from msrest.pipeline import ( - ClientHTTPAdapter, - ClientPipelineHook, - ClientRequest) -from msrest import ( - ServiceClient, - Configuration) -from msrest.exceptions import ( - TokenExpiredError, - ClientRequestError) - - -class TestRuntime(unittest.TestCase): - - @httpretty.activate - def test_credential_headers(self): - - httpretty.register_uri(httpretty.GET, "https://my_service.com/get_endpoint", - body='[{"title": "Test Data"}]', - content_type="application/json") - - token = { - 'access_token': 'eswfld123kjhn1v5423', - 'refresh_token': 'asdfkljh23490sdf', - 'token_type': 'Bearer', - 'expires_in': '3600', - } - - creds = OAuthTokenAuthentication("client_id", token) - cfg = Configuration("https://my_service.com") - - client = ServiceClient(creds, cfg) - - def hook(aptr, req, *args, **kwargs): - self.assertTrue('Authorization' in req.headers) - self.assertEqual(req.headers['Authorization'], 'Bearer eswfld123kjhn1v5423') - - client.add_hook('request', hook) - url = client.format_url("/get_endpoint") - request = client.get(url, {'check':True}) - response = client.send(request) - check = httpretty.last_request() - self.assertEqual(response.json(), [{"title": "Test Data"}]) - - token['expires_in'] = '-30' - creds = OAuthTokenAuthentication("client_id", token) - client = ServiceClient(creds, cfg) - url = client.format_url("/get_endpoint") - request = client.get(url, {'check':True}) - - with self.assertRaises(TokenExpiredError): - response = client.send(request) - - @mock.patch.object(requests, 'Session') - def test_request_fail(self, mock_requests): - - mock_requests.return_value.request.return_value = mock.Mock(_content_consumed=True) - - cfg = Configuration("https://my_service.com") - creds = Authentication() - - client = ServiceClient(creds, cfg) - url = client.format_url("/get_endpoint") - request = client.get(url, {'check':True}) - response = client.send(request) - - check = httpretty.last_request() - - self.assertTrue(response._content_consumed) - - mock_requests.return_value.request.side_effect = requests.RequestException - with self.assertRaises(ClientRequestError): - client.send(request) - - def test_request_proxy(self): - - cfg = Configuration("http://my_service.com") - cfg.proxies.add("http://my_service.com", 'http://localhost:57979') - creds = Authentication() - - def hook(adptr, request, *args, **kwargs): - self.assertEqual(kwargs.get('proxies'), {"http://my_service.com":'http://localhost:57979'}) - kwargs['result']._content_consumed = True - kwargs['result'].status_code = 200 - return kwargs['result'] - - client = ServiceClient(creds, cfg) - client.add_hook('request', hook, precall=False, overwrite=True) - url = client.format_url("/get_endpoint") - request = client.get(url, {'check':True}) - response = client.send(request) - - os.environ['HTTPS_PROXY'] = "http://localhost:1987" - - def hook2(adptr, request, *args, **kwargs): - self.assertEqual(kwargs.get('proxies')['https'], "http://localhost:1987") - kwargs['result']._content_consumed = True - kwargs['result'].status_code = 200 - return kwargs['result'] - - cfg = Configuration("http://my_service.com") - client = ServiceClient(creds, cfg) - client.add_hook('request', hook2, precall=False, overwrite=True) - url = client.format_url("/get_endpoint") - request = client.get(url, {'check':True}) - response = client.send(request) - - del os.environ['HTTPS_PROXY'] - - -class TestRedirect(unittest.TestCase): - - def setUp(self): - - cfg = Configuration("https://my_service.com") - cfg.retry_policy.backoff_factor=0 - cfg.redirect_policy.max_redirects=2 - creds = Authentication() - - self.client = ServiceClient(creds, cfg) - - return super(TestRedirect, self).setUp() - - @httpretty.activate - def test_request_redirect_post(self): - - url = self.client.format_url("/get_endpoint") - request = self.client.post(url, {'check':True}) - - httpretty.register_uri(httpretty.GET, 'https://my_service.com/http/success/get/200', status=200) - httpretty.register_uri(httpretty.POST, "https://my_service.com/get_endpoint", - responses=[ - httpretty.Response(body="", status=303, method='POST', location='/http/success/get/200'), - ]) - - - response = self.client.send(request) - self.assertEqual(response.status_code, 200, msg="Should redirect with GET on 303 with location header") - self.assertEqual(response.request.method, 'GET') - - self.assertEqual(response.history[0].status_code, 303) - self.assertTrue(response.history[0].is_redirect) - - httpretty.reset() - httpretty.register_uri(httpretty.POST, "https://my_service.com/get_endpoint", - responses=[ - httpretty.Response(body="", status=303, method='POST'), - ]) - - response = self.client.send(request) - self.assertEqual(response.status_code, 303, msg="Should not redirect on 303 without location header") - self.assertEqual(response.history, []) - self.assertFalse(response.is_redirect) - - @httpretty.activate - def test_request_redirect_head(self): - - url = self.client.format_url("/get_endpoint") - request = self.client.head(url, {'check':True}) - - httpretty.register_uri(httpretty.HEAD, 'https://my_service.com/http/success/200', status=200) - httpretty.register_uri(httpretty.HEAD, "https://my_service.com/get_endpoint", - responses=[ - httpretty.Response(body="", status=307, method='HEAD', location='/http/success/200'), - ]) - - - response = self.client.send(request) - self.assertEqual(response.status_code, 200, msg="Should redirect on 307 with location header") - self.assertEqual(response.request.method, 'HEAD') - - self.assertEqual(response.history[0].status_code, 307) - self.assertTrue(response.history[0].is_redirect) - - httpretty.reset() - httpretty.register_uri(httpretty.HEAD, "https://my_service.com/get_endpoint", - responses=[ - httpretty.Response(body="", status=307, method='HEAD'), - ]) - - response = self.client.send(request) - self.assertEqual(response.status_code, 307, msg="Should not redirect on 307 without location header") - self.assertEqual(response.history, []) - self.assertFalse(response.is_redirect) - - @httpretty.activate - def test_request_redirect_delete(self): - - url = self.client.format_url("/get_endpoint") - request = self.client.delete(url, {'check':True}) - - httpretty.register_uri(httpretty.DELETE, 'https://my_service.com/http/success/200', status=200) - httpretty.register_uri(httpretty.DELETE, "https://my_service.com/get_endpoint", - responses=[ - httpretty.Response(body="", status=307, method='DELETE', location='/http/success/200'), - ]) - - - response = self.client.send(request) - self.assertEqual(response.status_code, 200, msg="Should redirect on 307 with location header") - self.assertEqual(response.request.method, 'DELETE') - - self.assertEqual(response.history[0].status_code, 307) - self.assertTrue(response.history[0].is_redirect) - - httpretty.reset() - httpretty.register_uri(httpretty.DELETE, "https://my_service.com/get_endpoint", - responses=[ - httpretty.Response(body="", status=307, method='DELETE'), - ]) - - response = self.client.send(request) - self.assertEqual(response.status_code, 307, msg="Should not redirect on 307 without location header") - self.assertEqual(response.history, []) - self.assertFalse(response.is_redirect) - - @httpretty.activate - def test_request_redirect_put(self): - - url = self.client.format_url("/get_endpoint") - request = self.client.put(url, {'check':True}) - - httpretty.register_uri(httpretty.PUT, "https://my_service.com/get_endpoint", - responses=[ - httpretty.Response(body="", status=305, method='PUT', location='/http/success/200'), - ]) - - response = self.client.send(request) - self.assertEqual(response.status_code, 305, msg="Should not redirect on 305") - self.assertEqual(response.history, []) - self.assertFalse(response.is_redirect) - - @httpretty.activate - def test_request_redirect_get(self): - - url = self.client.format_url("/get_endpoint") - request = self.client.get(url, {'check':True}) - - httpretty.register_uri(httpretty.GET, "https://my_service.com/http/finished", - responses=[ - httpretty.Response(body="", status=200, method='GET'), - ]) - - httpretty.register_uri(httpretty.GET, "https://my_service.com/http/redirect3", - responses=[ - httpretty.Response(body="", status=307, method='GET', location='/http/finished'), - ]) - - httpretty.register_uri(httpretty.GET, "https://my_service.com/http/redirect2", - responses=[ - httpretty.Response(body="", status=307, method='GET', location='/http/redirect3'), - ]) - - httpretty.register_uri(httpretty.GET, "https://my_service.com/http/redirect1", - responses=[ - httpretty.Response(body="", status=307, method='GET', location='/http/redirect2'), - ]) - - httpretty.register_uri(httpretty.GET, "https://my_service.com/get_endpoint", - responses=[ - httpretty.Response(body="", status=307, method='GET', location='/http/redirect1'), - ]) - - with self.assertRaises(ClientRequestError, msg="Should exceed maximum redirects"): - response = self.client.send(request) - - - -class TestRuntimeRetry(unittest.TestCase): - - def setUp(self): - cfg = Configuration("https://my_service.com") - cfg.retry_policy.backoff_factor=0 - creds = Authentication() - - self.client = ServiceClient(creds, cfg) - url = self.client.format_url("/get_endpoint") - self.request = self.client.get(url, {'check':True}) - return super(TestRuntimeRetry, self).setUp() - - @httpretty.activate - def test_request_retry_502(self): - - httpretty.register_uri(httpretty.GET, "https://my_service.com/get_endpoint", - responses=[ - httpretty.Response(body="retry response", status=502), - httpretty.Response(body='success response', status=202), - ]) - - - response = self.client.send(self.request) - self.assertEqual(response.status_code, 202, msg="Should retry on 502") - - @httpretty.activate - def test_request_retry_408(self): - httpretty.register_uri(httpretty.GET, "https://my_service.com/get_endpoint", - responses=[ - httpretty.Response(body="retry response", status=408), - httpretty.Response(body='success response', status=202), - ]) - response = self.client.send(self.request) - self.assertEqual(response.status_code, 202, msg="Should retry on 408") - - @httpretty.activate - def test_request_retry_3_times(self): - httpretty.register_uri(httpretty.GET, "https://my_service.com/get_endpoint", - responses=[ - httpretty.Response(body="retry response", status=502), - httpretty.Response(body="retry response", status=502), - httpretty.Response(body="retry response", status=502), - httpretty.Response(body='success response', status=202), - ]) - - response = self.client.send(self.request) - self.assertEqual(response.status_code, 202, msg="Should retry 3 times") - - @httpretty.activate - def test_request_retry_max(self): - httpretty.register_uri(httpretty.GET, "https://my_service.com/get_endpoint", - responses=[ - httpretty.Response(body="retry response", status=502), - httpretty.Response(body="retry response", status=502), - httpretty.Response(body="retry response", status=502), - httpretty.Response(body="retry response", status=502), - ]) - - with self.assertRaises(ClientRequestError, msg="Max retries reached"): - response = self.client.send(self.request) - - @httpretty.activate - def test_request_retry_404(self): - httpretty.register_uri(httpretty.GET, "https://my_service.com/get_endpoint", - responses=[ - httpretty.Response(body="retry response", status=404), - httpretty.Response(body='success response', status=202), - ]) - - response = self.client.send(self.request) - self.assertEqual(response.status_code, 404, msg="Shouldn't retry on 404") - - @httpretty.activate - def test_request_retry_501(self): - httpretty.register_uri(httpretty.GET, "https://my_service.com/get_endpoint", - responses=[ - httpretty.Response(body="retry response", status=501), - httpretty.Response(body='success response', status=202), - ]) - - response = self.client.send(self.request) - self.assertEqual(response.status_code, 501, msg="Shouldn't retry on 501") - - @httpretty.activate - def test_request_retry_505(self): - httpretty.register_uri(httpretty.GET, "https://my_service.com/get_endpoint", - responses=[ - httpretty.Response(body="retry response", status=505), - httpretty.Response(body='success response', status=202), - ]) - - response = self.client.send(self.request) - self.assertEqual(response.status_code, 505, msg="Shouldn't retry on 505") - - -if __name__ == '__main__': - unittest.main() \ No newline at end of file diff --git a/src/client/Python/msrest/test/unittest_serialization.py b/src/client/Python/msrest/test/unittest_serialization.py deleted file mode 100644 index 166a375925..0000000000 --- a/src/client/Python/msrest/test/unittest_serialization.py +++ /dev/null @@ -1,1192 +0,0 @@ -#-------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -#-------------------------------------------------------------------------- - -import sys -import json -import isodate -import logging -from datetime import datetime -import unittest -try: - from unittest import mock -except ImportError: - import mock - -from requests import Response - -from msrest.serialization import Model -from msrest import Serializer, Deserializer -from msrest.exceptions import SerializationError, DeserializationError, ValidationError - - -class Resource(Model): - """Resource - - :param str id: Resource Id - :param str name: Resource name - :param str type: Resource type - :param str location: Resource location - :param dict tags: Resource tags - """ - - _validation = { - 'location': {'required': True}, - } - - _attribute_map = { - 'id': {'key': 'id', 'type': 'str'}, - 'name': {'key': 'name', 'type': 'str'}, - 'type': {'key': 'type', 'type': 'str'}, - 'location': {'key': 'location', 'type': 'str'}, - 'tags': {'key': 'tags', 'type': '{str}'}, - } - - def __init__(self, location, id=None, name=None, type=None, tags=None, **kwargs): - self.id = id - self.name = name - self.type = type - self.location = location - self.tags = tags - - super(Resource, self).__init__(**kwargs) - -class GenericResource(Resource): - """ - Resource information. - - :param str id: Resource Id - :param str name: Resource name - :param str type: Resource type - :param str location: Resource location - :param dict tags: Resource tags - :param Plan plan: Gets or sets the plan of the resource. - :param object properties: Gets or sets the resource properties. - """ - - _validation = {} - - _attribute_map = { - 'id': {'key': 'id', 'type': 'str'}, - 'name': {'key': 'name', 'type': 'str'}, - 'type': {'key': 'type', 'type': 'str'}, - 'location': {'key': 'location', 'type': 'str'}, - 'tags': {'key': 'tags', 'type': '{str}'}, - 'plan': {'key': 'plan', 'type': 'Plan'}, - 'properties': {'key': 'properties', 'type': 'object'}, - } - - def __init__(self, location, id=None, name=None, type=None, tags=None, plan=None, properties=None, **kwargs): - self.plan = plan - self.properties = properties - - super(GenericResource, self).__init__(location, id=id, name=name, type=type, tags=tags, **kwargs) - -class TestModelDeserialization(unittest.TestCase): - - def setUp(self): - self.d = Deserializer({'Resource':Resource, 'GenericResource':GenericResource}) - return super(TestModelDeserialization, self).setUp() - - def test_response(self): - - data = { - "properties": { - "platformUpdateDomainCount": 5, - "platformFaultDomainCount": 3, - "virtualMachines": [] - }, - "id": "/subscriptions/abc-def-ghi-jklmnop/resourceGroups/test_mgmt_resource_test_resourcesea/providers/Microsoft.Compute/availabilitySets/pytest", - "name": "pytest", - "type": "Microsoft.Compute/availabilitySets", - "location": "westus" - } - - resp = mock.create_autospec(Response) - resp.content = json.dumps(data) - model = self.d('GenericResource', resp) - self.assertEqual(model.properties['platformFaultDomainCount'], 3) - self.assertEqual(model.location, 'westus') - -class TestRuntimeSerialized(unittest.TestCase): - - class TestObj(Model): - - _validation = {} - _attribute_map = { - 'attr_a': {'key':'id', 'type':'str'}, - 'attr_b': {'key':'AttrB', 'type':'int'}, - 'attr_c': {'key':'Key_C', 'type': 'bool'}, - 'attr_d': {'key':'AttrD', 'type':'[int]'}, - 'attr_e': {'key':'AttrE', 'type': '{float}'} - } - - def __init__(self): - - self.attr_a = None - self.attr_b = None - self.attr_c = None - self.attr_d = None - self.attr_e = None - - def __str__(self): - return "Test_Object" - - def setUp(self): - self.s = Serializer() - return super(TestRuntimeSerialized, self).setUp() - - def test_obj_serialize_none(self): - """Test that serialize None in object is still None. - """ - obj = self.s.serialize_object({'test': None}) - self.assertIsNone(obj['test']) - - def test_obj_without_attr_map(self): - """ - Test serializing an object with no attribute_map. - """ - test_obj = type("BadTestObj", (), {}) - - with self.assertRaises(SerializationError): - self.s._serialize(test_obj) - - def test_obj_with_malformed_map(self): - """ - Test serializing an object with a malformed attribute_map. - """ - test_obj = type("BadTestObj", (Model,), {"_attribute_map":None}) - - with self.assertRaises(SerializationError): - self.s._serialize(test_obj) - - test_obj._attribute_map = {"attr":"val"} - - with self.assertRaises(SerializationError): - self.s._serialize(test_obj) - - test_obj._attribute_map = {"attr":{"val":1}} - - with self.assertRaises(SerializationError): - self.s._serialize(test_obj) - - def test_obj_with_mismatched_map(self): - """ - Test serializing an object with mismatching attributes and map. - """ - test_obj = type("BadTestObj", (Model,), {"_attribute_map":None}) - test_obj._attribute_map = {"abc":{"key":"ABC", "type":"str"}} - - with self.assertRaises(SerializationError): - self.s._serialize(test_obj) - - def test_attr_none(self): - """ - Test serializing an object with None attributes. - """ - test_obj = self.TestObj() - message = self.s._serialize(test_obj) - - self.assertIsInstance(message, dict) - self.assertFalse('id' in message) - - def test_attr_int(self): - """ - Test serializing an object with Int attributes. - """ - test_obj = self.TestObj() - self.TestObj._validation = { - 'attr_b': {'required': True}, - } - test_obj.attr_b = None - - with self.assertRaises(ValidationError): - self.s._serialize(test_obj) - - test_obj.attr_b = 25 - - message = self.s._serialize(test_obj) - self.assertEqual(message['AttrB'], int(test_obj.attr_b)) - - test_obj.attr_b = "34534" - - message = self.s._serialize(test_obj) - self.assertEqual(message['AttrB'], int(test_obj.attr_b)) - - test_obj.attr_b = "NotANumber" - - with self.assertRaises(SerializationError): - self.s._serialize(test_obj) - - self.TestObj._validation = {} - - def test_attr_str(self): - """ - Test serializing an object with Str attributes. - """ - test_obj = self.TestObj() - self.TestObj._validation = { - 'attr_a': {'required': True}, - } - test_obj.attr_a = None - - with self.assertRaises(ValidationError): - self.s._serialize(test_obj) - - self.TestObj._validation = {} - test_obj.attr_a = "TestString" - - message = self.s._serialize(test_obj) - self.assertEqual(message['id'], str(test_obj.attr_a)) - - test_obj.attr_a = 1234 - - message = self.s._serialize(test_obj) - self.assertEqual(message['id'], str(test_obj.attr_a)) - - test_obj.attr_a = list() - - message = self.s._serialize(test_obj) - self.assertEqual(message['id'], str(test_obj.attr_a)) - - test_obj.attr_a = [1] - - message = self.s._serialize(test_obj) - self.assertEqual(message['id'], str(test_obj.attr_a)) - - def test_attr_bool(self): - """ - Test serializing an object with bool attributes. - """ - test_obj = self.TestObj() - test_obj.attr_c = True - - message = self.s._serialize(test_obj) - self.assertEqual(message['Key_C'], True) - - test_obj.attr_c = "" - - message = self.s._serialize(test_obj) - self.assertTrue('Key_C' in message) - - test_obj.attr_c = None - - message = self.s._serialize(test_obj) - self.assertFalse('Key_C' in message) - - test_obj.attr_c = "NotEmpty" - - message = self.s._serialize(test_obj) - self.assertEqual(message['Key_C'], True) - - def test_attr_sequence(self): - """ - Test serializing a sequence. - """ - - test_obj = ["A", "B", "C"] - output = self.s._serialize(test_obj, '[str]', div='|') - self.assertEqual(output, "|".join(test_obj)) - - test_obj = [1,2,3] - output = self.s._serialize(test_obj, '[str]', div=',') - self.assertEqual(output, ",".join([str(i) for i in test_obj])) - - def test_attr_list_simple(self): - """ - Test serializing an object with simple-typed list attributes - """ - test_obj = self.TestObj() - test_obj.attr_d = [] - - message = self.s._serialize(test_obj) - self.assertEqual(message['AttrD'], test_obj.attr_d) - - test_obj.attr_d = [1,2,3] - - message = self.s._serialize(test_obj) - self.assertEqual(message['AttrD'], test_obj.attr_d) - - test_obj.attr_d = ["1","2","3"] - - message = self.s._serialize(test_obj) - self.assertEqual(message['AttrD'], [int(i) for i in test_obj.attr_d]) - - test_obj.attr_d = ["test","test2","test3"] - - with self.assertRaises(SerializationError): - self.s._serialize(test_obj) - - test_obj.attr_d = "NotAList" - - with self.assertRaises(SerializationError): - self.s._serialize(test_obj) - - def test_empty_list(self): - - input = [] - output = self.s._serialize(input, '[str]') - self.assertEqual(output, input) - - def test_attr_list_complex(self): - """ - Test serializing an object with a list of complex objects as an attribute. - """ - list_obj = type("ListObj", (Model,), {"_attribute_map":None, - "_validation":{}, - "abc":None}) - list_obj._attribute_map = {"abc":{"key":"ABC", "type":"int"}} - list_obj.abc = "123" - - test_obj = type("CmplxTestObj", (Model,), {"_attribute_map":None, - "_validation":{}, - "test_list":None}) - - test_obj._attribute_map = {"test_list":{"key":"_list", "type":"[ListObj]"}} - test_obj.test_list = [list_obj] - - message = self.s._serialize(test_obj) - self.assertEqual(message, {'_list':[{'ABC':123}]}) - - list_obj = type("BadListObj", (Model,), {"map":None}) - test_obj._attribute_map = {"test_list":{"key":"_list", "type":"[BadListObj]"}} - test_obj.test_list = [list_obj] - - s = self.s._serialize(test_obj) - self.assertEqual(s, {'_list':[{}]}) - - def test_attr_dict_simple(self): - """ - Test serializing an object with a simple dictionary attribute. - """ - - test_obj = self.TestObj() - test_obj.attr_e = {"value": 3.14} - - message = self.s._serialize(test_obj) - self.assertEqual(message['AttrE']['value'], float(test_obj.attr_e["value"])) - - test_obj.attr_e = {1: "3.14"} - - message = self.s._serialize(test_obj) - self.assertEqual(message['AttrE']['1'], float(test_obj.attr_e[1])) - - test_obj.attr_e = "NotADict" - - with self.assertRaises(SerializationError): - self.s._serialize(test_obj) - - test_obj.attr_e = {"value": "NotAFloat"} - - with self.assertRaises(SerializationError): - self.s._serialize(test_obj) - - def test_serialize_datetime(self): - - date_obj = isodate.parse_datetime('2015-01-01T00:00:00') - date_str = Serializer.serialize_iso(date_obj) - - self.assertEqual(date_str, '2015-01-01T00:00:00.000Z') - - date_obj = isodate.parse_datetime('1999-12-31T23:59:59-12:00') - date_str = Serializer.serialize_iso(date_obj) - - self.assertEqual(date_str, '2000-01-01T11:59:59.000Z') - - with self.assertRaises(SerializationError): - date_obj = isodate.parse_datetime('9999-12-31T23:59:59-12:00') - date_str = Serializer.serialize_iso(date_obj) - - with self.assertRaises(SerializationError): - date_obj = isodate.parse_datetime('0001-01-01T00:00:00+23:59') - date_str = Serializer.serialize_iso(date_obj) - - - date_obj = isodate.parse_datetime("2015-06-01T16:10:08.0121-07:00") - date_str = Serializer.serialize_iso(date_obj) - - self.assertEqual(date_str, '2015-06-01T23:10:08.0121Z') - - date_obj = datetime.min - date_str = Serializer.serialize_iso(date_obj) - self.assertEqual(date_str, '0001-01-01T00:00:00.000Z') - - date_obj = datetime.max - date_str = Serializer.serialize_iso(date_obj) - self.assertEqual(date_str, '9999-12-31T23:59:59.999999Z') - - - def test_serialize_primitive_types(self): - - a = self.s.serialize_data(1, 'int') - self.assertEqual(a, 1) - - b = self.s.serialize_data(True, 'bool') - self.assertEqual(b, True) - - c = self.s.serialize_data('True', 'str') - self.assertEqual(c, 'True') - - d = self.s.serialize_data(100.0123, 'float') - self.assertEqual(d, 100.0123) - - def test_serialize_object(self): - - a = self.s.body(1, 'object') - self.assertEqual(a, 1) - - b = self.s.body(True, 'object') - self.assertEqual(b, True) - - c = self.s.serialize_data('True', 'object') - self.assertEqual(c, 'True') - - d = self.s.serialize_data(100.0123, 'object') - self.assertEqual(d, 100.0123) - - e = self.s.serialize_data({}, 'object') - self.assertEqual(e, {}) - - f = self.s.body({"test":"data"}, 'object') - self.assertEqual(f, {"test":"data"}) - - g = self.s.body({"test":{"value":"data"}}, 'object') - self.assertEqual(g, {"test":{"value":"data"}}) - - h = self.s.serialize_data({"test":self.TestObj()}, 'object') - self.assertEqual(h, {"test":"Test_Object"}) - - i = self.s.serialize_data({"test":[1,2,3,4,5]}, 'object') - self.assertEqual(i, {"test":[1,2,3,4,5]}) - - def test_serialize_empty_iter(self): - - a = self.s.serialize_dict({}, 'int') - self.assertEqual(a, {}) - - b = self.s.serialize_iter([], 'int') - self.assertEqual(b, []) - - def test_serialize_json_obj(self): - - class ComplexId(Model): - - _validation = {} - _attribute_map = {'id':{'key':'id','type':'int'}, - 'name':{'key':'name','type':'str'}, - 'age':{'key':'age','type':'float'}, - 'male':{'key':'male','type':'bool'}, - 'birthday':{'key':'birthday','type':'iso-8601'}, - 'anniversary':{'key':'anniversary', 'type':'iso-8601'}} - - id = 1 - name = "Joey" - age = 23.36 - male = True - birthday = '1992-01-01T00:00:00.000Z' - anniversary = isodate.parse_datetime('2013-12-08T00:00:00') - - class ComplexJson(Model): - - _validation = {} - _attribute_map = {'p1':{'key':'p1','type':'str'}, - 'p2':{'key':'p2','type':'str'}, - 'top_date':{'key':'top_date', 'type':'iso-8601'}, - 'top_dates':{'key':'top_dates', 'type':'[iso-8601]'}, - 'insider':{'key':'insider','type':'{iso-8601}'}, - 'top_complex':{'key':'top_complex','type':'ComplexId'}} - - p1 = 'value1' - p2 = 'value2' - top_date = isodate.parse_datetime('2014-01-01T00:00:00') - top_dates = [isodate.parse_datetime('1900-01-01T00:00:00'), isodate.parse_datetime('1901-01-01T00:00:00')] - insider = { - 'k1': isodate.parse_datetime('2015-01-01T00:00:00'), - 'k2': isodate.parse_datetime('2016-01-01T00:00:00'), - 'k3': isodate.parse_datetime('2017-01-01T00:00:00')} - top_complex = ComplexId() - - message =self.s._serialize(ComplexJson()) - - output = { - 'p1': 'value1', - 'p2': 'value2', - 'top_date': '2014-01-01T00:00:00.000Z', - 'top_dates': [ - '1900-01-01T00:00:00.000Z', - '1901-01-01T00:00:00.000Z' - ], - 'insider': { - 'k1': '2015-01-01T00:00:00.000Z', - 'k2': '2016-01-01T00:00:00.000Z', - 'k3': '2017-01-01T00:00:00.000Z' - }, - 'top_complex': { - 'id': 1, - 'name': 'Joey', - 'age': 23.36, - 'male': True, - 'birthday': '1992-01-01T00:00:00.000Z', - 'anniversary': '2013-12-08T00:00:00.000Z', - } - } - self.maxDiff = None - self.assertEqual(message, output) - - def test_polymorphic_serialization(self): - - self.maxDiff = None - class Zoo(Model): - - _attribute_map = { - "animals":{"key":"Animals", "type":"[Animal]"}, - } - - def __init__(self): - self.animals = None - - class Animal(Model): - - _attribute_map = { - "name":{"key":"Name", "type":"str"} - } - - _subtype_map = { - 'dType': {"cat":"Cat", "dog":"Dog"} - } - - def __init__(self): - self.name = None - - class Dog(Animal): - - _attribute_map = { - "name":{"key":"Name", "type":"str"}, - "likes_dog_food":{"key":"likesDogFood","type":"bool"} - } - - def __init__(self): - self.likes_dog_food = None - super(Dog, self).__init__() - - class Cat(Animal): - - _attribute_map = { - "name":{"key":"Name", "type":"str"}, - "likes_mice":{"key":"likesMice","type":"bool"}, - "dislikes":{"key":"dislikes","type":"Animal"} - } - - _subtype_map = { - "dType":{"siamese":"Siamese"} - } - - def __init__(self): - self.likes_mice = None - self.dislikes = None - super(Cat, self).__init__() - - class Siamese(Cat): - - _attribute_map = { - "name":{"key":"Name", "type":"str"}, - "likes_mice":{"key":"likesMice","type":"bool"}, - "dislikes":{"key":"dislikes","type":"Animal"}, - "color":{"key":"Color", "type":"str"} - } - - def __init__(self): - self.color = None - super(Siamese, self).__init__() - - message = { - "Animals": [ - { - "dType": "dog", - "likesDogFood": True, - "Name": "Fido" - }, - { - "dType": "cat", - "likesMice": False, - "dislikes": { - "dType": "dog", - "likesDogFood": True, - "Name": "Angry" - }, - "Name": "Felix" - }, - { - "dType": "siamese", - "Color": "grey", - "likesMice": True, - "Name": "Finch" - }]} - - zoo = Zoo() - angry = Dog() - angry.name = "Angry" - angry.likes_dog_food = True - - fido = Dog() - fido.name = "Fido" - fido.likes_dog_food = True - - felix = Cat() - felix.name = "Felix" - felix.likes_mice = False - felix.dislikes = angry - - finch = Siamese() - finch.name = "Finch" - finch.color = "grey" - finch.likes_mice = True - - zoo.animals = [fido, felix, finch] - - serialized = self.s._serialize(zoo) - self.assertEqual(serialized, message) - - -class TestRuntimeDeserialized(unittest.TestCase): - - class TestObj(Model): - - _validation = {} - _attribute_map = { - 'attr_a': {'key':'id', 'type':'str'}, - 'attr_b': {'key':'AttrB', 'type':'int'}, - 'attr_c': {'key':'Key_C', 'type': 'bool'}, - 'attr_d': {'key':'AttrD', 'type':'[int]'}, - 'attr_e': {'key':'AttrE', 'type': '{float}'}, - 'attr_f': {'key':'AttrF', 'type': '[[str]]'} - } - - _header_map = { - 'client_request_id': {'key': 'client-request-id', 'type':'str'}, - 'e_tag': {'key': 'etag', 'type':'str'}, - } - - _response_map = { - 'status_code': {'key':'status_code', 'type':'str'} - } - - - def setUp(self): - self.d = Deserializer() - return super(TestRuntimeDeserialized, self).setUp() - - def test_non_obj_deserialization(self): - """ - Test direct deserialization of simple types. - """ - response_data = mock.create_autospec(Response) - - response_data.content = json.dumps({}) - response = self.d("[str]", response_data) - self.assertIsNone(response) - - response_data.content = "" - response = self.d("[str]", response_data) - self.assertIsNone(response) - - response_data.content = None - response = self.d("[str]", response_data) - self.assertIsNone(response) - - message = ["a","b","b"] - response_data.content = json.dumps(message) - response = self.d("[str]", response_data) - self.assertEqual(response, message) - - response_data.content = json.dumps(12345) - with self.assertRaises(DeserializationError): - response = self.d("[str]", response_data) - - response_data.content = True - response = self.d('bool', response_data) - self.assertEqual(response, True) - - response_data.content = json.dumps(1) - response = self.d('bool', response_data) - self.assertEqual(response, True) - - response_data.content = json.dumps("true1") - with self.assertRaises(DeserializationError): - response = self.d('bool', response_data) - - - def test_obj_with_no_attr(self): - """ - Test deserializing an object with no attributes. - """ - - response_data = mock.create_autospec(Response) - response_data.content = json.dumps({"a":"b"}) - - class EmptyResponse(Model): - _attribute_map = {} - _header_map = {} - - - derserialized = self.d(EmptyResponse, response_data) - self.assertIsInstance(derserialized, EmptyResponse) - - def test_obj_with_malformed_map(self): - """ - Test deserializing an object with a malformed attributes_map. - """ - response_data = mock.create_autospec(Response) - response_data.content = json.dumps({"a":"b"}) - - class BadResponse(Model): - _attribute_map = None - - def __init__(*args, **kwargs): - pass - - with self.assertRaises(DeserializationError): - self.d(BadResponse, response_data) - - class BadResponse(Model): - _attribute_map = {"attr":"val"} - - def __init__(*args, **kwargs): - pass - - with self.assertRaises(DeserializationError): - self.d(BadResponse, response_data) - - class BadResponse(Model): - _attribute_map = {"attr":{"val":1}} - - def __init__(*args, **kwargs): - pass - - with self.assertRaises(DeserializationError): - self.d(BadResponse, response_data) - - def test_attr_none(self): - """ - Test serializing an object with None attributes. - """ - response_data = mock.create_autospec(Response) - - with self.assertRaises(DeserializationError): - self.d(self.TestObj, response_data) - - response_data.status_code = None - response_data.headers = {'client-request-id':None, 'etag':None} - response_data.content = None - - response = self.d(self.TestObj, response_data) - self.assertIsNone(response) - - def test_attr_int(self): - """ - Test deserializing an object with Int attributes. - """ - response_data = mock.create_autospec(Response) - response_data.status_code = 200 - response_data.headers = {'client-request-id':"123", 'etag':456.3} - response_data.content = None - - response = self.d(self.TestObj, response_data) - self.assertIsNone(response) - - message = {'AttrB':'1234'} - response_data.content = json.dumps(message) - response = self.d(self.TestObj, response_data) - self.assertTrue(hasattr(response, 'attr_b')) - self.assertEqual(response.attr_b, int(message['AttrB'])) - - with self.assertRaises(DeserializationError): - response_data.content = json.dumps({'AttrB':'NotANumber'}) - response = self.d(self.TestObj, response_data) - - def test_attr_str(self): - """ - Test deserializing an object with Str attributes. - """ - message = {'id':'InterestingValue'} - response_data = mock.create_autospec(Response) - response_data.status_code = 200 - response_data.headers = {'client-request-id': 'a', 'etag': 'b'} - response_data.content = json.dumps(message) - - response = self.d(self.TestObj, response_data) - self.assertTrue(hasattr(response, 'attr_a')) - self.assertEqual(response.attr_a, message['id']) - - message = {'id':1234} - response_data.content = json.dumps(message) - response = self.d(self.TestObj, response_data) - self.assertEqual(response.attr_a, str(message['id'])) - - message = {'id':list()} - response_data.content = json.dumps(message) - response = self.d(self.TestObj, response_data) - self.assertEqual(response.attr_a, str(message['id'])) - - response_data.content = json.dumps({'id':None}) - response = self.d(self.TestObj, response_data) - self.assertEqual(response.attr_a, None) - - def test_attr_bool(self): - """ - Test deserializing an object with bool attributes. - """ - response_data = mock.create_autospec(Response) - response_data.status_code = 200 - response_data.headers = {'client-request-id': 'a', 'etag': 'b'} - response_data.content = json.dumps({'Key_C':True}) - - response = self.d(self.TestObj, response_data) - - self.assertTrue(hasattr(response, 'attr_c')) - self.assertEqual(response.attr_c, True) - - response_data.content = json.dumps({'Key_C':[]}) - with self.assertRaises(DeserializationError): - response = self.d(self.TestObj, response_data) - - response_data.content = json.dumps({'Key_C':0}) - response = self.d(self.TestObj, response_data) - self.assertEqual(response.attr_c, False) - - response_data.content = json.dumps({'Key_C':"value"}) - with self.assertRaises(DeserializationError): - response = self.d(self.TestObj, response_data) - - def test_attr_list_simple(self): - """ - Test deserializing an object with simple-typed list attributes - """ - response_data = mock.create_autospec(Response) - response_data.status_code = 200 - response_data.headers = {'client-request-id': 'a', 'etag': 'b'} - response_data.content = json.dumps({'AttrD': []}) - - response = self.d(self.TestObj, response_data) - deserialized_list = [d for d in response.attr_d] - self.assertEqual(deserialized_list, []) - - message = {'AttrD': [1,2,3]} - response_data.content = json.dumps(message) - response = self.d(self.TestObj, response_data) - deserialized_list = [d for d in response.attr_d] - self.assertEqual(deserialized_list, message['AttrD']) - - message = {'AttrD': ["1","2","3"]} - response_data.content = json.dumps(message) - response = self.d(self.TestObj, response_data) - deserialized_list = [d for d in response.attr_d] - self.assertEqual(deserialized_list, [int(i) for i in message['AttrD']]) - - response_data.content = json.dumps({'AttrD': ["test","test2","test3"]}) - with self.assertRaises(DeserializationError): - response = self.d(self.TestObj, response_data) - deserialized_list = [d for d in response.attr_d] - - response_data.content = json.dumps({'AttrD': "NotAList"}) - with self.assertRaises(DeserializationError): - response = self.d(self.TestObj, response_data) - deserialized_list = [d for d in response.attr_d] - - def test_attr_list_in_list(self): - """ - Test deserializing a list of lists - """ - response_data = mock.create_autospec(Response) - response_data.status_code = 200 - response_data.headers = {'client-request-id': 'a', 'etag': 'b'} - response_data.content = json.dumps({'AttrF':[]}) - - response = self.d(self.TestObj, response_data) - self.assertTrue(hasattr(response, 'attr_f')) - self.assertEqual(response.attr_f, []) - - response_data.content = json.dumps({'AttrF':None}) - - response = self.d(self.TestObj, response_data) - self.assertTrue(hasattr(response, 'attr_f')) - self.assertEqual(response.attr_f, None) - - response_data.content = json.dumps({}) - - response = self.d(self.TestObj, response_data) - - self.assertTrue(hasattr(response, 'attr_f')) - self.assertEqual(response.attr_f, None) - - message = {'AttrF':[[]]} - response_data.content = json.dumps(message) - - response = self.d(self.TestObj, response_data) - self.assertTrue(hasattr(response, 'attr_f')) - self.assertEqual(response.attr_f, message['AttrF']) - - message = {'AttrF':[[1,2,3], ['a','b','c']]} - response_data.content = json.dumps(message) - - response = self.d(self.TestObj, response_data) - self.assertTrue(hasattr(response, 'attr_f')) - self.assertEqual(response.attr_f, [[str(i) for i in k] for k in message['AttrF']]) - - with self.assertRaises(DeserializationError): - response_data.content = json.dumps({'AttrF':[1,2,3]}) - response = self.d(self.TestObj, response_data) - - def test_attr_list_complex(self): - """ - Test deserializing an object with a list of complex objects as an attribute. - """ - class ListObj(Model): - _attribute_map = {"abc":{"key":"ABC", "type":"int"}} - - class CmplxTestObj(Model): - _response_map = {} - _attribute_map = {'attr_a': {'key':'id', 'type':'[ListObj]'}} - - - response_data = mock.create_autospec(Response) - response_data.status_code = 200 - response_data.headers = {'client-request-id': 'a', 'etag': 'b'} - response_data.content = json.dumps({"id":[{"ABC": "123"}]}) - - d = Deserializer({'ListObj':ListObj}) - response = d(CmplxTestObj, response_data) - deserialized_list = list(response.attr_a) - - self.assertIsInstance(deserialized_list[0], ListObj) - self.assertEqual(deserialized_list[0].abc, 123) - - def test_deserialize_object(self): - - a = self.d('object', 1) - self.assertEqual(a, 1) - - b = self.d('object', True) - self.assertEqual(b, True) - - c = self.d('object', 'True') - self.assertEqual(c, 'True') - - d = self.d('object', 100.0123) - self.assertEqual(d, 100.0123) - - e = self.d('object', {}) - self.assertEqual(e, {}) - - f = self.d('object', {"test":"data"}) - self.assertEqual(f, {"test":"data"}) - - g = self.d('object', {"test":{"value":"data"}}) - self.assertEqual(g, {"test":{"value":"data"}}) - - with self.assertRaises(DeserializationError): - self.d('object', {"test":self.TestObj()}) - - h = self.d('object', {"test":[1,2,3,4,5]}) - self.assertEqual(h, {"test":[1,2,3,4,5]}) - - def test_deserialize_datetime(self): - - a = Deserializer.deserialize_iso('9999-12-31T23:59:59+23:59') - utc = a.utctimetuple() - - self.assertEqual(utc.tm_year, 9999) - self.assertEqual(utc.tm_mon, 12) - self.assertEqual(utc.tm_mday, 31) - self.assertEqual(utc.tm_hour, 0) - self.assertEqual(utc.tm_min, 0) - self.assertEqual(utc.tm_sec, 59) - self.assertEqual(a.microsecond, 0) - - with self.assertRaises(DeserializationError): - a = Deserializer.deserialize_iso('9999-12-31T23:59:59-23:59') - - a = Deserializer.deserialize_iso('1999-12-31T23:59:59-23:59') - utc = a.utctimetuple() - self.assertEqual(utc.tm_year, 2000) - self.assertEqual(utc.tm_mon, 1) - self.assertEqual(utc.tm_mday, 1) - self.assertEqual(utc.tm_hour, 23) - self.assertEqual(utc.tm_min, 58) - self.assertEqual(utc.tm_sec, 59) - self.assertEqual(a.microsecond, 0) - - a = Deserializer.deserialize_iso('0001-01-01T23:59:00+23:59') - utc = a.utctimetuple() - - self.assertEqual(utc.tm_year, 1) - self.assertEqual(utc.tm_mon, 1) - self.assertEqual(utc.tm_mday, 1) - self.assertEqual(utc.tm_hour, 0) - self.assertEqual(utc.tm_min, 0) - self.assertEqual(utc.tm_sec, 0) - self.assertEqual(a.microsecond, 0) - - #with self.assertRaises(DeserializationError): - # a = Deserializer.deserialize_iso('1996-01-01T23:01:54-22:66') #TODO - - with self.assertRaises(DeserializationError): - a = Deserializer.deserialize_iso('1996-01-01T23:01:54-24:30') - - with self.assertRaises(DeserializationError): - a = Deserializer.deserialize_iso('1996-01-01T23:01:78+00:30') - - with self.assertRaises(DeserializationError): - a = Deserializer.deserialize_iso('1996-01-01T23:60:01+00:30') - - with self.assertRaises(DeserializationError): - a = Deserializer.deserialize_iso('1996-01-01T24:01:01+00:30') - - #with self.assertRaises(DeserializationError): - # a = Deserializer.deserialize_iso('1996-01-01t01:01:01/00:30') #TODO - - with self.assertRaises(DeserializationError): - a = Deserializer.deserialize_iso('1996-01-01F01:01:01+00:30') - - with self.assertRaises(DeserializationError): - a = Deserializer.deserialize_iso('2015-02-32') - - with self.assertRaises(DeserializationError): - a = Deserializer.deserialize_iso('2015-22-01') - - with self.assertRaises(DeserializationError): - a = Deserializer.deserialize_iso('2010-13-31') - - with self.assertRaises(DeserializationError): - a = Deserializer.deserialize_iso('99999-12-31') - - with self.assertRaises(DeserializationError): - a = Deserializer.deserialize_iso(True) - - with self.assertRaises(DeserializationError): - a = Deserializer.deserialize_iso(2010) - - with self.assertRaises(DeserializationError): - a = Deserializer.deserialize_iso(None) - - with self.assertRaises(DeserializationError): - a = Deserializer.deserialize_iso('Happy New Year 2016') - - def test_polymorphic_deserialization(self): - - class Zoo(Model): - - _attribute_map = { - "animals":{"key":"Animals", "type":"[Animal]"}, - } - - class Animal(Model): - - _attribute_map = { - "name":{"key":"Name", "type":"str"} - } - - _test_attr = 123 - - _subtype_map = { - 'dType': {"cat":"Cat", "dog":"Dog"} - } - - class Dog(Animal): - - _attribute_map = { - "name":{"key":"Name", "type":"str"}, - "likes_dog_food":{"key":"likesDogFood","type":"bool"} - } - - class Cat(Animal): - - _attribute_map = { - "name":{"key":"Name", "type":"str"}, - "likes_mice":{"key":"likesMice","type":"bool"}, - "dislikes":{"key":"dislikes","type":"Animal"} - } - - _subtype_map = { - "dType":{"siamese":"Siamese"} - } - - class Siamese(Cat): - - _attribute_map = { - "name":{"key":"Name", "type":"str"}, - "likes_mice":{"key":"likesMice","type":"bool"}, - "dislikes":{"key":"dislikes","type":"Animal"}, - "color":{"key":"Color", "type":"str"} - } - - message = { - "Animals": [ - { - "dType": "dog", - "likesDogFood": True, - "Name": "Fido" - }, - { - "dType": "cat", - "likesMice": False, - "dislikes": { - "dType": "dog", - "likesDogFood": True, - "Name": "Angry" - }, - "Name": "Felix" - }, - { - "dType": "siamese", - "Color": "grey", - "likesMice": True, - "Name": "Finch" - }]} - - self.d.dependencies = { - 'Zoo':Zoo, 'Animal':Animal, 'Dog':Dog, - 'Cat':Cat, 'Siamese':Siamese} - - zoo = self.d(Zoo, message) - animals = [a for a in zoo.animals] - - self.assertEqual(len(animals), 3) - self.assertIsInstance(animals[0], Dog) - self.assertTrue(animals[0].likes_dog_food) - self.assertEqual(animals[0].name, message['Animals'][0]["Name"]) - - self.assertIsInstance(animals[1], Cat) - self.assertFalse(animals[1].likes_mice) - self.assertIsInstance(animals[1].dislikes, Dog) - self.assertEqual(animals[1].dislikes.name, message['Animals'][1]["dislikes"]["Name"]) - self.assertEqual(animals[1].name, message['Animals'][1]["Name"]) - - self.assertIsInstance(animals[2], Siamese) - self.assertEqual(animals[2].color, message['Animals'][2]["Color"]) - self.assertTrue(animals[2].likes_mice) - -if __name__ == '__main__': - unittest.main() diff --git a/src/client/Python/msrest/tox.ini b/src/client/Python/msrest/tox.ini deleted file mode 100644 index 2a127577c4..0000000000 --- a/src/client/Python/msrest/tox.ini +++ /dev/null @@ -1,34 +0,0 @@ -[tox] -envlist=py27, py35 -skipsdist=True - -[testenv] -changedir=test -commands= - coverage run -m unittest discover -s . -p unittest*.py -t .. -v - coverage report --fail-under=40 --omit=unittest*,*.tox*.py - #flake8 .. --exclude=unittest*.py,doc,env --statistics - -[testenv:py27] -deps= - -rrequirements27.txt - coverage - flake8 - -[testenv:py33] -deps= - -rrequirements27.txt - coverage - flake8 - -[testenv:py34] -deps= - -rrequirements35.txt - coverage - flake8 - -[testenv:py35] -deps= - -rrequirements35.txt - coverage - flake8 diff --git a/src/client/Python/msrest_build.sh b/src/client/Python/msrest_build.sh deleted file mode 100644 index 36564a7ad4..0000000000 --- a/src/client/Python/msrest_build.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -pushd msrest -rm -rf dist -python3 ./setup.py sdist --formats=zip -python3 ./setup.py bdist_wheel -python2 ./setup.py bdist_wheel -popd - -pushd msrestazure -rm -rf dist -python3 ./setup.py sdist --formats=zip -python3 ./setup.py bdist_wheel -python2 ./setup.py bdist_wheel -popd diff --git a/src/client/Python/msrestazure/MANIFEST.in b/src/client/Python/msrestazure/MANIFEST.in deleted file mode 100644 index f3eb9637aa..0000000000 --- a/src/client/Python/msrestazure/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -include *.rst \ No newline at end of file diff --git a/src/client/Python/msrestazure/doc/conf.py b/src/client/Python/msrestazure/doc/conf.py deleted file mode 100644 index 2b439c8548..0000000000 --- a/src/client/Python/msrestazure/doc/conf.py +++ /dev/null @@ -1,239 +0,0 @@ -# -*- coding: utf-8 -*- -# -# azure-sdk-for-python documentation build configuration file, created by -# sphinx-quickstart on Fri Jun 27 15:42:45 2014. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys -import os -import pip - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.abspath('../')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinx.ext.doctest', - 'sphinx.ext.viewcode', 'sphinx.ext.intersphinx'] - -intersphinx_mapping = { - 'python': ('https://docs.python.org/3.5', None), - 'msrest': ('http://msrest.readthedocs.org/en/latest/', None) -} - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'msrestazure' -copyright = u'2016, Microsoft' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '0.4.4' -# The full version, including alpha/beta/rc tags. -release = '0.4.4' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False - -# -- Options for extensions ---------------------------------------------------- -autoclass_content = 'both' - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -#html_theme = 'default' -#html_theme_options = {'collapsiblesidebar': True} - -# Activate the theme. -#pip.main(['install', 'sphinx_bootstrap_theme']) -#import sphinx_bootstrap_theme -#html_theme = 'bootstrap' -#html_theme_path = sphinx_bootstrap_theme.get_html_theme_path() - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -# html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'msrestazure-doc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'msrestazure.tex', u'msrest Documentation', - u'Microsoft', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - diff --git a/src/client/Python/msrestazure/doc/index.rst b/src/client/Python/msrestazure/doc/index.rst deleted file mode 100644 index 3e7d12f426..0000000000 --- a/src/client/Python/msrestazure/doc/index.rst +++ /dev/null @@ -1,64 +0,0 @@ -msrestazure -=========== - -Installation: -------------- - -From Pypi - - pip install msrestazure - -System Requirements: --------------------- - -The supported Python versions are 2.7.x, 3.3.x, 3.4.x, and 3.5.x -To download Python, please visit -https://www.python.org/download/ - - -We recommend Python Tools for Visual Studio as a development environment for developing your applications. Please visit http://aka.ms/python for more information. - - -Need Help?: ------------ - -Be sure to check out the Microsoft Azure `Developer Forums on Stack -Overflow `__ if you have -trouble with the provided code. - -Contributing: -------------- -Contribute Code or Provide Feedback: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you would like to become an active contributor to this project please -follow the instructions provided in `Microsoft Azure Projects -Contribution -Guidelines `__. - -If you encounter any bugs with the library please file an issue in the -`Issues `__ -section of the project. - -Learn More -========== - -`Microsoft Azure Python Developer -Center `__ - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - -.. toctree:: - :hidden: - -.. toctree:: - :hidden: - :glob: - - msrestazure diff --git a/src/client/Python/msrestazure/doc/make.bat b/src/client/Python/msrestazure/doc/make.bat deleted file mode 100644 index e99e578d5c..0000000000 --- a/src/client/Python/msrestazure/doc/make.bat +++ /dev/null @@ -1,242 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=_build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . -set I18NSPHINXOPTS=%SPHINXOPTS% . -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% - set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. texinfo to make Texinfo files - echo. gettext to make PO message catalogs - echo. changes to make an overview over all changed/added/deprecated items - echo. xml to make Docutils-native XML files - echo. pseudoxml to make pseudoxml-XML files for display purposes - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - - -%SPHINXBUILD% 2> nul -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\pydocumentdb.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\pydocumentdb.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdf" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf - cd %BUILDDIR%/.. - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdfja" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf-ja - cd %BUILDDIR%/.. - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end -) - -if "%1" == "gettext" ( - %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -if "%1" == "xml" ( - %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The XML files are in %BUILDDIR%/xml. - goto end -) - -if "%1" == "pseudoxml" ( - %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. - goto end -) - -:end diff --git a/src/client/Python/msrestazure/doc/modules.rst b/src/client/Python/msrestazure/doc/modules.rst deleted file mode 100644 index 97e977685f..0000000000 --- a/src/client/Python/msrestazure/doc/modules.rst +++ /dev/null @@ -1,7 +0,0 @@ -msrestazure -=========== - -.. toctree:: - :maxdepth: 4 - - msrestazure diff --git a/src/client/Python/msrestazure/doc/msrestazure.rst b/src/client/Python/msrestazure/doc/msrestazure.rst deleted file mode 100644 index 9fee025acd..0000000000 --- a/src/client/Python/msrestazure/doc/msrestazure.rst +++ /dev/null @@ -1,54 +0,0 @@ -msrestazure package -=================== - -Submodules ----------- - -msrestazure.azure_active_directory module ------------------------------------------ - -.. automodule:: msrestazure.azure_active_directory - :members: - :undoc-members: - :show-inheritance: - -msrestazure.azure_configuration module --------------------------------------- - -.. automodule:: msrestazure.azure_configuration - :members: - :undoc-members: - :show-inheritance: - -msrestazure.azure_exceptions module ------------------------------------ - -.. automodule:: msrestazure.azure_exceptions - :members: - :undoc-members: - :show-inheritance: - -msrestazure.azure_operation module ----------------------------------- - -.. automodule:: msrestazure.azure_operation - :members: - :undoc-members: - :show-inheritance: - -msrestazure.version module --------------------------- - -.. automodule:: msrestazure.version - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: msrestazure - :members: - :undoc-members: - :show-inheritance: diff --git a/src/client/Python/msrestazure/msrestazure.pyproj b/src/client/Python/msrestazure/msrestazure.pyproj deleted file mode 100644 index 24cf8037f9..0000000000 --- a/src/client/Python/msrestazure/msrestazure.pyproj +++ /dev/null @@ -1,78 +0,0 @@ - - - - Debug - 2.0 - {b80e5ecc-dcdc-4d31-b3be-8c32dea8e864} - - - msrestazure\__init__.py - ..\msrest\;. - . - . - clientruntime - client_runtime - - - - - - - true - false - - - true - false - - - - Code - - - Code - - - Code - - - - - Code - - - Code - - - - - Code - - - Code - - - - - - - - - Code - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets - - - - - - - - - - \ No newline at end of file diff --git a/src/client/Python/msrestazure/msrestazure/__init__.py b/src/client/Python/msrestazure/msrestazure/__init__.py deleted file mode 100644 index db95ddf97f..0000000000 --- a/src/client/Python/msrestazure/msrestazure/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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 .azure_configuration import AzureConfiguration -from .version import msrestazure_version - -__all__ = ["AzureConfiguration"] - -__version__ = msrestazure_version diff --git a/src/client/Python/msrestazure/msrestazure/azure_active_directory.py b/src/client/Python/msrestazure/msrestazure/azure_active_directory.py deleted file mode 100644 index cda68088d8..0000000000 --- a/src/client/Python/msrestazure/msrestazure/azure_active_directory.py +++ /dev/null @@ -1,527 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -# -------------------------------------------------------------------------- - -import ast -import re -import time -try: - from urlparse import urlparse, parse_qs -except ImportError: - from urllib.parse import urlparse, parse_qs - -import keyring -from oauthlib.oauth2 import BackendApplicationClient, LegacyApplicationClient -from oauthlib.oauth2.rfc6749.errors import ( - InvalidGrantError, - MismatchingStateError, - OAuth2Error, - TokenExpiredError) -from requests import RequestException -import requests_oauthlib as oauth - -from msrest.authentication import OAuthTokenAuthentication -from msrest.exceptions import TokenExpiredError as Expired -from msrest.exceptions import ( - AuthenticationError, - raise_with_traceback) - - -def _build_url(uri, paths, scheme): - """Combine URL parts. - - :param str uri: The base URL. - :param list paths: List of strings that make up the URL. - :param str scheme: The URL scheme, 'http' or 'https'. - :rtype: str - :return: Combined, formatted URL. - """ - path = [str(p).strip('/') for p in paths] - combined_path = '/'.join(path) - parsed_url = urlparse(uri) - replaced = parsed_url._replace(scheme=scheme) - if combined_path: - path = '/'.join([replaced.path, combined_path]) - replaced = replaced._replace(path=path) - - new_url = replaced.geturl() - new_url = new_url.replace('///', '//') - return new_url - - -def _http(uri, *extra): - """Convert https URL to http. - - :param str uri: The base URL. - :param str extra: Additional URL paths (optional). - :rtype: str - :return: An HTTP URL. - """ - return _build_url(uri, extra, 'http') - - -def _https(uri, *extra): - """Convert http URL to https. - - :param str uri: The base URL. - :param str extra: Additional URL paths (optional). - :rtype: str - :return: An HTTPS URL. - """ - return _build_url(uri, extra, 'https') - - -class AADMixin(OAuthTokenAuthentication): - """Mixin for Authentication object. - Provides some AAD functionality: - - State validation - - Token caching and retrieval - - Default AAD configuration - """ - _auth_endpoint = "//login.microsoftonline.com" - _china_auth_endpoint = "//login.chinacloudapi.cn" - _token_uri = "/oauth2/token" - _auth_uri = "/oauth2/authorize" - _tenant = "common" - _resource = 'https://management.core.windows.net/' - _china_resource = "https://management.core.chinacloudapi.cn/" - _keyring = "AzureAAD" - _case = re.compile('([a-z0-9])([A-Z])') - - def _configure(self, **kwargs): - """Configure authentication endpoint. - - Optional kwargs may include: - - china (bool): Configure auth for China-based service, - default is 'False'. - - tenant (str): Alternative tenant, default is 'common'. - - auth_uri (str): Alternative authentication endpoint. - - token_uri (str): Alternative token retrieval endpoint. - - resource (str): Alternative authentication resource, default - is 'https://management.core.windows.net/'. - - verify (bool): Verify secure connection, default is 'True'. - - keyring (str): Name of local token cache, default is 'AzureAAD'. - """ - if kwargs.get('china'): - auth_endpoint = self._china_auth_endpoint - resource = self._china_resource - else: - auth_endpoint = self._auth_endpoint - resource = self._resource - - tenant = kwargs.get('tenant', self._tenant) - self.auth_uri = kwargs.get('auth_uri', _https( - auth_endpoint, tenant, self._auth_uri)) - self.token_uri = kwargs.get('token_uri', _https( - auth_endpoint, tenant, self._token_uri)) - self.verify = kwargs.get('verify', True) - self.cred_store = kwargs.get('keyring', self._keyring) - self.resource = kwargs.get('resource', resource) - self.state = oauth.oauth2_session.generate_token() - self.store_key = "{}_{}".format( - self._auth_endpoint.strip('/'), self.store_key) - - def _check_state(self, response): - """Validate state returned by AAD server. - - :param str response: URL returned by server redirect. - :raises: ValueError if state does not match that of the request. - :rtype: None - """ - query = parse_qs(urlparse(response).query) - if self.state not in query.get('state', []): - raise ValueError( - "State received from server does not match that of request.") - - def _convert_token(self, token): - """Convert token fields from camel case. - - :param dict token: An authentication token. - :rtype: dict - """ - return {self._case.sub(r'\1_\2', k).lower(): v - for k, v in token.items()} - - def _parse_token(self): - # TODO: We could also check expires_on and use to update expires_in - if self.token.get('expires_at'): - countdown = float(self.token['expires_at']) - time.time() - self.token['expires_in'] = countdown - kwargs = {} - if self.token.get('refresh_token'): - kwargs['auto_refresh_url'] = self.token_uri - kwargs['auto_refresh_kwargs'] = {'client_id': self.id, - 'resource': self.resource} - kwargs['token_updater'] = self._default_token_cache - return kwargs - - def _default_token_cache(self, token): - """Store token for future sessions. - - :param dict token: An authentication token. - :rtype: None - """ - self.token = token - keyring.set_password(self.cred_store, self.store_key, str(token)) - - def _retrieve_stored_token(self): - """Retrieve stored token for new session. - - :raises: ValueError if no cached token found. - :rtype: dict - :return: Retrieved token. - """ - token = keyring.get_password(self.cred_store, self.store_key) - if token is None: - raise ValueError("No stored token found.") - self.token = ast.literal_eval(str(token)) - self.signed_session() - - def signed_session(self): - """Create token-friendly Requests session, using auto-refresh. - Used internally when a request is made. - - :rtype: requests_oauthlib.OAuth2Session - :raises: TokenExpiredError if token can no longer be refreshed. - """ - kwargs = self._parse_token() - try: - new_session = oauth.OAuth2Session( - self.id, - token=self.token, - **kwargs) - return new_session - except TokenExpiredError as err: - raise_with_traceback(Expired, "", err) - - def clear_cached_token(self): - """Clear any stored tokens. - - :raises: KeyError if failed to clear token. - :rtype: None - """ - try: - keyring.delete_password(self.cred_store, self.store_key) - except keyring.errors.PasswordDeleteError: - raise_with_traceback(KeyError, "Unable to clear token.") - - -class AADRefreshMixin(object): - """ - Additional token refresh logic - """ - - def refresh_session(self): - """Return updated session if token has expired, attempts to - refresh using newly acquired token. - - :rtype: requests.Session. - """ - if self.token.get('refresh_token'): - try: - return self.signed_session() - except Expired: - pass - self.set_token() - return self.signed_session() - - -class AADTokenCredentials(AADMixin): - """ - Credentials objects for AAD token retrieved through external process - e.g. Python ADAL lib. - - Optional kwargs may include: - - china (bool): Configure auth for China-based service, - default is 'False'. - - tenant (str): Alternative tenant, default is 'common'. - - auth_uri (str): Alternative authentication endpoint. - - token_uri (str): Alternative token retrieval endpoint. - - resource (str): Alternative authentication resource, default - is 'https://management.core.windows.net/'. - - verify (bool): Verify secure connection, default is 'True'. - - keyring (str): Name of local token cache, default is 'AzureAAD'. - - cached (bool): If true, will not attempt to collect a token, - which can then be populated later from a cached token. - - :param dict token: Authentication token. - :param str client_id: Client ID, if not set, Xplat Client ID - will be used. - """ - - def __init__(self, token, client_id=None, **kwargs): - if not client_id: - # Default to Xplat Client ID. - client_id = '04b07795-8ddb-461a-bbee-02f9e1bf7b46' - super(AADTokenCredentials, self).__init__(client_id, None) - self._configure(**kwargs) - if not kwargs.get('cached'): - self.token = self._convert_token(token) - self.signed_session() - - @classmethod - def retrieve_session(cls, client_id=None): - """Create AADTokenCredentials from a cached token if it has not - yet expired. - """ - session = cls(None, None, client_id=client_id, cached=True) - session._retrieve_stored_token() - return session - - -class UserPassCredentials(AADRefreshMixin, AADMixin): - """Credentials object for Headless Authentication, - i.e. AAD authentication via username and password. - - Headless Auth requires an AAD login (no a Live ID) that already has - permission to access the resource e.g. an organization account, and - that 2-factor auth be disabled. - - Optional kwargs may include: - - china (bool): Configure auth for China-based service, - default is 'False'. - - tenant (str): Alternative tenant, default is 'common'. - - auth_uri (str): Alternative authentication endpoint. - - token_uri (str): Alternative token retrieval endpoint. - - resource (str): Alternative authentication resource, default - is 'https://management.core.windows.net/'. - - verify (bool): Verify secure connection, default is 'True'. - - keyring (str): Name of local token cache, default is 'AzureAAD'. - - cached (bool): If true, will not attempt to collect a token, - which can then be populated later from a cached token. - - :param str username: Account username. - :param str password: Account password. - :param str client_id: Client ID, if not set, Xplat Client ID - will be used. - :param str secret: Client secret, only if required by server. - """ - - def __init__(self, username, password, - client_id=None, secret=None, **kwargs): - if not client_id: - # Default to Xplat Client ID. - client_id = '04b07795-8ddb-461a-bbee-02f9e1bf7b46' - super(UserPassCredentials, self).__init__(client_id, None) - self._configure(**kwargs) - - self.store_key += "_{}".format(username) - self.username = username - self.password = password - self.secret = secret - self.client = LegacyApplicationClient(client_id=self.id) - if not kwargs.get('cached'): - self.set_token() - - @classmethod - def retrieve_session(cls, username, client_id=None): - """Create ServicePrincipalCredentials from a cached token if it has not - yet expired. - """ - session = cls(username, None, client_id=client_id, cached=True) - session._retrieve_stored_token() - return session - - def _setup_session(self): - """Create token-friendly Requests session. - - :rtype: requests_oauthlib.OAuth2Session - """ - return oauth.OAuth2Session(client=self.client) - - def set_token(self): - """Get token using Username/Password credentials. - - :raises: AuthenticationError if credentials invalid, or call fails. - """ - session = self._setup_session() - optional = {} - if self.secret: - optional['client_secret'] = self.secret - try: - token = session.fetch_token(self.token_uri, client_id=self.id, - username=self.username, - password=self.password, - resource=self.resource, - verify=self.verify, - **optional) - except (RequestException, OAuth2Error, InvalidGrantError) as err: - raise_with_traceback(AuthenticationError, "", err) - - self.token = token - - -class ServicePrincipalCredentials(AADRefreshMixin, AADMixin): - """Credentials object for Service Principle Authentication. - Authenticates via a Client ID and Secret. - - Optional kwargs may include: - - china (bool): Configure auth for China-based service, - default is 'False'. - - tenant (str): Alternative tenant, default is 'common'. - - auth_uri (str): Alternative authentication endpoint. - - token_uri (str): Alternative token retrieval endpoint. - - resource (str): Alternative authentication resource, default - is 'https://management.core.windows.net/'. - - verify (bool): Verify secure connection, default is 'True'. - - keyring (str): Name of local token cache, default is 'AzureAAD'. - - cached (bool): If true, will not attempt to collect a token, - which can then be populated later from a cached token. - - :param str client_id: Client ID. - :param str secret: Client secret. - """ - def __init__(self, client_id, secret, **kwargs): - super(ServicePrincipalCredentials, self).__init__(client_id, None) - self._configure(**kwargs) - - self.secret = secret - self.client = BackendApplicationClient(self.id) - if not kwargs.get('cached'): - self.set_token() - - @classmethod - def retrieve_session(cls, client_id): - """Create ServicePrincipalCredentials from a cached token if it has not - yet expired. - """ - session = cls(client_id, None, cached=True) - session._retrieve_stored_token() - return session - - def _setup_session(self): - """Create token-friendly Requests session. - - :rtype: requests_oauthlib.OAuth2Session - """ - return oauth.OAuth2Session(self.id, client=self.client) - - def set_token(self): - """Get token using Client ID/Secret credentials. - - :raises: AuthenticationError if credentials invalid, or call fails. - """ - session = self._setup_session() - try: - token = session.fetch_token(self.token_uri, client_id=self.id, - resource=self.resource, - client_secret=self.secret, - response_type="client_credentials", - verify=self.verify) - except (RequestException, OAuth2Error, InvalidGrantError) as err: - raise_with_traceback(AuthenticationError, "", err) - else: - self.token = token - - -class InteractiveCredentials(AADMixin): - """Credentials object for Interactive/Web App Authentication. - Requires that an AAD Client be configured with a redirect URL. - - Optional kwargs may include: - - china (bool): Configure auth for China-based service, - default is 'False'. - - tenant (str): Alternative tenant, default is 'common'. - - auth_uri (str): Alternative authentication endpoint. - - token_uri (str): Alternative token retrieval endpoint. - - resource (str): Alternative authentication resource, default - is 'https://management.core.windows.net/'. - - verify (bool): Verify secure connection, default is 'True'. - - keyring (str): Name of local token cache, default is 'AzureAAD'. - - cached (bool): If true, will not attempt to collect a token, - which can then be populated later from a cached token. - - :param str client_id: Client ID. - :param str redirect: Redirect URL. - """ - - def __init__(self, client_id, redirect, **kwargs): - super(InteractiveCredentials, self).__init__(client_id, None) - self._configure(**kwargs) - - self.redirect = redirect - if not kwargs.get('cached'): - self.set_token() - - @classmethod - def retrieve_session(cls, client_id, redirect): - """Create InteractiveCredentials from a cached token if it has not - yet expired. - """ - session = cls(client_id, redirect, cached=True) - session._retrieve_stored_token() - return session - - def _setup_session(self): - """Create token-friendly Requests session. - - :rtype: requests_oauthlib.OAuth2Session - """ - return oauth.OAuth2Session(self.id, - redirect_uri=self.redirect, - state=self.state) - - def get_auth_url(self, msa=False, **additional_args): - """Get URL to web portal for authentication. - - :param bool msa: Set to 'True' if authenticating with Live ID. Default - is 'False'. - :param additional_args: Set and additional kwargs for requrired AAD - configuration: msdn.microsoft.com/en-us/library/azure/dn645542.aspx - :rtype: Tuple - :return: The URL for authentication (str), and state code that will - be verified in the response (str). - """ - if msa: - additional_args['domain_hint'] = 'live.com' - session = self._setup_session() - auth_url, state = session.authorization_url(self.auth_uri, - resource=self.resource, - **additional_args) - return auth_url, state - - def set_token(self, response_url): - """Get token using Authorization Code from redirected URL. - - :param str response_url: The full redirected URL from successful - authentication. - :raises: AuthenticationError if credentials invalid, or call fails. - """ - self._check_state(response_url) - session = self._setup_session() - - if response_url.startswith(_http(self.redirect)): - response_url = _https(response_url) - elif not response_url.startswith(_https(self.redirect)): - response_url = _https(self.redirect, response_url) - try: - token = session.fetch_token(self.token_uri, - authorization_response=response_url, - verify=self.verify) - except (InvalidGrantError, OAuth2Error, - MismatchingStateError, RequestException) as err: - raise_with_traceback(AuthenticationError, "", err) - else: - self.token = token diff --git a/src/client/Python/msrestazure/msrestazure/azure_configuration.py b/src/client/Python/msrestazure/msrestazure/azure_configuration.py deleted file mode 100644 index 6700d15f98..0000000000 --- a/src/client/Python/msrestazure/msrestazure/azure_configuration.py +++ /dev/null @@ -1,78 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -# -------------------------------------------------------------------------- - -try: - from configparser import NoOptionError -except ImportError: - from ConfigParser import NoOptionError - -from .version import msrestazure_version -from msrest import Configuration -from msrest.exceptions import raise_with_traceback - - -class AzureConfiguration(Configuration): - """Azure specific client configuration. - - :param str base_url: REST Service base URL. - :param str filepath: Path to an existing config file (optional). - """ - - def __init__(self, base_url, filepath=None): - super(AzureConfiguration, self).__init__(base_url, filepath) - self.long_running_operation_timeout = 30 - self.add_user_agent("msrest_azure/{}".format(msrestazure_version)) - - def save(self, filepath): - """Save current configuration to file. - - :param str filepath: Path to save file to. - :raises: ValueError if supplied filepath cannot be written to. - :rtype: None - """ - self._config.add_section("Azure") - self._config.set("Azure", - "long_running_operation_timeout", - self.long_running_operation_timeout) - return super(AzureConfiguration, self).save(filepath) - - def load(self, filepath): - """Load configuration from existing file. - - :param str filepath: Path to existing config file. - :raises: ValueError if supplied config file is invalid. - :rtype: None - """ - try: - self._config.read(filepath) - self.long_running_operation_timeout = self._config.getint( - "Azure", "long_running_operation_timeout") - except (ValueError, EnvironmentError, NoOptionError): - msg = "Supplied config file incompatible" - raise_with_traceback(ValueError, msg) - finally: - self._clear_config() - return super(AzureConfiguration, self).load(filepath) diff --git a/src/client/Python/msrestazure/msrestazure/azure_exceptions.py b/src/client/Python/msrestazure/msrestazure/azure_exceptions.py deleted file mode 100644 index bb85333f30..0000000000 --- a/src/client/Python/msrestazure/msrestazure/azure_exceptions.py +++ /dev/null @@ -1,198 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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 requests import RequestException - -from msrest.exceptions import ClientException -from msrest.serialization import Deserializer -from msrest.exceptions import DeserializationError - - -class CloudErrorData(object): - """Cloud Error Data object, deserialized from error data returned - during a failed REST API call. - """ - - _validation = {} - _attribute_map = { - 'error': {'key': 'code', 'type': 'str'}, - 'message': {'key': 'message', 'type': 'str'}, - 'target': {'key': 'target', 'type': 'str'}, - 'details': {'key': 'details', 'type': '[CloudErrorData]'}, - 'data': {'key': 'values', 'type': '{str}'} - } - - def __init__(self, *args, **kwargs): - self.error = kwargs.get('error') - self._message = kwargs.get('message') - self.request_id = None - self.error_time = None - self.target = kwargs.get('target') - self.details = kwargs.get('details') - self.data = kwargs.get('data') - super(CloudErrorData, self).__init__(*args) - - def __str__(self): - """Cloud error message.""" - error_str = "Azure Error: {}".format(self.error) - error_str += "\nMessage: {}".format(self._message) - if self.target: - error_str += "\nTarget: {}".format(self.target) - if self.request_id: - error_str += "\nRequest ID: {}".format(self.request_id) - if self.error_time: - error_str += "\nError Time: {}".format(self.error_time) - if self.data: - error_str += "\nAdditional Data:" - for key, value in self.data.items(): - error_str += "\n\t{} : {}".format(key, value) - if self.details: - error_str += "\nException Details:" - for error_obj in self.details: - error_str += "\n\tError Code: {}".format(error_obj.error) - error_str += "\n\tMessage: {}".format(error_obj.message) - error_str += "\n\tTarget: {}".format(error_obj.target) - error_bytes = error_str.encode() - return error_bytes.decode('ascii') - - @classmethod - def _get_subtype_map(cls): - return {} - - @property - def message(self): - """Cloud error message.""" - return self._message - - @message.setter - def message(self, value): - """Attempt to deconstruct error message to retrieve further - error data. - """ - try: - value = eval(value) - except (SyntaxError, TypeError): - pass - try: - value = value.get('value', value) - msg_data = value.split('\n') - self._message = msg_data[0] - except AttributeError: - self._message = value - return - try: - self.request_id = msg_data[1].partition(':')[2] - time_str = msg_data[2].partition(':') - self.error_time = Deserializer.deserialize_iso( - "".join(time_str[2:])) - except (IndexError, DeserializationError): - pass - - -class CloudError(ClientException): - """ClientError, exception raised for failed Azure REST call. - Will attempt to deserialize response into meaningful error - data. - - :param requests.Response response: Response object. - :param str error: Optional error message. - """ - - def __init__(self, response, error=None, *args, **kwargs): - self.deserializer = Deserializer({'CloudErrorData': CloudErrorData}) - self.error = None - self.message = None - self.response = response - self.status_code = self.response.status_code - self.request_id = None - - if error: - self.message = error - self.error = response - else: - self._build_error_data(response) - - if not self.error or not self.message: - self._build_error_message(response) - - super(CloudError, self).__init__( - self.message, self.error, *args, **kwargs) - - def __str__(self): - """Cloud error message""" - if self.error: - return str(self.error) - return str(self.message) - - def _build_error_data(self, response): - try: - data = response.json() - except ValueError: - data = response - else: - data = data.get('error', data) - try: - self.error = self.deserializer(CloudErrorData(), data) - except DeserializationError: - self.error = None - else: - if self.error: - if not self.error.error or not self.error.message: - self.error = None - else: - self.message = self.error.message - - def _get_state(self, content): - state = content.get("status") - if not state: - resource_content = content.get('properties', content) - state = resource_content.get("provisioningState") - return "Resource state {}".format(state) if state else "none" - - def _build_error_message(self, response): - try: - data = response.json() - except ValueError: - message = "none" - else: - message = data.get("message", self._get_state(data)) - try: - response.raise_for_status() - except RequestException as err: - if not self.error: - self.error = err - if not self.message: - if message == "none": - message = str(err) - msg = "Operation failed with status: {!r}. Details: {}" - self.message = msg.format(response.reason, message) - else: - if not self.error: - self.error = response - if not self.message: - msg = "Operation failed with status: {!r}. Details: {}" - self.message = msg.format( - response.status_code, message) \ No newline at end of file diff --git a/src/client/Python/msrestazure/msrestazure/azure_operation.py b/src/client/Python/msrestazure/msrestazure/azure_operation.py deleted file mode 100644 index b27b4a72a3..0000000000 --- a/src/client/Python/msrestazure/msrestazure/azure_operation.py +++ /dev/null @@ -1,559 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -# -------------------------------------------------------------------------- - -import re -import threading -import time -try: - from urlparse import urlparse -except ImportError: - from urllib.parse import urlparse - -from msrest.exceptions import DeserializationError -from msrestazure.azure_exceptions import CloudError - - -FINISHED = frozenset(['succeeded', 'canceled', 'failed']) -FAILED = frozenset(['canceled', 'failed']) -SUCCEEDED = frozenset(['succeeded']) - - -def finished(status): - if hasattr(status, 'value'): - status = status.value - return str(status).lower() in FINISHED - - -def failed(status): - if hasattr(status, 'value'): - status = status.value - return str(status).lower() in FAILED - - -def succeeded(status): - if hasattr(status, 'value'): - status = status.value - return str(status).lower() in SUCCEEDED - - -class BadStatus(Exception): - pass - - -class BadResponse(Exception): - pass - - -class OperationFailed(Exception): - pass - - -class OperationFinished(Exception): - pass - - -class SimpleResource: - """An implementation of Python 3 SimpleNamespace. - Used to deserialize resource objects from response bodies where - no particular object type has been specified. - """ - - def __init__(self, **kwargs): - self.__dict__.update(kwargs) - - def __repr__(self): - keys = sorted(self.__dict__) - items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys) - return "{}({})".format(type(self).__name__, ", ".join(items)) - - def __eq__(self, other): - return self.__dict__ == other.__dict__ - - -class LongRunningOperation(object): - """LongRunningOperation - Provides default logic for interpreting operation responses - and status updates. - """ - _convert = re.compile('([a-z0-9])([A-Z])') - - def __init__(self, response, outputs): - self.method = response.request.method - self.status = "" - self.resource = None - self.get_outputs = outputs - self.async_url = None - self.location_url = None - - def _validate(self, url): - """Validate header url - - :param str url: Polling URL extracted from response header. - :returns: URL if valid. - :raises: ValueError if URL has not scheme or host. - """ - if url is None: - return None - parsed = urlparse(url) - if not parsed.scheme or not parsed.netloc: - raise ValueError("Invalid URL header") - return url - - def _check_status(self, response): - """Check response status code is valid for a Put or Patch - reqest. Must be 200, 202, or 204. - - :raises: BadStatus if invalid status. - """ - code = response.status_code - if code in [200, 202] or (code == 201 and self.method == 'PUT') or \ - (code == 204 and self.method in ['DELETE', 'POST']): - return - raise BadStatus( - "Invalid return status for {!r} operation".format(self.method)) - - def _is_empty(self, response): - """Check if response body contains meaningful content. - - :rtype: bool - :raises: DeserializationError if response body contains invalid - json data. - """ - if not response.content: - return True - try: - body = response.json() - return not body - except ValueError: - raise DeserializationError( - "Error occurred in deserializing the response body.") - - def _deserialize(self, response): - """Attempt to deserialize resource from response. - - :raises: OperationFailed if deserialized resource has status of - failed or cancelled. - :raises: OperationFinished if deserialised resource has status - succeeded. - """ - self.resource = self.get_outputs(response) - if self.method == 'PUT': - resource_status = self._get_resource_status() - if failed(resource_status): - self.status = resource_status - raise OperationFailed("Operation failed or cancelled") - elif succeeded(resource_status): - raise OperationFinished("Operation succeeded") - elif resource_status: - self.status = resource_status - - def _get_body_status(self, response): - """Attempt to find status info in response body. - - :param requests.Response response: latest REST call response. - :rtype: str - :returns: Status if found, else 'None'. - """ - if self._is_empty(response): - return None - body = response.json() - return body.get('status') - - def _get_resource_status(self): - """ - Attempt to get provisioning state from resource. - :returns: Status if found, else 'None'. - """ - try: - return self.resource.provisioning_state - except AttributeError: - pass - try: - return self.resource.properties.provisioning_state - except AttributeError: - return None - - def _object_from_response(self, response): - """If deserialization fails, attempt to create object from - response body regardless. - Required functionality for Azure LRO's.... - - :param requests.Response response: latest REST call response. - """ - body = response.json() - body = {self._convert.sub(r'\1_\2', k).lower(): v - for k, v in body.items()} - properties = body.get('properties') - if properties: - properties = {self._convert.sub(r'\1_\2', k).lower(): v - for k, v in properties.items()} - del body['properties'] - body.update(properties) - self.resource = SimpleResource(**body) - else: - self.resource = SimpleResource(**body) - - def _process_status(self, response): - """Process response based on specific status code. - - :param requests.Response response: latest REST call response. - """ - process = getattr(self, '_status_' + str(response.status_code)) - process(response) - - def _status_200(self, response): - """Process response with status code 200. - - :param requests.Response response: latest REST call response. - """ - status = self._get_body_status(response) - self.status = status if status else 'Succeeded' - if not status: - try: - # Even if this fails, status '200' should be successful. - self._deserialize(response) - except CloudError: - if self.method in ['PUT', 'PATCH']: - self._object_from_response(response) - - def _status_201(self, response): - """Process response with status code 201. - - :param requests.Response response: latest REST call response. - :raises: BadResponse if response deserializes to CloudError. - """ - try: - self._deserialize(response) - if not self.status: - self.status = 'Succeeded' - except CloudError as err: - raise BadResponse(str(err)) - - def _status_202(self, response): - """Process response with status code 202. - Just sets status to 'InProgress'. - - :param requests.Response response: latest REST call response. - """ - self.status = 'InProgress' - - def _status_204(self, response): - """Process response with status code 204. - Interpretted as successful with no payload. - - :param requests.Response response: latest REST call response. - """ - self.status = 'Succeeded' - self.resource = None - - def is_done(self): - """Check whether the operation can be considered complete. - This is based on whether the data in the resource matches the current - status. If there is not resource, we assume it's complete. - - :rtype: bool - """ - if (self.async_url or not self.resource) and \ - self.method in ['PUT', 'PATCH']: - return False - resource_state = self._get_resource_status() - try: - return self.status.lower() == resource_state.lower() - except AttributeError: - return True - - def get_initial_status(self, response): - """Process first response after initiating long running - operation. - - :param requests.Response response: initial REST call response. - """ - self._deserialize(response) - self._check_status(response) - if response.status_code in [200, 202, 204]: - self._process_status(response) - status = self._get_body_status(response) - if status: - self.status = status - - def get_status_from_location(self, response): - """Process the latest status update retrieved from a 'location' - header. - - :param requests.Response response: latest REST call response. - :raises: BadResponse if response has no body and not status 202. - """ - self._check_status(response) - self._process_status(response) - - def get_status_from_resource(self, response): - """Process the latest status update retrieved from the same URL as - the previous request. - - :param requests.Response response: latest REST call response. - :raises: BadResponse if status not 200 or 204. - """ - self._check_status(response) - if self._is_empty(response) and self.method in ['PUT', 'PATCH']: - raise BadResponse('The response from long running ' - 'operation does not contain a body.') - self._process_status(response) - - def get_status_from_async(self, response): - """Process the latest status update retrieved from a - 'azure-asyncoperation' header. - - :param requests.Response response: latest REST call response. - :raises: BadResponse if response has no body, or body does not - contain status. - """ - self._check_status(response) - if self._is_empty(response): - raise BadResponse('The response from long running operation ' - 'does not contain a body.') - - self.status = self._get_body_status(response) - if not self.status: - raise BadResponse("No status found in body") - if self.method in ["POST", "DELETE"]: - try: - self._deserialize(response) - except CloudError: - pass # Not all 'accept' statuses will deserialize. - - def get_retry(self, response, *args): - """Retrieve the URL that will be polled for status. First looks for - 'azure-asyncoperation' header, if not found or invalid, check for - 'location' header. - - :param requests.Response response: latest REST call response. - """ - try: - self.async_url = self._validate( - response.headers.get('azure-asyncoperation')) - - # Return if we have a url, in case location header raises error. - if self.async_url: - return - except ValueError: - pass # We can ignore as location header may still be valid. - self.location_url = self._validate(response.headers.get('location')) - if not self.location_url and not self.async_url: - code = response.status_code - if code == 202 and self.method == 'POST': - raise BadResponse( - 'Location header is missing from long running operation.') - - -class AzureOperationPoller(object): - """Initiates long running operation and polls status in separate - thread. - - :param callable send_cmd: The API request to initiate the operation. - :param callable update_cmd: The API reuqest to check the status of - the operation. - :param callable output_cmd: The function to deserialize the resource - of the operation. - :param int timeout: Time in seconds to wait between status calls, - default is 30. - :param callable func: Callback function that takes at least one - argument, a completed LongRunningOperation (optional). - """ - - def __init__(self, send_cmd, output_cmd, update_cmd, timeout=30): - self._timeout = timeout - self._response = None - self._operation = None - self._exception = None - self._callbacks = [] - self._done = threading.Event() - self._thread = threading.Thread( - target=self._start, args=(send_cmd, update_cmd, output_cmd)) - self._thread.daemon = True - self._thread.start() - - def _start(self, send_cmd, update_cmd, output_cmd): - """Start the long running operation. - On completetion, runs any callbacks. - - :param callable send_cmd: The API request to initiate the operation. - :param callable update_cmd: The API reuqest to check the status of - the operation. - :param callable output_cmd: The function to deserialize the resource - of the operation. - """ - try: - self._response = send_cmd() - self._operation = LongRunningOperation(self._response, output_cmd) - self._operation.get_initial_status(self._response) - self._poll(update_cmd) - - except BadStatus: - self._operation.status = 'Failed' - self._exception = CloudError(self._response) - - except BadResponse as err: - self._operation.status = 'Failed' - self._exception = CloudError(self._response, str(err)) - - except OperationFailed: - self._exception = CloudError(self._response) - - except OperationFinished: - pass - - except Exception as err: - self._exception = err - - finally: - self._done.set() - - callbacks, self._callbacks = self._callbacks, [] - while callbacks: - for call in callbacks: - call(self._operation) - callbacks, self._callbacks = self._callbacks, [] - - def _delay(self): - """Check for a 'retry-after' header to set timeout, - otherwise use configured timeout. - """ - if self._response is None: - return - if self._response.headers.get('retry-after'): - time.sleep(int(self._response.headers['retry-after'])) - else: - time.sleep(self._timeout) - - def _polling_cookie(self): - """Collect retry cookie - we only want to do this for the test server - at this point, unless we implement a proper cookie policy. - - :returns: Dictionary containing a cookie header if required, - otherwise an empty dictionary. - """ - parsed_url = urlparse(self._response.request.url) - host = parsed_url.hostname.strip('.') - if host == 'localhost': - return {'cookie': self._response.headers.get('set-cookie', '')} - return {} - - def _poll(self, update_cmd): - """Poll status of operation so long as operation is incomplete and - we have an endpoint to query. - - :param callable update_cmd: The function to call to retrieve the - latest status of the long running operation. - :raises: OperationFinished if operation status 'Succeeded'. - :raises: OperationFailed if operation status 'Failed' or 'Cancelled'. - :raises: BadStatus if response status invalid. - :raises: BadResponse if response invalid. - """ - initial_url = self._response.request.url - - while not finished(self._operation.status): - self._delay() - url = self._response.request.url - headers = self._polling_cookie() - self._operation.get_retry(self._response, initial_url) - - if self._operation.async_url: - self._response = update_cmd( - self._operation.async_url, headers) - self._operation.get_status_from_async( - self._response) - elif self._operation.location_url: - self._response = update_cmd( - self._operation.location_url, headers) - self._operation.get_status_from_location( - self._response) - else: - self._response = update_cmd(url, headers) - self._operation.get_status_from_resource( - self._response) - - if failed(self._operation.status): - raise OperationFailed("Operation failed or cancelled") - elif not self._operation.is_done(): - self._response = update_cmd(initial_url) - self._operation.get_status_from_resource( - self._response) - - def result(self, timeout=None): - """Return the result of the long running operation, or - the result available after the specified timeout. - - :returns: The deserialized resource of the long running operation, - if one is available. - :raises CloudError: Server problem with the query. - """ - self.wait(timeout) - return self._operation.resource - - def wait(self, timeout=None): - """Wait on the long running operation for a specified length - of time. - - :param int timeout: Perion of time to wait for the long running - operation to complete. - :raises CloudError: Server problem with the query. - """ - self._thread.join(timeout=timeout) - try: - raise self._exception - except TypeError: - pass - - def done(self): - """Check status of the long running operation. - - :returns: 'True' if the process has completed, else 'False'. - """ - return not self._thread.isAlive() - - def add_done_callback(self, func): - """Add callback function to be run once the long running operation - has completed - regardless of the status of the operation. - - :param callable func: Callback function that takes at least one - argument, a completed LongRunningOperation. - :raises: ValueError if the long running operation has already - completed. - """ - if self._done.is_set(): - raise ValueError("Process is complete.") - self._callbacks.append(func) - - def remove_done_callback(self, func): - """Remove a callback from the long running operation. - - :param callable func: The function to be removed from the callbacks. - :raises: ValueError if the long running operation has already - completed. - """ - if self._done.is_set(): - raise ValueError("Process is complete.") - self._callbacks = [c for c in self._callbacks if c != func] diff --git a/src/client/Python/msrestazure/msrestazure/version.py b/src/client/Python/msrestazure/msrestazure/version.py deleted file mode 100644 index 9410ce6ecb..0000000000 --- a/src/client/Python/msrestazure/msrestazure/version.py +++ /dev/null @@ -1,27 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -# -------------------------------------------------------------------------- - -msrestazure_version = "0.4.3" diff --git a/src/client/Python/msrestazure/readme.rst b/src/client/Python/msrestazure/readme.rst deleted file mode 100644 index 1b6fbbcc0e..0000000000 --- a/src/client/Python/msrestazure/readme.rst +++ /dev/null @@ -1,133 +0,0 @@ -AutoRest: Python Client Runtime - Azure Module -=============================================== - - -Installation ------------- - -To install: - -.. code-block:: bash - - $ pip install msrestazure - - -Release History ---------------- - -2016-10-17 Version 0.4.4 -++++++++++++++++++++++++ - -**Bugfixes** - -- More informative and well-formed CloudError exceptions (https://github.com/Azure/autorest/issues/1460) -- Raise CustomException is defined in Swagger (https://github.com/Azure/autorest/issues/1404) - -2016-09-14 Version 0.4.3 -++++++++++++++++++++++++ - -**Bugfixes** - -- Make AzureOperationPoller thread as daemon (do not block anymore a Ctrl+C) (https://github.com/Azure/autorest/pull/1379) - -2016-09-01 Version 0.4.2 -++++++++++++++++++++++++ - -**Bugfixes** - -- Better exception message (https://github.com/Azure/autorest/pull/1300) - -This version needs msrest >= 0.4.3 - -2016-06-08 Version 0.4.1 -++++++++++++++++++++++++ - -**Bugfixes** - -- Fix for LRO PUT operation https://github.com/Azure/autorest/issues/1133 - -2016-05-25 Version 0.4.0 -++++++++++++++++++++++++ - -Update msrest dependency to 0.4.0 - -**Bugfixes** - -- Fix for several AAD issues https://github.com/Azure/autorest/issues/1055 -- Fix for LRO PATCH bug and refactor https://github.com/Azure/autorest/issues/993 - -**Behaviour changes** - -- Needs Autorest > 0.17.0 Nightly 20160525 - - -2016-04-26 Version 0.3.0 -++++++++++++++++++++++++ - -Update msrest dependency to 0.3.0 - -**Bugfixes** - -- Read only values are no longer in __init__ or sent to the server (https://github.com/Azure/autorest/pull/959) -- Useless kwarg removed - -**Behaviour changes** - -- Needs Autorest > 0.16.0 Nightly 20160426 - - -2016-03-31 Version 0.2.1 -++++++++++++++++++++++++ - -**Bugfixes** - -- Fix AzurePollerOperation if Swagger defines provisioning status as enum type (https://github.com/Azure/autorest/pull/892) - - -2016-03-25 Version 0.2.0 -++++++++++++++++++++++++ - -Update msrest dependency to 0.2.0 - -**Behaviour change** - -- async methods called with raw=True don't return anymore AzureOperationPoller but ClientRawResponse -- Needs Autorest > 0.16.0 Nightly 20160324 - - -2016-03-21 Version 0.1.2 -++++++++++++++++++++++++ - -Update msrest dependency to 0.1.3 - -**Bugfixes** - -- AzureOperationPoller.wait() failed to raise exception if query error (https://github.com/Azure/autorest/pull/856) - - -2016-03-04 Version 0.1.1 -++++++++++++++++++++++++ - -**Bugfixes** - -- Source package corrupted in Pypi (https://github.com/Azure/autorest/issues/799) - -2016-03-04 Version 0.1.0 -++++++++++++++++++++++++ - -**Behaviour change** - -- Replaced _required attribute in CloudErrorData class with _validation dict. - -2016-02-29 Version 0.0.2 -++++++++++++++++++++++++ - -**Bugfixes** - -- Fixed AAD bug to include connection verification in UserPassCredentials. (https://github.com/Azure/autorest/pull/725) -- Source package corrupted in Pypi (https://github.com/Azure/autorest/issues/718) - -2016-02-19 Version 0.0.1 -++++++++++++++++++++++++ - -- Initial release. diff --git a/src/client/Python/msrestazure/requirements27.txt b/src/client/Python/msrestazure/requirements27.txt deleted file mode 100644 index 4c6368baf8..0000000000 --- a/src/client/Python/msrestazure/requirements27.txt +++ /dev/null @@ -1,15 +0,0 @@ -certifi==2015.9.6.2 -enum34==1.0.4 -funcsigs==0.4 -futures==3.0.3 -httpretty==0.8.10 -isodate==0.5.4 -keyring==5.6 -mock==1.3.0 -oauthlib==1.0.3 -pbr==1.8.1 -requests==2.7.0 -requests-oauthlib==0.5.0 -six==1.10.0 -chardet==2.3.0 -msrest==0.2.0 diff --git a/src/client/Python/msrestazure/requirements35.txt b/src/client/Python/msrestazure/requirements35.txt deleted file mode 100644 index 76fe44ba95..0000000000 --- a/src/client/Python/msrestazure/requirements35.txt +++ /dev/null @@ -1,13 +0,0 @@ -funcsigs==0.4 -futures==3.0.3 -httpretty==0.8.10 -isodate==0.5.4 -keyring==5.6 -mock==1.3.0 -oauthlib==1.0.3 -pbr==1.8.1 -requests==2.7.0 -requests-oauthlib==0.5.0 -six==1.10.0 -chardet==2.3.0 -msrest==0.2.0 diff --git a/src/client/Python/msrestazure/setup.py b/src/client/Python/msrestazure/setup.py deleted file mode 100644 index 5654713131..0000000000 --- a/src/client/Python/msrestazure/setup.py +++ /dev/null @@ -1,53 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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 setuptools import setup - -setup( - name='msrestazure', - version='0.4.4', - author='Microsoft Corporation', - packages=['msrestazure'], - url=('https://github.com/Azure/autorest/tree/master/' - 'src/client/Python/msrestazure'), - license='MIT License', - description=('AutoRest swagger generator Python client runtime. ' - 'Azure-specific module.'), - long_description=open('readme.rst').read(), - classifiers=[ - 'Development Status :: 4 - Beta', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'License :: OSI Approved :: MIT License', - 'Topic :: Software Development'], - install_requires=[ - "msrest>=0.4.4"], -) diff --git a/src/client/Python/msrestazure/test/__init__.py b/src/client/Python/msrestazure/test/__init__.py deleted file mode 100644 index 793da781f4..0000000000 --- a/src/client/Python/msrestazure/test/__init__.py +++ /dev/null @@ -1,56 +0,0 @@ -# -------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -# -------------------------------------------------------------------------- - -import sys -import os - -from os.path import dirname, pardir, join, realpath - -cwd = dirname(realpath(__file__)) -runtime = realpath(join(cwd, pardir, pardir, 'msrest')) - -sys.path.append(runtime) - -if sys.version_info[:2] < (2, 7, ): - try: - from unittest2 import TestLoader, TextTestRunner - - except ImportError: - raise ImportError("The Python Client Runtime test suite requires " - "the unittest2 package to run on Python 2.6 and " - "below.\nPlease install this package to continue.") -else: - from unittest import TestLoader, TextTestRunner - - -if __name__ == '__main__': - - runner = TextTestRunner(verbosity=2) - test_dir = os.path.dirname(__file__) - - test_loader = TestLoader() - suite = test_loader.discover(test_dir, pattern="unittest_*.py") - runner.run(suite) diff --git a/src/client/Python/msrestazure/test/unittest_auth.py b/src/client/Python/msrestazure/test/unittest_auth.py deleted file mode 100644 index 363b4b835d..0000000000 --- a/src/client/Python/msrestazure/test/unittest_auth.py +++ /dev/null @@ -1,361 +0,0 @@ -#-------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -#-------------------------------------------------------------------------- - -import json -import sys -import unittest -try: - from unittest import mock -except ImportError: - import mock - -from requests_oauthlib import OAuth2Session -import oauthlib - -from msrestazure import AzureConfiguration -from msrestazure import azure_active_directory -from msrestazure.azure_active_directory import ( - AADMixin, - InteractiveCredentials, - ServicePrincipalCredentials, - UserPassCredentials - ) -from msrest.exceptions import ( - TokenExpiredError, - AuthenticationError, - ) - - -class TestInteractiveCredentials(unittest.TestCase): - - def setUp(self): - self.cfg = AzureConfiguration("https://my_service.com") - return super(TestInteractiveCredentials, self).setUp() - - def test_http(self): - - test_uri = "http://my_service.com" - build = azure_active_directory._http(test_uri, "path") - - self.assertEqual(build, "http://my_service.com/path") - - test_uri = "HTTPS://my_service.com" - build = azure_active_directory._http(test_uri, "path") - - self.assertEqual(build, "http://my_service.com/path") - - test_uri = "my_service.com" - build = azure_active_directory._http(test_uri, "path") - - self.assertEqual(build, "http://my_service.com/path") - - def test_https(self): - - test_uri = "http://my_service.com" - build = azure_active_directory._https(test_uri, "path") - - self.assertEqual(build, "https://my_service.com/path") - - test_uri = "HTTPS://my_service.com" - build = azure_active_directory._https(test_uri, "path") - - self.assertEqual(build, "https://my_service.com/path") - - test_uri = "my_service.com" - build = azure_active_directory._https(test_uri, "path") - - self.assertEqual(build, "https://my_service.com/path") - - - def test_check_state(self): - - mix = AADMixin(None, None) - mix.state = "abc" - - with self.assertRaises(ValueError): - mix._check_state("server?test") - with self.assertRaises(ValueError): - mix._check_state("server?test&abc") - with self.assertRaises(ValueError): - mix._check_state("server?test&state=xyx") - with self.assertRaises(ValueError): - mix._check_state("server?test&state=xyx&") - with self.assertRaises(ValueError): - mix._check_state("server?test&state=abcd&") - mix._check_state("server?test&state=abc&") - - def test_convert_token(self): - - mix = AADMixin(None, None) - token = {'access_token':'abc', 'expires_on':123, 'refresh_token':'asd'} - self.assertEqual(mix._convert_token(token), token) - - caps = {'accessToken':'abc', 'expiresOn':123, 'refreshToken':'asd'} - self.assertEqual(mix._convert_token(caps), token) - - caps = {'ACCessToken':'abc', 'Expires_On':123, 'REFRESH_TOKEN':'asd'} - self.assertEqual(mix._convert_token(caps), token) - - @mock.patch('msrestazure.azure_active_directory.keyring') - def test_store_token(self, mock_keyring): - - mix = AADMixin(None, None) - mix.cred_store = "store_name" - mix.store_key = "client_id" - mix._default_token_cache({'token_type':'1', 'access_token':'2'}) - - mock_keyring.set_password.assert_called_with( - "store_name", "client_id", - str({'token_type':'1', 'access_token':'2'})) - - @mock.patch('msrestazure.azure_active_directory.keyring') - def test_clear_token(self, mock_keyring): - - mix = AADMixin(None, None) - mix.cred_store = "store_name" - mix.store_key = "client_id" - mix.clear_cached_token() - - mock_keyring.delete_password.assert_called_with( - "store_name", "client_id") - - @mock.patch('msrestazure.azure_active_directory.keyring') - def test_credentials_get_stored_auth(self, mock_keyring): - - mix = AADMixin(None, None) - mix.cred_store = "store_name" - mix.store_key = "client_id" - mix.signed_session = mock.Mock() - - mock_keyring.get_password.return_value = None - - with self.assertRaises(ValueError): - mix._retrieve_stored_token() - - mock_keyring.get_password.assert_called_with( - "store_name", "client_id") - - mock_keyring.get_password.return_value = str( - {'token_type':'1', 'access_token':'2'}) - - mix._retrieve_stored_token() - mock_keyring.get_password.assert_called_with("store_name", "client_id") - - @mock.patch.object(AADMixin, '_retrieve_stored_token') - def test_credentials_retrieve_session(self, mock_retrieve): - - creds = InteractiveCredentials.retrieve_session("client_id", "redirect") - mock_retrieve.asset_called_with(mock.ANY) - - mock_retrieve.side_effect = ValueError("No stored token") - with self.assertRaises(ValueError): - InteractiveCredentials.retrieve_session("client_id", "redirect") - - mock_retrieve.side_effect = TokenExpiredError("Token expired") - with self.assertRaises(TokenExpiredError): - InteractiveCredentials.retrieve_session("client_id", "redirect") - - def test_credentials_auth_url(self): - - creds = mock.create_autospec(InteractiveCredentials) - session = mock.create_autospec(OAuth2Session) - creds._setup_session.return_value = session - creds.auth_uri = "auth_uri" - creds.resource = "auth_resource" - session.authorization_url.return_value = ("a","b") - - url, state = InteractiveCredentials.get_auth_url(creds) - self.assertEqual(url, "a") - self.assertEqual(state, "b") - session.authorization_url.assert_called_with( - "auth_uri", resource="auth_resource") - - InteractiveCredentials.get_auth_url(creds, msa=True, test="extra_arg") - session.authorization_url.assert_called_with( - "auth_uri", resource="auth_resource", - domain_hint='live.com', test='extra_arg') - - def test_credentials_get_token(self): - - creds = mock.create_autospec(InteractiveCredentials) - session = mock.create_autospec(OAuth2Session) - creds._setup_session.return_value = session - - session.fetch_token.return_value = { - 'expires_at':'1', - 'expires_in':'2', - 'refresh_token':"test"} - - creds.redirect = "//my_service.com" - creds.token_uri = "token_uri" - creds._check_state.return_value = True - creds.verify = True - - InteractiveCredentials.set_token(creds, "response") - self.assertEqual(creds.token, session.fetch_token.return_value) - session.fetch_token.assert_called_with( - "token_uri", - authorization_response="https://my_service.com/response", - verify=True) - - creds._check_state.side_effect = ValueError("failed") - with self.assertRaises(ValueError): - InteractiveCredentials.set_token(creds, "response") - - creds._check_state.side_effect = None - session.fetch_token.side_effect = oauthlib.oauth2.OAuth2Error - with self.assertRaises(AuthenticationError): - InteractiveCredentials.set_token(creds, "response") - - @mock.patch('msrestazure.azure_active_directory.oauth') - def test_credentials_signed_session(self, mock_requests): - - creds = mock.create_autospec(InteractiveCredentials) - creds._parse_token = lambda: AADMixin._parse_token(creds) - creds.id = 'client_id' - creds.token_uri = "token_uri" - creds.resource = "resource" - - creds.token = {'expires_at':'1', - 'expires_in':'2', - 'refresh_token':"test"} - - AADMixin.signed_session(creds) - mock_requests.OAuth2Session.assert_called_with( - 'client_id', - token=creds.token, - auto_refresh_url='token_uri', - auto_refresh_kwargs={'client_id':'client_id', 'resource':'resource'}, - token_updater=creds._default_token_cache) - - def test_service_principal(self): - - creds = mock.create_autospec(ServicePrincipalCredentials) - session = mock.create_autospec(OAuth2Session) - creds._setup_session.return_value = session - - session.fetch_token.return_value = { - 'expires_at':'1', - 'expires_in':'2'} - - creds.token_uri = "token_uri" - creds.verify = True - creds.id = 123 - creds.secret = 'secret' - creds.resource = 'resource' - - ServicePrincipalCredentials.set_token(creds) - self.assertEqual(creds.token, session.fetch_token.return_value) - session.fetch_token.assert_called_with( - "token_uri", client_id=123, client_secret='secret', - resource='resource', response_type="client_credentials", - verify=True) - - session.fetch_token.side_effect = oauthlib.oauth2.OAuth2Error - - with self.assertRaises(AuthenticationError): - ServicePrincipalCredentials.set_token(creds) - - session = mock.create_autospec(OAuth2Session) - with mock.patch.object( - ServicePrincipalCredentials, '_setup_session', return_value=session): - - creds = ServicePrincipalCredentials("client_id", "secret", - verify=False, tenant="private") - - session.fetch_token.assert_called_with( - "https://login.microsoftonline.com/private/oauth2/token", - client_id="client_id", client_secret='secret', - resource='https://management.core.windows.net/', - response_type="client_credentials", verify=False) - - with mock.patch.object( - ServicePrincipalCredentials, '_setup_session', return_value=session): - - creds = ServicePrincipalCredentials("client_id", "secret", china=True, - verify=False, tenant="private") - - session.fetch_token.assert_called_with( - "https://login.chinacloudapi.cn/private/oauth2/token", - client_id="client_id", client_secret='secret', - resource='https://management.core.chinacloudapi.cn/', - response_type="client_credentials", verify=False) - - def test_user_pass_credentials(self): - - creds = mock.create_autospec(UserPassCredentials) - session = mock.create_autospec(OAuth2Session) - creds._setup_session.return_value = session - - session.fetch_token.return_value = { - 'expires_at':'1', - 'expires_in':'2'} - - creds.token_uri = "token_uri" - creds.verify = True - creds.username = "user" - creds.password = 'pass' - creds.secret = 'secret' - creds.resource = 'resource' - creds.id = "id" - - UserPassCredentials.set_token(creds) - self.assertEqual(creds.token, session.fetch_token.return_value) - session.fetch_token.assert_called_with( - "token_uri", client_id="id", username='user', - client_secret="secret", password='pass', resource='resource', verify=True) - - session.fetch_token.side_effect = oauthlib.oauth2.OAuth2Error - - with self.assertRaises(AuthenticationError): - UserPassCredentials.set_token(creds) - - session = mock.create_autospec(OAuth2Session) - with mock.patch.object( - UserPassCredentials, '_setup_session', return_value=session): - - creds = UserPassCredentials("my_username", "my_password", - verify=False, tenant="private", resource='resource') - - session.fetch_token.assert_called_with( - "https://login.microsoftonline.com/private/oauth2/token", - client_id='04b07795-8ddb-461a-bbee-02f9e1bf7b46', username='my_username', - password='my_password', resource='resource', verify=False) - - with mock.patch.object( - UserPassCredentials, '_setup_session', return_value=session): - - creds = UserPassCredentials("my_username", "my_password", client_id="client_id", - verify=False, tenant="private", china=True) - - session.fetch_token.assert_called_with( - "https://login.chinacloudapi.cn/private/oauth2/token", - client_id="client_id", username='my_username', - password='my_password', resource='https://management.core.chinacloudapi.cn/', verify=False) - - -if __name__ == '__main__': - unittest.main() \ No newline at end of file diff --git a/src/client/Python/msrestazure/test/unittest_exceptions.py b/src/client/Python/msrestazure/test/unittest_exceptions.py deleted file mode 100644 index d263568eb7..0000000000 --- a/src/client/Python/msrestazure/test/unittest_exceptions.py +++ /dev/null @@ -1,204 +0,0 @@ -#-------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -#-------------------------------------------------------------------------- - -import json -import unittest -try: - from unittest import mock -except ImportError: - import mock - -from requests import Response - -from msrest import Deserializer, Configuration -from msrest.exceptions import RequestException -from msrestazure.azure_exceptions import CloudErrorData, CloudError - - -class TestCloudException(unittest.TestCase): - - def setUp(self): - self.cfg = Configuration("https://my_endpoint.com") - self._d = Deserializer() - self._d.dependencies = {'CloudErrorData': CloudErrorData} - return super(TestCloudException, self).setUp() - - def test_cloud_exception(self): - - message = { - 'code': '500', - 'message': 'Bad Request', - 'values': {'invalid_attribute':'data'} - } - - cloud_exp = self._d(CloudErrorData(), message) - self.assertEqual(cloud_exp.message, 'Bad Request') - self.assertEqual(cloud_exp.error, '500') - self.assertEqual(cloud_exp.data['invalid_attribute'], 'data') - - message = { - 'code': '500', - 'message': {'value': 'Bad Request\nRequest:34875\nTime:1999-12-31T23:59:59-23:59'}, - 'values': {'invalid_attribute':'data'} - } - - cloud_exp = self._d(CloudErrorData(), message) - self.assertEqual(cloud_exp.message, 'Bad Request') - self.assertEqual(cloud_exp.error, '500') - self.assertEqual(cloud_exp.data['invalid_attribute'], 'data') - - message = { - 'code': '500', - 'message': {'value': 'Bad Request\nRequest:34875'}, - 'values': {'invalid_attribute':'data'} - } - - cloud_exp = self._d(CloudErrorData(), message) - self.assertEqual(cloud_exp.message, 'Bad Request') - self.assertEqual(cloud_exp.request_id, '34875') - self.assertEqual(cloud_exp.error, '500') - self.assertEqual(cloud_exp.data['invalid_attribute'], 'data') - - message = {} - cloud_exp = self._d(CloudErrorData(), message) - self.assertEqual(cloud_exp.message, None) - self.assertEqual(cloud_exp.error, None) - - message = ('{\r\n "odata.metadata":"https://account.region.batch.azure.com/$metadata#' - 'Microsoft.Azure.Batch.Protocol.Entities.Container.errors/@Element","code":' - '"InvalidHeaderValue","message":{\r\n "lang":"en-US","value":"The value ' - 'for one of the HTTP headers is not in the correct format.\\nRequestId:5f4c1f05-' - '603a-4495-8e80-01f776310bbd\\nTime:2016-01-04T22:12:33.9245931Z"\r\n },' - '"values":[\r\n {\r\n "key":"HeaderName","value":"Content-Type"\r\n }' - ',{\r\n "key":"HeaderValue","value":"application/json; odata=minimalmetadata;' - ' charset=utf-8"\r\n }\r\n ]\r\n}') - message = json.loads(message) - cloud_exp = self._d(CloudErrorData(), message) - self.assertEqual( - cloud_exp.message, - "The value for one of the HTTP headers is not in the correct format.") - - message = { - "code": "BadArgument", - "message": "The provided database 'foo' has an invalid username.", - "target": "query", - "details": [ - { - "code": "301", - "target": "$search", - "message": "$search query option not supported", - } - ] - } - cloud_exp = self._d(CloudErrorData(), message) - self.assertEqual(cloud_exp.target, 'query') - self.assertEqual(cloud_exp.details[0].target, '$search') - - - - def test_cloud_error(self): - - response = mock.create_autospec(Response) - response.status_code = 400 - response.reason = 'BadRequest' - - message = { - 'code': '500', - 'message': {'value': 'Bad Request\nRequest:34875\nTime:1999-12-31T23:59:59-23:59'}, - 'values': {'invalid_attribute':'data'} - } - - response.content = json.dumps(message) - response.json = lambda: json.loads(response.content) - - error = CloudError(response) - self.assertEqual(error.message, 'Bad Request') - self.assertEqual(error.status_code, 400) - self.assertIsInstance(error.error, CloudErrorData) - - message = { 'error': { - 'code': '500', - 'message': {'value': 'Bad Request\nRequest:34875\nTime:1999-12-31T23:59:59-23:59'}, - 'values': {'invalid_attribute':'data'} - }} - - response.content = json.dumps(message) - error = CloudError(response) - self.assertEqual(error.message, 'Bad Request') - self.assertEqual(error.status_code, 400) - self.assertIsInstance(error.error, CloudErrorData) - - error = CloudError(response, "Request failed with bad status") - self.assertEqual(error.message, "Request failed with bad status") - self.assertEqual(error.status_code, 400) - self.assertIsInstance(error.error, Response) - - response.content = "{" - error = CloudError(response) - self.assertTrue("none" in error.message) - - response.content = json.dumps({'message':'server error'}) - error = CloudError(response) - self.assertTrue("server error" in error.message) - self.assertEqual(error.status_code, 400) - - response.content = "{" - response.raise_for_status.side_effect = RequestException("FAILED!") - error = CloudError(response) - self.assertTrue("FAILED!" in error.message) - self.assertIsInstance(error.error, RequestException) - - response.raise_for_status.side_effect = None - - response.content = '{\r\n "odata.metadata":"https://account.region.batch.azure.com/$metadata#Microsoft.Azure.Batch.Protocol.Entities.Container.errors/@Element","code":"InvalidHeaderValue","message":{\r\n "lang":"en-US","value":"The value for one of the HTTP headers is not in the correct format.\\nRequestId:5f4c1f05-603a-4495-8e80-01f776310bbd\\nTime:2016-01-04T22:12:33.9245931Z"\r\n },"values":[\r\n {\r\n "key":"HeaderName","value":"Content-Type"\r\n },{\r\n "key":"HeaderValue","value":"application/json; odata=minimalmetadata; charset=utf-8"\r\n }\r\n ]\r\n}' - error = CloudError(response) - self.assertIsInstance(error.error, CloudErrorData) - - response.content = '{"code":"Conflict","message":"The maximum number of Free ServerFarms allowed in a Subscription is 10.","target":null,"details":[{"message":"The maximum number of Free ServerFarms allowed in a Subscription is 10."},{"code":"Conflict"},{"errorentity":{"code":"Conflict","message":"The maximum number of Free ServerFarms allowed in a Subscription is 10.","extendedCode":"59301","messageTemplate":"The maximum number of {0} ServerFarms allowed in a Subscription is {1}.","parameters":["Free","10"],"innerErrors":null}}],"innererror":null}' - error = CloudError(response) - self.assertIsInstance(error.error, CloudErrorData) - self.assertEqual(error.error.error, "Conflict") - - response.content = json.dumps({ - "error": { - "code": "BadArgument", - "message": "The provided database 'foo' has an invalid username.", - "target": "query", - "details": [ - { - "code": "301", - "target": "$search", - "message": "$search query option not supported", - } - ] - }}) - error = CloudError(response) - self.assertIsInstance(error.error, CloudErrorData) - self.assertEqual(error.error.error, "BadArgument") - - -if __name__ == '__main__': - unittest.main() diff --git a/src/client/Python/msrestazure/test/unittest_operation.py b/src/client/Python/msrestazure/test/unittest_operation.py deleted file mode 100644 index ff5a89497b..0000000000 --- a/src/client/Python/msrestazure/test/unittest_operation.py +++ /dev/null @@ -1,312 +0,0 @@ -#-------------------------------------------------------------------------- -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# -# The MIT License (MIT) -# -# 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. -# -#-------------------------------------------------------------------------- - -import json -import re -import unittest -try: - from unittest import mock -except ImportError: - import mock - -from requests import Request, Response - -from msrest import Deserializer -from msrest.exceptions import RequestException, DeserializationError -from msrestazure.azure_exceptions import CloudError -from msrestazure.azure_operation import ( - LongRunningOperation, - AzureOperationPoller, - BadStatus, - SimpleResource) - -class BadEndpointError(Exception): - pass - -TEST_NAME = 'foo' -RESPONSE_BODY = {'properties':{'provisioningState': 'InProgress'}} -ASYNC_BODY = json.dumps({ 'status': 'Succeeded' }) -ASYNC_URL = 'http://dummyurlFromAzureAsyncOPHeader_Return200' -LOCATION_BODY = json.dumps({ 'name': TEST_NAME }) -LOCATION_URL = 'http://dummyurlurlFromLocationHeader_Return200' -RESOURCE_BODY = json.dumps({ 'name': TEST_NAME }) -RESOURCE_URL = 'http://subscriptions/sub1/resourcegroups/g1/resourcetype1/resource1' -ERROR = 'http://dummyurl_ReturnError' -POLLING_STATUS = 200 - -class TestLongRunningOperation(unittest.TestCase): - - convert = re.compile('([a-z0-9])([A-Z])') - - @staticmethod - def mock_send(method, status, headers, body=None): - response = mock.create_autospec(Response) - response.request = mock.create_autospec(Request) - response.request.method = method - response.request.url = RESOURCE_URL - response.status_code = status - response.headers = headers - content = body if body else RESPONSE_BODY - response.content = json.dumps(content) - response.json = lambda: json.loads(response.content) - return lambda: response - - @staticmethod - def mock_update(url, headers=None): - response = mock.create_autospec(Response) - response.request = mock.create_autospec(Request) - response.request.method = 'GET' - - if url == ASYNC_URL: - response.request.url = url - response.status_code = POLLING_STATUS - response.content = ASYNC_BODY - response.randomFieldFromPollAsyncOpHeader = None - - elif url == LOCATION_URL: - response.request.url = url - response.status_code = POLLING_STATUS - response.content = LOCATION_BODY - response.randomFieldFromPollLocationHeader = None - - elif url == ERROR: - raise BadEndpointError("boom") - - elif url == RESOURCE_URL: - response.request.url = url - response.status_code = POLLING_STATUS - response.content = RESOURCE_BODY - - else: - raise Exception('URL does not match') - response.json = lambda: json.loads(response.content) - return response - - @staticmethod - def mock_outputs(response): - body = response.json() - body = {TestLongRunningOperation.convert.sub(r'\1_\2', k).lower(): v - for k, v in body.items()} - properties = body.get('properties') - if properties: - properties = {TestLongRunningOperation.convert.sub(r'\1_\2', k).lower(): v - for k, v in properties.items()} - del body['properties'] - body.update(properties) - resource = SimpleResource(**body) - else: - resource = SimpleResource(**body) - return resource - - def test_long_running_put(self): - #TODO: Test custom header field - - # Test throw on non LRO related status code - response = TestLongRunningOperation.mock_send('PUT', 1000, {}) - op = LongRunningOperation(response(), lambda x:None) - with self.assertRaises(BadStatus): - op.get_initial_status(response()) - with self.assertRaises(CloudError): - AzureOperationPoller(response, - TestLongRunningOperation.mock_outputs, - TestLongRunningOperation.mock_update, 0).result() - - # Test polling from azure-asyncoperation header - response = TestLongRunningOperation.mock_send( - 'PUT', 201, - {'azure-asyncoperation': ASYNC_URL}) - poll = AzureOperationPoller(response, - TestLongRunningOperation.mock_outputs, - TestLongRunningOperation.mock_update, 0) - self.assertEqual(poll.result().name, TEST_NAME) - self.assertFalse(hasattr(poll._response, 'randomFieldFromPollAsyncOpHeader')) - - # Test polling location header - response = TestLongRunningOperation.mock_send( - 'PUT', 201, - {'location': LOCATION_URL}) - poll = AzureOperationPoller(response, - TestLongRunningOperation.mock_outputs, - TestLongRunningOperation.mock_update, 0) - self.assertEqual(poll.result().name, TEST_NAME) - self.assertIsNone(poll._response.randomFieldFromPollLocationHeader) - - # Test fail to poll from azure-asyncoperation header - response = TestLongRunningOperation.mock_send( - 'PUT', 201, - {'azure-asyncoperation': ERROR}) - with self.assertRaises(BadEndpointError): - poll = AzureOperationPoller(response, - TestLongRunningOperation.mock_outputs, - TestLongRunningOperation.mock_update, 0).result() - - # Test fail to poll from location header - response = TestLongRunningOperation.mock_send( - 'PUT', 201, - {'location': ERROR}) - with self.assertRaises(BadEndpointError): - poll = AzureOperationPoller(response, - TestLongRunningOperation.mock_outputs, - TestLongRunningOperation.mock_update, 0).result() - - def test_long_running_patch(self): - - # Test polling from location header - response = TestLongRunningOperation.mock_send( - 'PATCH', 202, - {'location': LOCATION_URL}, - body={'properties':{'provisioningState': 'Succeeded'}}) - poll = AzureOperationPoller(response, - TestLongRunningOperation.mock_outputs, - TestLongRunningOperation.mock_update, 0) - self.assertEqual(poll.result().name, TEST_NAME) - self.assertIsNone(poll._response.randomFieldFromPollLocationHeader) - - # Test polling from azure-asyncoperation header - response = TestLongRunningOperation.mock_send( - 'PATCH', 202, - {'azure-asyncoperation': ASYNC_URL}, - body={'properties':{'provisioningState': 'Succeeded'}}) - poll = AzureOperationPoller(response, - TestLongRunningOperation.mock_outputs, - TestLongRunningOperation.mock_update, 0) - self.assertEqual(poll.result().name, TEST_NAME) - self.assertFalse(hasattr(poll._response, 'randomFieldFromPollAsyncOpHeader')) - - # Test fail to poll from azure-asyncoperation header - response = TestLongRunningOperation.mock_send( - 'PATCH', 202, - {'azure-asyncoperation': ERROR}) - with self.assertRaises(BadEndpointError): - poll = AzureOperationPoller(response, - TestLongRunningOperation.mock_outputs, - TestLongRunningOperation.mock_update, 0).result() - - # Test fail to poll from location header - response = TestLongRunningOperation.mock_send( - 'PATCH', 202, - {'location': ERROR}) - with self.assertRaises(BadEndpointError): - poll = AzureOperationPoller(response, - TestLongRunningOperation.mock_outputs, - TestLongRunningOperation.mock_update, 0).result() - - def test_long_running_post_delete(self): - - # Test throw on non LRO related status code - response = TestLongRunningOperation.mock_send('POST', 201, {}) - op = LongRunningOperation(response(), lambda x:None) - with self.assertRaises(BadStatus): - op.get_initial_status(response()) - with self.assertRaises(CloudError): - AzureOperationPoller(response, - TestLongRunningOperation.mock_outputs, - TestLongRunningOperation.mock_update, 0).result() - - # Test polling from azure-asyncoperation header - response = TestLongRunningOperation.mock_send( - 'POST', 202, - {'azure-asyncoperation': ASYNC_URL}, - body={'properties':{'provisioningState': 'Succeeded'}}) - poll = AzureOperationPoller(response, - TestLongRunningOperation.mock_outputs, - TestLongRunningOperation.mock_update, 0) - poll.wait() - #self.assertIsNone(poll.result()) - self.assertIsNone(poll._response.randomFieldFromPollAsyncOpHeader) - - # Test polling from location header - response = TestLongRunningOperation.mock_send( - 'POST', 202, - {'location': LOCATION_URL}, - body={'properties':{'provisioningState': 'Succeeded'}}) - poll = AzureOperationPoller(response, - TestLongRunningOperation.mock_outputs, - TestLongRunningOperation.mock_update, 0) - self.assertEqual(poll.result().name, TEST_NAME) - self.assertIsNone(poll._response.randomFieldFromPollLocationHeader) - - # Test fail to poll from azure-asyncoperation header - response = TestLongRunningOperation.mock_send( - 'POST', 202, - {'azure-asyncoperation': ERROR}) - with self.assertRaises(BadEndpointError): - poll = AzureOperationPoller(response, - TestLongRunningOperation.mock_outputs, - TestLongRunningOperation.mock_update, 0).result() - - # Test fail to poll from location header - response = TestLongRunningOperation.mock_send( - 'POST', 202, - {'location': ERROR}) - with self.assertRaises(BadEndpointError): - poll = AzureOperationPoller(response, - TestLongRunningOperation.mock_outputs, - TestLongRunningOperation.mock_update, 0).result() - - def test_long_running_negative(self): - global LOCATION_BODY - global POLLING_STATUS - - # Test LRO PUT throws for invalid json - LOCATION_BODY = '{' - response = TestLongRunningOperation.mock_send( - 'POST', 202, - {'location': LOCATION_URL}) - poll = AzureOperationPoller(response, - TestLongRunningOperation.mock_outputs, - TestLongRunningOperation.mock_update, 0) - with self.assertRaises(DeserializationError): - poll.wait() - - LOCATION_BODY = '{\'"}' - response = TestLongRunningOperation.mock_send( - 'POST', 202, - {'location': LOCATION_URL}) - poll = AzureOperationPoller(response, - TestLongRunningOperation.mock_outputs, - TestLongRunningOperation.mock_update, 0) - with self.assertRaises(DeserializationError): - poll.wait() - - LOCATION_BODY = '{' - POLLING_STATUS = 203 - response = TestLongRunningOperation.mock_send( - 'POST', 202, - {'location': LOCATION_URL}) - poll = AzureOperationPoller(response, - TestLongRunningOperation.mock_outputs, - TestLongRunningOperation.mock_update, 0) - with self.assertRaises(CloudError): # TODO: Node.js raises on deserialization - poll.wait() - - LOCATION_BODY = json.dumps({ 'name': TEST_NAME }) - POLLING_STATUS = 200 - - - -if __name__ == '__main__': - unittest.main() diff --git a/src/client/Python/msrestazure/tox.ini b/src/client/Python/msrestazure/tox.ini deleted file mode 100644 index 57806b2d72..0000000000 --- a/src/client/Python/msrestazure/tox.ini +++ /dev/null @@ -1,34 +0,0 @@ -[tox] -envlist=py27, py35 -skipsdist=True - -[testenv] -changedir=test -commands= - coverage run -m unittest discover -s . -p unittest*.py -t .. -v - coverage report --fail-under=30 --omit=*test*,*.tox*.py --include=*msrestazure* - #flake8 .. --exclude=unittest*.py,doc --statistics - -[testenv:py27] -deps= - -rrequirements27.txt - coverage - flake8 - -[testenv:py33] -deps= - -rrequirements27.txt - coverage - flake8 - -[testenv:py34] -deps= - -rrequirements35.txt - coverage - flake8 - -[testenv:py35] -deps= - -rrequirements35.txt - coverage - flake8 \ No newline at end of file