From 5693dd4d14759ae32f3e3a024e34777fad998db2 Mon Sep 17 00:00:00 2001 From: Laurent Mazuel Date: Wed, 3 Jun 2020 10:58:22 -0700 Subject: [PATCH 01/25] Whitelist what pickle is serializing in context (#11688) * Whitelist what pickle is serializing in context * Indent --- .../azure/core/pipeline/__init__.py | 18 +++++++++++ .../tests/test_universal_pipeline.py | 32 +++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/sdk/core/azure-core/azure/core/pipeline/__init__.py b/sdk/core/azure-core/azure/core/pipeline/__init__.py index cec8606569ae..baeea6db1c7a 100644 --- a/sdk/core/azure-core/azure/core/pipeline/__init__.py +++ b/sdk/core/azure-core/azure/core/pipeline/__init__.py @@ -63,6 +63,9 @@ class PipelineContext(dict): :param transport: The HTTP transport type. :param kwargs: Developer-defined keyword arguments. """ + _PICKLE_CONTEXT = { + 'deserialized_data' + } def __init__(self, transport, **kwargs): # pylint: disable=super-init-not-called self.transport = transport @@ -75,6 +78,21 @@ def __getstate__(self): del state['transport'] return state + def __reduce__(self): + reduced = super(PipelineContext, self).__reduce__() + saved_context = {} + for key, value in self.items(): + if key in self._PICKLE_CONTEXT: + saved_context[key] = value + # 1 is for from __reduce__ spec of pickle (generic args for recreation) + # 2 is how dict is implementing __reduce__ (dict specific) + # tuple are read-only, we use a list in the meantime + reduced = list(reduced) + dict_reduced_result = list(reduced[1]) + dict_reduced_result[2] = saved_context + reduced[1] = tuple(dict_reduced_result) + return tuple(reduced) + def __setstate__(self, state): self.__dict__.update(state) # Re-create the unpickable entries diff --git a/sdk/core/azure-core/tests/test_universal_pipeline.py b/sdk/core/azure-core/tests/test_universal_pipeline.py index 51f735c2da09..40223f06965f 100644 --- a/sdk/core/azure-core/tests/test_universal_pipeline.py +++ b/sdk/core/azure-core/tests/test_universal_pipeline.py @@ -25,6 +25,7 @@ # #-------------------------------------------------------------------------- import logging +import pickle try: from unittest import mock except ImportError: @@ -56,6 +57,37 @@ HTTPPolicy, ) +def test_pipeline_context(): + kwargs={ + 'stream':True, + 'cont_token':"bla" + } + context = PipelineContext('transport', **kwargs) + context['foo'] = 'bar' + context['xyz'] = '123' + context['deserialized_data'] = 'marvelous' + + assert context['foo'] == 'bar' + assert context.options == kwargs + + with pytest.raises(TypeError): + context.clear() + + with pytest.raises(TypeError): + context.update({}) + + assert context.pop('foo') == 'bar' + assert 'foo' not in context + + serialized = pickle.dumps(context) + + revived_context = pickle.loads(serialized) + assert revived_context.options == kwargs + assert revived_context.transport is None + assert 'deserialized_data' in revived_context + assert len(revived_context) == 1 + + def test_request_history(): class Non_deep_copiable(object): def __deepcopy__(self, memodict={}): From 6123e8fea056c51ecfba3d9bb8a953942f9422c9 Mon Sep 17 00:00:00 2001 From: iscai-msft <43154838+iscai-msft@users.noreply.github.com> Date: Wed, 3 Jun 2020 15:21:30 -0400 Subject: [PATCH 02/25] [text analytics] param to ivar in model docstrings (#11788) --- .../azure/ai/textanalytics/_models.py | 260 +++++++++--------- 1 file changed, 130 insertions(+), 130 deletions(-) diff --git a/sdk/textanalytics/azure-ai-textanalytics/azure/ai/textanalytics/_models.py b/sdk/textanalytics/azure-ai-textanalytics/azure/ai/textanalytics/_models.py index 692178449da8..1b1bf19b29b8 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/azure/ai/textanalytics/_models.py +++ b/sdk/textanalytics/azure-ai-textanalytics/azure/ai/textanalytics/_models.py @@ -63,15 +63,15 @@ class DetectedLanguage(DictMixin): """DetectedLanguage contains the predicted language found in text, its confidence score, and ISO 639-1 representation. - :param name: Long name of a detected language (e.g. English, + :ivar name: Long name of a detected language (e.g. English, French). - :type name: str - :param iso6391_name: A two letter representation of the detected + :vartype name: str + :ivar iso6391_name: A two letter representation of the detected language according to the ISO 639-1 standard (e.g. en, fr). - :type iso6391_name: str - :param confidence_score: A confidence score between 0 and 1. Scores close + :vartype iso6391_name: str + :ivar confidence_score: A confidence score between 0 and 1. Scores close to 1 indicate 100% certainty that the identified language is true. - :type confidence_score: float + :vartype confidence_score: float """ def __init__(self, **kwargs): @@ -94,21 +94,21 @@ class RecognizeEntitiesResult(DictMixin): """RecognizeEntitiesResult is a result object which contains the recognized entities from a particular document. - :param id: Unique, non-empty document identifier that matches the + :ivar id: Unique, non-empty document identifier that matches the document id that was passed in with the request. If not specified in the request, an id is assigned for the document. - :type id: str - :param entities: Recognized entities in the document. - :type entities: + :vartype id: str + :ivar entities: Recognized entities in the document. + :vartype entities: list[~azure.ai.textanalytics.CategorizedEntity] - :param warnings: Warnings encountered while processing document. Results will still be returned + :ivar warnings: Warnings encountered while processing document. Results will still be returned if there are warnings, but they may not be fully accurate. - :type warnings: list[~azure.ai.textanalytics.TextAnalyticsWarning] - :param statistics: If show_stats=true was specified in the request this + :vartype warnings: list[~azure.ai.textanalytics.TextAnalyticsWarning] + :ivar statistics: If show_stats=true was specified in the request this field will contain information about the document payload. - :type statistics: + :vartype statistics: ~azure.ai.textanalytics.TextDocumentStatistics - :param bool is_error: Boolean check for error item when iterating over list of + :ivar bool is_error: Boolean check for error item when iterating over list of results. Always False for an instance of a RecognizeEntitiesResult. """ @@ -128,20 +128,20 @@ class DetectLanguageResult(DictMixin): """DetectLanguageResult is a result object which contains the detected language of a particular document. - :param id: Unique, non-empty document identifier that matches the + :ivar id: Unique, non-empty document identifier that matches the document id that was passed in with the request. If not specified in the request, an id is assigned for the document. - :type id: str - :param primary_language: The primary language detected in the document. - :type primary_language: ~azure.ai.textanalytics.DetectedLanguage - :param warnings: Warnings encountered while processing document. Results will still be returned + :vartype id: str + :ivar primary_language: The primary language detected in the document. + :vartype primary_language: ~azure.ai.textanalytics.DetectedLanguage + :ivar warnings: Warnings encountered while processing document. Results will still be returned if there are warnings, but they may not be fully accurate. - :type warnings: list[~azure.ai.textanalytics.TextAnalyticsWarning] - :param statistics: If show_stats=true was specified in the request this + :vartype warnings: list[~azure.ai.textanalytics.TextAnalyticsWarning] + :ivar statistics: If show_stats=true was specified in the request this field will contain information about the document payload. - :type statistics: + :vartype statistics: ~azure.ai.textanalytics.TextDocumentStatistics - :param bool is_error: Boolean check for error item when iterating over list of + :ivar bool is_error: Boolean check for error item when iterating over list of results. Always False for an instance of a DetectLanguageResult. """ @@ -162,15 +162,15 @@ class CategorizedEntity(DictMixin): """CategorizedEntity contains information about a particular entity found in text. - :param text: Entity text as appears in the request. - :type text: str - :param category: Entity category, such as Person/Location/Org/SSN etc - :type category: str - :param subcategory: Entity subcategory, such as Age/Year/TimeRange etc - :type subcategory: str - :param confidence_score: Confidence score between 0 and 1 of the extracted + :ivar text: Entity text as appears in the request. + :vartype text: str + :ivar category: Entity category, such as Person/Location/Org/SSN etc + :vartype category: str + :ivar subcategory: Entity subcategory, such as Age/Year/TimeRange etc + :vartype subcategory: str + :ivar confidence_score: Confidence score between 0 and 1 of the extracted entity. - :type confidence_score: float + :vartype confidence_score: float """ def __init__(self, **kwargs): @@ -199,16 +199,16 @@ class TextAnalyticsError(DictMixin): other details that explain why the batch or individual document failed to be processed by the service. - :param code: Error code. Possible values include: + :ivar code: Error code. Possible values include: 'invalidRequest', 'invalidArgument', 'internalServerError', 'serviceUnavailable', 'invalidParameterValue', 'invalidRequestBodyFormat', 'emptyRequest', 'missingInputRecords', 'invalidDocument', 'modelVersionIncorrect', 'invalidDocumentBatch', 'unsupportedLanguageCode', 'invalidCountryHint' - :type code: str - :param message: Error message. - :type message: str - :param target: Error target. - :type target: str + :vartype code: str + :ivar message: Error message. + :vartype message: str + :ivar target: Error target. + :vartype target: str """ def __init__(self, **kwargs): @@ -238,11 +238,11 @@ class TextAnalyticsWarning(DictMixin): """TextAnalyticsWarning contains the warning code and message that explains why the response has a warning. - :param code: Warning code. Possible values include: 'LongWordsInDocument', + :ivar code: Warning code. Possible values include: 'LongWordsInDocument', 'DocumentTruncated'. - :type code: str - :param message: Warning message. - :type message: str + :vartype code: str + :ivar message: Warning message. + :vartype message: str """ def __init__(self, **kwargs): @@ -265,22 +265,22 @@ class ExtractKeyPhrasesResult(DictMixin): """ExtractKeyPhrasesResult is a result object which contains the key phrases found in a particular document. - :param id: Unique, non-empty document identifier that matches the + :ivar id: Unique, non-empty document identifier that matches the document id that was passed in with the request. If not specified in the request, an id is assigned for the document. - :type id: str - :param key_phrases: A list of representative words or phrases. + :vartype id: str + :ivar key_phrases: A list of representative words or phrases. The number of key phrases returned is proportional to the number of words in the input document. - :type key_phrases: list[str] - :param warnings: Warnings encountered while processing document. Results will still be returned + :vartype key_phrases: list[str] + :ivar warnings: Warnings encountered while processing document. Results will still be returned if there are warnings, but they may not be fully accurate. - :type warnings: list[~azure.ai.textanalytics.TextAnalyticsWarning] - :param statistics: If show_stats=true was specified in the request this + :vartype warnings: list[~azure.ai.textanalytics.TextAnalyticsWarning] + :ivar statistics: If show_stats=true was specified in the request this field will contain information about the document payload. - :type statistics: + :vartype statistics: ~azure.ai.textanalytics.TextDocumentStatistics - :param bool is_error: Boolean check for error item when iterating over list of + :ivar bool is_error: Boolean check for error item when iterating over list of results. Always False for an instance of a ExtractKeyPhrasesResult. """ @@ -300,21 +300,21 @@ class RecognizeLinkedEntitiesResult(DictMixin): """RecognizeLinkedEntitiesResult is a result object which contains links to a well-known knowledge base, like for example, Wikipedia or Bing. - :param id: Unique, non-empty document identifier that matches the + :ivar id: Unique, non-empty document identifier that matches the document id that was passed in with the request. If not specified in the request, an id is assigned for the document. - :type id: str - :param entities: Recognized well-known entities in the document. - :type entities: + :vartype id: str + :ivar entities: Recognized well-known entities in the document. + :vartype entities: list[~azure.ai.textanalytics.LinkedEntity] - :param warnings: Warnings encountered while processing document. Results will still be returned + :ivar warnings: Warnings encountered while processing document. Results will still be returned if there are warnings, but they may not be fully accurate. - :type warnings: list[~azure.ai.textanalytics.TextAnalyticsWarning] - :param statistics: If show_stats=true was specified in the request this + :vartype warnings: list[~azure.ai.textanalytics.TextAnalyticsWarning] + :ivar statistics: If show_stats=true was specified in the request this field will contain information about the document payload. - :type statistics: + :vartype statistics: ~azure.ai.textanalytics.TextDocumentStatistics - :param bool is_error: Boolean check for error item when iterating over list of + :ivar bool is_error: Boolean check for error item when iterating over list of results. Always False for an instance of a RecognizeLinkedEntitiesResult. """ @@ -335,29 +335,29 @@ class AnalyzeSentimentResult(DictMixin): the overall predicted sentiment and confidence scores for your document and a per-sentence sentiment prediction with scores. - :param id: Unique, non-empty document identifier that matches the + :ivar id: Unique, non-empty document identifier that matches the document id that was passed in with the request. If not specified in the request, an id is assigned for the document. - :type id: str - :param sentiment: Predicted sentiment for document (Negative, + :vartype id: str + :ivar sentiment: Predicted sentiment for document (Negative, Neutral, Positive, or Mixed). Possible values include: 'positive', 'neutral', 'negative', 'mixed' - :type sentiment: str - :param warnings: Warnings encountered while processing document. Results will still be returned + :vartype sentiment: str + :ivar warnings: Warnings encountered while processing document. Results will still be returned if there are warnings, but they may not be fully accurate. - :type warnings: list[~azure.ai.textanalytics.TextAnalyticsWarning] - :param statistics: If show_stats=true was specified in the request this + :vartype warnings: list[~azure.ai.textanalytics.TextAnalyticsWarning] + :ivar statistics: If show_stats=true was specified in the request this field will contain information about the document payload. - :type statistics: + :vartype statistics: ~azure.ai.textanalytics.TextDocumentStatistics - :param confidence_scores: Document level sentiment confidence + :ivar confidence_scores: Document level sentiment confidence scores between 0 and 1 for each sentiment label. - :type confidence_scores: + :vartype confidence_scores: ~azure.ai.textanalytics.SentimentConfidenceScores - :param sentences: Sentence level sentiment analysis. - :type sentences: + :ivar sentences: Sentence level sentiment analysis. + :vartype sentences: list[~azure.ai.textanalytics.SentenceSentiment] - :param bool is_error: Boolean check for error item when iterating over list of + :ivar bool is_error: Boolean check for error item when iterating over list of results. Always False for an instance of a AnalyzeSentimentResult. """ @@ -381,12 +381,12 @@ class TextDocumentStatistics(DictMixin): """TextDocumentStatistics contains information about the document payload. - :param character_count: Number of text elements recognized in + :ivar character_count: Number of text elements recognized in the document. - :type character_count: int - :param transaction_count: Number of transactions for the + :vartype character_count: int + :ivar transaction_count: Number of transactions for the document. - :type transaction_count: int + :vartype transaction_count: int """ def __init__(self, **kwargs): @@ -411,13 +411,13 @@ class DocumentError(DictMixin): """DocumentError is an error object which represents an error on the individual document. - :param id: Unique, non-empty document identifier that matches the + :ivar id: Unique, non-empty document identifier that matches the document id that was passed in with the request. If not specified in the request, an id is assigned for the document. - :type id: str - :param error: The document error. - :type error: ~azure.ai.textanalytics.TextAnalyticsError - :param bool is_error: Boolean check for error item when iterating over list of + :vartype id: str + :ivar error: The document error. + :vartype error: ~azure.ai.textanalytics.TextAnalyticsError + :ivar bool is_error: Boolean check for error item when iterating over list of results. Always True for an instance of a DocumentError. """ @@ -458,15 +458,15 @@ def __repr__(self): class DetectLanguageInput(LanguageInput): """The input document to be analyzed for detecting language. - :param id: Required. Unique, non-empty document identifier. - :type id: str - :param text: Required. The input text to process. - :type text: str - :param country_hint: A country hint to help better detect + :ivar id: Required. Unique, non-empty document identifier. + :vartype id: str + :ivar text: Required. The input text to process. + :vartype text: str + :ivar country_hint: A country hint to help better detect the language of the text. Accepts two letter country codes specified by ISO 3166-1 alpha-2. Defaults to "US". Pass in the string "none" to not use a country_hint. - :type country_hint: str + :vartype country_hint: str """ def __init__(self, **kwargs): @@ -486,21 +486,21 @@ class LinkedEntity(DictMixin): or Bing. It additionally includes all of the matches of this entity found in the document. - :param name: Entity Linking formal name. - :type name: str - :param matches: List of instances this entity appears in the text. - :type matches: + :ivar name: Entity Linking formal name. + :vartype name: str + :ivar matches: List of instances this entity appears in the text. + :vartype matches: list[~azure.ai.textanalytics.LinkedEntityMatch] - :param language: Language used in the data source. - :type language: str - :param data_source_entity_id: Unique identifier of the recognized entity from the data + :ivar language: Language used in the data source. + :vartype language: str + :ivar data_source_entity_id: Unique identifier of the recognized entity from the data source. - :type data_source_entity_id: str - :param url: URL to the entity's page from the data source. - :type url: str - :param data_source: Data source used to extract entity linking, + :vartype data_source_entity_id: str + :ivar url: URL to the entity's page from the data source. + :vartype url: str + :ivar data_source: Data source used to extract entity linking, such as Wiki/Bing etc. - :type data_source: str + :vartype data_source: str """ def __init__(self, **kwargs): @@ -533,12 +533,12 @@ class LinkedEntityMatch(DictMixin): the confidence score of the prediction and where the entity was found in the text. - :param confidence_score: If a well-known item is recognized, a + :ivar confidence_score: If a well-known item is recognized, a decimal number denoting the confidence level between 0 and 1 will be returned. - :type confidence_score: float - :param text: Entity text as appears in the request. - :type text: str + :vartype confidence_score: float + :ivar text: Entity text as appears in the request. + :vartype text: str """ def __init__(self, **kwargs): @@ -561,14 +561,14 @@ def __repr__(self): class TextDocumentInput(MultiLanguageInput): """The input document to be analyzed by the service. - :param id: Required. A unique, non-empty document identifier. - :type id: str - :param text: Required. The input text to process. - :type text: str - :param language: This is the 2 letter ISO 639-1 representation + :ivar id: Required. A unique, non-empty document identifier. + :vartype id: str + :ivar text: Required. The input text to process. + :vartype text: str + :ivar language: This is the 2 letter ISO 639-1 representation of a language. For example, use "en" for English; "es" for Spanish etc. If not set, uses "en" for English as default. - :type language: str + :vartype language: str """ def __init__(self, **kwargs): @@ -587,16 +587,16 @@ class TextDocumentBatchStatistics(DictMixin): request payload. Note: This object is not returned in the response and needs to be retrieved by a response hook. - :param document_count: Number of documents submitted in the request. - :type document_count: int - :param valid_document_count: Number of valid documents. This + :ivar document_count: Number of documents submitted in the request. + :vartype document_count: int + :ivar valid_document_count: Number of valid documents. This excludes empty, over-size limit or non-supported languages documents. - :type valid_document_count: int - :param erroneous_document_count: Number of invalid documents. + :vartype valid_document_count: int + :ivar erroneous_document_count: Number of invalid documents. This includes empty, over-size limit or non-supported languages documents. - :type erroneous_document_count: int - :param transaction_count: Number of transactions for the request. - :type transaction_count: long + :vartype erroneous_document_count: int + :ivar transaction_count: Number of transactions for the request. + :vartype transaction_count: long """ def __init__(self, **kwargs): @@ -626,14 +626,14 @@ class SentenceSentiment(DictMixin): """SentenceSentiment contains the predicted sentiment and confidence scores for each individual sentence in the document. - :param text: The sentence text. - :type text: str - :param sentiment: The predicted Sentiment for the sentence. + :ivar text: The sentence text. + :vartype text: str + :ivar sentiment: The predicted Sentiment for the sentence. Possible values include: 'positive', 'neutral', 'negative' - :type sentiment: str - :param confidence_scores: The sentiment confidence score between 0 + :vartype sentiment: str + :ivar confidence_scores: The sentiment confidence score between 0 and 1 for the sentence for all labels. - :type confidence_scores: + :vartype confidence_scores: ~azure.ai.textanalytics.SentimentConfidenceScores """ @@ -662,12 +662,12 @@ class SentimentConfidenceScores(DictMixin): """The confidence scores (Softmax scores) between 0 and 1. Higher values indicate higher confidence. - :param positive: Positive score. - :type positive: float - :param neutral: Neutral score. - :type neutral: float - :param negative: Negative score. - :type negative: float + :ivar positive: Positive score. + :vartype positive: float + :ivar neutral: Neutral score. + :vartype neutral: float + :ivar negative: Negative score. + :vartype negative: float """ def __init__(self, **kwargs): From e49027cc121031f95d411b18ab7d908c501692f3 Mon Sep 17 00:00:00 2001 From: Laurent Mazuel Date: Wed, 3 Jun 2020 12:27:45 -0700 Subject: [PATCH 03/25] Core 1.6.0 release notes (#11786) --- sdk/core/azure-core/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/core/azure-core/CHANGELOG.md b/sdk/core/azure-core/CHANGELOG.md index 89b76c945ebb..5fd84d19d465 100644 --- a/sdk/core/azure-core/CHANGELOG.md +++ b/sdk/core/azure-core/CHANGELOG.md @@ -1,7 +1,7 @@ # Release History -## 1.6.0 (Unreleased) +## 1.6.0 (2020-06-03) ### Bug fixes @@ -13,7 +13,7 @@ - Added support for changesets as part of multipart message support #10485 - Add AsyncLROPoller in azure.core.polling #10801 - Add get_continuation_token/from_continuation_token/polling_method methods in pollers (sync and async) #10801 -- HttpResponse objects are now pickable #10801 +- HttpResponse and PipelineContext objects are now pickable #10801 ## 1.5.0 (2020-05-04) From 3094344cfddffcbdc1e7ed65c6c17aa8b0f88b97 Mon Sep 17 00:00:00 2001 From: iscai-msft <43154838+iscai-msft@users.noreply.github.com> Date: Wed, 3 Jun 2020 16:23:30 -0400 Subject: [PATCH 04/25] [form recognizer] Remove US receipt (#11764) --- .../azure-ai-formrecognizer/CHANGELOG.md | 3 + .../azure-ai-formrecognizer/README.md | 28 ++-- .../azure/ai/formrecognizer/__init__.py | 6 - .../formrecognizer/_form_recognizer_client.py | 4 +- .../azure/ai/formrecognizer/_models.py | 136 +----------------- .../ai/formrecognizer/_response_handlers.py | 43 +----- .../aio/_form_recognizer_client_async.py | 4 +- .../sample_recognize_receipts_async.py | 47 ++++-- ...ample_recognize_receipts_from_url_async.py | 47 ++++-- .../samples/sample_recognize_receipts.py | 47 ++++-- .../sample_recognize_receipts_from_url.py | 47 ++++-- .../tests/test_receipt.py | 136 ++++++++---------- .../tests/test_receipt_async.py | 136 ++++++++---------- .../tests/test_receipt_from_url.py | 136 ++++++++---------- .../tests/test_receipt_from_url_async.py | 136 ++++++++---------- .../tests/test_repr.py | 66 +-------- .../azure-ai-formrecognizer/tests/testcase.py | 38 ++--- 17 files changed, 414 insertions(+), 646 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md b/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md index a740919023f1..6fe1439c6791 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md +++ b/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md @@ -22,6 +22,9 @@ `CustomFormModel` and `CustomFormModelInfo` models. - `models` property of `CustomFormModel` is renamed to `submodels` - `CustomFormSubModel` is renamed to `CustomFormSubmodel` +- Removed `USReceipt`. To see how to deal with the return value of `begin_recognize_receipts`, see the recognize receipt samples in the [samples directory](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/formrecognizer/azure-ai-formrecognizer/samples) for details. +- Removed `USReceiptItem`. To see how to access the individual items on a receipt, see the recognize receipt samples in the [samples directory](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/formrecognizer/azure-ai-formrecognizer/samples) for details. +- Removed `ReceiptType` and the `receipt_type` property from `RecognizedReceipt`. See the recognize receipt samples in the [samples directory](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/formrecognizer/azure-ai-formrecognizer/samples) for details. **New features** diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/README.md b/sdk/formrecognizer/azure-ai-formrecognizer/README.md index 485804eb597b..998f2249121b 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/README.md +++ b/sdk/formrecognizer/azure-ai-formrecognizer/README.md @@ -210,7 +210,7 @@ for cell in table.cells: ``` ### Recognize Receipts -Recognize data from USA sales receipts using a prebuilt model. +Recognize data from USA sales receipts using a prebuilt model. [Here][service_recognize_receipt] are the fields the service returns for a recognized receipt. ```python from azure.ai.formrecognizer import FormRecognizerClient @@ -227,21 +227,16 @@ with open("", "rb") as fd: poller = form_recognizer_client.begin_recognize_receipts(receipt) result = poller.result() -r = result[0] -print("Receipt contained the following values with confidences: ") -print("Receipt Type: {} has confidence: {}".format(r.receipt_type.type, r.receipt_type.confidence)) -print("Merchant Name: {} has confidence: {}".format(r.merchant_name.value, r.merchant_name.confidence)) -print("Transaction Date: {} has confidence: {}".format(r.transaction_date.value, r.transaction_date.confidence)) -print("Receipt items:") -for item in r.receipt_items: - print("...Item Name: {} has confidence: {}".format(item.name.value, item.name.confidence)) - print("...Item Quantity: {} has confidence: {}".format(item.quantity.value, item.quantity.confidence)) - print("...Individual Item Price: {} has confidence: {}".format(item.price.value, item.price.confidence)) - print("...Total Item Price: {} has confidence: {}".format(item.total_price.value, item.total_price.confidence)) -print("Subtotal: {} has confidence: {}".format(r.subtotal.value, r.subtotal.confidence)) -print("Tax: {} has confidence: {}".format(r.tax.value, r.tax.confidence)) -print("Tip: {} has confidence: {}".format(r.tip.value, r.tip.confidence)) -print("Total: {} has confidence: {}".format(r.total.value, r.total.confidence)) +for receipt in result: + for name, field in receipt.fields.items(): + if name == "Items": + print("Receipt Items:") + for idx, items in enumerate(field.value): + print("...Item #{}".format(idx)) + for item_name, item in items.value.items(): + print("......{}: {} has confidence {}".format(item_name, item.value, item.confidence)) + else: + print("{}: {} has confidence {}".format(name, field.value, field.confidence)) ``` ### Train a model @@ -439,6 +434,7 @@ This project has adopted the [Microsoft Open Source Code of Conduct][code_of_con [cognitive_authentication_aad]: https://docs.microsoft.com/azure/cognitive-services/authentication#authenticate-with-azure-active-directory [azure_identity_credentials]: ../../identity/azure-identity#credentials [default_azure_credential]: ../../identity/azure-identity#defaultazurecredential +[service_recognize_receipt]: https://westus2.dev.cognitive.microsoft.com/docs/services/form-recognizer-api-v2-preview/operations/GetAnalyzeReceiptResult [cla]: https://cla.microsoft.com [code_of_conduct]: https://opensource.microsoft.com/codeofconduct/ diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py index f65b9e8e92af..dd86f0f42e41 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py @@ -14,9 +14,6 @@ TrainingStatus, CustomFormModelStatus, FormContentType, - USReceipt, - ReceiptType, - USReceiptItem, FormTable, FormTableCell, TrainingDocumentInfo, @@ -45,9 +42,6 @@ 'CustomFormModelStatus', 'FormContentType', 'FormContent', - 'USReceipt', - 'ReceiptType', - 'USReceiptItem', 'FormTable', 'FormTableCell', 'TrainingDocumentInfo', diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_recognizer_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_recognizer_client.py index d3d2173442aa..ac2bb7cd304f 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_recognizer_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_recognizer_client.py @@ -17,7 +17,7 @@ from azure.core.polling.base_polling import LROBasePolling from ._generated._form_recognizer_client import FormRecognizerClient as FormRecognizer from ._response_handlers import ( - prepare_us_receipt, + prepare_receipt, prepare_content_result, prepare_form_result ) @@ -74,7 +74,7 @@ def __init__(self, endpoint, credential, **kwargs): def _receipt_callback(self, raw_response, _, headers): # pylint: disable=unused-argument analyze_result = self._client._deserialize(AnalyzeOperationResult, raw_response) - return prepare_us_receipt(analyze_result) + return prepare_receipt(analyze_result) @distributed_trace def begin_recognize_receipts(self, receipt, **kwargs): diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py index cf61dd1038f4..b15c7d89866b 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py @@ -195,82 +195,13 @@ class RecognizedReceipt(RecognizedForm): :ivar list[~azure.ai.formrecognizer.FormPage] pages: A list of pages recognized from the input document. Contains lines, words, tables and page metadata. - :ivar ~azure.ai.formrecognizer.ReceiptType receipt_type: - The reciept type and confidence. - :ivar str receipt_locale: Defaults to "en-US". """ - def __init__(self, **kwargs): - super(RecognizedReceipt, self).__init__(**kwargs) - self.receipt_type = kwargs.get("receipt_type", None) - self.receipt_locale = kwargs.get("receipt_locale", "en-US") def __repr__(self): - return "RecognizedReceipt(form_type={}, fields={}, page_range={}, pages={}, " \ - "receipt_type={}, receipt_locale={})".format( - self.form_type, repr(self.fields), repr(self.page_range), repr(self.pages), - repr(self.receipt_type), self.receipt_locale + return "RecognizedReceipt(form_type={}, fields={}, page_range={}, pages={})".format( + self.form_type, repr(self.fields), repr(self.page_range), repr(self.pages) )[:1024] -class USReceipt(RecognizedReceipt): # pylint: disable=too-many-instance-attributes - """Extracted fields found on the US sales receipt. Provides - attributes for accessing common fields present in US sales receipts. - - :ivar ~azure.ai.formrecognizer.FormField merchant_address: - The address of the merchant. - :ivar ~azure.ai.formrecognizer.FormField merchant_name: - The name of the merchant. - :ivar ~azure.ai.formrecognizer.FormField merchant_phone_number: - The phone number associated with the merchant. - :ivar list[~azure.ai.formrecognizer.USReceiptItem] receipt_items: - The purchased items found on the receipt. - :ivar ~azure.ai.formrecognizer.FormField subtotal: - The subtotal found on the receipt - :ivar ~azure.ai.formrecognizer.FormField tax: - The tax value found on the receipt. - :ivar ~azure.ai.formrecognizer.FormField tip: - The tip value found on the receipt. - :ivar ~azure.ai.formrecognizer.FormField total: - The total amount found on the receipt. - :ivar ~azure.ai.formrecognizer.FormField transaction_date: - The transaction date of the sale. - :ivar ~azure.ai.formrecognizer.FormField transaction_time: - The transaction time of the sale. - :ivar fields: - A dictionary of the fields found on the receipt. - :vartype fields: dict[str, ~azure.ai.formrecognizer.FormField] - :ivar ~azure.ai.formrecognizer.FormPageRange page_range: - The first and last page number of the input receipt. - :ivar list[~azure.ai.formrecognizer.FormPage] pages: - Contains page metadata such as page width, length, text angle, unit. - If `include_text_content=True` is passed, contains a list - of extracted text lines for each page in the input document. - :ivar str form_type: The type of form. - """ - - def __init__(self, **kwargs): - super(USReceipt, self).__init__(**kwargs) - self.merchant_address = kwargs.get("merchant_address", None) - self.merchant_name = kwargs.get("merchant_name", None) - self.merchant_phone_number = kwargs.get("merchant_phone_number", None) - self.receipt_items = kwargs.get("receipt_items", None) - self.subtotal = kwargs.get("subtotal", None) - self.tax = kwargs.get("tax", None) - self.tip = kwargs.get("tip", None) - self.total = kwargs.get("total", None) - self.transaction_date = kwargs.get("transaction_date", None) - self.transaction_time = kwargs.get("transaction_time", None) - - def __repr__(self): - return "USReceipt(merchant_address={}, merchant_name={}, merchant_phone_number={}, " \ - "receipt_type={}, receipt_items={}, subtotal={}, tax={}, tip={}, total={}, "\ - "transaction_date={}, transaction_time={}, fields={}, page_range={}, pages={}, " \ - "form_type={}, receipt_locale={})".format( - repr(self.merchant_address), repr(self.merchant_name), repr(self.merchant_phone_number), - repr(self.receipt_type), repr(self.receipt_items), repr(self.subtotal), repr(self.tax), - repr(self.tip), repr(self.total), repr(self.transaction_date), repr(self.transaction_time), - repr(self.fields), repr(self.page_range), repr(self.pages), self.form_type, self.receipt_locale - )[:1024] - class FormField(object): """Represents a field recognized in an input form. @@ -513,69 +444,6 @@ def __repr__(self): )[:1024] -class ReceiptType(object): - """The type of the analyzed US receipt and the confidence - value of that type. - - :ivar str type: The type of the receipt. For example, "Itemized", - "CreditCard", "Gas", "Parking", "Gas", "Other". - :ivar float confidence: - Measures the degree of certainty of the recognition result. Value is between [0.0, 1.0]. - """ - - def __init__(self, **kwargs): - self.type = kwargs.get("type", None) - self.confidence = kwargs.get("confidence", None) - - @classmethod - def _from_generated(cls, item): - return cls( - type=item.value_string, - confidence=adjust_confidence(item.confidence)) if item else None - - def __repr__(self): - return "ReceiptType(type={}, confidence={})".format(self.type, self.confidence)[:1024] - - -class USReceiptItem(object): - """A receipt item on a US sales receipt. - Contains the item name, quantity, price, and total price. - - :ivar ~azure.ai.formrecognizer.FormField name: - The name of the item. - :ivar ~azure.ai.formrecognizer.FormField quantity: - The quantity associated with this item. - :ivar ~azure.ai.formrecognizer.FormField price: - The price of a single unit of this item. - :ivar ~azure.ai.formrecognizer.FormField total_price: - The total price of this item, taking the quantity into account. - """ - - def __init__(self, **kwargs): - self.name = kwargs.get("name", None) - self.quantity = kwargs.get("quantity", None) - self.price = kwargs.get("price", None) - self.total_price = kwargs.get("total_price", None) - - @classmethod - def _from_generated(cls, items, read_result): - try: - receipt_item = items.value_array - return [cls( - name=FormField._from_generated("Name", item.value_object.get("Name"), read_result), - quantity=FormField._from_generated("Quantity", item.value_object.get("Quantity"), read_result), - price=FormField._from_generated("Price", item.value_object.get("Price"), read_result), - total_price=FormField._from_generated("TotalPrice", item.value_object.get("TotalPrice"), read_result), - ) for item in receipt_item] - except AttributeError: - return [] - - def __repr__(self): - return "USReceiptItem(name={}, quantity={}, price={}, total_price={})".format( - repr(self.name), repr(self.quantity), repr(self.price), repr(self.total_price) - )[:1024] - - class FormTable(object): """Information about the extracted table contained on a page. diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_response_handlers.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_response_handlers.py index 08d8fa9d9461..90fe97582902 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_response_handlers.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_response_handlers.py @@ -7,20 +7,18 @@ # pylint: disable=protected-access from ._models import ( - USReceipt, - ReceiptType, FormField, - USReceiptItem, FormPage, FormLine, FormTable, FormTableCell, FormPageRange, - RecognizedForm + RecognizedForm, + RecognizedReceipt ) -def prepare_us_receipt(response): +def prepare_receipt(response): receipts = [] read_result = response.analyze_result.read_results document_result = response.analyze_result.document_results @@ -28,43 +26,14 @@ def prepare_us_receipt(response): for page in document_result: if page.fields is None: - receipt = USReceipt( + receipt = RecognizedReceipt( page_range=FormPageRange(first_page_number=page.page_range[0], last_page_number=page.page_range[1]), pages=form_page[page.page_range[0]-1:page.page_range[1]], form_type=page.doc_type, ) receipts.append(receipt) continue - receipt = USReceipt( - merchant_address=FormField._from_generated( - "MerchantAddress", page.fields.get("MerchantAddress"), read_result - ), - merchant_name=FormField._from_generated( - "MerchantName", page.fields.get("MerchantName"), read_result - ), - merchant_phone_number=FormField._from_generated( - "MerchantPhoneNumber", - page.fields.get("MerchantPhoneNumber"), - read_result, - ), - receipt_type=ReceiptType._from_generated(page.fields.get("ReceiptType")), - receipt_items=USReceiptItem._from_generated( - page.fields.get("Items"), read_result - ), - subtotal=FormField._from_generated( - "Subtotal", page.fields.get("Subtotal"), read_result - ), - tax=FormField._from_generated("Tax", page.fields.get("Tax"), read_result), - tip=FormField._from_generated("Tip", page.fields.get("Tip"), read_result), - total=FormField._from_generated( - "Total", page.fields.get("Total"), read_result - ), - transaction_date=FormField._from_generated( - "TransactionDate", page.fields.get("TransactionDate"), read_result - ), - transaction_time=FormField._from_generated( - "TransactionTime", page.fields.get("TransactionTime"), read_result - ), + receipt = RecognizedReceipt( page_range=FormPageRange( first_page_number=page.page_range[0], last_page_number=page.page_range[1] ), @@ -73,7 +42,7 @@ def prepare_us_receipt(response): fields={ key: FormField._from_generated(key, value, read_result) for key, value in page.fields.items() - }, + } ) receipts.append(receipt) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_recognizer_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_recognizer_client_async.py index 8e0a4dd81d56..ae35b3c275c6 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_recognizer_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_recognizer_client_async.py @@ -17,7 +17,7 @@ from azure.core.polling.async_base_polling import AsyncLROBasePolling from .._generated.aio._form_recognizer_client_async import FormRecognizerClient as FormRecognizer from .._response_handlers import ( - prepare_us_receipt, + prepare_receipt, prepare_content_result, prepare_form_result ) @@ -84,7 +84,7 @@ def __init__( def _receipt_callback(self, raw_response, _, headers): # pylint: disable=unused-argument analyze_result = self._client._deserialize(AnalyzeOperationResult, raw_response) - return prepare_us_receipt(analyze_result) + return prepare_receipt(analyze_result) @distributed_trace_async async def recognize_receipts( diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_receipts_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_receipts_async.py index 2e41b244a5e3..3bca0eb2549d 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_receipts_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_receipts_async.py @@ -45,19 +45,42 @@ async def recognize_receipts(self): for idx, receipt in enumerate(receipts): print("--------Recognizing receipt #{}--------".format(idx)) - print("Receipt Type: {} has confidence: {}".format(receipt.receipt_type.type, receipt.receipt_type.confidence)) - print("Merchant Name: {} has confidence: {}".format(receipt.merchant_name.value, receipt.merchant_name.confidence)) - print("Transaction Date: {} has confidence: {}".format(receipt.transaction_date.value, receipt.transaction_date.confidence)) + receipt_type = receipt.fields.get("ReceiptType") + if receipt_type: + print("Receipt Type: {} has confidence: {}".format(receipt_type.value, receipt_type.confidence)) + merchant_name = receipt.fields.get("MerchantName") + if merchant_name: + print("Merchant Name: {} has confidence: {}".format(merchant_name.value, merchant_name.confidence)) + transaction_date = receipt.fields.get("TransactionDate") + if transaction_date: + print("Transaction Date: {} has confidence: {}".format(transaction_date.value, transaction_date.confidence)) print("Receipt items:") - for item in receipt.receipt_items: - print("...Item Name: {} has confidence: {}".format(item.name.value, item.name.confidence)) - print("...Item Quantity: {} has confidence: {}".format(item.quantity.value, item.quantity.confidence)) - print("...Individual Item Price: {} has confidence: {}".format(item.price.value, item.price.confidence)) - print("...Total Item Price: {} has confidence: {}".format(item.total_price.value, item.total_price.confidence)) - print("Subtotal: {} has confidence: {}".format(receipt.subtotal.value, receipt.subtotal.confidence)) - print("Tax: {} has confidence: {}".format(receipt.tax.value, receipt.tax.confidence)) - print("Tip: {} has confidence: {}".format(receipt.tip.value, receipt.tip.confidence)) - print("Total: {} has confidence: {}".format(receipt.total.value, receipt.total.confidence)) + for idx, item in enumerate(receipt.fields.get("Items").value): + print("...Item #{}".format(idx)) + item_name = item.value.get("Name") + if item_name: + print("......Item Name: {} has confidence: {}".format(item_name.value, item_name.confidence)) + item_quantity = item.value.get("Quantity") + if item_quantity: + print("......Item Quantity: {} has confidence: {}".format(item_quantity.value, item_quantity.confidence)) + item_price = item.value.get("Price") + if item_price: + print("......Individual Item Price: {} has confidence: {}".format(item_price.value, item_price.confidence)) + item_total_price = item.value.get("TotalPrice") + if item_total_price: + print("......Total Item Price: {} has confidence: {}".format(item_total_price.value, item_total_price.confidence)) + subtotal = receipt.fields.get("Subtotal") + if subtotal: + print("Subtotal: {} has confidence: {}".format(subtotal.value, subtotal.confidence)) + tax = receipt.fields.get("Tax") + if tax: + print("Tax: {} has confidence: {}".format(tax.value, tax.confidence)) + tip = receipt.fields.get("Tip") + if tip: + print("Tip: {} has confidence: {}".format(tip.value, tip.confidence)) + total = receipt.fields.get("Total") + if total: + print("Total: {} has confidence: {}".format(total.value, total.confidence)) print("--------------------------------------") # [END recognize_receipts_async] diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_receipts_from_url_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_receipts_from_url_async.py index 8831e076fc69..3559261094fb 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_receipts_from_url_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_receipts_from_url_async.py @@ -42,19 +42,42 @@ async def recognize_receipts_from_url(self): for idx, receipt in enumerate(receipts): print("--------Recognizing receipt #{}--------".format(idx)) - print("Receipt Type: {} has confidence: {}".format(receipt.receipt_type.type, receipt.receipt_type.confidence)) - print("Merchant Name: {} has confidence: {}".format(receipt.merchant_name.value, receipt.merchant_name.confidence)) - print("Transaction Date: {} has confidence: {}".format(receipt.transaction_date.value, receipt.transaction_date.confidence)) + receipt_type = receipt.fields.get("ReceiptType") + if receipt_type: + print("Receipt Type: {} has confidence: {}".format(receipt_type.value, receipt_type.confidence)) + merchant_name = receipt.fields.get("MerchantName") + if merchant_name: + print("Merchant Name: {} has confidence: {}".format(merchant_name.value, merchant_name.confidence)) + transaction_date = receipt.fields.get("TransactionDate") + if transaction_date: + print("Transaction Date: {} has confidence: {}".format(transaction_date.value, transaction_date.confidence)) print("Receipt items:") - for item in receipt.receipt_items: - print("...Item Name: {} has confidence: {}".format(item.name.value, item.name.confidence)) - print("...Item Quantity: {} has confidence: {}".format(item.quantity.value, item.quantity.confidence)) - print("...Individual Item Price: {} has confidence: {}".format(item.price.value, item.price.confidence)) - print("...Total Item Price: {} has confidence: {}".format(item.total_price.value, item.total_price.confidence)) - print("Subtotal: {} has confidence: {}".format(receipt.subtotal.value, receipt.subtotal.confidence)) - print("Tax: {} has confidence: {}".format(receipt.tax.value, receipt.tax.confidence)) - print("Tip: {} has confidence: {}".format(receipt.tip.value, receipt.tip.confidence)) - print("Total: {} has confidence: {}".format(receipt.total.value, receipt.total.confidence)) + for idx, item in enumerate(receipt.fields.get("Items").value): + print("...Item #{}".format(idx)) + item_name = item.value.get("Name") + if item_name: + print("......Item Name: {} has confidence: {}".format(item_name.value, item_name.confidence)) + item_quantity = item.value.get("Quantity") + if item_quantity: + print("......Item Quantity: {} has confidence: {}".format(item_quantity.value, item_quantity.confidence)) + item_price = item.value.get("Price") + if item_price: + print("......Individual Item Price: {} has confidence: {}".format(item_price.value, item_price.confidence)) + item_total_price = item.value.get("TotalPrice") + if item_total_price: + print("......Total Item Price: {} has confidence: {}".format(item_total_price.value, item_total_price.confidence)) + subtotal = receipt.fields.get("Subtotal") + if subtotal: + print("Subtotal: {} has confidence: {}".format(subtotal.value, subtotal.confidence)) + tax = receipt.fields.get("Tax") + if tax: + print("Tax: {} has confidence: {}".format(tax.value, tax.confidence)) + tip = receipt.fields.get("Tip") + if tip: + print("Tip: {} has confidence: {}".format(tip.value, tip.confidence)) + total = receipt.fields.get("Total") + if total: + print("Total: {} has confidence: {}".format(total.value, total.confidence)) print("--------------------------------------") # [END recognize_receipts_from_url_async] diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_recognize_receipts.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_recognize_receipts.py index b321ef76553e..a53c04497daa 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_recognize_receipts.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_recognize_receipts.py @@ -42,19 +42,42 @@ def recognize_receipts(self): for idx, receipt in enumerate(receipts): print("--------Recognizing receipt #{}--------".format(idx)) - print("Receipt Type: {} has confidence: {}".format(receipt.receipt_type.type, receipt.receipt_type.confidence)) - print("Merchant Name: {} has confidence: {}".format(receipt.merchant_name.value, receipt.merchant_name.confidence)) - print("Transaction Date: {} has confidence: {}".format(receipt.transaction_date.value, receipt.transaction_date.confidence)) + receipt_type = receipt.fields.get("ReceiptType") + if receipt_type: + print("Receipt Type: {} has confidence: {}".format(receipt_type.value, receipt_type.confidence)) + merchant_name = receipt.fields.get("MerchantName") + if merchant_name: + print("Merchant Name: {} has confidence: {}".format(merchant_name.value, merchant_name.confidence)) + transaction_date = receipt.fields.get("TransactionDate") + if transaction_date: + print("Transaction Date: {} has confidence: {}".format(transaction_date.value, transaction_date.confidence)) print("Receipt items:") - for item in receipt.receipt_items: - print("...Item Name: {} has confidence: {}".format(item.name.value, item.name.confidence)) - print("...Item Quantity: {} has confidence: {}".format(item.quantity.value, item.quantity.confidence)) - print("...Individual Item Price: {} has confidence: {}".format(item.price.value, item.price.confidence)) - print("...Total Item Price: {} has confidence: {}".format(item.total_price.value, item.total_price.confidence)) - print("Subtotal: {} has confidence: {}".format(receipt.subtotal.value, receipt.subtotal.confidence)) - print("Tax: {} has confidence: {}".format(receipt.tax.value, receipt.tax.confidence)) - print("Tip: {} has confidence: {}".format(receipt.tip.value, receipt.tip.confidence)) - print("Total: {} has confidence: {}".format(receipt.total.value, receipt.total.confidence)) + for idx, item in enumerate(receipt.fields.get("Items").value): + print("...Item #{}".format(idx)) + item_name = item.value.get("Name") + if item_name: + print("......Item Name: {} has confidence: {}".format(item_name.value, item_name.confidence)) + item_quantity = item.value.get("Quantity") + if item_quantity: + print("......Item Quantity: {} has confidence: {}".format(item_quantity.value, item_quantity.confidence)) + item_price = item.value.get("Price") + if item_price: + print("......Individual Item Price: {} has confidence: {}".format(item_price.value, item_price.confidence)) + item_total_price = item.value.get("TotalPrice") + if item_total_price: + print("......Total Item Price: {} has confidence: {}".format(item_total_price.value, item_total_price.confidence)) + subtotal = receipt.fields.get("Subtotal") + if subtotal: + print("Subtotal: {} has confidence: {}".format(subtotal.value, subtotal.confidence)) + tax = receipt.fields.get("Tax") + if tax: + print("Tax: {} has confidence: {}".format(tax.value, tax.confidence)) + tip = receipt.fields.get("Tip") + if tip: + print("Tip: {} has confidence: {}".format(tip.value, tip.confidence)) + total = receipt.fields.get("Total") + if total: + print("Total: {} has confidence: {}".format(total.value, total.confidence)) print("--------------------------------------") # [END recognize_receipts] diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_recognize_receipts_from_url.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_recognize_receipts_from_url.py index 7ccd5c58586a..f3b333c4d7f1 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_recognize_receipts_from_url.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_recognize_receipts_from_url.py @@ -42,19 +42,42 @@ def recognize_receipts_from_url(self): for idx, receipt in enumerate(receipts): print("--------Recognizing receipt #{}--------".format(idx)) - print("Receipt Type: {} has confidence: {}".format(receipt.receipt_type.type, receipt.receipt_type.confidence)) - print("Merchant Name: {} has confidence: {}".format(receipt.merchant_name.value, receipt.merchant_name.confidence)) - print("Transaction Date: {} has confidence: {}".format(receipt.transaction_date.value, receipt.transaction_date.confidence)) + receipt_type = receipt.fields.get("ReceiptType") + if receipt_type: + print("Receipt Type: {} has confidence: {}".format(receipt_type.value, receipt_type.confidence)) + merchant_name = receipt.fields.get("MerchantName") + if merchant_name: + print("Merchant Name: {} has confidence: {}".format(merchant_name.value, merchant_name.confidence)) + transaction_date = receipt.fields.get("TransactionDate") + if transaction_date: + print("Transaction Date: {} has confidence: {}".format(transaction_date.value, transaction_date.confidence)) print("Receipt items:") - for item in receipt.receipt_items: - print("...Item Name: {} has confidence: {}".format(item.name.value, item.name.confidence)) - print("...Item Quantity: {} has confidence: {}".format(item.quantity.value, item.quantity.confidence)) - print("...Individual Item Price: {} has confidence: {}".format(item.price.value, item.price.confidence)) - print("...Total Item Price: {} has confidence: {}".format(item.total_price.value, item.total_price.confidence)) - print("Subtotal: {} has confidence: {}".format(receipt.subtotal.value, receipt.subtotal.confidence)) - print("Tax: {} has confidence: {}".format(receipt.tax.value, receipt.tax.confidence)) - print("Tip: {} has confidence: {}".format(receipt.tip.value, receipt.tip.confidence)) - print("Total: {} has confidence: {}".format(receipt.total.value, receipt.total.confidence)) + for idx, item in enumerate(receipt.fields.get("Items").value): + print("...Item #{}".format(idx)) + item_name = item.value.get("Name") + if item_name: + print("......Item Name: {} has confidence: {}".format(item_name.value, item_name.confidence)) + item_quantity = item.value.get("Quantity") + if item_quantity: + print("......Item Quantity: {} has confidence: {}".format(item_quantity.value, item_quantity.confidence)) + item_price = item.value.get("Price") + if item_price: + print("......Individual Item Price: {} has confidence: {}".format(item_price.value, item_price.confidence)) + item_total_price = item.value.get("TotalPrice") + if item_total_price: + print("......Total Item Price: {} has confidence: {}".format(item_total_price.value, item_total_price.confidence)) + subtotal = receipt.fields.get("Subtotal") + if subtotal: + print("Subtotal: {} has confidence: {}".format(subtotal.value, subtotal.confidence)) + tax = receipt.fields.get("Tax") + if tax: + print("Tax: {} has confidence: {}".format(tax.value, tax.confidence)) + tip = receipt.fields.get("Tip") + if tip: + print("Tip: {} has confidence: {}".format(tip.value, tip.confidence)) + total = receipt.fields.get("Total") + if total: + print("Total: {} has confidence: {}".format(total.value, total.confidence)) print("--------------------------------------") # [END recognize_receipts_from_url] diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt.py index e7a605036e63..c1296b292cbb 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt.py @@ -9,7 +9,7 @@ from azure.core.exceptions import ClientAuthenticationError, ServiceRequestError, HttpResponseError from azure.core.credentials import AzureKeyCredential from azure.ai.formrecognizer._generated.models import AnalyzeOperationResult -from azure.ai.formrecognizer._response_handlers import prepare_us_receipt +from azure.ai.formrecognizer._response_handlers import prepare_receipt from azure.ai.formrecognizer import FormRecognizerClient, FormContentType from testcase import FormRecognizerTest, GlobalFormRecognizerAccountPreparer @@ -136,7 +136,7 @@ def test_receipt_stream_transform_png(self, resource_group, location, form_recog def callback(raw_response, _, headers): analyze_result = client._client._deserialize(AnalyzeOperationResult, raw_response) - extracted_receipt = prepare_us_receipt(analyze_result) + extracted_receipt = prepare_receipt(analyze_result) responses.append(analyze_result) responses.append(extracted_receipt) @@ -157,17 +157,6 @@ def callback(raw_response, _, headers): read_results = raw_response.analyze_result.read_results document_results = raw_response.analyze_result.document_results - # check hardcoded values - self.assertFormFieldTransformCorrect(receipt.merchant_address, actual.get("MerchantAddress"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_name, actual.get("MerchantName"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_phone_number, actual.get("MerchantPhoneNumber"), read_results) - self.assertFormFieldTransformCorrect(receipt.subtotal, actual.get("Subtotal"), read_results) - self.assertFormFieldTransformCorrect(receipt.tax, actual.get("Tax"), read_results) - self.assertFormFieldTransformCorrect(receipt.tip, actual.get("Tip"), read_results) - self.assertFormFieldTransformCorrect(receipt.total, actual.get("Total"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_date, actual.get("TransactionDate"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_time, actual.get("TransactionTime"), read_results) - # check dict values self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantAddress"), actual.get("MerchantAddress"), read_results) self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantName"), actual.get("MerchantName"), read_results) @@ -184,11 +173,12 @@ def callback(raw_response, _, headers): self.assertEqual(receipt.page_range.last_page_number, document_results[0].page_range[1]) # check receipt type - self.assertEqual(receipt.receipt_type.confidence, actual["ReceiptType"].confidence) - self.assertEqual(receipt.receipt_type.type, actual["ReceiptType"].value_string) + receipt_type = receipt.fields.get("ReceiptType") + self.assertEqual(receipt_type.confidence, actual["ReceiptType"].confidence) + self.assertEqual(receipt_type.value, actual["ReceiptType"].value_string) # check receipt items - self.assertReceiptItemsTransformCorrect(receipt.receipt_items, actual["Items"], read_results) + self.assertReceiptItemsTransformCorrect(receipt.fields["Items"].value, actual["Items"], read_results) # Check page metadata self.assertFormPagesTransformCorrect(receipt.pages, read_results) @@ -201,7 +191,7 @@ def test_receipt_stream_transform_jpg(self, resource_group, location, form_recog def callback(raw_response, _, headers): analyze_result = client._client._deserialize(AnalyzeOperationResult, raw_response) - extracted_receipt = prepare_us_receipt(analyze_result) + extracted_receipt = prepare_receipt(analyze_result) responses.append(analyze_result) responses.append(extracted_receipt) @@ -223,17 +213,6 @@ def callback(raw_response, _, headers): document_results = raw_response.analyze_result.document_results page_results = raw_response.analyze_result.page_results - # check hardcoded values - self.assertFormFieldTransformCorrect(receipt.merchant_address, actual.get("MerchantAddress"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_name, actual.get("MerchantName"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_phone_number, actual.get("MerchantPhoneNumber"), read_results) - self.assertFormFieldTransformCorrect(receipt.subtotal, actual.get("Subtotal"), read_results) - self.assertFormFieldTransformCorrect(receipt.tax, actual.get("Tax"), read_results) - self.assertFormFieldTransformCorrect(receipt.tip, actual.get("Tip"), read_results) - self.assertFormFieldTransformCorrect(receipt.total, actual.get("Total"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_date, actual.get("TransactionDate"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_time, actual.get("TransactionTime"), read_results) - # check dict values self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantAddress"), actual.get("MerchantAddress"), read_results) self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantName"), actual.get("MerchantName"), read_results) @@ -250,11 +229,12 @@ def callback(raw_response, _, headers): self.assertEqual(receipt.page_range.last_page_number, document_results[0].page_range[1]) # check receipt type - self.assertEqual(receipt.receipt_type.confidence, actual["ReceiptType"].confidence) - self.assertEqual(receipt.receipt_type.type, actual["ReceiptType"].value_string) + receipt_type = receipt.fields.get("ReceiptType") + self.assertEqual(receipt_type.confidence, actual["ReceiptType"].confidence) + self.assertEqual(receipt_type.value, actual["ReceiptType"].value_string) # check receipt items - self.assertReceiptItemsTransformCorrect(receipt.receipt_items, actual["Items"], read_results) + self.assertReceiptItemsTransformCorrect(receipt.fields["Items"].value, actual["Items"], read_results) # Check form pages self.assertFormPagesTransformCorrect(receipt.pages, read_results) @@ -271,21 +251,22 @@ def test_receipt_jpg(self, resource_group, location, form_recognizer_account, fo result = poller.result() self.assertEqual(len(result), 1) receipt = result[0] - self.assertEqual(receipt.merchant_address.value, '123 Main Street Redmond, WA 98052') - self.assertEqual(receipt.merchant_name.value, 'Contoso Contoso') - self.assertEqual(receipt.merchant_phone_number.value, '+19876543210') - self.assertEqual(receipt.subtotal.value, 11.7) - self.assertEqual(receipt.tax.value, 1.17) - self.assertEqual(receipt.tip.value, 1.63) - self.assertEqual(receipt.total.value, 14.5) - self.assertEqual(receipt.transaction_date.value, date(year=2019, month=6, day=10)) - self.assertEqual(receipt.transaction_time.value, time(hour=13, minute=59, second=0)) + self.assertEqual(receipt.fields.get("MerchantAddress").value, '123 Main Street Redmond, WA 98052') + self.assertEqual(receipt.fields.get("MerchantName").value, 'Contoso Contoso') + self.assertEqual(receipt.fields.get("MerchantPhoneNumber").value, '+19876543210') + self.assertEqual(receipt.fields.get("Subtotal").value, 11.7) + self.assertEqual(receipt.fields.get("Tax").value, 1.17) + self.assertEqual(receipt.fields.get("Tip").value, 1.63) + self.assertEqual(receipt.fields.get("Total").value, 14.5) + self.assertEqual(receipt.fields.get("TransactionDate").value, date(year=2019, month=6, day=10)) + self.assertEqual(receipt.fields.get("TransactionTime").value, time(hour=13, minute=59, second=0)) self.assertEqual(receipt.page_range.first_page_number, 1) self.assertEqual(receipt.page_range.last_page_number, 1) self.assertFormPagesHasValues(receipt.pages) - self.assertIsNotNone(receipt.receipt_type.confidence) - self.assertEqual(receipt.receipt_type.type, 'Itemized') - self.assertReceiptItemsHasValues(receipt.receipt_items, receipt.page_range.first_page_number, False) + receipt_type = receipt.fields.get("ReceiptType") + self.assertIsNotNone(receipt_type.confidence) + self.assertEqual(receipt_type.value, 'Itemized') + self.assertReceiptItemsHasValues(receipt.fields['Items'].value, receipt.page_range.first_page_number, False) @GlobalFormRecognizerAccountPreparer() def test_receipt_png(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -297,18 +278,19 @@ def test_receipt_png(self, resource_group, location, form_recognizer_account, fo result = poller.result() self.assertEqual(len(result), 1) receipt = result[0] - self.assertEqual(receipt.merchant_address.value, '123 Main Street Redmond, WA 98052') - self.assertEqual(receipt.merchant_name.value, 'Contoso Contoso') - self.assertEqual(receipt.subtotal.value, 1098.99) - self.assertEqual(receipt.tax.value, 104.4) - self.assertEqual(receipt.total.value, 1203.39) - self.assertEqual(receipt.transaction_date.value, date(year=2019, month=6, day=10)) - self.assertEqual(receipt.transaction_time.value, time(hour=13, minute=59, second=0)) + self.assertEqual(receipt.fields.get("MerchantAddress").value, '123 Main Street Redmond, WA 98052') + self.assertEqual(receipt.fields.get("MerchantName").value, 'Contoso Contoso') + self.assertEqual(receipt.fields.get("Subtotal").value, 1098.99) + self.assertEqual(receipt.fields.get("Tax").value, 104.4) + self.assertEqual(receipt.fields.get("Total").value, 1203.39) + self.assertEqual(receipt.fields.get("TransactionDate").value, date(year=2019, month=6, day=10)) + self.assertEqual(receipt.fields.get("TransactionTime").value, time(hour=13, minute=59, second=0)) self.assertEqual(receipt.page_range.first_page_number, 1) self.assertEqual(receipt.page_range.last_page_number, 1) self.assertFormPagesHasValues(receipt.pages) - self.assertIsNotNone(receipt.receipt_type.confidence) - self.assertEqual(receipt.receipt_type.type, 'Itemized') + receipt_type = receipt.fields.get("ReceiptType") + self.assertIsNotNone(receipt_type.confidence) + self.assertEqual(receipt_type.value, 'Itemized') @GlobalFormRecognizerAccountPreparer() def test_receipt_jpg_include_text_content(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -323,7 +305,7 @@ def test_receipt_jpg_include_text_content(self, resource_group, location, form_r self.assertFormPagesHasValues(receipt.pages) for field, value in receipt.__dict__.items(): - if field not in ["receipt_type", "receipt_items", "page_range", "pages", "fields", "form_type", "receipt_locale"]: + if field not in ["receipt_items", "page_range", "pages", "fields", "form_type"]: form_field = getattr(receipt, field) self.assertTextContentHasValues(form_field.value_data.text_content, receipt.page_range.first_page_number) @@ -340,27 +322,29 @@ def test_receipt_multipage(self, resource_group, location, form_recognizer_accou self.assertEqual(len(result), 3) receipt = result[0] - self.assertEqual(receipt.merchant_address.value, '123 Hobbit Lane 567 Main St. Redmond, WA Redmond, WA') - self.assertEqual(receipt.merchant_name.value, 'Bilbo Baggins') - self.assertEqual(receipt.merchant_phone_number.value, '+15555555555') - self.assertEqual(receipt.subtotal.value, 300.0) - self.assertEqual(receipt.total.value, 100.0) + self.assertEqual(receipt.fields.get("MerchantAddress").value, '123 Hobbit Lane 567 Main St. Redmond, WA Redmond, WA') + self.assertEqual(receipt.fields.get("MerchantName").value, 'Bilbo Baggins') + self.assertEqual(receipt.fields.get("MerchantPhoneNumber").value, '+15555555555') + self.assertEqual(receipt.fields.get("Subtotal").value, 300.0) + self.assertEqual(receipt.fields.get("Total").value, 100.0) self.assertEqual(receipt.page_range.first_page_number, 1) self.assertEqual(receipt.page_range.last_page_number, 1) self.assertFormPagesHasValues(receipt.pages) - self.assertIsNotNone(receipt.receipt_type.confidence) - self.assertEqual(receipt.receipt_type.type, 'Itemized') + receipt_type = receipt.fields.get("ReceiptType") + self.assertIsNotNone(receipt_type.confidence) + self.assertEqual(receipt_type.value, 'Itemized') receipt = result[2] - self.assertEqual(receipt.merchant_address.value, '123 Hobbit Lane 567 Main St. Redmond, WA Redmond, WA') - self.assertEqual(receipt.merchant_name.value, 'Frodo Baggins') - self.assertEqual(receipt.merchant_phone_number.value, '+15555555555') - self.assertEqual(receipt.subtotal.value, 3000.0) - self.assertEqual(receipt.total.value, 1000.0) + self.assertEqual(receipt.fields.get("MerchantAddress").value, '123 Hobbit Lane 567 Main St. Redmond, WA Redmond, WA') + self.assertEqual(receipt.fields.get("MerchantName").value, 'Frodo Baggins') + self.assertEqual(receipt.fields.get("MerchantPhoneNumber").value, '+15555555555') + self.assertEqual(receipt.fields.get("Subtotal").value, 3000.0) + self.assertEqual(receipt.fields.get("Total").value, 1000.0) self.assertEqual(receipt.page_range.first_page_number, 3) self.assertEqual(receipt.page_range.last_page_number, 3) self.assertFormPagesHasValues(receipt.pages) - self.assertIsNotNone(receipt.receipt_type.confidence) - self.assertEqual(receipt.receipt_type.type, 'Itemized') + receipt_type = receipt.fields.get("ReceiptType") + self.assertIsNotNone(receipt_type.confidence) + self.assertEqual(receipt_type.value, 'Itemized') @GlobalFormRecognizerAccountPreparer() def test_receipt_multipage_transform(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -370,7 +354,7 @@ def test_receipt_multipage_transform(self, resource_group, location, form_recogn def callback(raw_response, _, headers): analyze_result = client._client._deserialize(AnalyzeOperationResult, raw_response) - extracted_receipt = prepare_us_receipt(analyze_result) + extracted_receipt = prepare_receipt(analyze_result) responses.append(analyze_result) responses.append(extracted_receipt) @@ -395,15 +379,6 @@ def callback(raw_response, _, headers): for receipt, actual in zip(returned_model, actual): if actual.fields is None: # second page is blank continue - self.assertFormFieldTransformCorrect(receipt.merchant_address, actual.fields.get("MerchantAddress"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_name, actual.fields.get("MerchantName"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_phone_number, actual.fields.get("MerchantPhoneNumber"), read_results) - self.assertFormFieldTransformCorrect(receipt.subtotal, actual.fields.get("Subtotal"), read_results) - self.assertFormFieldTransformCorrect(receipt.tax, actual.fields.get("Tax"), read_results) - self.assertFormFieldTransformCorrect(receipt.tip, actual.fields.get("Tip"), read_results) - self.assertFormFieldTransformCorrect(receipt.total, actual.fields.get("Total"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_date, actual.fields.get("TransactionDate"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_time, actual.fields.get("TransactionTime"), read_results) # check dict values self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantAddress"), actual.fields.get("MerchantAddress"), read_results) @@ -421,11 +396,12 @@ def callback(raw_response, _, headers): self.assertEqual(receipt.page_range.last_page_number, actual.page_range[1]) # check receipt type - self.assertEqual(receipt.receipt_type.confidence, actual.fields["ReceiptType"].confidence) - self.assertEqual(receipt.receipt_type.type, actual.fields["ReceiptType"].value_string) + receipt_type = receipt.fields.get("ReceiptType") + self.assertEqual(receipt_type.confidence, actual.fields["ReceiptType"].confidence) + self.assertEqual(receipt_type.value, actual.fields["ReceiptType"].value_string) # check receipt items - self.assertReceiptItemsTransformCorrect(receipt.receipt_items, actual.fields["Items"], read_results) + self.assertReceiptItemsTransformCorrect(receipt.fields["Items"].value, actual.fields["Items"], read_results) # Check form pages self.assertFormPagesTransformCorrect(returned_model, read_results) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_async.py index f496ee796fb5..3cfd22fc875d 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_async.py @@ -9,7 +9,7 @@ from azure.core.exceptions import ServiceRequestError, ClientAuthenticationError, HttpResponseError from azure.core.credentials import AzureKeyCredential from azure.ai.formrecognizer._generated.models import AnalyzeOperationResult -from azure.ai.formrecognizer._response_handlers import prepare_us_receipt +from azure.ai.formrecognizer._response_handlers import prepare_receipt from azure.ai.formrecognizer.aio import FormRecognizerClient from azure.ai.formrecognizer import FormContentType from testcase import GlobalFormRecognizerAccountPreparer @@ -135,7 +135,7 @@ async def test_receipt_stream_transform_png(self, resource_group, location, form def callback(raw_response, _, headers): analyze_result = client._client._deserialize(AnalyzeOperationResult, raw_response) - extracted_receipt = prepare_us_receipt(analyze_result) + extracted_receipt = prepare_receipt(analyze_result) responses.append(analyze_result) responses.append(extracted_receipt) @@ -155,17 +155,6 @@ def callback(raw_response, _, headers): read_results = raw_response.analyze_result.read_results document_results = raw_response.analyze_result.document_results - # check hardcoded values - self.assertFormFieldTransformCorrect(receipt.merchant_address, actual.get("MerchantAddress"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_name, actual.get("MerchantName"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_phone_number, actual.get("MerchantPhoneNumber"), read_results) - self.assertFormFieldTransformCorrect(receipt.subtotal, actual.get("Subtotal"), read_results) - self.assertFormFieldTransformCorrect(receipt.tax, actual.get("Tax"), read_results) - self.assertFormFieldTransformCorrect(receipt.tip, actual.get("Tip"), read_results) - self.assertFormFieldTransformCorrect(receipt.total, actual.get("Total"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_date, actual.get("TransactionDate"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_time, actual.get("TransactionTime"), read_results) - # check dict values self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantAddress"), actual.get("MerchantAddress"), read_results) self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantName"), actual.get("MerchantName"), read_results) @@ -182,11 +171,12 @@ def callback(raw_response, _, headers): self.assertEqual(receipt.page_range.last_page_number, document_results[0].page_range[1]) # check receipt type - self.assertEqual(receipt.receipt_type.confidence, actual["ReceiptType"].confidence) - self.assertEqual(receipt.receipt_type.type, actual["ReceiptType"].value_string) + receipt_type = receipt.fields.get("ReceiptType") + self.assertEqual(receipt_type.confidence, actual["ReceiptType"].confidence) + self.assertEqual(receipt_type.value, actual["ReceiptType"].value_string) # check receipt items - self.assertReceiptItemsTransformCorrect(receipt.receipt_items, actual["Items"], read_results) + self.assertReceiptItemsTransformCorrect(receipt.fields["Items"].value, actual["Items"], read_results) # Check page metadata self.assertFormPagesTransformCorrect(receipt.pages, read_results) @@ -199,7 +189,7 @@ async def test_receipt_stream_transform_jpg(self, resource_group, location, form def callback(raw_response, _, headers): analyze_result = client._client._deserialize(AnalyzeOperationResult, raw_response) - extracted_receipt = prepare_us_receipt(analyze_result) + extracted_receipt = prepare_receipt(analyze_result) responses.append(analyze_result) responses.append(extracted_receipt) @@ -220,17 +210,6 @@ def callback(raw_response, _, headers): document_results = raw_response.analyze_result.document_results page_results = raw_response.analyze_result.page_results - # check hardcoded values - self.assertFormFieldTransformCorrect(receipt.merchant_address, actual.get("MerchantAddress"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_name, actual.get("MerchantName"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_phone_number, actual.get("MerchantPhoneNumber"), read_results) - self.assertFormFieldTransformCorrect(receipt.subtotal, actual.get("Subtotal"), read_results) - self.assertFormFieldTransformCorrect(receipt.tax, actual.get("Tax"), read_results) - self.assertFormFieldTransformCorrect(receipt.tip, actual.get("Tip"), read_results) - self.assertFormFieldTransformCorrect(receipt.total, actual.get("Total"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_date, actual.get("TransactionDate"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_time, actual.get("TransactionTime"), read_results) - # check dict values self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantAddress"), actual.get("MerchantAddress"), read_results) self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantName"), actual.get("MerchantName"), read_results) @@ -247,11 +226,12 @@ def callback(raw_response, _, headers): self.assertEqual(receipt.page_range.last_page_number, document_results[0].page_range[1]) # check receipt type - self.assertEqual(receipt.receipt_type.confidence, actual["ReceiptType"].confidence) - self.assertEqual(receipt.receipt_type.type, actual["ReceiptType"].value_string) + receipt_type = receipt.fields.get("ReceiptType") + self.assertEqual(receipt_type.confidence, actual["ReceiptType"].confidence) + self.assertEqual(receipt_type.value, actual["ReceiptType"].value_string) # check receipt items - self.assertReceiptItemsTransformCorrect(receipt.receipt_items, actual["Items"], read_results) + self.assertReceiptItemsTransformCorrect(receipt.fields["Items"].value, actual["Items"], read_results) # Check form pages self.assertFormPagesTransformCorrect(receipt.pages, read_results) @@ -267,21 +247,22 @@ async def test_receipt_jpg(self, resource_group, location, form_recognizer_accou self.assertEqual(len(result), 1) receipt = result[0] - self.assertEqual(receipt.merchant_address.value, '123 Main Street Redmond, WA 98052') - self.assertEqual(receipt.merchant_name.value, 'Contoso Contoso') - self.assertEqual(receipt.merchant_phone_number.value, '+19876543210') - self.assertEqual(receipt.subtotal.value, 11.7) - self.assertEqual(receipt.tax.value, 1.17) - self.assertEqual(receipt.tip.value, 1.63) - self.assertEqual(receipt.total.value, 14.5) - self.assertEqual(receipt.transaction_date.value, date(year=2019, month=6, day=10)) - self.assertEqual(receipt.transaction_time.value, time(hour=13, minute=59, second=0)) + self.assertEqual(receipt.fields.get("MerchantAddress").value, '123 Main Street Redmond, WA 98052') + self.assertEqual(receipt.fields.get("MerchantName").value, 'Contoso Contoso') + self.assertEqual(receipt.fields.get("MerchantPhoneNumber").value, '+19876543210') + self.assertEqual(receipt.fields.get("Subtotal").value, 11.7) + self.assertEqual(receipt.fields.get("Tax").value, 1.17) + self.assertEqual(receipt.fields.get("Tip").value, 1.63) + self.assertEqual(receipt.fields.get("Total").value, 14.5) + self.assertEqual(receipt.fields.get("TransactionDate").value, date(year=2019, month=6, day=10)) + self.assertEqual(receipt.fields.get("TransactionTime").value, time(hour=13, minute=59, second=0)) self.assertEqual(receipt.page_range.first_page_number, 1) self.assertEqual(receipt.page_range.last_page_number, 1) self.assertFormPagesHasValues(receipt.pages) - self.assertIsNotNone(receipt.receipt_type.confidence) - self.assertEqual(receipt.receipt_type.type, 'Itemized') - self.assertReceiptItemsHasValues(receipt.receipt_items, receipt.page_range.first_page_number, False) + receipt_type = receipt.fields.get("ReceiptType") + self.assertIsNotNone(receipt_type.confidence) + self.assertEqual(receipt_type.value, 'Itemized') + self.assertReceiptItemsHasValues(receipt.fields["Items"].value, receipt.page_range.first_page_number, False) @GlobalFormRecognizerAccountPreparer() async def test_receipt_png(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -293,18 +274,19 @@ async def test_receipt_png(self, resource_group, location, form_recognizer_accou result = await client.recognize_receipts(receipt) self.assertEqual(len(result), 1) receipt = result[0] - self.assertEqual(receipt.merchant_address.value, '123 Main Street Redmond, WA 98052') - self.assertEqual(receipt.merchant_name.value, 'Contoso Contoso') - self.assertEqual(receipt.subtotal.value, 1098.99) - self.assertEqual(receipt.tax.value, 104.4) - self.assertEqual(receipt.total.value, 1203.39) - self.assertEqual(receipt.transaction_date.value, date(year=2019, month=6, day=10)) - self.assertEqual(receipt.transaction_time.value, time(hour=13, minute=59, second=0)) + self.assertEqual(receipt.fields.get("MerchantAddress").value, '123 Main Street Redmond, WA 98052') + self.assertEqual(receipt.fields.get("MerchantName").value, 'Contoso Contoso') + self.assertEqual(receipt.fields.get("Subtotal").value, 1098.99) + self.assertEqual(receipt.fields.get("Tax").value, 104.4) + self.assertEqual(receipt.fields.get("Total").value, 1203.39) + self.assertEqual(receipt.fields.get("TransactionDate").value, date(year=2019, month=6, day=10)) + self.assertEqual(receipt.fields.get("TransactionTime").value, time(hour=13, minute=59, second=0)) self.assertEqual(receipt.page_range.first_page_number, 1) self.assertEqual(receipt.page_range.last_page_number, 1) self.assertFormPagesHasValues(receipt.pages) - self.assertIsNotNone(receipt.receipt_type.confidence) - self.assertEqual(receipt.receipt_type.type, 'Itemized') + receipt_type = receipt.fields.get("ReceiptType") + self.assertIsNotNone(receipt_type.confidence) + self.assertEqual(receipt_type.value, 'Itemized') @GlobalFormRecognizerAccountPreparer() async def test_receipt_jpg_include_text_content(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -318,7 +300,7 @@ async def test_receipt_jpg_include_text_content(self, resource_group, location, self.assertFormPagesHasValues(receipt.pages) for field, value in receipt.__dict__.items(): - if field not in ["receipt_type", "receipt_items", "page_range", "pages", "fields", "form_type", "receipt_locale"]: + if field not in ["receipt_items", "page_range", "pages", "fields", "form_type"]: form_field = getattr(receipt, field) self.assertTextContentHasValues(form_field.value_data.text_content, receipt.page_range.first_page_number) @@ -334,27 +316,29 @@ async def test_receipt_multipage(self, resource_group, location, form_recognizer self.assertEqual(len(result), 3) receipt = result[0] - self.assertEqual(receipt.merchant_address.value, '123 Hobbit Lane 567 Main St. Redmond, WA Redmond, WA') - self.assertEqual(receipt.merchant_name.value, 'Bilbo Baggins') - self.assertEqual(receipt.merchant_phone_number.value, '+15555555555') - self.assertEqual(receipt.subtotal.value, 300.0) - self.assertEqual(receipt.total.value, 100.0) + self.assertEqual(receipt.fields.get("MerchantAddress").value, '123 Hobbit Lane 567 Main St. Redmond, WA Redmond, WA') + self.assertEqual(receipt.fields.get("MerchantName").value, 'Bilbo Baggins') + self.assertEqual(receipt.fields.get("MerchantPhoneNumber").value, '+15555555555') + self.assertEqual(receipt.fields.get("Subtotal").value, 300.0) + self.assertEqual(receipt.fields.get("Total").value, 100.0) self.assertEqual(receipt.page_range.first_page_number, 1) self.assertEqual(receipt.page_range.last_page_number, 1) self.assertFormPagesHasValues(receipt.pages) - self.assertIsNotNone(receipt.receipt_type.confidence) - self.assertEqual(receipt.receipt_type.type, 'Itemized') + receipt_type = receipt.fields.get("ReceiptType") + self.assertIsNotNone(receipt_type.confidence) + self.assertEqual(receipt_type.value, 'Itemized') receipt = result[2] - self.assertEqual(receipt.merchant_address.value, '123 Hobbit Lane 567 Main St. Redmond, WA Redmond, WA') - self.assertEqual(receipt.merchant_name.value, 'Frodo Baggins') - self.assertEqual(receipt.merchant_phone_number.value, '+15555555555') - self.assertEqual(receipt.subtotal.value, 3000.0) - self.assertEqual(receipt.total.value, 1000.0) + self.assertEqual(receipt.fields.get("MerchantAddress").value, '123 Hobbit Lane 567 Main St. Redmond, WA Redmond, WA') + self.assertEqual(receipt.fields.get("MerchantName").value, 'Frodo Baggins') + self.assertEqual(receipt.fields.get("MerchantPhoneNumber").value, '+15555555555') + self.assertEqual(receipt.fields.get("Subtotal").value, 3000.0) + self.assertEqual(receipt.fields.get("Total").value, 1000.0) self.assertEqual(receipt.page_range.first_page_number, 3) self.assertEqual(receipt.page_range.last_page_number, 3) self.assertFormPagesHasValues(receipt.pages) - self.assertIsNotNone(receipt.receipt_type.confidence) - self.assertEqual(receipt.receipt_type.type, 'Itemized') + receipt_type = receipt.fields.get("ReceiptType") + self.assertIsNotNone(receipt_type.confidence) + self.assertEqual(receipt_type.value, 'Itemized') @GlobalFormRecognizerAccountPreparer() async def test_receipt_multipage_transform(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -364,7 +348,7 @@ async def test_receipt_multipage_transform(self, resource_group, location, form_ def callback(raw_response, _, headers): analyze_result = client._client._deserialize(AnalyzeOperationResult, raw_response) - extracted_receipt = prepare_us_receipt(analyze_result) + extracted_receipt = prepare_receipt(analyze_result) responses.append(analyze_result) responses.append(extracted_receipt) @@ -388,15 +372,6 @@ def callback(raw_response, _, headers): for receipt, actual in zip(returned_model, actual): if actual.fields is None: # second page is blank continue - self.assertFormFieldTransformCorrect(receipt.merchant_address, actual.fields.get("MerchantAddress"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_name, actual.fields.get("MerchantName"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_phone_number, actual.fields.get("MerchantPhoneNumber"), read_results) - self.assertFormFieldTransformCorrect(receipt.subtotal, actual.fields.get("Subtotal"), read_results) - self.assertFormFieldTransformCorrect(receipt.tax, actual.fields.get("Tax"), read_results) - self.assertFormFieldTransformCorrect(receipt.tip, actual.fields.get("Tip"), read_results) - self.assertFormFieldTransformCorrect(receipt.total, actual.fields.get("Total"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_date, actual.fields.get("TransactionDate"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_time, actual.fields.get("TransactionTime"), read_results) # check dict values self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantAddress"), actual.fields.get("MerchantAddress"), read_results) @@ -414,11 +389,12 @@ def callback(raw_response, _, headers): self.assertEqual(receipt.page_range.last_page_number, actual.page_range[1]) # check receipt type - self.assertEqual(receipt.receipt_type.confidence, actual.fields["ReceiptType"].confidence) - self.assertEqual(receipt.receipt_type.type, actual.fields["ReceiptType"].value_string) + receipt_type = receipt.fields.get("ReceiptType") + self.assertEqual(receipt_type.confidence, actual.fields["ReceiptType"].confidence) + self.assertEqual(receipt_type.value, actual.fields["ReceiptType"].value_string) # check receipt items - self.assertReceiptItemsTransformCorrect(receipt.receipt_items, actual.fields["Items"], read_results) + self.assertReceiptItemsTransformCorrect(receipt.fields["Items"].value, actual.fields["Items"], read_results) # Check form pages self.assertFormPagesTransformCorrect(returned_model, read_results) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url.py index 9771d8255746..2ab8315d9077 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url.py @@ -9,7 +9,7 @@ from azure.core.exceptions import HttpResponseError, ServiceRequestError, ClientAuthenticationError from azure.core.credentials import AzureKeyCredential from azure.ai.formrecognizer._generated.models import AnalyzeOperationResult -from azure.ai.formrecognizer._response_handlers import prepare_us_receipt +from azure.ai.formrecognizer._response_handlers import prepare_receipt from azure.ai.formrecognizer import FormRecognizerClient from testcase import FormRecognizerTest, GlobalFormRecognizerAccountPreparer @@ -65,7 +65,7 @@ def test_receipt_url_transform_jpg(self, resource_group, location, form_recogniz def callback(raw_response, _, headers): analyze_result = client._client._deserialize(AnalyzeOperationResult, raw_response) - extracted_receipt = prepare_us_receipt(analyze_result) + extracted_receipt = prepare_receipt(analyze_result) responses.append(analyze_result) responses.append(extracted_receipt) @@ -83,17 +83,6 @@ def callback(raw_response, _, headers): read_results = raw_response.analyze_result.read_results document_results = raw_response.analyze_result.document_results - # check hardcoded values - self.assertFormFieldTransformCorrect(receipt.merchant_address, actual.get("MerchantAddress"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_name, actual.get("MerchantName"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_phone_number, actual.get("MerchantPhoneNumber"), read_results) - self.assertFormFieldTransformCorrect(receipt.subtotal, actual.get("Subtotal"), read_results) - self.assertFormFieldTransformCorrect(receipt.tax, actual.get("Tax"), read_results) - self.assertFormFieldTransformCorrect(receipt.tip, actual.get("Tip"), read_results) - self.assertFormFieldTransformCorrect(receipt.total, actual.get("Total"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_date, actual.get("TransactionDate"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_time, actual.get("TransactionTime"), read_results) - # check dict values self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantAddress"), actual.get("MerchantAddress"), read_results) self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantName"), actual.get("MerchantName"), read_results) @@ -110,11 +99,12 @@ def callback(raw_response, _, headers): self.assertEqual(receipt.page_range.last_page_number, document_results[0].page_range[1]) # check receipt type - self.assertEqual(receipt.receipt_type.confidence, actual["ReceiptType"].confidence) - self.assertEqual(receipt.receipt_type.type, actual["ReceiptType"].value_string) + receipt_type = receipt.fields.get("ReceiptType") + self.assertEqual(receipt_type.confidence, actual["ReceiptType"].confidence) + self.assertEqual(receipt_type.value, actual["ReceiptType"].value_string) # check receipt items - self.assertReceiptItemsTransformCorrect(receipt.receipt_items, actual["Items"], read_results) + self.assertReceiptItemsTransformCorrect(receipt.fields["Items"].value, actual["Items"], read_results) # Check page metadata self.assertFormPagesTransformCorrect(receipt.pages, read_results) @@ -127,7 +117,7 @@ def test_receipt_url_transform_png(self, resource_group, location, form_recogniz def callback(raw_response, _, headers): analyze_result = client._client._deserialize(AnalyzeOperationResult, raw_response) - extracted_receipt = prepare_us_receipt(analyze_result) + extracted_receipt = prepare_receipt(analyze_result) responses.append(analyze_result) responses.append(extracted_receipt) @@ -145,17 +135,6 @@ def callback(raw_response, _, headers): read_results = raw_response.analyze_result.read_results document_results = raw_response.analyze_result.document_results - # check hardcoded values - self.assertFormFieldTransformCorrect(receipt.merchant_address, actual.get("MerchantAddress"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_name, actual.get("MerchantName"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_phone_number, actual.get("MerchantPhoneNumber"), read_results) - self.assertFormFieldTransformCorrect(receipt.subtotal, actual.get("Subtotal"), read_results) - self.assertFormFieldTransformCorrect(receipt.tax, actual.get("Tax"), read_results) - self.assertFormFieldTransformCorrect(receipt.tip, actual.get("Tip"), read_results) - self.assertFormFieldTransformCorrect(receipt.total, actual.get("Total"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_date, actual.get("TransactionDate"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_time, actual.get("TransactionTime"), read_results) - # check dict values self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantAddress"), actual.get("MerchantAddress"), read_results) self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantName"), actual.get("MerchantName"), read_results) @@ -172,11 +151,12 @@ def callback(raw_response, _, headers): self.assertEqual(receipt.page_range.last_page_number, document_results[0].page_range[1]) # check receipt type - self.assertEqual(receipt.receipt_type.confidence, actual["ReceiptType"].confidence) - self.assertEqual(receipt.receipt_type.type, actual["ReceiptType"].value_string) + receipt_type = receipt.fields.get("ReceiptType") + self.assertEqual(receipt_type.confidence, actual["ReceiptType"].confidence) + self.assertEqual(receipt_type.value, actual["ReceiptType"].value_string) # check receipt items - self.assertReceiptItemsTransformCorrect(receipt.receipt_items, actual["Items"], read_results) + self.assertReceiptItemsTransformCorrect(receipt.fields["Items"].value, actual["Items"], read_results) # Check page metadata self.assertFormPagesTransformCorrect(receipt.pages, read_results) @@ -196,7 +176,7 @@ def test_receipt_url_include_text_content(self, resource_group, location, form_r self.assertFormPagesHasValues(receipt.pages) for field, value in receipt.__dict__.items(): - if field not in ["receipt_type", "receipt_items", "page_range", "pages", "fields", "form_type", "receipt_locale"]: + if field not in ["receipt_items", "page_range", "pages", "fields", "form_type"]: field = getattr(receipt, field) self.assertTextContentHasValues(field.value_data.text_content, receipt.page_range.first_page_number) @@ -212,21 +192,22 @@ def test_receipt_url_jpg(self, resource_group, location, form_recognizer_account result = poller.result() self.assertEqual(len(result), 1) receipt = result[0] - self.assertEqual(receipt.merchant_address.value, '123 Main Street Redmond, WA 98052') - self.assertEqual(receipt.merchant_name.value, 'Contoso Contoso') - self.assertEqual(receipt.merchant_phone_number.value, '+19876543210') - self.assertEqual(receipt.subtotal.value, 11.7) - self.assertEqual(receipt.tax.value, 1.17) - self.assertEqual(receipt.tip.value, 1.63) - self.assertEqual(receipt.total.value, 14.5) - self.assertEqual(receipt.transaction_date.value, date(year=2019, month=6, day=10)) - self.assertEqual(receipt.transaction_time.value, time(hour=13, minute=59, second=0)) + self.assertEqual(receipt.fields.get("MerchantAddress").value, '123 Main Street Redmond, WA 98052') + self.assertEqual(receipt.fields.get("MerchantName").value, 'Contoso Contoso') + self.assertEqual(receipt.fields.get("MerchantPhoneNumber").value, '+19876543210') + self.assertEqual(receipt.fields.get("Subtotal").value, 11.7) + self.assertEqual(receipt.fields.get("Tax").value, 1.17) + self.assertEqual(receipt.fields.get("Tip").value, 1.63) + self.assertEqual(receipt.fields.get("Total").value, 14.5) + self.assertEqual(receipt.fields.get("TransactionDate").value, date(year=2019, month=6, day=10)) + self.assertEqual(receipt.fields.get("TransactionTime").value, time(hour=13, minute=59, second=0)) self.assertEqual(receipt.page_range.first_page_number, 1) self.assertEqual(receipt.page_range.last_page_number, 1) self.assertFormPagesHasValues(receipt.pages) - self.assertIsNotNone(receipt.receipt_type.confidence) - self.assertEqual(receipt.receipt_type.type, 'Itemized') - self.assertReceiptItemsHasValues(receipt.receipt_items, receipt.page_range.first_page_number, False) + receipt_type = receipt.fields.get("ReceiptType") + self.assertIsNotNone(receipt_type.confidence) + self.assertEqual(receipt_type.value, 'Itemized') + self.assertReceiptItemsHasValues(receipt.fields["Items"].value, receipt.page_range.first_page_number, False) @GlobalFormRecognizerAccountPreparer() def test_receipt_url_png(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -237,18 +218,19 @@ def test_receipt_url_png(self, resource_group, location, form_recognizer_account result = poller.result() self.assertEqual(len(result), 1) receipt = result[0] - self.assertEqual(receipt.merchant_address.value, '123 Main Street Redmond, WA 98052') - self.assertEqual(receipt.merchant_name.value, 'Contoso Contoso') - self.assertEqual(receipt.subtotal.value, 1098.99) - self.assertEqual(receipt.tax.value, 104.4) - self.assertEqual(receipt.total.value, 1203.39) - self.assertEqual(receipt.transaction_date.value, date(year=2019, month=6, day=10)) - self.assertEqual(receipt.transaction_time.value, time(hour=13, minute=59, second=0)) + self.assertEqual(receipt.fields.get("MerchantAddress").value, '123 Main Street Redmond, WA 98052') + self.assertEqual(receipt.fields.get("MerchantName").value, 'Contoso Contoso') + self.assertEqual(receipt.fields.get("Subtotal").value, 1098.99) + self.assertEqual(receipt.fields.get("Tax").value, 104.4) + self.assertEqual(receipt.fields.get("Total").value, 1203.39) + self.assertEqual(receipt.fields.get("TransactionDate").value, date(year=2019, month=6, day=10)) + self.assertEqual(receipt.fields.get("TransactionTime").value, time(hour=13, minute=59, second=0)) self.assertEqual(receipt.page_range.first_page_number, 1) self.assertEqual(receipt.page_range.last_page_number, 1) self.assertFormPagesHasValues(receipt.pages) - self.assertIsNotNone(receipt.receipt_type.confidence) - self.assertEqual(receipt.receipt_type.type, 'Itemized') + receipt_type = receipt.fields.get("ReceiptType") + self.assertIsNotNone(receipt_type.confidence) + self.assertEqual(receipt_type.value, 'Itemized') @GlobalFormRecognizerAccountPreparer() def test_receipt_multipage_url(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -259,27 +241,29 @@ def test_receipt_multipage_url(self, resource_group, location, form_recognizer_a self.assertEqual(len(result), 3) receipt = result[0] - self.assertEqual(receipt.merchant_address.value, '123 Hobbit Lane 567 Main St. Redmond, WA Redmond, WA') - self.assertEqual(receipt.merchant_name.value, 'Bilbo Baggins') - self.assertEqual(receipt.merchant_phone_number.value, '+15555555555') - self.assertEqual(receipt.subtotal.value, 300.0) - self.assertEqual(receipt.total.value, 100.0) + self.assertEqual(receipt.fields.get("MerchantAddress").value, '123 Hobbit Lane 567 Main St. Redmond, WA Redmond, WA') + self.assertEqual(receipt.fields.get("MerchantName").value, 'Bilbo Baggins') + self.assertEqual(receipt.fields.get("MerchantPhoneNumber").value, '+15555555555') + self.assertEqual(receipt.fields.get("Subtotal").value, 300.0) + self.assertEqual(receipt.fields.get("Total").value, 100.0) self.assertEqual(receipt.page_range.first_page_number, 1) self.assertEqual(receipt.page_range.last_page_number, 1) self.assertFormPagesHasValues(receipt.pages) - self.assertIsNotNone(receipt.receipt_type.confidence) - self.assertEqual(receipt.receipt_type.type, 'Itemized') + receipt_type = receipt.fields.get("ReceiptType") + self.assertIsNotNone(receipt_type.confidence) + self.assertEqual(receipt_type.value, 'Itemized') receipt = result[2] - self.assertEqual(receipt.merchant_address.value, '123 Hobbit Lane 567 Main St. Redmond, WA Redmond, WA') - self.assertEqual(receipt.merchant_name.value, 'Frodo Baggins') - self.assertEqual(receipt.merchant_phone_number.value, '+15555555555') - self.assertEqual(receipt.subtotal.value, 3000.0) - self.assertEqual(receipt.total.value, 1000.0) + self.assertEqual(receipt.fields.get("MerchantAddress").value, '123 Hobbit Lane 567 Main St. Redmond, WA Redmond, WA') + self.assertEqual(receipt.fields.get("MerchantName").value, 'Frodo Baggins') + self.assertEqual(receipt.fields.get("MerchantPhoneNumber").value, '+15555555555') + self.assertEqual(receipt.fields.get("Subtotal").value, 3000.0) + self.assertEqual(receipt.fields.get("Total").value, 1000.0) self.assertEqual(receipt.page_range.first_page_number, 3) self.assertEqual(receipt.page_range.last_page_number, 3) self.assertFormPagesHasValues(receipt.pages) - self.assertIsNotNone(receipt.receipt_type.confidence) - self.assertEqual(receipt.receipt_type.type, 'Itemized') + receipt_type = receipt.fields.get("ReceiptType") + self.assertIsNotNone(receipt_type.confidence) + self.assertEqual(receipt_type.value, 'Itemized') @GlobalFormRecognizerAccountPreparer() def test_receipt_multipage_transform_url(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -289,7 +273,7 @@ def test_receipt_multipage_transform_url(self, resource_group, location, form_re def callback(raw_response, _, headers): analyze_result = client._client._deserialize(AnalyzeOperationResult, raw_response) - extracted_receipt = prepare_us_receipt(analyze_result) + extracted_receipt = prepare_receipt(analyze_result) responses.append(analyze_result) responses.append(extracted_receipt) @@ -311,15 +295,6 @@ def callback(raw_response, _, headers): for receipt, actual in zip(returned_model, actual): if actual.fields is None: # second page is blank continue - self.assertFormFieldTransformCorrect(receipt.merchant_address, actual.fields.get("MerchantAddress"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_name, actual.fields.get("MerchantName"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_phone_number, actual.fields.get("MerchantPhoneNumber"), read_results) - self.assertFormFieldTransformCorrect(receipt.subtotal, actual.fields.get("Subtotal"), read_results) - self.assertFormFieldTransformCorrect(receipt.tax, actual.fields.get("Tax"), read_results) - self.assertFormFieldTransformCorrect(receipt.tip, actual.fields.get("Tip"), read_results) - self.assertFormFieldTransformCorrect(receipt.total, actual.fields.get("Total"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_date, actual.fields.get("TransactionDate"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_time, actual.fields.get("TransactionTime"), read_results) # check dict values self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantAddress"), actual.fields.get("MerchantAddress"), read_results) @@ -337,11 +312,12 @@ def callback(raw_response, _, headers): self.assertEqual(receipt.page_range.last_page_number, actual.page_range[1]) # check receipt type - self.assertEqual(receipt.receipt_type.confidence, actual.fields["ReceiptType"].confidence) - self.assertEqual(receipt.receipt_type.type, actual.fields["ReceiptType"].value_string) + receipt_type = receipt.fields.get("ReceiptType") + self.assertEqual(receipt_type.confidence, actual.fields["ReceiptType"].confidence) + self.assertEqual(receipt_type.value, actual.fields["ReceiptType"].value_string) # check receipt items - self.assertReceiptItemsTransformCorrect(receipt.receipt_items, actual.fields["Items"], read_results) + self.assertReceiptItemsTransformCorrect(receipt.fields["Items"].value, actual.fields["Items"], read_results) # Check form pages self.assertFormPagesTransformCorrect(returned_model, read_results) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url_async.py index 3c95d8cf8d9d..d3981db07f21 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url_async.py @@ -9,7 +9,7 @@ from azure.core.exceptions import HttpResponseError, ServiceRequestError, ClientAuthenticationError from azure.core.credentials import AzureKeyCredential from azure.ai.formrecognizer._generated.models import AnalyzeOperationResult -from azure.ai.formrecognizer._response_handlers import prepare_us_receipt +from azure.ai.formrecognizer._response_handlers import prepare_receipt from azure.ai.formrecognizer.aio import FormRecognizerClient from testcase import GlobalFormRecognizerAccountPreparer from asynctestcase import AsyncFormRecognizerTest @@ -75,7 +75,7 @@ async def test_receipt_url_transform_jpg(self, resource_group, location, form_re def callback(raw_response, _, headers): analyze_result = client._client._deserialize(AnalyzeOperationResult, raw_response) - extracted_receipt = prepare_us_receipt(analyze_result) + extracted_receipt = prepare_receipt(analyze_result) responses.append(analyze_result) responses.append(extracted_receipt) @@ -92,17 +92,6 @@ def callback(raw_response, _, headers): read_results = raw_response.analyze_result.read_results document_results = raw_response.analyze_result.document_results - # check hardcoded values - self.assertFormFieldTransformCorrect(receipt.merchant_address, actual.get("MerchantAddress"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_name, actual.get("MerchantName"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_phone_number, actual.get("MerchantPhoneNumber"), read_results) - self.assertFormFieldTransformCorrect(receipt.subtotal, actual.get("Subtotal"), read_results) - self.assertFormFieldTransformCorrect(receipt.tax, actual.get("Tax"), read_results) - self.assertFormFieldTransformCorrect(receipt.tip, actual.get("Tip"), read_results) - self.assertFormFieldTransformCorrect(receipt.total, actual.get("Total"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_date, actual.get("TransactionDate"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_time, actual.get("TransactionTime"), read_results) - # check dict values self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantAddress"), actual.get("MerchantAddress"), read_results) self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantName"), actual.get("MerchantName"), read_results) @@ -119,11 +108,12 @@ def callback(raw_response, _, headers): self.assertEqual(receipt.page_range.last_page_number, document_results[0].page_range[1]) # check receipt type - self.assertEqual(receipt.receipt_type.confidence, actual["ReceiptType"].confidence) - self.assertEqual(receipt.receipt_type.type, actual["ReceiptType"].value_string) + receipt_type = receipt.fields.get("ReceiptType") + self.assertEqual(receipt_type.confidence, actual["ReceiptType"].confidence) + self.assertEqual(receipt_type.value, actual["ReceiptType"].value_string) # check receipt items - self.assertReceiptItemsTransformCorrect(receipt.receipt_items, actual["Items"], read_results) + self.assertReceiptItemsTransformCorrect(receipt.fields["Items"].value, actual["Items"], read_results) # Check page metadata self.assertFormPagesTransformCorrect(receipt.pages, read_results) @@ -136,7 +126,7 @@ async def test_receipt_url_transform_png(self, resource_group, location, form_re def callback(raw_response, _, headers): analyze_result = client._client._deserialize(AnalyzeOperationResult, raw_response) - extracted_receipt = prepare_us_receipt(analyze_result) + extracted_receipt = prepare_receipt(analyze_result) responses.append(analyze_result) responses.append(extracted_receipt) @@ -153,17 +143,6 @@ def callback(raw_response, _, headers): read_results = raw_response.analyze_result.read_results document_results = raw_response.analyze_result.document_results - # check hardcoded values - self.assertFormFieldTransformCorrect(receipt.merchant_address, actual.get("MerchantAddress"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_name, actual.get("MerchantName"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_phone_number, actual.get("MerchantPhoneNumber"), read_results) - self.assertFormFieldTransformCorrect(receipt.subtotal, actual.get("Subtotal"), read_results) - self.assertFormFieldTransformCorrect(receipt.tax, actual.get("Tax"), read_results) - self.assertFormFieldTransformCorrect(receipt.tip, actual.get("Tip"), read_results) - self.assertFormFieldTransformCorrect(receipt.total, actual.get("Total"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_date, actual.get("TransactionDate"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_time, actual.get("TransactionTime"), read_results) - # check dict values self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantAddress"), actual.get("MerchantAddress"), read_results) self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantName"), actual.get("MerchantName"), read_results) @@ -180,11 +159,12 @@ def callback(raw_response, _, headers): self.assertEqual(receipt.page_range.last_page_number, document_results[0].page_range[1]) # check receipt type - self.assertEqual(receipt.receipt_type.confidence, actual["ReceiptType"].confidence) - self.assertEqual(receipt.receipt_type.type, actual["ReceiptType"].value_string) + receipt_type = receipt.fields.get("ReceiptType") + self.assertEqual(receipt_type.confidence, actual["ReceiptType"].confidence) + self.assertEqual(receipt_type.value, actual["ReceiptType"].value_string) # check receipt items - self.assertReceiptItemsTransformCorrect(receipt.receipt_items, actual["Items"], read_results) + self.assertReceiptItemsTransformCorrect(receipt.fields["Items"].value, actual["Items"], read_results) # Check page metadata self.assertFormPagesTransformCorrect(receipt.pages, read_results) @@ -203,7 +183,7 @@ async def test_receipt_url_include_text_content(self, resource_group, location, self.assertFormPagesHasValues(receipt.pages) for field, value in receipt.__dict__.items(): - if field not in ["receipt_type", "receipt_items", "page_range", "pages", "fields", "form_type", "receipt_locale"]: + if field not in ["page_range", "pages", "fields", "form_type"]: field = getattr(receipt, field) self.assertTextContentHasValues(field.value_data.text_content, receipt.page_range.first_page_number) @@ -220,21 +200,22 @@ async def test_receipt_url_jpg(self, resource_group, location, form_recognizer_a self.assertEqual(len(result), 1) receipt = result[0] - self.assertEqual(receipt.merchant_address.value, '123 Main Street Redmond, WA 98052') - self.assertEqual(receipt.merchant_name.value, 'Contoso Contoso') - self.assertEqual(receipt.merchant_phone_number.value, '+19876543210') - self.assertEqual(receipt.subtotal.value, 11.7) - self.assertEqual(receipt.tax.value, 1.17) - self.assertEqual(receipt.tip.value, 1.63) - self.assertEqual(receipt.total.value, 14.5) - self.assertEqual(receipt.transaction_date.value, date(year=2019, month=6, day=10)) - self.assertEqual(receipt.transaction_time.value, time(hour=13, minute=59, second=0)) + self.assertEqual(receipt.fields.get("MerchantAddress").value, '123 Main Street Redmond, WA 98052') + self.assertEqual(receipt.fields.get("MerchantName").value, 'Contoso Contoso') + self.assertEqual(receipt.fields.get("MerchantPhoneNumber").value, '+19876543210') + self.assertEqual(receipt.fields.get("Subtotal").value, 11.7) + self.assertEqual(receipt.fields.get("Tax").value, 1.17) + self.assertEqual(receipt.fields.get("Tip").value, 1.63) + self.assertEqual(receipt.fields.get("Total").value, 14.5) + self.assertEqual(receipt.fields.get("TransactionDate").value, date(year=2019, month=6, day=10)) + self.assertEqual(receipt.fields.get("TransactionTime").value, time(hour=13, minute=59, second=0)) self.assertEqual(receipt.page_range.first_page_number, 1) self.assertEqual(receipt.page_range.last_page_number, 1) self.assertFormPagesHasValues(receipt.pages) - self.assertIsNotNone(receipt.receipt_type.confidence) - self.assertEqual(receipt.receipt_type.type, 'Itemized') - self.assertReceiptItemsHasValues(receipt.receipt_items, receipt.page_range.first_page_number, False) + receipt_type = receipt.fields.get("ReceiptType") + self.assertIsNotNone(receipt_type.confidence) + self.assertEqual(receipt_type.value, 'Itemized') + self.assertReceiptItemsHasValues(receipt.fields["Items"].value, receipt.page_range.first_page_number, False) @GlobalFormRecognizerAccountPreparer() async def test_receipt_url_png(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -244,18 +225,19 @@ async def test_receipt_url_png(self, resource_group, location, form_recognizer_a self.assertEqual(len(result), 1) receipt = result[0] - self.assertEqual(receipt.merchant_address.value, '123 Main Street Redmond, WA 98052') - self.assertEqual(receipt.merchant_name.value, 'Contoso Contoso') - self.assertEqual(receipt.subtotal.value, 1098.99) - self.assertEqual(receipt.tax.value, 104.4) - self.assertEqual(receipt.total.value, 1203.39) - self.assertEqual(receipt.transaction_date.value, date(year=2019, month=6, day=10)) - self.assertEqual(receipt.transaction_time.value, time(hour=13, minute=59, second=0)) + self.assertEqual(receipt.fields.get("MerchantAddress").value, '123 Main Street Redmond, WA 98052') + self.assertEqual(receipt.fields.get("MerchantName").value, 'Contoso Contoso') + self.assertEqual(receipt.fields.get("Subtotal").value, 1098.99) + self.assertEqual(receipt.fields.get("Tax").value, 104.4) + self.assertEqual(receipt.fields.get("Total").value, 1203.39) + self.assertEqual(receipt.fields.get("TransactionDate").value, date(year=2019, month=6, day=10)) + self.assertEqual(receipt.fields.get("TransactionTime").value, time(hour=13, minute=59, second=0)) self.assertEqual(receipt.page_range.first_page_number, 1) self.assertEqual(receipt.page_range.last_page_number, 1) self.assertFormPagesHasValues(receipt.pages) - self.assertIsNotNone(receipt.receipt_type.confidence) - self.assertEqual(receipt.receipt_type.type, 'Itemized') + receipt_type = receipt.fields.get("ReceiptType") + self.assertIsNotNone(receipt_type.confidence) + self.assertEqual(receipt_type.value, 'Itemized') @GlobalFormRecognizerAccountPreparer() async def test_receipt_multipage_url(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -265,27 +247,29 @@ async def test_receipt_multipage_url(self, resource_group, location, form_recogn self.assertEqual(len(result), 3) receipt = result[0] - self.assertEqual(receipt.merchant_address.value, '123 Hobbit Lane 567 Main St. Redmond, WA Redmond, WA') - self.assertEqual(receipt.merchant_name.value, 'Bilbo Baggins') - self.assertEqual(receipt.merchant_phone_number.value, '+15555555555') - self.assertEqual(receipt.subtotal.value, 300.0) - self.assertEqual(receipt.total.value, 100.0) + self.assertEqual(receipt.fields.get("MerchantAddress").value, '123 Hobbit Lane 567 Main St. Redmond, WA Redmond, WA') + self.assertEqual(receipt.fields.get("MerchantName").value, 'Bilbo Baggins') + self.assertEqual(receipt.fields.get("MerchantPhoneNumber").value, '+15555555555') + self.assertEqual(receipt.fields.get("Subtotal").value, 300.0) + self.assertEqual(receipt.fields.get("Total").value, 100.0) self.assertEqual(receipt.page_range.first_page_number, 1) self.assertEqual(receipt.page_range.last_page_number, 1) self.assertFormPagesHasValues(receipt.pages) - self.assertIsNotNone(receipt.receipt_type.confidence) - self.assertEqual(receipt.receipt_type.type, 'Itemized') + receipt_type = receipt.fields.get("ReceiptType") + self.assertIsNotNone(receipt_type.confidence) + self.assertEqual(receipt_type.value, 'Itemized') receipt = result[2] - self.assertEqual(receipt.merchant_address.value, '123 Hobbit Lane 567 Main St. Redmond, WA Redmond, WA') - self.assertEqual(receipt.merchant_name.value, 'Frodo Baggins') - self.assertEqual(receipt.merchant_phone_number.value, '+15555555555') - self.assertEqual(receipt.subtotal.value, 3000.0) - self.assertEqual(receipt.total.value, 1000.0) + self.assertEqual(receipt.fields.get("MerchantAddress").value, '123 Hobbit Lane 567 Main St. Redmond, WA Redmond, WA') + self.assertEqual(receipt.fields.get("MerchantName").value, 'Frodo Baggins') + self.assertEqual(receipt.fields.get("MerchantPhoneNumber").value, '+15555555555') + self.assertEqual(receipt.fields.get("Subtotal").value, 3000.0) + self.assertEqual(receipt.fields.get("Total").value, 1000.0) self.assertEqual(receipt.page_range.first_page_number, 3) self.assertEqual(receipt.page_range.last_page_number, 3) self.assertFormPagesHasValues(receipt.pages) - self.assertIsNotNone(receipt.receipt_type.confidence) - self.assertEqual(receipt.receipt_type.type, 'Itemized') + receipt_type = receipt.fields.get("ReceiptType") + self.assertIsNotNone(receipt_type.confidence) + self.assertEqual(receipt_type.value, 'Itemized') @GlobalFormRecognizerAccountPreparer() async def test_receipt_multipage_transform_url(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -295,7 +279,7 @@ async def test_receipt_multipage_transform_url(self, resource_group, location, f def callback(raw_response, _, headers): analyze_result = client._client._deserialize(AnalyzeOperationResult, raw_response) - extracted_receipt = prepare_us_receipt(analyze_result) + extracted_receipt = prepare_receipt(analyze_result) responses.append(analyze_result) responses.append(extracted_receipt) @@ -316,15 +300,6 @@ def callback(raw_response, _, headers): for receipt, actual in zip(returned_model, actual): if actual.fields is None: # second page is blank continue - self.assertFormFieldTransformCorrect(receipt.merchant_address, actual.fields.get("MerchantAddress"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_name, actual.fields.get("MerchantName"), read_results) - self.assertFormFieldTransformCorrect(receipt.merchant_phone_number, actual.fields.get("MerchantPhoneNumber"), read_results) - self.assertFormFieldTransformCorrect(receipt.subtotal, actual.fields.get("Subtotal"), read_results) - self.assertFormFieldTransformCorrect(receipt.tax, actual.fields.get("Tax"), read_results) - self.assertFormFieldTransformCorrect(receipt.tip, actual.fields.get("Tip"), read_results) - self.assertFormFieldTransformCorrect(receipt.total, actual.fields.get("Total"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_date, actual.fields.get("TransactionDate"), read_results) - self.assertFormFieldTransformCorrect(receipt.transaction_time, actual.fields.get("TransactionTime"), read_results) # check dict values self.assertFormFieldTransformCorrect(receipt.fields.get("MerchantAddress"), actual.fields.get("MerchantAddress"), read_results) @@ -342,11 +317,12 @@ def callback(raw_response, _, headers): self.assertEqual(receipt.page_range.last_page_number, actual.page_range[1]) # check receipt type - self.assertEqual(receipt.receipt_type.confidence, actual.fields["ReceiptType"].confidence) - self.assertEqual(receipt.receipt_type.type, actual.fields["ReceiptType"].value_string) + receipt_type = receipt.fields.get("ReceiptType") + self.assertEqual(receipt_type.confidence, actual.fields["ReceiptType"].confidence) + self.assertEqual(receipt_type.value, actual.fields["ReceiptType"].value_string) # check receipt items - self.assertReceiptItemsTransformCorrect(receipt.receipt_items, actual.fields["Items"], read_results) + self.assertReceiptItemsTransformCorrect(receipt.fields["Items"].value, actual.fields["Items"], read_results) # Check form pages self.assertFormPagesTransformCorrect(returned_model, read_results) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_repr.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_repr.py index ee4ab885f386..9510f300bc59 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_repr.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_repr.py @@ -95,20 +95,6 @@ def form_page(form_table, form_line): assert repr(model) == model_repr return model, model_repr -@pytest.fixture -def us_receipt_type(): - model = _models.ReceiptType(type="Itemized", confidence=1.0) - model_repr = "ReceiptType(type=Itemized, confidence=1.0)" - assert repr(model) == model_repr - return model, model_repr - -@pytest.fixture -def us_receipt_item(form_field_two): - model = _models.USReceiptItem(name=form_field_two[0], quantity=form_field_two[0], price=form_field_two[0], total_price=form_field_two[0]) - model_repr = "USReceiptItem(name={}, quantity={}, price={}, total_price={})".format(form_field_two[1], form_field_two[1], form_field_two[1], form_field_two[1])[:1024] - assert repr(model) == model_repr - return model, model_repr - @pytest.fixture def custom_form_model_field(): model = _models.CustomFormModelField(label="label", name="name", accuracy=0.99) @@ -141,65 +127,21 @@ def training_document_info(form_recognizer_error): class TestRepr(): # Not inheriting form FormRecognizerTest because that doesn't allow me to define pytest fixtures in the same file # Not worth moving pytest fixture definitions to conftest since all I would use is assertEqual and I can just use assert - def test_recognized_form(self, form_field_one, page_range, form_page, us_receipt_type, us_receipt_item): + def test_recognized_form(self, form_field_one, page_range, form_page): model = _models.RecognizedForm(form_type="receipt", fields={"one": form_field_one[0]}, page_range=page_range[0], pages=[form_page[0]]) model_repr = "RecognizedForm(form_type=receipt, fields={{'one': {}}}, page_range={}, pages=[{}])".format( form_field_one[1], page_range[1], form_page[1] )[:1024] assert repr(model) == model_repr - def test_recognized_receipt(self, form_field_one, page_range, form_page, us_receipt_type): + def test_recognized_receipt(self, form_field_one, page_range, form_page): model = _models.RecognizedReceipt( - form_type="receipt", fields={"one": form_field_one[0]}, page_range=page_range[0], pages=[form_page[0]], - receipt_type=us_receipt_type[0], receipt_locale="en-US") + form_type="receipt", fields={"one": form_field_one[0]}, page_range=page_range[0], pages=[form_page[0]]) model_repr = "RecognizedReceipt(form_type=receipt, fields={{'one': {}}}, page_range={}, pages=[{}])".format( - form_field_one[1], page_range[1], form_page[1], us_receipt_type[0], "en-US" + form_field_one[1], page_range[1], form_page[1] )[:1024] assert repr(model) == model_repr - def test_us_receipt(self, form_field_one, form_field_two, us_receipt_type, us_receipt_item, page_range, form_page): - model = _models.USReceipt( - merchant_address=form_field_one[0], - merchant_name=form_field_two[0], - merchant_phone_number=form_field_one[0], - receipt_type=us_receipt_type[0], - receipt_items=[us_receipt_item[0], us_receipt_item[0]], - subtotal=form_field_two[0], - tax=form_field_one[0], - tip=form_field_two[0], - total=form_field_one[0], - transaction_date=form_field_two[0], - transaction_time=form_field_one[0], - fields={ - "one": form_field_one[0] - }, - page_range=page_range[0], - pages=[form_page[0]], - form_type="test", - receipt_locale="en-US" - ) - model_repr="USReceipt(merchant_address={}, merchant_name={}, merchant_phone_number={}, receipt_type={}, receipt_items=[{}, {}], subtotal={}, " \ - "tax={}, tip={}, total={}, transaction_date={}, transaction_time={}, fields={{'one': {}}}, page_range={}, pages=[{}], " \ - "form_type=test, receipt_locale=en-US)".format( - form_field_one[1], - form_field_two[1], - form_field_one[1], - us_receipt_type[1], - us_receipt_item[1], - us_receipt_item[1], - form_field_two[1], - form_field_one[1], - form_field_two[1], - form_field_one[1], - form_field_two[1], - form_field_one[1], - form_field_one[1], - page_range[1], - form_page[1] - )[:1024] - - - assert repr(model) == model_repr def test_custom_form_model(self, custom_form_sub_model, form_recognizer_error, training_document_info): model = _models.CustomFormModel( diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py index bdc95253117a..caeb23bb5a67 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py @@ -262,10 +262,10 @@ def assertReceiptItemsTransformCorrect(self, items, actual_items, read_results=N actual = actual_items.value_array for r, a in zip(items, actual): - self.assertFormFieldTransformCorrect(r.name, a.value_object.get("Name"), read_results) - self.assertFormFieldTransformCorrect(r.quantity, a.value_object.get("Quantity"), read_results) - self.assertFormFieldTransformCorrect(r.total_price, a.value_object.get("TotalPrice"), read_results) - self.assertFormFieldTransformCorrect(r.price, a.value_object.get("Price"), read_results) + self.assertFormFieldTransformCorrect(r.value.get("Name"), a.value_object.get("Name"), read_results) + self.assertFormFieldTransformCorrect(r.value.get("Quantity"), a.value_object.get("Quantity"), read_results) + self.assertFormFieldTransformCorrect(r.value.get("TotalPrice"), a.value_object.get("TotalPrice"), read_results) + self.assertFormFieldTransformCorrect(r.value.get("Price"), a.value_object.get("Price"), read_results) def assertTablesTransformCorrect(self, layout, actual_layout, read_results=None, **kwargs): for table, actual_table in zip(layout, actual_layout): @@ -287,24 +287,24 @@ def assertTablesTransformCorrect(self, layout, actual_layout, read_results=None, def assertReceiptItemsHasValues(self, items, page_number, include_text_content): for item in items: - self.assertBoundingBoxHasPoints(item.name.value_data.bounding_box) - self.assertIsNotNone(item.name.confidence) - self.assertIsNotNone(item.name.value_data.text) - self.assertBoundingBoxHasPoints(item.quantity.value_data.bounding_box) - self.assertIsNotNone(item.quantity.confidence) - self.assertIsNotNone(item.quantity.value_data.text) - self.assertBoundingBoxHasPoints(item.total_price.value_data.bounding_box) - self.assertIsNotNone(item.total_price.confidence) - self.assertIsNotNone(item.total_price.value_data.text) + self.assertBoundingBoxHasPoints(item.value.get("Name").value_data.bounding_box) + self.assertIsNotNone(item.value.get("Name").confidence) + self.assertIsNotNone(item.value.get("Name").value_data.text) + self.assertBoundingBoxHasPoints(item.value.get("Quantity").value_data.bounding_box) + self.assertIsNotNone(item.value.get("Quantity").confidence) + self.assertIsNotNone(item.value.get("Quantity").value_data.text) + self.assertBoundingBoxHasPoints(item.value.get("TotalPrice").value_data.bounding_box) + self.assertIsNotNone(item.value.get("TotalPrice").confidence) + self.assertIsNotNone(item.value.get("TotalPrice").value_data.text) if include_text_content: - self.assertTextContentHasValues(item.name.value_data.text_content, page_number) - self.assertTextContentHasValues(item.name.value_data.text_content, page_number) - self.assertTextContentHasValues(item.name.value_data.text_content, page_number) + self.assertTextContentHasValues(item.value.get("Name").value_data.text_content, page_number) + self.assertTextContentHasValues(item.value.get("Name").value_data.text_content, page_number) + self.assertTextContentHasValues(item.value.get("Name").value_data.text_content, page_number) else: - self.assertIsNone(item.name.value_data.text_content) - self.assertIsNone(item.name.value_data.text_content) - self.assertIsNone(item.name.value_data.text_content) + self.assertIsNone(item.value.get("Name").value_data.text_content) + self.assertIsNone(item.value.get("Name").value_data.text_content) + self.assertIsNone(item.value.get("Name").value_data.text_content) def assertBoundingBoxHasPoints(self, box): if box is None: From a9de6f00133d8e25e0f4104e7334b4e9033503f9 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Wed, 3 Jun 2020 14:44:18 -0700 Subject: [PATCH 05/25] [formrecognizer] adds AsyncLROPoller and continuation token support (#11650) * regenerate code * async poller and continuation token changes * update tests * update samples * update shared requirements * updates after cimultidict change in azure-core * update readme/changelog * mypy * one more update on readme * try with azure-core whitelisted context * revert dev reqs * update changelog with new dependency on azure-core 1.6.0 * forgot to apply changes * update type hints * fix for tests * fix type hints, changelog; delete recording for test that doesn't exist --- .../azure-ai-formrecognizer/CHANGELOG.md | 36 ++- .../azure-ai-formrecognizer/README.md | 10 +- .../formrecognizer/_form_recognizer_client.py | 34 +- .../formrecognizer/_form_training_client.py | 32 +- .../_generated/_form_recognizer_client.py | 2 + .../ai/formrecognizer/_generated/_version.py | 2 +- .../_generated/aio/_configuration_async.py | 2 +- .../aio/_form_recognizer_client_async.py | 6 +- ...form_recognizer_client_operations_async.py | 296 +++++++++++------- .../_form_recognizer_client_operations.py | 278 ++++++++++------ .../aio/_form_recognizer_client_async.py | 127 +++++--- .../aio/_form_training_client_async.py | 68 ++-- .../sample_authentication_async.py | 14 +- .../async_samples/sample_copy_model_async.py | 3 +- ...s_trained_with_and_without_labels_async.py | 19 +- .../sample_get_bounding_boxes_async.py | 6 +- .../sample_manage_custom_models_async.py | 5 +- .../sample_recognize_content_async.py | 5 +- .../sample_recognize_custom_forms_async.py | 8 +- .../sample_recognize_receipts_async.py | 5 +- ...ample_recognize_receipts_from_url_async.py | 3 +- .../sample_train_model_with_labels_async.py | 13 +- ...sample_train_model_without_labels_async.py | 8 +- .../samples/sample_recognize_custom_forms.py | 2 +- .../samples/sample_train_model_with_labels.py | 13 +- .../sample_train_model_without_labels.py | 8 +- .../azure-ai-formrecognizer/setup.py | 2 +- .../tests/test_content.py | 16 + .../tests/test_content_async.py | 70 +++-- .../tests/test_content_from_url.py | 14 + .../tests/test_content_from_url_async.py | 49 ++- .../tests/test_copy_model.py | 27 +- .../tests/test_copy_model_async.py | 43 ++- .../tests/test_custom_forms.py | 44 ++- .../tests/test_custom_forms_async.py | 100 ++++-- .../tests/test_custom_forms_from_url.py | 43 ++- .../tests/test_custom_forms_from_url_async.py | 95 ++++-- .../tests/test_mgmt.py | 4 +- .../tests/test_mgmt_async.py | 10 +- .../tests/test_receipt.py | 16 + .../tests/test_receipt_async.py | 73 +++-- .../tests/test_receipt_from_url.py | 12 + .../tests/test_receipt_from_url_async.py | 51 ++- .../tests/test_training.py | 37 ++- .../tests/test_training_async.py | 50 ++- .../azure-ai-formrecognizer/tests/testcase.py | 7 +- shared_requirements.txt | 2 +- 47 files changed, 1245 insertions(+), 525 deletions(-) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md b/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md index 6fe1439c6791..75231f1a7538 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md +++ b/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md @@ -4,27 +4,36 @@ **Breaking Changes** -- `training_files` parameter of `begin_train_model` is renamed to `training_files_url` -- `use_labels` parameter of `begin_train_model` is renamed to `use_training_labels` +- All asynchronous long running operation methods now return an instance of an `AsyncLROPoller` from `azure-core` +- All asynchronous long running operation methods are renamed with the `begin_` prefix to indicate that an `AsyncLROPoller` is returned: + - `train_model` is renamed to `begin_training` + - `recognize_receipts` is renamed to `begin_recognize_receipts` + - `recognize_receipts_from_url` is renamed to `begin_recognize_receipts_from_url` + - `recognize_content` is renamed to `begin_recognize_content` + - `recognize_content_from_url` is renamed to `begin_recognize_content_from_url` + - `recognize_custom_forms` is renamed to `begin_recognize_custom_forms` + - `recognize_custom_forms_from_url` is renamed to `begin_recognize_custom_forms_from_url` +- Sync method `begin_train_model` renamed to `begin_training` +- `training_files` parameter of `begin_training` is renamed to `training_files_url` +- `use_labels` parameter of `begin_training` is renamed to `use_training_labels` - `list_model_infos` method has been renamed to `list_custom_models` - Removed `get_form_training_client` from `FormRecognizerClient` - Added `get_form_recognizer_client` to `FormTrainingClient` -- A `HttpResponseError` is now raised if a model with `status=="invalid"` is returned from the `begin_train_model()` or `train_model()` methods +- A `HttpResponseError` is now raised if a model with `status=="invalid"` is returned from the `begin_training` methods - `PageRange` is renamed to `FormPageRange` - `first_page` and `last_page` renamed to `first_page_number` and `last_page_number`, respectively on `FormPageRange` -- `FormField` does not have a page_number. -- `begin_recognize_receipts` APIs now return `RecognizedReceipt` instead of `USReceipt` -- `USReceiptType` is renamed to `ReceiptType` -- `use_training_labels` is now a required positional param in the `begin_training` APIs. -- `stream` and `url` parameters found on methods for `FormRecognizerClient` have been renamed to `form` and `form_url`, respectively. -- For recognize receipt methods, parameters have been renamed to `receipt` and `receipt_url`. +- `FormField` does not have a page_number +- `use_training_labels` is now a required positional param in the `begin_training` APIs +- `stream` and `url` parameters found on methods for `FormRecognizerClient` have been renamed to `form` and `form_url`, respectively +- For `begin_recognize_receipt` methods, parameters have been renamed to `receipt` and `receipt_url` - `created_on` and `last_modified` are renamed to `requested_on` and `completed_on` in the -`CustomFormModel` and `CustomFormModelInfo` models. +`CustomFormModel` and `CustomFormModelInfo` models - `models` property of `CustomFormModel` is renamed to `submodels` - `CustomFormSubModel` is renamed to `CustomFormSubmodel` +- `begin_recognize_receipts` APIs now return `RecognizedReceipt` instead of `USReceipt` - Removed `USReceipt`. To see how to deal with the return value of `begin_recognize_receipts`, see the recognize receipt samples in the [samples directory](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/formrecognizer/azure-ai-formrecognizer/samples) for details. - Removed `USReceiptItem`. To see how to access the individual items on a receipt, see the recognize receipt samples in the [samples directory](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/formrecognizer/azure-ai-formrecognizer/samples) for details. -- Removed `ReceiptType` and the `receipt_type` property from `RecognizedReceipt`. See the recognize receipt samples in the [samples directory](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/formrecognizer/azure-ai-formrecognizer/samples) for details. +- Removed `USReceiptType` and the `receipt_type` property from `RecognizedReceipt`. See the recognize receipt samples in the [samples directory](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/formrecognizer/azure-ai-formrecognizer/samples) for details. **New features** @@ -32,6 +41,11 @@ - Authentication using `azure-identity` credentials now supported - see the [Azure Identity documentation](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/identity/azure-identity/README.md) for more information - `page_number` attribute has been added to `FormTable` +- All long running operation methods now accept the keyword argument `continuation_token` to restart the poller from a saved state + +**Dependency updates** + +- Adopted [azure-core](https://pypi.org/project/azure-core/) version 1.6.0 or greater ## 1.0.0b2 (2020-05-06) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/README.md b/sdk/formrecognizer/azure-ai-formrecognizer/README.md index 998f2249121b..3a3e08b33004 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/README.md +++ b/sdk/formrecognizer/azure-ai-formrecognizer/README.md @@ -140,10 +140,10 @@ Long-running operations are operations which consist of an initial request sent followed by polling the service at intervals to determine whether the operation has completed or failed, and if it has succeeded, to get the result. -Methods that train models or recognize values from forms are modeled as long-running operations. The client exposes -a `begin_` method that returns an `LROPoller`. Callers should wait for the operation to complete by -calling `result()` on the operation returned from the `begin_` method. Sample code snippets are provided -to illustrate using long-running operations [below](#examples "Examples"). +Methods that train models, recognize values from forms, or copy models are modeled as long-running operations. +The client exposes a `begin_` method that returns an `LROPoller` or `AsyncLROPoller`. Callers should wait +for the operation to complete by calling `result()` on the operation returned from the `begin_` method. +Sample code snippets are provided to illustrate using long-running operations [below](#examples "Examples"). ## Examples @@ -254,7 +254,7 @@ credential = AzureKeyCredential("") form_training_client = FormTrainingClient(endpoint, credential) container_sas_url = "xxx" # training documents uploaded to blob storage -poller = form_training_client.begin_train_model(container_sas_url) +poller = form_training_client.begin_training(container_sas_url) model = poller.result() # Custom model information diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_recognizer_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_recognizer_client.py index ac2bb7cd304f..b5349668390e 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_recognizer_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_recognizer_client.py @@ -10,6 +10,7 @@ Any, IO, Union, + List, TYPE_CHECKING ) from azure.core.tracing.decorator import distributed_trace @@ -27,6 +28,7 @@ from ._polling import AnalyzePolling if TYPE_CHECKING: from azure.core.credentials import AzureKeyCredential, TokenCredential + from ._models import RecognizedReceipt, FormPage, RecognizedForm class FormRecognizerClient(object): @@ -66,7 +68,7 @@ def __init__(self, endpoint, credential, **kwargs): authentication_policy = get_authentication_policy(credential) self._client = FormRecognizer( endpoint=endpoint, - credential=credential, + credential=credential, # type: ignore sdk_moniker=USER_AGENT, authentication_policy=authentication_policy, **kwargs @@ -78,7 +80,7 @@ def _receipt_callback(self, raw_response, _, headers): # pylint: disable=unused @distributed_trace def begin_recognize_receipts(self, receipt, **kwargs): - # type: (Union[bytes, IO[bytes]], Any) -> LROPoller + # type: (Union[bytes, IO[bytes]], Any) -> LROPoller[List[RecognizedReceipt]] """Extract field text and semantic values from a given US sales receipt. The input document must be of one of the supported content types - 'application/pdf', 'image/jpeg', 'image/png' or 'image/tiff'. @@ -93,6 +95,7 @@ def begin_recognize_receipts(self, receipt, **kwargs): see :class:`~azure.ai.formrecognizer.FormContentType`. :keyword int polling_interval: Waiting time between two polls for LRO operations if no Retry-After header is present. Defaults to 5 seconds. + :keyword str continuation_token: A continuation token to restart a poller from a saved state. :return: An instance of an LROPoller. Call `result()` on the poller object to return a list[:class:`~azure.ai.formrecognizer.RecognizedReceipt`]. :rtype: ~azure.core.polling.LROPoller[list[~azure.ai.formrecognizer.RecognizedReceipt]] @@ -109,6 +112,7 @@ def begin_recognize_receipts(self, receipt, **kwargs): """ polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) + continuation_token = kwargs.pop("continuation_token", None) content_type = kwargs.pop("content_type", None) if content_type == "application/json": raise TypeError("Call begin_recognize_receipts_from_url() to analyze a receipt from a url.") @@ -125,12 +129,13 @@ def begin_recognize_receipts(self, receipt, **kwargs): cls=kwargs.pop("cls", self._receipt_callback), polling=LROBasePolling(timeout=polling_interval, **kwargs), error_map=error_map, + continuation_token=continuation_token, **kwargs ) @distributed_trace def begin_recognize_receipts_from_url(self, receipt_url, **kwargs): - # type: (str, Any) -> LROPoller + # type: (str, Any) -> LROPoller[List[RecognizedReceipt]] """Extract field text and semantic values from a given US sales receipt. The input document must be the location (Url) of the receipt to be analyzed. @@ -141,6 +146,7 @@ def begin_recognize_receipts_from_url(self, receipt_url, **kwargs): Whether or not to include text elements such as lines and words in addition to form fields. :keyword int polling_interval: Waiting time between two polls for LRO operations if no Retry-After header is present. Defaults to 5 seconds. + :keyword str continuation_token: A continuation token to restart a poller from a saved state. :return: An instance of an LROPoller. Call `result()` on the poller object to return a list[:class:`~azure.ai.formrecognizer.RecognizedReceipt`]. :rtype: ~azure.core.polling.LROPoller[list[~azure.ai.formrecognizer.RecognizedReceipt]] @@ -157,6 +163,7 @@ def begin_recognize_receipts_from_url(self, receipt_url, **kwargs): """ polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) + continuation_token = kwargs.pop("continuation_token", None) include_text_content = kwargs.pop("include_text_content", False) return self._client.begin_analyze_receipt_async( @@ -165,6 +172,7 @@ def begin_recognize_receipts_from_url(self, receipt_url, **kwargs): cls=kwargs.pop("cls", self._receipt_callback), polling=LROBasePolling(timeout=polling_interval, **kwargs), error_map=error_map, + continuation_token=continuation_token, **kwargs ) @@ -174,7 +182,7 @@ def _content_callback(self, raw_response, _, headers): # pylint: disable=unused @distributed_trace def begin_recognize_content(self, form, **kwargs): - # type: (Union[bytes, IO[bytes]], Any) -> LROPoller + # type: (Union[bytes, IO[bytes]], Any) -> LROPoller[List[FormPage]] """Extract text and content/layout information from a given document. The input document must be of one of the supported content types - 'application/pdf', 'image/jpeg', 'image/png' or 'image/tiff'. @@ -186,6 +194,7 @@ def begin_recognize_content(self, form, **kwargs): see :class:`~azure.ai.formrecognizer.FormContentType`. :keyword int polling_interval: Waiting time between two polls for LRO operations if no Retry-After header is present. Defaults to 5 seconds. + :keyword str continuation_token: A continuation token to restart a poller from a saved state. :return: An instance of an LROPoller. Call `result()` on the poller object to return a list[:class:`~azure.ai.formrecognizer.FormPage`]. :rtype: ~azure.core.polling.LROPoller[list[~azure.ai.formrecognizer.FormPage]] @@ -202,6 +211,7 @@ def begin_recognize_content(self, form, **kwargs): """ polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) + continuation_token = kwargs.pop("continuation_token", None) content_type = kwargs.pop("content_type", None) if content_type == "application/json": raise TypeError("Call begin_recognize_content_from_url() to analyze a document from a url.") @@ -215,12 +225,13 @@ def begin_recognize_content(self, form, **kwargs): cls=kwargs.pop("cls", self._content_callback), polling=LROBasePolling(timeout=polling_interval, **kwargs), error_map=error_map, + continuation_token=continuation_token, **kwargs ) @distributed_trace def begin_recognize_content_from_url(self, form_url, **kwargs): - # type: (str, Any) -> LROPoller + # type: (str, Any) -> LROPoller[List[FormPage]] """Extract text and layout information from a given document. The input document must be the location (Url) of the document to be analyzed. @@ -228,6 +239,7 @@ def begin_recognize_content_from_url(self, form_url, **kwargs): of one of the supported formats: JPEG, PNG, PDF and TIFF. :keyword int polling_interval: Waiting time between two polls for LRO operations if no Retry-After header is present. Defaults to 5 seconds. + :keyword str continuation_token: A continuation token to restart a poller from a saved state. :return: An instance of an LROPoller. Call `result()` on the poller object to return a list[:class:`~azure.ai.formrecognizer.FormPage`]. :rtype: ~azure.core.polling.LROPoller[list[~azure.ai.formrecognizer.FormPage]] @@ -235,18 +247,20 @@ def begin_recognize_content_from_url(self, form_url, **kwargs): """ polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) + continuation_token = kwargs.pop("continuation_token", None) return self._client.begin_analyze_layout_async( file_stream={"source": form_url}, cls=kwargs.pop("cls", self._content_callback), polling=LROBasePolling(timeout=polling_interval, **kwargs), error_map=error_map, + continuation_token=continuation_token, **kwargs ) @distributed_trace def begin_recognize_custom_forms(self, model_id, form, **kwargs): - # type: (str, Union[bytes, IO[bytes]], Any) -> LROPoller + # type: (str, Union[bytes, IO[bytes]], Any) -> LROPoller[List[RecognizedForm]] """Analyze a custom form with a model trained with or without labels. The form to analyze should be of the same type as the forms that were used to train the model. The input document must be of one of the supported content types - 'application/pdf', @@ -262,6 +276,7 @@ def begin_recognize_custom_forms(self, model_id, form, **kwargs): see :class:`~azure.ai.formrecognizer.FormContentType`. :keyword int polling_interval: Waiting time between two polls for LRO operations if no Retry-After header is present. Defaults to 5 seconds. + :keyword str continuation_token: A continuation token to restart a poller from a saved state. :return: An instance of an LROPoller. Call `result()` on the poller object to return a list[:class:`~azure.ai.formrecognizer.RecognizedForm`]. :rtype: ~azure.core.polling.LROPoller[list[~azure.ai.formrecognizer.RecognizedForm] @@ -282,6 +297,7 @@ def begin_recognize_custom_forms(self, model_id, form, **kwargs): cls = kwargs.pop("cls", None) polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) + continuation_token = kwargs.pop("continuation_token", None) content_type = kwargs.pop("content_type", None) if content_type == "application/json": raise TypeError("Call begin_recognize_custom_forms_from_url() to analyze a document from a url.") @@ -303,12 +319,13 @@ def analyze_callback(raw_response, _, headers): # pylint: disable=unused-argume cls=deserialization_callback, polling=LROBasePolling(timeout=polling_interval, lro_algorithms=[AnalyzePolling()], **kwargs), error_map=error_map, + continuation_token=continuation_token, **kwargs ) @distributed_trace def begin_recognize_custom_forms_from_url(self, model_id, form_url, **kwargs): - # type: (str, str, Any) -> LROPoller + # type: (str, str, Any) -> LROPoller[List[RecognizedForm]] """Analyze a custom form with a model trained with or without labels. The form to analyze should be of the same type as the forms that were used to train the model. The input document must be the location (Url) of the document to be analyzed. @@ -320,6 +337,7 @@ def begin_recognize_custom_forms_from_url(self, model_id, form_url, **kwargs): Whether or not to include text elements such as lines and words in addition to form fields. :keyword int polling_interval: Waiting time between two polls for LRO operations if no Retry-After header is present. Defaults to 5 seconds. + :keyword str continuation_token: A continuation token to restart a poller from a saved state. :return: An instance of an LROPoller. Call `result()` on the poller object to return a list[:class:`~azure.ai.formrecognizer.RecognizedForm`]. :rtype: ~azure.core.polling.LROPoller[list[~azure.ai.formrecognizer.RecognizedForm] @@ -331,6 +349,7 @@ def begin_recognize_custom_forms_from_url(self, model_id, form_url, **kwargs): cls = kwargs.pop("cls", None) polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) + continuation_token = kwargs.pop("continuation_token", None) include_text_content = kwargs.pop("include_text_content", False) def analyze_callback(raw_response, _, headers): # pylint: disable=unused-argument @@ -345,6 +364,7 @@ def analyze_callback(raw_response, _, headers): # pylint: disable=unused-argume cls=deserialization_callback, polling=LROBasePolling(timeout=polling_interval, lro_algorithms=[AnalyzePolling()], **kwargs), error_map=error_map, + continuation_token=continuation_token, **kwargs ) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py index b79480d379d2..530b256da206 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_form_training_client.py @@ -80,15 +80,15 @@ def __init__(self, endpoint, credential, **kwargs): authentication_policy = get_authentication_policy(credential) self._client = FormRecognizer( endpoint=self._endpoint, - credential=self._credential, + credential=self._credential, # type: ignore sdk_moniker=USER_AGENT, authentication_policy=authentication_policy, **kwargs ) @distributed_trace - def begin_train_model(self, training_files_url, use_training_labels, **kwargs): - # type: (str, bool, Any) -> LROPoller + def begin_training(self, training_files_url, use_training_labels, **kwargs): + # type: (str, bool, Any) -> LROPoller[CustomFormModel] """Create and train a custom model. The request must include a `training_files_url` parameter that is an externally accessible Azure storage blob container Uri (preferably a Shared Access Signature Uri). Models are trained using documents that are of the following content type - 'application/pdf', @@ -105,6 +105,7 @@ def begin_train_model(self, training_files_url, use_training_labels, **kwargs): Use with `prefix` to filter for only certain sub folders. Not supported if training with labels. :keyword int polling_interval: Waiting time between two polls for LRO operations if no Retry-After header is present. Defaults to 5 seconds. + :keyword str continuation_token: A continuation token to restart a poller from a saved state. :return: An instance of an LROPoller. Call `result()` on the poller object to return a :class:`~azure.ai.formrecognizer.CustomFormModel`. :rtype: ~azure.core.polling.LROPoller[~azure.ai.formrecognizer.CustomFormModel] @@ -122,8 +123,23 @@ def begin_train_model(self, training_files_url, use_training_labels, **kwargs): :caption: Training a model with your custom forms. """ + def callback(raw_response): + model = self._client._deserialize(Model, raw_response) + return CustomFormModel._from_generated(model) + cls = kwargs.pop("cls", None) + continuation_token = kwargs.pop("continuation_token", None) polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) + deserialization_callback = cls if cls else callback + + if continuation_token: + return LROPoller.from_continuation_token( + polling_method=LROBasePolling(timeout=polling_interval, lro_algorithms=[TrainingPolling()], **kwargs), + continuation_token=continuation_token, + client=self._client._client, + deserialization_callback=deserialization_callback + ) + response = self._client.train_custom_model_async( # type: ignore train_request=TrainRequest( source=training_files_url, @@ -138,11 +154,6 @@ def begin_train_model(self, training_files_url, use_training_labels, **kwargs): **kwargs ) # type: PipelineResponseType - def callback(raw_response): - model = self._client._deserialize(Model, raw_response) - return CustomFormModel._from_generated(model) - - deserialization_callback = cls if cls else callback return LROPoller( self._client._client, response, @@ -297,7 +308,7 @@ def begin_copy_model( target, # type: Dict **kwargs # type: Any ): - # type: (...) -> LROPoller + # type: (...) -> LROPoller[CustomFormModelInfo] """Copy a custom model stored in this resource (the source) to the user specified target Form Recognizer resource. This should be called with the source Form Recognizer resource (with the model that is intended to be copied). The `target` parameter should be supplied from the @@ -309,6 +320,7 @@ def begin_copy_model( :func:`~get_copy_authorization()`. :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. + :keyword str continuation_token: A continuation token to restart a poller from a saved state. :return: An instance of an LROPoller. Call `result()` on the poller object to return a :class:`~azure.ai.formrecognizer.CustomFormModelInfo`. :rtype: ~azure.core.polling.LROPoller[~azure.ai.formrecognizer.CustomFormModelInfo] @@ -328,6 +340,7 @@ def begin_copy_model( raise ValueError("model_id cannot be None or empty.") polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) + continuation_token = kwargs.pop("continuation_token", None) def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument copy_result = self._client._deserialize(CopyOperationResult, raw_response) @@ -347,6 +360,7 @@ def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument cls=kwargs.pop("cls", _copy_callback), polling=LROBasePolling(timeout=polling_interval, lro_algorithms=[CopyPolling()], **kwargs), error_map=error_map, + continuation_token=continuation_token, **kwargs ) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_form_recognizer_client.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_form_recognizer_client.py index ad4fc9939ad0..ebfee04f90f6 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_form_recognizer_client.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_form_recognizer_client.py @@ -13,6 +13,8 @@ # pylint: disable=unused-import,ungrouped-imports from typing import Any + from azure.core.credentials import TokenCredential + from ._configuration import FormRecognizerClientConfiguration from .operations import FormRecognizerClientOperationsMixin from . import models diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_version.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_version.py index 4b19902c2480..9aa774407087 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_version.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/_version.py @@ -4,4 +4,4 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -VERSION = "1.0.0b2" +VERSION = "1.0.0b3" diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/_configuration_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/_configuration_async.py index 5a4c7f8cb2eb..3faa127ff1c9 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/_configuration_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/_configuration_async.py @@ -13,7 +13,7 @@ if TYPE_CHECKING: # pylint: disable=unused-import,ungrouped-imports - from azure.core.credentials import TokenCredential + from azure.core.credentials_async import AsyncTokenCredential class FormRecognizerClientConfiguration(Configuration): diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/_form_recognizer_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/_form_recognizer_client_async.py index c084748c0821..eee9966f59a4 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/_form_recognizer_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/_form_recognizer_client_async.py @@ -4,11 +4,15 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from typing import Any +from typing import Any, TYPE_CHECKING from azure.core import AsyncPipelineClient from msrest import Deserializer, Serializer +if TYPE_CHECKING: + # pylint: disable=unused-import,ungrouped-imports + from azure.core.credentials_async import AsyncTokenCredential + from ._configuration_async import FormRecognizerClientConfiguration from .operations_async import FormRecognizerClientOperationsMixin from .. import models diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/operations_async/_form_recognizer_client_operations_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/operations_async/_form_recognizer_client_operations_async.py index 64ce71c09954..0746043cba4a 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/operations_async/_form_recognizer_client_operations_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/aio/operations_async/_form_recognizer_client_operations_async.py @@ -3,14 +3,14 @@ # Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.0.6282, generator: {generator}) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from typing import Any, AsyncIterable, Callable, Dict, Generic, Optional, TypeVar, Union +from typing import Any, AsyncIterable, Callable, Dict, Generic, IO, Optional, TypeVar, Union import warnings from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error from azure.core.pipeline import PipelineResponse from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest -from azure.core.polling import AsyncNoPolling, AsyncPollingMethod, async_poller +from azure.core.polling import AsyncLROPoller, AsyncNoPolling, AsyncPollingMethod from azure.core.polling.async_base_polling import AsyncLROBasePolling from azure.core.tracing.decorator import distributed_trace from azure.core.tracing.decorator_async import distributed_trace_async @@ -28,14 +28,22 @@ async def train_custom_model_async( train_request: "models.TrainRequest", **kwargs ) -> None: - """Create and train a custom model. The request must include a source parameter that is either an externally accessible Azure storage blob container Uri (preferably a Shared Access Signature Uri) or valid path to a data folder in a locally mounted drive. When local paths are specified, they must follow the Linux/Unix path format and be an absolute path rooted to the input mount configuration setting value e.g., if '{Mounts:Input}' configuration setting value is '/input' then a valid source path would be '/input/contosodataset'. All data to be trained is expected to be under the source folder or sub folders under it. Models are trained using documents that are of the following content type - 'application/pdf', 'image/jpeg', 'image/png', 'image/tiff'. Other type of content is ignored. - - Train Custom Model. + """Train Custom Model. + + Create and train a custom model. The request must include a source parameter that is either an + externally accessible Azure storage blob container Uri (preferably a Shared Access Signature + Uri) or valid path to a data folder in a locally mounted drive. When local paths are specified, + they must follow the Linux/Unix path format and be an absolute path rooted to the input mount + configuration setting value e.g., if '{Mounts:Input}' configuration setting value is '/input' + then a valid source path would be '/input/contosodataset'. All data to be trained is expected + to be under the source folder or sub folders under it. Models are trained using documents that + are of the following content type - 'application/pdf', 'image/jpeg', 'image/png', 'image/tiff'. + Other type of content is ignored. :param train_request: Training request parameters. :type train_request: ~azure.ai.formrecognizer.models.TrainRequest :keyword callable cls: A custom type or function that will be passed the direct response - :return: None or the result of cls(response) + :return: None, or the result of cls(response) :rtype: None :raises: ~azure.core.exceptions.HttpResponseError """ @@ -76,7 +84,7 @@ async def train_custom_model_async( response_headers['Location']=self._deserialize('str', response.headers.get('Location')) if cls: - return cls(pipeline_response, None, response_headers) + return cls(pipeline_response, None, response_headers) train_custom_model_async.metadata = {'url': '/custom/models'} # type: ignore @@ -87,16 +95,16 @@ async def get_custom_model( include_keys: Optional[bool] = False, **kwargs ) -> "models.Model": - """Get detailed information about a custom model. + """Get Custom Model. - Get Custom Model. + Get detailed information about a custom model. :param model_id: Model identifier. :type model_id: str :param include_keys: Include list of extracted keys in model information. :type include_keys: bool :keyword callable cls: A custom type or function that will be passed the direct response - :return: Model or the result of cls(response) + :return: Model, or the result of cls(response) :rtype: ~azure.ai.formrecognizer.models.Model :raises: ~azure.core.exceptions.HttpResponseError """ @@ -134,7 +142,7 @@ async def get_custom_model( deserialized = self._deserialize('Model', pipeline_response) if cls: - return cls(pipeline_response, deserialized, {}) + return cls(pipeline_response, deserialized, {}) return deserialized get_custom_model.metadata = {'url': '/custom/models/{modelId}'} # type: ignore @@ -145,14 +153,15 @@ async def delete_custom_model( model_id: str, **kwargs ) -> None: - """Mark model for deletion. Model artifacts will be permanently removed within a predetermined period. + """Delete Custom Model. - Delete Custom Model. + Mark model for deletion. Model artifacts will be permanently removed within a predetermined + period. :param model_id: Model identifier. :type model_id: str :keyword callable cls: A custom type or function that will be passed the direct response - :return: None or the result of cls(response) + :return: None, or the result of cls(response) :rtype: None :raises: ~azure.core.exceptions.HttpResponseError """ @@ -185,7 +194,7 @@ async def delete_custom_model( raise HttpResponseError(response=response, model=error) if cls: - return cls(pipeline_response, None, {}) + return cls(pipeline_response, None, {}) delete_custom_model.metadata = {'url': '/custom/models/{modelId}'} # type: ignore @@ -193,7 +202,7 @@ async def _analyze_with_custom_model_initial( self, model_id: str, include_text_details: Optional[bool] = False, - file_stream: Optional[Union[str, "models.SourcePath"]] = None, + file_stream: Optional[Union[IO, "models.SourcePath"]] = None, **kwargs ) -> None: cls = kwargs.pop('cls', None) # type: ClsType[None] @@ -220,9 +229,9 @@ async def _analyze_with_custom_model_initial( # Construct and send request body_content_kwargs = {} # type: Dict[str, Any] - if header_parameters['Content-Type'] in ['application/pdf', 'image/jpeg', 'image/png', 'image/tiff']: + if header_parameters['Content-Type'].split(";")[0] in ['application/pdf', 'image/jpeg', 'image/png', 'image/tiff']: body_content_kwargs['stream_content'] = file_stream - elif header_parameters['Content-Type'] in ['application/json']: + elif header_parameters['Content-Type'].split(";")[0] in ['application/json']: if file_stream is not None: body_content = self._serialize.body(file_stream, 'SourcePath') else: @@ -230,7 +239,8 @@ async def _analyze_with_custom_model_initial( body_content_kwargs['content'] = body_content else: raise ValueError( - "Content type {} is not valid for this operation".format(header_parameters['Content-Type']) + "The content_type '{}' is not one of the allowed values: " + "['application/pdf', 'image/jpeg', 'image/png', 'image/tiff', 'application/json']".format(header_parameters['Content-Type']) ) request = self._client.post(url, query_parameters, header_parameters, **body_content_kwargs) @@ -246,21 +256,24 @@ async def _analyze_with_custom_model_initial( response_headers['Operation-Location']=self._deserialize('str', response.headers.get('Operation-Location')) if cls: - return cls(pipeline_response, None, response_headers) + return cls(pipeline_response, None, response_headers) _analyze_with_custom_model_initial.metadata = {'url': '/custom/models/{modelId}/analyze'} # type: ignore @distributed_trace_async - async def analyze_with_custom_model( + async def begin_analyze_with_custom_model( self, model_id: str, include_text_details: Optional[bool] = False, - file_stream: Optional[Union[str, "models.SourcePath"]] = None, + file_stream: Optional[Union[IO, "models.SourcePath"]] = None, **kwargs ) -> None: - """Extract key-value pairs, tables, and semantic values from a given document. The input document must be of one of the supported content types - 'application/pdf', 'image/jpeg', 'image/png' or 'image/tiff'. Alternatively, use 'application/json' type to specify the location (Uri or local path) of the document to be analyzed. + """Analyze Form. - Analyze Form. + Extract key-value pairs, tables, and semantic values from a given document. The input document + must be of one of the supported content types - 'application/pdf', 'image/jpeg', 'image/png' or + 'image/tiff'. Alternatively, use 'application/json' type to specify the location (Uri or local + path) of the document to be analyzed. :param model_id: Model identifier. :type model_id: str @@ -269,11 +282,12 @@ async def analyze_with_custom_model( :param file_stream: .json, .pdf, .jpg, .png or .tiff type file stream. :type file_stream: ~azure.ai.formrecognizer.models.SourcePath :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. :keyword polling: True for ARMPolling, False for no polling, or a polling object for personal polling strategy :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. - :return: None + :return: None, or the result of cls(response) :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ @@ -283,13 +297,18 @@ async def analyze_with_custom_model( 'polling_interval', self._config.polling_interval ) - raw_result = await self._analyze_with_custom_model_initial( - model_id=model_id, - include_text_details=include_text_details, - file_stream=file_stream, - cls=lambda x,y,z: x, - **kwargs - ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._analyze_with_custom_model_initial( + model_id=model_id, + include_text_details=include_text_details, + file_stream=file_stream, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) def get_long_running_output(pipeline_response): if cls: @@ -298,8 +317,16 @@ def get_long_running_output(pipeline_response): if polling is True: polling_method = AsyncLROBasePolling(lro_delay, **kwargs) elif polling is False: polling_method = AsyncNoPolling() else: polling_method = polling - return await async_poller(self._client, raw_result, get_long_running_output, polling_method) - analyze_with_custom_model.metadata = {'url': '/custom/models/{modelId}/analyze'} # type: ignore + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_analyze_with_custom_model.metadata = {'url': '/custom/models/{modelId}/analyze'} # type: ignore @distributed_trace_async async def get_analyze_form_result( @@ -308,16 +335,16 @@ async def get_analyze_form_result( result_id: str, **kwargs ) -> "models.AnalyzeOperationResult": - """Obtain current status and the result of the analyze form operation. + """Get Analyze Form Result. - Get Analyze Form Result. + Obtain current status and the result of the analyze form operation. :param model_id: Model identifier. :type model_id: str :param result_id: Analyze operation result identifier. :type result_id: str :keyword callable cls: A custom type or function that will be passed the direct response - :return: AnalyzeOperationResult or the result of cls(response) + :return: AnalyzeOperationResult, or the result of cls(response) :rtype: ~azure.ai.formrecognizer.models.AnalyzeOperationResult :raises: ~azure.core.exceptions.HttpResponseError """ @@ -354,7 +381,7 @@ async def get_analyze_form_result( deserialized = self._deserialize('AnalyzeOperationResult', pipeline_response) if cls: - return cls(pipeline_response, deserialized, {}) + return cls(pipeline_response, deserialized, {}) return deserialized get_analyze_form_result.metadata = {'url': '/custom/models/{modelId}/analyzeResults/{resultId}'} # type: ignore @@ -403,31 +430,33 @@ async def _copy_custom_model_initial( response_headers['Operation-Location']=self._deserialize('str', response.headers.get('Operation-Location')) if cls: - return cls(pipeline_response, None, response_headers) + return cls(pipeline_response, None, response_headers) _copy_custom_model_initial.metadata = {'url': '/custom/models/{modelId}/copy'} # type: ignore @distributed_trace_async - async def copy_custom_model( + async def begin_copy_custom_model( self, model_id: str, copy_request: "models.CopyRequest", **kwargs ) -> None: - """Copy custom model stored in this resource (the source) to user specified target Form Recognizer resource. + """Copy Custom Model. - Copy Custom Model. + Copy custom model stored in this resource (the source) to user specified target Form Recognizer + resource. :param model_id: Model identifier. :type model_id: str :param copy_request: Copy request parameters. :type copy_request: ~azure.ai.formrecognizer.models.CopyRequest :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. :keyword polling: True for ARMPolling, False for no polling, or a polling object for personal polling strategy :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. - :return: None + :return: None, or the result of cls(response) :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ @@ -437,12 +466,17 @@ async def copy_custom_model( 'polling_interval', self._config.polling_interval ) - raw_result = await self._copy_custom_model_initial( - model_id=model_id, - copy_request=copy_request, - cls=lambda x,y,z: x, - **kwargs - ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._copy_custom_model_initial( + model_id=model_id, + copy_request=copy_request, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) def get_long_running_output(pipeline_response): if cls: @@ -451,8 +485,16 @@ def get_long_running_output(pipeline_response): if polling is True: polling_method = AsyncLROBasePolling(lro_delay, **kwargs) elif polling is False: polling_method = AsyncNoPolling() else: polling_method = polling - return await async_poller(self._client, raw_result, get_long_running_output, polling_method) - copy_custom_model.metadata = {'url': '/custom/models/{modelId}/copy'} # type: ignore + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_copy_custom_model.metadata = {'url': '/custom/models/{modelId}/copy'} # type: ignore @distributed_trace_async async def get_custom_model_copy_result( @@ -461,16 +503,16 @@ async def get_custom_model_copy_result( result_id: str, **kwargs ) -> "models.CopyOperationResult": - """Obtain current status and the result of a custom model copy operation. + """Get Custom Model Copy Result. - Get Custom Model Copy Result. + Obtain current status and the result of a custom model copy operation. :param model_id: Model identifier. :type model_id: str :param result_id: Copy operation result identifier. :type result_id: str :keyword callable cls: A custom type or function that will be passed the direct response - :return: CopyOperationResult or the result of cls(response) + :return: CopyOperationResult, or the result of cls(response) :rtype: ~azure.ai.formrecognizer.models.CopyOperationResult :raises: ~azure.core.exceptions.HttpResponseError """ @@ -507,7 +549,7 @@ async def get_custom_model_copy_result( deserialized = self._deserialize('CopyOperationResult', pipeline_response) if cls: - return cls(pipeline_response, deserialized, {}) + return cls(pipeline_response, deserialized, {}) return deserialized get_custom_model_copy_result.metadata = {'url': '/custom/models/{modelId}/copyResults/{resultId}'} # type: ignore @@ -517,12 +559,12 @@ async def generate_model_copy_authorization( self, **kwargs ) -> "models.CopyAuthorizationResult": - """Generate authorization to copy a model into the target Form Recognizer resource. + """Generate Copy Authorization. - Generate Copy Authorization. + Generate authorization to copy a model into the target Form Recognizer resource. :keyword callable cls: A custom type or function that will be passed the direct response - :return: CopyAuthorizationResult or the result of cls(response) + :return: CopyAuthorizationResult, or the result of cls(response) :rtype: ~azure.ai.formrecognizer.models.CopyAuthorizationResult :raises: ~azure.core.exceptions.HttpResponseError """ @@ -559,7 +601,7 @@ async def generate_model_copy_authorization( deserialized = self._deserialize('CopyAuthorizationResult', pipeline_response) if cls: - return cls(pipeline_response, deserialized, response_headers) + return cls(pipeline_response, deserialized, response_headers) return deserialized generate_model_copy_authorization.metadata = {'url': '/custom/models/copyAuthorization'} # type: ignore @@ -567,7 +609,7 @@ async def generate_model_copy_authorization( async def _analyze_receipt_async_initial( self, include_text_details: Optional[bool] = False, - file_stream: Optional[Union[str, "models.SourcePath"]] = None, + file_stream: Optional[Union[IO, "models.SourcePath"]] = None, **kwargs ) -> None: cls = kwargs.pop('cls', None) # type: ClsType[None] @@ -593,9 +635,9 @@ async def _analyze_receipt_async_initial( # Construct and send request body_content_kwargs = {} # type: Dict[str, Any] - if header_parameters['Content-Type'] in ['application/pdf', 'image/jpeg', 'image/png', 'image/tiff']: + if header_parameters['Content-Type'].split(";")[0] in ['application/pdf', 'image/jpeg', 'image/png', 'image/tiff']: body_content_kwargs['stream_content'] = file_stream - elif header_parameters['Content-Type'] in ['application/json']: + elif header_parameters['Content-Type'].split(";")[0] in ['application/json']: if file_stream is not None: body_content = self._serialize.body(file_stream, 'SourcePath') else: @@ -603,7 +645,8 @@ async def _analyze_receipt_async_initial( body_content_kwargs['content'] = body_content else: raise ValueError( - "Content type {} is not valid for this operation".format(header_parameters['Content-Type']) + "The content_type '{}' is not one of the allowed values: " + "['application/pdf', 'image/jpeg', 'image/png', 'image/tiff', 'application/json']".format(header_parameters['Content-Type']) ) request = self._client.post(url, query_parameters, header_parameters, **body_content_kwargs) @@ -619,31 +662,35 @@ async def _analyze_receipt_async_initial( response_headers['Operation-Location']=self._deserialize('str', response.headers.get('Operation-Location')) if cls: - return cls(pipeline_response, None, response_headers) + return cls(pipeline_response, None, response_headers) _analyze_receipt_async_initial.metadata = {'url': '/prebuilt/receipt/analyze'} # type: ignore @distributed_trace_async - async def analyze_receipt_async( + async def begin_analyze_receipt_async( self, include_text_details: Optional[bool] = False, - file_stream: Optional[Union[str, "models.SourcePath"]] = None, + file_stream: Optional[Union[IO, "models.SourcePath"]] = None, **kwargs ) -> None: - """Extract field text and semantic values from a given receipt document. The input document must be of one of the supported content types - 'application/pdf', 'image/jpeg', 'image/png' or 'image/tiff'. Alternatively, use 'application/json' type to specify the location (Uri or local path) of the document to be analyzed. + """Analyze Receipt. - Analyze Receipt. + Extract field text and semantic values from a given receipt document. The input document must + be of one of the supported content types - 'application/pdf', 'image/jpeg', 'image/png' or + 'image/tiff'. Alternatively, use 'application/json' type to specify the location (Uri or local + path) of the document to be analyzed. :param include_text_details: Include text lines and element references in the result. :type include_text_details: bool :param file_stream: .json, .pdf, .jpg, .png or .tiff type file stream. :type file_stream: ~azure.ai.formrecognizer.models.SourcePath :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. :keyword polling: True for ARMPolling, False for no polling, or a polling object for personal polling strategy :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. - :return: None + :return: None, or the result of cls(response) :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ @@ -653,12 +700,17 @@ async def analyze_receipt_async( 'polling_interval', self._config.polling_interval ) - raw_result = await self._analyze_receipt_async_initial( - include_text_details=include_text_details, - file_stream=file_stream, - cls=lambda x,y,z: x, - **kwargs - ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._analyze_receipt_async_initial( + include_text_details=include_text_details, + file_stream=file_stream, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) def get_long_running_output(pipeline_response): if cls: @@ -667,8 +719,16 @@ def get_long_running_output(pipeline_response): if polling is True: polling_method = AsyncLROBasePolling(lro_delay, **kwargs) elif polling is False: polling_method = AsyncNoPolling() else: polling_method = polling - return await async_poller(self._client, raw_result, get_long_running_output, polling_method) - analyze_receipt_async.metadata = {'url': '/prebuilt/receipt/analyze'} # type: ignore + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_analyze_receipt_async.metadata = {'url': '/prebuilt/receipt/analyze'} # type: ignore @distributed_trace_async async def get_analyze_receipt_result( @@ -676,14 +736,14 @@ async def get_analyze_receipt_result( result_id: str, **kwargs ) -> "models.AnalyzeOperationResult": - """Track the progress and obtain the result of the analyze receipt operation. + """Get Analyze Receipt Result. - Get Analyze Receipt Result. + Track the progress and obtain the result of the analyze receipt operation. :param result_id: Analyze operation result identifier. :type result_id: str :keyword callable cls: A custom type or function that will be passed the direct response - :return: AnalyzeOperationResult or the result of cls(response) + :return: AnalyzeOperationResult, or the result of cls(response) :rtype: ~azure.ai.formrecognizer.models.AnalyzeOperationResult :raises: ~azure.core.exceptions.HttpResponseError """ @@ -719,14 +779,14 @@ async def get_analyze_receipt_result( deserialized = self._deserialize('AnalyzeOperationResult', pipeline_response) if cls: - return cls(pipeline_response, deserialized, {}) + return cls(pipeline_response, deserialized, {}) return deserialized get_analyze_receipt_result.metadata = {'url': '/prebuilt/receipt/analyzeResults/{resultId}'} # type: ignore async def _analyze_layout_async_initial( self, - file_stream: Optional[Union[str, "models.SourcePath"]] = None, + file_stream: Optional[Union[IO, "models.SourcePath"]] = None, **kwargs ) -> None: cls = kwargs.pop('cls', None) # type: ClsType[None] @@ -750,9 +810,9 @@ async def _analyze_layout_async_initial( # Construct and send request body_content_kwargs = {} # type: Dict[str, Any] - if header_parameters['Content-Type'] in ['application/pdf', 'image/jpeg', 'image/png', 'image/tiff']: + if header_parameters['Content-Type'].split(";")[0] in ['application/pdf', 'image/jpeg', 'image/png', 'image/tiff']: body_content_kwargs['stream_content'] = file_stream - elif header_parameters['Content-Type'] in ['application/json']: + elif header_parameters['Content-Type'].split(";")[0] in ['application/json']: if file_stream is not None: body_content = self._serialize.body(file_stream, 'SourcePath') else: @@ -760,7 +820,8 @@ async def _analyze_layout_async_initial( body_content_kwargs['content'] = body_content else: raise ValueError( - "Content type {} is not valid for this operation".format(header_parameters['Content-Type']) + "The content_type '{}' is not one of the allowed values: " + "['application/pdf', 'image/jpeg', 'image/png', 'image/tiff', 'application/json']".format(header_parameters['Content-Type']) ) request = self._client.post(url, query_parameters, header_parameters, **body_content_kwargs) @@ -776,28 +837,32 @@ async def _analyze_layout_async_initial( response_headers['Operation-Location']=self._deserialize('str', response.headers.get('Operation-Location')) if cls: - return cls(pipeline_response, None, response_headers) + return cls(pipeline_response, None, response_headers) _analyze_layout_async_initial.metadata = {'url': '/layout/analyze'} # type: ignore @distributed_trace_async - async def analyze_layout_async( + async def begin_analyze_layout_async( self, - file_stream: Optional[Union[str, "models.SourcePath"]] = None, + file_stream: Optional[Union[IO, "models.SourcePath"]] = None, **kwargs ) -> None: - """Extract text and layout information from a given document. The input document must be of one of the supported content types - 'application/pdf', 'image/jpeg', 'image/png' or 'image/tiff'. Alternatively, use 'application/json' type to specify the location (Uri or local path) of the document to be analyzed. + """Analyze Layout. - Analyze Layout. + Extract text and layout information from a given document. The input document must be of one of + the supported content types - 'application/pdf', 'image/jpeg', 'image/png' or 'image/tiff'. + Alternatively, use 'application/json' type to specify the location (Uri or local path) of the + document to be analyzed. :param file_stream: .json, .pdf, .jpg, .png or .tiff type file stream. :type file_stream: ~azure.ai.formrecognizer.models.SourcePath :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. :keyword polling: True for ARMPolling, False for no polling, or a polling object for personal polling strategy :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. - :return: None + :return: None, or the result of cls(response) :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ @@ -807,11 +872,16 @@ async def analyze_layout_async( 'polling_interval', self._config.polling_interval ) - raw_result = await self._analyze_layout_async_initial( - file_stream=file_stream, - cls=lambda x,y,z: x, - **kwargs - ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = await self._analyze_layout_async_initial( + file_stream=file_stream, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) def get_long_running_output(pipeline_response): if cls: @@ -820,8 +890,16 @@ def get_long_running_output(pipeline_response): if polling is True: polling_method = AsyncLROBasePolling(lro_delay, **kwargs) elif polling is False: polling_method = AsyncNoPolling() else: polling_method = polling - return await async_poller(self._client, raw_result, get_long_running_output, polling_method) - analyze_layout_async.metadata = {'url': '/layout/analyze'} # type: ignore + if cont_token: + return AsyncLROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method) + begin_analyze_layout_async.metadata = {'url': '/layout/analyze'} # type: ignore @distributed_trace_async async def get_analyze_layout_result( @@ -829,14 +907,14 @@ async def get_analyze_layout_result( result_id: str, **kwargs ) -> "models.AnalyzeOperationResult": - """Track the progress and obtain the result of the analyze layout operation. + """Get Analyze Layout Result. - Get Analyze Layout Result. + Track the progress and obtain the result of the analyze layout operation. :param result_id: Analyze operation result identifier. :type result_id: str :keyword callable cls: A custom type or function that will be passed the direct response - :return: AnalyzeOperationResult or the result of cls(response) + :return: AnalyzeOperationResult, or the result of cls(response) :rtype: ~azure.ai.formrecognizer.models.AnalyzeOperationResult :raises: ~azure.core.exceptions.HttpResponseError """ @@ -872,7 +950,7 @@ async def get_analyze_layout_result( deserialized = self._deserialize('AnalyzeOperationResult', pipeline_response) if cls: - return cls(pipeline_response, deserialized, {}) + return cls(pipeline_response, deserialized, {}) return deserialized get_analyze_layout_result.metadata = {'url': '/layout/analyzeResults/{resultId}'} # type: ignore @@ -882,12 +960,12 @@ def list_custom_models( self, **kwargs ) -> AsyncIterable["models.Models"]: - """Get information about all custom models. + """List Custom Models. - List Custom Models. + Get information about all custom models. :keyword callable cls: A custom type or function that will be passed the direct response - :return: An iterator like instance of Models or the result of cls(response) + :return: An iterator like instance of either Models or the result of cls(response) :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.ai.formrecognizer.models.Models] :raises: ~azure.core.exceptions.HttpResponseError """ @@ -953,12 +1031,12 @@ async def get_custom_models( self, **kwargs ) -> "models.Models": - """Get information about all custom models. + """Get Custom Models. - Get Custom Models. + Get information about all custom models. :keyword callable cls: A custom type or function that will be passed the direct response - :return: Models or the result of cls(response) + :return: Models, or the result of cls(response) :rtype: ~azure.ai.formrecognizer.models.Models :raises: ~azure.core.exceptions.HttpResponseError """ @@ -995,7 +1073,7 @@ async def get_custom_models( deserialized = self._deserialize('Models', pipeline_response) if cls: - return cls(pipeline_response, deserialized, {}) + return cls(pipeline_response, deserialized, {}) return deserialized get_custom_models.metadata = {'url': '/custom/models'} # type: ignore diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/operations/_form_recognizer_client_operations.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/operations/_form_recognizer_client_operations.py index 6a93c83008f9..3bc85d224944 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/operations/_form_recognizer_client_operations.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_generated/operations/_form_recognizer_client_operations.py @@ -18,7 +18,7 @@ if TYPE_CHECKING: # pylint: disable=unused-import,ungrouped-imports - from typing import Any, Callable, Dict, Generic, Iterable, Optional, TypeVar, Union + from typing import Any, Callable, Dict, Generic, IO, Iterable, Optional, TypeVar, Union T = TypeVar('T') ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -32,14 +32,22 @@ def train_custom_model_async( **kwargs # type: Any ): # type: (...) -> None - """Create and train a custom model. The request must include a source parameter that is either an externally accessible Azure storage blob container Uri (preferably a Shared Access Signature Uri) or valid path to a data folder in a locally mounted drive. When local paths are specified, they must follow the Linux/Unix path format and be an absolute path rooted to the input mount configuration setting value e.g., if '{Mounts:Input}' configuration setting value is '/input' then a valid source path would be '/input/contosodataset'. All data to be trained is expected to be under the source folder or sub folders under it. Models are trained using documents that are of the following content type - 'application/pdf', 'image/jpeg', 'image/png', 'image/tiff'. Other type of content is ignored. - - Train Custom Model. + """Train Custom Model. + + Create and train a custom model. The request must include a source parameter that is either an + externally accessible Azure storage blob container Uri (preferably a Shared Access Signature + Uri) or valid path to a data folder in a locally mounted drive. When local paths are specified, + they must follow the Linux/Unix path format and be an absolute path rooted to the input mount + configuration setting value e.g., if '{Mounts:Input}' configuration setting value is '/input' + then a valid source path would be '/input/contosodataset'. All data to be trained is expected + to be under the source folder or sub folders under it. Models are trained using documents that + are of the following content type - 'application/pdf', 'image/jpeg', 'image/png', 'image/tiff'. + Other type of content is ignored. :param train_request: Training request parameters. :type train_request: ~azure.ai.formrecognizer.models.TrainRequest :keyword callable cls: A custom type or function that will be passed the direct response - :return: None or the result of cls(response) + :return: None, or the result of cls(response) :rtype: None :raises: ~azure.core.exceptions.HttpResponseError """ @@ -80,7 +88,7 @@ def train_custom_model_async( response_headers['Location']=self._deserialize('str', response.headers.get('Location')) if cls: - return cls(pipeline_response, None, response_headers) + return cls(pipeline_response, None, response_headers) train_custom_model_async.metadata = {'url': '/custom/models'} # type: ignore @@ -92,16 +100,16 @@ def get_custom_model( **kwargs # type: Any ): # type: (...) -> "models.Model" - """Get detailed information about a custom model. + """Get Custom Model. - Get Custom Model. + Get detailed information about a custom model. :param model_id: Model identifier. :type model_id: str :param include_keys: Include list of extracted keys in model information. :type include_keys: bool :keyword callable cls: A custom type or function that will be passed the direct response - :return: Model or the result of cls(response) + :return: Model, or the result of cls(response) :rtype: ~azure.ai.formrecognizer.models.Model :raises: ~azure.core.exceptions.HttpResponseError """ @@ -139,7 +147,7 @@ def get_custom_model( deserialized = self._deserialize('Model', pipeline_response) if cls: - return cls(pipeline_response, deserialized, {}) + return cls(pipeline_response, deserialized, {}) return deserialized get_custom_model.metadata = {'url': '/custom/models/{modelId}'} # type: ignore @@ -151,14 +159,15 @@ def delete_custom_model( **kwargs # type: Any ): # type: (...) -> None - """Mark model for deletion. Model artifacts will be permanently removed within a predetermined period. + """Delete Custom Model. - Delete Custom Model. + Mark model for deletion. Model artifacts will be permanently removed within a predetermined + period. :param model_id: Model identifier. :type model_id: str :keyword callable cls: A custom type or function that will be passed the direct response - :return: None or the result of cls(response) + :return: None, or the result of cls(response) :rtype: None :raises: ~azure.core.exceptions.HttpResponseError """ @@ -191,7 +200,7 @@ def delete_custom_model( raise HttpResponseError(response=response, model=error) if cls: - return cls(pipeline_response, None, {}) + return cls(pipeline_response, None, {}) delete_custom_model.metadata = {'url': '/custom/models/{modelId}'} # type: ignore @@ -199,7 +208,7 @@ def _analyze_with_custom_model_initial( self, model_id, # type: str include_text_details=False, # type: Optional[bool] - file_stream=None, # type: Optional[Union[str, "models.SourcePath"]] + file_stream=None, # type: Optional[Union[IO, "models.SourcePath"]] **kwargs # type: Any ): # type: (...) -> None @@ -227,9 +236,9 @@ def _analyze_with_custom_model_initial( # Construct and send request body_content_kwargs = {} # type: Dict[str, Any] - if header_parameters['Content-Type'] in ['application/pdf', 'image/jpeg', 'image/png', 'image/tiff']: + if header_parameters['Content-Type'].split(";")[0] in ['application/pdf', 'image/jpeg', 'image/png', 'image/tiff']: body_content_kwargs['stream_content'] = file_stream - elif header_parameters['Content-Type'] in ['application/json']: + elif header_parameters['Content-Type'].split(";")[0] in ['application/json']: if file_stream is not None: body_content = self._serialize.body(file_stream, 'SourcePath') else: @@ -237,7 +246,8 @@ def _analyze_with_custom_model_initial( body_content_kwargs['content'] = body_content else: raise ValueError( - "Content type {} is not valid for this operation".format(header_parameters['Content-Type']) + "The content_type '{}' is not one of the allowed values: " + "['application/pdf', 'image/jpeg', 'image/png', 'image/tiff', 'application/json']".format(header_parameters['Content-Type']) ) request = self._client.post(url, query_parameters, header_parameters, **body_content_kwargs) @@ -253,7 +263,7 @@ def _analyze_with_custom_model_initial( response_headers['Operation-Location']=self._deserialize('str', response.headers.get('Operation-Location')) if cls: - return cls(pipeline_response, None, response_headers) + return cls(pipeline_response, None, response_headers) _analyze_with_custom_model_initial.metadata = {'url': '/custom/models/{modelId}/analyze'} # type: ignore @@ -262,13 +272,16 @@ def begin_analyze_with_custom_model( self, model_id, # type: str include_text_details=False, # type: Optional[bool] - file_stream=None, # type: Optional[Union[str, "models.SourcePath"]] + file_stream=None, # type: Optional[Union[IO, "models.SourcePath"]] **kwargs # type: Any ): # type: (...) -> LROPoller - """Extract key-value pairs, tables, and semantic values from a given document. The input document must be of one of the supported content types - 'application/pdf', 'image/jpeg', 'image/png' or 'image/tiff'. Alternatively, use 'application/json' type to specify the location (Uri or local path) of the document to be analyzed. + """Analyze Form. - Analyze Form. + Extract key-value pairs, tables, and semantic values from a given document. The input document + must be of one of the supported content types - 'application/pdf', 'image/jpeg', 'image/png' or + 'image/tiff'. Alternatively, use 'application/json' type to specify the location (Uri or local + path) of the document to be analyzed. :param model_id: Model identifier. :type model_id: str @@ -277,11 +290,12 @@ def begin_analyze_with_custom_model( :param file_stream: .json, .pdf, .jpg, .png or .tiff type file stream. :type file_stream: ~azure.ai.formrecognizer.models.SourcePath :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. :keyword polling: True for ARMPolling, False for no polling, or a polling object for personal polling strategy :paramtype polling: bool or ~azure.core.polling.PollingMethod :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. - :return: An instance of LROPoller that returns None + :return: An instance of LROPoller that returns either None or the result of cls(response) :rtype: ~azure.core.polling.LROPoller[None] :raises ~azure.core.exceptions.HttpResponseError: """ @@ -291,13 +305,18 @@ def begin_analyze_with_custom_model( 'polling_interval', self._config.polling_interval ) - raw_result = self._analyze_with_custom_model_initial( - model_id=model_id, - include_text_details=include_text_details, - file_stream=file_stream, - cls=lambda x,y,z: x, - **kwargs - ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._analyze_with_custom_model_initial( + model_id=model_id, + include_text_details=include_text_details, + file_stream=file_stream, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) def get_long_running_output(pipeline_response): if cls: @@ -306,7 +325,15 @@ def get_long_running_output(pipeline_response): if polling is True: polling_method = LROBasePolling(lro_delay, **kwargs) elif polling is False: polling_method = NoPolling() else: polling_method = polling - return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) begin_analyze_with_custom_model.metadata = {'url': '/custom/models/{modelId}/analyze'} # type: ignore @distributed_trace @@ -317,16 +344,16 @@ def get_analyze_form_result( **kwargs # type: Any ): # type: (...) -> "models.AnalyzeOperationResult" - """Obtain current status and the result of the analyze form operation. + """Get Analyze Form Result. - Get Analyze Form Result. + Obtain current status and the result of the analyze form operation. :param model_id: Model identifier. :type model_id: str :param result_id: Analyze operation result identifier. :type result_id: str :keyword callable cls: A custom type or function that will be passed the direct response - :return: AnalyzeOperationResult or the result of cls(response) + :return: AnalyzeOperationResult, or the result of cls(response) :rtype: ~azure.ai.formrecognizer.models.AnalyzeOperationResult :raises: ~azure.core.exceptions.HttpResponseError """ @@ -363,7 +390,7 @@ def get_analyze_form_result( deserialized = self._deserialize('AnalyzeOperationResult', pipeline_response) if cls: - return cls(pipeline_response, deserialized, {}) + return cls(pipeline_response, deserialized, {}) return deserialized get_analyze_form_result.metadata = {'url': '/custom/models/{modelId}/analyzeResults/{resultId}'} # type: ignore @@ -413,7 +440,7 @@ def _copy_custom_model_initial( response_headers['Operation-Location']=self._deserialize('str', response.headers.get('Operation-Location')) if cls: - return cls(pipeline_response, None, response_headers) + return cls(pipeline_response, None, response_headers) _copy_custom_model_initial.metadata = {'url': '/custom/models/{modelId}/copy'} # type: ignore @@ -425,20 +452,22 @@ def begin_copy_custom_model( **kwargs # type: Any ): # type: (...) -> LROPoller - """Copy custom model stored in this resource (the source) to user specified target Form Recognizer resource. + """Copy Custom Model. - Copy Custom Model. + Copy custom model stored in this resource (the source) to user specified target Form Recognizer + resource. :param model_id: Model identifier. :type model_id: str :param copy_request: Copy request parameters. :type copy_request: ~azure.ai.formrecognizer.models.CopyRequest :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. :keyword polling: True for ARMPolling, False for no polling, or a polling object for personal polling strategy :paramtype polling: bool or ~azure.core.polling.PollingMethod :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. - :return: An instance of LROPoller that returns None + :return: An instance of LROPoller that returns either None or the result of cls(response) :rtype: ~azure.core.polling.LROPoller[None] :raises ~azure.core.exceptions.HttpResponseError: """ @@ -448,12 +477,17 @@ def begin_copy_custom_model( 'polling_interval', self._config.polling_interval ) - raw_result = self._copy_custom_model_initial( - model_id=model_id, - copy_request=copy_request, - cls=lambda x,y,z: x, - **kwargs - ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._copy_custom_model_initial( + model_id=model_id, + copy_request=copy_request, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) def get_long_running_output(pipeline_response): if cls: @@ -462,7 +496,15 @@ def get_long_running_output(pipeline_response): if polling is True: polling_method = LROBasePolling(lro_delay, **kwargs) elif polling is False: polling_method = NoPolling() else: polling_method = polling - return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) begin_copy_custom_model.metadata = {'url': '/custom/models/{modelId}/copy'} # type: ignore @distributed_trace @@ -473,16 +515,16 @@ def get_custom_model_copy_result( **kwargs # type: Any ): # type: (...) -> "models.CopyOperationResult" - """Obtain current status and the result of a custom model copy operation. + """Get Custom Model Copy Result. - Get Custom Model Copy Result. + Obtain current status and the result of a custom model copy operation. :param model_id: Model identifier. :type model_id: str :param result_id: Copy operation result identifier. :type result_id: str :keyword callable cls: A custom type or function that will be passed the direct response - :return: CopyOperationResult or the result of cls(response) + :return: CopyOperationResult, or the result of cls(response) :rtype: ~azure.ai.formrecognizer.models.CopyOperationResult :raises: ~azure.core.exceptions.HttpResponseError """ @@ -519,7 +561,7 @@ def get_custom_model_copy_result( deserialized = self._deserialize('CopyOperationResult', pipeline_response) if cls: - return cls(pipeline_response, deserialized, {}) + return cls(pipeline_response, deserialized, {}) return deserialized get_custom_model_copy_result.metadata = {'url': '/custom/models/{modelId}/copyResults/{resultId}'} # type: ignore @@ -530,12 +572,12 @@ def generate_model_copy_authorization( **kwargs # type: Any ): # type: (...) -> "models.CopyAuthorizationResult" - """Generate authorization to copy a model into the target Form Recognizer resource. + """Generate Copy Authorization. - Generate Copy Authorization. + Generate authorization to copy a model into the target Form Recognizer resource. :keyword callable cls: A custom type or function that will be passed the direct response - :return: CopyAuthorizationResult or the result of cls(response) + :return: CopyAuthorizationResult, or the result of cls(response) :rtype: ~azure.ai.formrecognizer.models.CopyAuthorizationResult :raises: ~azure.core.exceptions.HttpResponseError """ @@ -572,7 +614,7 @@ def generate_model_copy_authorization( deserialized = self._deserialize('CopyAuthorizationResult', pipeline_response) if cls: - return cls(pipeline_response, deserialized, response_headers) + return cls(pipeline_response, deserialized, response_headers) return deserialized generate_model_copy_authorization.metadata = {'url': '/custom/models/copyAuthorization'} # type: ignore @@ -580,7 +622,7 @@ def generate_model_copy_authorization( def _analyze_receipt_async_initial( self, include_text_details=False, # type: Optional[bool] - file_stream=None, # type: Optional[Union[str, "models.SourcePath"]] + file_stream=None, # type: Optional[Union[IO, "models.SourcePath"]] **kwargs # type: Any ): # type: (...) -> None @@ -607,9 +649,9 @@ def _analyze_receipt_async_initial( # Construct and send request body_content_kwargs = {} # type: Dict[str, Any] - if header_parameters['Content-Type'] in ['application/pdf', 'image/jpeg', 'image/png', 'image/tiff']: + if header_parameters['Content-Type'].split(";")[0] in ['application/pdf', 'image/jpeg', 'image/png', 'image/tiff']: body_content_kwargs['stream_content'] = file_stream - elif header_parameters['Content-Type'] in ['application/json']: + elif header_parameters['Content-Type'].split(";")[0] in ['application/json']: if file_stream is not None: body_content = self._serialize.body(file_stream, 'SourcePath') else: @@ -617,7 +659,8 @@ def _analyze_receipt_async_initial( body_content_kwargs['content'] = body_content else: raise ValueError( - "Content type {} is not valid for this operation".format(header_parameters['Content-Type']) + "The content_type '{}' is not one of the allowed values: " + "['application/pdf', 'image/jpeg', 'image/png', 'image/tiff', 'application/json']".format(header_parameters['Content-Type']) ) request = self._client.post(url, query_parameters, header_parameters, **body_content_kwargs) @@ -633,7 +676,7 @@ def _analyze_receipt_async_initial( response_headers['Operation-Location']=self._deserialize('str', response.headers.get('Operation-Location')) if cls: - return cls(pipeline_response, None, response_headers) + return cls(pipeline_response, None, response_headers) _analyze_receipt_async_initial.metadata = {'url': '/prebuilt/receipt/analyze'} # type: ignore @@ -641,24 +684,28 @@ def _analyze_receipt_async_initial( def begin_analyze_receipt_async( self, include_text_details=False, # type: Optional[bool] - file_stream=None, # type: Optional[Union[str, "models.SourcePath"]] + file_stream=None, # type: Optional[Union[IO, "models.SourcePath"]] **kwargs # type: Any ): # type: (...) -> LROPoller - """Extract field text and semantic values from a given receipt document. The input document must be of one of the supported content types - 'application/pdf', 'image/jpeg', 'image/png' or 'image/tiff'. Alternatively, use 'application/json' type to specify the location (Uri or local path) of the document to be analyzed. + """Analyze Receipt. - Analyze Receipt. + Extract field text and semantic values from a given receipt document. The input document must + be of one of the supported content types - 'application/pdf', 'image/jpeg', 'image/png' or + 'image/tiff'. Alternatively, use 'application/json' type to specify the location (Uri or local + path) of the document to be analyzed. :param include_text_details: Include text lines and element references in the result. :type include_text_details: bool :param file_stream: .json, .pdf, .jpg, .png or .tiff type file stream. :type file_stream: ~azure.ai.formrecognizer.models.SourcePath :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. :keyword polling: True for ARMPolling, False for no polling, or a polling object for personal polling strategy :paramtype polling: bool or ~azure.core.polling.PollingMethod :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. - :return: An instance of LROPoller that returns None + :return: An instance of LROPoller that returns either None or the result of cls(response) :rtype: ~azure.core.polling.LROPoller[None] :raises ~azure.core.exceptions.HttpResponseError: """ @@ -668,12 +715,17 @@ def begin_analyze_receipt_async( 'polling_interval', self._config.polling_interval ) - raw_result = self._analyze_receipt_async_initial( - include_text_details=include_text_details, - file_stream=file_stream, - cls=lambda x,y,z: x, - **kwargs - ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._analyze_receipt_async_initial( + include_text_details=include_text_details, + file_stream=file_stream, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) def get_long_running_output(pipeline_response): if cls: @@ -682,7 +734,15 @@ def get_long_running_output(pipeline_response): if polling is True: polling_method = LROBasePolling(lro_delay, **kwargs) elif polling is False: polling_method = NoPolling() else: polling_method = polling - return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) begin_analyze_receipt_async.metadata = {'url': '/prebuilt/receipt/analyze'} # type: ignore @distributed_trace @@ -692,14 +752,14 @@ def get_analyze_receipt_result( **kwargs # type: Any ): # type: (...) -> "models.AnalyzeOperationResult" - """Track the progress and obtain the result of the analyze receipt operation. + """Get Analyze Receipt Result. - Get Analyze Receipt Result. + Track the progress and obtain the result of the analyze receipt operation. :param result_id: Analyze operation result identifier. :type result_id: str :keyword callable cls: A custom type or function that will be passed the direct response - :return: AnalyzeOperationResult or the result of cls(response) + :return: AnalyzeOperationResult, or the result of cls(response) :rtype: ~azure.ai.formrecognizer.models.AnalyzeOperationResult :raises: ~azure.core.exceptions.HttpResponseError """ @@ -735,14 +795,14 @@ def get_analyze_receipt_result( deserialized = self._deserialize('AnalyzeOperationResult', pipeline_response) if cls: - return cls(pipeline_response, deserialized, {}) + return cls(pipeline_response, deserialized, {}) return deserialized get_analyze_receipt_result.metadata = {'url': '/prebuilt/receipt/analyzeResults/{resultId}'} # type: ignore def _analyze_layout_async_initial( self, - file_stream=None, # type: Optional[Union[str, "models.SourcePath"]] + file_stream=None, # type: Optional[Union[IO, "models.SourcePath"]] **kwargs # type: Any ): # type: (...) -> None @@ -767,9 +827,9 @@ def _analyze_layout_async_initial( # Construct and send request body_content_kwargs = {} # type: Dict[str, Any] - if header_parameters['Content-Type'] in ['application/pdf', 'image/jpeg', 'image/png', 'image/tiff']: + if header_parameters['Content-Type'].split(";")[0] in ['application/pdf', 'image/jpeg', 'image/png', 'image/tiff']: body_content_kwargs['stream_content'] = file_stream - elif header_parameters['Content-Type'] in ['application/json']: + elif header_parameters['Content-Type'].split(";")[0] in ['application/json']: if file_stream is not None: body_content = self._serialize.body(file_stream, 'SourcePath') else: @@ -777,7 +837,8 @@ def _analyze_layout_async_initial( body_content_kwargs['content'] = body_content else: raise ValueError( - "Content type {} is not valid for this operation".format(header_parameters['Content-Type']) + "The content_type '{}' is not one of the allowed values: " + "['application/pdf', 'image/jpeg', 'image/png', 'image/tiff', 'application/json']".format(header_parameters['Content-Type']) ) request = self._client.post(url, query_parameters, header_parameters, **body_content_kwargs) @@ -793,29 +854,33 @@ def _analyze_layout_async_initial( response_headers['Operation-Location']=self._deserialize('str', response.headers.get('Operation-Location')) if cls: - return cls(pipeline_response, None, response_headers) + return cls(pipeline_response, None, response_headers) _analyze_layout_async_initial.metadata = {'url': '/layout/analyze'} # type: ignore @distributed_trace def begin_analyze_layout_async( self, - file_stream=None, # type: Optional[Union[str, "models.SourcePath"]] + file_stream=None, # type: Optional[Union[IO, "models.SourcePath"]] **kwargs # type: Any ): # type: (...) -> LROPoller - """Extract text and layout information from a given document. The input document must be of one of the supported content types - 'application/pdf', 'image/jpeg', 'image/png' or 'image/tiff'. Alternatively, use 'application/json' type to specify the location (Uri or local path) of the document to be analyzed. + """Analyze Layout. - Analyze Layout. + Extract text and layout information from a given document. The input document must be of one of + the supported content types - 'application/pdf', 'image/jpeg', 'image/png' or 'image/tiff'. + Alternatively, use 'application/json' type to specify the location (Uri or local path) of the + document to be analyzed. :param file_stream: .json, .pdf, .jpg, .png or .tiff type file stream. :type file_stream: ~azure.ai.formrecognizer.models.SourcePath :keyword callable cls: A custom type or function that will be passed the direct response + :keyword str continuation_token: A continuation token to restart a poller from a saved state. :keyword polling: True for ARMPolling, False for no polling, or a polling object for personal polling strategy :paramtype polling: bool or ~azure.core.polling.PollingMethod :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. - :return: An instance of LROPoller that returns None + :return: An instance of LROPoller that returns either None or the result of cls(response) :rtype: ~azure.core.polling.LROPoller[None] :raises ~azure.core.exceptions.HttpResponseError: """ @@ -825,11 +890,16 @@ def begin_analyze_layout_async( 'polling_interval', self._config.polling_interval ) - raw_result = self._analyze_layout_async_initial( - file_stream=file_stream, - cls=lambda x,y,z: x, - **kwargs - ) + cont_token = kwargs.pop('continuation_token', None) # type: Optional[str] + if cont_token is None: + raw_result = self._analyze_layout_async_initial( + file_stream=file_stream, + cls=lambda x,y,z: x, + **kwargs + ) + + kwargs.pop('error_map', None) + kwargs.pop('content_type', None) def get_long_running_output(pipeline_response): if cls: @@ -838,7 +908,15 @@ def get_long_running_output(pipeline_response): if polling is True: polling_method = LROBasePolling(lro_delay, **kwargs) elif polling is False: polling_method = NoPolling() else: polling_method = polling - return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + if cont_token: + return LROPoller.from_continuation_token( + polling_method=polling_method, + continuation_token=cont_token, + client=self._client, + deserialization_callback=get_long_running_output + ) + else: + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) begin_analyze_layout_async.metadata = {'url': '/layout/analyze'} # type: ignore @distributed_trace @@ -848,14 +926,14 @@ def get_analyze_layout_result( **kwargs # type: Any ): # type: (...) -> "models.AnalyzeOperationResult" - """Track the progress and obtain the result of the analyze layout operation. + """Get Analyze Layout Result. - Get Analyze Layout Result. + Track the progress and obtain the result of the analyze layout operation. :param result_id: Analyze operation result identifier. :type result_id: str :keyword callable cls: A custom type or function that will be passed the direct response - :return: AnalyzeOperationResult or the result of cls(response) + :return: AnalyzeOperationResult, or the result of cls(response) :rtype: ~azure.ai.formrecognizer.models.AnalyzeOperationResult :raises: ~azure.core.exceptions.HttpResponseError """ @@ -891,7 +969,7 @@ def get_analyze_layout_result( deserialized = self._deserialize('AnalyzeOperationResult', pipeline_response) if cls: - return cls(pipeline_response, deserialized, {}) + return cls(pipeline_response, deserialized, {}) return deserialized get_analyze_layout_result.metadata = {'url': '/layout/analyzeResults/{resultId}'} # type: ignore @@ -902,12 +980,12 @@ def list_custom_models( **kwargs # type: Any ): # type: (...) -> Iterable["models.Models"] - """Get information about all custom models. + """List Custom Models. - List Custom Models. + Get information about all custom models. :keyword callable cls: A custom type or function that will be passed the direct response - :return: An iterator like instance of Models or the result of cls(response) + :return: An iterator like instance of either Models or the result of cls(response) :rtype: ~azure.core.paging.ItemPaged[~azure.ai.formrecognizer.models.Models] :raises: ~azure.core.exceptions.HttpResponseError """ @@ -974,12 +1052,12 @@ def get_custom_models( **kwargs # type: Any ): # type: (...) -> "models.Models" - """Get information about all custom models. + """Get Custom Models. - Get Custom Models. + Get information about all custom models. :keyword callable cls: A custom type or function that will be passed the direct response - :return: Models or the result of cls(response) + :return: Models, or the result of cls(response) :rtype: ~azure.ai.formrecognizer.models.Models :raises: ~azure.core.exceptions.HttpResponseError """ @@ -1016,7 +1094,7 @@ def get_custom_models( deserialized = self._deserialize('Models', pipeline_response) if cls: - return cls(pipeline_response, deserialized, {}) + return cls(pipeline_response, deserialized, {}) return deserialized get_custom_models.metadata = {'url': '/custom/models'} # type: ignore diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_recognizer_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_recognizer_client_async.py index ae35b3c275c6..3e26bd518e27 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_recognizer_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_recognizer_client_async.py @@ -8,12 +8,13 @@ from typing import ( Any, - List, IO, Union, + List, TYPE_CHECKING, ) from azure.core.tracing.decorator_async import distributed_trace_async +from azure.core.polling import AsyncLROPoller from azure.core.polling.async_base_polling import AsyncLROBasePolling from .._generated.aio._form_recognizer_client_async import FormRecognizerClient as FormRecognizer from .._response_handlers import ( @@ -25,14 +26,10 @@ from .._helpers import get_content_type, get_authentication_policy, error_map, POLLING_INTERVAL from .._user_agent import USER_AGENT from .._polling import AnalyzePolling +from .._models import RecognizedReceipt, FormPage, RecognizedForm if TYPE_CHECKING: from azure.core.credentials import AzureKeyCredential from azure.core.credentials_async import AsyncTokenCredential - from .._models import ( - RecognizedReceipt, - FormPage, - RecognizedForm - ) class FormRecognizerClient(object): @@ -76,7 +73,7 @@ def __init__( authentication_policy = get_authentication_policy(credential) self._client = FormRecognizer( endpoint=endpoint, - credential=credential, + credential=credential, # type: ignore sdk_moniker=USER_AGENT, authentication_policy=authentication_policy, **kwargs @@ -87,11 +84,11 @@ def _receipt_callback(self, raw_response, _, headers): # pylint: disable=unused return prepare_receipt(analyze_result) @distributed_trace_async - async def recognize_receipts( + async def begin_recognize_receipts( self, receipt: Union[bytes, IO[bytes]], **kwargs: Any - ) -> List["RecognizedReceipt"]: + ) -> AsyncLROPoller[List[RecognizedReceipt]]: """Extract field text and semantic values from a given US sales receipt. The input document must be of one of the supported content types - 'application/pdf', 'image/jpeg', 'image/png' or 'image/tiff'. @@ -106,8 +103,10 @@ async def recognize_receipts( see :class:`~azure.ai.formrecognizer.FormContentType`. :keyword int polling_interval: Waiting time between two polls for LRO operations if no Retry-After header is present. Defaults to 5 seconds. - :return: A list of RecognizedReceipt. - :rtype: list[~azure.ai.formrecognizer.RecognizedReceipt] + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :return: An instance of an AsyncLROPoller. Call `result()` on the poller + object to return a list[:class:`~azure.ai.formrecognizer.RecognizedReceipt`]. + :rtype: ~azure.core.polling.AsyncLROPoller[list[~azure.ai.formrecognizer.RecognizedReceipt]] :raises ~azure.core.exceptions.HttpResponseError: .. admonition:: Example: @@ -121,6 +120,7 @@ async def recognize_receipts( """ polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) + continuation_token = kwargs.pop("continuation_token", None) content_type = kwargs.pop("content_type", None) if content_type == "application/json": raise TypeError("Call begin_recognize_receipts_from_url() to analyze a receipt from a url.") @@ -130,22 +130,26 @@ async def recognize_receipts( if content_type is None: content_type = get_content_type(receipt) - return await self._client.analyze_receipt_async( # type: ignore + return await self._client.begin_analyze_receipt_async( # type: ignore file_stream=receipt, content_type=content_type, include_text_details=include_text_content, cls=kwargs.pop("cls", self._receipt_callback), - polling=AsyncLROBasePolling(timeout=polling_interval, **kwargs), + polling=AsyncLROBasePolling( + timeout=polling_interval, + **kwargs + ), error_map=error_map, + continuation_token=continuation_token, **kwargs ) @distributed_trace_async - async def recognize_receipts_from_url( + async def begin_recognize_receipts_from_url( self, receipt_url: str, **kwargs: Any - ) -> List["RecognizedReceipt"]: + ) -> AsyncLROPoller[List[RecognizedReceipt]]: """Extract field text and semantic values from a given US sales receipt. The input document must be the location (Url) of the receipt to be analyzed. @@ -156,8 +160,10 @@ async def recognize_receipts_from_url( Whether or not to include text elements such as lines and words in addition to form fields. :keyword int polling_interval: Waiting time between two polls for LRO operations if no Retry-After header is present. Defaults to 5 seconds. - :return: A list of RecognizedReceipt. - :rtype: list[~azure.ai.formrecognizer.RecognizedReceipt] + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :return: An instance of an AsyncLROPoller. Call `result()` on the poller + object to return a list[:class:`~azure.ai.formrecognizer.RecognizedReceipt`]. + :rtype: ~azure.core.polling.AsyncLROPoller[list[~azure.ai.formrecognizer.RecognizedReceipt]] :raises ~azure.core.exceptions.HttpResponseError: .. admonition:: Example: @@ -171,14 +177,19 @@ async def recognize_receipts_from_url( """ polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) + continuation_token = kwargs.pop("continuation_token", None) include_text_content = kwargs.pop("include_text_content", False) - return await self._client.analyze_receipt_async( # type: ignore + return await self._client.begin_analyze_receipt_async( # type: ignore file_stream={"source": receipt_url}, include_text_details=include_text_content, cls=kwargs.pop("cls", self._receipt_callback), - polling=AsyncLROBasePolling(timeout=polling_interval, **kwargs), + polling=AsyncLROBasePolling( + timeout=polling_interval, + **kwargs + ), error_map=error_map, + continuation_token=continuation_token, **kwargs ) @@ -187,7 +198,11 @@ def _content_callback(self, raw_response, _, headers): # pylint: disable=unused return prepare_content_result(analyze_result) @distributed_trace_async - async def recognize_content(self, form: Union[bytes, IO[bytes]], **kwargs: Any) -> List["FormPage"]: + async def begin_recognize_content( + self, + form: Union[bytes, IO[bytes]], + **kwargs: Any + ) -> AsyncLROPoller[List[FormPage]]: """Extract text and content/layout information from a given document. The input document must be of one of the supported content types - 'application/pdf', 'image/jpeg', 'image/png' or 'image/tiff'. @@ -199,8 +214,10 @@ async def recognize_content(self, form: Union[bytes, IO[bytes]], **kwargs: Any) see :class:`~azure.ai.formrecognizer.FormContentType`. :keyword int polling_interval: Waiting time between two polls for LRO operations if no Retry-After header is present. Defaults to 5 seconds. - :return: A list of FormPage. - :rtype: list[~azure.ai.formrecognizer.FormPage] + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :return: An instance of an AsyncLROPoller. Call `result()` on the poller + object to return a list[:class:`~azure.ai.formrecognizer.FormPage`]. + :rtype: ~azure.core.polling.AsyncLROPoller[list[~azure.ai.formrecognizer.FormPage]] :raises ~azure.core.exceptions.HttpResponseError: .. admonition:: Example: @@ -214,6 +231,7 @@ async def recognize_content(self, form: Union[bytes, IO[bytes]], **kwargs: Any) """ polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) + continuation_token = kwargs.pop("continuation_token", None) content_type = kwargs.pop("content_type", None) if content_type == "application/json": raise TypeError("Call begin_recognize_content_from_url() to analyze a document from a url.") @@ -221,17 +239,21 @@ async def recognize_content(self, form: Union[bytes, IO[bytes]], **kwargs: Any) if content_type is None: content_type = get_content_type(form) - return await self._client.analyze_layout_async( # type: ignore + return await self._client.begin_analyze_layout_async( # type: ignore file_stream=form, content_type=content_type, cls=kwargs.pop("cls", self._content_callback), - polling=AsyncLROBasePolling(timeout=polling_interval, **kwargs), + polling=AsyncLROBasePolling( + timeout=polling_interval, + **kwargs + ), error_map=error_map, + continuation_token=continuation_token, **kwargs ) @distributed_trace_async - async def recognize_content_from_url(self, form_url: str, **kwargs: Any) -> List["FormPage"]: + async def begin_recognize_content_from_url(self, form_url: str, **kwargs: Any) -> AsyncLROPoller[List[FormPage]]: """Extract text and layout information from a given document. The input document must be the location (Url) of the document to be analyzed. @@ -239,27 +261,34 @@ async def recognize_content_from_url(self, form_url: str, **kwargs: Any) -> List of one of the supported formats: JPEG, PNG, PDF and TIFF. :keyword int polling_interval: Waiting time between two polls for LRO operations if no Retry-After header is present. Defaults to 5 seconds. - :return: A list of FormPage. - :rtype: list[~azure.ai.formrecognizer.FormPage] + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :return: An instance of an AsyncLROPoller. Call `result()` on the poller + object to return a list[:class:`~azure.ai.formrecognizer.FormPage`]. + :rtype: ~azure.core.polling.AsyncLROPoller[list[~azure.ai.formrecognizer.FormPage]] :raises ~azure.core.exceptions.HttpResponseError: """ polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) - return await self._client.analyze_layout_async( # type: ignore + continuation_token = kwargs.pop("continuation_token", None) + return await self._client.begin_analyze_layout_async( # type: ignore file_stream={"source": form_url}, cls=kwargs.pop("cls", self._content_callback), - polling=AsyncLROBasePolling(timeout=polling_interval, **kwargs), + polling=AsyncLROBasePolling( + timeout=polling_interval, + **kwargs + ), error_map=error_map, + continuation_token=continuation_token, **kwargs ) @distributed_trace_async - async def recognize_custom_forms( + async def begin_recognize_custom_forms( self, model_id: str, form: Union[bytes, IO[bytes]], **kwargs: Any - ) -> List["RecognizedForm"]: + ) -> AsyncLROPoller[List[RecognizedForm]]: """Analyze a custom form with a model trained with or without labels. The form to analyze should be of the same type as the forms that were used to train the model. The input document must be of one of the supported content types - 'application/pdf', @@ -275,8 +304,10 @@ async def recognize_custom_forms( see :class:`~azure.ai.formrecognizer.FormContentType`. :keyword int polling_interval: Waiting time between two polls for LRO operations if no Retry-After header is present. Defaults to 5 seconds. - :return: A list of RecognizedForm. - :rtype: list[~azure.ai.formrecognizer.RecognizedForm] + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :return: An instance of an AsyncLROPoller. Call `result()` on the poller + object to return a list[:class:`~azure.ai.formrecognizer.RecognizedForm`]. + :rtype: ~azure.core.polling.AsyncLROPoller[list[~azure.ai.formrecognizer.RecognizedForm] :raises ~azure.core.exceptions.HttpResponseError: .. admonition:: Example: @@ -294,6 +325,7 @@ async def recognize_custom_forms( cls = kwargs.pop("cls", None) polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) + continuation_token = kwargs.pop("continuation_token", None) content_type = kwargs.pop("content_type", None) if content_type == "application/json": raise TypeError("Call begin_recognize_custom_forms_from_url() to analyze a document from a url.") @@ -308,24 +340,29 @@ def analyze_callback(raw_response, _, headers): # pylint: disable=unused-argume return prepare_form_result(analyze_result, model_id) deserialization_callback = cls if cls else analyze_callback - return await self._client.analyze_with_custom_model( # type: ignore + return await self._client.begin_analyze_with_custom_model( # type: ignore file_stream=form, model_id=model_id, include_text_details=include_text_content, content_type=content_type, cls=deserialization_callback, - polling=AsyncLROBasePolling(timeout=polling_interval, lro_algorithms=[AnalyzePolling()], **kwargs), + polling=AsyncLROBasePolling( + timeout=polling_interval, + lro_algorithms=[AnalyzePolling()], + **kwargs + ), error_map=error_map, + continuation_token=continuation_token, **kwargs ) @distributed_trace_async - async def recognize_custom_forms_from_url( + async def begin_recognize_custom_forms_from_url( self, model_id: str, form_url: str, **kwargs: Any - ) -> List["RecognizedForm"]: + ) -> AsyncLROPoller[List[RecognizedForm]]: """Analyze a custom form with a model trained with or without labels. The form to analyze should be of the same type as the forms that were used to train the model. The input document must be the location (Url) of the document to be analyzed. @@ -337,8 +374,10 @@ async def recognize_custom_forms_from_url( Whether or not to include text elements such as lines and words in addition to form fields. :keyword int polling_interval: Waiting time between two polls for LRO operations if no Retry-After header is present. Defaults to 5 seconds. - :return: A list of RecognizedForm. - :rtype: list[~azure.ai.formrecognizer.RecognizedForm] + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :return: An instance of an AsyncLROPoller. Call `result()` on the poller + object to return a list[:class:`~azure.ai.formrecognizer.RecognizedForm`]. + :rtype: ~azure.core.polling.AsyncLROPoller[list[~azure.ai.formrecognizer.RecognizedForm] :raises ~azure.core.exceptions.HttpResponseError: """ @@ -347,6 +386,7 @@ async def recognize_custom_forms_from_url( cls = kwargs.pop("cls", None) polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) + continuation_token = kwargs.pop("continuation_token", None) include_text_content = kwargs.pop("include_text_content", False) def analyze_callback(raw_response, _, headers): # pylint: disable=unused-argument @@ -354,13 +394,18 @@ def analyze_callback(raw_response, _, headers): # pylint: disable=unused-argume return prepare_form_result(analyze_result, model_id) deserialization_callback = cls if cls else analyze_callback - return await self._client.analyze_with_custom_model( # type: ignore + return await self._client.begin_analyze_with_custom_model( # type: ignore file_stream={"source": form_url}, model_id=model_id, include_text_details=include_text_content, cls=deserialization_callback, - polling=AsyncLROBasePolling(timeout=polling_interval, lro_algorithms=[AnalyzePolling()], **kwargs), + polling=AsyncLROBasePolling( + timeout=polling_interval, + lro_algorithms=[AnalyzePolling()], + **kwargs + ), error_map=error_map, + continuation_token=continuation_token, **kwargs ) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py index 70611586bf83..70e288d5e7b8 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/aio/_form_training_client_async.py @@ -14,7 +14,7 @@ Union, TYPE_CHECKING, ) -from azure.core.polling import async_poller +from azure.core.polling import AsyncLROPoller from azure.core.polling.async_base_polling import AsyncLROBasePolling from azure.core.tracing.decorator import distributed_trace from azure.core.tracing.decorator_async import distributed_trace_async @@ -85,19 +85,19 @@ def __init__( authentication_policy = get_authentication_policy(credential) self._client = FormRecognizer( endpoint=self._endpoint, - credential=self._credential, + credential=self._credential, # type: ignore sdk_moniker=USER_AGENT, authentication_policy=authentication_policy, **kwargs ) @distributed_trace_async - async def train_model( + async def begin_training( self, training_files_url: str, use_training_labels: bool, **kwargs: Any - ) -> CustomFormModel: + ) -> AsyncLROPoller[CustomFormModel]: """Create and train a custom model. The request must include a `training_files_url` parameter that is an externally accessible Azure storage blob container Uri (preferably a Shared Access Signature Uri). Models are trained using documents that are of the following content type - 'application/pdf', @@ -114,8 +114,10 @@ async def train_model( Use with `prefix` to filter for only certain sub folders. Not supported if training with labels. :keyword int polling_interval: Waiting time between two polls for LRO operations if no Retry-After header is present. Defaults to 5 seconds. - :return: CustomFormModel - :rtype: ~azure.ai.formrecognizer.CustomFormModel + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :return: An instance of an AsyncLROPoller. Call `result()` on the poller + object to return a :class:`~azure.ai.formrecognizer.CustomFormModel`. + :rtype: ~azure.core.polling.AsyncLROPoller[~azure.ai.formrecognizer.CustomFormModel] :raises ~azure.core.exceptions.HttpResponseError: Note that if the training fails, the exception is raised, but a model with an "invalid" status is still created. You can delete this model by calling :func:`~delete_model()` @@ -130,8 +132,27 @@ async def train_model( :caption: Training a model with your custom forms. """ + def callback(raw_response): + model = self._client._deserialize(Model, raw_response) + return CustomFormModel._from_generated(model) + cls = kwargs.pop("cls", None) + continuation_token = kwargs.pop("continuation_token", None) polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) + deserialization_callback = cls if cls else callback + + if continuation_token: + return AsyncLROPoller.from_continuation_token( + polling_method=AsyncLROBasePolling( # type: ignore + timeout=polling_interval, + lro_algorithms=[TrainingPolling()], + **kwargs + ), + continuation_token=continuation_token, + client=self._client._client, + deserialization_callback=deserialization_callback + ) + response = await self._client.train_custom_model_async( train_request=TrainRequest( source=training_files_url, @@ -146,16 +167,15 @@ async def train_model( **kwargs ) - def callback(raw_response): - model = self._client._deserialize(Model, raw_response) - return CustomFormModel._from_generated(model) - - deserialization_callback = cls if cls else callback - return await async_poller( + return AsyncLROPoller( self._client._client, response, deserialization_callback, - AsyncLROBasePolling(timeout=polling_interval, lro_algorithms=[TrainingPolling()], **kwargs) + AsyncLROBasePolling( # type: ignore + timeout=polling_interval, + lro_algorithms=[TrainingPolling()], + **kwargs + ) ) @distributed_trace_async @@ -272,7 +292,7 @@ async def get_copy_authorization( ) -> Dict[str, Union[str, int]]: """Generate authorization for copying a custom model into the target Form Recognizer resource. This should be called by the target resource (where the model will be copied to) - and the output can be passed as the `target` parameter into :func:`~copy_model()`. + and the output can be passed as the `target` parameter into :func:`~begin_copy_model()`. :param str resource_id: Azure Resource Id of the target Form Recognizer resource where the model will be copied to. @@ -304,12 +324,12 @@ async def get_copy_authorization( return target @distributed_trace_async - async def copy_model( + async def begin_copy_model( self, model_id: str, target: dict, **kwargs: Any - ) -> CustomFormModelInfo: + ) -> AsyncLROPoller[CustomFormModelInfo]: """Copy a custom model stored in this resource (the source) to the user specified target Form Recognizer resource. This should be called with the source Form Recognizer resource (with the model that is intended to be copied). The `target` parameter should be supplied from the @@ -321,8 +341,10 @@ async def copy_model( :func:`~get_copy_authorization()`. :keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present. - :return: CustomFormModelInfo - :rtype: ~azure.ai.formrecognizer.CustomFormModelInfo + :keyword str continuation_token: A continuation token to restart a poller from a saved state. + :return: An instance of an AsyncLROPoller. Call `result()` on the poller + object to return a :class:`~azure.ai.formrecognizer.CustomFormModelInfo`. + :rtype: ~azure.core.polling.AsyncLROPoller[~azure.ai.formrecognizer.CustomFormModelInfo] :raises ~azure.core.exceptions.HttpResponseError: .. admonition:: Example: @@ -338,13 +360,14 @@ async def copy_model( if not model_id: raise ValueError("model_id cannot be None or empty.") + continuation_token = kwargs.pop("continuation_token", None) polling_interval = kwargs.pop("polling_interval", POLLING_INTERVAL) def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument copy_result = self._client._deserialize(CopyOperationResult, raw_response) return CustomFormModelInfo._from_generated(copy_result, target["modelId"]) - return await self._client.copy_custom_model( # type: ignore + return await self._client.begin_copy_custom_model( # type: ignore model_id=model_id, copy_request=CopyRequest( target_resource_id=target["resourceId"], @@ -356,8 +379,13 @@ def _copy_callback(raw_response, _, headers): # pylint: disable=unused-argument ) ), cls=kwargs.pop("cls", _copy_callback), - polling=AsyncLROBasePolling(timeout=polling_interval, lro_algorithms=[CopyPolling()], **kwargs), + polling=AsyncLROBasePolling( + timeout=polling_interval, + lro_algorithms=[CopyPolling()], + **kwargs + ), error_map=error_map, + continuation_token=continuation_token, **kwargs ) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_authentication_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_authentication_async.py index 7b5b28c89f65..03e9e45165fb 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_authentication_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_authentication_async.py @@ -47,7 +47,9 @@ async def authentication_with_api_key_credential_form_recognizer_client_async(se form_recognizer_client = FormRecognizerClient(endpoint, AzureKeyCredential(key)) # [END create_fr_client_with_key_async] - receipt = await form_recognizer_client.recognize_receipts_from_url(self.url) + async with form_recognizer_client: + poller = await form_recognizer_client.begin_recognize_receipts_from_url(self.url) + result = await poller.result() async def authentication_with_azure_active_directory_form_recognizer_client_async(self): """DefaultAzureCredential will use the values from these environment @@ -62,7 +64,9 @@ async def authentication_with_azure_active_directory_form_recognizer_client_asyn form_recognizer_client = FormRecognizerClient(endpoint, credential) # [END create_fr_client_with_aad_async] - poller = await form_recognizer_client.recognize_receipts_from_url(self.url) + async with form_recognizer_client: + poller = await form_recognizer_client.begin_recognize_receipts_from_url(self.url) + result = await poller.result() async def authentication_with_api_key_credential_form_training_client_async(self): # [START create_ft_client_with_key_async] @@ -73,7 +77,8 @@ async def authentication_with_api_key_credential_form_training_client_async(self form_training_client = FormTrainingClient(endpoint, AzureKeyCredential(key)) # [END create_ft_client_with_key_async] - properties = await form_training_client.get_account_properties() + async with form_training_client: + properties = await form_training_client.get_account_properties() async def authentication_with_azure_active_directory_form_training_client_async(self): """DefaultAzureCredential will use the values from these environment @@ -88,7 +93,8 @@ async def authentication_with_azure_active_directory_form_training_client_async( form_training_client = FormTrainingClient(endpoint, credential) # [END create_ft_client_with_aad_async] - properties = await form_training_client.get_account_properties() + async with form_training_client: + properties = await form_training_client.get_account_properties() async def main(): diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py index 90b0c50ad8b6..1101cab2c5be 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_copy_model_async.py @@ -59,10 +59,11 @@ async def copy_model_async(self): target_client = FormTrainingClient(endpoint=target_endpoint, credential=AzureKeyCredential(target_key)) async with source_client: - copy = await source_client.copy_model( + poller = await source_client.begin_copy_model( model_id=source_model_id, target=target ) + copy = await poller.result() async with target_client: copied_over_model = await target_client.get_custom_model(copy.model_id) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_differentiate_output_models_trained_with_and_without_labels_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_differentiate_output_models_trained_with_and_without_labels_async.py index 18a2b42702a6..8c11623a4a91 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_differentiate_output_models_trained_with_and_without_labels_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_differentiate_output_models_trained_with_and_without_labels_async.py @@ -11,7 +11,7 @@ DESCRIPTION: This sample demonstrates the differences in output that arise when recognize_custom_forms - is called with custom models trained with labeled and unlabeled data. For a more general + is called with custom models trained with labels and without labels. For a more general example of recognizing custom forms, see sample_recognize_custom_forms_async.py USAGE: python sample_differentiate_output_models_trained_with_and_without_labels_async.py @@ -26,11 +26,13 @@ import os import asyncio + def format_bounding_box(bounding_box): if not bounding_box: return "N/A" return ", ".join(["[{}, {}]".format(p.x, p.y) for p in bounding_box]) + class DifferentiateOutputModelsTrainedWithAndWithoutLabelsSampleAsync(object): async def recognize_custom_forms(self): @@ -49,14 +51,16 @@ async def recognize_custom_forms(self): # Make sure your form's type is included in the list of form types the custom model can recognize with open(path_to_sample_forms, "rb") as f: - stream = f.read() - forms_with_labeled_model = await form_recognizer_client.recognize_custom_forms( - model_id=model_trained_with_labels_id, form=stream - ) - forms_with_unlabeled_model = await form_recognizer_client.recognize_custom_forms( - model_id=model_trained_without_labels_id, form=stream + form = f.read() + with_labels_poller = await form_recognizer_client.begin_recognize_custom_forms( + model_id=model_trained_with_labels_id, form=form ) + forms_with_labeled_model = await with_labels_poller.result() + without_labels_poller = await form_recognizer_client.begin_recognize_custom_forms( + model_id=model_trained_without_labels_id, form=form + ) + forms_with_unlabeled_model = await without_labels_poller.result() # With a form recognized by a model trained with labels, this 'name' key will be its # training-time label, otherwise it will be denoted by numeric indices. # Label data is not returned for model trained with labels. @@ -91,7 +95,6 @@ async def recognize_custom_forms(self): )) - async def main(): sample = DifferentiateOutputModelsTrainedWithAndWithoutLabelsSampleAsync() await sample.recognize_custom_forms() diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_get_bounding_boxes_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_get_bounding_boxes_async.py index f2b603a15b40..73a8f31f51c5 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_get_bounding_boxes_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_get_bounding_boxes_async.py @@ -30,6 +30,7 @@ def format_bounding_box(bounding_box): return "N/A" return ", ".join(["[{}, {}]".format(p.x, p.y) for p in bounding_box]) + class GetBoundingBoxesSampleAsync(object): async def get_bounding_boxes(self): @@ -49,10 +50,11 @@ async def get_bounding_boxes(self): async with form_recognizer_client: # Make sure your form's type is included in the list of form types the custom model can recognize with open(path_to_sample_forms, "rb") as f: - forms = await form_recognizer_client.recognize_custom_forms( - model_id=model_id, form=f.read(), include_text_content=True + poller = await form_recognizer_client.begin_recognize_custom_forms( + model_id=model_id, form=f, include_text_content=True ) + forms = await poller.result() for idx, form in enumerate(forms): print("--------RECOGNIZING FORM #{}--------".format(idx)) print("Form has type {}".format(form.form_type)) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_manage_custom_models_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_manage_custom_models_async.py index 8c2d089f8d1f..6a1a5ba4a8ab 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_manage_custom_models_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_manage_custom_models_async.py @@ -11,8 +11,8 @@ DESCRIPTION: This sample demonstrates how to manage the custom models on your account. To learn - how to create and train a custom model, look at sample_train_unlabeled_model.py and - sample_train_labeled_model.py. + how to create and train a custom model, look at sample_train_model_without_labels.py and + sample_train_model_with_labels.py. USAGE: python sample_manage_custom_models_async.py @@ -79,6 +79,7 @@ async def manage_custom_models(self): print("Successfully deleted model with id {}".format(custom_model.model_id)) # [END delete_model_async] + async def main(): sample = ManageCustomModelsSampleAsync() await sample.manage_custom_models() diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_content_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_content_async.py index a20143df346e..64348e507c5d 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_content_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_content_async.py @@ -30,6 +30,7 @@ def format_bounding_box(bounding_box): return "N/A" return ", ".join(["[{}, {}]".format(p.x, p.y) for p in bounding_box]) + class RecognizeContentSampleAsync(object): async def recognize_content(self): @@ -46,7 +47,9 @@ async def recognize_content(self): ) as form_recognizer_client: with open(path_to_sample_forms, "rb") as f: - contents = await form_recognizer_client.recognize_content(form=f.read()) + poller = await form_recognizer_client.begin_recognize_content(form=f) + + contents = await poller.result() for idx, content in enumerate(contents): print("----Recognizing content from page #{}----".format(idx)) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_custom_forms_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_custom_forms_async.py index 0ffa898041d4..d763770c00ab 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_custom_forms_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_custom_forms_async.py @@ -13,7 +13,7 @@ This sample demonstrates how to analyze a form from a document with a custom trained model. The form must be of the same type as the forms the custom model was trained on. To learn how to train your own models, look at - sample_train_unlabeled_model_async.py and sample_train_labeled_model_async.py + sample_train_model_without_labels_async.py and sample_train_model_with_labels_async.py USAGE: python sample_recognize_custom_forms_async.py @@ -25,7 +25,6 @@ import os import asyncio -from pathlib import Path class RecognizeCustomFormsSampleAsync(object): @@ -46,9 +45,10 @@ async def recognize_custom_forms(self): # Make sure your form's type is included in the list of form types the custom model can recognize with open(path_to_sample_forms, "rb") as f: - forms = await form_recognizer_client.recognize_custom_forms( - model_id=model_id, form=f.read() + poller = await form_recognizer_client.begin_recognize_custom_forms( + model_id=model_id, form=f ) + forms = await poller.result() for idx, form in enumerate(forms): print("--------Recognizing Form #{}--------".format(idx)) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_receipts_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_receipts_async.py index 3bca0eb2549d..1b410bc6f20f 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_receipts_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_receipts_async.py @@ -22,7 +22,6 @@ import os import asyncio -from pathlib import Path class RecognizeReceiptsSampleAsync(object): @@ -41,7 +40,9 @@ async def recognize_receipts(self): ) as form_recognizer_client: with open(path_to_sample_forms, "rb") as f: - receipts = await form_recognizer_client.recognize_receipts(receipt=f.read()) + poller = await form_recognizer_client.begin_recognize_receipts(receipt=f) + + receipts = await poller.result() for idx, receipt in enumerate(receipts): print("--------Recognizing receipt #{}--------".format(idx)) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_receipts_from_url_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_receipts_from_url_async.py index 3559261094fb..8f244f8b20c4 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_receipts_from_url_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_recognize_receipts_from_url_async.py @@ -38,7 +38,8 @@ async def recognize_receipts_from_url(self): endpoint=endpoint, credential=AzureKeyCredential(key) ) as form_recognizer_client: url = "https://raw.githubusercontent.com/Azure/azure-sdk-for-python/master/sdk/formrecognizer/azure-ai-formrecognizer/tests/sample_forms/receipt/contoso-receipt.png" - receipts = await form_recognizer_client.recognize_receipts_from_url(receipt_url=url) + poller = await form_recognizer_client.begin_recognize_receipts_from_url(receipt_url=url) + receipts = await poller.result() for idx, receipt in enumerate(receipts): print("--------Recognizing receipt #{}--------".format(idx)) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_train_model_with_labels_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_train_model_with_labels_async.py index 205aa36b855a..21d897d5a680 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_train_model_with_labels_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_train_model_with_labels_async.py @@ -10,8 +10,9 @@ FILE: sample_train_model_with_labels_async.py DESCRIPTION: - This sample demonstrates how to train a model with labeled data. To see how to label your documents. You can use the service's labeling tool - to label your documents: https://docs.microsoft.com/en-us/azure/cognitive-services/form-recognizer/quickstarts/label-tool, and follow their + This sample demonstrates how to train a model with labels. To see how to label your documents, you can use the + service's labeling tool to label your documents: + https://docs.microsoft.com/azure/cognitive-services/form-recognizer/quickstarts/label-tool. Follow the instructions to store these labeled files in your blob container with the other form files. See sample_recognize_custom_forms_async.py to recognize forms with your custom model. USAGE: @@ -21,8 +22,8 @@ 1) AZURE_FORM_RECOGNIZER_ENDPOINT - the endpoint to your Cognitive Services resource. 2) AZURE_FORM_RECOGNIZER_KEY - your Form Recognizer API key 3) CONTAINER_SAS_URL - The shared access signature (SAS) Url of your Azure Blob Storage container with your labeled data. - See https://docs.microsoft.com/en-us/azure/cognitive-services/form-recognizer/quickstarts/python-labeled-data#train-a-model-using-labeled-data - for more detailed descriptions on how to get it. + See https://docs.microsoft.com/azure/cognitive-services/form-recognizer/quickstarts/python-labeled-data#train-a-model-using-labeled-data + for more detailed descriptions on how to get it. """ import os @@ -44,7 +45,8 @@ async def train_model_with_labels(self): ) async with form_training_client: - model = await form_training_client.train_model(container_sas_url, use_training_labels=True) + poller = await form_training_client.begin_training(container_sas_url, use_training_labels=True) + model = await poller.result() # Custom model information print("Model ID: {}".format(model.model_id)) @@ -69,6 +71,7 @@ async def train_model_with_labels(self): print("Document page count: {}".format(doc.page_count)) print("Document errors: {}".format(doc.errors)) + async def main(): sample = TrainModelWithLabelsSampleAsync() await sample.train_model_with_labels() diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_train_model_without_labels_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_train_model_without_labels_async.py index 37de8d1539d6..c483df401358 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_train_model_without_labels_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/async_samples/sample_train_model_without_labels_async.py @@ -19,8 +19,8 @@ 1) AZURE_FORM_RECOGNIZER_ENDPOINT - the endpoint to your Cognitive Services resource. 2) AZURE_FORM_RECOGNIZER_KEY - your Form Recognizer API key 3) CONTAINER_SAS_URL - The shared access signature (SAS) Url of your Azure Blob Storage container with your forms. - See https://docs.microsoft.com/en-us/azure/cognitive-services/form-recognizer/quickstarts/label-tool#connect-to-the-sample-labeling-tool - for more detailed descriptions on how to get it. + See https://docs.microsoft.com/azure/cognitive-services/form-recognizer/quickstarts/label-tool#connect-to-the-sample-labeling-tool + for more detailed descriptions on how to get it. """ import os @@ -42,7 +42,8 @@ async def train_model_without_labels(self): endpoint, AzureKeyCredential(key) ) as form_training_client: - model = await form_training_client.train_model(container_sas_url, use_training_labels=False) + poller = await form_training_client.begin_training(container_sas_url, use_training_labels=False) + model = await poller.result() # Custom model information print("Model ID: {}".format(model.model_id)) @@ -66,6 +67,7 @@ async def train_model_without_labels(self): print("Document page count: {}".format(doc.page_count)) print("Document errors: {}".format(doc.errors)) + async def main(): sample = TrainModelWithoutLabelsSampleAsync() await sample.train_model_without_labels() diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_recognize_custom_forms.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_recognize_custom_forms.py index da3092d399b6..175eff0486b6 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_recognize_custom_forms.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_recognize_custom_forms.py @@ -13,7 +13,7 @@ This sample demonstrates how to analyze a form from a document with a custom trained model. The form must be of the same type as the forms the custom model was trained on. To learn how to train your own models, look at - sample_train_unlabeled_model.py and sample_train_labeled_model.py + sample_train_model_without_labels.py and sample_train_model_with_labels.py USAGE: python sample_recognize_custom_forms.py diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_train_model_with_labels.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_train_model_with_labels.py index 9508c4945876..0f6efbe46937 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_train_model_with_labels.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_train_model_with_labels.py @@ -10,8 +10,9 @@ FILE: sample_train_model_with_labels.py DESCRIPTION: - This sample demonstrates how to train a model with labeled data. To see how to label your documents. You can use the service's labeling tool - to label your documents: https://docs.microsoft.com/en-us/azure/cognitive-services/form-recognizer/quickstarts/label-tool, and follow their + This sample demonstrates how to train a model with labels. To see how to label your documents, you can use the + service's labeling tool to label your documents: + https://docs.microsoft.com/azure/cognitive-services/form-recognizer/quickstarts/label-tool. Follow the instructions to store these labeled files in your blob container with the other form files. See sample_recognize_custom_forms.py to recognize forms with your custom model. USAGE: @@ -21,8 +22,8 @@ 1) AZURE_FORM_RECOGNIZER_ENDPOINT - the endpoint to your Cognitive Services resource. 2) AZURE_FORM_RECOGNIZER_KEY - your Form Recognizer API key 3) CONTAINER_SAS_URL - The shared access signature (SAS) Url of your Azure Blob Storage container with your labeled data. - See https://docs.microsoft.com/en-us/azure/cognitive-services/form-recognizer/quickstarts/python-labeled-data#train-a-model-using-labeled-data - for more detailed descriptions on how to get it. + See https://docs.microsoft.com/azure/cognitive-services/form-recognizer/quickstarts/python-labeled-data#train-a-model-using-labeled-data + for more detailed descriptions on how to get it. """ import os @@ -39,8 +40,7 @@ def train_model_with_labels(self): container_sas_url = os.environ["CONTAINER_SAS_URL"] form_training_client = FormTrainingClient(endpoint, AzureKeyCredential(key)) - - poller = form_training_client.begin_train_model(container_sas_url, use_training_labels=True) + poller = form_training_client.begin_training(container_sas_url, use_training_labels=True) model = poller.result() # Custom model information @@ -66,6 +66,7 @@ def train_model_with_labels(self): print("Document page count: {}".format(doc.page_count)) print("Document errors: {}".format(doc.errors)) + if __name__ == '__main__': sample = TrainModelWithLabelsSample() sample.train_model_with_labels() diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_train_model_without_labels.py b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_train_model_without_labels.py index 73a69f17311b..9ddfbaaf2237 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_train_model_without_labels.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_train_model_without_labels.py @@ -19,8 +19,8 @@ 1) AZURE_FORM_RECOGNIZER_ENDPOINT - the endpoint to your Cognitive Services resource. 2) AZURE_FORM_RECOGNIZER_KEY - your Form Recognizer API key 3) CONTAINER_SAS_URL - The shared access signature (SAS) Url of your Azure Blob Storage container with your forms. - See https://docs.microsoft.com/en-us/azure/cognitive-services/form-recognizer/quickstarts/label-tool#connect-to-the-sample-labeling-tool - for more detailed descriptions on how to get it. + See https://docs.microsoft.com/azure/cognitive-services/form-recognizer/quickstarts/label-tool#connect-to-the-sample-labeling-tool + for more detailed descriptions on how to get it. """ import os @@ -38,8 +38,7 @@ def train_model_without_labels(self): container_sas_url = os.environ["CONTAINER_SAS_URL"] form_training_client = FormTrainingClient(endpoint, AzureKeyCredential(key)) - - poller = form_training_client.begin_train_model(container_sas_url, use_training_labels=False) + poller = form_training_client.begin_training(container_sas_url, use_training_labels=False) model = poller.result() # Custom model information @@ -64,6 +63,7 @@ def train_model_without_labels(self): print("Document page count: {}".format(doc.page_count)) print("Document errors: {}".format(doc.errors)) + if __name__ == '__main__': sample = TrainModelWithoutLabelsSample() sample.train_model_without_labels() diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/setup.py b/sdk/formrecognizer/azure-ai-formrecognizer/setup.py index 7fde2ad11ac3..eb0854143789 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/setup.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/setup.py @@ -78,7 +78,7 @@ 'azure.ai', ]), install_requires=[ - "azure-core<2.0.0,>=1.4.0", + "azure-core<2.0.0,>=1.6.0", "msrest>=0.6.12", 'six>=1.6', ], diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_content.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_content.py index ca49e789ff15..a4473c0446ff 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_content.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_content.py @@ -4,6 +4,7 @@ # Licensed under the MIT License. # ------------------------------------ +import pytest from io import BytesIO from azure.core.exceptions import ServiceRequestError, ClientAuthenticationError, HttpResponseError from azure.core.credentials import AzureKeyCredential @@ -243,3 +244,18 @@ def callback(raw_response, _, headers): # Check form pages self.assertFormPagesTransformCorrect(layout, read_results, page_results) + + @GlobalFormRecognizerAccountPreparer() + @pytest.mark.live_test_only + def test_content_continuation_token(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): + client = FormRecognizerClient(form_recognizer_account, + AzureKeyCredential(form_recognizer_account_key)) + with open(self.form_jpg, "rb") as fd: + myfile = fd.read() + initial_poller = client.begin_recognize_content(myfile) + cont_token = initial_poller.continuation_token() + + poller = client.begin_recognize_content(myfile, continuation_token=cont_token) + result = poller.result() + self.assertIsNotNone(result) + initial_poller.wait() # necessary so azure-devtools doesn't throw assertion error diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_content_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_content_async.py index dfb0d8dcb463..0d75274f4d8c 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_content_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_content_async.py @@ -4,6 +4,7 @@ # Licensed under the MIT License. # ------------------------------------ +import pytest from io import BytesIO from azure.core.exceptions import ServiceRequestError, ClientAuthenticationError, HttpResponseError from azure.core.credentials import AzureKeyCredential @@ -23,30 +24,34 @@ async def test_content_bad_endpoint(self, resource_group, location, form_recogni myfile = fd.read() with self.assertRaises(ServiceRequestError): client = FormRecognizerClient("http://notreal.azure.com", AzureKeyCredential(form_recognizer_account_key)) - result = await client.recognize_content(myfile) + poller = await client.begin_recognize_content(myfile) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_content_authentication_successful_key(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) with open(self.invoice_pdf, "rb") as fd: myfile = fd.read() - result = await client.recognize_content(myfile) + poller = await client.begin_recognize_content(myfile) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_content_authentication_bad_key(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential("xxxx")) with self.assertRaises(ClientAuthenticationError): - result = await client.recognize_content(b"xxx", content_type="application/pdf") + poller = await client.begin_recognize_content(b"xxx", content_type="application/pdf") + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_passing_enum_content_type(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) with open(self.invoice_pdf, "rb") as fd: myfile = fd.read() - result = await client.recognize_content( + poller = await client.begin_recognize_content( myfile, content_type=FormContentType.application_pdf ) + result = await poller.result() self.assertIsNotNone(result) @GlobalFormRecognizerAccountPreparer() @@ -54,36 +59,40 @@ async def test_damaged_file_passed_as_bytes(self, resource_group, location, form client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) damaged_pdf = b"\x25\x50\x44\x46\x55\x55\x55" # still has correct bytes to be recognized as PDF with self.assertRaises(HttpResponseError): - poller = await client.recognize_content( + poller = await client.begin_recognize_content( damaged_pdf, ) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_damaged_file_bytes_fails_autodetect_content_type(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) damaged_pdf = b"\x50\x44\x46\x55\x55\x55" # doesn't match any magic file numbers with self.assertRaises(ValueError): - poller = await client.recognize_content( + poller = await client.begin_recognize_content( damaged_pdf, ) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_damaged_file_passed_as_bytes_io(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) damaged_pdf = BytesIO(b"\x25\x50\x44\x46\x55\x55\x55") # still has correct bytes to be recognized as PDF with self.assertRaises(HttpResponseError): - poller = await client.recognize_content( + poller = await client.begin_recognize_content( damaged_pdf, ) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_damaged_file_bytes_io_fails_autodetect(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) damaged_pdf = BytesIO(b"\x50\x44\x46\x55\x55\x55") # doesn't match any magic file numbers with self.assertRaises(ValueError): - poller = await client.recognize_content( + poller = await client.begin_recognize_content( damaged_pdf, ) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_blank_page(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -91,9 +100,10 @@ async def test_blank_page(self, resource_group, location, form_recognizer_accoun with open(self.blank_pdf, "rb") as fd: blank = fd.read() - result = await client.recognize_content( + poller = await client.begin_recognize_content( blank, ) + result = await poller.result() self.assertIsNotNone(result) @GlobalFormRecognizerAccountPreparer() @@ -102,17 +112,19 @@ async def test_passing_bad_content_type_param_passed(self, resource_group, locat with open(self.invoice_pdf, "rb") as fd: myfile = fd.read() with self.assertRaises(ValueError): - result = await client.recognize_content( + poller = await client.begin_recognize_content( myfile, content_type="application/jpeg" ) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_content_stream_passing_url(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) with self.assertRaises(TypeError): - result = await client.recognize_content("https://badurl.jpg", content_type="application/json") + poller = await client.begin_recognize_content("https://badurl.jpg", content_type="application/json") + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_auto_detect_unsupported_stream_content(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -122,9 +134,10 @@ async def test_auto_detect_unsupported_stream_content(self, resource_group, loca myfile = fd.read() with self.assertRaises(ValueError): - result = await client.recognize_content( + poller = await client.begin_recognize_content( myfile ) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_content_stream_transform_pdf(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -140,7 +153,8 @@ def callback(raw_response, _, headers): responses.append(analyze_result) responses.append(extracted_layout) - result = await client.recognize_content(myform, cls=callback) + poller = await client.begin_recognize_content(myform, cls=callback) + result = await poller.result() raw_response = responses[0] layout = responses[1] page_results = raw_response.analyze_result.page_results @@ -156,7 +170,8 @@ async def test_content_stream_pdf(self, resource_group, location, form_recognize with open(self.invoice_pdf, "rb") as fd: myform = fd.read() - result = await client.recognize_content(myform) + poller = await client.begin_recognize_content(myform) + result = await poller.result() self.assertEqual(len(result), 1) layout = result[0] self.assertEqual(layout.page_number, 1) @@ -179,7 +194,8 @@ def callback(raw_response, _, headers): responses.append(analyze_result) responses.append(extracted_layout) - result = await client.recognize_content(myform, cls=callback) + poller = await client.begin_recognize_content(myform, cls=callback) + result = await poller.result() raw_response = responses[0] layout = responses[1] page_results = raw_response.analyze_result.page_results @@ -195,7 +211,8 @@ async def test_content_stream_jpg(self, resource_group, location, form_recognize with open(self.form_jpg, "rb") as fd: myform = fd.read() - result = await client.recognize_content(myform) + poller = await client.begin_recognize_content(myform) + result = await poller.result() self.assertEqual(len(result), 1) layout = result[0] self.assertEqual(layout.page_number, 1) @@ -212,7 +229,8 @@ async def test_content_multipage(self, resource_group, location, form_recognizer client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) with open(self.multipage_invoice_pdf, "rb") as fd: invoice = fd.read() - result = await client.recognize_content(invoice) + poller = await client.begin_recognize_content(invoice) + result = await poller.result() self.assertEqual(len(result), 3) self.assertFormPagesHasValues(result) @@ -231,7 +249,8 @@ def callback(raw_response, _, headers): responses.append(analyze_result) responses.append(extracted_layout) - result = await client.recognize_content(myform, cls=callback) + poller = await client.begin_recognize_content(myform, cls=callback) + result = await poller.result() raw_response = responses[0] layout = responses[1] page_results = raw_response.analyze_result.page_results @@ -239,3 +258,18 @@ def callback(raw_response, _, headers): # Check form pages self.assertFormPagesTransformCorrect(layout, read_results, page_results) + + @GlobalFormRecognizerAccountPreparer() + @pytest.mark.live_test_only + async def test_content_continuation_token(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): + client = FormRecognizerClient(form_recognizer_account, + AzureKeyCredential(form_recognizer_account_key)) + with open(self.form_jpg, "rb") as fd: + myfile = fd.read() + initial_poller = await client.begin_recognize_content(myfile) + cont_token = initial_poller.continuation_token() + + poller = await client.begin_recognize_content(myfile, continuation_token=cont_token) + result = await poller.result() + self.assertIsNotNone(result) + await initial_poller.wait() # necessary so azure-devtools doesn't throw assertion error diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_content_from_url.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_content_from_url.py index c1ecc4f496ba..20d2f4530136 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_content_from_url.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_content_from_url.py @@ -4,6 +4,7 @@ # Licensed under the MIT License. # ------------------------------------ +import pytest from azure.core.exceptions import HttpResponseError, ServiceRequestError, ClientAuthenticationError from azure.core.credentials import AzureKeyCredential from azure.ai.formrecognizer._generated.models import AnalyzeOperationResult @@ -152,3 +153,16 @@ def callback(raw_response, _, headers): # Check form pages self.assertFormPagesTransformCorrect(layout, read_results, page_results) + + @GlobalFormRecognizerAccountPreparer() + @pytest.mark.live_test_only + def test_content_continuation_token(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): + client = FormRecognizerClient(form_recognizer_account, + AzureKeyCredential(form_recognizer_account_key)) + initial_poller = client.begin_recognize_content_from_url(self.form_url_jpg) + cont_token = initial_poller.continuation_token() + + poller = client.begin_recognize_content_from_url(self.form_url_jpg, continuation_token=cont_token) + result = poller.result() + self.assertIsNotNone(result) + initial_poller.wait() # necessary so azure-devtools doesn't throw assertion error \ No newline at end of file diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_content_from_url_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_content_from_url_async.py index 7f4263dd312f..5003a63387d8 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_content_from_url_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_content_from_url_async.py @@ -4,6 +4,7 @@ # Licensed under the MIT License. # ------------------------------------ +import pytest from azure.core.exceptions import HttpResponseError, ServiceRequestError, ClientAuthenticationError from azure.core.credentials import AzureKeyCredential from azure.ai.formrecognizer._generated.models import AnalyzeOperationResult @@ -19,25 +20,29 @@ class TestContentFromUrlAsync(AsyncFormRecognizerTest): async def test_content_url_bad_endpoint(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): with self.assertRaises(ServiceRequestError): client = FormRecognizerClient("http://notreal.azure.com", AzureKeyCredential(form_recognizer_account_key)) - result = await client.recognize_content_from_url(self.invoice_url_pdf) + poller = await client.begin_recognize_content_from_url(self.invoice_url_pdf) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_content_url_auth_successful_key(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) - result = await client.recognize_content_from_url(self.invoice_url_pdf) + poller = await client.begin_recognize_content_from_url(self.invoice_url_pdf) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_content_url_auth_bad_key(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential("xxxx")) with self.assertRaises(ClientAuthenticationError): - result = await client.recognize_content_from_url(self.invoice_url_pdf) + poller = await client.begin_recognize_content_from_url(self.invoice_url_pdf) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_content_bad_url(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) with self.assertRaises(HttpResponseError): - result = await client.recognize_content_from_url("https://badurl.jpg") + poller = await client.begin_recognize_content_from_url("https://badurl.jpg") + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_content_url_pass_stream(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -46,7 +51,8 @@ async def test_content_url_pass_stream(self, resource_group, location, form_reco receipt = fd.read(4) # makes the recording smaller with self.assertRaises(HttpResponseError): - result = await client.recognize_content_from_url(receipt) + poller = await client.begin_recognize_content_from_url(receipt) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_content_url_transform_pdf(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -60,7 +66,8 @@ def callback(raw_response, _, headers): responses.append(analyze_result) responses.append(extracted_layout) - result = await client.recognize_content_from_url(self.invoice_url_pdf, cls=callback) + poller = await client.begin_recognize_content_from_url(self.invoice_url_pdf, cls=callback) + result = await poller.result() raw_response = responses[0] layout = responses[1] page_results = raw_response.analyze_result.page_results @@ -74,7 +81,8 @@ async def test_content_url_pdf(self, resource_group, location, form_recognizer_a client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) - result = await client.recognize_content_from_url(self.invoice_url_pdf) + poller = await client.begin_recognize_content_from_url(self.invoice_url_pdf) + result = await poller.result() self.assertEqual(len(result), 1) layout = result[0] self.assertEqual(layout.page_number, 1) @@ -95,7 +103,8 @@ def callback(raw_response, _, headers): responses.append(analyze_result) responses.append(extracted_layout) - result = await client.recognize_content_from_url(self.form_url_jpg, cls=callback) + poller = await client.begin_recognize_content_from_url(self.form_url_jpg, cls=callback) + result = await poller.result() raw_response = responses[0] layout = responses[1] page_results = raw_response.analyze_result.page_results @@ -109,7 +118,8 @@ async def test_content_url_jpg(self, resource_group, location, form_recognizer_a client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) - result = await client.recognize_content_from_url(self.form_url_jpg) + poller = await client.begin_recognize_content_from_url(self.form_url_jpg) + result = await poller.result() self.assertEqual(len(result), 1) layout = result[0] self.assertEqual(layout.page_number, 1) @@ -124,8 +134,8 @@ async def test_content_url_jpg(self, resource_group, location, form_recognizer_a @GlobalFormRecognizerAccountPreparer() async def test_content_multipage_url(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) - result = await client.recognize_content_from_url(self.multipage_url_pdf) - + poller = await client.begin_recognize_content_from_url(self.multipage_url_pdf) + result = await poller.result() self.assertEqual(len(result), 3) self.assertFormPagesHasValues(result) @@ -140,7 +150,8 @@ def callback(raw_response, _, headers): responses.append(analyze_result) responses.append(extracted_layout) - result = await client.recognize_content_from_url(self.multipage_url_pdf, cls=callback) + poller = await client.begin_recognize_content_from_url(self.multipage_url_pdf, cls=callback) + result = await poller.result() raw_response = responses[0] layout = responses[1] page_results = raw_response.analyze_result.page_results @@ -148,3 +159,17 @@ def callback(raw_response, _, headers): # Check form pages self.assertFormPagesTransformCorrect(layout, read_results, page_results) + + @GlobalFormRecognizerAccountPreparer() + @pytest.mark.live_test_only + async def test_content_continuation_token(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): + client = FormRecognizerClient(form_recognizer_account, + AzureKeyCredential(form_recognizer_account_key)) + initial_poller = await client.begin_recognize_content_from_url(self.form_url_jpg) + cont_token = initial_poller.continuation_token() + + poller = await client.begin_recognize_content_from_url(self.form_url_jpg, continuation_token=cont_token) + result = await poller.result() + self.assertIsNotNone(result) + await initial_poller.wait() # necessary so azure-devtools doesn't throw assertion error + diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model.py index c486ae3091ab..b5e2cedf9e38 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model.py @@ -4,6 +4,7 @@ # Licensed under the MIT License. # ------------------------------------ +import pytest import functools from azure.core.exceptions import HttpResponseError from azure.ai.formrecognizer._generated.models import CopyOperationResult @@ -33,7 +34,7 @@ def test_copy_model_empty_model_id(self, client, container_sas_url): @GlobalTrainingAccountPreparer(copy=True) def test_copy_model_successful(self, client, container_sas_url, location, resource_id): - poller = client.begin_train_model(container_sas_url, use_training_labels=False) + poller = client.begin_training(container_sas_url, use_training_labels=False) model = poller.result() target = client.get_copy_authorization(resource_region=location, resource_id=resource_id) @@ -54,7 +55,7 @@ def test_copy_model_successful(self, client, container_sas_url, location, resour @GlobalTrainingAccountPreparer(copy=True) def test_copy_model_fail(self, client, container_sas_url, location, resource_id): - poller = client.begin_train_model(container_sas_url, use_training_labels=False) + poller = client.begin_training(container_sas_url, use_training_labels=False) model = poller.result() # give an incorrect region @@ -68,7 +69,7 @@ def test_copy_model_fail(self, client, container_sas_url, location, resource_id) @GlobalTrainingAccountPreparer(copy=True) def test_copy_model_transform(self, client, container_sas_url, location, resource_id): - poller = client.begin_train_model(container_sas_url, use_training_labels=False) + poller = client.begin_training(container_sas_url, use_training_labels=False) model = poller.result() target = client.get_copy_authorization(resource_region=location, resource_id=resource_id) @@ -102,3 +103,23 @@ def test_copy_authorization(self, client, container_sas_url, location, resource_ self.assertIsNotNone(target["expirationDateTimeTicks"]) self.assertEqual(target["resourceRegion"], "eastus") self.assertEqual(target["resourceId"], resource_id) + + @GlobalFormRecognizerAccountPreparer() + @GlobalTrainingAccountPreparer(copy=True) + @pytest.mark.live_test_only + def test_copy_continuation_token(self, client, container_sas_url, location, resource_id): + + poller = client.begin_training(container_sas_url, use_training_labels=False) + model = poller.result() + + target = client.get_copy_authorization(resource_region=location, resource_id=resource_id) + initial_poller = client.begin_copy_model(model.model_id, target=target) + cont_token = initial_poller.continuation_token() + + poller = client.begin_copy_model(model.model_id, target=target, continuation_token=cont_token) + result = poller.result() + self.assertIsNotNone(result) + + copied_model = client.get_custom_model(result.model_id) + self.assertIsNotNone(copied_model) + initial_poller.wait() # necessary so azure-devtools doesn't throw assertion error diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model_async.py index 912712233b63..e9c12e069677 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_copy_model_async.py @@ -4,6 +4,7 @@ # Licensed under the MIT License. # ------------------------------------ +import pytest import functools from azure.core.exceptions import HttpResponseError from azure.ai.formrecognizer._generated.models import CopyOperationResult @@ -22,23 +23,25 @@ class TestCopyModelAsync(AsyncFormRecognizerTest): @GlobalTrainingAccountPreparer() async def test_copy_model_none_model_id(self, client, container_sas_url): with self.assertRaises(ValueError): - await client.copy_model(model_id=None, target={}) + await client.begin_copy_model(model_id=None, target={}) @GlobalFormRecognizerAccountPreparer() @GlobalTrainingAccountPreparer() async def test_copy_model_empty_model_id(self, client, container_sas_url): with self.assertRaises(ValueError): - await client.copy_model(model_id="", target={}) + await client.begin_copy_model(model_id="", target={}) @GlobalFormRecognizerAccountPreparer() @GlobalTrainingAccountPreparer(copy=True) async def test_copy_model_successful(self, client, container_sas_url, location, resource_id): - model = await client.train_model(container_sas_url, use_training_labels=False) + training_poller = await client.begin_training(container_sas_url, use_training_labels=False) + model = await training_poller.result() target = await client.get_copy_authorization(resource_region=location, resource_id=resource_id) - copy = await client.copy_model(model.model_id, target=target) + copy_poller = await client.begin_copy_model(model.model_id, target=target) + copy = await copy_poller.result() copied_model = await client.get_custom_model(copy.model_id) @@ -53,19 +56,22 @@ async def test_copy_model_successful(self, client, container_sas_url, location, @GlobalTrainingAccountPreparer(copy=True) async def test_copy_model_fail(self, client, container_sas_url, location, resource_id): - model = await client.train_model(container_sas_url, use_training_labels=False) + training_poller = await client.begin_training(container_sas_url, use_training_labels=False) + model = await training_poller.result() # give an incorrect region target = await client.get_copy_authorization(resource_region="eastus", resource_id=resource_id) with self.assertRaises(HttpResponseError): - copy = await client.copy_model(model.model_id, target=target) + poller = await client.begin_copy_model(model.model_id, target=target) + copy = await poller.result() @GlobalFormRecognizerAccountPreparer() @GlobalTrainingAccountPreparer(copy=True) async def test_copy_model_transform(self, client, container_sas_url, location, resource_id): - model = await client.train_model(container_sas_url, use_training_labels=False) + training_poller = await client.begin_training(container_sas_url, use_training_labels=False) + model = await training_poller.result() target = await client.get_copy_authorization(resource_region=location, resource_id=resource_id) @@ -77,7 +83,8 @@ def callback(response, _, headers): raw_response.append(copy_result) raw_response.append(model_info) - copy = await client.copy_model(model.model_id, target=target, cls=callback) + poller = await client.begin_copy_model(model.model_id, target=target, cls=callback) + copy = await poller.result() actual = raw_response[0] copy = raw_response[1] @@ -97,3 +104,23 @@ async def test_copy_authorization(self, client, container_sas_url, location, res self.assertIsNotNone(target["expirationDateTimeTicks"]) self.assertEqual(target["resourceRegion"], "eastus") self.assertEqual(target["resourceId"], resource_id) + + @GlobalFormRecognizerAccountPreparer() + @GlobalTrainingAccountPreparer(copy=True) + @pytest.mark.live_test_only + async def test_copy_continuation_token(self, client, container_sas_url, location, resource_id): + + poller = await client.begin_training(container_sas_url, use_training_labels=False) + model = await poller.result() + + target = await client.get_copy_authorization(resource_region=location, resource_id=resource_id) + + initial_poller = await client.begin_copy_model(model.model_id, target=target) + cont_token = initial_poller.continuation_token() + poller = await client.begin_copy_model(model.model_id, target=target, continuation_token=cont_token) + result = await poller.result() + self.assertIsNotNone(result) + + copied_model = await client.get_custom_model(result.model_id) + self.assertIsNotNone(copied_model) + await initial_poller.wait() # necessary so azure-devtools doesn't throw assertion error diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms.py index ff24a677056d..8af45e30c197 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms.py @@ -4,6 +4,7 @@ # Licensed under the MIT License. # ------------------------------------ +import pytest import functools from azure.core.credentials import AzureKeyCredential from azure.core.exceptions import ServiceRequestError, ClientAuthenticationError, HttpResponseError @@ -70,7 +71,7 @@ def test_auto_detect_unsupported_stream_content(self, resource_group, location, def test_custom_form_damaged_file(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - poller = client.begin_train_model(container_sas_url, use_training_labels=False) + poller = client.begin_training(container_sas_url, use_training_labels=False) model = poller.result() with self.assertRaises(HttpResponseError): @@ -85,7 +86,7 @@ def test_custom_form_damaged_file(self, client, container_sas_url): def test_custom_form_unlabeled(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - poller = client.begin_train_model(container_sas_url, use_training_labels=False) + poller = client.begin_training(container_sas_url, use_training_labels=False) model = poller.result() with open(self.form_jpg, "rb") as stream: @@ -110,7 +111,7 @@ def test_custom_form_unlabeled(self, client, container_sas_url): def test_custom_form_multipage_unlabeled(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - poller = client.begin_train_model(container_sas_url, use_training_labels=False) + poller = client.begin_training(container_sas_url, use_training_labels=False) model = poller.result() with open(self.multipage_invoice_pdf, "rb") as stream: @@ -136,7 +137,7 @@ def test_custom_form_multipage_unlabeled(self, client, container_sas_url): def test_custom_form_labeled(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - poller = client.begin_train_model( + poller = client.begin_training( container_sas_url, use_training_labels=True ) @@ -161,7 +162,7 @@ def test_custom_form_labeled(self, client, container_sas_url): def test_custom_form_multipage_labeled(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - poller = client.begin_train_model( + poller = client.begin_training( container_sas_url, use_training_labels=True ) @@ -191,7 +192,7 @@ def test_custom_form_multipage_labeled(self, client, container_sas_url): def test_custom_form_unlabeled_transform(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - poller = client.begin_train_model(container_sas_url, use_training_labels=False) + poller = client.begin_training(container_sas_url, use_training_labels=False) model = poller.result() responses = [] @@ -228,7 +229,7 @@ def callback(raw_response, _, headers): def test_custom_form_multipage_unlabeled_transform(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - poller = client.begin_train_model(container_sas_url, use_training_labels=False) + poller = client.begin_training(container_sas_url, use_training_labels=False) model = poller.result() responses = [] @@ -266,7 +267,7 @@ def callback(raw_response, _, headers): def test_custom_form_labeled_transform(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - poller = client.begin_train_model(container_sas_url, use_training_labels=True) + poller = client.begin_training(container_sas_url, use_training_labels=True) model = poller.result() responses = [] @@ -303,7 +304,7 @@ def callback(raw_response, _, headers): def test_custom_form_multipage_labeled_transform(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - poller = client.begin_train_model(container_sas_url, use_training_labels=True) + poller = client.begin_training(container_sas_url, use_training_labels=True) model = poller.result() responses = [] @@ -336,3 +337,28 @@ def callback(raw_response, _, headers): self.assertEqual(form.page_range.last_page_number, actual.page_range[1]) self.assertEqual(form.form_type, "form-"+model.model_id) self.assertLabeledFormFieldDictTransformCorrect(form.fields, actual.fields, read_results) + + @GlobalFormRecognizerAccountPreparer() + @GlobalTrainingAccountPreparer() + @pytest.mark.live_test_only + def test_custom_form_continuation_token(self, client, container_sas_url): + fr_client = client.get_form_recognizer_client() + + poller = client.begin_training(container_sas_url, use_training_labels=False) + model = poller.result() + + with open(self.form_jpg, "rb") as fd: + myfile = fd.read() + initial_poller = fr_client.begin_recognize_custom_forms( + model.model_id, + myfile + ) + cont_token = initial_poller.continuation_token() + poller = fr_client.begin_recognize_custom_forms( + model.model_id, + myfile, + continuation_token=cont_token + ) + result = poller.result() + self.assertIsNotNone(result) + initial_poller.wait() # necessary so azure-devtools doesn't throw assertion error diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms_async.py index 41de5f298b13..5987e72b254a 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms_async.py @@ -4,6 +4,7 @@ # Licensed under the MIT License. # ------------------------------------ +import pytest import functools from azure.core.credentials import AzureKeyCredential from azure.core.exceptions import ServiceRequestError, ClientAuthenticationError, HttpResponseError @@ -25,13 +26,13 @@ class TestCustomFormsAsync(AsyncFormRecognizerTest): async def test_custom_form_none_model_id(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) with self.assertRaises(ValueError): - await client.recognize_custom_forms(model_id=None, form=b"xx") + await client.begin_recognize_custom_forms(model_id=None, form=b"xx") @GlobalFormRecognizerAccountPreparer() async def test_custom_form_empty_model_id(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) with self.assertRaises(ValueError): - await client.recognize_custom_forms(model_id="", form=b"xx") + await client.begin_recognize_custom_forms(model_id="", form=b"xx") @GlobalFormRecognizerAccountPreparer() async def test_custom_form_bad_endpoint(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -39,20 +40,23 @@ async def test_custom_form_bad_endpoint(self, resource_group, location, form_rec myfile = fd.read() with self.assertRaises(ServiceRequestError): client = FormRecognizerClient("http://notreal.azure.com", AzureKeyCredential(form_recognizer_account_key)) - result = await client.recognize_custom_forms(model_id="xx", form=myfile) + poller = await client.begin_recognize_custom_forms(model_id="xx", form=myfile) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_authentication_bad_key(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential("xxxx")) with self.assertRaises(ClientAuthenticationError): - result = await client.recognize_custom_forms(model_id="xx", form=b"xx", content_type="image/jpeg") + poller = await client.begin_recognize_custom_forms(model_id="xx", form=b"xx", content_type="image/jpeg") + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_passing_unsupported_url_content_type(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) with self.assertRaises(TypeError): - result = await client.recognize_custom_forms(model_id="xx", form="https://badurl.jpg", content_type="application/json") + poller = await client.begin_recognize_custom_forms(model_id="xx", form="https://badurl.jpg", content_type="application/json") + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_auto_detect_unsupported_stream_content(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -62,36 +66,40 @@ async def test_auto_detect_unsupported_stream_content(self, resource_group, loca myfile = fd.read() with self.assertRaises(ValueError): - poller = await client.recognize_custom_forms( + poller = await client.begin_recognize_custom_forms( model_id="xxx", form=myfile, ) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() @GlobalTrainingAccountPreparer() async def test_custom_form_damaged_file(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - model = await client.train_model(container_sas_url, use_training_labels=False) + training_poller = await client.begin_training(container_sas_url, use_training_labels=False) + model = await training_poller.result() with self.assertRaises(HttpResponseError): - form = await fr_client.recognize_custom_forms( + poller = await fr_client.begin_recognize_custom_forms( model.model_id, b"\x25\x50\x44\x46\x55\x55\x55", ) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() @GlobalTrainingAccountPreparer() async def test_custom_form_unlabeled(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - model = await client.train_model(container_sas_url, use_training_labels=False) + training_poller = await client.begin_training(container_sas_url, use_training_labels=False) + model = await training_poller.result() with open(self.form_jpg, "rb") as fd: myfile = fd.read() - form = await fr_client.recognize_custom_forms(model.model_id, myfile, content_type=FormContentType.image_jpeg) - + poller = await fr_client.begin_recognize_custom_forms(model.model_id, myfile, content_type=FormContentType.image_jpeg) + form = await poller.result() self.assertEqual(form[0].form_type, "form-0") self.assertFormPagesHasValues(form[0].pages) for label, field in form[0].fields.items(): @@ -106,15 +114,18 @@ async def test_custom_form_unlabeled(self, client, container_sas_url): async def test_custom_form_multipage_unlabeled(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - model = await client.train_model(container_sas_url, use_training_labels=False) + training_poller = await client.begin_training(container_sas_url, use_training_labels=False) + model = await training_poller.result() with open(self.multipage_invoice_pdf, "rb") as fd: myfile = fd.read() - forms = await fr_client.recognize_custom_forms( + + poller = await fr_client.begin_recognize_custom_forms( model.model_id, myfile, content_type=FormContentType.application_pdf ) + forms = await poller.result() for form in forms: self.assertEqual(form.form_type, "form-0") @@ -131,12 +142,14 @@ async def test_custom_form_multipage_unlabeled(self, client, container_sas_url): async def test_custom_form_labeled(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - model = await client.train_model(container_sas_url, use_training_labels=True) + training_poller = await client.begin_training(container_sas_url, use_training_labels=True) + model = await training_poller.result() with open(self.form_jpg, "rb") as fd: myfile = fd.read() - form = await fr_client.recognize_custom_forms(model.model_id, myfile, content_type=FormContentType.image_jpeg) + poller = await fr_client.begin_recognize_custom_forms(model.model_id, myfile, content_type=FormContentType.image_jpeg) + form = await poller.result() self.assertEqual(form[0].form_type, "form-"+model.model_id) self.assertFormPagesHasValues(form[0].pages) @@ -151,19 +164,21 @@ async def test_custom_form_labeled(self, client, container_sas_url): async def test_custom_form_multipage_labeled(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - model = await client.train_model( + training_poller = await client.begin_training( container_sas_url, use_training_labels=True ) + model = await training_poller.result() with open(self.multipage_invoice_pdf, "rb") as fd: myfile = fd.read() - forms = await fr_client.recognize_custom_forms( + poller = await fr_client.begin_recognize_custom_forms( model.model_id, myfile, content_type=FormContentType.application_pdf ) + forms = await poller.result() for form in forms: self.assertEqual(form.form_type, "form-"+model.model_id) @@ -180,7 +195,8 @@ async def test_custom_form_multipage_labeled(self, client, container_sas_url): async def test_form_unlabeled_transform(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - model = await client.train_model(container_sas_url, use_training_labels=False) + training_poller = await client.begin_training(container_sas_url, use_training_labels=False) + model = await training_poller.result() responses = [] @@ -193,12 +209,13 @@ def callback(raw_response, _, headers): with open(self.form_jpg, "rb") as fd: myfile = fd.read() - form = await fr_client.recognize_custom_forms( + poller = await fr_client.begin_recognize_custom_forms( model.model_id, myfile, include_text_content=True, cls=callback ) + form = await poller.result() actual = responses[0] recognized_form = responses[1] @@ -216,7 +233,8 @@ def callback(raw_response, _, headers): async def test_custom_forms_multipage_unlabeled_transform(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - model = await client.train_model(container_sas_url, use_training_labels=False) + training_poller = await client.begin_training(container_sas_url, use_training_labels=False) + model = await training_poller.result() responses = [] @@ -229,12 +247,13 @@ def callback(raw_response, _, headers): with open(self.multipage_invoice_pdf, "rb") as fd: myfile = fd.read() - form = await fr_client.recognize_custom_forms( + poller = await fr_client.begin_recognize_custom_forms( model.model_id, myfile, include_text_content=True, cls=callback ) + form = await poller.result() actual = responses[0] recognized_form = responses[1] read_results = actual.analyze_result.read_results @@ -254,7 +273,8 @@ def callback(raw_response, _, headers): async def test_form_labeled_transform(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - model = await client.train_model(container_sas_url, use_training_labels=True) + training_polling = await client.begin_training(container_sas_url, use_training_labels=True) + model = await training_polling.result() responses = [] @@ -267,12 +287,13 @@ def callback(raw_response, _, headers): with open(self.form_jpg, "rb") as fd: myfile = fd.read() - form = await fr_client.recognize_custom_forms( + poller = await fr_client.begin_recognize_custom_forms( model.model_id, myfile, include_text_content=True, cls=callback ) + form = await poller.result() actual = responses[0] recognized_form = responses[1] @@ -290,7 +311,8 @@ def callback(raw_response, _, headers): async def test_custom_forms_multipage_labeled_transform(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - model = await client.train_model(container_sas_url, use_training_labels=True) + training_poller = await client.begin_training(container_sas_url, use_training_labels=True) + model = await training_poller.result() responses = [] @@ -303,12 +325,14 @@ def callback(raw_response, _, headers): with open(self.multipage_invoice_pdf, "rb") as fd: myfile = fd.read() - form = await fr_client.recognize_custom_forms( + poller = await fr_client.begin_recognize_custom_forms( model.model_id, myfile, include_text_content=True, cls=callback ) + form = await poller.result() + actual = responses[0] recognized_form = responses[1] read_results = actual.analyze_result.read_results @@ -321,3 +345,29 @@ def callback(raw_response, _, headers): self.assertEqual(form.page_range.last_page_number, actual.page_range[1]) self.assertEqual(form.form_type, "form-"+model.model_id) self.assertLabeledFormFieldDictTransformCorrect(form.fields, actual.fields, read_results) + + @GlobalFormRecognizerAccountPreparer() + @GlobalTrainingAccountPreparer() + @pytest.mark.live_test_only + async def test_custom_form_continuation_token(self, client, container_sas_url): + fr_client = client.get_form_recognizer_client() + + poller = await client.begin_training(container_sas_url, use_training_labels=False) + model = await poller.result() + + with open(self.form_jpg, "rb") as fd: + myfile = fd.read() + initial_poller = await fr_client.begin_recognize_custom_forms( + model.model_id, + myfile + ) + + cont_token = initial_poller.continuation_token() + poller = await fr_client.begin_recognize_custom_forms( + model.model_id, + myfile, + continuation_token=cont_token + ) + result = await poller.result() + self.assertIsNotNone(result) + await initial_poller.wait() # necessary so azure-devtools doesn't throw assertion error diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms_from_url.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms_from_url.py index 1f4ae6f7c579..64bb51301377 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms_from_url.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms_from_url.py @@ -4,6 +4,7 @@ # Licensed under the MIT License. # ------------------------------------ +import pytest import functools from azure.core.credentials import AzureKeyCredential from azure.core.exceptions import HttpResponseError, ServiceRequestError, ClientAuthenticationError @@ -66,7 +67,7 @@ def test_pass_stream_into_url(self, resource_group, location, form_recognizer_ac def test_custom_form_bad_url(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - poller = client.begin_train_model(container_sas_url, use_training_labels=True) + poller = client.begin_training(container_sas_url, use_training_labels=True) model = poller.result() with self.assertRaises(HttpResponseError): @@ -81,7 +82,7 @@ def test_custom_form_bad_url(self, client, container_sas_url): def test_custom_form_unlabeled(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - poller = client.begin_train_model(container_sas_url, use_training_labels=False) + poller = client.begin_training(container_sas_url, use_training_labels=False) model = poller.result() poller = fr_client.begin_recognize_custom_forms_from_url(model.model_id, self.form_url_jpg) @@ -101,7 +102,7 @@ def test_custom_form_unlabeled(self, client, container_sas_url): def test_form_multipage_unlabeled(self, client, container_sas_url, blob_sas_url): fr_client = client.get_form_recognizer_client() - poller = client.begin_train_model(container_sas_url, use_training_labels=False) + poller = client.begin_training(container_sas_url, use_training_labels=False) model = poller.result() poller = fr_client.begin_recognize_custom_forms_from_url( @@ -125,7 +126,7 @@ def test_form_multipage_unlabeled(self, client, container_sas_url, blob_sas_url) def test_custom_form_labeled(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - poller = client.begin_train_model(container_sas_url, use_training_labels=True) + poller = client.begin_training(container_sas_url, use_training_labels=True) model = poller.result() poller = fr_client.begin_recognize_custom_forms_from_url(model.model_id, self.form_url_jpg) @@ -144,7 +145,7 @@ def test_custom_form_labeled(self, client, container_sas_url): def test_form_multipage_labeled(self, client, container_sas_url, blob_sas_url): fr_client = client.get_form_recognizer_client() - poller = client.begin_train_model( + poller = client.begin_training( container_sas_url, use_training_labels=True ) @@ -171,7 +172,7 @@ def test_form_multipage_labeled(self, client, container_sas_url, blob_sas_url): def test_custom_form_unlabeled_transform(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - poller = client.begin_train_model(container_sas_url, use_training_labels=False) + poller = client.begin_training(container_sas_url, use_training_labels=False) model = poller.result() responses = [] @@ -205,7 +206,7 @@ def callback(raw_response, _, headers): def test_custom_form_multipage_unlabeled_transform(self, client, container_sas_url, blob_sas_url): fr_client = client.get_form_recognizer_client() - poller = client.begin_train_model(container_sas_url, use_training_labels=False) + poller = client.begin_training(container_sas_url, use_training_labels=False) model = poller.result() responses = [] @@ -241,7 +242,7 @@ def callback(raw_response, _, headers): def test_form_labeled_transform(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - poller = client.begin_train_model(container_sas_url, use_training_labels=True) + poller = client.begin_training(container_sas_url, use_training_labels=True) model = poller.result() responses = [] @@ -275,7 +276,7 @@ def callback(raw_response, _, headers): def test_custom_form_multipage_labeled_transform(self, client, container_sas_url, blob_sas_url): fr_client = client.get_form_recognizer_client() - poller = client.begin_train_model(container_sas_url, use_training_labels=True) + poller = client.begin_training(container_sas_url, use_training_labels=True) model = poller.result() responses = [] @@ -305,3 +306,27 @@ def callback(raw_response, _, headers): self.assertEqual(form.page_range.last_page_number, actual.page_range[1]) self.assertEqual(form.form_type, "form-"+model.model_id) self.assertLabeledFormFieldDictTransformCorrect(form.fields, actual.fields, read_results) + + @GlobalFormRecognizerAccountPreparer() + @GlobalTrainingAccountPreparer() + @pytest.mark.live_test_only + def test_custom_form_continuation_token(self, client, container_sas_url): + fr_client = client.get_form_recognizer_client() + + training_poller = client.begin_training(container_sas_url, use_training_labels=False) + model = training_poller.result() + + initial_poller = fr_client.begin_recognize_custom_forms_from_url( + model.model_id, + self.form_url_jpg + ) + + cont_token = initial_poller.continuation_token() + poller = fr_client.begin_recognize_custom_forms_from_url( + model.model_id, + self.form_url_jpg, + continuation_token=cont_token + ) + result = poller.result() + self.assertIsNotNone(result) + initial_poller.wait() # necessary so azure-devtools doesn't throw assertion error diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms_from_url_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms_from_url_async.py index c9cb60da7656..92fc73345c89 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms_from_url_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_custom_forms_from_url_async.py @@ -4,6 +4,7 @@ # Licensed under the MIT License. # ------------------------------------ +import pytest import functools from azure.core.credentials import AzureKeyCredential from azure.core.exceptions import HttpResponseError, ServiceRequestError, ClientAuthenticationError @@ -23,32 +24,35 @@ class TestCustomFormsFromUrlAsync(AsyncFormRecognizerTest): async def test_custom_form_none_model_id(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) with self.assertRaises(ValueError): - await client.recognize_custom_forms_from_url(model_id=None, form_url="https://badurl.jpg") + await client.begin_recognize_custom_forms_from_url(model_id=None, form_url="https://badurl.jpg") @GlobalFormRecognizerAccountPreparer() async def test_custom_form_empty_model_id(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) with self.assertRaises(ValueError): - await client.recognize_custom_forms_from_url(model_id="", form_url="https://badurl.jpg") + await client.begin_recognize_custom_forms_from_url(model_id="", form_url="https://badurl.jpg") @GlobalFormRecognizerAccountPreparer() async def test_custom_form_url_bad_endpoint(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): with self.assertRaises(ServiceRequestError): client = FormRecognizerClient("http://notreal.azure.com", AzureKeyCredential(form_recognizer_account_key)) - result = await client.recognize_custom_forms_from_url(model_id="xx", form_url=self.form_url_jpg) + poller = await client.begin_recognize_custom_forms_from_url(model_id="xx", form_url=self.form_url_jpg) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_url_authentication_bad_key(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential("xxxx")) with self.assertRaises(ClientAuthenticationError): - result = await client.recognize_custom_forms_from_url(model_id="xx", form_url=self.form_url_jpg) + poller = await client.begin_recognize_custom_forms_from_url(model_id="xx", form_url=self.form_url_jpg) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_passing_bad_url(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) with self.assertRaises(HttpResponseError): - result = await client.recognize_custom_forms_from_url(model_id="xx", form_url="https://badurl.jpg") + poller = await client.begin_recognize_custom_forms_from_url(model_id="xx", form_url="https://badurl.jpg") + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_pass_stream_into_url(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -56,32 +60,37 @@ async def test_pass_stream_into_url(self, resource_group, location, form_recogni with open(self.unsupported_content_py, "rb") as fd: with self.assertRaises(HttpResponseError): - result = await client.recognize_custom_forms_from_url( + poller = await client.begin_recognize_custom_forms_from_url( model_id="xxx", form_url=fd, ) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() @GlobalTrainingAccountPreparer() async def test_form_bad_url(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - model = await client.train_model(container_sas_url, use_training_labels=True) + training_poller = await client.begin_training(container_sas_url, use_training_labels=True) + model = await training_poller.result() with self.assertRaises(HttpResponseError): - form = await fr_client.recognize_custom_forms_from_url( + poller = await fr_client.begin_recognize_custom_forms_from_url( model.model_id, form_url="https://badurl.jpg" ) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() @GlobalTrainingAccountPreparer() async def test_form_unlabeled(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - model = await client.train_model(container_sas_url, use_training_labels=False) + training_poller = await client.begin_training(container_sas_url, use_training_labels=False) + model = await training_poller.result() - form = await fr_client.recognize_custom_forms_from_url(model.model_id, self.form_url_jpg) + poller = await fr_client.begin_recognize_custom_forms_from_url(model.model_id, self.form_url_jpg) + form = await poller.result() self.assertEqual(form[0].form_type, "form-0") self.assertFormPagesHasValues(form[0].pages) @@ -97,12 +106,14 @@ async def test_form_unlabeled(self, client, container_sas_url): async def test_custom_form_multipage_unlabeled(self, client, container_sas_url, blob_sas_url): fr_client = client.get_form_recognizer_client() - model = await client.train_model(container_sas_url, use_training_labels=False) + training_poller = await client.begin_training(container_sas_url, use_training_labels=False) + model = await training_poller.result() - forms = await fr_client.recognize_custom_forms_from_url( + poller = await fr_client.begin_recognize_custom_forms_from_url( model.model_id, blob_sas_url, ) + forms = await poller.result() for form in forms: self.assertEqual(form.form_type, "form-0") @@ -119,9 +130,11 @@ async def test_custom_form_multipage_unlabeled(self, client, container_sas_url, async def test_form_labeled(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - model = await client.train_model(container_sas_url, use_training_labels=True) + training_poller = await client.begin_training(container_sas_url, use_training_labels=True) + model = await training_poller.result() - form = await fr_client.recognize_custom_forms_from_url(model.model_id, self.form_url_jpg) + poller = await fr_client.begin_recognize_custom_forms_from_url(model.model_id, self.form_url_jpg) + form = await poller.result() self.assertEqual(form[0].form_type, "form-"+model.model_id) self.assertFormPagesHasValues(form[0].pages) @@ -136,15 +149,17 @@ async def test_form_labeled(self, client, container_sas_url): async def test_form_multipage_labeled(self, client, container_sas_url, blob_sas_url): fr_client = client.get_form_recognizer_client() - model = await client.train_model( + training_poller = await client.begin_training( container_sas_url, use_training_labels=True ) + model = await training_poller.result() - forms = await fr_client.recognize_custom_forms_from_url( + poller = await fr_client.begin_recognize_custom_forms_from_url( model.model_id, blob_sas_url ) + forms = await poller.result() for form in forms: self.assertEqual(form.form_type, "form-"+model.model_id) @@ -160,7 +175,8 @@ async def test_form_multipage_labeled(self, client, container_sas_url, blob_sas_ async def test_form_unlabeled_transform(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - model = await client.train_model(container_sas_url, use_training_labels=False) + training_poller = await client.begin_training(container_sas_url, use_training_labels=False) + model = await training_poller.result() responses = [] @@ -170,12 +186,13 @@ def callback(raw_response, _, headers): responses.append(analyze_result) responses.append(form) - form = await fr_client.recognize_custom_forms_from_url( + poller = await fr_client.begin_recognize_custom_forms_from_url( model.model_id, self.form_url_jpg, include_text_content=True, cls=callback ) + form = await poller.result() actual = responses[0] recognized_form = responses[1] @@ -193,7 +210,8 @@ def callback(raw_response, _, headers): async def test_multipage_unlabeled_transform(self, client, container_sas_url, blob_sas_url): fr_client = client.get_form_recognizer_client() - model = await client.train_model(container_sas_url, use_training_labels=False) + training_poller = await client.begin_training(container_sas_url, use_training_labels=False) + model = await training_poller.result() responses = [] @@ -203,12 +221,14 @@ def callback(raw_response, _, headers): responses.append(analyze_result) responses.append(form) - form = await fr_client.recognize_custom_forms_from_url( + poller = await fr_client.begin_recognize_custom_forms_from_url( model.model_id, blob_sas_url, include_text_content=True, cls=callback ) + + form = await poller.result() actual = responses[0] recognized_form = responses[1] read_results = actual.analyze_result.read_results @@ -226,7 +246,8 @@ def callback(raw_response, _, headers): async def test_form_labeled_transform(self, client, container_sas_url): fr_client = client.get_form_recognizer_client() - model = await client.train_model(container_sas_url, use_training_labels=True) + training_poller = await client.begin_training(container_sas_url, use_training_labels=True) + model = await training_poller.result() responses = [] @@ -236,12 +257,13 @@ def callback(raw_response, _, headers): responses.append(analyze_result) responses.append(form) - form = await fr_client.recognize_custom_forms_from_url( + poller = await fr_client.begin_recognize_custom_forms_from_url( model.model_id, self.form_url_jpg, include_text_content=True, cls=callback ) + form = await poller.result() actual = responses[0] recognized_form = responses[1] @@ -259,7 +281,8 @@ def callback(raw_response, _, headers): async def test_multipage_labeled_transform(self, client, container_sas_url, blob_sas_url): fr_client = client.get_form_recognizer_client() - model = await client.train_model(container_sas_url, use_training_labels=True) + training_poller = await client.begin_training(container_sas_url, use_training_labels=True) + model = await training_poller.result() responses = [] @@ -269,12 +292,13 @@ def callback(raw_response, _, headers): responses.append(analyze_result) responses.append(form) - form = await fr_client.recognize_custom_forms_from_url( + poller = await fr_client.begin_recognize_custom_forms_from_url( model.model_id, blob_sas_url, include_text_content=True, cls=callback ) + form = await poller.result() actual = responses[0] recognized_form = responses[1] @@ -288,3 +312,26 @@ def callback(raw_response, _, headers): self.assertEqual(form.page_range.last_page_number, actual.page_range[1]) self.assertEqual(form.form_type, "form-"+model.model_id) self.assertLabeledFormFieldDictTransformCorrect(form.fields, actual.fields, read_results) + + @GlobalFormRecognizerAccountPreparer() + @GlobalTrainingAccountPreparer() + @pytest.mark.live_test_only + async def test_custom_form_continuation_token(self, client, container_sas_url): + fr_client = client.get_form_recognizer_client() + + poller = await client.begin_training(container_sas_url, use_training_labels=False) + model = await poller.result() + + initial_poller = await fr_client.begin_recognize_custom_forms_from_url( + model.model_id, + self.form_url_jpg + ) + cont_token = initial_poller.continuation_token() + poller = await fr_client.begin_recognize_custom_forms_from_url( + model.model_id, + self.form_url_jpg, + continuation_token=cont_token + ) + result = await poller.result() + self.assertIsNotNone(result) + await initial_poller.wait() # necessary so azure-devtools doesn't throw assertion error diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_mgmt.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_mgmt.py index efaf90c6e49b..0de73c057d2d 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_mgmt.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_mgmt.py @@ -80,7 +80,7 @@ def test_account_properties(self, resource_group, location, form_recognizer_acco @GlobalTrainingAccountPreparer() def test_mgmt_model_labeled(self, client, container_sas_url): - poller = client.begin_train_model(container_sas_url, use_training_labels=True) + poller = client.begin_training(container_sas_url, use_training_labels=True) labeled_model_from_train = poller.result() labeled_model_from_get = client.get_custom_model(labeled_model_from_train.model_id) @@ -116,7 +116,7 @@ def test_mgmt_model_labeled(self, client, container_sas_url): @GlobalTrainingAccountPreparer() def test_mgmt_model_unlabeled(self, client, container_sas_url): - poller = client.begin_train_model(container_sas_url, use_training_labels=False) + poller = client.begin_training(container_sas_url, use_training_labels=False) unlabeled_model_from_train = poller.result() unlabeled_model_from_get = client.get_custom_model(unlabeled_model_from_train.model_id) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_mgmt_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_mgmt_async.py index f0b65db830f2..a8d9791d4bd3 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_mgmt_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_mgmt_async.py @@ -81,8 +81,8 @@ async def test_account_properties(self, resource_group, location, form_recognize @GlobalTrainingAccountPreparer() async def test_mgmt_model_labeled(self, client, container_sas_url): - labeled_model_from_train = await client.train_model(container_sas_url, use_training_labels=True) - + poller = await client.begin_training(container_sas_url, use_training_labels=True) + labeled_model_from_train = await poller.result() labeled_model_from_get = await client.get_custom_model(labeled_model_from_train.model_id) self.assertEqual(labeled_model_from_train.model_id, labeled_model_from_get.model_id) @@ -115,8 +115,8 @@ async def test_mgmt_model_labeled(self, client, container_sas_url): @GlobalFormRecognizerAccountPreparer() @GlobalTrainingAccountPreparer() async def test_mgmt_model_unlabeled(self, client, container_sas_url): - unlabeled_model_from_train = await client.train_model(container_sas_url, use_training_labels=False) - + poller = await client.begin_training(container_sas_url, use_training_labels=False) + unlabeled_model_from_train = await poller.result() unlabeled_model_from_get = await client.get_custom_model(unlabeled_model_from_train.model_id) self.assertEqual(unlabeled_model_from_train.model_id, unlabeled_model_from_get.model_id) @@ -155,6 +155,6 @@ async def test_get_form_recognizer_client(self, resource_group, location, form_r assert transport.session is not None async with ftc.get_form_recognizer_client() as frc: assert transport.session is not None - await frc.recognize_receipts_from_url(self.receipt_url_jpg) + await frc.begin_recognize_receipts_from_url(self.receipt_url_jpg) await ftc.get_account_properties() assert transport.session is not None diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt.py index c1296b292cbb..3814319cd13e 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt.py @@ -4,6 +4,7 @@ # Licensed under the MIT License. # ------------------------------------ +import pytest from io import BytesIO from datetime import date, time from azure.core.exceptions import ClientAuthenticationError, ServiceRequestError, HttpResponseError @@ -405,3 +406,18 @@ def callback(raw_response, _, headers): # Check form pages self.assertFormPagesTransformCorrect(returned_model, read_results) + + @GlobalFormRecognizerAccountPreparer() + @pytest.mark.live_test_only + def test_receipt_continuation_token(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): + client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) + + with open(self.receipt_jpg, "rb") as fd: + receipt = fd.read() + + initial_poller = client.begin_recognize_receipts(receipt) + cont_token = initial_poller.continuation_token() + poller = client.begin_recognize_receipts(receipt, continuation_token=cont_token) + result = poller.result() + self.assertIsNotNone(result) + initial_poller.wait() # necessary so azure-devtools doesn't throw assertion error diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_async.py index 3cfd22fc875d..79601625d9f4 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_async.py @@ -4,6 +4,7 @@ # Licensed under the MIT License. # ------------------------------------ +import pytest from io import BytesIO from datetime import date, time from azure.core.exceptions import ServiceRequestError, ClientAuthenticationError, HttpResponseError @@ -24,30 +25,34 @@ async def test_receipt_bad_endpoint(self, resource_group, location, form_recogni myfile = fd.read() with self.assertRaises(ServiceRequestError): client = FormRecognizerClient("http://notreal.azure.com", AzureKeyCredential(form_recognizer_account_key)) - result = await client.recognize_receipts(myfile) + poller = await client.begin_recognize_receipts(myfile) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_authentication_successful_key(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) with open(self.receipt_jpg, "rb") as fd: myfile = fd.read() - result = await client.recognize_receipts(myfile) + poller = await client.begin_recognize_receipts(myfile) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_authentication_bad_key(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential("xxxx")) with self.assertRaises(ClientAuthenticationError): - result = await client.recognize_receipts(b"xx", content_type="image/jpeg") + poller = await client.begin_recognize_receipts(b"xx", content_type="image/jpeg") + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_passing_enum_content_type(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) with open(self.receipt_png, "rb") as fd: myfile = fd.read() - result = await client.recognize_receipts( + poller = await client.begin_recognize_receipts( myfile, content_type=FormContentType.image_png ) + result = await poller.result() self.assertIsNotNone(result) @GlobalFormRecognizerAccountPreparer() @@ -55,36 +60,40 @@ async def test_damaged_file_passed_as_bytes(self, resource_group, location, form client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) damaged_pdf = b"\x25\x50\x44\x46\x55\x55\x55" # still has correct bytes to be recognized as PDF with self.assertRaises(HttpResponseError): - poller = await client.recognize_receipts( + poller = await client.begin_recognize_receipts( damaged_pdf, ) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_damaged_file_bytes_fails_autodetect_content_type(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) damaged_pdf = b"\x50\x44\x46\x55\x55\x55" # doesn't match any magic file numbers with self.assertRaises(ValueError): - poller = await client.recognize_receipts( + poller = await client.begin_recognize_receipts( damaged_pdf, ) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_damaged_file_passed_as_bytes_io(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) damaged_pdf = BytesIO(b"\x25\x50\x44\x46\x55\x55\x55") # still has correct bytes to be recognized as PDF with self.assertRaises(HttpResponseError): - poller = await client.recognize_receipts( + poller = await client.begin_recognize_receipts( damaged_pdf, ) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_damaged_file_bytes_io_fails_autodetect(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) damaged_pdf = BytesIO(b"\x50\x44\x46\x55\x55\x55") # doesn't match any magic file numbers with self.assertRaises(ValueError): - poller = await client.recognize_receipts( + poller = await client.begin_recognize_receipts( damaged_pdf, ) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_blank_page(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -92,9 +101,10 @@ async def test_blank_page(self, resource_group, location, form_recognizer_accoun with open(self.blank_pdf, "rb") as fd: blank = fd.read() - result = await client.recognize_receipts( + poller = await client.begin_recognize_receipts( blank, ) + result = await poller.result() self.assertIsNotNone(result) @GlobalFormRecognizerAccountPreparer() @@ -103,17 +113,19 @@ async def test_passing_bad_content_type_param_passed(self, resource_group, locat with open(self.receipt_jpg, "rb") as fd: myfile = fd.read() with self.assertRaises(ValueError): - result = await client.recognize_receipts( + poller = await client.begin_recognize_receipts( myfile, content_type="application/jpeg" ) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_passing_unsupported_url_content_type(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) with self.assertRaises(TypeError): - result = await client.recognize_receipts("https://badurl.jpg", content_type="application/json") + poller = await client.begin_recognize_receipts("https://badurl.jpg", content_type="application/json") + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_auto_detect_unsupported_stream_content(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -123,9 +135,10 @@ async def test_auto_detect_unsupported_stream_content(self, resource_group, loca myfile = fd.read() with self.assertRaises(ValueError): - result = await client.recognize_receipts( + poller = await client.begin_recognize_receipts( myfile, ) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_receipt_stream_transform_png(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -142,11 +155,12 @@ def callback(raw_response, _, headers): with open(self.receipt_png, "rb") as fd: myfile = fd.read() - result = await client.recognize_receipts( + poller = await client.begin_recognize_receipts( receipt=myfile, include_text_content=True, cls=callback ) + result = await poller.result() raw_response = responses[0] returned_model = responses[1] @@ -196,11 +210,12 @@ def callback(raw_response, _, headers): with open(self.receipt_jpg, "rb") as fd: myfile = fd.read() - result = await client.recognize_receipts( + poller = await client.begin_recognize_receipts( receipt=myfile, include_text_content=True, cls=callback ) + result = await poller.result() raw_response = responses[0] returned_model = responses[1] @@ -243,7 +258,8 @@ async def test_receipt_jpg(self, resource_group, location, form_recognizer_accou with open(self.receipt_jpg, "rb") as fd: receipt = fd.read() - result = await client.recognize_receipts(receipt) + poller = await client.begin_recognize_receipts(receipt) + result = await poller.result() self.assertEqual(len(result), 1) receipt = result[0] @@ -271,7 +287,8 @@ async def test_receipt_png(self, resource_group, location, form_recognizer_accou with open(self.receipt_png, "rb") as fd: receipt = fd.read() - result = await client.recognize_receipts(receipt) + poller = await client.begin_recognize_receipts(receipt) + result = await poller.result() self.assertEqual(len(result), 1) receipt = result[0] self.assertEqual(receipt.fields.get("MerchantAddress").value, '123 Main Street Redmond, WA 98052') @@ -293,7 +310,8 @@ async def test_receipt_jpg_include_text_content(self, resource_group, location, client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) with open(self.receipt_jpg, "rb") as fd: receipt = fd.read() - result = await client.recognize_receipts(receipt, include_text_content=True) + poller = await client.begin_recognize_receipts(receipt, include_text_content=True) + result = await poller.result() self.assertEqual(len(result), 1) receipt = result[0] @@ -312,7 +330,8 @@ async def test_receipt_multipage(self, resource_group, location, form_recognizer client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) with open(self.multipage_invoice_pdf, "rb") as fd: receipt = fd.read() - result = await client.recognize_receipts(receipt, include_text_content=True) + poller = await client.begin_recognize_receipts(receipt, include_text_content=True) + result = await poller.result() self.assertEqual(len(result), 3) receipt = result[0] @@ -355,11 +374,12 @@ def callback(raw_response, _, headers): with open(self.multipage_invoice_pdf, "rb") as fd: myfile = fd.read() - result = await client.recognize_receipts( + poller = await client.begin_recognize_receipts( receipt=myfile, include_text_content=True, cls=callback ) + result = await poller.result() raw_response = responses[0] returned_model = responses[1] @@ -398,3 +418,18 @@ def callback(raw_response, _, headers): # Check form pages self.assertFormPagesTransformCorrect(returned_model, read_results) + + @GlobalFormRecognizerAccountPreparer() + @pytest.mark.live_test_only + async def test_receipt_continuation_token(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): + client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) + + with open(self.receipt_jpg, "rb") as fd: + receipt = fd.read() + + initial_poller = await client.begin_recognize_receipts(receipt) + cont_token = initial_poller.continuation_token() + poller = await client.begin_recognize_receipts(receipt, continuation_token=cont_token) + result = await poller.result() + self.assertIsNotNone(result) + await initial_poller.wait() # necessary so azure-devtools doesn't throw assertion error diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url.py index 2ab8315d9077..53504fb8fa19 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url.py @@ -321,3 +321,15 @@ def callback(raw_response, _, headers): # Check form pages self.assertFormPagesTransformCorrect(returned_model, read_results) + + @GlobalFormRecognizerAccountPreparer() + @pytest.mark.live_test_only + def test_receipt_continuation_token(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): + client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) + + initial_poller = client.begin_recognize_receipts_from_url(self.receipt_url_jpg) + cont_token = initial_poller.continuation_token() + poller = client.begin_recognize_receipts_from_url(self.receipt_url_jpg, continuation_token=cont_token) + result = poller.result() + self.assertIsNotNone(result) + initial_poller.wait() # necessary so azure-devtools doesn't throw assertion error diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url_async.py index d3981db07f21..24eb6cd79746 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_receipt_from_url_async.py @@ -23,40 +23,45 @@ async def test_active_directory_auth_async(self): token = self.generate_oauth_token() endpoint = self.get_oauth_endpoint() client = FormRecognizerClient(endpoint, token) - result = await client.recognize_receipts_from_url( + poller = await client.begin_recognize_receipts_from_url( self.receipt_url_jpg ) + result = await poller.result() self.assertIsNotNone(result) @GlobalFormRecognizerAccountPreparer() async def test_receipt_url_bad_endpoint(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): with self.assertRaises(ServiceRequestError): client = FormRecognizerClient("http://notreal.azure.com", AzureKeyCredential(form_recognizer_account_key)) - result = await client.recognize_receipts_from_url( + poller = await client.begin_recognize_receipts_from_url( self.receipt_url_jpg ) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_receipt_url_auth_successful_key(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) - result = await client.recognize_receipts_from_url( + poller = await client.begin_recognize_receipts_from_url( self.receipt_url_jpg ) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_receipt_url_auth_bad_key(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential("xxxx")) with self.assertRaises(ClientAuthenticationError): - result = await client.recognize_receipts_from_url( + poller = await client.begin_recognize_receipts_from_url( self.receipt_url_jpg ) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_receipt_bad_url(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) with self.assertRaises(HttpResponseError): - result = await client.recognize_receipts_from_url("https://badurl.jpg") + poller = await client.begin_recognize_receipts_from_url("https://badurl.jpg") + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_receipt_url_pass_stream(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -65,7 +70,8 @@ async def test_receipt_url_pass_stream(self, resource_group, location, form_reco receipt = fd.read(4) # makes the recording smaller with self.assertRaises(HttpResponseError): - result = await client.recognize_receipts_from_url(receipt) + poller = await client.begin_recognize_receipts_from_url(receipt) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() async def test_receipt_url_transform_jpg(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): @@ -79,11 +85,12 @@ def callback(raw_response, _, headers): responses.append(analyze_result) responses.append(extracted_receipt) - result = await client.recognize_receipts_from_url( + poller = await client.begin_recognize_receipts_from_url( self.receipt_url_jpg, include_text_content=True, cls=callback ) + result = await poller.result() raw_response = responses[0] returned_model = responses[1] @@ -130,11 +137,12 @@ def callback(raw_response, _, headers): responses.append(analyze_result) responses.append(extracted_receipt) - result = await client.recognize_receipts_from_url( + poller = await client.begin_recognize_receipts_from_url( self.receipt_url_png, include_text_content=True, cls=callback ) + result = await poller.result() raw_response = responses[0] returned_model = responses[1] @@ -173,10 +181,11 @@ def callback(raw_response, _, headers): async def test_receipt_url_include_text_content(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) - result = await client.recognize_receipts_from_url( + poller = await client.begin_recognize_receipts_from_url( self.receipt_url_jpg, include_text_content=True ) + result = await poller.result() self.assertEqual(len(result), 1) receipt = result[0] @@ -194,9 +203,10 @@ async def test_receipt_url_include_text_content(self, resource_group, location, async def test_receipt_url_jpg(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) - result = await client.recognize_receipts_from_url( + poller = await client.begin_recognize_receipts_from_url( self.receipt_url_jpg ) + result = await poller.result() self.assertEqual(len(result), 1) receipt = result[0] @@ -221,7 +231,8 @@ async def test_receipt_url_jpg(self, resource_group, location, form_recognizer_a async def test_receipt_url_png(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) - result = await client.recognize_receipts_from_url(self.receipt_url_png) + poller = await client.begin_recognize_receipts_from_url(self.receipt_url_png) + result = await poller.result() self.assertEqual(len(result), 1) receipt = result[0] @@ -243,7 +254,8 @@ async def test_receipt_url_png(self, resource_group, location, form_recognizer_a async def test_receipt_multipage_url(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) - result = await client.recognize_receipts_from_url(self.multipage_url_pdf, include_text_content=True) + poller = await client.begin_recognize_receipts_from_url(self.multipage_url_pdf, include_text_content=True) + result = await poller.result() self.assertEqual(len(result), 3) receipt = result[0] @@ -283,12 +295,13 @@ def callback(raw_response, _, headers): responses.append(analyze_result) responses.append(extracted_receipt) - result = await client.recognize_receipts_from_url( + poller = await client.begin_recognize_receipts_from_url( self.multipage_url_pdf, include_text_content=True, cls=callback ) + result = await poller.result() raw_response = responses[0] returned_model = responses[1] actual = raw_response.analyze_result.document_results @@ -326,3 +339,15 @@ def callback(raw_response, _, headers): # Check form pages self.assertFormPagesTransformCorrect(returned_model, read_results) + + @GlobalFormRecognizerAccountPreparer() + @pytest.mark.live_test_only + async def test_receipt_continuation_token(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): + client = FormRecognizerClient(form_recognizer_account, AzureKeyCredential(form_recognizer_account_key)) + + initial_poller = await client.begin_recognize_receipts_from_url(self.receipt_url_jpg) + cont_token = initial_poller.continuation_token() + poller = await client.begin_recognize_receipts_from_url(self.receipt_url_jpg, continuation_token=cont_token) + result = await poller.result() + self.assertIsNotNone(result) + await initial_poller.wait() # necessary so azure-devtools doesn't throw assertion error diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_training.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_training.py index 2ee398403abf..f649b92b8868 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_training.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_training.py @@ -4,6 +4,7 @@ # Licensed under the MIT License. # ------------------------------------ +import pytest import functools from azure.core.credentials import AzureKeyCredential from azure.core.exceptions import ClientAuthenticationError, HttpResponseError @@ -23,13 +24,13 @@ class TestTraining(FormRecognizerTest): def test_training_auth_bad_key(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormTrainingClient(form_recognizer_account, AzureKeyCredential("xxxx")) with self.assertRaises(ClientAuthenticationError): - poller = client.begin_train_model("xx", use_training_labels=False) + poller = client.begin_training("xx", use_training_labels=False) @GlobalFormRecognizerAccountPreparer() @GlobalTrainingAccountPreparer() def test_training(self, client, container_sas_url): - poller = client.begin_train_model(training_files_url=container_sas_url, use_training_labels=False) + poller = client.begin_training(training_files_url=container_sas_url, use_training_labels=False) model = poller.result() self.assertIsNotNone(model.model_id) @@ -52,7 +53,7 @@ def test_training(self, client, container_sas_url): @GlobalTrainingAccountPreparer(multipage=True) def test_training_multipage(self, client, container_sas_url): - poller = client.begin_train_model(container_sas_url, use_training_labels=False) + poller = client.begin_training(container_sas_url, use_training_labels=False) model = poller.result() self.assertIsNotNone(model.model_id) @@ -83,7 +84,7 @@ def callback(response): raw_response.append(raw_model) raw_response.append(custom_model) - poller = client.begin_train_model(training_files_url=container_sas_url, use_training_labels=False, cls=callback) + poller = client.begin_training(training_files_url=container_sas_url, use_training_labels=False, cls=callback) model = poller.result() raw_model = raw_response[0] @@ -102,7 +103,7 @@ def callback(response): raw_response.append(raw_model) raw_response.append(custom_model) - poller = client.begin_train_model(container_sas_url, use_training_labels=False, cls=callback) + poller = client.begin_training(container_sas_url, use_training_labels=False, cls=callback) model = poller.result() raw_model = raw_response[0] @@ -113,7 +114,7 @@ def callback(response): @GlobalTrainingAccountPreparer() def test_training_with_labels(self, client, container_sas_url): - poller = client.begin_train_model(training_files_url=container_sas_url, use_training_labels=True) + poller = client.begin_training(training_files_url=container_sas_url, use_training_labels=True) model = poller.result() self.assertIsNotNone(model.model_id) @@ -137,7 +138,7 @@ def test_training_with_labels(self, client, container_sas_url): @GlobalTrainingAccountPreparer(multipage=True) def test_training_multipage_with_labels(self, client, container_sas_url): - poller = client.begin_train_model(container_sas_url, use_training_labels=True) + poller = client.begin_training(container_sas_url, use_training_labels=True) model = poller.result() self.assertIsNotNone(model.model_id) @@ -169,7 +170,7 @@ def callback(response): raw_response.append(raw_model) raw_response.append(custom_model) - poller = client.begin_train_model(training_files_url=container_sas_url, use_training_labels=True, cls=callback) + poller = client.begin_training(training_files_url=container_sas_url, use_training_labels=True, cls=callback) model = poller.result() raw_model = raw_response[0] @@ -188,7 +189,7 @@ def callback(response): raw_response.append(raw_model) raw_response.append(custom_model) - poller = client.begin_train_model(container_sas_url, use_training_labels=True, cls=callback) + poller = client.begin_training(container_sas_url, use_training_labels=True, cls=callback) model = poller.result() raw_model = raw_response[0] @@ -199,16 +200,28 @@ def callback(response): @GlobalTrainingAccountPreparer() def test_training_with_files_filter(self, client, container_sas_url): - poller = client.begin_train_model(training_files_url=container_sas_url, use_training_labels=False, include_sub_folders=True) + poller = client.begin_training(training_files_url=container_sas_url, use_training_labels=False, include_sub_folders=True) model = poller.result() self.assertEqual(len(model.training_documents), 6) self.assertEqual(model.training_documents[-1].document_name, "subfolder/Form_6.jpg") # we traversed subfolders - poller = client.begin_train_model(container_sas_url, use_training_labels=False, prefix="subfolder", include_sub_folders=True) + poller = client.begin_training(container_sas_url, use_training_labels=False, prefix="subfolder", include_sub_folders=True) model = poller.result() self.assertEqual(len(model.training_documents), 1) self.assertEqual(model.training_documents[0].document_name, "subfolder/Form_6.jpg") # we filtered for only subfolders with self.assertRaises(HttpResponseError): - poller = client.begin_train_model(training_files_url=container_sas_url, use_training_labels=False, prefix="xxx") + poller = client.begin_training(training_files_url=container_sas_url, use_training_labels=False, prefix="xxx") model = poller.result() + + @GlobalFormRecognizerAccountPreparer() + @GlobalTrainingAccountPreparer() + @pytest.mark.live_test_only + def test_training_continuation_token(self, client, container_sas_url): + + initial_poller = client.begin_training(training_files_url=container_sas_url, use_training_labels=False) + cont_token = initial_poller.continuation_token() + poller = client.begin_training(training_files_url=container_sas_url, use_training_labels=False, continuation_token=cont_token) + result = poller.result() + self.assertIsNotNone(result) + initial_poller.wait() # necessary so azure-devtools doesn't throw assertion error diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_training_async.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_training_async.py index 1507ea299c23..b693a0700ce7 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_training_async.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_training_async.py @@ -4,6 +4,7 @@ # Licensed under the MIT License. # ------------------------------------ +import pytest import functools from azure.core.credentials import AzureKeyCredential from azure.core.exceptions import ClientAuthenticationError, HttpResponseError @@ -23,15 +24,17 @@ class TestTrainingAsync(AsyncFormRecognizerTest): async def test_training_auth_bad_key(self, resource_group, location, form_recognizer_account, form_recognizer_account_key): client = FormTrainingClient(form_recognizer_account, AzureKeyCredential("xxxx")) with self.assertRaises(ClientAuthenticationError): - result = await client.train_model("xx", use_training_labels=False) + poller = await client.begin_training("xx", use_training_labels=False) + result = await poller.result() @GlobalFormRecognizerAccountPreparer() @GlobalTrainingAccountPreparer() async def test_training(self, client, container_sas_url): - model = await client.train_model( + poller = await client.begin_training( training_files_url=container_sas_url, use_training_labels=False) + model = await poller.result() self.assertIsNotNone(model.model_id) self.assertIsNotNone(model.requested_on) @@ -53,7 +56,8 @@ async def test_training(self, client, container_sas_url): @GlobalTrainingAccountPreparer(multipage=True) async def test_training_multipage(self, client, container_sas_url): - model = await client.train_model(container_sas_url, use_training_labels=False) + poller = await client.begin_training(container_sas_url, use_training_labels=False) + model = await poller.result() self.assertIsNotNone(model.model_id) self.assertIsNotNone(model.requested_on) @@ -83,10 +87,11 @@ def callback(response): raw_response.append(raw_model) raw_response.append(custom_model) - model = await client.train_model( + poller = await client.begin_training( training_files_url=container_sas_url, use_training_labels=False, cls=callback) + model = await poller.result() raw_model = raw_response[0] custom_model = raw_response[1] @@ -104,7 +109,8 @@ def callback(response): raw_response.append(raw_model) raw_response.append(custom_model) - model = await client.train_model(container_sas_url, use_training_labels=False, cls=callback) + poller = await client.begin_training(container_sas_url, use_training_labels=False, cls=callback) + model = await poller.result() raw_model = raw_response[0] custom_model = raw_response[1] @@ -114,7 +120,8 @@ def callback(response): @GlobalTrainingAccountPreparer() async def test_training_with_labels(self, client, container_sas_url): - model = await client.train_model(training_files_url=container_sas_url, use_training_labels=True) + poller = await client.begin_training(training_files_url=container_sas_url, use_training_labels=True) + model = await poller.result() self.assertIsNotNone(model.model_id) self.assertIsNotNone(model.requested_on) @@ -136,7 +143,8 @@ async def test_training_with_labels(self, client, container_sas_url): @GlobalTrainingAccountPreparer(multipage=True) async def test_training_multipage_with_labels(self, client, container_sas_url): - model = await client.train_model(container_sas_url, use_training_labels=True) + poller = await client.begin_training(container_sas_url, use_training_labels=True) + model = await poller.result() self.assertIsNotNone(model.model_id) self.assertIsNotNone(model.requested_on) @@ -167,7 +175,8 @@ def callback(response): raw_response.append(raw_model) raw_response.append(custom_model) - model = await client.train_model(training_files_url=container_sas_url, use_training_labels=True, cls=callback) + poller = await client.begin_training(training_files_url=container_sas_url, use_training_labels=True, cls=callback) + model = await poller.result() raw_model = raw_response[0] custom_model = raw_response[1] @@ -185,7 +194,9 @@ def callback(response): raw_response.append(raw_model) raw_response.append(custom_model) - model = await client.train_model(container_sas_url, use_training_labels=True, cls=callback) + poller = await client.begin_training(container_sas_url, use_training_labels=True, cls=callback) + model = await poller.result() + raw_model = raw_response[0] custom_model = raw_response[1] self.assertModelTransformCorrect(custom_model, raw_model) @@ -194,13 +205,28 @@ def callback(response): @GlobalTrainingAccountPreparer() async def test_training_with_files_filter(self, client, container_sas_url): - model = await client.train_model(training_files_url=container_sas_url, use_training_labels=False, include_sub_folders=True) + poller = await client.begin_training(training_files_url=container_sas_url, use_training_labels=False, include_sub_folders=True) + model = await poller.result() self.assertEqual(len(model.training_documents), 6) self.assertEqual(model.training_documents[-1].document_name, "subfolder/Form_6.jpg") # we traversed subfolders - model = await client.train_model(container_sas_url, use_training_labels=False, prefix="subfolder", include_sub_folders=True) + poller = await client.begin_training(container_sas_url, use_training_labels=False, prefix="subfolder", include_sub_folders=True) + model = await poller.result() self.assertEqual(len(model.training_documents), 1) self.assertEqual(model.training_documents[0].document_name, "subfolder/Form_6.jpg") # we filtered for only subfolders with self.assertRaises(HttpResponseError): - model = await client.train_model(training_files_url=container_sas_url, use_training_labels=False, prefix="xxx") + poller = await client.begin_training(training_files_url=container_sas_url, use_training_labels=False, prefix="xxx") + model = await poller.result() + + @GlobalFormRecognizerAccountPreparer() + @GlobalTrainingAccountPreparer() + @pytest.mark.live_test_only + async def test_training_continuation_token(self, client, container_sas_url): + + initial_poller = await client.begin_training(training_files_url=container_sas_url, use_training_labels=False) + cont_token = initial_poller.continuation_token() + poller = await client.begin_training(training_files_url=container_sas_url, use_training_labels=False, continuation_token=cont_token) + result = await poller.result() + self.assertIsNotNone(result) + await initial_poller.wait() # necessary so azure-devtools doesn't throw assertion error diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py index caeb23bb5a67..708950a652ad 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/testcase.py @@ -43,11 +43,12 @@ def process_response(self, response): import json try: body = json.loads(response['body']['string']) - body['accessToken'] = self._replacement + if 'accessToken' in body: + body['accessToken'] = self._replacement + response['body']['string'] = json.dumps(body) + return response except (KeyError, ValueError): return response - response['body']['string'] = json.dumps(body) - return response class FakeTokenCredential(object): diff --git a/shared_requirements.txt b/shared_requirements.txt index 18d16c257e7f..fba887ea9b35 100644 --- a/shared_requirements.txt +++ b/shared_requirements.txt @@ -126,7 +126,7 @@ six>=1.6 #override azure-ai-textanalytics azure-core<2.0.0,>=1.4.0 #override azure-search-documents azure-core<2.0.0,>=1.4.0 #override azure-ai-formrecognizer msrest>=0.6.12 -#override azure-ai-formrecognizer azure-core<2.0.0,>=1.4.0 +#override azure-ai-formrecognizer azure-core<2.0.0,>=1.6.0 #override azure-storage-blob azure-core<2.0.0,>=1.4.0 #override azure-storage-blob msrest>=0.6.10 #override azure-storage-queue msrest>=0.6.10 From ad179ad9cd8978b5c57792443c606ff412c70f92 Mon Sep 17 00:00:00 2001 From: iscai-msft <43154838+iscai-msft@users.noreply.github.com> Date: Wed, 3 Jun 2020 18:10:50 -0400 Subject: [PATCH 06/25] add more logging info for next time model_version comes back None (#11794) --- .../azure-ai-textanalytics/tests/test_analyze_sentiment.py | 3 ++- .../tests/test_analyze_sentiment_async.py | 3 ++- .../azure-ai-textanalytics/tests/test_detect_language.py | 3 ++- .../azure-ai-textanalytics/tests/test_detect_language_async.py | 3 ++- .../azure-ai-textanalytics/tests/test_extract_key_phrases.py | 3 ++- .../tests/test_extract_key_phrases_async.py | 3 ++- .../azure-ai-textanalytics/tests/test_recognize_entities.py | 3 ++- .../tests/test_recognize_entities_async.py | 3 ++- .../tests/test_recognize_linked_entities.py | 3 ++- .../tests/test_recognize_linked_entities_async.py | 3 ++- 10 files changed, 20 insertions(+), 10 deletions(-) diff --git a/sdk/textanalytics/azure-ai-textanalytics/tests/test_analyze_sentiment.py b/sdk/textanalytics/azure-ai-textanalytics/tests/test_analyze_sentiment.py index 8d4f601134a7..e2f199c4777c 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/tests/test_analyze_sentiment.py +++ b/sdk/textanalytics/azure-ai-textanalytics/tests/test_analyze_sentiment.py @@ -217,7 +217,8 @@ def test_out_of_order_ids(self, client): @TextAnalyticsClientPreparer() def test_show_stats_and_model_version(self, client): def callback(response): - self.assertIsNotNone(response.model_version) + self.assertIsNotNone(response) + self.assertIsNotNone(response.model_version, msg=response.raw_response) self.assertIsNotNone(response.raw_response) self.assertEqual(response.statistics.document_count, 5) self.assertEqual(response.statistics.transaction_count, 4) diff --git a/sdk/textanalytics/azure-ai-textanalytics/tests/test_analyze_sentiment_async.py b/sdk/textanalytics/azure-ai-textanalytics/tests/test_analyze_sentiment_async.py index 8e8b9c12f74d..d622ac552b4d 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/tests/test_analyze_sentiment_async.py +++ b/sdk/textanalytics/azure-ai-textanalytics/tests/test_analyze_sentiment_async.py @@ -220,7 +220,8 @@ async def test_out_of_order_ids(self, client): @TextAnalyticsClientPreparer() async def test_show_stats_and_model_version(self, client): def callback(response): - self.assertIsNotNone(response.model_version) + self.assertIsNotNone(response) + self.assertIsNotNone(response.model_version, msg=response.raw_response) self.assertIsNotNone(response.raw_response) self.assertEqual(response.statistics.document_count, 5) self.assertEqual(response.statistics.transaction_count, 4) diff --git a/sdk/textanalytics/azure-ai-textanalytics/tests/test_detect_language.py b/sdk/textanalytics/azure-ai-textanalytics/tests/test_detect_language.py index d6efe1735f3c..31b9dcd654c7 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/tests/test_detect_language.py +++ b/sdk/textanalytics/azure-ai-textanalytics/tests/test_detect_language.py @@ -210,7 +210,8 @@ def test_out_of_order_ids(self, client): @TextAnalyticsClientPreparer() def test_show_stats_and_model_version(self, client): def callback(response): - self.assertIsNotNone(response.model_version) + self.assertIsNotNone(response) + self.assertIsNotNone(response.model_version, msg=response.raw_response) self.assertIsNotNone(response.raw_response) self.assertEqual(response.statistics.document_count, 5) self.assertEqual(response.statistics.transaction_count, 4) diff --git a/sdk/textanalytics/azure-ai-textanalytics/tests/test_detect_language_async.py b/sdk/textanalytics/azure-ai-textanalytics/tests/test_detect_language_async.py index e7174961758b..c2db6b837911 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/tests/test_detect_language_async.py +++ b/sdk/textanalytics/azure-ai-textanalytics/tests/test_detect_language_async.py @@ -223,7 +223,8 @@ async def test_out_of_order_ids(self, client): @TextAnalyticsClientPreparer() async def test_show_stats_and_model_version(self, client): def callback(response): - self.assertIsNotNone(response.model_version) + self.assertIsNotNone(response) + self.assertIsNotNone(response.model_version, msg=response.raw_response) self.assertIsNotNone(response.raw_response) self.assertEqual(response.statistics.document_count, 5) self.assertEqual(response.statistics.transaction_count, 4) diff --git a/sdk/textanalytics/azure-ai-textanalytics/tests/test_extract_key_phrases.py b/sdk/textanalytics/azure-ai-textanalytics/tests/test_extract_key_phrases.py index 48709c5928fe..c06a41d3d36d 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/tests/test_extract_key_phrases.py +++ b/sdk/textanalytics/azure-ai-textanalytics/tests/test_extract_key_phrases.py @@ -172,7 +172,8 @@ def test_out_of_order_ids(self, client): @TextAnalyticsClientPreparer() def test_show_stats_and_model_version(self, client): def callback(response): - self.assertIsNotNone(response.model_version) + self.assertIsNotNone(response) + self.assertIsNotNone(response.model_version, msg=response.raw_response) self.assertIsNotNone(response.raw_response) self.assertEqual(response.statistics.document_count, 5) self.assertEqual(response.statistics.transaction_count, 4) diff --git a/sdk/textanalytics/azure-ai-textanalytics/tests/test_extract_key_phrases_async.py b/sdk/textanalytics/azure-ai-textanalytics/tests/test_extract_key_phrases_async.py index 2a43c350ba76..08b685bcf986 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/tests/test_extract_key_phrases_async.py +++ b/sdk/textanalytics/azure-ai-textanalytics/tests/test_extract_key_phrases_async.py @@ -187,7 +187,8 @@ async def test_out_of_order_ids(self, client): @TextAnalyticsClientPreparer() async def test_show_stats_and_model_version(self, client): def callback(response): - self.assertIsNotNone(response.model_version) + self.assertIsNotNone(response) + self.assertIsNotNone(response.model_version, msg=response.raw_response) self.assertIsNotNone(response.raw_response) self.assertEqual(response.statistics.document_count, 5) self.assertEqual(response.statistics.transaction_count, 4) diff --git a/sdk/textanalytics/azure-ai-textanalytics/tests/test_recognize_entities.py b/sdk/textanalytics/azure-ai-textanalytics/tests/test_recognize_entities.py index 415ce0e97bf4..d10bad7350d9 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/tests/test_recognize_entities.py +++ b/sdk/textanalytics/azure-ai-textanalytics/tests/test_recognize_entities.py @@ -180,7 +180,8 @@ def test_out_of_order_ids(self, client): @TextAnalyticsClientPreparer() def test_show_stats_and_model_version(self, client): def callback(response): - self.assertIsNotNone(response.model_version) + self.assertIsNotNone(response) + self.assertIsNotNone(response.model_version, msg=response.raw_response) self.assertIsNotNone(response.raw_response) self.assertEqual(response.statistics.document_count, 5) self.assertEqual(response.statistics.transaction_count, 4) diff --git a/sdk/textanalytics/azure-ai-textanalytics/tests/test_recognize_entities_async.py b/sdk/textanalytics/azure-ai-textanalytics/tests/test_recognize_entities_async.py index 3b05b33c8cc3..dbda319a5d2d 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/tests/test_recognize_entities_async.py +++ b/sdk/textanalytics/azure-ai-textanalytics/tests/test_recognize_entities_async.py @@ -196,7 +196,8 @@ async def test_out_of_order_ids(self, client): @TextAnalyticsClientPreparer() async def test_show_stats_and_model_version(self, client): def callback(response): - self.assertIsNotNone(response.model_version) + self.assertIsNotNone(response) + self.assertIsNotNone(response.model_version, msg=response.raw_response) self.assertIsNotNone(response.raw_response) self.assertEqual(response.statistics.document_count, 5) self.assertEqual(response.statistics.transaction_count, 4) diff --git a/sdk/textanalytics/azure-ai-textanalytics/tests/test_recognize_linked_entities.py b/sdk/textanalytics/azure-ai-textanalytics/tests/test_recognize_linked_entities.py index 98b8c0f4c75c..4de37b91c59a 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/tests/test_recognize_linked_entities.py +++ b/sdk/textanalytics/azure-ai-textanalytics/tests/test_recognize_linked_entities.py @@ -180,7 +180,8 @@ def test_out_of_order_ids(self, client): @TextAnalyticsClientPreparer() def test_show_stats_and_model_version(self, client): def callback(response): - self.assertIsNotNone(response.model_version) + self.assertIsNotNone(response) + self.assertIsNotNone(response.model_version, msg=response.raw_response) self.assertIsNotNone(response.raw_response) self.assertEqual(response.statistics.document_count, 5) self.assertEqual(response.statistics.transaction_count, 4) diff --git a/sdk/textanalytics/azure-ai-textanalytics/tests/test_recognize_linked_entities_async.py b/sdk/textanalytics/azure-ai-textanalytics/tests/test_recognize_linked_entities_async.py index b276c9a43199..22c53b363802 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/tests/test_recognize_linked_entities_async.py +++ b/sdk/textanalytics/azure-ai-textanalytics/tests/test_recognize_linked_entities_async.py @@ -204,7 +204,8 @@ async def test_out_of_order_ids(self, client): async def test_show_stats_and_model_version(self, client): def callback(response): - self.assertIsNotNone(response.model_version) + self.assertIsNotNone(response) + self.assertIsNotNone(response.model_version, msg=response.raw_response) self.assertIsNotNone(response.raw_response) self.assertEqual(response.statistics.document_count, 5) self.assertEqual(response.statistics.transaction_count, 4) From 0e07b20f3e0c57a3f9e042cd961c498f530c1a4b Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Wed, 3 Jun 2020 16:12:39 -0700 Subject: [PATCH 07/25] Add AzureCliCredential and VSCodeCredential to public API (#11790) --- sdk/identity/azure-identity/CHANGELOG.md | 3 +++ sdk/identity/azure-identity/azure/identity/__init__.py | 4 ++++ .../azure/identity/_credentials/__init__.py | 3 +++ .../azure-identity/azure/identity/aio/__init__.py | 4 ++++ .../azure/identity/aio/_credentials/__init__.py | 2 ++ .../azure-identity/tests/test_cli_credential.py | 4 ++-- .../azure-identity/tests/test_cli_credential_async.py | 2 +- .../azure-identity/tests/test_vscode_credential.py | 8 +++++--- .../tests/test_vscode_credential_async.py | 10 ++++++---- 9 files changed, 30 insertions(+), 10 deletions(-) diff --git a/sdk/identity/azure-identity/CHANGELOG.md b/sdk/identity/azure-identity/CHANGELOG.md index ea5b7fca0727..781fe4b105c3 100644 --- a/sdk/identity/azure-identity/CHANGELOG.md +++ b/sdk/identity/azure-identity/CHANGELOG.md @@ -1,6 +1,9 @@ # Release History ## 1.4.0b4 (Unreleased) +- `AzureCliCredential` and `VSCodeCredential`, which enable authenticating as + the identity signed in to the Azure CLI and Visual Studio Code, respectively, + can be imported from `azure.identity` and `azure.identity.aio`. - `azure.identity.aio.AuthorizationCodeCredential.get_token()` no longer accepts optional keyword arguments `executor` or `loop`. Prior versions of the method didn't use these correctly, provoking exceptions, and internal changes in this diff --git a/sdk/identity/azure-identity/azure/identity/__init__.py b/sdk/identity/azure-identity/azure/identity/__init__.py index 3fbc78c57bfa..5f408028a4c0 100644 --- a/sdk/identity/azure-identity/azure/identity/__init__.py +++ b/sdk/identity/azure-identity/azure/identity/__init__.py @@ -8,6 +8,7 @@ from ._exceptions import AuthenticationRequiredError, CredentialUnavailableError from ._constants import KnownAuthorities from ._credentials import ( + AzureCliCredential, AuthorizationCodeCredential, CertificateCredential, ChainedTokenCredential, @@ -19,11 +20,13 @@ ManagedIdentityCredential, SharedTokenCacheCredential, UsernamePasswordCredential, + VSCodeCredential, ) __all__ = [ "AuthenticationRecord", + "AzureCliCredential", "AuthenticationRequiredError", "AuthorizationCodeCredential", "CertificateCredential", @@ -38,6 +41,7 @@ "ManagedIdentityCredential", "SharedTokenCacheCredential", "UsernamePasswordCredential", + "VSCodeCredential", ] from ._version import VERSION diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/__init__.py b/sdk/identity/azure-identity/azure/identity/_credentials/__init__.py index cd0068cc3cd8..baf64e6d5102 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/__init__.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/__init__.py @@ -14,10 +14,12 @@ from .azure_cli import AzureCliCredential from .device_code import DeviceCodeCredential from .user_password import UsernamePasswordCredential +from .vscode_credential import VSCodeCredential __all__ = [ "AuthorizationCodeCredential", + "AzureCliCredential", "CertificateCredential", "ChainedTokenCredential", "ClientSecretCredential", @@ -29,4 +31,5 @@ "SharedTokenCacheCredential", "AzureCliCredential", "UsernamePasswordCredential", + "VSCodeCredential", ] diff --git a/sdk/identity/azure-identity/azure/identity/aio/__init__.py b/sdk/identity/azure-identity/azure/identity/aio/__init__.py index 775ee06abd85..3c2288e308a8 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/__init__.py +++ b/sdk/identity/azure-identity/azure/identity/aio/__init__.py @@ -6,6 +6,7 @@ from ._credentials import ( AuthorizationCodeCredential, + AzureCliCredential, CertificateCredential, ChainedTokenCredential, ClientSecretCredential, @@ -13,11 +14,13 @@ EnvironmentCredential, ManagedIdentityCredential, SharedTokenCacheCredential, + VSCodeCredential, ) __all__ = [ "AuthorizationCodeCredential", + "AzureCliCredential", "CertificateCredential", "ClientSecretCredential", "DefaultAzureCredential", @@ -25,4 +28,5 @@ "ManagedIdentityCredential", "ChainedTokenCredential", "SharedTokenCacheCredential", + "VSCodeCredential", ] diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/__init__.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/__init__.py index cf63acbd84d6..d9146708694d 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/__init__.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/__init__.py @@ -11,6 +11,7 @@ from .client_secret import ClientSecretCredential from .shared_cache import SharedTokenCacheCredential from .azure_cli import AzureCliCredential +from .vscode_credential import VSCodeCredential __all__ = [ @@ -23,4 +24,5 @@ "EnvironmentCredential", "ManagedIdentityCredential", "SharedTokenCacheCredential", + "VSCodeCredential", ] diff --git a/sdk/identity/azure-identity/tests/test_cli_credential.py b/sdk/identity/azure-identity/tests/test_cli_credential.py index bc588436668f..7377d330455e 100644 --- a/sdk/identity/azure-identity/tests/test_cli_credential.py +++ b/sdk/identity/azure-identity/tests/test_cli_credential.py @@ -5,8 +5,8 @@ from datetime import datetime import json -from azure.identity import CredentialUnavailableError -from azure.identity._credentials.azure_cli import AzureCliCredential, CLI_NOT_FOUND +from azure.identity import AzureCliCredential, CredentialUnavailableError +from azure.identity._credentials.azure_cli import CLI_NOT_FOUND from azure.core.exceptions import ClientAuthenticationError import subprocess diff --git a/sdk/identity/azure-identity/tests/test_cli_credential_async.py b/sdk/identity/azure-identity/tests/test_cli_credential_async.py index 1ad4dba493d9..9e8ad1f82217 100644 --- a/sdk/identity/azure-identity/tests/test_cli_credential_async.py +++ b/sdk/identity/azure-identity/tests/test_cli_credential_async.py @@ -8,7 +8,7 @@ from unittest import mock from azure.identity import CredentialUnavailableError -from azure.identity.aio._credentials.azure_cli import AzureCliCredential +from azure.identity.aio import AzureCliCredential from azure.identity._credentials.azure_cli import CLI_NOT_FOUND from azure.core.exceptions import ClientAuthenticationError import pytest diff --git a/sdk/identity/azure-identity/tests/test_vscode_credential.py b/sdk/identity/azure-identity/tests/test_vscode_credential.py index d4e0afe2b338..779578053d04 100644 --- a/sdk/identity/azure-identity/tests/test_vscode_credential.py +++ b/sdk/identity/azure-identity/tests/test_vscode_credential.py @@ -3,18 +3,20 @@ # Licensed under the MIT License. # ------------------------------------ import sys -import pytest + from azure.core.credentials import AccessToken -from azure.identity import CredentialUnavailableError +from azure.identity import CredentialUnavailableError, VSCodeCredential from azure.core.pipeline.policies import SansIOHTTPPolicy from azure.identity._internal.user_agent import USER_AGENT +from azure.identity._credentials.vscode_credential import get_credentials +import pytest + from helpers import build_aad_response, mock_response, Request, validating_transport try: from unittest import mock except ImportError: # python < 3.3 import mock -from azure.identity._credentials.vscode_credential import VSCodeCredential, get_credentials def test_no_scopes(): diff --git a/sdk/identity/azure-identity/tests/test_vscode_credential_async.py b/sdk/identity/azure-identity/tests/test_vscode_credential_async.py index 89f27a78d4f5..edd59dcc0b3d 100644 --- a/sdk/identity/azure-identity/tests/test_vscode_credential_async.py +++ b/sdk/identity/azure-identity/tests/test_vscode_credential_async.py @@ -2,15 +2,17 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # ------------------------------------ -import pytest +from unittest import mock + from azure.core.credentials import AccessToken -from azure.identity._internal.user_agent import USER_AGENT from azure.identity import CredentialUnavailableError +from azure.identity.aio import VSCodeCredential +from azure.identity._internal.user_agent import USER_AGENT from azure.core.pipeline.policies import SansIOHTTPPolicy +import pytest + from helpers import build_aad_response, mock_response, Request from helpers_async import async_validating_transport, AsyncMockTransport, wrap_in_future -from unittest import mock -from azure.identity.aio._credentials.vscode_credential import VSCodeCredential @pytest.mark.asyncio From 376173008a0e8f6613c649c342eac25dd6410f25 Mon Sep 17 00:00:00 2001 From: aim-for-better Date: Thu, 4 Jun 2020 12:01:05 +0800 Subject: [PATCH 08/25] [HDInsight] Fix hdi test failure (#11806) * Initial generation Synapse autorest v5 * Fix empty model generation * Fix Test Failure: Skip 3 test case: test_create_with_adlsgen1, test_create_with_additional_storage, test_oms_on_running_cluster Rename test_http_extend to test_gateway_setting for http settings is replaced with gateway settings Co-authored-by: Laurent Mazuel Co-authored-by: Zhenyu Zhou --- .../azure-mgmt-hdinsight/dev_requirements.txt | 1 + ...te_kafka_cluster_with_disk_encryption.yaml | 2526 +++++++++++------ ..._hdinsight.test_create_with_adls_gen1.yaml | 930 ------ ..._mgmt_hdinsight.test_gateway_settings.yaml | 1507 ++++++++++ ...est_mgmt_hdinsight.test_http_extended.yaml | 1164 -------- ...hdinsight.test_hue_on_running_cluster.yaml | 781 +++-- .../test/test_mgmt_hdinsight.py | 189 +- 7 files changed, 3858 insertions(+), 3240 deletions(-) delete mode 100644 sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_create_with_adls_gen1.yaml create mode 100644 sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_gateway_settings.yaml delete mode 100644 sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_http_extended.yaml diff --git a/sdk/hdinsight/azure-mgmt-hdinsight/dev_requirements.txt b/sdk/hdinsight/azure-mgmt-hdinsight/dev_requirements.txt index b0c11033324b..99233514bcb6 100644 --- a/sdk/hdinsight/azure-mgmt-hdinsight/dev_requirements.txt +++ b/sdk/hdinsight/azure-mgmt-hdinsight/dev_requirements.txt @@ -2,4 +2,5 @@ -e ../../core/azure-core -e ../../keyvault/azure-keyvault-keys -e ../../keyvault/azure-mgmt-keyvault +-e ../../loganalytics/azure-mgmt-loganalytics -e ../../resources/azure-mgmt-msi/ \ No newline at end of file diff --git a/sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_create_kafka_cluster_with_disk_encryption.yaml b/sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_create_kafka_cluster_with_disk_encryption.yaml index 216003de85b0..e37fcc777277 100644 --- a/sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_create_kafka_cluster_with_disk_encryption.yaml +++ b/sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_create_kafka_cluster_with_disk_encryption.yaml @@ -2,31 +2,52 @@ interactions: - request: body: '{"location": "North Central US"}' headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - Content-Length: ['32'] - Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-msi/0.2.0 Azure-SDK-For-Python] - accept-language: [en-US] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '32' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-msi/1.0.0 Azure-SDK-For-Python + accept-language: + - en-US method: PUT - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.ManagedIdentity/userAssignedIdentities/hdipyuai8ce41b44?api-version=2015-08-31-preview + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.ManagedIdentity/userAssignedIdentities/hdipyuai8ce41b44?api-version=2018-11-30 response: - body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/Microsoft.ManagedIdentity/userAssignedIdentities/hdipyuai8ce41b44","name":"hdipyuai8ce41b44","type":"Microsoft.ManagedIdentity/userAssignedIdentities","location":"northcentralus","tags":{},"properties":{"tenantId":"00000000-0000-0000-0000-000000000000","principalId":"52397674-1024-43c0-8826-a57b80ca8a39","clientId":"998e4f8e-72c2-439d-86e2-5f1e13db642d","clientSecretUrl":"https://control-northcentralus.identity.azure.net/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/Microsoft.ManagedIdentity/userAssignedIdentities/hdipyuai8ce41b44/credentials?tid=00000000-0000-0000-0000-000000000000&oid=52397674-1024-43c0-8826-a57b80ca8a39&aid=998e4f8e-72c2-439d-86e2-5f1e13db642d"}}'} - headers: - cache-control: [no-cache] - content-length: ['818'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:03:00 GMT'] - expires: ['-1'] - location: [/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/Microsoft.ManagedIdentity/userAssignedIdentities/hdipyuai8ce41b44] - pragma: [no-cache] - server: [Microsoft-HTTPAPI/2.0] - strict-transport-security: [max-age=31536000; includeSubDomains] - x-content-type-options: [nosniff] - x-ms-ratelimit-remaining-subscription-writes: ['1199'] - status: {code: 201, message: Created} + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/Microsoft.ManagedIdentity/userAssignedIdentities/hdipyuai8ce41b44","name":"hdipyuai8ce41b44","type":"Microsoft.ManagedIdentity/userAssignedIdentities","location":"northcentralus","tags":{},"properties":{"tenantId":"00000000-0000-0000-0000-000000000000","principalId":"1b11ead4-22b6-4384-a14d-d081131fad4b","clientId":"1b12fe54-7b96-47a6-8f1b-ba1938623b65"}}' + headers: + cache-control: + - no-cache + content-length: + - '456' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:40:40 GMT + expires: + - '-1' + location: + - /subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/Microsoft.ManagedIdentity/userAssignedIdentities/hdipyuai8ce41b44 + pragma: + - no-cache + server: + - Microsoft-HTTPAPI/2.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-writes: + - '1199' + status: + code: 201 + message: Created - request: body: 'b''b\''b\\\''{"location": "North Central US", "properties": {"tenantId": "00000000-0000-0000-0000-000000000000", "sku": {"family": "A", "name": "premium"}, @@ -40,104 +61,221 @@ interactions: "backup", "restore"], "storage": ["get", "list", "delete", "set", "update", "regeneratekey", "recover", "purge", "backup", "restore", "setsas", "listsas", "getsas", "deletesas"]}}, {"tenantId": "00000000-0000-0000-0000-000000000000", - "objectId": "52397674-1024-43c0-8826-a57b80ca8a39", "permissions": {"keys": + "objectId": "1b11ead4-22b6-4384-a14d-d081131fad4b", "permissions": {"keys": ["get", "wrapKey", "unwrapKey"], "secrets": ["get", "set", "delete"]}}], "vaultUri": - "https://hdipy8ce41b44.vault.azure.net/", "enabledForDeployment": true, "enabledForDiskEncryption": - true, "enabledForTemplateDeployment": true, "enableSoftDelete": true}}\\\''\''''' - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - Content-Length: ['1291'] - Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-keyvault/1.1.0 Azure-SDK-For-Python] - accept-language: [en-US] + "https://hdipy8ce41b44..vault.azure.net/", "enabledForDeployment": true, "enabledForDiskEncryption": + true, "enabledForTemplateDeployment": true, "enableSoftDelete": true, "softDeleteRetentionInDays": + 90, "enableRbacAuthorization": false}}\\\''\''''' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '1358' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-keyvault/2.2.0 Azure-SDK-For-Python + accept-language: + - en-US method: PUT - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.KeyVault/vaults/hdipy8ce41b44?api-version=2018-02-14 + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.KeyVault/vaults/hdipy8ce41b44?api-version=2019-09-01 response: - body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.KeyVault/vaults/hdipy8ce41b44","name":"hdipy8ce41b44","type":"Microsoft.KeyVault/vaults","location":"North - Central US","tags":{},"properties":{"sku":{"family":"A","name":"premium"},"tenantId":"00000000-0000-0000-0000-000000000000","accessPolicies":[{"tenantId":"00000000-0000-0000-0000-000000000000","objectId":"00000000-0000-0000-0000-000000000000","permissions":{"keys":["encrypt","decrypt","wrapKey","unwrapKey","sign","verify","get","list","create","update","import","delete","backup","restore","recover","purge"],"secrets":["get","list","set","delete","backup","restore","recover","purge"],"certificates":["get","list","delete","create","import","update","managecontacts","getissuers","listissuers","setissuers","deleteissuers","manageissuers","recover","purge","backup","restore"],"storage":["get","list","delete","set","update","regeneratekey","recover","purge","backup","restore","setsas","listsas","getsas","deletesas"]}},{"tenantId":"00000000-0000-0000-0000-000000000000","objectId":"52397674-1024-43c0-8826-a57b80ca8a39","permissions":{"keys":["get","wrapKey","unwrapKey"],"secrets":["get","set","delete"]}}],"enabledForDeployment":true,"enabledForDiskEncryption":true,"enabledForTemplateDeployment":true,"enableSoftDelete":true,"vaultUri":"https://hdipy8ce41b44.vault.azure.net/","provisioningState":"Succeeded"}}'} - headers: - cache-control: [no-cache] - content-length: ['1434'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:03:02 GMT'] - expires: ['-1'] - pragma: [no-cache] - server: [Microsoft-IIS/10.0] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-aspnet-version: [4.0.30319] - x-content-type-options: [nosniff] - x-ms-keyvault-service-version: [1.1.0.235] - x-ms-ratelimit-remaining-subscription-writes: ['1199'] - x-powered-by: [ASP.NET] - status: {code: 200, message: OK} + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.KeyVault/vaults/hdipy8ce41b44","name":"hdipy8ce41b44","type":"Microsoft.KeyVault/vaults","location":"North + Central US","tags":{},"properties":{"sku":{"family":"A","name":"premium"},"tenantId":"00000000-0000-0000-0000-000000000000","accessPolicies":[{"tenantId":"00000000-0000-0000-0000-000000000000","objectId":"00000000-0000-0000-0000-000000000000","permissions":{"keys":["encrypt","decrypt","wrapKey","unwrapKey","sign","verify","get","list","create","update","import","delete","backup","restore","recover","purge"],"secrets":["get","list","set","delete","backup","restore","recover","purge"],"certificates":["get","list","delete","create","import","update","managecontacts","getissuers","listissuers","setissuers","deleteissuers","manageissuers","recover","purge","backup","restore"],"storage":["get","list","delete","set","update","regeneratekey","recover","purge","backup","restore","setsas","listsas","getsas","deletesas"]}},{"tenantId":"00000000-0000-0000-0000-000000000000","objectId":"1b11ead4-22b6-4384-a14d-d081131fad4b","permissions":{"keys":["get","wrapKey","unwrapKey"],"secrets":["get","set","delete"]}}],"enabledForDeployment":true,"enabledForDiskEncryption":true,"enabledForTemplateDeployment":true,"enableSoftDelete":true,"softDeleteRetentionInDays":90,"enableRbacAuthorization":false,"vaultUri":"https://hdipy8ce41b44..vault.azure.net/","provisioningState":"Succeeded"}}' + headers: + cache-control: + - no-cache + content-length: + - '1497' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:40:43 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - Microsoft-IIS/10.0 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-aspnet-version: + - 4.0.30319 + x-content-type-options: + - nosniff + x-ms-keyvault-service-version: + - 1.1.0.281 + x-ms-ratelimit-remaining-subscription-writes: + - '1199' + x-powered-by: + - ASP.NET + status: + code: 200 + message: OK - request: - body: '' - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - Content-Length: [0] - Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-keyvault/7.0 Azure-SDK-For-Python] - accept-language: [en-US] + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - azsdk-python-keyvault-keys/4.2.0b2 Python/3.7.4 (Windows-10-10.0.18362-SP0) + method: POST + uri: https://hdipy8ce41b44..vault.azure.net/keys/hdipykey18ce41b44/create?api-version=7.1-preview + response: + body: + string: '{"error":{"code":"Unauthorized","message":"Request is missing a Bearer + or PoP token."}}' + headers: + cache-control: + - no-cache + content-length: + - '87' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:40:45 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000;includeSubDomains + www-authenticate: + - Bearer authorization="https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47", + resource="https://vault.azure.net" + x-aspnet-version: + - 4.0.30319 + x-content-type-options: + - nosniff + x-ms-keyvault-network-info: + - conn_type=Ipv4;addr=167.220.232.23;act_addr_fam=InterNetwork; + x-ms-keyvault-region: + - North Central US + x-ms-keyvault-service-version: + - 1.1.5.0 + x-powered-by: + - ASP.NET + status: + code: 401 + message: Unauthorized +- request: + body: '{"kty": "RSA"}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '14' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - azsdk-python-keyvault-keys/4.2.0b2 Python/3.7.4 (Windows-10-10.0.18362-SP0) method: POST - uri: https://hdipy8ce41b44.vault.azure.net/keys/hdipykey18ce41b44/create?api-version=7.0 + uri: https://hdipy8ce41b44..vault.azure.net/keys/hdipykey18ce41b44/create?api-version=7.1-preview response: - body: {string: ''} - headers: - cache-control: [no-cache] - content-length: ['0'] - date: ['Fri, 28 Dec 2018 09:03:02 GMT'] - expires: ['-1'] - pragma: [no-cache] - server: [Microsoft-IIS/10.0] - strict-transport-security: [max-age=31536000;includeSubDomains] - www-authenticate: ['Bearer authorization="https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47", - resource="https://vault.azure.net"'] - x-aspnet-version: [4.0.30319] - x-content-type-options: [nosniff] - x-ms-keyvault-network-info: [addr=131.107.160.11;act_addr_fam=InterNetwork;] - x-ms-keyvault-region: [North Central US] - x-ms-keyvault-service-version: [1.1.0.859] - x-powered-by: [ASP.NET] - status: {code: 401, message: Unauthorized} + body: + string: '{"key":{"kid":"https://hdipy8ce41b44..vault.azure.net/keys/hdipykey18ce41b44/830e48e217534b51ad2ddcf2f1ce4adb","kty":"RSA","key_ops":["encrypt","decrypt","sign","verify","wrapKey","unwrapKey"],"n":"kJXp3s-u1l_J8ZZqF_pXPe--esCwOTzMqX_5W_XzTx_KEdjxYPM7NzpOGCbATR_CGfNONEnW5he_mb8_Ky9MVkfC3AdBKAY7d40AdFel04titIB8RSHg3u5ZMqZV8UVAyKB9huwjeFxsEK8uxHHsJU5-Mnq-SdNKsdAnREz0mW8YHt41IXB95G7iz0_nx_KyuDcwomy5lT-f_RCkO08CRVm-VmjBvvHiXfgmTedmcHn6LWgbMhbHIco_5YeMrOigXBOCkwFECq8ZgGnLurJR7Xj93vaW9pUmn2G0i32l8qmD12TgeFXiIRjmPAN2nA1iaIqy37nHROm_PvoB1F3Kcw","e":"AQAB"},"attributes":{"enabled":true,"created":1591188046,"updated":1591188046,"recoveryLevel":"Recoverable+Purgeable","recoverableDays":90}}' + headers: + cache-control: + - no-cache + content-length: + - '686' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:40:46 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000;includeSubDomains + x-aspnet-version: + - 4.0.30319 + x-content-type-options: + - nosniff + x-ms-keyvault-network-info: + - conn_type=Ipv4;addr=167.220.232.23;act_addr_fam=InterNetwork; + x-ms-keyvault-region: + - North Central US + x-ms-keyvault-service-version: + - 1.1.5.0 + x-powered-by: + - ASP.NET + status: + code: 200 + message: OK - request: body: '{"kty": "RSA"}' headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - Content-Length: ['14'] - Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-keyvault/7.0 Azure-SDK-For-Python] - accept-language: [en-US] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '14' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - azsdk-python-keyvault-keys/4.2.0b2 Python/3.7.4 (Windows-10-10.0.18362-SP0) method: POST - uri: https://hdipy8ce41b44.vault.azure.net/keys/hdipykey18ce41b44/create?api-version=7.0 + uri: https://hdipy8ce41b44..vault.azure.net/keys/hdipykey28ce41b44/create?api-version=7.1-preview response: - body: {string: '{"key":{"kid":"https://hdipy8ce41b44.vault.azure.net/keys/hdipykey18ce41b44/8dc96189f25541c39c45221d01536eaf","kty":"RSA","key_ops":["encrypt","decrypt","sign","verify","wrapKey","unwrapKey"],"n":"3LMSjeDzM38A1tV4WxtHOeFFsmro8gw73flkzG0ZqtfKLwKeCv_DMQRQHypsGu8DEp62rxeogywUPryP9Gtgy7Oyo3h5NqnPjticEQAJOOcVJd6qY8cUsyo6au1ZxSUYWmHZ6TETTAy9IhM_eSQ0y7V6EWHWkJzDA3uJvN1vc47_Sfg8vfAuUyVRzVvhUlxOmlU88lgCxQXbw_B9mrQF0TYPJcL16_1UTvpkMcRsw-F7HXXejIx82ubW_K6J__WBxAxIKtpaUZHL_qM1iSxkmLmALhp4KckHR8i8kJzJ6Zxps_QU_Hgph72MktFmrlkUJ2sXBuNWXq-siwZfALD65w","e":"AQAB"},"attributes":{"enabled":true,"created":1545987783,"updated":1545987783,"recoveryLevel":"Recoverable+Purgeable"}}'} - headers: - cache-control: [no-cache] - content-length: ['665'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:03:03 GMT'] - expires: ['-1'] - pragma: [no-cache] - server: [Microsoft-IIS/10.0] - strict-transport-security: [max-age=31536000;includeSubDomains] - x-aspnet-version: [4.0.30319] - x-content-type-options: [nosniff] - x-ms-keyvault-network-info: [addr=131.107.160.11;act_addr_fam=InterNetwork;] - x-ms-keyvault-region: [North Central US] - x-ms-keyvault-service-version: [1.1.0.859] - x-powered-by: [ASP.NET] - status: {code: 200, message: OK} + body: + string: '{"key":{"kid":"https://hdipy8ce41b44..vault.azure.net/keys/hdipykey28ce41b44/58ef873805c14c5a9d292aaa20f10ccb","kty":"RSA","key_ops":["encrypt","decrypt","sign","verify","wrapKey","unwrapKey"],"n":"1IZKlVmqnmWJ7oONmq1Dtq_IQlsxpt6V4dNNatRHwFK8agwSBKdqZJJZsuEeMMwfwvMaaW-jMFjMnBmho_9Nvim3dLRZYOmu7PFDKex3DY8OMmQUWuWNhMHubE8dIZl_GakpUUQRE55AFUfjIBp-cnPsdHP-FRM1YjoCld6y0ev_u7SWk9jgDFgxoPU7UNNRKWtcIfCVFSYsd7EtKe1BmrMh_OvH86bh6O1M76zqjOUOmQo8gcUGhobYM6FL7EfuIZpbfrHrydWAqiaq19tpgbBscoXaruZFSNJxAEI_cogLjXYDvLQ7g3_SrvIzkR_5LqLjDSNfbFLfvp8Egk7TOw","e":"AQAB"},"attributes":{"enabled":true,"created":1591188047,"updated":1591188047,"recoveryLevel":"Recoverable+Purgeable","recoverableDays":90}}' + headers: + cache-control: + - no-cache + content-length: + - '686' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:40:46 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000;includeSubDomains + x-aspnet-version: + - 4.0.30319 + x-content-type-options: + - nosniff + x-ms-keyvault-network-info: + - conn_type=Ipv4;addr=167.220.232.23;act_addr_fam=InterNetwork; + x-ms-keyvault-region: + - North Central US + x-ms-keyvault-service-version: + - 1.1.5.0 + x-powered-by: + - ASP.NET + status: + code: 200 + message: OK - request: body: 'b''b\''{"location": "North Central US", "tags": {}, "properties": {"clusterVersion": "3.6", "osType": "Linux", "tier": "Standard", "clusterDefinition": {"kind": @@ -151,919 +289,1633 @@ interactions: "dataDisksGroups": [{"disksPerNode": 8}]}, {"name": "zookeepernode", "targetInstanceCount": 3, "hardwareProfile": {"vmSize": "Small"}, "osProfile": {"linuxOperatingSystemProfile": {"username": "sshuser", "password": "Password1!"}}}]}, "storageProfile": {"storageaccounts": - [{"name": "hdipy8ce41b44.blob.core.windows.net", "isDefault": true, "container": - "hdisdk-kafka-byok8ce41b44", "key": "8Tm/F1xWzEjObfavswhyUl2S08j8goN7EBeN0Gf4nkcoLQ1IXNjUeNRixNIFS6fFK+us/CapU7rcfU73JKoMRg=="}]}, - "diskEncryptionProperties": {"vaultUri": "https://hdipy8ce41b44.vault.azure.net", - "keyName": "hdipykey18ce41b44", "keyVersion": "8dc96189f25541c39c45221d01536eaf", - "msiResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/Microsoft.ManagedIdentity/userAssignedIdentities/hdipyuai8ce41b44"}}, + [{"name": "hdipy.blob.core.windows.net", "isDefault": true, "container": "hdisdk-kafka-byok8ce41b44", + "key": "4NAmrBx8TObfhTYfdNvPiwtd4P0H18hvmoa079B8eeyJobqs42ORlgtCDXOmLKYavC1sehvmksuCAPbjvuSiyA=="}]}, + "diskEncryptionProperties": {"vaultUri": "https://hdipy8ce41b44..vault.azure.net", "keyName": + "hdipykey18ce41b44", "keyVersion": "830e48e217534b51ad2ddcf2f1ce4adb", "msiResourceId": + "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/Microsoft.ManagedIdentity/userAssignedIdentities/hdipyuai8ce41b44"}}, "identity": {"type": "UserAssigned", "userAssignedIdentities": {"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/Microsoft.ManagedIdentity/userAssignedIdentities/hdipyuai8ce41b44": {}}}}\''''' headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - Content-Length: ['1781'] - Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - accept-language: [en-US] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '1781' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python + accept-language: + - en-US method: PUT uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44?api-version=2018-06-01-preview response: - body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44","name":"hdisdk-kafka-byok8ce41b44","type":"Microsoft.HDInsight/clusters","location":"North - Central US","etag":"8b2fc785-1ec8-4e36-874a-1793259f42bd","tags":{},"properties":{"clusterVersion":"3.6.1000.67","clusterHdpVersion":"","osType":"Linux","clusterDefinition":{"blueprint":"https://blueprints.azurehdinsight.net/kafka-3.6.1000.67.1812120705.json","kind":"Kafka","componentVersion":{"Kafka":"1.1"}},"computeProfile":{"roles":[{"name":"headnode","targetInstanceCount":2,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"workernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"dataDisksGroups":[{"disksPerNode":8,"storageAccountType":"Standard_LRS","diskSizeGB":1023}],"encryptDataDisks":false},{"name":"zookeepernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"Small"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false}]},"provisioningState":"InProgress","clusterState":"Accepted","createdDate":"2018-12-28T09:03:10.693","quotaInfo":{"coresUsed":23},"tier":"standard","diskEncryptionProperties":{"vaultUri":"https://hdipy8ce41b44.vault.azure.net","keyName":"hdipykey18ce41b44","keyVersion":"8dc96189f25541c39c45221d01536eaf","encryptionAlgorithm":"RSA-OAEP","msiResourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/microsoft.managedidentity/userassignedidentities/hdipyuai8ce41b44"}},"identity":{"type":"UserAssigned","userAssignedIdentities":{"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/microsoft.managedidentity/userassignedidentities/hdipyuai8ce41b44":{}}}}'} - headers: - azure-asyncoperation: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview'] - cache-control: [no-cache] - content-length: ['1944'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:03:10 GMT'] - etag: ['"8b2fc785-1ec8-4e36-874a-1793259f42bd"'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-clusteruri: ['https://management.azure.com/subscriptions/964c10bb-8a6c-43bc-83d3-6b318c6c7305/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44?api-version=2018-06-01-preview'] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - x-ms-ratelimit-remaining-subscription-writes: ['1199'] - status: {code: 200, message: OK} + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44","name":"hdisdk-kafka-byok8ce41b44","type":"Microsoft.HDInsight/clusters","location":"North + Central US","etag":"2515b354-0de3-4b9d-be0c-f7df55badceb","tags":{},"properties":{"clusterVersion":"3.6.1000.67","clusterHdpVersion":"","osType":"Linux","clusterDefinition":{"blueprint":"https://blueprints.azurehdinsight.net/kafka-3.6.1000.67.2004291541.json","kind":"Kafka","componentVersion":{"Kafka":"1.1"}},"computeProfile":{"roles":[{"name":"headnode","targetInstanceCount":2,"hardwareProfile":{"vmSize":"standard_a4_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"workernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"standard_a4_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"dataDisksGroups":[{"disksPerNode":8,"storageAccountType":"Standard_LRS","diskSizeGB":1023}],"encryptDataDisks":false},{"name":"zookeepernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"standard_a1_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false}]},"provisioningState":"InProgress","clusterState":"Accepted","createdDate":"2020-06-03T12:41:11.943","quotaInfo":{"coresUsed":23},"tier":"standard","diskEncryptionProperties":{"vaultUri":"https://hdipy8ce41b44..vault.azure.net","keyName":"hdipykey18ce41b44","keyVersion":"830e48e217534b51ad2ddcf2f1ce4adb","encryptionAlgorithm":"RSA-OAEP","msiResourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/microsoft.managedidentity/userassignedidentities/hdipyuai8ce41b44"},"storageProfile":{"storageaccounts":[{"name":"hdipy.blob.core.windows.net","resourceId":null,"msiResourceId":null,"key":null,"fileSystem":null,"container":"hdisdk-kafka-byok8ce41b44","saskey":null,"isDefault":true}]}},"identity":{"type":"UserAssigned","userAssignedIdentities":{"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/microsoft.managedidentity/userassignedidentities/hdipyuai8ce41b44":{}}}}' + headers: + azure-asyncoperation: + - https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview + cache-control: + - no-cache + content-length: + - '2196' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:41:13 GMT + etag: + - '"2515b354-0de3-4b9d-be0c-f7df55badceb"' + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-clusteruri: + - https://management.azure.com/subscriptions/964c10bb-8a6c-43bc-83d3-6b318c6c7305/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44?api-version=2018-06-01-preview + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + x-ms-ratelimit-remaining-subscription-writes: + - '1199' + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:03:41 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:41:45 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:04:13 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:42:16 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:04:43 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:42:47 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:05:14 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:43:17 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:05:45 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:43:48 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:06:16 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:44:19 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:06:47 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:44:49 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:07:18 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:45:20 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:07:50 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:45:50 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:08:21 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:46:22 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:08:52 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:46:53 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:09:22 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:47:23 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:09:53 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:47:54 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:10:25 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:48:25 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:10:55 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:48:55 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:11:26 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:49:26 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:11:57 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:49:57 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:12:29 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:50:27 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:12:59 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:50:59 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:13:30 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:51:30 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:14:02 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:52:00 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:14:32 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:52:31 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:15:04 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:53:02 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"Succeeded"}'} - headers: - cache-control: [no-cache] - content-length: ['22'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:15:34 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:53:32 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44?api-version=2018-06-01-preview + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44","name":"hdisdk-kafka-byok8ce41b44","type":"Microsoft.HDInsight/clusters","location":"North - Central US","etag":"8b2fc785-1ec8-4e36-874a-1793259f42bd","tags":{},"properties":{"clusterVersion":"3.6.1000.67","clusterHdpVersion":"2.6.5.3005-27","osType":"Linux","clusterDefinition":{"blueprint":"https://blueprints.azurehdinsight.net/kafka-3.6.1000.67.1812120705.json","kind":"Kafka","componentVersion":{"Kafka":"1.1"}},"computeProfile":{"roles":[{"name":"headnode","targetInstanceCount":2,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"workernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"dataDisksGroups":[{"disksPerNode":8,"storageAccountType":"Standard_LRS","diskSizeGB":1023}],"encryptDataDisks":false},{"name":"zookeepernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"Small"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false}]},"provisioningState":"Succeeded","clusterState":"Running","createdDate":"2018-12-28T09:03:10.693","quotaInfo":{"coresUsed":23},"connectivityEndpoints":[{"name":"SSH","protocol":"TCP","location":"hdisdk-kafka-byok8ce41b44-ssh.azurehdinsight.net","port":22},{"name":"HTTPS","protocol":"TCP","location":"hdisdk-kafka-byok8ce41b44.azurehdinsight.net","port":443}],"tier":"standard","diskEncryptionProperties":{"vaultUri":"https://hdipy8ce41b44.vault.azure.net","keyName":"hdipykey18ce41b44","keyVersion":"8dc96189f25541c39c45221d01536eaf","encryptionAlgorithm":"RSA-OAEP","msiResourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/microsoft.managedidentity/userassignedidentities/hdipyuai8ce41b44"}},"identity":{"type":"UserAssigned","userAssignedIdentities":{"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/microsoft.managedidentity/userassignedidentities/hdipyuai8ce41b44":{"principalId":"998e4f8e-72c2-439d-86e2-5f1e13db642d","tenantId":"00000000-0000-0000-0000-000000000000"}}}}'} - headers: - cache-control: [no-cache] - content-length: ['2290'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:15:35 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:54:02 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: - body: '{"kty": "RSA"}' + body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - Content-Length: ['14'] - Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-keyvault/7.0 Azure-SDK-For-Python] - accept-language: [en-US] - method: POST - uri: https://hdipy8ce41b44.vault.azure.net/keys/hdipykey28ce41b44/create?api-version=7.0 + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"Succeeded"}' + headers: + cache-control: + - no-cache + content-length: + - '22' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:54:34 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44?api-version=2018-06-01-preview response: - body: {string: '{"key":{"kid":"https://hdipy8ce41b44.vault.azure.net/keys/hdipykey28ce41b44/0e4ed336f038445f9b32ccdccac2f769","kty":"RSA","key_ops":["encrypt","decrypt","sign","verify","wrapKey","unwrapKey"],"n":"sJvTRrrs49qVdFNsIgRy1JM1aPZ7ddfgD_achlCfJxjP94vMb1xxyUY_Rq1hP09nWxAEKczrfoq8TdGS0RjH1ATiJSZaZve_diBKVxyLrRDWOTOyWWOcWXcFBFM8_assu_fte8kvjgq6LQoRgj22QVFR_l8B-YlZ-5P2Ha1khPnkpsH48NCSFYSkCFDlutcDkp-ZD-aQ9JwR4vXBOwcUnTHwqMfF0o4x1EvVdILeDfMoNHk9hYXNLqx0tT9U8ScC4ULlJIyK_7rj8TMDGqXhlPmGqJz7_9udX5mXWu17QMZiHeZMAohXGt5GmlxCGUW5SATTdHlK1vJwsfD1f4HtJw","e":"AQAB"},"attributes":{"enabled":true,"created":1545988536,"updated":1545988536,"recoveryLevel":"Recoverable+Purgeable"}}'} - headers: - cache-control: [no-cache] - content-length: ['665'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:15:37 GMT'] - expires: ['-1'] - pragma: [no-cache] - server: [Microsoft-IIS/10.0] - strict-transport-security: [max-age=31536000;includeSubDomains] - x-aspnet-version: [4.0.30319] - x-content-type-options: [nosniff] - x-ms-keyvault-network-info: [addr=131.107.160.11;act_addr_fam=InterNetwork;] - x-ms-keyvault-region: [North Central US] - x-ms-keyvault-service-version: [1.1.0.859] - x-powered-by: [ASP.NET] - status: {code: 200, message: OK} + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44","name":"hdisdk-kafka-byok8ce41b44","type":"Microsoft.HDInsight/clusters","location":"North + Central US","etag":"2515b354-0de3-4b9d-be0c-f7df55badceb","tags":{},"properties":{"clusterVersion":"3.6.1000.67","clusterHdpVersion":"2.6.5.3022-3","osType":"Linux","clusterDefinition":{"blueprint":"https://blueprints.azurehdinsight.net/kafka-3.6.1000.67.2004291541.json","kind":"Kafka","componentVersion":{"Kafka":"1.1"}},"computeProfile":{"roles":[{"name":"headnode","targetInstanceCount":2,"hardwareProfile":{"vmSize":"standard_a4_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"workernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"standard_a4_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"dataDisksGroups":[{"disksPerNode":8,"storageAccountType":"Standard_LRS","diskSizeGB":1023}],"encryptDataDisks":false},{"name":"zookeepernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"standard_a1_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false}]},"provisioningState":"Succeeded","clusterState":"Running","createdDate":"2020-06-03T12:41:11.943","quotaInfo":{"coresUsed":23},"connectivityEndpoints":[{"name":"SSH","protocol":"TCP","location":"hdisdk-kafka-byok8ce41b44-ssh.azurehdinsight.net","port":22},{"name":"HTTPS","protocol":"TCP","location":"hdisdk-kafka-byok8ce41b44.azurehdinsight.net","port":443}],"tier":"standard","diskEncryptionProperties":{"vaultUri":"https://hdipy8ce41b44..vault.azure.net","keyName":"hdipykey18ce41b44","keyVersion":"830e48e217534b51ad2ddcf2f1ce4adb","encryptionAlgorithm":"RSA-OAEP","msiResourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/microsoft.managedidentity/userassignedidentities/hdipyuai8ce41b44"},"storageProfile":{"storageaccounts":[{"name":"hdipy.blob.core.windows.net","resourceId":null,"msiResourceId":null,"key":null,"fileSystem":null,"container":"hdisdk-kafka-byok8ce41b44","saskey":null,"isDefault":true}]}},"identity":{"type":"UserAssigned","userAssignedIdentities":{"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/microsoft.managedidentity/userassignedidentities/hdipyuai8ce41b44":{"principalId":"1b12fe54-7b96-47a6-8f1b-ba1938623b65","tenantId":"00000000-0000-0000-0000-000000000000"}}}}' + headers: + cache-control: + - no-cache + content-length: + - '2541' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:54:35 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: - body: '{"vaultUri": "https://hdipy8ce41b44.vault.azure.net", "keyName": "hdipykey28ce41b44", - "keyVersion": "0e4ed336f038445f9b32ccdccac2f769"}' - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - Content-Length: ['135'] - Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - accept-language: [en-US] + body: 'b''{"vaultUri": "https://hdipy8ce41b44..vault.azure.net", "keyName": "hdipykey28ce41b44", + "keyVersion": "58ef873805c14c5a9d292aaa20f10ccb"}''' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '135' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python + accept-language: + - en-US method: POST uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/rotatediskencryptionkey?api-version=2018-06-01-preview response: - body: {string: ''} - headers: - azure-asyncoperation: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/3ff45ea6-0c3f-4988-9057-03f87d333490-0-r?api-version=2018-06-01-preview'] - cache-control: [no-cache] - content-length: ['0'] - date: ['Fri, 28 Dec 2018 09:15:39 GMT'] - expires: ['-1'] - location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/operationresults/3ff45ea6-0c3f-4988-9057-03f87d333490-0-r?api-version=2018-06-01-preview'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - x-ms-ratelimit-remaining-subscription-writes: ['1199'] - status: {code: 202, message: Accepted} + body: + string: '' + headers: + azure-asyncoperation: + - https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/9c89483a-13d2-4a90-bbd3-378115386b55-0-r?api-version=2018-06-01-preview + cache-control: + - no-cache + content-length: + - '0' + date: + - Wed, 03 Jun 2020 12:54:37 GMT + expires: + - '-1' + location: + - https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/operationresults/9c89483a-13d2-4a90-bbd3-378115386b55-0-r?api-version=2018-06-01-preview + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + x-ms-ratelimit-remaining-subscription-writes: + - '1199' + status: + code: 202 + message: Accepted - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/3ff45ea6-0c3f-4988-9057-03f87d333490-0-r?api-version=2018-06-01-preview + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/9c89483a-13d2-4a90-bbd3-378115386b55-0-r?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:16:40 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:55:39 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/3ff45ea6-0c3f-4988-9057-03f87d333490-0-r?api-version=2018-06-01-preview + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/9c89483a-13d2-4a90-bbd3-378115386b55-0-r?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:17:11 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:56:09 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/3ff45ea6-0c3f-4988-9057-03f87d333490-0-r?api-version=2018-06-01-preview + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/9c89483a-13d2-4a90-bbd3-378115386b55-0-r?api-version=2018-06-01-preview response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:17:41 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:56:40 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/3ff45ea6-0c3f-4988-9057-03f87d333490-0-r?api-version=2018-06-01-preview + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44/azureasyncoperations/9c89483a-13d2-4a90-bbd3-378115386b55-0-r?api-version=2018-06-01-preview response: - body: {string: '{"status":"Succeeded"}'} - headers: - cache-control: [no-cache] - content-length: ['22'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:18:12 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"status":"Succeeded"}' + headers: + cache-control: + - no-cache + content-length: + - '22' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:57:10 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - accept-language: [en-US] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.4.0 Azure-SDK-For-Python + accept-language: + - en-US method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44?api-version=2018-06-01-preview response: - body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44","name":"hdisdk-kafka-byok8ce41b44","type":"Microsoft.HDInsight/clusters","location":"North - Central US","etag":"8b2fc785-1ec8-4e36-874a-1793259f42bd","tags":{},"properties":{"clusterVersion":"3.6.1000.67","clusterHdpVersion":"2.6.5.3005-27","osType":"Linux","clusterDefinition":{"blueprint":"https://blueprints.azurehdinsight.net/kafka-3.6.1000.67.1812120705.json","kind":"Kafka","componentVersion":{"Kafka":"1.1"}},"computeProfile":{"roles":[{"name":"headnode","targetInstanceCount":2,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"workernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"dataDisksGroups":[{"disksPerNode":8,"storageAccountType":"Standard_LRS","diskSizeGB":1023}],"encryptDataDisks":false},{"name":"zookeepernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"Small"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false}]},"provisioningState":"Succeeded","clusterState":"Running","createdDate":"2018-12-28T09:03:10.693","quotaInfo":{"coresUsed":23},"connectivityEndpoints":[{"name":"SSH","protocol":"TCP","location":"hdisdk-kafka-byok8ce41b44-ssh.azurehdinsight.net","port":22},{"name":"HTTPS","protocol":"TCP","location":"hdisdk-kafka-byok8ce41b44.azurehdinsight.net","port":443}],"tier":"standard","diskEncryptionProperties":{"vaultUri":"https://hdipy8ce41b44.vault.azure.net","keyName":"hdipykey28ce41b44","keyVersion":"0e4ed336f038445f9b32ccdccac2f769","encryptionAlgorithm":"RSA-OAEP","msiResourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/microsoft.managedidentity/userassignedidentities/hdipyuai8ce41b44"}},"identity":{"type":"UserAssigned","userAssignedIdentities":{"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/microsoft.managedidentity/userassignedidentities/hdipyuai8ce41b44":{"principalId":"998e4f8e-72c2-439d-86e2-5f1e13db642d","tenantId":"00000000-0000-0000-0000-000000000000"}}}}'} - headers: - cache-control: [no-cache] - content-length: ['2290'] - content-type: [application/json; charset=utf-8] - date: ['Fri, 28 Dec 2018 09:18:13 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-8ce41b44/providers/Microsoft.HDInsight/clusters/hdisdk-kafka-byok8ce41b44","name":"hdisdk-kafka-byok8ce41b44","type":"Microsoft.HDInsight/clusters","location":"North + Central US","etag":"2515b354-0de3-4b9d-be0c-f7df55badceb","tags":{},"properties":{"clusterVersion":"3.6.1000.67","clusterHdpVersion":"2.6.5.3022-3","osType":"Linux","clusterDefinition":{"blueprint":"https://blueprints.azurehdinsight.net/kafka-3.6.1000.67.2004291541.json","kind":"Kafka","componentVersion":{"Kafka":"1.1"}},"computeProfile":{"roles":[{"name":"headnode","targetInstanceCount":2,"hardwareProfile":{"vmSize":"standard_a4_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"workernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"standard_a4_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"dataDisksGroups":[{"disksPerNode":8,"storageAccountType":"Standard_LRS","diskSizeGB":1023}],"encryptDataDisks":false},{"name":"zookeepernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"standard_a1_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false}]},"provisioningState":"Succeeded","clusterState":"Running","createdDate":"2020-06-03T12:41:11.943","quotaInfo":{"coresUsed":23},"connectivityEndpoints":[{"name":"SSH","protocol":"TCP","location":"hdisdk-kafka-byok8ce41b44-ssh.azurehdinsight.net","port":22},{"name":"HTTPS","protocol":"TCP","location":"hdisdk-kafka-byok8ce41b44.azurehdinsight.net","port":443}],"tier":"standard","diskEncryptionProperties":{"vaultUri":"https://hdipy8ce41b44..vault.azure.net","keyName":"hdipykey28ce41b44","keyVersion":"58ef873805c14c5a9d292aaa20f10ccb","encryptionAlgorithm":"RSA-OAEP","msiResourceId":"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/microsoft.managedidentity/userassignedidentities/hdipyuai8ce41b44"},"storageProfile":{"storageaccounts":[{"name":"hdipy.blob.core.windows.net","resourceId":null,"msiResourceId":null,"key":null,"fileSystem":null,"container":"hdisdk-kafka-byok8ce41b44","saskey":null,"isDefault":true}]}},"identity":{"type":"UserAssigned","userAssignedIdentities":{"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/hdipy-8ce41b44/providers/microsoft.managedidentity/userassignedidentities/hdipyuai8ce41b44":{"principalId":"1b12fe54-7b96-47a6-8f1b-ba1938623b65","tenantId":"00000000-0000-0000-0000-000000000000"}}}}' + headers: + cache-control: + - no-cache + content-length: + - '2541' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 12:57:13 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK version: 1 diff --git a/sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_create_with_adls_gen1.yaml b/sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_create_with_adls_gen1.yaml deleted file mode 100644 index 5f7597fe1f9f..000000000000 --- a/sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_create_with_adls_gen1.yaml +++ /dev/null @@ -1,930 +0,0 @@ -interactions: -- request: - body: 'b''b\''b\\\''b\\\\\\\''{"location": "East US 2", "tags": {}, "properties": - {"clusterVersion": "3.6", "osType": "Linux", "tier": "Standard", "clusterDefinition": - {"kind": "hadoop", "configurations": {"gateway": {"restAuthCredential.isEnabled": - "true", "restAuthCredential.username": "admin", "restAuthCredential.password": - "Password1!"}, "clusterIdentity": {"clusterIdentity.applicationId": "00000000-0000-0000-0000-000000000000", - "clusterIdentity.certificate": "MIIJ8gIBAzCCCa4GCSqGSIb3DQEHAaCCCZ8EggmbMIIJlzCCBgAGCSqGSIb3DQEHAaCCBfEEggXtMIIF6TCCBeUGCyqGSIb3DQEMCgECoIIE9jCCBPIwHAYKKoZIhvcNAQwBAzAOBAiTJstpWcGFZAICB9AEggTQZvg9qVE2ptb3hdH9hnDf5pwIeGghe9assBeEKj/W1JMUjsdEu7qzXH9/3Ro6C1HF6MvSqbav7MD8je9AMb0jl7T3ZmXPgGtrbUsSBTPruVv0hTXPRTxQmcfwae5vEkD03b/4W22sXMMYZB7wOTQMl1d5+0wt267qdF+G1XWtRI2jnxetK8/oyMQxn5Cwuz/VAmn1tXwRAN9gIiZDA8MwvpYha/iFVWKu/vnHg8HT47ry+27/wh8ifM9ea7JWhKh2tZoPIMou9/P/CgkkMv9KVHlmiMldA3Phxsrqjbh/wbd8RWBOtSM7rryMVnc1MYonZraDJMGOLGAhvEcXNBKLwRdmrDDYvpOYlDYKlmNvDXYDm410XCOia2aKP0WoP4qLsExtUwW8Qk2r2QRy5O4B5p2EbPZBlPlMMO4S1NkASjJCghuTCUgvk3uwe2L/mMf0IajAf+R0/VW/fXHbhJkFKobi5JlIqWaHsSC7hMidWj6771Yi8UEXOMshWERs2UHH05aIO3c50lnyypHyhA3BohKUXzNhHA0o7ImQRjmjjTJFBLMNiIZSW0aPtLN1+92pT0a6iS7P1PC0DqEnOjkcs/VOUI3qTt0X78b6wnDO+ATo39B13njGD0mtrVvtTeHclBouoFzpKHkS86GSGmDoHQH6EHhpGF/7wPVfAjAiSrNQb/QLjPHWo+BeiOml4Xrti0K6rWb0AXhY8AmtIlEUC9GscDSdT55v9j9tWONzOXECCgZBYDzNlagMLkCDIFHZwbEGPn3pOc7BTOmQf1GQjfvunLiLWWfe3of9pR+NCDyi1VJUNvjoE+/YnVoBBUMBBO6/4t2SL92iouEF4fyqkQFDb0FOPW4Kfh7H5W+sDZIN9NfqNzniK6HFcpS+jnGm9x9rx81DmMcwtiYZTfYDSivtNxOYrmRFXx574stBzvG0En11uc6E4QhWnkCSsBnnOMjRGDyv95BFVMZC0gIS0rWoKYxjdblpmo9w/yfDtAmQuCs3bdqcJ4mMYt0ueUUZImPRQRJOSrVyoq+brLw657EqM1SahtBmzTG7+HTl1Qi/xZ1xmz6paQDSFVPRcb5QSIp4v08j/Lmj0x4R9jQ4cAmZ3CfPKXBKuIRu2AI2EuqGOoAxvQQEpSjSKUs3fbQxjptUhK7o5FcXAfAxHLzdx2/9L1Iqbo/3HDkbmuix24NRXESG0e/kVr7VAGhoALI7L+eKAdn4AkgmBt55FXZ+uHY9bSKZUoz4Oed2bz2A+9sQBcXG06fLqQEwGVPhATEbYyRduuY6AdTRAmOKmadT5BTTD7+dnFlIt+u7ZpbXm6S6LcSqGqHVacig27SwDt0VznQsjMRDVCiHaWKg4W78xbP7YVvNTB/cBCHmhh5ZXfO/TucizXsQPJlwEMr2CbqByqldXi0i1GUrbg4aLUGZtxgUYex7dHlx6GUejOGRh7fLYCNBo43pjCFvbhFwb0/dWya0crJjpGiY3DNtl1YosJBmvso/Rli4QqVeN7tb45ZsGWTEUg1MDeoGRDqal7GDsvBnH574T5Sz3nSLAoNXR7k0rYaWhezJNobo/SDkuSXskVjNJpv+vjEyW2UGYNhaeK/UHKBP8IrmSAEIZejQj6OEzSPM6TNLW5qJb6LK9agxgdswEwYJKoZIhvcNAQkVMQYEBAEAAAAwXQYJKwYBBAGCNxEBMVAeTgBNAGkAYwByAG8AcwBvAGYAdAAgAFMAdAByAG8AbgBnACAAQwByAHkAcAB0AG8AZwByAGEAcABoAGkAYwAgAFAAcgBvAHYAaQBkAGUAcjBlBgkqhkiG9w0BCRQxWB5WAFAAdgBrAFQAbQBwADoAMAAyAGYAZQA0AGUAOAAzAC0AMgAzADEANgAtADQAMQA3AGMALQA5ADQANQBjAC0AZgA1ADUAMABhADUAZAAwAGIAMAAzAGEwggOPBgkqhkiG9w0BBwagggOAMIIDfAIBADCCA3UGCSqGSIb3DQEHATAcBgoqhkiG9w0BDAEDMA4ECAR1hzovrDkgAgIH0ICCA0gq6boOLRoE5PHFfVIXYtzqg1u2vPMm5mgBUvrh3u+VZ/1FMGTj8od9+Yu91cnumVSgfRiGq7lz+K6by5JsBqP68ksLA2d/PqtTdofCoZ7SgVIo+qqzA64HIQFkElNpo/BJMX/JGpc5OlFq7mdHe6xL2Pfx/3z/pNSV+D+WaAwaDnbLqI7MU6ED3j5l63mExk/8H/VVbiPdqMTzbhIp65oHTGanw86w7RlywqeNb3DkPVMB78Jhcg8vf2AxB8hKf6QiO2uJc/4WKkyLoLmNoD/zhaoUuAbC6hrNVAa9VRWNRfwKZrzwIMSLlKYwWmVcD/QgC8gwxuF+wV3UHwDNAdEe8TEsOhE99/ZiUiogxMdkopZwwtZMszzBB/x5mHCGySauDMVPwoYT6QXewJhGrUap0jwB/Vzy5FaWHi/m8964zWpwC6xfkT2hkDb+rfouWutpiAgMne5tD9YvqxTUmZFIlgwpLrVdPcKQS+b/uIXPTv8uW177XsCOmGGu728ld8H1Ifb2nPveK09Y0AA+ARFpOX0p0ZuxMQqk6NnlA+eESJVm5cLfKszorRcrNPINXaEOGl2okuijm8va30FH9GIYWRt+Be6s8qG672aTO/2eHaTHeR/qQ9aEt0ASDXGcugYS14Jnu2wbauyvotZ6eAvgl5tM2leMpgSLaQqYzPTV2uiD6zDUqxwjm2P8EZQihEQqLUV1jvQuQB4Ui7MryDQ+QiDBD2m5c+9SDPafcR7qgRe/cP4hj5BqzHTcNQAD5BLXze7Yx+TMdf+Qe/R1uBYm8bLjUv9hwUmtMeZP4RU6RPJrN2aRf7BUdgS0j/8YAhxViPucRENuhEfS4sotHf1CJZ7xJz0ZE9cpVY6JLl1tbmuf1Eh50cicZ1SHQhqSP0ggLHV6DNcJz+kyekEe9qggGDi6mreYz/kJnnumsDy5cToIHy9jJhtXzj+/ZNGkdpq9HWMiwAT/VR1WPpzjn06m7Z87PiLaiC3simQtjnl0gVF11Ev4rbIhYjFBL0nKfNpzaWlMaOVF+EumROk3EbZVpx1K6Yh0zWh/NocWSUrtSoHVklzwPCNRvnE1Ehyw5t9YbEBsTIDWRYyqbVYoFVfOUhq5p4TXrqEwOzAfMAcGBSsOAwIaBBSx7sJo66zYk4VOsgD9V/co1SikFAQUUvU/kE4wTRnPRnaWXnno+FCb56kCAgfQ", - "clusterIdentity.aadTenantId": "https://login.windows.net/00000000-0000-0000-0000-000000000000", - "clusterIdentity.resourceUri": "https://datalake.azure.net/", "clusterIdentity.certificatePassword": - "123"}, "core-site": {"fs.defaultFS": "adl://home", "dfs.adls.home.hostname": - "fakehdiadlsaccount.azuredatalakestore.net", "dfs.adls.home.mountpoint": "/clusters/hdi"}}}, - "computeProfile": {"roles": [{"name": "headnode", "targetInstanceCount": 2, - "hardwareProfile": {"vmSize": "Large"}, "osProfile": {"linuxOperatingSystemProfile": - {"username": "sshuser", "password": "Password1!"}}}, {"name": "workernode", - "targetInstanceCount": 3, "hardwareProfile": {"vmSize": "Large"}, "osProfile": - {"linuxOperatingSystemProfile": {"username": "sshuser", "password": "Password1!"}}}, - {"name": "zookeepernode", "targetInstanceCount": 3, "hardwareProfile": {"vmSize": - "Small"}, "osProfile": {"linuxOperatingSystemProfile": {"username": "sshuser", - "password": "Password1!"}}}]}, "storageProfile": {"storageaccounts": [{"name": - "hdipybcf5129f.blob.core.windows.net", "isDefault": false, "container": "hdisdk-adlsgen1bcf5129f", - "key": "TkbluDiyifRIM9uhGTWeoe66m6GV9cIAezOY/hC0XCQ6DNje1ZgpuIo4769Eb0aNxd5O7Zun2YomPQBPMLsZgg=="}]}}}\\\\\\\''\\\''\''''' - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - Content-Length: ['5044'] - Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - accept-language: [en-US] - method: PUT - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f?api-version=2018-06-01-preview - response: - body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f","name":"hdisdk-adlsgen1bcf5129f","type":"Microsoft.HDInsight/clusters","location":"East - US 2","etag":"e012fb8d-f502-42b1-93ce-fd0bd46aa8b3","tags":{},"properties":{"clusterVersion":"3.6.1000.67","clusterHdpVersion":"","osType":"Linux","clusterDefinition":{"blueprint":"https://blueprints.azurehdinsight.net/hadoop-3.6.1000.67.1812120705.json","kind":"hadoop","componentVersion":{"hadoop":"2.7"}},"computeProfile":{"roles":[{"name":"headnode","targetInstanceCount":2,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"workernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"zookeepernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"Medium"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false}]},"provisioningState":"InProgress","clusterState":"Accepted","createdDate":"2018-12-29T02:19:48.243","quotaInfo":{"coresUsed":20},"tier":"standard"}}'} - headers: - azure-asyncoperation: ['https://management.azure.com:443/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview'] - cache-control: [no-cache] - content-length: ['1252'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:19:49 GMT'] - etag: ['"e012fb8d-f502-42b1-93ce-fd0bd46aa8b3"'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-clusteruri: ['https://management.azure.com/subscriptions/964c10bb-8a6c-43bc-83d3-6b318c6c7305/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f?api-version=2018-06-01-preview'] - x-ms-hdi-served-by: [global] - x-ms-ratelimit-remaining-subscription-writes: ['1199'] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:20:19 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:20:51 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:21:22 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:21:53 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:22:25 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:22:55 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:23:26 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:23:57 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:24:28 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:24:59 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:25:31 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:26:01 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:26:32 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:27:04 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:27:34 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:28:06 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:28:36 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:29:07 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:29:39 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:30:09 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:30:40 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:31:11 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:31:43 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:32:14 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:32:44 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:33:16 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:33:46 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:34:18 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:34:49 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:35:19 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:35:51 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:36:23 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:36:53 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"Succeeded"}'} - headers: - cache-control: [no-cache] - content-length: ['22'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:37:24 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f?api-version=2018-06-01-preview - response: - body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-bcf5129f/providers/Microsoft.HDInsight/clusters/hdisdk-adlsgen1bcf5129f","name":"hdisdk-adlsgen1bcf5129f","type":"Microsoft.HDInsight/clusters","location":"East - US 2","etag":"e012fb8d-f502-42b1-93ce-fd0bd46aa8b3","tags":{},"properties":{"clusterVersion":"3.6.1000.67","clusterHdpVersion":"2.6.5.3005-27","osType":"Linux","clusterDefinition":{"blueprint":"https://blueprints.azurehdinsight.net/hadoop-3.6.1000.67.1812120705.json","kind":"hadoop","componentVersion":{"hadoop":"2.7"}},"computeProfile":{"roles":[{"name":"headnode","targetInstanceCount":2,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"workernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"zookeepernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"Medium"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false}]},"provisioningState":"Succeeded","clusterState":"Running","createdDate":"2018-12-29T02:19:48.243","quotaInfo":{"coresUsed":20},"connectivityEndpoints":[{"name":"SSH","protocol":"TCP","location":"hdisdk-adlsgen1bcf5129f-ssh.azurehdinsight.net","port":22},{"name":"HTTPS","protocol":"TCP","location":"hdisdk-adlsgen1bcf5129f.azurehdinsight.net","port":443}],"tier":"standard"}}'} - headers: - cache-control: [no-cache] - content-length: ['1492'] - content-type: [application/json; charset=utf-8] - date: ['Sat, 29 Dec 2018 02:37:26 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-served-by: [global] - status: {code: 200, message: OK} -version: 1 diff --git a/sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_gateway_settings.yaml b/sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_gateway_settings.yaml new file mode 100644 index 000000000000..d0891ab0cbb9 --- /dev/null +++ b/sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_gateway_settings.yaml @@ -0,0 +1,1507 @@ +interactions: +- request: + body: 'b''{"location": "North Central US", "tags": {}, "properties": {"clusterVersion": + "3.6", "osType": "Linux", "tier": "Standard", "clusterDefinition": {"kind": + "hadoop", "configurations": {"gateway": {"restAuthCredential.isEnabled": "true", + "restAuthCredential.username": "admin", "restAuthCredential.password": "Password1!"}}}, + "computeProfile": {"roles": [{"name": "headnode", "targetInstanceCount": 2, + "hardwareProfile": {"vmSize": "Large"}, "osProfile": {"linuxOperatingSystemProfile": + {"username": "sshuser", "password": "Password1!"}}}, {"name": "workernode", + "targetInstanceCount": 3, "hardwareProfile": {"vmSize": "Large"}, "osProfile": + {"linuxOperatingSystemProfile": {"username": "sshuser", "password": "Password1!"}}}, + {"name": "zookeepernode", "targetInstanceCount": 3, "hardwareProfile": {"vmSize": + "Small"}, "osProfile": {"linuxOperatingSystemProfile": {"username": "sshuser", + "password": "Password1!"}}}]}, "storageProfile": {"storageaccounts": [{"name": + "hdipy.blob.core.windows.net", "isDefault": true, "container": "hdisdk-http64501105", + "key": "fyuFawWCkHUCWVfGKU/NI0ncpS1oQM5S4NGi3Yt5h4dXKBFM5hlB/OAVLd4wCE8b17ecLWZuopcfu3XKFho5rQ=="}]}}}''' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '1160' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + accept-language: + - en-US + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105?api-version=2018-06-01-preview + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105","name":"hdisdk-http64501105","type":"Microsoft.HDInsight/clusters","location":"North + Central US","etag":"ede1f50f-d36e-412d-9f7b-abe90fc85fe5","tags":{},"properties":{"clusterVersion":"3.6.1000.67","clusterHdpVersion":"","osType":"Linux","clusterDefinition":{"blueprint":"https://blueprints.azurehdinsight.net/hadoop-3.6.1000.67.2004291541.json","kind":"hadoop","componentVersion":{"hadoop":"2.7"}},"computeProfile":{"roles":[{"name":"headnode","targetInstanceCount":2,"hardwareProfile":{"vmSize":"standard_a4_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"workernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"standard_a4_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"zookeepernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"standard_a2_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false}]},"provisioningState":"InProgress","clusterState":"Accepted","createdDate":"2020-06-03T09:05:26.587","quotaInfo":{"coresUsed":20},"tier":"standard","storageProfile":{"storageaccounts":[{"name":"hdipy.blob.core.windows.net","resourceId":null,"msiResourceId":null,"key":null,"fileSystem":null,"container":"hdisdk-http64501105","saskey":null,"isDefault":true}]}}}' + headers: + azure-asyncoperation: + - https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + cache-control: + - no-cache + content-length: + - '1496' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:05:29 GMT + etag: + - '"ede1f50f-d36e-412d-9f7b-abe90fc85fe5"' + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-clusteruri: + - https://management.azure.com/subscriptions/964c10bb-8a6c-43bc-83d3-6b318c6c7305/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105?api-version=2018-06-01-preview + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + x-ms-ratelimit-remaining-subscription-writes: + - '1198' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:06:00 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:06:31 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:07:01 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:07:32 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:08:02 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:08:33 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:09:03 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:09:33 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:10:04 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:10:35 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:11:05 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:11:35 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:12:06 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:12:37 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:13:07 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:13:38 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:14:08 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:14:39 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:15:09 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:15:40 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:16:11 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:16:41 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:17:11 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:17:42 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/create?api-version=2018-06-01-preview + response: + body: + string: '{"status":"Succeeded"}' + headers: + cache-control: + - no-cache + content-length: + - '22' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:18:12 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105?api-version=2018-06-01-preview + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105","name":"hdisdk-http64501105","type":"Microsoft.HDInsight/clusters","location":"North + Central US","etag":"ede1f50f-d36e-412d-9f7b-abe90fc85fe5","tags":{},"properties":{"clusterVersion":"3.6.1000.67","clusterHdpVersion":"2.6.5.3022-3","osType":"Linux","clusterDefinition":{"blueprint":"https://blueprints.azurehdinsight.net/hadoop-3.6.1000.67.2004291541.json","kind":"hadoop","componentVersion":{"hadoop":"2.7"}},"computeProfile":{"roles":[{"name":"headnode","targetInstanceCount":2,"hardwareProfile":{"vmSize":"standard_a4_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"workernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"standard_a4_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"zookeepernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"standard_a2_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false}]},"provisioningState":"Succeeded","clusterState":"Running","createdDate":"2020-06-03T09:05:26.587","quotaInfo":{"coresUsed":20},"connectivityEndpoints":[{"name":"SSH","protocol":"TCP","location":"hdisdk-http64501105-ssh.azurehdinsight.net","port":22},{"name":"HTTPS","protocol":"TCP","location":"hdisdk-http64501105.azurehdinsight.net","port":443}],"tier":"standard","storageProfile":{"storageaccounts":[{"name":"hdipy.blob.core.windows.net","resourceId":null,"msiResourceId":null,"key":null,"fileSystem":null,"container":"hdisdk-http64501105","saskey":null,"isDefault":true}]}}}' + headers: + cache-control: + - no-cache + content-length: + - '1727' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:18:13 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + accept-language: + - en-US + method: POST + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/getGatewaySettings?api-version=2018-06-01-preview + response: + body: + string: '{"restAuthCredential.isEnabled":"true","restAuthCredential.username":"admin","restAuthCredential.password":"Password1!"}' + headers: + cache-control: + - no-cache + content-length: + - '120' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:18:14 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + x-ms-ratelimit-remaining-subscription-writes: + - '1199' + status: + code: 200 + message: OK +- request: + body: '{"restAuthCredential.isEnabled": true, "restAuthCredential.username": "admin", + "restAuthCredential.password": "NewPassword1!"}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '126' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + accept-language: + - en-US + method: POST + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/updateGatewaySettings?api-version=2018-06-01-preview + response: + body: + string: '' + headers: + azure-asyncoperation: + - https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/8d5a4692-38ea-4524-a1d1-ada06d8d36ff-0-r?api-version=2018-06-01-preview + cache-control: + - no-cache + content-length: + - '0' + date: + - Wed, 03 Jun 2020 09:18:15 GMT + expires: + - '-1' + location: + - https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/operationresults/8d5a4692-38ea-4524-a1d1-ada06d8d36ff-0-r?api-version=2018-06-01-preview + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + x-ms-ratelimit-remaining-subscription-writes: + - '1198' + status: + code: 202 + message: Accepted +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/azureasyncoperations/8d5a4692-38ea-4524-a1d1-ada06d8d36ff-0-r?api-version=2018-06-01-preview + response: + body: + string: '{"status":"Succeeded"}' + headers: + cache-control: + - no-cache + content-length: + - '22' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:19:18 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + accept-language: + - en-US + method: POST + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-64501105/providers/Microsoft.HDInsight/clusters/hdisdk-http64501105/getGatewaySettings?api-version=2018-06-01-preview + response: + body: + string: '{"restAuthCredential.isEnabled":"true","restAuthCredential.username":"admin","restAuthCredential.password":"NewPassword1!"}' + headers: + cache-control: + - no-cache + content-length: + - '123' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:19:19 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + x-ms-ratelimit-remaining-subscription-writes: + - '1197' + status: + code: 200 + message: OK +version: 1 diff --git a/sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_http_extended.yaml b/sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_http_extended.yaml deleted file mode 100644 index 1f6625a2944e..000000000000 --- a/sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_http_extended.yaml +++ /dev/null @@ -1,1164 +0,0 @@ -interactions: -- request: - body: '{"location": "North Central US", "tags": {}, "properties": {"clusterVersion": - "3.6", "osType": "Linux", "tier": "Standard", "clusterDefinition": {"kind": - "hadoop", "configurations": {"gateway": {"restAuthCredential.isEnabled": "true", - "restAuthCredential.username": "admin", "restAuthCredential.password": "Password1!"}}}, - "computeProfile": {"roles": [{"name": "headnode", "targetInstanceCount": 2, - "hardwareProfile": {"vmSize": "Large"}, "osProfile": {"linuxOperatingSystemProfile": - {"username": "sshuser", "password": "Password1!"}}}, {"name": "workernode", - "targetInstanceCount": 3, "hardwareProfile": {"vmSize": "Large"}, "osProfile": - {"linuxOperatingSystemProfile": {"username": "sshuser", "password": "Password1!"}}}, - {"name": "zookeepernode", "targetInstanceCount": 3, "hardwareProfile": {"vmSize": - "Small"}, "osProfile": {"linuxOperatingSystemProfile": {"username": "sshuser", - "password": "Password1!"}}}]}, "storageProfile": {"storageaccounts": [{"name": - "hdipy33370fb3.blob.core.windows.net", "isDefault": true, "container": "hdisdk-http33370fb3", - "key": "QjPI8i2SeLFBj+mY1TqGenoLfINAaiJFWePiXS17fcL9Q8Ox/RIkWxATvMbomQZ72kBkaJTpB/iVNjG8Cl8KNA=="}]}}}' - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - Content-Length: ['1160'] - Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - accept-language: [en-US] - method: PUT - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3?api-version=2018-06-01-preview - response: - body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3","name":"hdisdk-http33370fb3","type":"Microsoft.HDInsight/clusters","location":"North - Central US","etag":"5fdccf81-5141-4144-960e-4312a7672fe0","tags":{},"properties":{"clusterVersion":"3.6.1000.67","clusterHdpVersion":"","osType":"Linux","clusterDefinition":{"blueprint":"https://blueprints.azurehdinsight.net/hadoop-3.6.1000.67.1812120705.json","kind":"hadoop","componentVersion":{"hadoop":"2.7"}},"computeProfile":{"roles":[{"name":"headnode","targetInstanceCount":2,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"workernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"zookeepernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"Medium"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false}]},"provisioningState":"InProgress","clusterState":"Accepted","createdDate":"2018-12-25T09:31:18.527","quotaInfo":{"coresUsed":20},"tier":"standard"}}'} - headers: - azure-asyncoperation: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview'] - cache-control: [no-cache] - content-length: ['1251'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:31:18 GMT'] - etag: ['"5fdccf81-5141-4144-960e-4312a7672fe0"'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-clusteruri: ['https://management.azure.com/subscriptions/964c10bb-8a6c-43bc-83d3-6b318c6c7305/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3?api-version=2018-06-01-preview'] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - x-ms-ratelimit-remaining-subscription-writes: ['1199'] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:31:49 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:32:20 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:32:52 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:33:23 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:33:54 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:34:24 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:34:56 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:35:27 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:35:57 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:36:28 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:37:00 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:37:30 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:38:01 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:38:32 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:39:03 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:39:34 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:40:05 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:40:36 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:41:07 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:41:38 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:42:08 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:42:40 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:43:10 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:43:42 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:44:13 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:44:44 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:45:15 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:45:46 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:46:17 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:46:48 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:47:18 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:47:49 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:48:20 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:48:52 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"InProgress"}'} - headers: - cache-control: [no-cache] - content-length: ['23'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:49:23 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/create?api-version=2018-06-01-preview - response: - body: {string: '{"status":"Succeeded"}'} - headers: - cache-control: [no-cache] - content-length: ['22'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:49:54 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3?api-version=2018-06-01-preview - response: - body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3","name":"hdisdk-http33370fb3","type":"Microsoft.HDInsight/clusters","location":"North - Central US","etag":"5fdccf81-5141-4144-960e-4312a7672fe0","tags":{},"properties":{"clusterVersion":"3.6.1000.67","clusterHdpVersion":"2.6.5.3005-27","osType":"Linux","clusterDefinition":{"blueprint":"https://blueprints.azurehdinsight.net/hadoop-3.6.1000.67.1812120705.json","kind":"hadoop","componentVersion":{"hadoop":"2.7"}},"computeProfile":{"roles":[{"name":"headnode","targetInstanceCount":2,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"workernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"zookeepernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"Medium"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false}]},"provisioningState":"Succeeded","clusterState":"Running","createdDate":"2018-12-25T09:31:18.527","quotaInfo":{"coresUsed":20},"connectivityEndpoints":[{"name":"SSH","protocol":"TCP","location":"hdisdk-http33370fb3-ssh.azurehdinsight.net","port":22},{"name":"HTTPS","protocol":"TCP","location":"hdisdk-http33370fb3.azurehdinsight.net","port":443}],"tier":"standard"}}'} - headers: - cache-control: [no-cache] - content-length: ['1483'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:49:55 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - accept-language: [en-US] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/configurations/gateway?api-version=2018-06-01-preview - response: - body: {string: '{"restAuthCredential.isEnabled":"true","restAuthCredential.username":"admin","restAuthCredential.password":"Password1!"}'} - headers: - cache-control: [no-cache] - content-length: ['120'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:49:56 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: '{"restAuthCredential.isEnabled": "true", "restAuthCredential.username": - "admin", "restAuthCredential.password": "NewPassword1!"}' - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - Content-Length: ['128'] - Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - accept-language: [en-US] - method: POST - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/configurations/gateway?api-version=2018-06-01-preview - response: - body: {string: ''} - headers: - azure-asyncoperation: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/d1409e55-9cf3-4543-b85d-5ba458ad4da3-0-r?api-version=2018-06-01-preview'] - cache-control: [no-cache] - content-length: ['0'] - date: ['Tue, 25 Dec 2018 09:49:56 GMT'] - expires: ['-1'] - location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/operationresults/d1409e55-9cf3-4543-b85d-5ba458ad4da3-0-r?api-version=2018-06-01-preview'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - x-ms-ratelimit-remaining-subscription-writes: ['1199'] - status: {code: 202, message: Accepted} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/azureasyncoperations/d1409e55-9cf3-4543-b85d-5ba458ad4da3-0-r?api-version=2018-06-01-preview - response: - body: {string: '{"status":"Succeeded"}'} - headers: - cache-control: [no-cache] - content-length: ['22'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:50:58 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -- request: - body: null - headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - accept-language: [en-US] - method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-33370fb3/providers/Microsoft.HDInsight/clusters/hdisdk-http33370fb3/configurations/gateway?api-version=2018-06-01-preview - response: - body: {string: '{"restAuthCredential.isEnabled":"true","restAuthCredential.username":"admin","restAuthCredential.password":"NewPassword1!"}'} - headers: - cache-control: [no-cache] - content-length: ['123'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 09:50:59 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} -version: 1 diff --git a/sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_hue_on_running_cluster.yaml b/sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_hue_on_running_cluster.yaml index 7b0b04385367..10db33ebb1b3 100644 --- a/sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_hue_on_running_cluster.yaml +++ b/sdk/hdinsight/azure-mgmt-hdinsight/test/recordings/test_mgmt_hdinsight.test_hue_on_running_cluster.yaml @@ -1,104 +1,174 @@ interactions: - request: - body: '{"location": "North Central US", "tags": {}, "properties": {"clusterVersion": + body: 'b''{"location": "North Central US", "tags": {}, "properties": {"clusterVersion": "3.6", "osType": "Linux", "tier": "Standard", "clusterDefinition": {"kind": - "hadoop", "configurations": {"gateway": {"restAuthCredential.isEnabled": - "true", "restAuthCredential.username": "admin", "restAuthCredential.password": - "Password1!"}}}, "computeProfile": {"roles": [{"name": "headnode", "targetInstanceCount": - 2, "hardwareProfile": {"vmSize": "Large"}, "osProfile": {"linuxOperatingSystemProfile": + "hadoop", "configurations": {"gateway": {"restAuthCredential.isEnabled": "true", + "restAuthCredential.username": "admin", "restAuthCredential.password": "Password1!"}}}, + "computeProfile": {"roles": [{"name": "headnode", "targetInstanceCount": 2, + "hardwareProfile": {"vmSize": "Large"}, "osProfile": {"linuxOperatingSystemProfile": {"username": "sshuser", "password": "Password1!"}}}, {"name": "workernode", - "targetInstanceCount": 1, "hardwareProfile": {"vmSize": "Large"}, "osProfile": - {"linuxOperatingSystemProfile": {"username": "sshuser", "password": "Password1!"}}}]}, - "storageProfile": {"storageaccounts": [{"name": "hdipyd29c1382.blob.core.windows.net", - "isDefault": true, "container": "hdisdk-applications-hued29c1382", "key": "TGsFHWwXRVNlFKURgc5OiS+ishTKFpqrZVJQL794VZKIjO2UvqOwP5dhirF3/DDMNxZWmi+Xq8DDkuRCYeIFHw=="}]}}}' + "targetInstanceCount": 3, "hardwareProfile": {"vmSize": "Large"}, "osProfile": + {"linuxOperatingSystemProfile": {"username": "sshuser", "password": "Password1!"}}}, + {"name": "zookeepernode", "targetInstanceCount": 3, "hardwareProfile": {"vmSize": + "Small"}, "osProfile": {"linuxOperatingSystemProfile": {"username": "sshuser", + "password": "Password1!"}}}]}, "storageProfile": {"storageaccounts": [{"name": + "hdipy.blob.core.windows.net", "isDefault": true, "container": "hdisdk-applications-hued29c1382", + "key": "8sFiS5xxlEDcIC3Q252wR9menGs5x6KaZw2DizQOat/oPUOUCYj6O4UhkSTbOxcy85yvfAljZYaKiN2cK6MHog=="}]}}}''' headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - Content-Length: ['991'] - Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - accept-language: [en-US] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '1172' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + accept-language: + - en-US method: PUT uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382?api-version=2018-06-01-preview response: - body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382","name":"hdisdk-applications-hued29c1382","type":"Microsoft.HDInsight/clusters","location":"North - Central US","etag":"b82c89e7-923d-4a01-b48e-ba4731f1150d","tags":{},"properties":{"clusterVersion":"3.6.1000.67","clusterHdpVersion":"2.6.5.3005-27","osType":"Linux","clusterDefinition":{"blueprint":"https://blueprints.azurehdinsight.net/hadoop-3.6.1000.67.1812120705.json","kind":"hadoop","componentVersion":{"hadoop":"2.7"}},"computeProfile":{"roles":[{"name":"headnode","targetInstanceCount":2,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"workernode","targetInstanceCount":1,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"zookeepernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"Medium"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"edgenode1","targetInstanceCount":1,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false}]},"provisioningState":"Succeeded","clusterState":"Running","createdDate":"2018-12-24T11:39:00.623","quotaInfo":{"coresUsed":16},"connectivityEndpoints":[{"name":"SSH","protocol":"TCP","location":"hdisdk-applications-hued29c1382-ssh.azurehdinsight.net","port":22},{"name":"HTTPS","protocol":"TCP","location":"hdisdk-applications-hued29c1382.azurehdinsight.net","port":443}],"tier":"standard"}}'} + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382","name":"hdisdk-applications-hued29c1382","type":"Microsoft.HDInsight/clusters","location":"North + Central US","etag":"27a1e167-8d5d-4c61-9503-8ca86abde447","tags":{},"properties":{"clusterVersion":"3.6.1000.67","clusterHdpVersion":"2.6.5.3022-3","osType":"Linux","clusterDefinition":{"blueprint":"https://blueprints.azurehdinsight.net/hadoop-3.6.1000.67.2004291541.json","kind":"hadoop","componentVersion":{"hadoop":"2.7"}},"computeProfile":{"roles":[{"name":"headnode","targetInstanceCount":2,"hardwareProfile":{"vmSize":"standard_a4_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"workernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"standard_a4_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"zookeepernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"standard_a2_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"edgenode1","targetInstanceCount":1,"hardwareProfile":{"vmSize":"standard_a4_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false}]},"provisioningState":"Succeeded","clusterState":"Running","createdDate":"2020-06-03T09:10:55.02","quotaInfo":{"coresUsed":24},"connectivityEndpoints":[{"name":"SSH","protocol":"TCP","location":"hdisdk-applications-hued29c1382-ssh.azurehdinsight.net","port":22},{"name":"HTTPS","protocol":"TCP","location":"hdisdk-applications-hued29c1382.azurehdinsight.net","port":443}],"tier":"standard","storageProfile":{"storageaccounts":[{"name":"hdipy.blob.core.windows.net","resourceId":null,"msiResourceId":null,"key":null,"fileSystem":null,"container":"hdisdk-applications-hued29c1382","saskey":null,"isDefault":true}]}}}' headers: - azure-asyncoperation: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/azureasyncoperations/create?api-version=2018-06-01-preview'] - cache-control: [no-cache] - content-length: ['1705'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 02:59:12 GMT'] - etag: ['"b82c89e7-923d-4a01-b48e-ba4731f1150d"'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-clusteruri: ['https://management.azure.com/subscriptions/964c10bb-8a6c-43bc-83d3-6b318c6c7305/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382?api-version=2018-06-01-preview'] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - x-ms-ratelimit-remaining-subscription-writes: ['1198'] - status: {code: 200, message: OK} + azure-asyncoperation: + - https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/azureasyncoperations/create?api-version=2018-06-01-preview + cache-control: + - no-cache + content-length: + - '1969' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:58:45 GMT + etag: + - '"27a1e167-8d5d-4c61-9503-8ca86abde447"' + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-clusteruri: + - https://management.azure.com/subscriptions/964c10bb-8a6c-43bc-83d3-6b318c6c7305/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382?api-version=2018-06-01-preview + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + x-ms-ratelimit-remaining-subscription-writes: + - '1198' + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"Succeeded"}'} + body: + string: '{"status":"Succeeded"}' headers: - cache-control: [no-cache] - content-length: ['22'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 02:59:43 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + cache-control: + - no-cache + content-length: + - '22' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:59:16 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382?api-version=2018-06-01-preview response: - body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382","name":"hdisdk-applications-hued29c1382","type":"Microsoft.HDInsight/clusters","location":"North - Central US","etag":"b82c89e7-923d-4a01-b48e-ba4731f1150d","tags":{},"properties":{"clusterVersion":"3.6.1000.67","clusterHdpVersion":"2.6.5.3005-27","osType":"Linux","clusterDefinition":{"blueprint":"https://blueprints.azurehdinsight.net/hadoop-3.6.1000.67.1812120705.json","kind":"hadoop","componentVersion":{"hadoop":"2.7"}},"computeProfile":{"roles":[{"name":"headnode","targetInstanceCount":2,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"workernode","targetInstanceCount":1,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"zookeepernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"Medium"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"edgenode1","targetInstanceCount":1,"hardwareProfile":{"vmSize":"Large"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false}]},"provisioningState":"Succeeded","clusterState":"Running","createdDate":"2018-12-24T11:39:00.623","quotaInfo":{"coresUsed":16},"connectivityEndpoints":[{"name":"SSH","protocol":"TCP","location":"hdisdk-applications-hued29c1382-ssh.azurehdinsight.net","port":22},{"name":"HTTPS","protocol":"TCP","location":"hdisdk-applications-hued29c1382.azurehdinsight.net","port":443}],"tier":"standard"}}'} + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382","name":"hdisdk-applications-hued29c1382","type":"Microsoft.HDInsight/clusters","location":"North + Central US","etag":"27a1e167-8d5d-4c61-9503-8ca86abde447","tags":{},"properties":{"clusterVersion":"3.6.1000.67","clusterHdpVersion":"2.6.5.3022-3","osType":"Linux","clusterDefinition":{"blueprint":"https://blueprints.azurehdinsight.net/hadoop-3.6.1000.67.2004291541.json","kind":"hadoop","componentVersion":{"hadoop":"2.7"}},"computeProfile":{"roles":[{"name":"headnode","targetInstanceCount":2,"hardwareProfile":{"vmSize":"standard_a4_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"workernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"standard_a4_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"zookeepernode","targetInstanceCount":3,"hardwareProfile":{"vmSize":"standard_a2_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false},{"name":"edgenode1","targetInstanceCount":1,"hardwareProfile":{"vmSize":"standard_a4_v2"},"osProfile":{"linuxOperatingSystemProfile":{"username":"sshuser"}},"encryptDataDisks":false}]},"provisioningState":"Succeeded","clusterState":"Running","createdDate":"2020-06-03T09:10:55.02","quotaInfo":{"coresUsed":24},"connectivityEndpoints":[{"name":"SSH","protocol":"TCP","location":"hdisdk-applications-hued29c1382-ssh.azurehdinsight.net","port":22},{"name":"HTTPS","protocol":"TCP","location":"hdisdk-applications-hued29c1382.azurehdinsight.net","port":443}],"tier":"standard","storageProfile":{"storageaccounts":[{"name":"hdipy.blob.core.windows.net","resourceId":null,"msiResourceId":null,"key":null,"fileSystem":null,"container":"hdisdk-applications-hued29c1382","saskey":null,"isDefault":true}]}}}' headers: - cache-control: [no-cache] - content-length: ['1705'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 02:59:44 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + cache-control: + - no-cache + content-length: + - '1969' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:59:17 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: '{"properties": {"computeProfile": {"roles": [{"name": "edgenode", "targetInstanceCount": 1, "hardwareProfile": {"vmSize": "Large"}}]}, "installScriptActions": [{"name": @@ -106,204 +176,449 @@ interactions: "parameters": "-version latest -port 20000", "roles": ["edgenode"]}], "applicationType": "CustomApplication"}}' headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - Content-Length: ['398'] - Content-Type: [application/json; charset=utf-8] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - accept-language: [en-US] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '398' + Content-Type: + - application/json; charset=utf-8 + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + accept-language: + - en-US method: PUT uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/applications/MyApplication?api-version=2018-06-01-preview response: - body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/applications/MyApplication","name":"MyApplication","type":"Microsoft.HDInsight/clusters/applications","etag":"87B98989-136A-4541-B042-D5BDC4698217","tags":null,"properties":{"computeProfile":{"roles":[{"name":"edgenode","targetInstanceCount":1,"hardwareProfile":{"vmSize":"Large"},"encryptDataDisks":false}]},"installScriptActions":[{"name":"InstallHue","uri":"https://hdiconfigactions.blob.core.windows.net/linuxhueconfigactionv02/install-hue-uber-v02.sh","roles":["edgenode"]}],"uninstallScriptActions":[],"httpsEndpoints":[],"sshEndpoints":[{"location":"MyApplication.hdisdk-applications-hued29c1382-ssh.azurehdinsight.net:22","destinationPort":22,"publicPort":22}],"provisioningState":"Failed","applicationState":"Error","errors":[{"code":"FailedToAddApplicationErrorCode","message":"Failed - to add an application with id: 135"}],"createdDate":"2018-12-24T11:58:41.23","applicationType":"CustomApplication"}}'} + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/applications/MyApplication","name":"MyApplication","type":"Microsoft.HDInsight/clusters/applications","etag":"99CD7556-3ECD-47AA-88DC-D2E3FE283B76","tags":null,"properties":{"computeProfile":{"roles":[{"name":"edgenode","targetInstanceCount":1,"VMGroupName":"edgenode1","hardwareProfile":{"vmSize":"standard_a4_v2"},"encryptDataDisks":false}]},"installScriptActions":[{"name":"InstallHue","uri":"https://hdiconfigactions.blob.core.windows.net/linuxhueconfigactionv02/install-hue-uber-v02.sh","roles":["edgenode"]}],"uninstallScriptActions":[],"httpsEndpoints":[],"sshEndpoints":[{"location":"MyApplication.hdisdk-applications-hued29c1382-ssh.azurehdinsight.net:22","destinationPort":22,"publicPort":22}],"provisioningState":"Failed","applicationState":"Error","errors":[{"code":"FailedToAddApplicationErrorCode","message":"Failed + to add an application {ApplicationName: MyApplication, ApplicationId: 256}"}],"createdDate":"2020-06-03T09:23:58.69","applicationType":"CustomApplication"}}' headers: - azure-asyncoperation: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/azureasyncoperations/create?api-version=2018-06-01-preview'] - cache-control: [no-cache] - content-length: ['1071'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 02:59:46 GMT'] - etag: ['"87B98989-136A-4541-B042-D5BDC4698217"'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-appuri: ['https://management.azure.com/subscriptions/964c10bb-8a6c-43bc-83d3-6b318c6c7305/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/applications/MyApplication?api-version=2018-06-01-preview'] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - x-ms-ratelimit-remaining-subscription-writes: ['1199'] - status: {code: 200, message: OK} + azure-asyncoperation: + - https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/azureasyncoperations/create?api-version=2018-06-01-preview + cache-control: + - no-cache + content-length: + - '1146' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:59:18 GMT + etag: + - '"99CD7556-3ECD-47AA-88DC-D2E3FE283B76"' + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-appuri: + - https://management.azure.com/subscriptions/964c10bb-8a6c-43bc-83d3-6b318c6c7305/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/applications/MyApplication?api-version=2018-06-01-preview + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + x-ms-ratelimit-remaining-subscription-writes: + - '1197' + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/azureasyncoperations/create?api-version=2018-06-01-preview response: - body: {string: '{"status":"Succeeded"}'} + body: + string: '{"status":"Succeeded"}' headers: - cache-control: [no-cache] - content-length: ['22'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 03:00:17 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + cache-control: + - no-cache + content-length: + - '22' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:59:50 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/applications/MyApplication?api-version=2018-06-01-preview response: - body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/applications/MyApplication","name":"MyApplication","type":"Microsoft.HDInsight/clusters/applications","etag":"87B98989-136A-4541-B042-D5BDC4698217","tags":null,"properties":{"computeProfile":{"roles":[{"name":"edgenode","targetInstanceCount":1,"hardwareProfile":{"vmSize":"Large"},"encryptDataDisks":false}]},"installScriptActions":[{"name":"InstallHue","uri":"https://hdiconfigactions.blob.core.windows.net/linuxhueconfigactionv02/install-hue-uber-v02.sh","roles":["edgenode"]}],"uninstallScriptActions":[],"httpsEndpoints":[],"sshEndpoints":[{"location":"MyApplication.hdisdk-applications-hued29c1382-ssh.azurehdinsight.net:22","destinationPort":22,"publicPort":22}],"provisioningState":"Failed","applicationState":"Error","errors":[{"code":"FailedToAddApplicationErrorCode","message":"Failed - to add an application with id: 135"}],"createdDate":"2018-12-24T11:58:41.23","applicationType":"CustomApplication"}}'} + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/applications/MyApplication","name":"MyApplication","type":"Microsoft.HDInsight/clusters/applications","etag":"99CD7556-3ECD-47AA-88DC-D2E3FE283B76","tags":null,"properties":{"computeProfile":{"roles":[{"name":"edgenode","targetInstanceCount":1,"VMGroupName":"edgenode1","hardwareProfile":{"vmSize":"standard_a4_v2"},"encryptDataDisks":false}]},"installScriptActions":[{"name":"InstallHue","uri":"https://hdiconfigactions.blob.core.windows.net/linuxhueconfigactionv02/install-hue-uber-v02.sh","roles":["edgenode"]}],"uninstallScriptActions":[],"httpsEndpoints":[],"sshEndpoints":[{"location":"MyApplication.hdisdk-applications-hued29c1382-ssh.azurehdinsight.net:22","destinationPort":22,"publicPort":22}],"provisioningState":"Failed","applicationState":"Error","errors":[{"code":"FailedToAddApplicationErrorCode","message":"Failed + to add an application {ApplicationName: MyApplication, ApplicationId: 256}"}],"createdDate":"2020-06-03T09:23:58.69","applicationType":"CustomApplication"}}' headers: - cache-control: [no-cache] - content-length: ['1071'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 03:00:19 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + cache-control: + - no-cache + content-length: + - '1146' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:59:50 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - accept-language: [en-US] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + accept-language: + - en-US method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/applications?api-version=2018-06-01-preview response: - body: {string: '{"value":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/applications/MyApplication","name":"MyApplication","type":"Microsoft.HDInsight/clusters/applications","etag":"87B98989-136A-4541-B042-D5BDC4698217","tags":null,"properties":{"computeProfile":{"roles":[{"name":"edgenode","targetInstanceCount":1,"hardwareProfile":{"vmSize":"Large"},"encryptDataDisks":false}]},"installScriptActions":[{"name":"InstallHue","uri":"https://hdiconfigactions.blob.core.windows.net/linuxhueconfigactionv02/install-hue-uber-v02.sh","roles":["edgenode"]}],"uninstallScriptActions":[],"httpsEndpoints":[],"sshEndpoints":[{"location":"MyApplication.hdisdk-applications-hued29c1382-ssh.azurehdinsight.net:22","destinationPort":22,"publicPort":22}],"provisioningState":"Failed","applicationState":"Error","errors":[{"code":"FailedToAddApplicationErrorCode","message":"Failed - to add an application with id: 135"}],"createdDate":"2018-12-24T11:58:41.23","applicationType":"CustomApplication"}}]}'} + body: + string: '{"value":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/applications/MyApplication","name":"MyApplication","type":"Microsoft.HDInsight/clusters/applications","etag":"99CD7556-3ECD-47AA-88DC-D2E3FE283B76","tags":null,"properties":{"computeProfile":{"roles":[{"name":"edgenode","targetInstanceCount":1,"VMGroupName":"edgenode1","hardwareProfile":{"vmSize":"standard_a4_v2"},"encryptDataDisks":false}]},"installScriptActions":[{"name":"InstallHue","uri":"https://hdiconfigactions.blob.core.windows.net/linuxhueconfigactionv02/install-hue-uber-v02.sh","roles":["edgenode"]}],"uninstallScriptActions":[],"httpsEndpoints":[],"sshEndpoints":[{"location":"MyApplication.hdisdk-applications-hued29c1382-ssh.azurehdinsight.net:22","destinationPort":22,"publicPort":22}],"provisioningState":"Failed","applicationState":"Error","errors":[{"code":"FailedToAddApplicationErrorCode","message":"Failed + to add an application {ApplicationName: MyApplication, ApplicationId: 256}"}],"createdDate":"2020-06-03T09:23:58.69","applicationType":"CustomApplication"}}]}' headers: - cache-control: [no-cache] - content-length: ['1083'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 03:00:20 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + cache-control: + - no-cache + content-length: + - '1158' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 09:59:51 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - Content-Length: ['0'] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - accept-language: [en-US] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + accept-language: + - en-US method: DELETE uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/applications/MyApplication?api-version=2018-06-01-preview response: - body: {string: ''} + body: + string: '' headers: - azure-asyncoperation: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/azureasyncoperations/5868a637-1a93-4c5e-adaa-be752d473f53-0-r?api-version=2018-06-01-preview'] - cache-control: [no-cache] - content-length: ['0'] - date: ['Tue, 25 Dec 2018 03:00:22 GMT'] - expires: ['-1'] - location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/operationresults/5868a637-1a93-4c5e-adaa-be752d473f53-0-r?api-version=2018-06-01-preview'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - x-ms-ratelimit-remaining-subscription-deletes: ['14999'] - status: {code: 202, message: Accepted} + azure-asyncoperation: + - https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/azureasyncoperations/48b33508-6e62-4452-8291-638e39c8fa3d-0-r?api-version=2018-06-01-preview + cache-control: + - no-cache + content-length: + - '0' + date: + - Wed, 03 Jun 2020 10:01:52 GMT + expires: + - '-1' + location: + - https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/operationresults/48b33508-6e62-4452-8291-638e39c8fa3d-0-r?api-version=2018-06-01-preview + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + x-ms-ratelimit-remaining-subscription-deletes: + - '14999' + status: + code: 202 + message: Accepted - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python method: GET - uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/azureasyncoperations/5868a637-1a93-4c5e-adaa-be752d473f53-0-r?api-version=2018-06-01-preview + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/azureasyncoperations/48b33508-6e62-4452-8291-638e39c8fa3d-0-r?api-version=2018-06-01-preview response: - body: {string: '{"status":"Succeeded"}'} + body: + string: '{"status":"InProgress"}' headers: - cache-control: [no-cache] - content-length: ['22'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 03:01:23 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 10:02:53 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK - request: body: null headers: - Accept: [application/json] - Accept-Encoding: ['gzip, deflate'] - Connection: [keep-alive] - User-Agent: [python/3.7.1 (Windows-10-10.0.14393-SP0) msrest/0.6.2 msrest_azure/0.4.34 - azure-mgmt-hdinsight/0.2.0 Azure-SDK-For-Python] - accept-language: [en-US] + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/azureasyncoperations/48b33508-6e62-4452-8291-638e39c8fa3d-0-r?api-version=2018-06-01-preview + response: + body: + string: '{"status":"InProgress"}' + headers: + cache-control: + - no-cache + content-length: + - '23' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 10:03:24 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/azureasyncoperations/48b33508-6e62-4452-8291-638e39c8fa3d-0-r?api-version=2018-06-01-preview + response: + body: + string: '{"status":"Succeeded"}' + headers: + cache-control: + - no-cache + content-length: + - '22' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 10:03:54 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - python/3.7.4 (Windows-10-10.0.18362-SP0) msrest/0.6.14 msrest_azure/0.6.3 + azure-mgmt-hdinsight/1.5.0 Azure-SDK-For-Python + accept-language: + - en-US method: GET uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/hdipy-d29c1382/providers/Microsoft.HDInsight/clusters/hdisdk-applications-hued29c1382/applications?api-version=2018-06-01-preview response: - body: {string: '{"value":[]}'} + body: + string: '{"value":[]}' headers: - cache-control: [no-cache] - content-length: ['12'] - content-type: [application/json; charset=utf-8] - date: ['Tue, 25 Dec 2018 03:01:23 GMT'] - expires: ['-1'] - pragma: [no-cache] - strict-transport-security: [max-age=31536000; includeSubDomains] - transfer-encoding: [chunked] - vary: [Accept-Encoding] - x-content-type-options: [nosniff] - x-ms-hdi-matched-rule: [ClusterResourcesAndSubResources] - x-ms-hdi-routed-to: [RegionalRp] - x-ms-hdi-served-by: [northcentralus] - status: {code: 200, message: OK} + cache-control: + - no-cache + content-length: + - '12' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 03 Jun 2020 10:03:56 GMT + expires: + - '-1' + pragma: + - no-cache + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-hdi-matched-rule: + - ClusterResourcesAndSubResources + x-ms-hdi-routed-to: + - RegionalRp + x-ms-hdi-served-by: + - northcentralus + status: + code: 200 + message: OK version: 1 diff --git a/sdk/hdinsight/azure-mgmt-hdinsight/test/test_mgmt_hdinsight.py b/sdk/hdinsight/azure-mgmt-hdinsight/test/test_mgmt_hdinsight.py index 65821f7d072f..36d331d9e3de 100644 --- a/sdk/hdinsight/azure-mgmt-hdinsight/test/test_mgmt_hdinsight.py +++ b/sdk/hdinsight/azure-mgmt-hdinsight/test/test_mgmt_hdinsight.py @@ -1,18 +1,21 @@ # coding: utf-8 -#------------------------------------------------------------------------- +# ------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See License.txt in the project root for # license information. -#-------------------------------------------------------------------------- +# -------------------------------------------------------------------------- import unittest +from azure.keyvault.keys import KeyVaultKey, KeyClient from azure.mgmt.hdinsight import HDInsightManagementClient from azure.mgmt.hdinsight.models import * from azure.mgmt.keyvault import KeyVaultManagementClient from azure.mgmt.msi import ManagedServiceIdentityClient from azure.mgmt.keyvault.models import SecretPermissions, KeyPermissions, CertificatePermissions, StoragePermissions, \ Permissions, Sku, SkuName, AccessPolicyEntry, VaultProperties, VaultCreateOrUpdateParameters, Vault +from azure.mgmt.loganalytics import LogAnalyticsManagementClient +from azure.mgmt.loganalytics.models import Workspace from azure.mgmt.storage.models import Kind from devtools_testutils import AzureMgmtTestCase, ResourceGroupPreparer, StorageAccountPreparer, FakeStorageAccount from mgmt_hdinsight_preparers import KeyVaultPreparer @@ -28,6 +31,7 @@ FAKE_WORKSPACE_ID = '1d364e89-bb71-4503-aa3d-a23535aea7bd' + class MgmtHDInsightTest(AzureMgmtTestCase): def setUp(self): @@ -38,13 +42,6 @@ def setUp(self): self.msi_client = self.create_mgmt_client(ManagedServiceIdentityClient) self.vault_mgmt_client = self.create_mgmt_client(KeyVaultManagementClient) - # if self.is_live: - # self.vault_client = self.create_basic_client(KeyVaultClient) - # else: - # def _auth_callback(server, resource, scope): - # return AccessToken('Bearer', 'fake-token') - # self.vault_client = KeyVaultClient(KeyVaultAuthentication(authorization_callback=_auth_callback)) - # sensitive test configs self.tenant_id = self.settings.TENANT_ID self.adls_account_name = self.settings.HDI_ADLS_ACCOUNT_NAME @@ -56,9 +53,10 @@ def setUp(self): self.ssh_username = 'sshuser' self.ssh_password = 'Password1!' self.adls_home_mountpoint = '/clusters/hdi' - self.cert_password = '123' - self.cert_content = 'MIIJ8gIBAzCCCa4GCSqGSIb3DQEHAaCCCZ8EggmbMIIJlzCCBgAGCSqGSIb3DQEHAaCCBfEEggXtMIIF6TCCBeUGCyqGSIb3DQEMCgECoIIE9jCCBPIwHAYKKoZIhvcNAQwBAzAOBAiTJstpWcGFZAICB9AEggTQZvg9qVE2ptb3hdH9hnDf5pwIeGghe9assBeEKj/W1JMUjsdEu7qzXH9/3Ro6C1HF6MvSqbav7MD8je9AMb0jl7T3ZmXPgGtrbUsSBTPruVv0hTXPRTxQmcfwae5vEkD03b/4W22sXMMYZB7wOTQMl1d5+0wt267qdF+G1XWtRI2jnxetK8/oyMQxn5Cwuz/VAmn1tXwRAN9gIiZDA8MwvpYha/iFVWKu/vnHg8HT47ry+27/wh8ifM9ea7JWhKh2tZoPIMou9/P/CgkkMv9KVHlmiMldA3Phxsrqjbh/wbd8RWBOtSM7rryMVnc1MYonZraDJMGOLGAhvEcXNBKLwRdmrDDYvpOYlDYKlmNvDXYDm410XCOia2aKP0WoP4qLsExtUwW8Qk2r2QRy5O4B5p2EbPZBlPlMMO4S1NkASjJCghuTCUgvk3uwe2L/mMf0IajAf+R0/VW/fXHbhJkFKobi5JlIqWaHsSC7hMidWj6771Yi8UEXOMshWERs2UHH05aIO3c50lnyypHyhA3BohKUXzNhHA0o7ImQRjmjjTJFBLMNiIZSW0aPtLN1+92pT0a6iS7P1PC0DqEnOjkcs/VOUI3qTt0X78b6wnDO+ATo39B13njGD0mtrVvtTeHclBouoFzpKHkS86GSGmDoHQH6EHhpGF/7wPVfAjAiSrNQb/QLjPHWo+BeiOml4Xrti0K6rWb0AXhY8AmtIlEUC9GscDSdT55v9j9tWONzOXECCgZBYDzNlagMLkCDIFHZwbEGPn3pOc7BTOmQf1GQjfvunLiLWWfe3of9pR+NCDyi1VJUNvjoE+/YnVoBBUMBBO6/4t2SL92iouEF4fyqkQFDb0FOPW4Kfh7H5W+sDZIN9NfqNzniK6HFcpS+jnGm9x9rx81DmMcwtiYZTfYDSivtNxOYrmRFXx574stBzvG0En11uc6E4QhWnkCSsBnnOMjRGDyv95BFVMZC0gIS0rWoKYxjdblpmo9w/yfDtAmQuCs3bdqcJ4mMYt0ueUUZImPRQRJOSrVyoq+brLw657EqM1SahtBmzTG7+HTl1Qi/xZ1xmz6paQDSFVPRcb5QSIp4v08j/Lmj0x4R9jQ4cAmZ3CfPKXBKuIRu2AI2EuqGOoAxvQQEpSjSKUs3fbQxjptUhK7o5FcXAfAxHLzdx2/9L1Iqbo/3HDkbmuix24NRXESG0e/kVr7VAGhoALI7L+eKAdn4AkgmBt55FXZ+uHY9bSKZUoz4Oed2bz2A+9sQBcXG06fLqQEwGVPhATEbYyRduuY6AdTRAmOKmadT5BTTD7+dnFlIt+u7ZpbXm6S6LcSqGqHVacig27SwDt0VznQsjMRDVCiHaWKg4W78xbP7YVvNTB/cBCHmhh5ZXfO/TucizXsQPJlwEMr2CbqByqldXi0i1GUrbg4aLUGZtxgUYex7dHlx6GUejOGRh7fLYCNBo43pjCFvbhFwb0/dWya0crJjpGiY3DNtl1YosJBmvso/Rli4QqVeN7tb45ZsGWTEUg1MDeoGRDqal7GDsvBnH574T5Sz3nSLAoNXR7k0rYaWhezJNobo/SDkuSXskVjNJpv+vjEyW2UGYNhaeK/UHKBP8IrmSAEIZejQj6OEzSPM6TNLW5qJb6LK9agxgdswEwYJKoZIhvcNAQkVMQYEBAEAAAAwXQYJKwYBBAGCNxEBMVAeTgBNAGkAYwByAG8AcwBvAGYAdAAgAFMAdAByAG8AbgBnACAAQwByAHkAcAB0AG8AZwByAGEAcABoAGkAYwAgAFAAcgBvAHYAaQBkAGUAcjBlBgkqhkiG9w0BCRQxWB5WAFAAdgBrAFQAbQBwADoAMAAyAGYAZQA0AGUAOAAzAC0AMgAzADEANgAtADQAMQA3AGMALQA5ADQANQBjAC0AZgA1ADUAMABhADUAZAAwAGIAMAAzAGEwggOPBgkqhkiG9w0BBwagggOAMIIDfAIBADCCA3UGCSqGSIb3DQEHATAcBgoqhkiG9w0BDAEDMA4ECAR1hzovrDkgAgIH0ICCA0gq6boOLRoE5PHFfVIXYtzqg1u2vPMm5mgBUvrh3u+VZ/1FMGTj8od9+Yu91cnumVSgfRiGq7lz+K6by5JsBqP68ksLA2d/PqtTdofCoZ7SgVIo+qqzA64HIQFkElNpo/BJMX/JGpc5OlFq7mdHe6xL2Pfx/3z/pNSV+D+WaAwaDnbLqI7MU6ED3j5l63mExk/8H/VVbiPdqMTzbhIp65oHTGanw86w7RlywqeNb3DkPVMB78Jhcg8vf2AxB8hKf6QiO2uJc/4WKkyLoLmNoD/zhaoUuAbC6hrNVAa9VRWNRfwKZrzwIMSLlKYwWmVcD/QgC8gwxuF+wV3UHwDNAdEe8TEsOhE99/ZiUiogxMdkopZwwtZMszzBB/x5mHCGySauDMVPwoYT6QXewJhGrUap0jwB/Vzy5FaWHi/m8964zWpwC6xfkT2hkDb+rfouWutpiAgMne5tD9YvqxTUmZFIlgwpLrVdPcKQS+b/uIXPTv8uW177XsCOmGGu728ld8H1Ifb2nPveK09Y0AA+ARFpOX0p0ZuxMQqk6NnlA+eESJVm5cLfKszorRcrNPINXaEOGl2okuijm8va30FH9GIYWRt+Be6s8qG672aTO/2eHaTHeR/qQ9aEt0ASDXGcugYS14Jnu2wbauyvotZ6eAvgl5tM2leMpgSLaQqYzPTV2uiD6zDUqxwjm2P8EZQihEQqLUV1jvQuQB4Ui7MryDQ+QiDBD2m5c+9SDPafcR7qgRe/cP4hj5BqzHTcNQAD5BLXze7Yx+TMdf+Qe/R1uBYm8bLjUv9hwUmtMeZP4RU6RPJrN2aRf7BUdgS0j/8YAhxViPucRENuhEfS4sotHf1CJZ7xJz0ZE9cpVY6JLl1tbmuf1Eh50cicZ1SHQhqSP0ggLHV6DNcJz+kyekEe9qggGDi6mreYz/kJnnumsDy5cToIHy9jJhtXzj+/ZNGkdpq9HWMiwAT/VR1WPpzjn06m7Z87PiLaiC3simQtjnl0gVF11Ev4rbIhYjFBL0nKfNpzaWlMaOVF+EumROk3EbZVpx1K6Yh0zWh/NocWSUrtSoHVklzwPCNRvnE1Ehyw5t9YbEBsTIDWRYyqbVYoFVfOUhq5p4TXrqEwOzAfMAcGBSsOAwIaBBSx7sJo66zYk4VOsgD9V/co1SikFAQUUvU/kE4wTRnPRnaWXnno+FCb56kCAgfQ' - self.workspace_id = '1d364e89-bb71-4503-aa3d-a23535aea7bd' + self.cert_password = 'password' + self.cert_content = 'MIIE5TCCAs0CFDGDR+Zz5To67BBDmsF3agvAtdUvMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNVBAYTAmNuMQ4wDAYDVQQIDAVjaGluYTEQMA4GA1UECgwHenp5dGVzdDAeFw0yMDA0MTYxMDEzNTlaFw0yMTA0MTYxMDEzNTlaMC8xCzAJBgNVBAYTAmNuMQ4wDAYDVQQIDAVjaGluYTEQMA4GA1UECgwHenp5dGVzdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMmvOHmbbD5kIXnvIdEGFPVd3dHe8RFHBKMBSyqVdcwiijPsaQGkx2/PHyD019FTFPDcwo5Wt2rPXdkOm5Em7NiHcYWjZTF/UDZytf+B2pihI1jDz5qUGf65vIGWI5VVtuuXHSGMOZ4RGyM8/3SyMfAy02db6bJnat2RziZJ2F3FSPfMebGYgFn8uxfYKLGQj7mPEqVyGHxcx0KqbH+2jfzBqDjbaQfo7vBsqxvMfG+2G9SAHaiZPBveym4HuyDDtBZ3ChslVHitWUw0qsbPEuR7Jp8NenAqKVrzvixoepAm7vvErRs/olkJFu3OcIusDIOEQcYem30/rSQejQvrXTcdIvD3UPcqApdzrEZvdiCvIr0ys1Ie2OoOwdz391KCIlH3zgGu4Tdg0vJ+RQIYNT8DNK2PUbbw1bENEcwklgkdT2uIjgh6kOIjMCuy6UzAPnWBF8bl9YY3rB5p/EjnGk8BSp/nCEggMVxzfUhUNQJGKo1C85yFl8Olet/jtPZgf8JV9TOJLdNHlzdkidwrcLGJ8SAEsbveF2w5CtobqeDoClrSieK6ANPPLOWplMNFPZWqUaLe45ReExGYlm7Q+hpdnJem7ywWanJTzI1GoVJMr04ZJmsMEmVYhoSqN4yvFfyWM+rDrKdpzBF6ZqknzWxw+T59u+Eu+PrRMOMAWsDJAgMBAAEwDQYJKoZIhvcNAQELBQADggIBAC/5VPkcsb8sH6wpS3LeKViG2Z+XBZ70Q7FUliE4wfLwP5duzN8DN6eJyxS/nTyxohvI6p18MVgZdhjPcvndR1FE8eBsMqZM0D3eDyCYoiB9Ghm1DSxn0AZyk7/aC4nNYLorZouWa1DdCCdOFZegod5I3USXIvUOBDh9eIQQAGCYdANSLkYsyaZgTaKWiBDH0pTVvCOroCJ7NCayibCMc4vdHUQY/UyKSgOZG0Y2M6AgwNI/yC3tyizu/D8OoF7RUb/A4JqvHnqkY2hGF3/GwEBO4eQrCmHFozrA5qZx40bWP4sXGzcmZz/4Nl9TWRWdIKe5Wh3xz6ZMtJ3gPDwt4Vi59ZHcmq187uwYIRvuvGzD4/oI4zeZ80nxhJUQrZdPh3beaA5GhvTS9MM/RGgkXgB+CA61iF0euAb3FEC3MvpjDwDq9DZDiBulAscRn3QnYhxaL2AxMkNgtj6oaHGx+RlepXKqPd11hsdWhKo8X0zcCVrtrz73b6yDQesSP+lDapLuo/74APJVyAuEXM7zGQSt3zTmeE6RTIywB00VpifqL9HmcekllopPuQrBgs0cpgrs6/VjbC6uwIwV9dUrIsP6geLeocS9j6aQmEIr/E/HjvEZ0kI+03Cw+gQqeAlSeKP6ZY9AgQsCFBIBsgORNcn/Aii0QenXC19LeFC0dJYm' + self.workspace_id = '3741ffb2-a54e-407c-952a-43ab44b57c9d' + self.primary_key = 'qFmud5LfxcCxWUvWcGMhKDp0v0KuBRLsO/AIddX734W7lzdInsVMsB5ILVoOrF+0fCfk/IYYy5SJ9Q+2v4aihQ==' @ResourceGroupPreparer(name_prefix='hdipy-', location=LOCATION) @StorageAccountPreparer(name_prefix='hdipy', location=LOCATION) @@ -71,17 +69,19 @@ def test_create_humboldt_cluster(self, resource_group, location, storage_account @ResourceGroupPreparer(name_prefix='hdipy-', location=LOCATION) @StorageAccountPreparer(name_prefix='hdipy', location=LOCATION) - def test_create_humboldt_cluster_with_premium_tier(self, resource_group, location, storage_account, storage_account_key): + def test_create_humboldt_cluster_with_premium_tier(self, resource_group, location, storage_account, + storage_account_key): cluster_name = self.get_resource_name('hdisdk-premium') create_params = self.get_cluster_create_params(location, cluster_name, storage_account, storage_account_key) - create_params.properties.tier=Tier.premium + create_params.properties.tier = Tier.premium create_poller = self.hdinsight_client.clusters.create(resource_group.name, cluster_name, create_params) cluster = create_poller.result() self.validate_cluster(cluster_name, create_params, cluster) @ResourceGroupPreparer(name_prefix='hdipy-', location=LOCATION) @StorageAccountPreparer(name_prefix='hdipy', location=LOCATION) - def test_create_with_empty_extended_parameters(self, resource_group, location, storage_account, storage_account_key): + def test_create_with_empty_extended_parameters(self, resource_group, location, storage_account, + storage_account_key): cluster_name = self.get_resource_name('hdisdk-cluster') create_params = ClusterCreateParametersExtended() @@ -95,12 +95,14 @@ def test_create_with_empty_extended_parameters(self, resource_group, location, s @ResourceGroupPreparer(name_prefix='hdipy-', location=LOCATION) @StorageAccountPreparer(name_prefix='hdipy', location=LOCATION) - def test_create_humboldt_cluster_with_custom_vm_sizes(self, resource_group, location, storage_account, storage_account_key): + def test_create_humboldt_cluster_with_custom_vm_sizes(self, resource_group, location, storage_account, + storage_account_key): cluster_name = self.get_resource_name('hdisdk-customvmsizes') create_params = self.get_cluster_create_params(location, cluster_name, storage_account, storage_account_key) headnode = next(item for item in create_params.properties.compute_profile.roles if item.name == 'headnode') headnode.hardware_profile = HardwareProfile(vm_size="ExtraLarge") - zookeepernode = next(item for item in create_params.properties.compute_profile.roles if item.name == 'zookeepernode') + zookeepernode = next( + item for item in create_params.properties.compute_profile.roles if item.name == 'zookeepernode') zookeepernode.hardware_profile = HardwareProfile(vm_size="Medium") create_poller = self.hdinsight_client.clusters.create(resource_group.name, cluster_name, create_params) cluster = create_poller.result() @@ -108,18 +110,20 @@ def test_create_humboldt_cluster_with_custom_vm_sizes(self, resource_group, loca @ResourceGroupPreparer(name_prefix='hdipy-', location=LOCATION) @StorageAccountPreparer(name_prefix='hdipy', location=LOCATION) - def test_create_linux_spark_cluster_with_component_version(self, resource_group, location, storage_account, storage_account_key): + def test_create_linux_spark_cluster_with_component_version(self, resource_group, location, storage_account, + storage_account_key): cluster_name = self.get_resource_name('hdisdk-sparkcomponentversions') create_params = self.get_cluster_create_params(location, cluster_name, storage_account, storage_account_key) create_params.properties.cluster_definition.kind = 'Spark' - create_params.properties.cluster_definition.Component_version = {'Spark' : '2.2'} + create_params.properties.cluster_definition.Component_version = {'Spark': '2.2'} create_poller = self.hdinsight_client.clusters.create(resource_group.name, cluster_name, create_params) cluster = create_poller.result() self.validate_cluster(cluster_name, create_params, cluster) @ResourceGroupPreparer(name_prefix='hdipy-', location=LOCATION) @StorageAccountPreparer(name_prefix='hdipy', location=LOCATION) - def test_create_kafka_cluster_with_managed_disks(self, resource_group, location, storage_account, storage_account_key): + def test_create_kafka_cluster_with_managed_disks(self, resource_group, location, storage_account, + storage_account_key): cluster_name = self.get_resource_name('hdisdk-kafka') create_params = self.get_cluster_create_params(location, cluster_name, storage_account, storage_account_key) create_params.properties.cluster_definition.kind = 'Kafka' @@ -133,23 +137,26 @@ def test_create_kafka_cluster_with_managed_disks(self, resource_group, location, cluster = create_poller.result() self.validate_cluster(cluster_name, create_params, cluster) - @unittest.skip('skipping temporarily to unblock azure-keyvault checkin') + # @unittest.skip('skipping temporarily to unblock azure-keyvault checkin') @ResourceGroupPreparer(name_prefix='hdipy-', location=LOCATION) @StorageAccountPreparer(name_prefix='hdipy', location=LOCATION) @KeyVaultPreparer(name_prefix='hdipy', location=LOCATION, enable_soft_delete=True) - def test_create_kafka_cluster_with_disk_encryption(self, resource_group, location, storage_account, storage_account_key, vault): + def test_create_kafka_cluster_with_disk_encryption(self, resource_group, location, storage_account, + storage_account_key, vault): # create managed identities for Azure resources. msi_name = self.get_resource_name('hdipyuai') msi_principal_id = "00000000-0000-0000-0000-000000000000" - msi_id = "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/{}/providers/microsoft.managedidentity/userassignedidentities/{}".format(resource_group.name, msi_name) + msi_id = "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/{}/providers/microsoft.managedidentity/userassignedidentities/{}".format( + resource_group.name, msi_name) if self.is_live: msi = self.msi_client.user_assigned_identities.create_or_update(resource_group.name, msi_name, location) msi_id = msi.id msi_principal_id = msi.principal_id # add managed identity to vault - required_permissions = Permissions(keys=[KeyPermissions.get, KeyPermissions.wrap_key, KeyPermissions.unwrap_key], - secrets=[SecretPermissions.get, SecretPermissions.set,SecretPermissions.delete]) + required_permissions = Permissions( + keys=[KeyPermissions.get, KeyPermissions.wrap_key, KeyPermissions.unwrap_key], + secrets=[SecretPermissions.get, SecretPermissions.set, SecretPermissions.delete]) vault.properties.access_policies.append( AccessPolicyEntry(tenant_id=self.tenant_id, object_id=msi_principal_id, @@ -160,11 +167,17 @@ def test_create_kafka_cluster_with_disk_encryption(self, resource_group, locatio vault = self.vault_mgmt_client.vaults.create_or_update(resource_group.name, vault.name, update_params).result() self.assertIsNotNone(vault) + # create keyclient + key_client_credential = self.settings.get_azure_core_credentials(scope="https://vault.azure.net/.default") + self.vault_client = KeyClient(vault_url=vault.properties.vault_uri, credential=key_client_credential) + # create key - vault_uri = vault.properties.vault_uri key_name = self.get_resource_name('hdipykey1') - created_bundle = self.vault_client.create_key(vault_uri, key_name, 'RSA') - vault_key = KeyVaultId.parse_key_id(created_bundle.key.kid) + vault_key = self.vault_client.create_key(key_name, 'RSA') + + # create a new key for test rotate + new_key_name = self.get_resource_name('hdipykey2') + new_vault_key = self.vault_client.create_key(new_key_name, 'RSA') # create HDInsight cluster with Kafka disk encryption rg_name = resource_group.name @@ -182,9 +195,9 @@ def test_create_kafka_cluster_with_disk_encryption(self, resource_group, locatio user_assigned_identities={msi_id: ClusterIdentityUserAssignedIdentitiesValue()} ) create_params.properties.disk_encryption_properties = DiskEncryptionProperties( - vault_uri=vault_key.vault, + vault_uri=vault_key.properties.vault_url, key_name=vault_key.name, - key_version=vault_key.version, + key_version=vault_key.properties.version, msi_resource_id=msi_id ) cluster = self.hdinsight_client.clusters.create(resource_group.name, cluster_name, create_params).result() @@ -192,18 +205,17 @@ def test_create_kafka_cluster_with_disk_encryption(self, resource_group, locatio # check disk encryption properties self.assertIsNotNone(cluster.properties.disk_encryption_properties) - self.assertEqual(create_params.properties.disk_encryption_properties.vault_uri, cluster.properties.disk_encryption_properties.vault_uri) - self.assertEqual(create_params.properties.disk_encryption_properties.key_name, cluster.properties.disk_encryption_properties.key_name) - self.assertEqual(create_params.properties.disk_encryption_properties.msi_resource_id.lower(), cluster.properties.disk_encryption_properties.msi_resource_id.lower()) + self.assertEqual(create_params.properties.disk_encryption_properties.vault_uri, + cluster.properties.disk_encryption_properties.vault_uri) + self.assertEqual(create_params.properties.disk_encryption_properties.key_name, + cluster.properties.disk_encryption_properties.key_name) + self.assertEqual(create_params.properties.disk_encryption_properties.msi_resource_id.lower(), + cluster.properties.disk_encryption_properties.msi_resource_id.lower()) - # create a new key - new_key_name = self.get_resource_name('hdipykey2') - created_bundle = self.vault_client.create_key(vault_uri, new_key_name, 'RSA') - new_vault_key = KeyVaultId.parse_key_id(created_bundle.key.kid) rotate_params = ClusterDiskEncryptionParameters( - vault_uri=new_vault_key.vault, + vault_uri=new_vault_key.properties.vault_url, key_name=new_vault_key.name, - key_version=new_vault_key.version + key_version=new_vault_key.properties.version ) # rotate cluster key @@ -216,6 +228,7 @@ def test_create_kafka_cluster_with_disk_encryption(self, resource_group, locatio self.assertEqual(rotate_params.key_name, cluster.properties.disk_encryption_properties.key_name) self.assertEqual(msi_id.lower(), cluster.properties.disk_encryption_properties.msi_resource_id.lower()) + @unittest.skip("There is something wrong in ADLS Gen1 from RP.") @ResourceGroupPreparer(name_prefix='hdipy-', location=ADLS_LOCATION) @StorageAccountPreparer(name_prefix='hdipy', location=ADLS_LOCATION) def test_create_with_adls_gen1(self, resource_group, location, storage_account, storage_account_key): @@ -241,7 +254,8 @@ def test_create_with_adls_gen1(self, resource_group, location, storage_account, def test_create_with_adls_gen2(self, resource_group, location, storage_account, storage_account_key, second_storage_account, second_storage_account_key): cluster_name = self.get_resource_name('hdisdk-adlgen2') - create_params = self.get_cluster_create_params_for_adls_gen2(location, cluster_name, storage_account, storage_account_key) + create_params = self.get_cluster_create_params_for_adls_gen2(location, cluster_name, storage_account, + storage_account_key) # Add additional storage account create_params.properties.storage_profile.storageaccounts.append( @@ -256,6 +270,7 @@ def test_create_with_adls_gen2(self, resource_group, location, storage_account, cluster = self.hdinsight_client.clusters.create(resource_group.name, cluster_name, create_params).result() self.validate_cluster(cluster_name, create_params, cluster) + @unittest.skip("This test depends on ADLS Gen1. Now there is something wrong with ADLS Gen1.") @ResourceGroupPreparer(name_prefix='hdipy-', location=LOCATION) @StorageAccountPreparer(name_prefix='hdipy', location=LOCATION) @StorageAccountPreparer(name_prefix='hdipy2', location=LOCATION, parameter_name='second_storage_account') @@ -307,7 +322,7 @@ def test_create_rserver_cluster(self, resource_group, location, storage_account, def test_create_mlservices_cluster(self, resource_group, location, storage_account, storage_account_key): cluster_name = self.get_resource_name('hdisdk-mlservices') create_params = self.get_cluster_create_params(location, cluster_name, storage_account, storage_account_key) - create_params.properties.cluster_version="3.6" + create_params.properties.cluster_version = "3.6" create_params.properties.cluster_definition.kind = 'MLServices' create_params.properties.compute_profile.roles.append( Role( @@ -371,7 +386,7 @@ def test_list_clusters_in_subscription(self, resource_group, location, storage_a def test_hue_on_running_cluster(self, resource_group, location, storage_account, storage_account_key): cluster_name = self.get_resource_name('hdisdk-applications-hue') create_params = self.get_cluster_create_params(location, cluster_name, storage_account, storage_account_key) - create_params.properties.cluster_version="3.6" + create_params.properties.cluster_version = "3.6" create_poller = self.hdinsight_client.clusters.create(resource_group.name, cluster_name, create_params) cluster = create_poller.result() self.validate_cluster(cluster_name, create_params, cluster) @@ -395,20 +410,25 @@ def test_hue_on_running_cluster(self, resource_group, location, storage_account, hardware_profile=HardwareProfile( vm_size="Large" ), - target_instance_count = 1 + target_instance_count=1 ) ] ) ) ) - self.hdinsight_client.applications.create(resource_group.name, cluster_name, application_name, application).wait() + self.hdinsight_client.applications.create(resource_group.name, cluster_name, application_name, + application).wait() application_list = list(self.hdinsight_client.applications.list_by_cluster(resource_group.name, cluster_name)) self.assertGreater(len(application_list), 0) application_match = [item for item in application_list if item.name == application_name] self.assertIsNotNone(application_match) self.assertEqual(len(application_match), 1) + # sleep for robust + import time + time.sleep(120) + self.hdinsight_client.applications.delete(resource_group.name, cluster_name, application_name).wait() application_list = list(self.hdinsight_client.applications.list_by_cluster(resource_group.name, cluster_name)) self.assertEqual(len(application_list), 0) @@ -467,7 +487,7 @@ def test_get_configurations(self, resource_group, location, storage_account, sto @ResourceGroupPreparer(name_prefix='hdipy-', location=LOCATION) @StorageAccountPreparer(name_prefix='hdipy', location=LOCATION) - def test_http_extended(self, resource_group, location, storage_account, storage_account_key): + def test_gateway_settings(self, resource_group, location, storage_account, storage_account_key): rg_name = resource_group.name cluster_name = self.get_resource_name('hdisdk-http') create_params = self.get_cluster_create_params(location, cluster_name, storage_account, storage_account_key) @@ -475,21 +495,17 @@ def test_http_extended(self, resource_group, location, storage_account, storage_ cluster = create_poller.result() self.validate_cluster(cluster_name, create_params, cluster) - gateway = 'gateway' user_name = self.cluster_username user_password = self.cluster_password - http_settings = self.hdinsight_client.configurations.get(rg_name, cluster_name, gateway) - self.validate_http_settings(http_settings, user_name, user_password) + gateway_settings = self.hdinsight_client.clusters.get_gateway_settings(rg_name, cluster_name) + self.validate_gateway_settings(gateway_settings, user_name, user_password) new_password = 'NewPassword1!' - update_params = { - 'restAuthCredential.isEnabled': 'true', - 'restAuthCredential.username': user_name, - 'restAuthCredential.password': new_password - } - self.hdinsight_client.configurations.update(rg_name, cluster_name, gateway, update_params).wait() - http_settings = self.hdinsight_client.configurations.get(rg_name, cluster_name, gateway) - self.validate_http_settings(http_settings, user_name, new_password) + update_params = UpdateGatewaySettingsParameters(is_credential_enabled=True, user_name=user_name, + password=new_password) + self.hdinsight_client.clusters.update_gateway_settings(rg_name, cluster_name, update_params).wait() + gateway_settings = self.hdinsight_client.clusters.get_gateway_settings(rg_name, cluster_name) + self.validate_gateway_settings(gateway_settings, user_name, new_password) def test_get_usages(self): usages = self.hdinsight_client.locations.list_usages(LOCATION) @@ -502,6 +518,7 @@ def test_get_usages(self): self.assertIsNotNone(usage.name) self.assertIsNotNone(usage.unit) + @unittest.skip("Script executed failed due to Internal server. The issue is related with RP not SDK.") @ResourceGroupPreparer(name_prefix='hdipy-', location=LOCATION) @StorageAccountPreparer(name_prefix='hdipy', location=LOCATION) def test_oms_on_running_cluster(self, resource_group, location, storage_account, storage_account_key): @@ -509,12 +526,23 @@ def test_oms_on_running_cluster(self, resource_group, location, storage_account, cluster_name = self.get_resource_name('hdisdk-oms') create_params = self.get_cluster_create_params(location, cluster_name, storage_account, storage_account_key) create_params.properties.cluster_definition.kind = 'Spark' - create_params.properties.cluster_version="3.6" + create_params.properties.cluster_version = "3.6" create_poller = self.hdinsight_client.clusters.create(resource_group.name, cluster_name, create_params) cluster = create_poller.result() self.validate_cluster(cluster_name, create_params, cluster) - self.hdinsight_client.extensions.enable_monitoring(rg_name, cluster_name, self.workspace_id).wait() + # create log analytics workspace + self.loganalytics_mgmt_client = self.create_mgmt_client(LogAnalyticsManagementClient) + workspace_name = self.get_resource_name('workspaceforpytest') + workspace_params = Workspace(name=workspace_name, location=location) + workspace_poller = self.loganalytics_mgmt_client.workspaces.create_or_update(rg_name, workspace_name, + workspace_params) + workspace = workspace_poller.result() + self.workspace_id = workspace.customer_id + self.primary_key = self.loganalytics_mgmt_client.shared_keys.get_shared_keys(rg_name, workspace_name) + + self.hdinsight_client.extensions.enable_monitoring(rg_name, cluster_name, self.workspace_id, + self.primary_key).wait() monitoring_status = self.hdinsight_client.extensions.get_monitoring_status(rg_name, cluster_name) self.assertTrue(monitoring_status.cluster_monitoring_enabled) self.assertEqual(monitoring_status.workspace_id, self.workspace_id) @@ -530,7 +558,8 @@ def test_resize_cluster(self, resource_group, location, storage_account, storage rg_name = resource_group.name cluster_name = self.get_resource_name('hdisdk-clusterresize') create_params = self.get_cluster_create_params(location, cluster_name, storage_account, storage_account_key) - workernode_params = next(item for item in create_params.properties.compute_profile.roles if item.name == 'workernode') + workernode_params = next( + item for item in create_params.properties.compute_profile.roles if item.name == 'workernode') create_poller = self.hdinsight_client.clusters.create(resource_group.name, cluster_name, create_params) cluster = create_poller.result() self.validate_cluster(cluster_name, create_params, cluster) @@ -577,7 +606,8 @@ def test_script_actions_on_running_cluster(self, resource_group, location, stora self.assertEqual(0, len(script_action_list)) # List script action history and validate script appears there. - list_history_response = list(self.hdinsight_client.script_execution_history.list_by_cluster(rg_name, cluster_name)) + list_history_response = list( + self.hdinsight_client.script_execution_history.list_by_cluster(rg_name, cluster_name)) self.assertEqual(1, len(list_history_response)) script_action = list_history_response[0] self.assertEqual(1, len(script_action.execution_summary)) @@ -587,7 +617,8 @@ def test_script_actions_on_running_cluster(self, resource_group, location, stora self.assertEqual("Succeeded", script_action.status) # Get the script action by ID and validate it's the same action. - script_action = self.hdinsight_client.script_actions.get_execution_detail(rg_name, cluster_name, str(list_history_response[0].script_execution_id)) + script_action = self.hdinsight_client.script_actions.get_execution_detail(rg_name, cluster_name, str( + list_history_response[0].script_execution_id)) self.assertEqual(script_action_params[0].name, script_action.name) # Execute script actions, but don't persist on success. @@ -595,7 +626,8 @@ def test_script_actions_on_running_cluster(self, resource_group, location, stora self.hdinsight_client.clusters.execute_script_actions(rg_name, cluster_name, False, script_action_params).wait() # List script action history and validate the new script also appears. - list_history_response = list(self.hdinsight_client.script_execution_history.list_by_cluster(rg_name, cluster_name)) + list_history_response = list( + self.hdinsight_client.script_execution_history.list_by_cluster(rg_name, cluster_name)) self.assertEqual(2, len(list_history_response)) script_action = next(a for a in list_history_response if a.name == script_action_params[0].name) self.assertIsNotNone(script_action) @@ -606,7 +638,8 @@ def test_script_actions_on_running_cluster(self, resource_group, location, stora self.assertEqual("Succeeded", script_action.status) # Promote non-persisted script. - self.hdinsight_client.script_execution_history.promote(rg_name, cluster_name, str(list_history_response[0].script_execution_id)) + self.hdinsight_client.script_execution_history.promote(rg_name, cluster_name, + str(list_history_response[0].script_execution_id)) # List script action list and validate the promoted script is the only one there. script_action_list = list(self.hdinsight_client.script_actions.list_by_cluster(rg_name, cluster_name)) @@ -617,16 +650,17 @@ def test_script_actions_on_running_cluster(self, resource_group, location, stora self.assertEqual(script_action_params[0].roles, script_action.roles) # List script action history and validate all three scripts are there. - list_history_response = list(self.hdinsight_client.script_execution_history.list_by_cluster(rg_name, cluster_name)) + list_history_response = list( + self.hdinsight_client.script_execution_history.list_by_cluster(rg_name, cluster_name)) self.assertEqual(2, len(list_history_response)) self.assertTrue(all(a.status == "Succeeded" for a in list_history_response)) def get_execute_script_action_params(self, script_name, script_uri): return [ RuntimeScriptAction( - name = script_name, - uri = script_uri, - roles = ['headnode', 'workernode'] + name=script_name, + uri=script_uri, + roles=['headnode', 'workernode'] ) ] @@ -656,7 +690,8 @@ def get_cluster_create_params_for_adls_gen1(self, location, cluster_name, create return create_params - def get_cluster_create_params_for_adls_gen2(self, location, cluster_name, storage_account, storage_account_key, create_params=None): + def get_cluster_create_params_for_adls_gen2(self, location, cluster_name, storage_account, storage_account_key, + create_params=None): if create_params is None: create_params = self.get_cluster_create_params(location, cluster_name) is_default = len(create_params.properties.storage_profile.storageaccounts) == 0 @@ -665,7 +700,7 @@ def get_cluster_create_params_for_adls_gen2(self, location, cluster_name, storag name=storage_account.name + STORAGE_ADLS_FILE_SYSTEM_ENDPOINT_SUFFIX, key=storage_account_key, file_system=cluster_name.lower(), - is_default= is_default + is_default=is_default ) ) @@ -760,15 +795,16 @@ def validate_cluster(self, cluster_name, create_parameters, cluster_response): self.assertEqual(create_parameters.properties.os_type, cluster_response.properties.os_type) self.assertIsNone(cluster_response.properties.errors) self.assertEqual(HDInsightClusterProvisioningState.succeeded, cluster_response.properties.provisioning_state) - self.assertEqual(create_parameters.properties.cluster_definition.kind, cluster_response.properties.cluster_definition.kind) + self.assertEqual(create_parameters.properties.cluster_definition.kind, + cluster_response.properties.cluster_definition.kind) self.assertEqual(create_parameters.properties.cluster_version, cluster_response.properties.cluster_version[0:3]) self.assertIsNone(cluster_response.properties.cluster_definition.configurations) - def validate_http_settings(self, http_settings, expected_user_name, expected_user_password): - self.assertIsNotNone(http_settings) - self.assertEqual('true', http_settings['restAuthCredential.isEnabled']) - self.assertEqual(expected_user_name, http_settings['restAuthCredential.username']) - self.assertEqual(expected_user_password, http_settings['restAuthCredential.password']) + def validate_gateway_settings(self, gateway_settings, expected_user_name, expected_user_password): + self.assertIsNotNone(gateway_settings) + self.assertEqual('true', gateway_settings.is_credential_enabled) + self.assertEqual(expected_user_name, gateway_settings.user_name) + self.assertEqual(expected_user_password, gateway_settings.password) def _setup_scrubber(self): super(MgmtHDInsightTest, self)._setup_scrubber() @@ -778,6 +814,7 @@ def _setup_scrubber(self): self.scrubber.register_name_pair(getattr(self.settings, key), getattr(self._fake_settings, key)) -#------------------------------------------------------------------------------ + +# ------------------------------------------------------------------------------ if __name__ == '__main__': unittest.main() From 12e2e34086ca172b89cae4e0526730c5f3c56ed6 Mon Sep 17 00:00:00 2001 From: Xiang Yan Date: Thu, 4 Jun 2020 07:14:59 -0700 Subject: [PATCH 09/25] disable some by design bandit warnings (#11495) * disable some by design bandit warnings * Packaging update of azure-mgmt-datalake-analytics Co-authored-by: Azure SDK Bot --- sdk/cosmos/azure-cosmos/test/test_crud.py | 16 ++++----- sdk/cosmos/azure-cosmos/test/test_globaldb.py | 4 +-- .../azure-cosmos/test/test_multi_orderby.py | 2 +- sdk/cosmos/azure-cosmos/test/test_orderby.py | 8 ++--- sdk/cosmos/azure-cosmos/test/test_query.py | 18 +++++----- .../azure-mgmt-datalake-analytics/README.md | 33 +++++++------------ .../azure-mgmt-datalake-analytics/setup.py | 5 ++- .../tests/test_mgmt_datalake_analytics.py | 2 +- .../_vendor/storage/blob/_shared/policies.py | 2 +- .../_vendor/storage/blob/_shared/policies.py | 2 +- .../tests/test_browser_credential.py | 4 +-- .../tests/test_certificate_credential.py | 2 +- .../azure/storage/blob/_shared/policies.py | 2 +- .../blob_samples_client_side_encryption.py | 8 ++--- .../tests/encryption_test_helper.py | 8 ++--- .../storage/filedatalake/_shared/policies.py | 2 +- .../tests/testcase.py | 2 +- .../storage/fileshare/_shared/policies.py | 2 +- .../tests/encryption_test_helper.py | 8 ++--- .../azure/storage/queue/_shared/policies.py | 2 +- .../tests/encryption_test_helper.py | 8 ++--- 21 files changed, 67 insertions(+), 73 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/test/test_crud.py b/sdk/cosmos/azure-cosmos/test/test_crud.py index d8e4480381a3..602d031fd7d8 100644 --- a/sdk/cosmos/azure-cosmos/test/test_crud.py +++ b/sdk/cosmos/azure-cosmos/test/test_crud.py @@ -207,7 +207,7 @@ def test_sql_query_crud(self): self.assertEqual(0, len(databases), 'Unexpected number of query results.') # query with a string. - databases = list(self.client.query_databases('SELECT * FROM root r WHERE r.id="' + db2.id + '"')) + databases = list(self.client.query_databases('SELECT * FROM root r WHERE r.id="' + db2.id + '"')) #nosec self.assertEqual(1, len(databases), 'Unexpected number of query results.') self.client.delete_database(db1.id) self.client.delete_database(db2.id) @@ -507,7 +507,7 @@ def test_partitioned_collection_document_crud_and_query(self): # query document on the partition key specified in the predicate will pass even without setting enableCrossPartitionQuery or passing in the partitionKey value documentlist = list(created_collection.query_items( { - 'query': 'SELECT * FROM root r WHERE r.id=\'' + replaced_document.get('id') + '\'' + 'query': 'SELECT * FROM root r WHERE r.id=\'' + replaced_document.get('id') + '\'' #nosec })) self.assertEqual(1, len(documentlist)) @@ -515,14 +515,14 @@ def test_partitioned_collection_document_crud_and_query(self): try: list(created_collection.query_items( { - 'query': 'SELECT * FROM root r WHERE r.key=\'' + replaced_document.get('key') + '\'' + 'query': 'SELECT * FROM root r WHERE r.key=\'' + replaced_document.get('key') + '\'' #nosec })) except Exception: pass # cross partition query documentlist = list(created_collection.query_items( - query='SELECT * FROM root r WHERE r.key=\'' + replaced_document.get('key') + '\'', + query='SELECT * FROM root r WHERE r.key=\'' + replaced_document.get('key') + '\'', #nosec enable_cross_partition_query=True )) @@ -530,7 +530,7 @@ def test_partitioned_collection_document_crud_and_query(self): # query document by providing the partitionKey value documentlist = list(created_collection.query_items( - query='SELECT * FROM root r WHERE r.key=\'' + replaced_document.get('key') + '\'', + query='SELECT * FROM root r WHERE r.key=\'' + replaced_document.get('key') + '\'', #nosec partition_key=replaced_document.get('id') )) @@ -746,14 +746,14 @@ def test_partitioned_collection_conflict_crud_and_query(self): # query conflicts on any property other than partitionKey will fail without setting enableCrossPartitionQuery or passing in the partitionKey value try: list(created_collection.query_conflicts( - query='SELECT * FROM root r WHERE r.resourceType=\'' + conflict_definition.get( + query='SELECT * FROM root r WHERE r.resourceType=\'' + conflict_definition.get( #nosec 'resourceType') + '\'' )) except Exception: pass conflictlist = list(created_collection.query_conflicts( - query='SELECT * FROM root r WHERE r.resourceType=\'' + conflict_definition.get('resourceType') + '\'', + query='SELECT * FROM root r WHERE r.resourceType=\'' + conflict_definition.get('resourceType') + '\'', #nosec enable_cross_partition_query=True )) @@ -762,7 +762,7 @@ def test_partitioned_collection_conflict_crud_and_query(self): # query conflicts by providing the partitionKey value options = {'partitionKey': conflict_definition.get('id')} conflictlist = list(created_collection.query_conflicts( - query='SELECT * FROM root r WHERE r.resourceType=\'' + conflict_definition.get('resourceType') + '\'', + query='SELECT * FROM root r WHERE r.resourceType=\'' + conflict_definition.get('resourceType') + '\'', #nosec partition_key=conflict_definition['id'] )) diff --git a/sdk/cosmos/azure-cosmos/test/test_globaldb.py b/sdk/cosmos/azure-cosmos/test/test_globaldb.py index 467a0de40e6d..88a9289c6694 100644 --- a/sdk/cosmos/azure-cosmos/test/test_globaldb.py +++ b/sdk/cosmos/azure-cosmos/test/test_globaldb.py @@ -89,7 +89,7 @@ def setUp(self): self.client = cosmos_client_connection.CosmosClientConnection(Test_globaldb_tests.host, Test_globaldb_tests.masterKey) # Create the test database only when it's not already present - query_iterable = self.client.QueryDatabases('SELECT * FROM root r WHERE r.id=\'' + Test_globaldb_tests.test_database_id + '\'') + query_iterable = self.client.QueryDatabases('SELECT * FROM root r WHERE r.id=\'' + Test_globaldb_tests.test_database_id + '\'') #nosec it = iter(query_iterable) self.test_db = next(it, None) @@ -97,7 +97,7 @@ def setUp(self): self.test_db = self.client.CreateDatabase({'id' : Test_globaldb_tests.test_database_id}) # Create the test collection only when it's not already present - query_iterable = self.client.QueryContainers(self.test_db['_self'], 'SELECT * FROM root r WHERE r.id=\'' + Test_globaldb_tests.test_collection_id + '\'') + query_iterable = self.client.QueryContainers(self.test_db['_self'], 'SELECT * FROM root r WHERE r.id=\'' + Test_globaldb_tests.test_collection_id + '\'') #nosec it = iter(query_iterable) self.test_coll = next(it, None) diff --git a/sdk/cosmos/azure-cosmos/test/test_multi_orderby.py b/sdk/cosmos/azure-cosmos/test/test_multi_orderby.py index b68db27b520e..1b68b39ae090 100644 --- a/sdk/cosmos/azure-cosmos/test/test_multi_orderby.py +++ b/sdk/cosmos/azure-cosmos/test/test_multi_orderby.py @@ -252,7 +252,7 @@ def test_multi_orderby_queries(self): where_string = "WHERE root." + self.NUMBER_FIELD + " % 2 = 0" if has_filter else "" query = "SELECT " + top_string + " [" + select_item_builder + "] " + \ "FROM root " + where_string + " " + \ - "ORDER BY " + orderby_item_builder + "ORDER BY " + orderby_item_builder #nosec expected_ordered_list = self.top(self.sort(self.filter(self.items, has_filter), composite_index, invert), has_top, top_count) diff --git a/sdk/cosmos/azure-cosmos/test/test_orderby.py b/sdk/cosmos/azure-cosmos/test/test_orderby.py index ba1eb99b3c17..da9e26bc3d16 100644 --- a/sdk/cosmos/azure-cosmos/test/test_orderby.py +++ b/sdk/cosmos/azure-cosmos/test/test_orderby.py @@ -168,7 +168,7 @@ def test_orderby_top_query(self): # an order by query with top, total existing docs more than requested top count query = { - 'query': 'SELECT top %d * FROM root r order by r.spam' % top_count + 'query': 'SELECT top %d * FROM root r order by r.spam' % top_count #nosec } def get_order_by_key(r): @@ -186,7 +186,7 @@ def test_orderby_top_query_less_results_than_top_counts(self): # an order by query with top, total existing docs less than requested top count query = { - 'query': 'SELECT top %d * FROM root r order by r.spam' % top_count + 'query': 'SELECT top %d * FROM root r order by r.spam' % top_count #nosec } def get_order_by_key(r): @@ -226,7 +226,7 @@ def test_top_query(self): # a top query, the results will be sorted based on the target partition key range query = { - 'query': 'SELECT top %d * FROM root r' % len(expected_ordered_ids) + 'query': 'SELECT top %d * FROM root r' % len(expected_ordered_ids) #nosec } self.execute_query_and_validate_results(query, expected_ordered_ids) @@ -260,7 +260,7 @@ def test_top_query_as_string(self): expected_ordered_ids = [d['id'] for d in first_two_ranges_results] # a top query, the results will be sorted based on the target partition key range - query = 'SELECT top %d * FROM root r' % len(expected_ordered_ids) + query = 'SELECT top %d * FROM root r' % len(expected_ordered_ids) #nosec self.execute_query_and_validate_results(query, expected_ordered_ids) def test_parametrized_top_query(self): diff --git a/sdk/cosmos/azure-cosmos/test/test_query.py b/sdk/cosmos/azure-cosmos/test/test_query.py index e9e066c8df50..80cb9c3ec32c 100644 --- a/sdk/cosmos/azure-cosmos/test/test_query.py +++ b/sdk/cosmos/azure-cosmos/test/test_query.py @@ -349,55 +349,55 @@ def test_distinct(self): padded_docs = self._pad_with_none(documents, distinct_field) self._validate_distinct(created_collection=created_collection, - query='SELECT distinct c.%s from c ORDER BY c.%s' % (distinct_field, distinct_field), + query='SELECT distinct c.%s from c ORDER BY c.%s' % (distinct_field, distinct_field), #nosec results=self._get_distinct_docs(self._get_order_by_docs(padded_docs, distinct_field, None), distinct_field, None, True), is_select=False, fields=[distinct_field]) self._validate_distinct(created_collection=created_collection, - query='SELECT distinct c.%s, c.%s from c ORDER BY c.%s, c.%s' % (distinct_field, pk_field, pk_field, distinct_field), + query='SELECT distinct c.%s, c.%s from c ORDER BY c.%s, c.%s' % (distinct_field, pk_field, pk_field, distinct_field), #nosec results=self._get_distinct_docs(self._get_order_by_docs(padded_docs, pk_field, distinct_field), distinct_field, pk_field, True), is_select=False, fields=[distinct_field, pk_field]) self._validate_distinct(created_collection=created_collection, - query='SELECT distinct c.%s, c.%s from c ORDER BY c.%s, c.%s' % (distinct_field, pk_field, distinct_field, pk_field), + query='SELECT distinct c.%s, c.%s from c ORDER BY c.%s, c.%s' % (distinct_field, pk_field, distinct_field, pk_field), #nosec results=self._get_distinct_docs(self._get_order_by_docs(padded_docs, distinct_field, pk_field), distinct_field, pk_field, True), is_select=False, fields=[distinct_field, pk_field]) self._validate_distinct(created_collection=created_collection, - query='SELECT distinct value c.%s from c ORDER BY c.%s' % (distinct_field, distinct_field), + query='SELECT distinct value c.%s from c ORDER BY c.%s' % (distinct_field, distinct_field), #nosec results=self._get_distinct_docs(self._get_order_by_docs(padded_docs, distinct_field, None), distinct_field, None, True), is_select=False, fields=[distinct_field]) self._validate_distinct(created_collection=created_collection, - query='SELECT distinct c.%s from c' % (distinct_field), + query='SELECT distinct c.%s from c' % (distinct_field), #nosec results=self._get_distinct_docs(padded_docs, distinct_field, None, False), is_select=True, fields=[distinct_field]) self._validate_distinct(created_collection=created_collection, - query='SELECT distinct c.%s, c.%s from c' % (distinct_field, pk_field), + query='SELECT distinct c.%s, c.%s from c' % (distinct_field, pk_field), #nosec results=self._get_distinct_docs(padded_docs, distinct_field, pk_field, False), is_select=True, fields=[distinct_field, pk_field]) self._validate_distinct(created_collection=created_collection, - query='SELECT distinct value c.%s from c' % (distinct_field), + query='SELECT distinct value c.%s from c' % (distinct_field), #nosec results=self._get_distinct_docs(padded_docs, distinct_field, None, True), is_select=True, fields=[distinct_field]) self._validate_distinct(created_collection=created_collection, - query='SELECT distinct c.%s from c ORDER BY c.%s' % (different_field, different_field), + query='SELECT distinct c.%s from c ORDER BY c.%s' % (different_field, different_field), #nosec results=[], is_select=True, fields=[different_field]) self._validate_distinct(created_collection=created_collection, - query='SELECT distinct c.%s from c' % (different_field), + query='SELECT distinct c.%s from c' % (different_field), #nosec results=['None'], is_select=True, fields=[different_field]) diff --git a/sdk/datalake/azure-mgmt-datalake-analytics/README.md b/sdk/datalake/azure-mgmt-datalake-analytics/README.md index a7b30f74cea7..e90c728d4daf 100644 --- a/sdk/datalake/azure-mgmt-datalake-analytics/README.md +++ b/sdk/datalake/azure-mgmt-datalake-analytics/README.md @@ -1,30 +1,21 @@ -## Microsoft Azure SDK for Python +# Microsoft Azure SDK for Python -This is the Microsoft Azure Data Lake Analytics Management Client -Library. +This is the Microsoft Azure Data Lake Analytics Management Client Library. +This package has been tested with Python 2.7, 3.5, 3.6, 3.7 and 3.8. +For a more complete view of Azure libraries, see the [Github repo](https://github.com/Azure/azure-sdk-for-python/) -Azure Resource Manager (ARM) is the next generation of management APIs -that replace the old Azure Service Management (ASM). -This package has been tested with Python 2.7, 3.5, 3.6 and 3.7. +# Usage -For the older Azure Service Management (ASM) libraries, see -[azure-servicemanagement-legacy](https://pypi.python.org/pypi/azure-servicemanagement-legacy) -library. - -For a more complete set of Azure libraries, see the -[azure](https://pypi.python.org/pypi/azure) bundle package. - -## Usage - -For code examples, see [Data Lake Analytics -Management](https://docs.microsoft.com/python/api/overview/azure/data-lake-analytics) +For code examples, see [Data Lake Analytics Management](https://docs.microsoft.com/python/api/overview/azure/data-lake-analytics) on docs.microsoft.com. -## Provide Feedback -If you encounter any bugs or have suggestions, please file an issue in -the [Issues](https://github.com/Azure/azure-sdk-for-python/issues) +# Provide Feedback + +If you encounter any bugs or have suggestions, please file an issue in the +[Issues](https://github.com/Azure/azure-sdk-for-python/issues) section of the project. -![image](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-python%2Fazure-mgmt-datalake-analytics%2FREADME.png) + +![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-python%2Fazure-mgmt-datalake-analytics%2FREADME.png) diff --git a/sdk/datalake/azure-mgmt-datalake-analytics/setup.py b/sdk/datalake/azure-mgmt-datalake-analytics/setup.py index 59d06fe21618..7cde837fe302 100644 --- a/sdk/datalake/azure-mgmt-datalake-analytics/setup.py +++ b/sdk/datalake/azure-mgmt-datalake-analytics/setup.py @@ -36,7 +36,9 @@ pass # Version extraction inspired from 'requests' -with open(os.path.join(package_folder_path, 'version.py'), 'r') as fd: +with open(os.path.join(package_folder_path, 'version.py') + if os.path.exists(os.path.join(package_folder_path, 'version.py')) + else os.path.join(package_folder_path, '_version.py'), 'r') as fd: version = re.search(r'^VERSION\s*=\s*[\'"]([^\'"]*)[\'"]', fd.read(), re.MULTILINE).group(1) @@ -67,6 +69,7 @@ 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', 'License :: OSI Approved :: MIT License', ], zip_safe=False, diff --git a/sdk/datalake/azure-mgmt-datalake-analytics/tests/test_mgmt_datalake_analytics.py b/sdk/datalake/azure-mgmt-datalake-analytics/tests/test_mgmt_datalake_analytics.py index fd9d27cf5e6a..812dd68c8f3b 100644 --- a/sdk/datalake/azure-mgmt-datalake-analytics/tests/test_mgmt_datalake_analytics.py +++ b/sdk/datalake/azure-mgmt-datalake-analytics/tests/test_mgmt_datalake_analytics.py @@ -154,7 +154,7 @@ def setUp(self): ) AS T(a, b); -END;""".format(self.db_name, self.table_name, self.tvf_name, self.view_name, self.proc_name) +END;""".format(self.db_name, self.table_name, self.tvf_name, self.view_name, self.proc_name) #nosec # define all the job IDs to be used during execution if self.is_playback(): diff --git a/sdk/eventhub/azure-eventhub-checkpointstoreblob-aio/azure/eventhub/extensions/checkpointstoreblobaio/_vendor/storage/blob/_shared/policies.py b/sdk/eventhub/azure-eventhub-checkpointstoreblob-aio/azure/eventhub/extensions/checkpointstoreblobaio/_vendor/storage/blob/_shared/policies.py index b603efe505e8..07331541191e 100644 --- a/sdk/eventhub/azure-eventhub-checkpointstoreblob-aio/azure/eventhub/extensions/checkpointstoreblobaio/_vendor/storage/blob/_shared/policies.py +++ b/sdk/eventhub/azure-eventhub-checkpointstoreblob-aio/azure/eventhub/extensions/checkpointstoreblobaio/_vendor/storage/blob/_shared/policies.py @@ -350,7 +350,7 @@ def __init__(self, **kwargs): # pylint: disable=unused-argument @staticmethod def get_content_md5(data): - md5 = hashlib.md5() + md5 = hashlib.md5() #nosec if isinstance(data, bytes): md5.update(data) elif hasattr(data, 'read'): diff --git a/sdk/eventhub/azure-eventhub-checkpointstoreblob/azure/eventhub/extensions/checkpointstoreblob/_vendor/storage/blob/_shared/policies.py b/sdk/eventhub/azure-eventhub-checkpointstoreblob/azure/eventhub/extensions/checkpointstoreblob/_vendor/storage/blob/_shared/policies.py index b603efe505e8..07331541191e 100644 --- a/sdk/eventhub/azure-eventhub-checkpointstoreblob/azure/eventhub/extensions/checkpointstoreblob/_vendor/storage/blob/_shared/policies.py +++ b/sdk/eventhub/azure-eventhub-checkpointstoreblob/azure/eventhub/extensions/checkpointstoreblob/_vendor/storage/blob/_shared/policies.py @@ -350,7 +350,7 @@ def __init__(self, **kwargs): # pylint: disable=unused-argument @staticmethod def get_content_md5(data): - md5 = hashlib.md5() + md5 = hashlib.md5() #nosec if isinstance(data, bytes): md5.update(data) elif hasattr(data, 'read'): diff --git a/sdk/identity/azure-identity/tests/test_browser_credential.py b/sdk/identity/azure-identity/tests/test_browser_credential.py index 3892d18ffc52..e662b027d7d7 100644 --- a/sdk/identity/azure-identity/tests/test_browser_credential.py +++ b/sdk/identity/azure-identity/tests/test_browser_credential.py @@ -284,8 +284,8 @@ def test_redirect_server(): thread.start() # send a request, verify the server exposes the query - url = "http://127.0.0.1:{}/?{}={}".format(port, expected_param, expected_value) - response = urllib.request.urlopen(url) + url = "http://127.0.0.1:{}/?{}={}".format(port, expected_param, expected_value) #nosec + response = urllib.request.urlopen(url) #nosec assert response.code == 200 assert server.query_params[expected_param] == [expected_value] diff --git a/sdk/identity/azure-identity/tests/test_certificate_credential.py b/sdk/identity/azure-identity/tests/test_certificate_credential.py index 06b65ee54c88..7a783b4a727b 100644 --- a/sdk/identity/azure-identity/tests/test_certificate_credential.py +++ b/sdk/identity/azure-identity/tests/test_certificate_credential.py @@ -135,7 +135,7 @@ def validate_jwt(request, client_id, pem_bytes): deserialized_header = json.loads(header.decode("utf-8")) assert deserialized_header["alg"] == "RS256" assert deserialized_header["typ"] == "JWT" - assert urlsafeb64_decode(deserialized_header["x5t"]) == cert.fingerprint(hashes.SHA1()) + assert urlsafeb64_decode(deserialized_header["x5t"]) == cert.fingerprint(hashes.SHA1()) #nosec assert claims["aud"] == request.url assert claims["iss"] == claims["sub"] == client_id diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/policies.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/policies.py index b4a2f9eecbdf..2ba9ea48377d 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/policies.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/policies.py @@ -322,7 +322,7 @@ def __init__(self, **kwargs): # pylint: disable=unused-argument @staticmethod def get_content_md5(data): - md5 = hashlib.md5() + md5 = hashlib.md5() #nosec if isinstance(data, bytes): md5.update(data) elif hasattr(data, 'read'): diff --git a/sdk/storage/azure-storage-blob/samples/blob_samples_client_side_encryption.py b/sdk/storage/azure-storage-blob/samples/blob_samples_client_side_encryption.py index 1a9b60364bd1..0d6ed51105b9 100644 --- a/sdk/storage/azure-storage-blob/samples/blob_samples_client_side_encryption.py +++ b/sdk/storage/azure-storage-blob/samples/blob_samples_client_side_encryption.py @@ -87,8 +87,8 @@ def wrap_key(self, key, algorithm='RSA'): if algorithm == 'RSA': return self.public_key.encrypt(key, OAEP( - mgf=MGF1(algorithm=SHA1()), - algorithm=SHA1(), + mgf=MGF1(algorithm=SHA1()), #nosec + algorithm=SHA1(), #nosec label=None) ) raise ValueError('Unknown key wrap algorithm.') @@ -97,8 +97,8 @@ def unwrap_key(self, key, algorithm): if algorithm == 'RSA': return self.private_key.decrypt(key, OAEP( - mgf=MGF1(algorithm=SHA1()), - algorithm=SHA1(), + mgf=MGF1(algorithm=SHA1()), #nosec + algorithm=SHA1(), #nosec label=None) ) raise ValueError('Unknown key wrap algorithm.') diff --git a/sdk/storage/azure-storage-blob/tests/encryption_test_helper.py b/sdk/storage/azure-storage-blob/tests/encryption_test_helper.py index a7548a549cb8..3f997142c7aa 100644 --- a/sdk/storage/azure-storage-blob/tests/encryption_test_helper.py +++ b/sdk/storage/azure-storage-blob/tests/encryption_test_helper.py @@ -65,8 +65,8 @@ def wrap_key(self, key, algorithm='RSA'): if algorithm == 'RSA': return self.public_key.encrypt(key, OAEP( - mgf=MGF1(algorithm=SHA1()), - algorithm=SHA1(), + mgf=MGF1(algorithm=SHA1()), #nosec + algorithm=SHA1(), #nosec label=None) ) @@ -76,8 +76,8 @@ def unwrap_key(self, key, algorithm): if algorithm == 'RSA': return self.private_key.decrypt(key, OAEP( - mgf=MGF1(algorithm=SHA1()), - algorithm=SHA1(), + mgf=MGF1(algorithm=SHA1()), #nosec + algorithm=SHA1(), #nosec label=None) ) diff --git a/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/policies.py b/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/policies.py index b4a2f9eecbdf..2ba9ea48377d 100644 --- a/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/policies.py +++ b/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/policies.py @@ -322,7 +322,7 @@ def __init__(self, **kwargs): # pylint: disable=unused-argument @staticmethod def get_content_md5(data): - md5 = hashlib.md5() + md5 = hashlib.md5() #nosec if isinstance(data, bytes): md5.update(data) elif hasattr(data, 'read'): diff --git a/sdk/storage/azure-storage-file-datalake/tests/testcase.py b/sdk/storage/azure-storage-file-datalake/tests/testcase.py index 14be122d4475..40d6a8fe5776 100644 --- a/sdk/storage/azure-storage-file-datalake/tests/testcase.py +++ b/sdk/storage/azure-storage-file-datalake/tests/testcase.py @@ -354,7 +354,7 @@ def _scrub(self, val): val = val.replace(old_value.encode(), new_value.encode()) elif isinstance(val, dict): val2 = str(val).replace(old_value, new_value) - val = eval(val2) + val = eval(val2) #nosec else: val = val.replace(old_value, new_value) return val diff --git a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/policies.py b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/policies.py index b4a2f9eecbdf..2ba9ea48377d 100644 --- a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/policies.py +++ b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/policies.py @@ -322,7 +322,7 @@ def __init__(self, **kwargs): # pylint: disable=unused-argument @staticmethod def get_content_md5(data): - md5 = hashlib.md5() + md5 = hashlib.md5() #nosec if isinstance(data, bytes): md5.update(data) elif hasattr(data, 'read'): diff --git a/sdk/storage/azure-storage-file-share/tests/encryption_test_helper.py b/sdk/storage/azure-storage-file-share/tests/encryption_test_helper.py index a7548a549cb8..3f997142c7aa 100644 --- a/sdk/storage/azure-storage-file-share/tests/encryption_test_helper.py +++ b/sdk/storage/azure-storage-file-share/tests/encryption_test_helper.py @@ -65,8 +65,8 @@ def wrap_key(self, key, algorithm='RSA'): if algorithm == 'RSA': return self.public_key.encrypt(key, OAEP( - mgf=MGF1(algorithm=SHA1()), - algorithm=SHA1(), + mgf=MGF1(algorithm=SHA1()), #nosec + algorithm=SHA1(), #nosec label=None) ) @@ -76,8 +76,8 @@ def unwrap_key(self, key, algorithm): if algorithm == 'RSA': return self.private_key.decrypt(key, OAEP( - mgf=MGF1(algorithm=SHA1()), - algorithm=SHA1(), + mgf=MGF1(algorithm=SHA1()), #nosec + algorithm=SHA1(), #nosec label=None) ) diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/policies.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/policies.py index b4a2f9eecbdf..2ba9ea48377d 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/policies.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/policies.py @@ -322,7 +322,7 @@ def __init__(self, **kwargs): # pylint: disable=unused-argument @staticmethod def get_content_md5(data): - md5 = hashlib.md5() + md5 = hashlib.md5() #nosec if isinstance(data, bytes): md5.update(data) elif hasattr(data, 'read'): diff --git a/sdk/storage/azure-storage-queue/tests/encryption_test_helper.py b/sdk/storage/azure-storage-queue/tests/encryption_test_helper.py index a7548a549cb8..3f997142c7aa 100644 --- a/sdk/storage/azure-storage-queue/tests/encryption_test_helper.py +++ b/sdk/storage/azure-storage-queue/tests/encryption_test_helper.py @@ -65,8 +65,8 @@ def wrap_key(self, key, algorithm='RSA'): if algorithm == 'RSA': return self.public_key.encrypt(key, OAEP( - mgf=MGF1(algorithm=SHA1()), - algorithm=SHA1(), + mgf=MGF1(algorithm=SHA1()), #nosec + algorithm=SHA1(), #nosec label=None) ) @@ -76,8 +76,8 @@ def unwrap_key(self, key, algorithm): if algorithm == 'RSA': return self.private_key.decrypt(key, OAEP( - mgf=MGF1(algorithm=SHA1()), - algorithm=SHA1(), + mgf=MGF1(algorithm=SHA1()), #nosec + algorithm=SHA1(), #nosec label=None) ) From 92d63895ee9ebf049c0478f5d31e49fbfa423512 Mon Sep 17 00:00:00 2001 From: Azure SDK Bot <53356347+azure-sdk@users.noreply.github.com> Date: Thu, 4 Jun 2020 07:21:42 -0700 Subject: [PATCH 10/25] Increment package version after release of azure_core (#11795) --- sdk/core/azure-core/CHANGELOG.md | 3 +++ sdk/core/azure-core/azure/core/_version.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/sdk/core/azure-core/CHANGELOG.md b/sdk/core/azure-core/CHANGELOG.md index 5fd84d19d465..bc650815c813 100644 --- a/sdk/core/azure-core/CHANGELOG.md +++ b/sdk/core/azure-core/CHANGELOG.md @@ -1,6 +1,9 @@ # Release History +## 1.6.1 (Unreleased) + + ## 1.6.0 (2020-06-03) ### Bug fixes diff --git a/sdk/core/azure-core/azure/core/_version.py b/sdk/core/azure-core/azure/core/_version.py index f83b79240838..63b396f7f785 100644 --- a/sdk/core/azure-core/azure/core/_version.py +++ b/sdk/core/azure-core/azure/core/_version.py @@ -9,4 +9,4 @@ # regenerated. # -------------------------------------------------------------------------- -VERSION = "1.6.0" +VERSION = "1.6.1" From 48d6007a663a25646717fee90dd73f5fe95d81f2 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Thu, 4 Jun 2020 08:24:17 -0700 Subject: [PATCH 11/25] Use subject claim as home_account_id when no client_info (#11639) --- .../identity/_internal/msal_credentials.py | 12 +++-- .../tests/test_interactive_credential.py | 53 +++++++++++++++++++ 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/sdk/identity/azure-identity/azure/identity/_internal/msal_credentials.py b/sdk/identity/azure-identity/azure/identity/_internal/msal_credentials.py index 1701a0c12b85..775b11b79368 100644 --- a/sdk/identity/azure-identity/azure/identity/_internal/msal_credentials.py +++ b/sdk/identity/azure-identity/azure/identity/_internal/msal_credentials.py @@ -61,18 +61,24 @@ def _build_auth_record(response): """Build an AuthenticationRecord from the result of an MSAL ClientApplication token request""" try: - client_info = json.loads(_decode_client_info(response["client_info"])) id_token = response["id_token_claims"] + if "client_info" in response: + client_info = json.loads(_decode_client_info(response["client_info"])) + home_account_id = "{uid}.{utid}".format(**client_info) + else: + # MSAL uses the subject claim as home_account_id when the STS doesn't provide client_info + home_account_id = id_token["sub"] + return AuthenticationRecord( authority=urlparse(id_token["iss"]).netloc, # "iss" is the URL of the issuing tenant client_id=id_token["aud"], - home_account_id="{uid}.{utid}".format(**client_info), + home_account_id=home_account_id, tenant_id=id_token["tid"], # tenant which issued the token, not necessarily user's home tenant username=id_token["preferred_username"], ) except (KeyError, ValueError): - # surprising: msal.ClientApplication always requests client_info and an id token, whose shapes shouldn't change + # surprising: msal.ClientApplication always requests an id token, whose shape shouldn't change return None diff --git a/sdk/identity/azure-identity/tests/test_interactive_credential.py b/sdk/identity/azure-identity/tests/test_interactive_credential.py index 631844567f09..0f3efd57d32e 100644 --- a/sdk/identity/azure-identity/tests/test_interactive_credential.py +++ b/sdk/identity/azure-identity/tests/test_interactive_credential.py @@ -18,6 +18,8 @@ except ImportError: # python < 3.3 from mock import Mock, patch # type: ignore +from helpers import build_aad_response + class MockCredential(InteractiveCredential): """Test class to drive InteractiveCredential. @@ -266,3 +268,54 @@ def _request_token(self, *_, **__): TestCredential(enable_persistent_cache=True, allow_unencrypted_cache=True) assert mock_extensions.PersistedTokenCache.called_with(mock_extensions.FilePersistence) + + +def test_home_account_id_client_info(): + """when MSAL returns client_info, the credential should decode it to get the home_account_id""" + + object_id = "object-id" + home_tenant = "home-tenant-id" + msal_response = build_aad_response(uid=object_id, utid=home_tenant, access_token="***", refresh_token="**") + msal_response["id_token_claims"] = { + "aud": "client-id", + "iss": "https://localhost", + "object_id": object_id, + "tid": home_tenant, + "preferred_username": "me", + "sub": "subject", + } + + class TestCredential(InteractiveCredential): + def __init__(self, **kwargs): + super(TestCredential, self).__init__(client_id="...", **kwargs) + + def _request_token(self, *_, **__): + return msal_response + + record = TestCredential().authenticate() + assert record.home_account_id == "{}.{}".format(object_id, home_tenant) + + +def test_home_account_id_no_client_info(): + """the credential should use the subject claim as home_account_id when MSAL doesn't provide client_info""" + + subject = "subject" + msal_response = build_aad_response(access_token="***", refresh_token="**") + msal_response["id_token_claims"] = { + "aud": "client-id", + "iss": "https://localhost", + "object_id": "some-guid", + "tid": "some-tenant", + "preferred_username": "me", + "sub": subject, + } + + class TestCredential(InteractiveCredential): + def __init__(self, **kwargs): + super(TestCredential, self).__init__(client_id="...", **kwargs) + + def _request_token(self, *_, **__): + return msal_response + + record = TestCredential().authenticate() + assert record.home_account_id == subject From d4633cf0011f63c68df9fbd26b4340ce41dcd3c0 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Thu, 4 Jun 2020 08:40:42 -0700 Subject: [PATCH 12/25] Refactor ClientCertificateCredential to use AadClient (#11719) --- .../azure-identity/azure/identity/_base.py | 52 ----------------- .../identity/_credentials/certificate.py | 12 ++-- .../azure/identity/_internal/__init__.py | 4 ++ .../azure/identity/_internal/aad_client.py | 9 +++ .../identity/_internal/aad_client_base.py | 56 +++++++++++++++++-- .../_internal/aadclient_certificate.py | 41 ++++++++++++++ .../_internal/certificate_credential_base.py | 47 ++++++++++++++++ .../identity/aio/_credentials/certificate.py | 15 +++-- .../identity/aio/_internal/aad_client.py | 9 +++ 9 files changed, 174 insertions(+), 71 deletions(-) create mode 100644 sdk/identity/azure-identity/azure/identity/_internal/aadclient_certificate.py create mode 100644 sdk/identity/azure-identity/azure/identity/_internal/certificate_credential_base.py diff --git a/sdk/identity/azure-identity/azure/identity/_base.py b/sdk/identity/azure-identity/azure/identity/_base.py index 45941d80a88e..058d0d35665e 100644 --- a/sdk/identity/azure-identity/azure/identity/_base.py +++ b/sdk/identity/azure-identity/azure/identity/_base.py @@ -3,13 +3,6 @@ # Licensed under the MIT License. # ------------------------------------ import abc -import binascii - -from cryptography import x509 -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.backends import default_backend -from msal.oauth2cli import JwtSigner -import six try: ABC = abc.ABC @@ -41,48 +34,3 @@ def __init__(self, tenant_id, client_id, secret, **kwargs): # pylint:disable=un ) self._form_data = {"client_id": client_id, "client_secret": secret, "grant_type": "client_credentials"} super(ClientSecretCredentialBase, self).__init__() - - -class CertificateCredentialBase(ABC): - """Sans I/O base for certificate credentials""" - - def __init__(self, tenant_id, client_id, certificate_path, **kwargs): # pylint:disable=unused-argument - # type: (str, str, str, **Any) -> None - if not certificate_path: - raise ValueError( - "'certificate_path' must be the path to a PEM file containing an x509 certificate and its private key" - ) - - super(CertificateCredentialBase, self).__init__() - - password = kwargs.pop("password", None) - if isinstance(password, six.text_type): - password = password.encode(encoding="utf-8") - - with open(certificate_path, "rb") as f: - pem_bytes = f.read() - - private_key = serialization.load_pem_private_key(pem_bytes, password=password, backend=default_backend()) - cert = x509.load_pem_x509_certificate(pem_bytes, default_backend()) - fingerprint = cert.fingerprint(hashes.SHA1()) #nosec - - self._client = self._get_auth_client(tenant_id, **kwargs) - self._client_id = client_id - self._signer = JwtSigner(private_key, "RS256", sha1_thumbprint=binascii.hexlify(fingerprint)) - - def _get_request_data(self, *scopes): - assertion = self._signer.sign_assertion(audience=self._client.auth_url, issuer=self._client_id) - if isinstance(assertion, six.binary_type): - assertion = assertion.decode("utf-8") - - return { - "client_assertion": assertion, - "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", - "client_id": self._client_id, - "grant_type": "client_credentials", - "scope": " ".join(scopes), - } - - @abc.abstractmethod - def _get_auth_client(self, tenant_id, **kwargs): - pass diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/certificate.py b/sdk/identity/azure-identity/azure/identity/_credentials/certificate.py index 3ed84cd335a0..56d640c12e37 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/certificate.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/certificate.py @@ -4,8 +4,7 @@ # ------------------------------------ from typing import TYPE_CHECKING -from .._authn_client import AuthnClient -from .._base import CertificateCredentialBase +from .._internal import AadClient, CertificateCredentialBase if TYPE_CHECKING: from azure.core.credentials import AccessToken @@ -42,11 +41,10 @@ def get_token(self, *scopes, **kwargs): # pylint:disable=unused-argument if not scopes: raise ValueError("'get_token' requires at least one scope") - token = self._client.get_cached_token(scopes) + token = self._client.get_cached_access_token(scopes) if not token: - data = self._get_request_data(*scopes) - token = self._client.request_token(scopes, form_data=data) + token = self._client.obtain_token_by_client_certificate(scopes, self._certificate, **kwargs) return token - def _get_auth_client(self, tenant_id, **kwargs): - return AuthnClient(tenant=tenant_id, **kwargs) + def _get_auth_client(self, tenant_id, client_id, **kwargs): + return AadClient(tenant_id, client_id, **kwargs) diff --git a/sdk/identity/azure-identity/azure/identity/_internal/__init__.py b/sdk/identity/azure-identity/azure/identity/_internal/__init__.py index b6d5ec1f2632..b966c03023e4 100644 --- a/sdk/identity/azure-identity/azure/identity/_internal/__init__.py +++ b/sdk/identity/azure-identity/azure/identity/_internal/__init__.py @@ -33,6 +33,8 @@ def get_default_authority(): from .aad_client import AadClient from .aad_client_base import AadClientBase from .auth_code_redirect_handler import AuthCodeRedirectServer +from .aadclient_certificate import AadClientCertificate +from .certificate_credential_base import CertificateCredentialBase from .exception_wrapper import wrap_exceptions from .msal_credentials import ConfidentialClientCredential, InteractiveCredential, PublicClientCredential from .msal_transport_adapter import MsalTransportAdapter, MsalTransportResponse @@ -56,6 +58,8 @@ def _scopes_to_resource(*scopes): "AadClient", "AadClientBase", "AuthCodeRedirectServer", + "AadClientCertificate", + "CertificateCredentialBase", "ConfidentialClientCredential", "get_default_authority", "InteractiveCredential", diff --git a/sdk/identity/azure-identity/azure/identity/_internal/aad_client.py b/sdk/identity/azure-identity/azure/identity/_internal/aad_client.py index 75de3d05cf41..6877f53e0bc5 100644 --- a/sdk/identity/azure-identity/azure/identity/_internal/aad_client.py +++ b/sdk/identity/azure-identity/azure/identity/_internal/aad_client.py @@ -26,6 +26,7 @@ from azure.core.credentials import AccessToken from azure.core.pipeline.policies import HTTPPolicy, SansIOHTTPPolicy from azure.core.pipeline.transport import HttpTransport + from .._internal import AadClientCertificate Policy = Union[HTTPPolicy, SansIOHTTPPolicy] @@ -41,6 +42,14 @@ def obtain_token_by_authorization_code(self, scopes, code, redirect_uri, client_ content = ContentDecodePolicy.deserialize_from_http_generics(response.http_response) return self._process_response(response=content, scopes=scopes, now=now) + def obtain_token_by_client_certificate(self, scopes, certificate, **kwargs): + # type: (Sequence[str], AadClientCertificate, **Any) -> AccessToken + request = self._get_client_certificate_request(scopes, certificate) + now = int(time.time()) + response = self._pipeline.run(request, stream=False, **kwargs) + content = ContentDecodePolicy.deserialize_from_http_generics(response.http_response) + return self._process_response(response=content, scopes=scopes, now=now) + def obtain_token_by_refresh_token(self, scopes, refresh_token, **kwargs): # type: (str, Sequence[str], **Any) -> AccessToken request = self._get_refresh_token_request(scopes, refresh_token) diff --git a/sdk/identity/azure-identity/azure/identity/_internal/aad_client_base.py b/sdk/identity/azure-identity/azure/identity/_internal/aad_client_base.py index bf659087a2cb..96a7b37cb71e 100644 --- a/sdk/identity/azure-identity/azure/identity/_internal/aad_client_base.py +++ b/sdk/identity/azure-identity/azure/identity/_internal/aad_client_base.py @@ -3,9 +3,13 @@ # Licensed under the MIT License. # ------------------------------------ import abc +import base64 import copy +import json import time +from uuid import uuid4 +import six from msal import TokenCache from azure.core.pipeline.transport import HttpRequest @@ -29,6 +33,7 @@ from azure.core.pipeline import AsyncPipeline, Pipeline from azure.core.pipeline.policies import AsyncHTTPPolicy, HTTPPolicy, SansIOHTTPPolicy from azure.core.pipeline.transport import AsyncHttpTransport, HttpTransport + from .._internal import AadClientCertificate PipelineType = Union[AsyncPipeline, Pipeline] PolicyType = Union[AsyncHTTPPolicy, HTTPPolicy, SansIOHTTPPolicy] @@ -62,6 +67,10 @@ def get_cached_refresh_tokens(self, scopes): def obtain_token_by_authorization_code(self, scopes, code, redirect_uri, client_secret=None, **kwargs): pass + @abc.abstractmethod + def obtain_token_by_client_certificate(self, scopes, certificate, **kwargs): + pass + @abc.abstractmethod def obtain_token_by_refresh_token(self, scopes, refresh_token, **kwargs): pass @@ -90,8 +99,7 @@ def _process_response(self, response, scopes, now): return AccessToken(response_copy["access_token"], expires_on) def _get_auth_code_request(self, scopes, code, redirect_uri, client_secret=None): - # type: (str, str, Sequence[str], Optional[str]) -> HttpRequest - + # type: (Sequence[str], str, str, Optional[str]) -> HttpRequest data = { "client_id": self._client_id, "code": code, @@ -107,9 +115,49 @@ def _get_auth_code_request(self, scopes, code, redirect_uri, client_secret=None) ) return request - def _get_refresh_token_request(self, scopes, refresh_token): - # type: (str, Sequence[str]) -> HttpRequest + def _get_client_certificate_request(self, scopes, certificate): + # type: (Sequence[str], AadClientCertificate) -> HttpRequest + assertion = self._get_jwt_assertion(certificate) + data = { + "client_assertion": assertion, + "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", + "client_id": self._client_id, + "grant_type": "client_credentials", + "scope": " ".join(scopes), + } + request = HttpRequest( + "POST", self._token_endpoint, headers={"Content-Type": "application/x-www-form-urlencoded"}, data=data + ) + return request + + def _get_jwt_assertion(self, certificate): + # type: (AadClientCertificate) -> str + now = int(time.time()) + header = six.ensure_binary( + json.dumps({"typ": "JWT", "alg": "RS256", "x5t": certificate.thumbprint}), encoding="utf-8" + ) + payload = six.ensure_binary( + json.dumps( + { + "jti": str(uuid4()), + "aud": self._token_endpoint, + "iss": self._client_id, + "sub": self._client_id, + "nbf": now, + "exp": now + (60 * 30), + } + ), + encoding="utf-8", + ) + jws = base64.urlsafe_b64encode(header) + b"." + base64.urlsafe_b64encode(payload) + signature = certificate.sign(jws) + jwt_bytes = jws + b"." + base64.urlsafe_b64encode(signature) + + return jwt_bytes.decode("utf-8") + + def _get_refresh_token_request(self, scopes, refresh_token): + # type: (Sequence[str], str) -> HttpRequest data = { "grant_type": "refresh_token", "refresh_token": refresh_token, diff --git a/sdk/identity/azure-identity/azure/identity/_internal/aadclient_certificate.py b/sdk/identity/azure-identity/azure/identity/_internal/aadclient_certificate.py new file mode 100644 index 000000000000..271fcd42dcbc --- /dev/null +++ b/sdk/identity/azure-identity/azure/identity/_internal/aadclient_certificate.py @@ -0,0 +1,41 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +import base64 +from typing import TYPE_CHECKING + +from cryptography import x509 +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import padding +from cryptography.hazmat.backends import default_backend +import six + +if TYPE_CHECKING: + # pylint:disable=unused-import,ungrouped-imports + from typing import Optional + + +class AadClientCertificate(object): + """Wraps 'cryptography' to provide the crypto operations AadClient requires for certificate authentication. + + :param bytes pem_bytes: bytes of a a PEM-encoded certificate including the private key + :param bytes password: (optional) the certificate's password + """ + def __init__(self, pem_bytes, password=None): + # type: (bytes, Optional[bytes]) -> None + cert = x509.load_pem_x509_certificate(pem_bytes, default_backend()) + fingerprint = cert.fingerprint(hashes.SHA1()) # nosec + self._private_key = serialization.load_pem_private_key(pem_bytes, password=password, backend=default_backend()) + self._thumbprint = six.ensure_str(base64.urlsafe_b64encode(fingerprint), encoding="utf-8") + + @property + def thumbprint(self): + # type: () -> str + """The certificate's SHA1 thumbprint as a base64url-encoded string""" + return self._thumbprint + + def sign(self, plaintext): + # type: (bytes) -> bytes + """Sign bytes using RS256""" + return self._private_key.sign(plaintext, padding.PKCS1v15(), hashes.SHA256()) diff --git a/sdk/identity/azure-identity/azure/identity/_internal/certificate_credential_base.py b/sdk/identity/azure-identity/azure/identity/_internal/certificate_credential_base.py new file mode 100644 index 000000000000..1b8736c14019 --- /dev/null +++ b/sdk/identity/azure-identity/azure/identity/_internal/certificate_credential_base.py @@ -0,0 +1,47 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +import abc + +import six +from azure.identity._internal import AadClientCertificate + +try: + ABC = abc.ABC +except AttributeError: # Python 2.7, abc exists, but not ABC + ABC = abc.ABCMeta("ABC", (object,), {"__slots__": ()}) # type: ignore + +try: + from typing import TYPE_CHECKING +except ImportError: + TYPE_CHECKING = False + +if TYPE_CHECKING: + # pylint:disable=unused-import + from typing import Any + + +class CertificateCredentialBase(ABC): + def __init__(self, tenant_id, client_id, certificate_path, **kwargs): + # type: (str, str, str, **Any) -> None + if not certificate_path: + raise ValueError( + "'certificate_path' must be the path to a PEM file containing an x509 certificate and its private key" + ) + + super(CertificateCredentialBase, self).__init__() + + password = kwargs.pop("password", None) + if isinstance(password, six.text_type): + password = password.encode(encoding="utf-8") + + with open(certificate_path, "rb") as f: + pem_bytes = f.read() + + self._certificate = AadClientCertificate(pem_bytes, password=password) + self._client = self._get_auth_client(tenant_id, client_id, **kwargs) + + @abc.abstractmethod + def _get_auth_client(self, tenant_id, client_id, **kwargs): + pass diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/certificate.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/certificate.py index 300728f221f1..f79a61276ce3 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/certificate.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/certificate.py @@ -5,8 +5,8 @@ from typing import TYPE_CHECKING from .base import AsyncCredentialBase -from .._authn_client import AsyncAuthnClient -from ..._base import CertificateCredentialBase +from .._internal import AadClient +from ..._internal import CertificateCredentialBase if TYPE_CHECKING: from typing import Any @@ -51,11 +51,10 @@ async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": # py if not scopes: raise ValueError("'get_token' requires at least one scope") - token = self._client.get_cached_token(scopes) + token = self._client.get_cached_access_token(scopes) if not token: - data = self._get_request_data(*scopes) - token = await self._client.request_token(scopes, form_data=data) - return token # type: ignore + token = await self._client.obtain_token_by_client_certificate(scopes, self._certificate, **kwargs) + return token - def _get_auth_client(self, tenant_id, **kwargs): - return AsyncAuthnClient(tenant=tenant_id, **kwargs) + def _get_auth_client(self, tenant_id, client_id, **kwargs): + return AadClient(tenant_id, client_id, **kwargs) diff --git a/sdk/identity/azure-identity/azure/identity/aio/_internal/aad_client.py b/sdk/identity/azure-identity/azure/identity/aio/_internal/aad_client.py index 98075b9aeb66..010d638b1ffd 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_internal/aad_client.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_internal/aad_client.py @@ -25,6 +25,7 @@ from azure.core.credentials import AccessToken from azure.core.pipeline.policies import AsyncHTTPPolicy, SansIOHTTPPolicy from azure.core.pipeline.transport import AsyncHttpTransport + from ..._internal import AadClientCertificate Policy = Union[AsyncHTTPPolicy, SansIOHTTPPolicy] @@ -58,6 +59,14 @@ async def obtain_token_by_authorization_code( content = ContentDecodePolicy.deserialize_from_http_generics(response.http_response) return self._process_response(response=content, scopes=scopes, now=now) + async def obtain_token_by_client_certificate(self, scopes, certificate, **kwargs): + # type: (Sequence[str], AadClientCertificate, **Any) -> AccessToken + request = self._get_client_certificate_request(scopes, certificate) + now = int(time.time()) + response = await self._pipeline.run(request, stream=False, **kwargs) + content = ContentDecodePolicy.deserialize_from_http_generics(response.http_response) + return self._process_response(response=content, scopes=scopes, now=now) + async def obtain_token_by_refresh_token( self, scopes: "Sequence[str]", refresh_token: str, **kwargs: "Any" ) -> "AccessToken": From 0ec1601d709406444cd901189a97a3e2ed6c00b6 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Thu, 4 Jun 2020 09:18:10 -0700 Subject: [PATCH 13/25] Refactor ClientSecretCredential to use AadClient (#11718) --- .../identity/_credentials/client_secret.py | 18 +++++------- .../azure/identity/_internal/__init__.py | 2 ++ .../azure/identity/_internal/aad_client.py | 12 ++++++-- .../identity/_internal/aad_client_base.py | 17 +++++++++++ .../client_secret_credential_base.py} | 29 +++++++++---------- .../aio/_credentials/client_secret.py | 22 +++++++------- .../identity/aio/_internal/aad_client.py | 9 ++++++ .../azure-identity/tests/test_aad_client.py | 24 +++++++++++++++ .../tests/test_aad_client_async.py | 24 +++++++++++++++ 9 files changed, 117 insertions(+), 40 deletions(-) rename sdk/identity/azure-identity/azure/identity/{_base.py => _internal/client_secret_credential_base.py} (54%) diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/client_secret.py b/sdk/identity/azure-identity/azure/identity/_credentials/client_secret.py index f8dbd45bce9c..35ec0403114a 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/client_secret.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/client_secret.py @@ -2,8 +2,7 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # ------------------------------------ -from .._authn_client import AuthnClient -from .._base import ClientSecretCredentialBase +from .._internal import AadClient, ClientSecretCredentialBase try: from typing import TYPE_CHECKING @@ -28,12 +27,7 @@ class ClientSecretCredential(ClientSecretCredentialBase): defines authorities for other clouds. """ - def __init__(self, tenant_id, client_id, client_secret, **kwargs): - # type: (str, str, str, **Any) -> None - super(ClientSecretCredential, self).__init__(tenant_id, client_id, client_secret, **kwargs) - self._client = AuthnClient(tenant=tenant_id, **kwargs) - - def get_token(self, *scopes, **kwargs): # pylint:disable=unused-argument + def get_token(self, *scopes, **kwargs): # type: (*str, **Any) -> AccessToken """Request an access token for `scopes`. @@ -48,8 +42,10 @@ def get_token(self, *scopes, **kwargs): # pylint:disable=unused-argument if not scopes: raise ValueError("'get_token' requires at least one scope") - token = self._client.get_cached_token(scopes) + token = self._client.get_cached_access_token(scopes) if not token: - data = dict(self._form_data, scope=" ".join(scopes)) - token = self._client.request_token(scopes, form_data=data) + token = self._client.obtain_token_by_client_secret(scopes, self._secret, **kwargs) return token + + def _get_auth_client(self, tenant_id, client_id, **kwargs): + return AadClient(tenant_id, client_id, **kwargs) diff --git a/sdk/identity/azure-identity/azure/identity/_internal/__init__.py b/sdk/identity/azure-identity/azure/identity/_internal/__init__.py index b966c03023e4..40a11461b559 100644 --- a/sdk/identity/azure-identity/azure/identity/_internal/__init__.py +++ b/sdk/identity/azure-identity/azure/identity/_internal/__init__.py @@ -35,6 +35,7 @@ def get_default_authority(): from .auth_code_redirect_handler import AuthCodeRedirectServer from .aadclient_certificate import AadClientCertificate from .certificate_credential_base import CertificateCredentialBase +from .client_secret_credential_base import ClientSecretCredentialBase from .exception_wrapper import wrap_exceptions from .msal_credentials import ConfidentialClientCredential, InteractiveCredential, PublicClientCredential from .msal_transport_adapter import MsalTransportAdapter, MsalTransportResponse @@ -60,6 +61,7 @@ def _scopes_to_resource(*scopes): "AuthCodeRedirectServer", "AadClientCertificate", "CertificateCredentialBase", + "ClientSecretCredentialBase", "ConfidentialClientCredential", "get_default_authority", "InteractiveCredential", diff --git a/sdk/identity/azure-identity/azure/identity/_internal/aad_client.py b/sdk/identity/azure-identity/azure/identity/_internal/aad_client.py index 6877f53e0bc5..d84fe1ea0d33 100644 --- a/sdk/identity/azure-identity/azure/identity/_internal/aad_client.py +++ b/sdk/identity/azure-identity/azure/identity/_internal/aad_client.py @@ -33,7 +33,7 @@ class AadClient(AadClientBase): def obtain_token_by_authorization_code(self, scopes, code, redirect_uri, client_secret=None, **kwargs): - # type: (str, str, Sequence[str], Optional[str], **Any) -> AccessToken + # type: (Sequence[str], str, str, Optional[str], **Any) -> AccessToken request = self._get_auth_code_request( scopes=scopes, code=code, redirect_uri=redirect_uri, client_secret=client_secret ) @@ -50,8 +50,16 @@ def obtain_token_by_client_certificate(self, scopes, certificate, **kwargs): content = ContentDecodePolicy.deserialize_from_http_generics(response.http_response) return self._process_response(response=content, scopes=scopes, now=now) + def obtain_token_by_client_secret(self, scopes, secret, **kwargs): + # type: (Sequence[str], str, **Any) -> AccessToken + request = self._get_client_secret_request(scopes, secret) + now = int(time.time()) + response = self._pipeline.run(request, stream=False, **kwargs) + content = ContentDecodePolicy.deserialize_from_http_generics(response.http_response) + return self._process_response(response=content, scopes=scopes, now=now) + def obtain_token_by_refresh_token(self, scopes, refresh_token, **kwargs): - # type: (str, Sequence[str], **Any) -> AccessToken + # type: (Sequence[str], str, **Any) -> AccessToken request = self._get_refresh_token_request(scopes, refresh_token) now = int(time.time()) response = self._pipeline.run(request, stream=False, **kwargs) diff --git a/sdk/identity/azure-identity/azure/identity/_internal/aad_client_base.py b/sdk/identity/azure-identity/azure/identity/_internal/aad_client_base.py index 96a7b37cb71e..61c697337262 100644 --- a/sdk/identity/azure-identity/azure/identity/_internal/aad_client_base.py +++ b/sdk/identity/azure-identity/azure/identity/_internal/aad_client_base.py @@ -71,6 +71,10 @@ def obtain_token_by_authorization_code(self, scopes, code, redirect_uri, client_ def obtain_token_by_client_certificate(self, scopes, certificate, **kwargs): pass + @abc.abstractmethod + def obtain_token_by_client_secret(self, scopes, secret, **kwargs): + pass + @abc.abstractmethod def obtain_token_by_refresh_token(self, scopes, refresh_token, **kwargs): pass @@ -131,6 +135,19 @@ def _get_client_certificate_request(self, scopes, certificate): ) return request + def _get_client_secret_request(self, scopes, secret): + # type: (Sequence[str], str) -> HttpRequest + data = { + "client_id": self._client_id, + "client_secret": secret, + "grant_type": "client_credentials", + "scope": " ".join(scopes), + } + request = HttpRequest( + "POST", self._token_endpoint, headers={"Content-Type": "application/x-www-form-urlencoded"}, data=data + ) + return request + def _get_jwt_assertion(self, certificate): # type: (AadClientCertificate) -> str now = int(time.time()) diff --git a/sdk/identity/azure-identity/azure/identity/_base.py b/sdk/identity/azure-identity/azure/identity/_internal/client_secret_credential_base.py similarity index 54% rename from sdk/identity/azure-identity/azure/identity/_base.py rename to sdk/identity/azure-identity/azure/identity/_internal/client_secret_credential_base.py index 058d0d35665e..977c55dab409 100644 --- a/sdk/identity/azure-identity/azure/identity/_base.py +++ b/sdk/identity/azure-identity/azure/identity/_internal/client_secret_credential_base.py @@ -3,34 +3,33 @@ # Licensed under the MIT License. # ------------------------------------ import abc +from typing import TYPE_CHECKING try: ABC = abc.ABC -except AttributeError: # Python 2.7, abc exists, but not ABC +except AttributeError: # Python 2.7 ABC = abc.ABCMeta("ABC", (object,), {"__slots__": ()}) # type: ignore -try: - from typing import TYPE_CHECKING -except ImportError: - TYPE_CHECKING = False - if TYPE_CHECKING: - # pylint:disable=unused-import - from typing import Any, Optional, Union - + # pylint:disable=unused-import,ungrouped-imports + from typing import Any -class ClientSecretCredentialBase(object): - """Sans I/O base for client secret credentials""" - def __init__(self, tenant_id, client_id, secret, **kwargs): # pylint:disable=unused-argument +class ClientSecretCredentialBase(ABC): + def __init__(self, tenant_id, client_id, client_secret, **kwargs): # type: (str, str, str, **Any) -> None if not client_id: raise ValueError("client_id should be the id of an Azure Active Directory application") - if not secret: + if not client_secret: raise ValueError("secret should be an Azure Active Directory application's client secret") if not tenant_id: raise ValueError( "tenant_id should be an Azure Active Directory tenant's id (also called its 'directory id')" ) - self._form_data = {"client_id": client_id, "client_secret": secret, "grant_type": "client_credentials"} - super(ClientSecretCredentialBase, self).__init__() + + self._client = self._get_auth_client(tenant_id, client_id, **kwargs) + self._secret = client_secret + + @abc.abstractmethod + def _get_auth_client(self, tenant_id, client_id, **kwargs): + pass diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/client_secret.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/client_secret.py index 60a51bb037e5..80b5a5577921 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/client_secret.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/client_secret.py @@ -5,15 +5,15 @@ from typing import TYPE_CHECKING from .base import AsyncCredentialBase -from .._authn_client import AsyncAuthnClient -from ..._base import ClientSecretCredentialBase +from .._internal import AadClient +from ..._internal import ClientSecretCredentialBase if TYPE_CHECKING: from typing import Any from azure.core.credentials import AccessToken -class ClientSecretCredential(ClientSecretCredentialBase, AsyncCredentialBase): +class ClientSecretCredential(AsyncCredentialBase, ClientSecretCredentialBase): """Authenticates as a service principal using a client ID and client secret. :param str tenant_id: ID of the service principal's tenant. Also called its 'directory' ID. @@ -25,10 +25,6 @@ class ClientSecretCredential(ClientSecretCredentialBase, AsyncCredentialBase): defines authorities for other clouds. """ - def __init__(self, tenant_id: str, client_id: str, client_secret: str, **kwargs: "Any") -> None: - super(ClientSecretCredential, self).__init__(tenant_id, client_id, client_secret, **kwargs) - self._client = AsyncAuthnClient(tenant=tenant_id, **kwargs) - async def __aenter__(self): await self._client.__aenter__() return self @@ -38,7 +34,7 @@ async def close(self): await self._client.__aexit__() - async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": # pylint:disable=unused-argument + async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": """Asynchronously request an access token for `scopes`. .. note:: This method is called by Azure SDK clients. It isn't intended for use in application code. @@ -52,8 +48,10 @@ async def get_token(self, *scopes: str, **kwargs: "Any") -> "AccessToken": # py if not scopes: raise ValueError("'get_token' requires at least one scope") - token = self._client.get_cached_token(scopes) + token = self._client.get_cached_access_token(scopes) if not token: - data = dict(self._form_data, scope=" ".join(scopes)) - token = await self._client.request_token(scopes, form_data=data) - return token # type: ignore + token = await self._client.obtain_token_by_client_secret(scopes, self._secret, **kwargs) + return token + + def _get_auth_client(self, tenant_id, client_id, **kwargs): + return AadClient(tenant_id, client_id, **kwargs) diff --git a/sdk/identity/azure-identity/azure/identity/aio/_internal/aad_client.py b/sdk/identity/azure-identity/azure/identity/aio/_internal/aad_client.py index 010d638b1ffd..85136ea0e4d6 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_internal/aad_client.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_internal/aad_client.py @@ -67,6 +67,15 @@ async def obtain_token_by_client_certificate(self, scopes, certificate, **kwargs content = ContentDecodePolicy.deserialize_from_http_generics(response.http_response) return self._process_response(response=content, scopes=scopes, now=now) + async def obtain_token_by_client_secret( + self, scopes: "Sequence[str]", secret: str, **kwargs: "Any" + ) -> "AccessToken": + request = self._get_client_secret_request(scopes, secret) + now = int(time.time()) + response = await self._pipeline.run(request, **kwargs) + content = ContentDecodePolicy.deserialize_from_http_generics(response.http_response) + return self._process_response(response=content, scopes=scopes, now=now) + async def obtain_token_by_refresh_token( self, scopes: "Sequence[str]", refresh_token: str, **kwargs: "Any" ) -> "AccessToken": diff --git a/sdk/identity/azure-identity/tests/test_aad_client.py b/sdk/identity/azure-identity/tests/test_aad_client.py index 98a74fa4ae68..90d0a9310719 100644 --- a/sdk/identity/azure-identity/tests/test_aad_client.py +++ b/sdk/identity/azure-identity/tests/test_aad_client.py @@ -126,6 +126,30 @@ def send(request, **_): assert transport.send.call_count == 1 +def test_client_secret(): + tenant_id = "tenant-id" + client_id = "client-id" + scope = "scope" + secret = "refresh-token" + access_token = "***" + + def send(request, **_): + assert request.data["client_id"] == client_id + assert request.data["client_secret"] == secret + assert request.data["grant_type"] == "client_credentials" + assert request.data["scope"] == scope + + return mock_response(json_payload={"access_token": access_token, "expires_in": 42}) + + transport = Mock(send=Mock(wraps=send)) + + client = AadClient(tenant_id, client_id, transport=transport) + token = client.obtain_token_by_client_secret(scopes=(scope,), secret=secret) + + assert token.token == access_token + assert transport.send.call_count == 1 + + def test_refresh_token(): tenant_id = "tenant-id" client_id = "client-id" diff --git a/sdk/identity/azure-identity/tests/test_aad_client_async.py b/sdk/identity/azure-identity/tests/test_aad_client_async.py index db7ce99c3e30..f3a5d996caaa 100644 --- a/sdk/identity/azure-identity/tests/test_aad_client_async.py +++ b/sdk/identity/azure-identity/tests/test_aad_client_async.py @@ -108,6 +108,30 @@ async def send(request, **_): assert transport.send.call_count == 1 +async def test_client_secret(): + tenant_id = "tenant-id" + client_id = "client-id" + scope = "scope" + secret = "refresh-token" + access_token = "***" + + async def send(request, **_): + assert request.data["client_id"] == client_id + assert request.data["client_secret"] == secret + assert request.data["grant_type"] == "client_credentials" + assert request.data["scope"] == scope + + return mock_response(json_payload={"access_token": access_token, "expires_in": 42}) + + transport = Mock(send=Mock(wraps=send)) + + client = AadClient(tenant_id, client_id, transport=transport) + token = await client.obtain_token_by_client_secret(scopes=(scope,), secret=secret) + + assert token.token == access_token + assert transport.send.call_count == 1 + + async def test_refresh_token(): tenant_id = "tenant-id" client_id = "client-id" From 9f67111a3754d047dd3e7b84b74b90027994e4d3 Mon Sep 17 00:00:00 2001 From: annatisch Date: Thu, 4 Jun 2020 09:21:31 -0700 Subject: [PATCH 14/25] [Cosmos] Fixed incorrect ID type error (#11798) * Fixed incorrect ID type error * Fix pylint --- sdk/cosmos/azure-cosmos/CHANGELOG.md | 5 +++++ .../azure/cosmos/_cosmos_client_connection.py | 14 +++++++++----- sdk/cosmos/azure-cosmos/azure/cosmos/_version.py | 2 +- .../samples/access_cosmos_with_resource_token.py | 2 +- sdk/cosmos/azure-cosmos/test/test_crud.py | 5 +++++ 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/CHANGELOG.md b/sdk/cosmos/azure-cosmos/CHANGELOG.md index 24a11dd36193..075644d2aeaf 100644 --- a/sdk/cosmos/azure-cosmos/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos/CHANGELOG.md @@ -1,3 +1,8 @@ +## 4.0.1 (Unreleased) + +- Fixed error raised when a non string ID is used in an item. It now raises TypeError rather than AttributeError. Issue 11793 - thank you @Rabbit994. + + ## 4.0.0 (2020-05-20) - Stable release. diff --git a/sdk/cosmos/azure-cosmos/azure/cosmos/_cosmos_client_connection.py b/sdk/cosmos/azure-cosmos/azure/cosmos/_cosmos_client_connection.py index 3fa09e0ed51e..f9183e739762 100644 --- a/sdk/cosmos/azure-cosmos/azure/cosmos/_cosmos_client_connection.py +++ b/sdk/cosmos/azure-cosmos/azure/cosmos/_cosmos_client_connection.py @@ -31,6 +31,7 @@ from urllib3.util.retry import Retry from azure.core.paging import ItemPaged # type: ignore from azure.core import PipelineClient # type: ignore +from azure.core.exceptions import raise_with_traceback # type: ignore from azure.core.pipeline.policies import ( # type: ignore HTTPPolicy, ContentDecodePolicy, @@ -2480,11 +2481,14 @@ def __CheckAndUnifyQueryFormat(self, query_body): def __ValidateResource(resource): id_ = resource.get("id") if id_: - if id_.find("/") != -1 or id_.find("\\") != -1 or id_.find("?") != -1 or id_.find("#") != -1: - raise ValueError("Id contains illegal chars.") - - if id_[-1] == " ": - raise ValueError("Id ends with a space.") + try: + if id_.find("/") != -1 or id_.find("\\") != -1 or id_.find("?") != -1 or id_.find("#") != -1: + raise ValueError("Id contains illegal chars.") + + if id_[-1] == " ": + raise ValueError("Id ends with a space.") + except AttributeError: + raise_with_traceback(TypeError, message="Id type must be a string.") # Adds the partition key to options def _AddPartitionKey(self, collection_link, document, options): diff --git a/sdk/cosmos/azure-cosmos/azure/cosmos/_version.py b/sdk/cosmos/azure-cosmos/azure/cosmos/_version.py index e2f89349120a..db751d88b3e5 100644 --- a/sdk/cosmos/azure-cosmos/azure/cosmos/_version.py +++ b/sdk/cosmos/azure-cosmos/azure/cosmos/_version.py @@ -19,4 +19,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -VERSION = "4.0.0" +VERSION = "4.0.1" diff --git a/sdk/cosmos/azure-cosmos/samples/access_cosmos_with_resource_token.py b/sdk/cosmos/azure-cosmos/samples/access_cosmos_with_resource_token.py index 9efb03da0ac4..87cc629a9f51 100644 --- a/sdk/cosmos/azure-cosmos/samples/access_cosmos_with_resource_token.py +++ b/sdk/cosmos/azure-cosmos/samples/access_cosmos_with_resource_token.py @@ -14,7 +14,7 @@ # https://docs.microsoft.com/azure/cosmos-db/create-sql-api-python#create-a-database-account # # 2. Microsoft Azure Cosmos -# pip install azure-cosmos==4.0.0 +# pip install azure-cosmos>=4.0.0 # ---------------------------------------------------------------------------------------------------------- # Sample - how to get and use resource token that allows restricted access to data # ---------------------------------------------------------------------------------------------------------- diff --git a/sdk/cosmos/azure-cosmos/test/test_crud.py b/sdk/cosmos/azure-cosmos/test/test_crud.py index 602d031fd7d8..a809382a197b 100644 --- a/sdk/cosmos/azure-cosmos/test/test_crud.py +++ b/sdk/cosmos/azure-cosmos/test/test_crud.py @@ -939,6 +939,11 @@ def test_document_upsert(self): self.assertEqual(created_document['id'], document_definition['id']) + # test error for non-string id + with pytest.raises(TypeError): + document_definition['id'] = 7 + created_collection.upsert_item(body=document_definition) + # read documents after creation and verify updated count documents = list(created_collection.read_all_items()) self.assertEqual( From 17161be93eb2ff958ef99a925d62a3ff5e91c96d Mon Sep 17 00:00:00 2001 From: iscai-msft <43154838+iscai-msft@users.noreply.github.com> Date: Thu, 4 Jun 2020 13:05:08 -0400 Subject: [PATCH 15/25] [text analytics] Update readme (#11796) --- .../azure-ai-textanalytics/README.md | 127 +++++++++--------- 1 file changed, 63 insertions(+), 64 deletions(-) diff --git a/sdk/textanalytics/azure-ai-textanalytics/README.md b/sdk/textanalytics/azure-ai-textanalytics/README.md index 5af75f1c0fcb..e04b6f86511b 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/README.md +++ b/sdk/textanalytics/azure-ai-textanalytics/README.md @@ -16,16 +16,6 @@ Text Analytics is a cloud-based service that provides advanced natural language * You must have an [Azure subscription][azure_subscription] and a [Cognitive Services or Text Analytics resource][TA_or_CS_resource] to use this package. -### Install the package -Install the Azure Text Analytics client library for Python with [pip][pip]: - -```bash -pip install azure-ai-textanalytics --pre -``` - -> Note: This version of the client library supports the v3.0 version of the Text Analytics service - -### Authenticate the client #### Create a Cognitive Services or Text Analytics resource Text Analytics supports both [multi-service and single-service access][multi_and_single_service]. Create a Cognitive Services resource if you plan to access multiple cognitive services under a single endpoint/key. For Text Analytics access only, create a Text Analytics resource. @@ -68,7 +58,17 @@ Note that if you create a [custom subdomain][cognitive_custom_subdomain] name for your resource the endpoint may look different than in the above code snippet. For example, `https://.cognitiveservices.azure.com/`. -#### Looking up the endpoint +### Install the package +Install the Azure Text Analytics client library for Python with [pip][pip]: + +```bash +pip install azure-ai-textanalytics +``` + +> Note: This version of the client library supports the v3.0 version of the Text Analytics service + +### Authenticate the client +#### Get the endpoint You can find the endpoint for your text analytics resource using the [Azure Portal][azure_portal_get_endpoint] or [Azure CLI][azure_cli_endpoint_lookup]: @@ -78,59 +78,58 @@ or [Azure CLI][azure_cli_endpoint_lookup]: az cognitiveservices account show --name "resource-name" --resource-group "resource-group-name" --query "endpoint" ``` -#### Types of credentials -The `credential` parameter may be provided as a [AzureKeyCredential][azure-key-credential] from azure.core.credentials or as a token from Azure Active Directory. -See the full details regarding [authentication][cognitive_authentication] of -cognitive services. +#### Get the API Key +You can get the [API key][cognitive_authentication_api_key] from the Cognitive Services or Text Analytics resource in the [Azure Portal][azure_portal_get_endpoint]. +Alternatively, you can use [Azure CLI][azure_cli_endpoint_lookup] snippet below to get the API key of your resource. -1. To use an [API key][cognitive_authentication_api_key], - pass the key as a string into an instance of `AzureKeyCredential("")`. - The API key can be found in the Azure Portal or by running the following Azure CLI command: +```az cognitiveservices account keys list --name "resource-name" --resource-group "resource-group-name"``` - ```az cognitiveservices account keys list --name "resource-name" --resource-group "resource-group-name"``` +#### Create a TextAnalyticsClient with an API Key Credential +Once you have the value for the API key, you can pass it as a string into an instance of [AzureKeyCredential][azure-key-credential]. Use the key as the credential parameter +to authenticate the client: - Use the key as the credential parameter to authenticate the client: - ```python - from azure.core.credentials import AzureKeyCredential - from azure.ai.textanalytics import TextAnalyticsClient +```python +from azure.core.credentials import AzureKeyCredential +from azure.ai.textanalytics import TextAnalyticsClient - credential = AzureKeyCredential("") - text_analytics_client = TextAnalyticsClient(endpoint="https://.api.cognitive.microsoft.com/", credential=credential) - ``` +credential = AzureKeyCredential("") +text_analytics_client = TextAnalyticsClient(endpoint="https://.api.cognitive.microsoft.com/", credential=credential) +``` -2. To use an [Azure Active Directory (AAD) token credential][cognitive_authentication_aad], - provide an instance of the desired credential type obtained from the - [azure-identity][azure_identity_credentials] library. - Note that regional endpoints do not support AAD authentication. Create a [custom subdomain][custom_subdomain] - name for your resource in order to use this type of authentication. +#### Create a TextAnalyticsClient with an Azure Active Directory Credential +To use an [Azure Active Directory (AAD) token credential][cognitive_authentication_aad], +provide an instance of the desired credential type obtained from the +[azure-identity][azure_identity_credentials] library. +Note that regional endpoints do not support AAD authentication. Create a [custom subdomain][custom_subdomain] +name for your resource in order to use this type of authentication. - Authentication with AAD requires some initial setup: - * [Install azure-identity][install_azure_identity] - * [Register a new AAD application][register_aad_app] - * [Grant access][grant_role_access] to Text Analytics by assigning the `"Cognitive Services User"` role to your service principal. +Authentication with AAD requires some initial setup: +* [Install azure-identity][install_azure_identity] +* [Register a new AAD application][register_aad_app] +* [Grant access][grant_role_access] to Text Analytics by assigning the `"Cognitive Services User"` role to your service principal. - After setup, you can choose which type of [credential][azure_identity_credentials] from azure.identity to use. - As an example, [DefaultAzureCredential][default_azure_credential] - can be used to authenticate the client: +After setup, you can choose which type of [credential][azure_identity_credentials] from azure.identity to use. +As an example, [DefaultAzureCredential][default_azure_credential] +can be used to authenticate the client: - Set the values of the client ID, tenant ID, and client secret of the AAD application as environment variables: - AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET +Set the values of the client ID, tenant ID, and client secret of the AAD application as environment variables: +AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET - Use the returned token credential to authenticate the client: - ```python - from azure.identity import DefaultAzureCredential - from azure.ai.textanalytics import TextAnalyticsClient - token_credential = DefaultAzureCredential() +Use the returned token credential to authenticate the client: +```python +from azure.identity import DefaultAzureCredential +from azure.ai.textanalytics import TextAnalyticsClient +token_credential = DefaultAzureCredential() - text_analytics_client = TextAnalyticsClient( - endpoint="https://.cognitiveservices.azure.com/", - credential=token_credential - ) - ``` +text_analytics_client = TextAnalyticsClient( + endpoint="https://.cognitiveservices.azure.com/", + credential=token_credential +) +``` ## Key concepts -### Client +### TextAnalyticsClient The Text Analytics client library provides a [TextAnalyticsClient][text_analytics_client] to do analysis on [batches of documents](#Examples "examples"). It provides both synchronous and asynchronous operations to access a specific use of Text Analytics, such as language detection or key phrase extraction. @@ -432,7 +431,7 @@ This project has adopted the [Microsoft Open Source Code of Conduct][code_of_con [source_code]: azure/ai/textanalytics [TA_pypi]: https://pypi.org/project/azure-ai-textanalytics/ [TA_ref_docs]: https://aka.ms/azsdk-python-textanalytics-ref-docs -[TA_samples]: samples +[TA_samples]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples [TA_product_documentation]: https://docs.microsoft.com/azure/cognitive-services/text-analytics/overview [azure_subscription]: https://azure.microsoft.com/free/ [TA_or_CS_resource]: https://docs.microsoft.com/azure/cognitive-services/cognitive-services-apis-create-account?tabs=multiservice%2Cwindows @@ -485,18 +484,18 @@ This project has adopted the [Microsoft Open Source Code of Conduct][code_of_con [azure_core]: ../../core/azure-core/README.md [azure_identity]: ../../identity/azure-identity [python_logging]: https://docs.python.org/3.5/library/logging.html -[sample_authentication]: samples/sample_authentication.py -[sample_authentication_async]: samples/async_samples/sample_authentication_async.py -[detect_language_sample]: samples/sample_detect_language.py -[detect_language_sample_async]: samples/async_samples/sample_detect_language_async.py -[analyze_sentiment_sample]: samples/sample_analyze_sentiment.py -[analyze_sentiment_sample_async]: samples/async_samples/sample_analyze_sentiment_async.py -[extract_key_phrases_sample]: samples/sample_extract_key_phrases.py -[extract_key_phrases_sample_async]: samples/async_samples/sample_extract_key_phrases_async.py -[recognize_entities_sample]: samples/sample_recognize_entities.py -[recognize_entities_sample_async]: samples/async_samples/sample_recognize_entities_async.py -[recognize_linked_entities_sample]: samples/sample_recognize_linked_entities.py -[recognize_linked_entities_sample_async]: samples/async_samples/sample_recognize_linked_entities_async.py +[sample_authentication]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/sample_authentication.py +[sample_authentication_async]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/async_samples/sample_authentication_async.py +[detect_language_sample]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/sample_detect_language.py +[detect_language_sample_async]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/async_samples/sample_detect_language_async.py +[analyze_sentiment_sample]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/sample_analyze_sentiment.py +[analyze_sentiment_sample_async]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/async_samples/sample_analyze_sentiment_async.py +[extract_key_phrases_sample]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/sample_extract_key_phrases.py +[extract_key_phrases_sample_async]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/async_samples/sample_extract_key_phrases_async.py +[recognize_entities_sample]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/sample_recognize_entities.py +[recognize_entities_sample_async]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/async_samples/sample_recognize_entities_async.py +[recognize_linked_entities_sample]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/sample_recognize_linked_entities.py +[recognize_linked_entities_sample_async]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/async_samples/sample_recognize_linked_entities_async.py [cla]: https://cla.microsoft.com [code_of_conduct]: https://opensource.microsoft.com/codeofconduct/ From d4bd596d43d3e6bc0750264defa368f3efd52f12 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Thu, 4 Jun 2020 10:07:31 -0700 Subject: [PATCH 16/25] try something (#11797) --- .../azure/ai/textanalytics/_policies.py | 11 ++++++----- .../ai/textanalytics/aio/_policies_async.py | 17 +++++++++-------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/sdk/textanalytics/azure-ai-textanalytics/azure/ai/textanalytics/_policies.py b/sdk/textanalytics/azure-ai-textanalytics/azure/ai/textanalytics/_policies.py index be9292570474..3d0fca67ebcd 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/azure/ai/textanalytics/_policies.py +++ b/sdk/textanalytics/azure-ai-textanalytics/azure/ai/textanalytics/_policies.py @@ -23,8 +23,9 @@ def on_response(self, request, response): statistics = data.get("statistics", None) model_version = data.get("modelVersion", None) - batch_statistics = TextDocumentBatchStatistics._from_generated(statistics) # pylint: disable=protected-access - response.statistics = batch_statistics - response.model_version = model_version - response.raw_response = data - self._response_callback(response) + if statistics or model_version: + batch_statistics = TextDocumentBatchStatistics._from_generated(statistics) # pylint: disable=protected-access + response.statistics = batch_statistics + response.model_version = model_version + response.raw_response = data + self._response_callback(response) diff --git a/sdk/textanalytics/azure-ai-textanalytics/azure/ai/textanalytics/aio/_policies_async.py b/sdk/textanalytics/azure-ai-textanalytics/azure/ai/textanalytics/aio/_policies_async.py index c8ba797a8743..f035a52520f8 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/azure/ai/textanalytics/aio/_policies_async.py +++ b/sdk/textanalytics/azure-ai-textanalytics/azure/ai/textanalytics/aio/_policies_async.py @@ -25,11 +25,12 @@ async def on_response(self, request, response): statistics = data.get("statistics", None) model_version = data.get("modelVersion", None) - batch_statistics = TextDocumentBatchStatistics._from_generated(statistics) # pylint: disable=protected-access - response.statistics = batch_statistics - response.model_version = model_version - response.raw_response = data - if asyncio.iscoroutine(self._response_callback): - await self._response_callback(response) - else: - self._response_callback(response) + if statistics or model_version: + batch_statistics = TextDocumentBatchStatistics._from_generated(statistics) # pylint: disable=protected-access + response.statistics = batch_statistics + response.model_version = model_version + response.raw_response = data + if asyncio.iscoroutine(self._response_callback): + await self._response_callback(response) + else: + self._response_callback(response) From aad9601f87ca0dc092a3e2eed69270ba6c65cf54 Mon Sep 17 00:00:00 2001 From: Xiang Yan Date: Thu, 4 Jun 2020 10:32:56 -0700 Subject: [PATCH 17/25] Search refactoring 3 (#11804) * create_or_update takes object * rename is_hidden to hidden * fix types * updates --- .../azure-search-documents/CHANGELOG.md | 1 + .../documents/indexes/_internal/_index.py | 20 ++-- .../indexes/_internal/_search_index_client.py | 90 ++++++-------- .../_internal/_search_indexer_client.py | 112 ++++++----------- .../documents/indexes/_internal/_utils.py | 20 +++- .../_internal/aio/_search_index_client.py | 98 +++++++-------- .../_internal/aio/_search_indexer_client.py | 113 ++++++------------ .../documents/indexes/models/__init__.py | 2 + .../sample_synonym_map_operations_async.py | 5 +- .../sample_indexer_datasource_skillset.py | 3 +- .../samples/sample_synonym_map_operations.py | 5 +- .../async_tests/test_service_live_async.py | 93 +++++++++----- .../tests/test_index_field_helpers.py | 4 +- .../tests/test_service_live.py | 101 ++++++++++------ 14 files changed, 315 insertions(+), 352 deletions(-) diff --git a/sdk/search/azure-search-documents/CHANGELOG.md b/sdk/search/azure-search-documents/CHANGELOG.md index 5e2252734156..317ffb4b0d05 100644 --- a/sdk/search/azure-search-documents/CHANGELOG.md +++ b/sdk/search/azure-search-documents/CHANGELOG.md @@ -24,6 +24,7 @@ PathHierarchyTokenizerV2 -> PathHierarchyTokenizer - Renamed DataSource methods to DataSourceConnection #11693 - Autocomplete & suggest methods now takes arguments search_text & suggester_name rather than query objects #11747 +- Create_or_updates methods does not support partial updates ## 1.0.0b3 (2020-05-04) diff --git a/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/_index.py b/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/_index.py index 7f128cdfd2ca..7d555ab22d21 100644 --- a/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/_index.py +++ b/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/_index.py @@ -32,13 +32,13 @@ class SearchField(msrest.serialization.Model): type Edm.String. Key fields can be used to look up documents directly and update or delete specific documents. Default is false for simple fields and null for complex fields. :type key: bool - :param is_hidden: A value indicating whether the field can be returned in a search result. + :param hidden: A value indicating whether the field can be returned in a search result. You can enable this option if you want to use a field (for example, margin) as a filter, sorting, or scoring mechanism but do not want the field to be visible to the end user. This property must be False for key fields, and it must be null for complex fields. This property can be changed on existing fields. Enabling this property does not cause any increase in index storage requirements. Default is False for simple fields and null for complex fields. - :type is_hidden: bool + :type hidden: bool :param searchable: A value indicating whether the field is full-text searchable. This means it will undergo analysis such as word-breaking during indexing. If you set a searchable field to a value like "sunny day", internally it will be split into the individual tokens "sunny" and @@ -161,7 +161,7 @@ class SearchField(msrest.serialization.Model): 'name': {'key': 'name', 'type': 'str'}, 'type': {'key': 'type', 'type': 'str'}, 'key': {'key': 'key', 'type': 'bool'}, - 'is_hidden': {'key': 'isHidden', 'type': 'bool'}, + 'hidden': {'key': 'hidden', 'type': 'bool'}, 'searchable': {'key': 'searchable', 'type': 'bool'}, 'filterable': {'key': 'filterable', 'type': 'bool'}, 'sortable': {'key': 'sortable', 'type': 'bool'}, @@ -181,7 +181,7 @@ def __init__( self.name = kwargs['name'] self.type = kwargs['type'] self.key = kwargs.get('key', None) - self.is_hidden = kwargs.get('is_hidden', None) + self.hidden = kwargs.get('hidden', None) self.searchable = kwargs.get('searchable', None) self.filterable = kwargs.get('filterable', None) self.sortable = kwargs.get('sortable', None) @@ -210,13 +210,13 @@ def SimpleField(**kw): type SearchFieldDataType.String. Key fields can be used to look up documents directly and update or delete specific documents. Default is False :type key: bool - :param is_hidden: A value indicating whether the field can be returned in a search result. + :param hidden: A value indicating whether the field can be returned in a search result. You can enable this option if you want to use a field (for example, margin) as a filter, sorting, or scoring mechanism but do not want the field to be visible to the end user. This property must be False for key fields. This property can be changed on existing fields. Enabling this property does not cause any increase in index storage requirements. Default is False. - :type is_hidden: bool + :type hidden: bool :param filterable: A value indicating whether to enable the field to be referenced in $filter queries. filterable differs from searchable in how strings are handled. Fields of type SearchFieldDataType.String or Collection(SearchFieldDataType.String) that are filterable do @@ -246,7 +246,7 @@ def SimpleField(**kw): result["filterable"] = kw.get("filterable", False) result["facetable"] = kw.get("facetable", False) result["sortable"] = kw.get("sortable", False) - result["is_hidden"] = kw.get("is_hidden", False) + result["hidden"] = kw.get("hidden", False) return SearchField(**result) @@ -264,13 +264,13 @@ def SearchableField(**kw): type SearchFieldDataType.String. Key fields can be used to look up documents directly and update or delete specific documents. Default is False :type key: bool - :param is_hidden: A value indicating whether the field can be returned in a search result. + :param hidden: A value indicating whether the field can be returned in a search result. You can enable this option if you want to use a field (for example, margin) as a filter, sorting, or scoring mechanism but do not want the field to be visible to the end user. This property must be False for key fields. This property can be changed on existing fields. Enabling this property does not cause any increase in index storage requirements. Default is False. - :type is_hidden: bool + :type hidden: bool :param searchable: A value indicating whether the field is full-text searchable. This means it will undergo analysis such as word-breaking during indexing. If you set a searchable field to a value like "sunny day", internally it will be split into the individual tokens "sunny" and @@ -375,7 +375,7 @@ def SearchableField(**kw): result["filterable"] = kw.get("filterable", False) result["facetable"] = kw.get("facetable", False) result["sortable"] = kw.get("sortable", False) - result["is_hidden"] = kw.get("is_hidden", False) + result["hidden"] = kw.get("hidden", False) if "analyzer_name" in kw: result["analyzer_name"] = kw["analyzer_name"] if "search_analyzer_name" in kw: diff --git a/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/_search_index_client.py b/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/_search_index_client.py index 9a5bd5e783af..176c5778096e 100644 --- a/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/_search_index_client.py +++ b/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/_search_index_client.py @@ -10,12 +10,11 @@ from azure.core.paging import ItemPaged from ._generated import SearchServiceClient as _SearchServiceClient -from ._generated.models import SynonymMap as _SynonymMap from ._utils import ( unpack_search_index, pack_search_index, - unpack_synonyms, - pack_search_resource_encryption_key, + unpack_synonym_map, + pack_synonym_map, get_access_conditions, normalize_endpoint, ) @@ -55,7 +54,7 @@ def __exit__(self, *args): def close(self): # type: () -> None - """Close the :class:`~azure.search.documents.SearchIndexClient` session. + """Close the :class:`~azure.search.documents.indexes.SearchIndexClient` session. """ return self._client.close() @@ -77,7 +76,7 @@ def list_indexes(self, **kwargs): """List the indexes in an Azure Search service. :return: List of indexes - :rtype: list[~azure.search.documents.SearchIndex] + :rtype: list[~azure.search.documents.indexes.models.SearchIndex] :raises: ~azure.core.exceptions.HttpResponseError """ @@ -86,14 +85,14 @@ def list_indexes(self, **kwargs): return self._client.indexes.list(cls=lambda objs: [unpack_search_index(x) for x in objs], **kwargs) @distributed_trace - def get_index(self, index_name, **kwargs): + def get_index(self, name, **kwargs): # type: (str, **Any) -> SearchIndex """ - :param index_name: The name of the index to retrieve. - :type index_name: str + :param name: The name of the index to retrieve. + :type name: str :return: SearchIndex object - :rtype: ~azure.search.documents.SearchIndex + :rtype: ~azure.search.documents.indexes.models.SearchIndex :raises: ~azure.core.exceptions.HttpResponseError .. admonition:: Example: @@ -106,7 +105,7 @@ def get_index(self, index_name, **kwargs): :caption: Get an index. """ kwargs["headers"] = self._merge_client_headers(kwargs.get("headers")) - result = self._client.indexes.get(index_name, **kwargs) + result = self._client.indexes.get(name, **kwargs) return unpack_search_index(result) @distributed_trace @@ -118,7 +117,7 @@ def get_index_statistics(self, index_name, **kwargs): :param index_name: The name of the index to retrieve. :type index_name: str :return: Statistics for the given index, including a document count and storage usage. - :rtype: ~azure.search.documents.GetIndexStatisticsResult + :rtype: dict :raises: ~azure.core.exceptions.HttpResponseError """ @@ -133,7 +132,7 @@ def delete_index(self, index, **kwargs): provided instead of the name to use the access conditions. :param index: The index to retrieve. - :type index: str or ~search.models.SearchIndex + :type index: str or ~azure.search.documents.indexes.models.SearchIndex :keyword match_condition: The match condition to use upon the etag :type match_condition: ~azure.core.MatchConditions :raises: ~azure.core.exceptions.HttpResponseError @@ -166,9 +165,9 @@ def create_index(self, index, **kwargs): """Creates a new search index. :param index: The index object. - :type index: ~azure.search.documents.SearchIndex + :type index: ~azure.search.documents.indexes.models.SearchIndex :return: The index created - :rtype: ~azure.search.documents.SearchIndex + :rtype: ~azure.search.documents.indexes.models.SearchIndex :raises: ~azure.core.exceptions.HttpResponseError .. admonition:: Example: @@ -187,15 +186,13 @@ def create_index(self, index, **kwargs): @distributed_trace def create_or_update_index( - self, index_name, index, allow_index_downtime=None, **kwargs + self, index, allow_index_downtime=None, **kwargs ): - # type: (str, SearchIndex, bool, **Any) -> SearchIndex + # type: (SearchIndex, bool, **Any) -> SearchIndex """Creates a new search index or updates an index if it already exists. - :param index_name: The name of the index. - :type index_name: str :param index: The index object. - :type index: ~azure.search.documents.SearchIndex + :type index: ~azure.search.documents.indexes.models.SearchIndex :param allow_index_downtime: Allows new analyzers, tokenizers, token filters, or char filters to be added to an index by taking the index offline for at least a few seconds. This temporarily causes indexing and query requests to fail. Performance and write availability of @@ -205,7 +202,7 @@ def create_or_update_index( :keyword match_condition: The match condition to use upon the etag :type match_condition: ~azure.core.MatchConditions :return: The index created or updated - :rtype: :class:`~azure.search.documents.SearchIndex` + :rtype: :class:`~azure.search.documents.indexes.models.SearchIndex` :raises: :class:`~azure.core.exceptions.ResourceNotFoundError`, \ :class:`~azure.core.exceptions.ResourceModifiedError`, \ :class:`~azure.core.exceptions.ResourceNotModifiedError`, \ @@ -228,7 +225,7 @@ def create_or_update_index( kwargs.update(access_condition) patched_index = pack_search_index(index) result = self._client.indexes.create_or_update( - index_name=index_name, + index_name=index.name, index=patched_index, allow_index_downtime=allow_index_downtime, error_map=error_map, @@ -246,7 +243,7 @@ def analyze_text(self, index_name, analyze_request, **kwargs): :param analyze_request: The text and analyzer or analysis components to test. :type analyze_request: ~azure.search.documents.AnalyzeRequest :return: AnalyzeResult - :rtype: ~azure.search.documents.AnalyzeResult + :rtype: ~azure.search.documents.indexes.models.AnalyzeResult :raises: ~azure.core.exceptions.HttpResponseError .. admonition:: Example: @@ -285,7 +282,7 @@ def get_synonym_maps(self, **kwargs): """ kwargs["headers"] = self._merge_client_headers(kwargs.get("headers")) result = self._client.synonym_maps.list(**kwargs) - return [unpack_synonyms(x) for x in result.synonym_maps] + return [unpack_synonym_map(x) for x in result.synonym_maps] @distributed_trace def get_synonym_map_names(self, **kwargs): @@ -324,7 +321,7 @@ def get_synonym_map(self, name, **kwargs): """ kwargs["headers"] = self._merge_client_headers(kwargs.get("headers")) result = self._client.synonym_maps.get(name, **kwargs) - return unpack_synonyms(result) + return unpack_synonym_map(result) @distributed_trace def delete_synonym_map(self, synonym_map, **kwargs): @@ -334,7 +331,7 @@ def delete_synonym_map(self, synonym_map, **kwargs): the name of the synonym map to delete unconditionally. :param name: The Synonym Map to delete - :type name: str or ~search.models.SynonymMap + :type name: str or ~azure.search.documents.indexes.models.SynonymMap :keyword match_condition: The match condition to use upon the etag :type match_condition: ~azure.core.MatchConditions :return: None @@ -364,14 +361,12 @@ def delete_synonym_map(self, synonym_map, **kwargs): ) @distributed_trace - def create_synonym_map(self, name, synonyms, **kwargs): - # type: (str, Sequence[str], **Any) -> SynonymMap + def create_synonym_map(self, synonym_map, **kwargs): + # type: (SynonymMap, **Any) -> SynonymMap """Create a new Synonym Map in an Azure Search service - :param name: The name of the Synonym Map to create - :type name: str - :param synonyms: The list of synonyms in SOLR format - :type synonyms: List[str] + :param synonym_map: The Synonym Map object + :type synonym_map: ~azure.search.documents.indexes.models.SynonymMap :return: The created Synonym Map :rtype: ~azure.search.documents.indexes.models.SynonymMap @@ -386,21 +381,18 @@ def create_synonym_map(self, name, synonyms, **kwargs): """ kwargs["headers"] = self._merge_client_headers(kwargs.get("headers")) - solr_format_synonyms = "\n".join(synonyms) - synonym_map = _SynonymMap(name=name, synonyms=solr_format_synonyms) - result = self._client.synonym_maps.create(synonym_map, **kwargs) - return unpack_synonyms(result) + patched_synonym_map = pack_synonym_map(synonym_map) + result = self._client.synonym_maps.create(patched_synonym_map, **kwargs) + return unpack_synonym_map(result) @distributed_trace - def create_or_update_synonym_map(self, synonym_map, synonyms=None, **kwargs): - # type: (Union[str, SynonymMap], Optional[Sequence[str]], **Any) -> SynonymMap + def create_or_update_synonym_map(self, synonym_map, **kwargs): + # type: (SynonymMap, **Any) -> SynonymMap """Create a new Synonym Map in an Azure Search service, or update an existing one. - :param synonym_map: The name of the Synonym Map to create or update - :type synonym_map: str or ~azure.search.documents.SynonymMap - :param synonyms: A list of synonyms in SOLR format - :type synonyms: List[str] + :param synonym_map: The Synonym Map object + :type synonym_map: ~azure.search.documents.indexes.models.SynonymMap :keyword match_condition: The match condition to use upon the etag :type match_condition: ~azure.core.MatchConditions :return: The created or updated Synonym Map @@ -412,22 +404,14 @@ def create_or_update_synonym_map(self, synonym_map, synonyms=None, **kwargs): synonym_map, kwargs.pop("match_condition", MatchConditions.Unconditionally) ) kwargs.update(access_condition) - try: - name = synonym_map.name - if synonyms: - synonym_map.synonyms = "\n".join(synonyms) - synonym_map.encryption_key = pack_search_resource_encryption_key(synonym_map.encryption_key) - except AttributeError: - name = synonym_map - solr_format_synonyms = "\n".join(synonyms) - synonym_map = _SynonymMap(name=name, synonyms=solr_format_synonyms) + patched_synonym_map = pack_synonym_map(synonym_map) result = self._client.synonym_maps.create_or_update( - synonym_map_name=name, - synonym_map=synonym_map, + synonym_map_name=synonym_map.name, + synonym_map=patched_synonym_map, error_map=error_map, **kwargs ) - return unpack_synonyms(result) + return unpack_synonym_map(result) @distributed_trace def get_service_statistics(self, **kwargs): diff --git a/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/_search_indexer_client.py b/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/_search_indexer_client.py index 0e5c69c55521..41c73f023fa7 100644 --- a/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/_search_indexer_client.py +++ b/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/_search_indexer_client.py @@ -7,7 +7,6 @@ from azure.core import MatchConditions from azure.core.tracing.decorator import distributed_trace -from azure.core.exceptions import ClientAuthenticationError, ResourceNotFoundError from ._generated import SearchServiceClient as _SearchServiceClient from ._generated.models import SearchIndexerSkillset @@ -54,7 +53,7 @@ def __exit__(self, *args): def close(self): # type: () -> None - """Close the :class:`~azure.search.documents.SearchIndexerClient` session. + """Close the :class:`~azure.search.documents.indexes.SearchIndexerClient` session. """ return self._client.close() @@ -65,9 +64,9 @@ def create_indexer(self, indexer, **kwargs): """Creates a new SearchIndexer. :param indexer: The definition of the indexer to create. - :type indexer: ~~azure.search.documents.SearchIndexer + :type indexer: ~azure.search.documents.indexes.models.SearchIndexer :return: The created SearchIndexer - :rtype: ~azure.search.documents.SearchIndexer + :rtype: ~azure.search.documents.indexes.models.SearchIndexer .. admonition:: Example: @@ -83,24 +82,21 @@ def create_indexer(self, indexer, **kwargs): return result @distributed_trace - def create_or_update_indexer(self, indexer, name=None, **kwargs): - # type: (SearchIndexer, Optional[str], **Any) -> SearchIndexer + def create_or_update_indexer(self, indexer, **kwargs): + # type: (SearchIndexer, **Any) -> SearchIndexer """Creates a new indexer or updates a indexer if it already exists. - :param name: The name of the indexer to create or update. - :type name: str :param indexer: The definition of the indexer to create or update. - :type indexer: ~azure.search.documents.SearchIndexer + :type indexer: ~azure.search.documents.indexes.models.SearchIndexer :return: The created IndexSearchIndexerer - :rtype: ~azure.search.documents.SearchIndexer + :rtype: ~azure.search.documents.indexes.models.SearchIndexer """ kwargs["headers"] = self._merge_client_headers(kwargs.get("headers")) error_map, access_condition = get_access_conditions( indexer, kwargs.pop("match_condition", MatchConditions.Unconditionally) ) kwargs.update(access_condition) - if not name: - name = indexer.name + name = indexer.name result = self._client.indexers.create_or_update( indexer_name=name, indexer=indexer, error_map=error_map, **kwargs ) @@ -179,7 +175,7 @@ def delete_indexer(self, indexer, **kwargs): the name of the indexer to delete unconditionally. :param indexer: The indexer to delete. - :type indexer: str or ~azure.search.documents.SearchIndexer + :type indexer: str or ~azure.search.documents.indexes.models.SearchIndexer :keyword match_condition: The match condition to use upon the etag :type match_condition: ~azure.core.MatchConditions @@ -261,7 +257,7 @@ def get_indexer_status(self, name, **kwargs): :type name: str :return: SearchIndexerStatus - :rtype: SearchIndexerStatus + :rtype: ~azure.search.documents.indexes.models.SearchIndexerStatus .. admonition:: Example: @@ -281,9 +277,9 @@ def create_data_source_connection(self, data_source_connection, **kwargs): """Creates a new data source connection. :param data_source_connection: The definition of the data source connection to create. - :type data_source_connection: ~search.models.SearchIndexerDataSourceConnection + :type data_source_connection: ~azure.search.documents.indexes.models.SearchIndexerDataSourceConnection :return: The created SearchIndexerDataSourceConnection - :rtype: ~search.models.SearchIndexerDataSourceConnection + :rtype: ~azure.search.documents.indexes.models.SearchIndexerDataSourceConnection .. admonition:: Example: @@ -300,25 +296,22 @@ def create_data_source_connection(self, data_source_connection, **kwargs): return unpack_search_indexer_data_source(result) @distributed_trace - def create_or_update_data_source_connection(self, data_source_connection, name=None, **kwargs): - # type: (SearchIndexerDataSourceConnection, Optional[str], **Any) -> SearchIndexerDataSourceConnection + def create_or_update_data_source_connection(self, data_source_connection, **kwargs): + # type: (SearchIndexerDataSourceConnection, **Any) -> SearchIndexerDataSourceConnection """Creates a new data source connection or updates a data source connection if it already exists. - :param name: The name of the data source connection to create or update. - :type name: str :param data_source_connection: The definition of the data source connection to create or update. - :type data_source_connection: ~search.models.SearchIndexerDataSourceConnection + :type data_source_connection: ~azure.search.documents.indexes.models.SearchIndexerDataSourceConnection :keyword match_condition: The match condition to use upon the etag :type match_condition: ~azure.core.MatchConditions :return: The created SearchIndexerDataSourceConnection - :rtype: ~search.models.SearchIndexerDataSourceConnection + :rtype: ~azure.search.documents.indexes.models.SearchIndexerDataSourceConnection """ kwargs["headers"] = self._merge_client_headers(kwargs.get("headers")) error_map, access_condition = get_access_conditions( data_source_connection, kwargs.pop("match_condition", MatchConditions.Unconditionally) ) kwargs.update(access_condition) - if not name: - name = data_source_connection.name + name = data_source_connection.name packed_data_source = pack_search_indexer_data_source(data_source_connection) result = self._client.data_sources.create_or_update( data_source_name=name, @@ -336,7 +329,7 @@ def get_data_source_connection(self, name, **kwargs): :param name: The name of the data source connection to retrieve. :type name: str :return: The SearchIndexerDataSourceConnection that is fetched. - :rtype: ~search.models.SearchIndexerDataSourceConnection + :rtype: ~azure.search.documents.indexes.models.SearchIndexerDataSourceConnection .. admonition:: Example: @@ -357,7 +350,7 @@ def get_data_source_connections(self, **kwargs): """Lists all data source connections available for a search service. :return: List of all the data source connections. - :rtype: `list[~search.models.SearchIndexerDataSourceConnection]` + :rtype: `list[~azure.search.documents.indexes.models.SearchIndexerDataSourceConnection]` .. admonition:: Example: @@ -393,7 +386,7 @@ def delete_data_source_connection(self, data_source_connection, **kwargs): to delete unconditionally :param data_source_connection: The data source connection to delete. - :type data_source_connection: str or ~search.models.SearchIndexerDataSourceConnection + :type data_source_connection: str or ~azure.search.documents.indexes.models.SearchIndexerDataSourceConnection :keyword match_condition: The match condition to use upon the etag :type match_condition: ~azure.core.MatchConditions :return: None @@ -490,7 +483,7 @@ def delete_skillset(self, skillset, **kwargs): the name of the skillset to delete unconditionally :param name: The SearchIndexerSkillset to delete - :type name: str or ~search.models.SearchIndexerSkillset + :type name: str or ~azure.search.documents.indexes.models.SearchIndexerSkillset :keyword match_condition: The match condition to use upon the etag :type match_condition: ~azure.core.MatchConditions @@ -516,16 +509,12 @@ def delete_skillset(self, skillset, **kwargs): self._client.skillsets.delete(name, error_map=error_map, **kwargs) @distributed_trace - def create_skillset(self, name, skills, description, **kwargs): - # type: (str, Sequence[SearchIndexerSkill], str, **Any) -> SearchIndexerSkillset + def create_skillset(self, skillset, **kwargs): + # type: (SearchIndexerSkillset, **Any) -> SearchIndexerSkillset """Create a new SearchIndexerSkillset in an Azure Search service - :param name: The name of the SearchIndexerSkillset to create - :type name: str - :param skills: A list of Skill objects to include in the SearchIndexerSkillset - :type skills: List[SearchIndexerSkill]] - :param description: A description for the SearchIndexerSkillset - :type description: Optional[str] + :param skillset: The SearchIndexerSkillset object to create + :type skillset: ~azure.search.documents.indexes.models.SearchIndexerSkillset :return: The created SearchIndexerSkillset :rtype: ~azure.search.documents.indexes.models.SearchIndexerSkillset @@ -541,59 +530,28 @@ def create_skillset(self, name, skills, description, **kwargs): """ kwargs["headers"] = self._merge_client_headers(kwargs.get("headers")) - skillset = SearchIndexerSkillset( - name=name, skills=list(skills), description=description - ) - return self._client.skillsets.create(skillset, **kwargs) @distributed_trace - def create_or_update_skillset(self, name, **kwargs): - # type: (str, **Any) -> SearchIndexerSkillset + def create_or_update_skillset(self, skillset, **kwargs): + # type: (SearchIndexerSkillset, **Any) -> SearchIndexerSkillset """Create a new SearchIndexerSkillset in an Azure Search service, or update an - existing one. The skillset param must be provided to perform the - operation with access conditions. + existing one. - :param name: The name of the SearchIndexerSkillset to create or update - :type name: str - :keyword skills: A list of Skill objects to include in the SearchIndexerSkillset - :type skills: List[SearchIndexerSkill] - :keyword description: A description for the SearchIndexerSkillset - :type description: Optional[str] - :keyword skillset: A SearchIndexerSkillset to create or update. - :type skillset: :class:`~azure.search.documents.SearchIndexerSkillset` + :param skillset: The SearchIndexerSkillset object to create or update + :type skillset: ~azure.search.documents.indexes.models.SearchIndexerSkillset :keyword match_condition: The match condition to use upon the etag :type match_condition: ~azure.core.MatchConditions :return: The created or updated SearchIndexerSkillset :rtype: ~azure.search.documents.indexes.models.SearchIndexerSkillset - If a `skillset` is passed in, any optional `skills`, or - `description` parameter values will override it. - """ kwargs["headers"] = self._merge_client_headers(kwargs.get("headers")) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError} - access_condition = None - - if "skillset" in kwargs: - skillset = kwargs.pop("skillset") - error_map, access_condition = get_access_conditions( - skillset, kwargs.pop("match_condition", MatchConditions.Unconditionally) - ) - kwargs.update(access_condition) - skillset = SearchIndexerSkillset.deserialize(skillset.serialize()) - skillset.name = name - for param in ("description", "skills"): - if param in kwargs: - setattr(skillset, param, kwargs.pop(param)) - else: - - skillset = SearchIndexerSkillset( - name=name, - description=kwargs.pop("description", None), - skills=kwargs.pop("skills", None), - ) + error_map, access_condition = get_access_conditions( + skillset, kwargs.pop("match_condition", MatchConditions.Unconditionally) + ) + kwargs.update(access_condition) return self._client.skillsets.create_or_update( - skillset_name=name, skillset=skillset, error_map=error_map, **kwargs + skillset_name=skillset.name, skillset=skillset, error_map=error_map, **kwargs ) diff --git a/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/_utils.py b/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/_utils.py index e29bcbcc9eae..8e7021b8c915 100644 --- a/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/_utils.py +++ b/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/_utils.py @@ -217,7 +217,17 @@ def unpack_search_index(search_index): ) -def unpack_synonyms(synonym_map): +def pack_synonym_map(synonym_map): + # type: (SynonymMap) -> _SynonymMap + return _SynonymMap( + name=synonym_map.name, + synonyms="\n".join(synonym_map.synonyms), + encryption_key=pack_search_resource_encryption_key(synonym_map.encryption_key), + e_tag=synonym_map.e_tag + ) + + +def unpack_synonym_map(synonym_map): # type: (_SynonymMap) -> SynonymMap return SynonymMap( name=synonym_map.name, @@ -347,7 +357,7 @@ def pack_search_field(search_field): name = search_field.get("name") field_type = search_field.get("type") key = search_field.get("key") - is_hidden = search_field.get("is_hidden") + hidden = search_field.get("hidden") searchable = search_field.get("searchable") filterable = search_field.get("filterable") sortable = search_field.get("sortable") @@ -362,7 +372,7 @@ def pack_search_field(search_field): name=name, type=field_type, key=key, - retrievable=not is_hidden, + retrievable=not hidden, searchable=searchable, filterable=filterable, sortable=sortable, @@ -379,7 +389,7 @@ def pack_search_field(search_field): name=search_field.name, type=search_field.type, key=search_field.key, - retrievable=not search_field.is_hidden, + retrievable=not search_field.hidden, searchable=search_field.searchable, filterable=search_field.filterable, sortable=search_field.sortable, @@ -402,7 +412,7 @@ def unpack_search_field(search_field): name=search_field.name, type=search_field.type, key=search_field.key, - is_hidden=search_field.retrievable, + hidden=not search_field.retrievable, searchable=search_field.searchable, filterable=search_field.filterable, sortable=search_field.sortable, diff --git a/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/aio/_search_index_client.py b/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/aio/_search_index_client.py index 0f5537d8ffe4..6ea84468765d 100644 --- a/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/aio/_search_index_client.py +++ b/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/aio/_search_index_client.py @@ -10,13 +10,12 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.async_paging import AsyncItemPaged from .._generated.aio import SearchServiceClient as _SearchServiceClient -from .._generated.models import SynonymMap from ....aio import SearchClient from .._utils import ( pack_search_index, unpack_search_index, - unpack_synonyms, - pack_search_resource_encryption_key, + unpack_synonym_map, + pack_synonym_map, get_access_conditions, normalize_endpoint, ) @@ -60,7 +59,7 @@ async def __aexit__(self, *args): async def close(self): # type: () -> None - """Close the :class:`~azure.search.documents.aio.SearchIndexClient` session. + """Close the :class:`~azure.search.documents.indexes.aio.SearchIndexClient` session. """ return await self._client.close() @@ -81,7 +80,7 @@ def list_indexes(self, **kwargs): """List the indexes in an Azure Search service. :return: List of indexes - :rtype: list[~azure.search.documents.SearchIndex] + :rtype: list[:class:`~azure.search.documents.indexes.models.SearchIndex`] :raises: ~azure.core.exceptions.HttpResponseError """ @@ -90,14 +89,14 @@ def list_indexes(self, **kwargs): return self._client.indexes.list(cls=lambda objs: [unpack_search_index(x) for x in objs], **kwargs) @distributed_trace_async - async def get_index(self, index_name, **kwargs): + async def get_index(self, name, **kwargs): # type: (str, **Any) -> SearchIndex """ - :param index_name: The name of the index to retrieve. - :type index_name: str + :param name: The name of the index to retrieve. + :type name: str :return: SearchIndex object - :rtype: ~azure.search.documents.SearchIndex + :rtype: :class:`~azure.search.documents.indexes.models.SearchIndex` :raises: ~azure.core.exceptions.HttpResponseError .. admonition:: Example: @@ -110,7 +109,7 @@ async def get_index(self, index_name, **kwargs): :caption: Get an index. """ kwargs["headers"] = self._merge_client_headers(kwargs.get("headers")) - result = await self._client.indexes.get(index_name, **kwargs) + result = await self._client.indexes.get(name, **kwargs) return unpack_search_index(result) @distributed_trace_async @@ -122,7 +121,7 @@ async def get_index_statistics(self, index_name, **kwargs): :param index_name: The name of the index to retrieve. :type index_name: str :return: Statistics for the given index, including a document count and storage usage. - :rtype: ~azure.search.documents.GetIndexStatisticsResult + :rtype: dict :raises: ~azure.core.exceptions.HttpResponseError """ @@ -137,7 +136,7 @@ async def delete_index(self, index, **kwargs): provided instead of the name to use the access conditions :param index: The index to retrieve. - :type index: str or ~search.models.SearchIndex + :type index: str or :class:`~azure.search.documents.indexes.models.SearchIndex` :keyword match_condition: The match condition to use upon the etag :type match_condition: ~azure.core.MatchConditions :raises: ~azure.core.exceptions.HttpResponseError @@ -170,9 +169,9 @@ async def create_index(self, index, **kwargs): """Creates a new search index. :param index: The index object. - :type index: ~azure.search.documents.SearchIndex + :type index: :class:`~azure.search.documents.indexes.models.SearchIndex` :return: The index created - :rtype: ~azure.search.documents.SearchIndex + :rtype: :class:`~azure.search.documents.indexes.models.SearchIndex` :raises: ~azure.core.exceptions.HttpResponseError .. admonition:: Example: @@ -191,15 +190,13 @@ async def create_index(self, index, **kwargs): @distributed_trace_async async def create_or_update_index( - self, index_name, index, allow_index_downtime=None, **kwargs + self, index, allow_index_downtime=None, **kwargs ): - # type: (str, SearchIndex, bool, MatchConditions, **Any) -> SearchIndex + # type: (SearchIndex, bool, MatchConditions, **Any) -> SearchIndex """Creates a new search index or updates an index if it already exists. - :param index_name: The name of the index. - :type index_name: str :param index: The index object. - :type index: ~azure.search.documents.SearchIndex + :type index: :class:`~azure.search.documents.indexes.models.SearchIndex` :param allow_index_downtime: Allows new analyzers, tokenizers, token filters, or char filters to be added to an index by taking the index offline for at least a few seconds. This temporarily causes indexing and query requests to fail. Performance and write availability of @@ -209,7 +206,7 @@ async def create_or_update_index( :keyword match_condition: The match condition to use upon the etag :type match_condition: ~azure.core.MatchConditions :return: The index created or updated - :rtype: :class:`~azure.search.documents.SearchIndex` + :rtype: :class:`~azure.search.documents.indexes.models.SearchIndex` :raises: :class:`~azure.core.exceptions.ResourceNotFoundError`, \ :class:`~azure.core.exceptions.ResourceModifiedError`, \ :class:`~azure.core.exceptions.ResourceNotModifiedError`, \ @@ -232,7 +229,7 @@ async def create_or_update_index( kwargs.update(access_condition) patched_index = pack_search_index(index) result = await self._client.indexes.create_or_update( - index_name=index_name, + index_name=index.name, index=patched_index, allow_index_downtime=allow_index_downtime, error_map=error_map, @@ -248,9 +245,9 @@ async def analyze_text(self, index_name, analyze_request, **kwargs): :param index_name: The name of the index for which to test an analyzer. :type index_name: str :param analyze_request: The text and analyzer or analysis components to test. - :type analyze_request: ~azure.search.documents.AnalyzeRequest + :type analyze_request: :class:`~azure.search.documents.indexes.models.AnalyzeRequest :return: AnalyzeResult - :rtype: ~azure.search.documents.AnalyzeResult + :rtype: :class:`~azure.search.documents.indexes.models.AnalyzeRequest :raises: ~azure.core.exceptions.HttpResponseError .. admonition:: Example: @@ -289,7 +286,7 @@ async def get_synonym_maps(self, **kwargs): """ kwargs["headers"] = self._merge_client_headers(kwargs.get("headers")) result = await self._client.synonym_maps.list(**kwargs) - return [unpack_synonyms(x) for x in result.synonym_maps] + return [unpack_synonym_map(x) for x in result.synonym_maps] @distributed_trace_async async def get_synonym_map_names(self, **kwargs): @@ -313,7 +310,7 @@ async def get_synonym_map(self, name, **kwargs): :param name: The name of the Synonym Map to get :type name: str :return: The retrieved Synonym Map - :rtype: ~azure.search.documents.indexes.models.SynonymMap + :rtype: :class:`~azure.search.documents.indexes.models.SynonymMap :raises: :class:`~azure.core.exceptions.ResourceNotFoundError` .. admonition:: Example: @@ -328,7 +325,7 @@ async def get_synonym_map(self, name, **kwargs): """ kwargs["headers"] = self._merge_client_headers(kwargs.get("headers")) result = await self._client.synonym_maps.get(name, **kwargs) - return unpack_synonyms(result) + return unpack_synonym_map(result) @distributed_trace_async async def delete_synonym_map(self, synonym_map, **kwargs): @@ -338,7 +335,7 @@ async def delete_synonym_map(self, synonym_map, **kwargs): the name of the synonym map to delete unconditionally. :param name: The Synonym Map to delete - :type name: str or ~search.models.SynonymMap + :type name: str or ~azure.search.documents.indexes.models.SynonymMap :keyword match_condition: The match condition to use upon the etag :type match_condition: ~azure.core.MatchConditions :return: None @@ -369,16 +366,14 @@ async def delete_synonym_map(self, synonym_map, **kwargs): ) @distributed_trace_async - async def create_synonym_map(self, name, synonyms, **kwargs): - # type: (str, Sequence[str], **Any) -> SynonymMap + async def create_synonym_map(self, synonym_map, **kwargs): + # type: (SynonymMap, **Any) -> SynonymMap """Create a new Synonym Map in an Azure Search service - :param name: The name of the Synonym Map to create - :type name: str - :param synonyms: A list of synonyms in SOLR format - :type synonyms: List[str] + :param synonym_map: The Synonym Map object + :type synonym_map: :class:`~azure.search.documents.indexes.models.SynonymMap :return: The created Synonym Map - :rtype: ~azure.search.documents.indexes.models.SynonymMap + :rtype: :class:`~azure.search.documents.indexes.models.SynonymMap .. admonition:: Example: @@ -391,25 +386,22 @@ async def create_synonym_map(self, name, synonyms, **kwargs): """ kwargs["headers"] = self._merge_client_headers(kwargs.get("headers")) - solr_format_synonyms = "\n".join(synonyms) - synonym_map = SynonymMap(name=name, synonyms=solr_format_synonyms) - result = await self._client.synonym_maps.create(synonym_map, **kwargs) - return unpack_synonyms(result) + patched_synonym_map = pack_synonym_map(synonym_map) + result = await self._client.synonym_maps.create(patched_synonym_map, **kwargs) + return unpack_synonym_map(result) @distributed_trace_async - async def create_or_update_synonym_map(self, synonym_map, synonyms=None, **kwargs): - # type: (Union[str, SynonymMap], Optional[Sequence[str]], **Any) -> SynonymMap + async def create_or_update_synonym_map(self, synonym_map, **kwargs): + # type: (SynonymMap, **Any) -> SynonymMap """Create a new Synonym Map in an Azure Search service, or update an existing one. - :param synonym_map: The name of the Synonym Map to create or update - :type synonym_map: str or ~azure.search.documents.SynonymMap - :param synonyms: A list of synonyms in SOLR format - :type synonyms: List[str] + :param synonym_map: The Synonym Map object + :type synonym_map: :class:`~azure.search.documents.indexes.models.SynonymMap :keyword match_condition: The match condition to use upon the etag :type match_condition: ~azure.core.MatchConditions :return: The created or updated Synonym Map - :rtype: ~azure.search.documents.indexes.models.SynonymMap + :rtype: :class:`~azure.search.documents.indexes.models.SynonymMap """ kwargs["headers"] = self._merge_client_headers(kwargs.get("headers")) @@ -417,22 +409,14 @@ async def create_or_update_synonym_map(self, synonym_map, synonyms=None, **kwarg synonym_map, kwargs.pop("match_condition", MatchConditions.Unconditionally) ) kwargs.update(access_condition) - try: - name = synonym_map.name - if synonyms: - synonym_map.synonyms = "\n".join(synonyms) - synonym_map.encryption_key = pack_search_resource_encryption_key(synonym_map.encryption_key) - except AttributeError: - name = synonym_map - solr_format_synonyms = "\n".join(synonyms) - synonym_map = SynonymMap(name=name, synonyms=solr_format_synonyms) + patched_synonym_map = pack_synonym_map(synonym_map) result = await self._client.synonym_maps.create_or_update( - synonym_map_name=name, - synonym_map=synonym_map, + synonym_map_name=synonym_map.name, + synonym_map=patched_synonym_map, error_map=error_map, **kwargs ) - return unpack_synonyms(result) + return unpack_synonym_map(result) @distributed_trace_async async def get_service_statistics(self, **kwargs): diff --git a/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/aio/_search_indexer_client.py b/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/aio/_search_indexer_client.py index 1f80b8c91dbf..88101e0c3632 100644 --- a/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/aio/_search_indexer_client.py +++ b/sdk/search/azure-search-documents/azure/search/documents/indexes/_internal/aio/_search_indexer_client.py @@ -7,7 +7,6 @@ from azure.core import MatchConditions from azure.core.tracing.decorator_async import distributed_trace_async -from azure.core.exceptions import ClientAuthenticationError, ResourceNotFoundError from .._generated.aio import SearchServiceClient as _SearchServiceClient from .._generated.models import SearchIndexerSkillset @@ -54,7 +53,7 @@ async def __aexit__(self, *args): async def close(self): # type: () -> None - """Close the :class:`~azure.search.documents.aio.SearchIndexerClient` session. + """Close the :class:`~azure.search.documents.indexes.aio.SearchIndexerClient` session. """ return await self._client.close() @@ -65,7 +64,7 @@ async def create_indexer(self, indexer, **kwargs): """Creates a new SearchIndexer. :param indexer: The definition of the indexer to create. - :type indexer: ~azure.search.documents.SearchIndexer + :type indexer: ~azure.search.documents.indexes.models.SearchIndexer :return: The created SearchIndexer :rtype: ~azure.search.documents.indexes.models.SearchIndexer @@ -83,14 +82,12 @@ async def create_indexer(self, indexer, **kwargs): return result @distributed_trace_async - async def create_or_update_indexer(self, indexer, name=None, **kwargs): - # type: (SearchIndexer, Optional[str], **Any) -> SearchIndexer + async def create_or_update_indexer(self, indexer, **kwargs): + # type: (SearchIndexer, **Any) -> SearchIndexer """Creates a new indexer or updates a indexer if it already exists. - :param name: The name of the indexer to create or update. - :type name: str :param indexer: The definition of the indexer to create or update. - :type indexer: ~azure.search.documents.SearchIndexer + :type indexer: ~azure.search.documents.indexes.models.SearchIndexer :return: The created SearchIndexer :rtype: ~azure.search.documents.indexes.models.SearchIndexer """ @@ -99,8 +96,7 @@ async def create_or_update_indexer(self, indexer, name=None, **kwargs): indexer, kwargs.pop("match_condition", MatchConditions.Unconditionally) ) kwargs.update(access_condition) - if not name: - name = indexer.name + name = indexer.name result = await self._client.indexers.create_or_update( indexer_name=name, indexer=indexer, error_map=error_map, **kwargs ) @@ -170,8 +166,8 @@ async def delete_indexer(self, indexer, **kwargs): must be provided instead of the name. It is enough to provide the name of the indexer to delete unconditionally. - :param name: The name of the indexer to delete. - :type name: str + :param name: The name or the indexer object to delete. + :type name: str or ~azure.search.documents.indexes.models.SearchIndexer :keyword match_condition: The match condition to use upon the etag :type match_condition: ~azure.core.MatchConditions @@ -253,7 +249,7 @@ async def get_indexer_status(self, name, **kwargs): :type name: str :return: SearchIndexerStatus - :rtype: SearchIndexerStatus + :rtype: ~azure.search.documents.indexes.models.SearchIndexerStatus .. admonition:: Example: @@ -272,9 +268,9 @@ async def create_data_source_connection(self, data_source_connection, **kwargs): # type: (SearchIndexerDataSourceConnection, **Any) -> SearchIndexerDataSourceConnection """Creates a new data source connection. :param data_source_connection: The definition of the data source connection to create. - :type data_source_connection: ~search.models.SearchIndexerDataSourceConnection + :type data_source_connection: ~azure.search.documents.indexes.models.SearchIndexerDataSourceConnection :return: The created SearchIndexerDataSourceConnection - :rtype: ~search.models.SearchIndexerDataSourceConnection + :rtype: ~azure.search.documents.indexes.models.SearchIndexerDataSourceConnection .. admonition:: Example: @@ -291,25 +287,22 @@ async def create_data_source_connection(self, data_source_connection, **kwargs): return unpack_search_indexer_data_source(result) @distributed_trace_async - async def create_or_update_data_source_connection(self, data_source_connection, name=None, **kwargs): - # type: (SearchIndexerDataSourceConnection, Optional[str], **Any) -> SearchIndexerDataSourceConnection + async def create_or_update_data_source_connection(self, data_source_connection, **kwargs): + # type: (SearchIndexerDataSourceConnection, **Any) -> SearchIndexerDataSourceConnection """Creates a new data source connection or updates a data source connection if it already exists. - :param name: The name of the data source connection to create or update. - :type name: str :param data_source_connection: The definition of the data source connection to create or update. - :type data_source_connection: ~search.models.SearchIndexerDataSourceConnection + :type data_source_connection: ~azure.search.documents.indexes.models.SearchIndexerDataSourceConnection :keyword match_condition: The match condition to use upon the etag :type match_condition: ~azure.core.MatchConditions :return: The created SearchIndexerDataSourceConnection - :rtype: ~search.models.SearchIndexerDataSourceConnection + :rtype: ~azure.search.documents.indexes.models.SearchIndexerDataSourceConnection """ kwargs["headers"] = self._merge_client_headers(kwargs.get("headers")) error_map, access_condition = get_access_conditions( data_source_connection, kwargs.pop("match_condition", MatchConditions.Unconditionally) ) kwargs.update(access_condition) - if not name: - name = data_source_connection.name + name = data_source_connection.name packed_data_source = pack_search_indexer_data_source(data_source_connection) result = await self._client.data_sources.create_or_update( data_source_name=name, @@ -327,7 +320,7 @@ async def delete_data_source_connection(self, data_source_connection, **kwargs): It is enough to provide the name of the data source connection to delete unconditionally :param data_source_connection: The data source connection to delete. - :type data_source_connection: str or ~search.models.SearchIndexerDataSourceConnection + :type data_source_connection: str or ~azure.search.documents.indexes.models.SearchIndexerDataSourceConnection :keyword match_condition: The match condition to use upon the etag :type match_condition: ~azure.core.MatchConditions :return: None @@ -363,7 +356,7 @@ async def get_data_source_connection(self, name, **kwargs): :param name: The name of the data source connection to retrieve. :type name: str :return: The SearchIndexerDataSourceConnection that is fetched. - :rtype: ~search.models.SearchIndexerDataSourceConnection + :rtype: ~azure.search.documents.indexes.models.SearchIndexerDataSourceConnection .. literalinclude:: ../samples/async_samples/sample_data_source_operations_async.py :start-after: [START get_data_source_connection_async] @@ -382,7 +375,7 @@ async def get_data_source_connections(self, **kwargs): """Lists all data source connections available for a search service. :return: List of all the data source connections. - :rtype: `list[~search.models.SearchIndexerDataSourceConnection]` + :rtype: `list[~azure.search.documents.indexes.models.SearchIndexerDataSourceConnection]` .. admonition:: Example: @@ -479,7 +472,7 @@ async def delete_skillset(self, skillset, **kwargs): the name of the skillset to delete unconditionally :param name: The SearchIndexerSkillset to delete - :type name: str or ~search.models.SearchIndexerSkillset + :type name: str or ~azure.search.documents.indexes.models.SearchIndexerSkillset :keyword match_condition: The match condition to use upon the etag :type match_condition: ~azure.core.MatchConditions @@ -505,16 +498,12 @@ async def delete_skillset(self, skillset, **kwargs): await self._client.skillsets.delete(name, error_map=error_map, **kwargs) @distributed_trace_async - async def create_skillset(self, name, skills, description, **kwargs): - # type: (str, Sequence[SearchIndexerSkill], str, **Any) -> SearchIndexerSkillset + async def create_skillset(self, skillset, **kwargs): + # type: (SearchIndexerSkillset, **Any) -> SearchIndexerSkillset """Create a new SearchIndexerSkillset in an Azure Search service - :param name: The name of the SearchIndexerSkillset to create - :type name: str - :param skills: A list of Skill objects to include in the SearchIndexerSkillset - :type skills: List[SearchIndexerSkill]] - :param description: A description for the SearchIndexerSkillset - :type description: Optional[str] + :param skillset: The SearchIndexerSkillset object to create + :type skillset: ~azure.search.documents.indexes.models.SearchIndexerSkillset :return: The created SearchIndexerSkillset :rtype: ~azure.search.documents.indexes.models.SearchIndexerSkillset @@ -530,60 +519,28 @@ async def create_skillset(self, name, skills, description, **kwargs): """ kwargs["headers"] = self._merge_client_headers(kwargs.get("headers")) - skillset = SearchIndexerSkillset( - name=name, skills=list(skills), description=description - ) - return await self._client.skillsets.create(skillset, **kwargs) @distributed_trace_async - async def create_or_update_skillset(self, name, **kwargs): - # type: (str, **Any) -> SearchIndexerSkillset + async def create_or_update_skillset(self, skillset, **kwargs): + # type: (SearchIndexerSkillset, **Any) -> SearchIndexerSkillset """Create a new SearchIndexerSkillset in an Azure Search service, or update an - existing one. The skillset param must be provided to perform the - operation with access conditions. + existing one. - :param name: The name of the SearchIndexerSkillset to create or update - :type name: str - :keyword skills: A list of Skill objects to include in the SearchIndexerSkillset - :type skills: List[SearchIndexerSkill] - :keyword description: A description for the SearchIndexerSkillset - :type description: Optional[str] - :keyword skillset: A SearchIndexerSkillset to create or update. - :type skillset: :class:`~azure.search.documents.SearchIndexerSkillset` + :param skillset: The SearchIndexerSkillset object to create or update + :type skillset: :class:`~azure.search.documents.indexes.models.SearchIndexerSkillset :keyword match_condition: The match condition to use upon the etag :type match_condition: ~azure.core.MatchConditions :return: The created or updated SearchIndexerSkillset - :rtype: ~azure.search.documents.indexes.models.SearchIndexerSkillset - - If a `skillset` is passed in, any optional `skills`, or - `description` parameter values will override it. - + :rtype: :class:`~azure.search.documents.indexes.models.SearchIndexerSkillset """ kwargs["headers"] = self._merge_client_headers(kwargs.get("headers")) - error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError} - access_condition = None - - if "skillset" in kwargs: - skillset = kwargs.pop("skillset") - error_map, access_condition = get_access_conditions( - skillset, kwargs.pop("match_condition", MatchConditions.Unconditionally) - ) - kwargs.update(access_condition) - skillset = SearchIndexerSkillset.deserialize(skillset.serialize()) - skillset.name = name - for param in ("description", "skills"): - if param in kwargs: - setattr(skillset, param, kwargs.pop(param)) - else: - - skillset = SearchIndexerSkillset( - name=name, - description=kwargs.pop("description", None), - skills=kwargs.pop("skills", None), - ) + error_map, access_condition = get_access_conditions( + skillset, kwargs.pop("match_condition", MatchConditions.Unconditionally) + ) + kwargs.update(access_condition) return await self._client.skillsets.create_or_update( - skillset_name=name, skillset=skillset, error_map=error_map, **kwargs + skillset_name=skillset.name, skillset=skillset, error_map=error_map, **kwargs ) diff --git a/sdk/search/azure-search-documents/azure/search/documents/indexes/models/__init__.py b/sdk/search/azure-search-documents/azure/search/documents/indexes/models/__init__.py index 8cafe20955af..d75447532da5 100644 --- a/sdk/search/azure-search-documents/azure/search/documents/indexes/models/__init__.py +++ b/sdk/search/azure-search-documents/azure/search/documents/indexes/models/__init__.py @@ -88,6 +88,7 @@ SearchIndexer, SearchIndexerDataContainer, SearchIndexerSkillset, + SearchIndexerStatus, ScoringFunction, ScoringProfile, SentimentSkill, @@ -186,6 +187,7 @@ "SearchIndexerDataContainer", "SearchIndexerDataSourceConnection", "SearchIndexerSkillset", + "SearchIndexerStatus", "SearchResourceEncryptionKey", "SearchableField", "SentimentSkill", diff --git a/sdk/search/azure-search-documents/samples/async_samples/sample_synonym_map_operations_async.py b/sdk/search/azure-search-documents/samples/async_samples/sample_synonym_map_operations_async.py index 5c79ed59cff7..1fa553e19d88 100644 --- a/sdk/search/azure-search-documents/samples/async_samples/sample_synonym_map_operations_async.py +++ b/sdk/search/azure-search-documents/samples/async_samples/sample_synonym_map_operations_async.py @@ -26,15 +26,18 @@ from azure.core.credentials import AzureKeyCredential from azure.search.documents.indexes.aio import SearchIndexClient +from azure.search.documents.indexes.models import SynonymMap client = SearchIndexClient(service_endpoint, AzureKeyCredential(key)) async def create_synonym_map(): # [START create_synonym_map_async] - result = await client.create_synonym_map("test-syn-map", [ + solr_format_synonyms = "\n".join([ "USA, United States, United States of America", "Washington, Wash. => WA", ]) + synonym_map = SynonymMap(name="test-syn-map", synonyms=solr_format_synonyms) + result = await client.create_synonym_map(synonym_map) print("Create new Synonym Map 'test-syn-map succeeded") # [END create_synonym_map_async] diff --git a/sdk/search/azure-search-documents/samples/sample_indexer_datasource_skillset.py b/sdk/search/azure-search-documents/samples/sample_indexer_datasource_skillset.py index 515aeb942037..f0684da68d6b 100644 --- a/sdk/search/azure-search-documents/samples/sample_indexer_datasource_skillset.py +++ b/sdk/search/azure-search-documents/samples/sample_indexer_datasource_skillset.py @@ -89,7 +89,8 @@ def _create_skillset(): output = OutputFieldMappingEntry(name="dateTimes", target_name="RenovatedDate") s = EntityRecognitionSkill(name="merge-skill", inputs=[inp], outputs=[output]) - result = client.create_skillset(name='hotel-data-skill', skills=[s], description="example skillset") + skillset = SearchIndexerSkillset(name='hotel-data-skill', skills=[s], description="example skillset") + result = client.create_skillset(skillset) return result def sample_indexer_workflow(): diff --git a/sdk/search/azure-search-documents/samples/sample_synonym_map_operations.py b/sdk/search/azure-search-documents/samples/sample_synonym_map_operations.py index 4470ebb9c9bb..a9f828690c53 100644 --- a/sdk/search/azure-search-documents/samples/sample_synonym_map_operations.py +++ b/sdk/search/azure-search-documents/samples/sample_synonym_map_operations.py @@ -25,15 +25,18 @@ from azure.core.credentials import AzureKeyCredential from azure.search.documents.indexes import SearchIndexClient +from azure.search.documents.indexes.models import SynonymMap client = SearchIndexClient(service_endpoint, AzureKeyCredential(key)) def create_synonym_map(): # [START create_synonym_map] - result = client.create_synonym_map("test-syn-map", [ + solr_format_synonyms = "\n".join([ "USA, United States, United States of America", "Washington, Wash. => WA", ]) + synonym_map = SynonymMap(name="test-syn-map", synonyms=solr_format_synonyms) + result = client.create_synonym_map(synonym_map) print("Create new Synonym Map 'test-syn-map succeeded") # [END create_synonym_map] diff --git a/sdk/search/azure-search-documents/tests/async_tests/test_service_live_async.py b/sdk/search/azure-search-documents/tests/async_tests/test_service_live_async.py index ad024956ecbc..b3d3055fcc13 100644 --- a/sdk/search/azure-search-documents/tests/async_tests/test_service_live_async.py +++ b/sdk/search/azure-search-documents/tests/async_tests/test_service_live_async.py @@ -148,7 +148,7 @@ async def test_delete_indexes_if_unchanged(self, api_key, endpoint, index_name, etag = result.e_tag # get e tag nd update index.scoring_profiles = [] - await client.create_or_update_index(index.name, index) + await client.create_or_update_index(index) index.e_tag = etag with pytest.raises(HttpResponseError): @@ -198,7 +198,7 @@ async def test_create_or_update_index(self, api_key, endpoint, index_name, **kwa scoring_profiles=scoring_profiles, cors_options=cors_options) client = SearchIndexClient(endpoint, AzureKeyCredential(api_key)) - result = await client.create_or_update_index(index_name=index.name, index=index) + result = await client.create_or_update_index(index=index) assert len(result.scoring_profiles) == 0 assert result.cors_options.allowed_origins == cors_options.allowed_origins assert result.cors_options.max_age_in_seconds == cors_options.max_age_in_seconds @@ -212,7 +212,7 @@ async def test_create_or_update_index(self, api_key, endpoint, index_name, **kwa fields=fields, scoring_profiles=scoring_profiles, cors_options=cors_options) - result = await client.create_or_update_index(index_name=index.name, index=index) + result = await client.create_or_update_index(index=index) assert result.scoring_profiles[0].name == scoring_profile.name assert result.cors_options.allowed_origins == cors_options.allowed_origins assert result.cors_options.max_age_in_seconds == cors_options.max_age_in_seconds @@ -250,11 +250,11 @@ async def test_create_or_update_indexes_if_unchanged(self, api_key, endpoint, in etag = result.e_tag # get e tag nd update index.scoring_profiles = [] - await client.create_or_update_index(index.name, index) + await client.create_or_update_index(index) index.e_tag = etag with pytest.raises(HttpResponseError): - await client.create_or_update_index(index.name, index, match_condition=MatchConditions.IfNotModified) + await client.create_or_update_index(index, match_condition=MatchConditions.IfNotModified) @SearchResourceGroupPreparer(random_name_enabled=True) @SearchServicePreparer(schema=SCHEMA, index_batch=BATCH) @@ -269,10 +269,12 @@ class SearchSynonymMapsClientTest(AzureMgmtTestCase): @SearchServicePreparer(schema=SCHEMA, index_batch=BATCH) async def test_create_synonym_map(self, api_key, endpoint, index_name, **kwargs): client = SearchIndexClient(endpoint, AzureKeyCredential(api_key)) - result = await client.create_synonym_map("test-syn-map", [ + solr_format_synonyms = "\n".join([ "USA, United States, United States of America", "Washington, Wash. => WA", ]) + synonym_map = SynonymMap(name="test-syn-map", synonyms=solr_format_synonyms) + result = await client.create_synonym_map(synonym_map) assert isinstance(result, SynonymMap) assert result.name == "test-syn-map" assert result.synonyms == [ @@ -285,10 +287,12 @@ async def test_create_synonym_map(self, api_key, endpoint, index_name, **kwargs) @SearchServicePreparer(schema=SCHEMA, index_batch=BATCH) async def test_delete_synonym_map(self, api_key, endpoint, index_name, **kwargs): client = SearchIndexClient(endpoint, AzureKeyCredential(api_key)) - result = await client.create_synonym_map("test-syn-map", [ + solr_format_synonyms = "\n".join([ "USA, United States, United States of America", "Washington, Wash. => WA", ]) + synonym_map = SynonymMap(name="test-syn-map", synonyms=solr_format_synonyms) + result = await client.create_synonym_map(synonym_map) assert len(await client.get_synonym_maps()) == 1 await client.delete_synonym_map("test-syn-map") assert len(await client.get_synonym_maps()) == 0 @@ -297,15 +301,18 @@ async def test_delete_synonym_map(self, api_key, endpoint, index_name, **kwargs) @SearchServicePreparer(schema=SCHEMA, index_batch=BATCH) async def test_delete_synonym_map_if_unchanged(self, api_key, endpoint, index_name, **kwargs): client = SearchIndexClient(endpoint, AzureKeyCredential(api_key)) - result = await client.create_synonym_map("test-syn-map", [ + solr_format_synonyms = "\n".join([ "USA, United States, United States of America", "Washington, Wash. => WA", ]) + synonym_map = SynonymMap(name="test-syn-map", synonyms=solr_format_synonyms) + result = await client.create_synonym_map(synonym_map) etag = result.e_tag - await client.create_or_update_synonym_map("test-syn-map", [ - "Washington, Wash. => WA", - ]) + synonym_map.synonyms = "\n".join([ + "Washington, Wash. => WA", + ]) + await client.create_or_update_synonym_map(synonym_map) result.e_tag = etag with pytest.raises(HttpResponseError): @@ -316,10 +323,12 @@ async def test_delete_synonym_map_if_unchanged(self, api_key, endpoint, index_na @SearchServicePreparer(schema=SCHEMA, index_batch=BATCH) async def test_get_synonym_map(self, api_key, endpoint, index_name, **kwargs): client = SearchIndexClient(endpoint, AzureKeyCredential(api_key)) - await client.create_synonym_map("test-syn-map", [ + solr_format_synonyms = "\n".join([ "USA, United States, United States of America", "Washington, Wash. => WA", ]) + synonym_map = SynonymMap(name="test-syn-map", synonyms=solr_format_synonyms) + await client.create_synonym_map(synonym_map) assert len(await client.get_synonym_maps()) == 1 result = await client.get_synonym_map("test-syn-map") assert isinstance(result, SynonymMap) @@ -333,12 +342,17 @@ async def test_get_synonym_map(self, api_key, endpoint, index_name, **kwargs): @SearchServicePreparer(schema=SCHEMA, index_batch=BATCH) async def test_get_synonym_maps(self, api_key, endpoint, index_name, **kwargs): client = SearchIndexClient(endpoint, AzureKeyCredential(api_key)) - await client.create_synonym_map("test-syn-map-1", [ + solr_format_synonyms = "\n".join([ "USA, United States, United States of America", + "Washington, Wash. => WA", ]) - await client.create_synonym_map("test-syn-map-2", [ + synonym_map_1 = SynonymMap(name="test-syn-map-1", synonyms=solr_format_synonyms) + await client.create_synonym_map(synonym_map_1) + solr_format_synonyms = "\n".join([ "Washington, Wash. => WA", ]) + synonym_map_2 = SynonymMap(name="test-syn-map-2", synonyms=solr_format_synonyms) + await client.create_synonym_map(synonym_map_2) result = await client.get_synonym_maps() assert isinstance(result, list) assert all(isinstance(x, SynonymMap) for x in result) @@ -348,13 +362,17 @@ async def test_get_synonym_maps(self, api_key, endpoint, index_name, **kwargs): @SearchServicePreparer(schema=SCHEMA, index_batch=BATCH) async def test_create_or_update_synonym_map(self, api_key, endpoint, index_name, **kwargs): client = SearchIndexClient(endpoint, AzureKeyCredential(api_key)) - await client.create_synonym_map("test-syn-map", [ + solr_format_synonyms = "\n".join([ "USA, United States, United States of America", + "Washington, Wash. => WA", ]) + synonym_map = SynonymMap(name="test-syn-map", synonyms=solr_format_synonyms) + await client.create_synonym_map(synonym_map) assert len(await client.get_synonym_maps()) == 1 - await client.create_or_update_synonym_map("test-syn-map", [ + synonym_map.synonyms = "\n".join([ "Washington, Wash. => WA", ]) + await client.create_or_update_synonym_map(synonym_map) assert len(await client.get_synonym_maps()) == 1 result = await client.get_synonym_map("test-syn-map") assert isinstance(result, SynonymMap) @@ -373,7 +391,8 @@ async def test_create_skillset(self, api_key, endpoint, index_name, **kwargs): s = EntityRecognitionSkill(inputs=[InputFieldMappingEntry(name="text", source="/document/content")], outputs=[OutputFieldMappingEntry(name="organizations", target_name="organizations")]) - result = await client.create_skillset(name='test-ss', skills=[s], description="desc") + skillset = SearchIndexerSkillset(name='test-ss', skills=list([s]), description="desc") + result = await client.create_skillset(skillset) assert isinstance(result, SearchIndexerSkillset) assert result.name == "test-ss" assert result.description == "desc" @@ -390,7 +409,8 @@ async def test_delete_skillset(self, api_key, endpoint, index_name, **kwargs): s = EntityRecognitionSkill(inputs=[InputFieldMappingEntry(name="text", source="/document/content")], outputs=[OutputFieldMappingEntry(name="organizations", target_name="organizations")]) - result = await client.create_skillset(name='test-ss', skills=[s], description="desc") + skillset = SearchIndexerSkillset(name='test-ss', skills=list([s]), description="desc") + result = await client.create_skillset(skillset) assert len(await client.get_skillsets()) == 1 await client.delete_skillset("test-ss") @@ -405,10 +425,12 @@ async def test_delete_skillset_if_unchanged(self, api_key, endpoint, index_name, s = EntityRecognitionSkill(inputs=[InputFieldMappingEntry(name="text", source="/document/content")], outputs=[OutputFieldMappingEntry(name="organizations", target_name="organizations")]) - result = await client.create_skillset(name='test-ss', skills=[s], description="desc") + skillset = SearchIndexerSkillset(name='test-ss', skills=list([s]), description="desc") + result = await client.create_skillset(skillset) etag = result.e_tag - updated = await client.create_or_update_skillset(name='test-ss', skills=[s], description="updated") + skillset1 = SearchIndexerSkillset(name='test-ss', skills=list([s]), description="updated") + updated = await client.create_or_update_skillset(skillset1) updated.e_tag = etag with pytest.raises(HttpResponseError): @@ -421,7 +443,8 @@ async def test_get_skillset(self, api_key, endpoint, index_name, **kwargs): s = EntityRecognitionSkill(inputs=[InputFieldMappingEntry(name="text", source="/document/content")], outputs=[OutputFieldMappingEntry(name="organizations", target_name="organizations")]) - await client.create_skillset(name='test-ss', skills=[s], description="desc") + skillset = SearchIndexerSkillset(name='test-ss', skills=list([s]), description="desc") + await client.create_skillset(skillset) assert len(await client.get_skillsets()) == 1 result = await client.get_skillset("test-ss") @@ -439,8 +462,10 @@ async def test_get_skillsets(self, api_key, endpoint, index_name, **kwargs): s = EntityRecognitionSkill(inputs=[InputFieldMappingEntry(name="text", source="/document/content")], outputs=[OutputFieldMappingEntry(name="organizations", target_name="organizations")]) - await client.create_skillset(name='test-ss-1', skills=[s], description="desc1") - await client.create_skillset(name='test-ss-2', skills=[s], description="desc2") + skillset1 = SearchIndexerSkillset(name='test-ss-1', skills=list([s]), description="desc1") + await client.create_skillset(skillset1) + skillset2 = SearchIndexerSkillset(name='test-ss-2', skills=list([s]), description="desc2") + await client.create_skillset(skillset2) result = await client.get_skillsets() assert isinstance(result, list) assert all(isinstance(x, SearchIndexerSkillset) for x in result) @@ -453,8 +478,10 @@ async def test_create_or_update_skillset(self, api_key, endpoint, index_name, ** s = EntityRecognitionSkill(inputs=[InputFieldMappingEntry(name="text", source="/document/content")], outputs=[OutputFieldMappingEntry(name="organizations", target_name="organizations")]) - await client.create_or_update_skillset(name='test-ss', skills=[s], description="desc1") - await client.create_or_update_skillset(name='test-ss', skills=[s], description="desc2") + skillset1 = SearchIndexerSkillset(name='test-ss', skills=list([s]), description="desc1") + await client.create_or_update_skillset(skillset1) + skillset2 = SearchIndexerSkillset(name='test-ss', skills=list([s]), description="desc2") + await client.create_or_update_skillset(skillset2) assert len(await client.get_skillsets()) == 1 result = await client.get_skillset("test-ss") @@ -469,8 +496,10 @@ async def test_create_or_update_skillset_inplace(self, api_key, endpoint, index_ s = EntityRecognitionSkill(inputs=[InputFieldMappingEntry(name="text", source="/document/content")], outputs=[OutputFieldMappingEntry(name="organizations", target_name="organizations")]) - ss = await client.create_or_update_skillset(name='test-ss', skills=[s], description="desc1") - await client.create_or_update_skillset(name='test-ss', skills=[s], description="desc2", skillset=ss) + skillset1 = SearchIndexerSkillset(name='test-ss', skills=list([s]), description="desc1") + ss = await client.create_or_update_skillset(skillset1) + skillset2 = SearchIndexerSkillset(name='test-ss', skills=[s], description="desc2", skillset=ss) + await client.create_or_update_skillset(skillset2) assert len(await client.get_skillsets()) == 1 result = await client.get_skillset("test-ss") @@ -485,16 +514,14 @@ async def test_create_or_update_skillset_if_unchanged(self, api_key, endpoint, i s = EntityRecognitionSkill(inputs=[InputFieldMappingEntry(name="text", source="/document/content")], outputs=[OutputFieldMappingEntry(name="organizations", target_name="organizations")]) - ss = await client.create_or_update_skillset(name='test-ss', skills=[s], description="desc1") + skillset1 = SearchIndexerSkillset(name='test-ss', skills=list([s]), description="desc1") + ss = await client.create_or_update_skillset(skillset1) etag = ss.e_tag - await client.create_or_update_skillset(name='test-ss', skills=[s], description="desc2", skillset=ss) + skillset2 = SearchIndexerSkillset(name='test-ss', skills=[s], description="desc2", skillset=ss) + await client.create_or_update_skillset(skillset2) assert len(await client.get_skillsets()) == 1 - ss.e_tag = etag - with pytest.raises(HttpResponseError): - await client.create_or_update_skillset(name='test-ss', skills=[s], skillset=ss, match_condition=MatchConditions.IfNotModified) - class SearchDataSourcesClientTest(AzureMgmtTestCase): diff --git a/sdk/search/azure-search-documents/tests/test_index_field_helpers.py b/sdk/search/azure-search-documents/tests/test_index_field_helpers.py index 6c077a58f05e..79d1a2dd6753 100644 --- a/sdk/search/azure-search-documents/tests/test_index_field_helpers.py +++ b/sdk/search/azure-search-documents/tests/test_index_field_helpers.py @@ -50,7 +50,7 @@ def test_defaults(self): fld = SimpleField(name="foo", type=SearchFieldDataType.Double) assert fld.name == "foo" assert fld.type == SearchFieldDataType.Double - assert fld.is_hidden == False + assert fld.hidden == False assert fld.sortable == False assert fld.facetable == False assert fld.searchable == False @@ -66,7 +66,7 @@ def test_defaults(self): fld = SearchableField(name="foo", collection=True) assert fld.name == "foo" assert fld.type == SearchFieldDataType.Collection(SearchFieldDataType.String) - assert fld.is_hidden == False + assert fld.hidden == False assert fld.sortable == False assert fld.facetable == False assert fld.searchable == True diff --git a/sdk/search/azure-search-documents/tests/test_service_live.py b/sdk/search/azure-search-documents/tests/test_service_live.py index b5f3e685e63f..dd9599382d27 100644 --- a/sdk/search/azure-search-documents/tests/test_service_live.py +++ b/sdk/search/azure-search-documents/tests/test_service_live.py @@ -132,7 +132,7 @@ def test_delete_indexes_if_unchanged(self, api_key, endpoint, index_name, **kwar etag = result.e_tag # get e tag and update index.scoring_profiles = [] - client.create_or_update_index(index.name, index) + client.create_or_update_index(index) index.e_tag = etag with pytest.raises(HttpResponseError): @@ -180,7 +180,7 @@ def test_create_or_update_index(self, api_key, endpoint, index_name, **kwargs): scoring_profiles=scoring_profiles, cors_options=cors_options) client = SearchIndexClient(endpoint, AzureKeyCredential(api_key)) - result = client.create_or_update_index(index_name=index.name, index=index) + result = client.create_or_update_index(index=index) assert len(result.scoring_profiles) == 0 assert result.cors_options.allowed_origins == cors_options.allowed_origins assert result.cors_options.max_age_in_seconds == cors_options.max_age_in_seconds @@ -194,7 +194,7 @@ def test_create_or_update_index(self, api_key, endpoint, index_name, **kwargs): fields=fields, scoring_profiles=scoring_profiles, cors_options=cors_options) - result = client.create_or_update_index(index_name=index.name, index=index) + result = client.create_or_update_index(index=index) assert result.scoring_profiles[0].name == scoring_profile.name assert result.cors_options.allowed_origins == cors_options.allowed_origins assert result.cors_options.max_age_in_seconds == cors_options.max_age_in_seconds @@ -232,11 +232,11 @@ def test_create_or_update_indexes_if_unchanged(self, api_key, endpoint, index_na etag = result.e_tag # get e tag and update index.scoring_profiles = [] - client.create_or_update_index(index.name, index) + client.create_or_update_index(index) index.e_tag = etag with pytest.raises(HttpResponseError): - client.create_or_update_index(index.name, index, match_condition=MatchConditions.IfNotModified) + client.create_or_update_index(index, match_condition=MatchConditions.IfNotModified) @SearchResourceGroupPreparer(random_name_enabled=True) @SearchServicePreparer(schema=SCHEMA, index_batch=BATCH) @@ -251,10 +251,12 @@ class SearchSynonymMapsClientTest(AzureMgmtTestCase): @SearchServicePreparer(schema=SCHEMA, index_batch=BATCH) def test_create_synonym_map(self, api_key, endpoint, index_name, **kwargs): client = SearchIndexClient(endpoint, AzureKeyCredential(api_key)) - result = client.create_synonym_map("test-syn-map", [ + solr_format_synonyms = "\n".join([ "USA, United States, United States of America", "Washington, Wash. => WA", ]) + synonym_map = SynonymMap(name="test-syn-map", synonyms=solr_format_synonyms) + result = client.create_synonym_map(synonym_map) assert isinstance(result, SynonymMap) assert result.name == "test-syn-map" assert result.synonyms == [ @@ -267,10 +269,12 @@ def test_create_synonym_map(self, api_key, endpoint, index_name, **kwargs): @SearchServicePreparer(schema=SCHEMA, index_batch=BATCH) def test_delete_synonym_map(self, api_key, endpoint, index_name, **kwargs): client = SearchIndexClient(endpoint, AzureKeyCredential(api_key)) - result = client.create_synonym_map("test-syn-map", [ + solr_format_synonyms = "\n".join([ "USA, United States, United States of America", "Washington, Wash. => WA", ]) + synonym_map = SynonymMap(name="test-syn-map", synonyms=solr_format_synonyms) + result = client.create_synonym_map(synonym_map) assert len(client.get_synonym_maps()) == 1 client.delete_synonym_map("test-syn-map") assert len(client.get_synonym_maps()) == 0 @@ -279,15 +283,18 @@ def test_delete_synonym_map(self, api_key, endpoint, index_name, **kwargs): @SearchServicePreparer(schema=SCHEMA, index_batch=BATCH) def test_delete_synonym_map_if_unchanged(self, api_key, endpoint, index_name, **kwargs): client = SearchIndexClient(endpoint, AzureKeyCredential(api_key)) - result = client.create_synonym_map("test-syn-map", [ + solr_format_synonyms = "\n".join([ "USA, United States, United States of America", "Washington, Wash. => WA", ]) + synonym_map = SynonymMap(name="test-syn-map", synonyms=solr_format_synonyms) + result = client.create_synonym_map(synonym_map) etag = result.e_tag - client.create_or_update_synonym_map("test-syn-map", [ + synonym_map.synonyms = "\n".join([ "Washington, Wash. => WA", ]) + client.create_or_update_synonym_map(synonym_map) result.e_tag = etag with pytest.raises(HttpResponseError): @@ -298,10 +305,12 @@ def test_delete_synonym_map_if_unchanged(self, api_key, endpoint, index_name, ** @SearchServicePreparer(schema=SCHEMA, index_batch=BATCH) def test_get_synonym_map(self, api_key, endpoint, index_name, **kwargs): client = SearchIndexClient(endpoint, AzureKeyCredential(api_key)) - client.create_synonym_map("test-syn-map", [ + solr_format_synonyms = "\n".join([ "USA, United States, United States of America", "Washington, Wash. => WA", ]) + synonym_map = SynonymMap(name="test-syn-map", synonyms=solr_format_synonyms) + client.create_synonym_map(synonym_map) assert len(client.get_synonym_maps()) == 1 result = client.get_synonym_map("test-syn-map") assert isinstance(result, SynonymMap) @@ -315,12 +324,16 @@ def test_get_synonym_map(self, api_key, endpoint, index_name, **kwargs): @SearchServicePreparer(schema=SCHEMA, index_batch=BATCH) def test_get_synonym_maps(self, api_key, endpoint, index_name, **kwargs): client = SearchIndexClient(endpoint, AzureKeyCredential(api_key)) - client.create_synonym_map("test-syn-map-1", [ + solr_format_synonyms = "\n".join([ "USA, United States, United States of America", ]) - client.create_synonym_map("test-syn-map-2", [ + synonym_map_1 = SynonymMap(name="test-syn-map-1", synonyms=solr_format_synonyms) + client.create_synonym_map(synonym_map_1) + solr_format_synonyms = "\n".join([ "Washington, Wash. => WA", ]) + synonym_map_2 = SynonymMap(name="test-syn-map-2", synonyms=solr_format_synonyms) + client.create_synonym_map(synonym_map_2) result = client.get_synonym_maps() assert isinstance(result, list) assert all(isinstance(x, SynonymMap) for x in result) @@ -330,13 +343,17 @@ def test_get_synonym_maps(self, api_key, endpoint, index_name, **kwargs): @SearchServicePreparer(schema=SCHEMA, index_batch=BATCH) def test_create_or_update_synonym_map(self, api_key, endpoint, index_name, **kwargs): client = SearchIndexClient(endpoint, AzureKeyCredential(api_key)) - client.create_synonym_map("test-syn-map", [ + solr_format_synonyms = "\n".join([ "USA, United States, United States of America", + "Washington, Wash. => WA", ]) + synonym_map = SynonymMap(name="test-syn-map", synonyms=solr_format_synonyms) + client.create_synonym_map(synonym_map) assert len(client.get_synonym_maps()) == 1 - client.create_or_update_synonym_map("test-syn-map", [ + synonym_map.synonyms = "\n".join([ "Washington, Wash. => WA", ]) + client.create_or_update_synonym_map(synonym_map) assert len(client.get_synonym_maps()) == 1 result = client.get_synonym_map("test-syn-map") assert isinstance(result, SynonymMap) @@ -349,15 +366,20 @@ def test_create_or_update_synonym_map(self, api_key, endpoint, index_name, **kwa @SearchServicePreparer(schema=SCHEMA, index_batch=BATCH) def test_create_or_update_synonym_map_if_unchanged(self, api_key, endpoint, index_name, **kwargs): client = SearchIndexClient(endpoint, AzureKeyCredential(api_key)) - result = client.create_synonym_map("test-syn-map", [ + solr_format_synonyms = "\n".join([ "USA, United States, United States of America", + "Washington, Wash. => WA", ]) + synonym_map = SynonymMap(name="test-syn-map", synonyms=solr_format_synonyms) + result = client.create_synonym_map(synonym_map) etag = result.e_tag - client.create_or_update_synonym_map("test-syn-map", [ + synonym_map.synonyms = "\n".join([ "Washington, Wash. => WA", ]) + client.create_or_update_synonym_map(synonym_map) + result.e_tag = etag with pytest.raises(HttpResponseError): client.create_or_update_synonym_map(result, match_condition=MatchConditions.IfNotModified) @@ -373,7 +395,9 @@ def test_create_skillset(self, api_key, endpoint, index_name, **kwargs): s = EntityRecognitionSkill(inputs=[InputFieldMappingEntry(name="text", source="/document/content")], outputs=[OutputFieldMappingEntry(name="organizations", target_name="organizations")]) - result = client.create_skillset(name='test-ss', skills=[s], description="desc") + skillset = SearchIndexerSkillset(name='test-ss', skills=list([s]), description="desc") + + result = client.create_skillset(skillset) assert isinstance(result, SearchIndexerSkillset) assert result.name == "test-ss" assert result.description == "desc" @@ -390,7 +414,9 @@ def test_delete_skillset(self, api_key, endpoint, index_name, **kwargs): s = EntityRecognitionSkill(inputs=[InputFieldMappingEntry(name="text", source="/document/content")], outputs=[OutputFieldMappingEntry(name="organizations", target_name="organizations")]) - result = client.create_skillset(name='test-ss', skills=[s], description="desc") + skillset = SearchIndexerSkillset(name='test-ss', skills=list([s]), description="desc") + + result = client.create_skillset(skillset) assert len(client.get_skillsets()) == 1 client.delete_skillset("test-ss") @@ -403,10 +429,13 @@ def test_delete_skillset_if_unchanged(self, api_key, endpoint, index_name, **kwa s = EntityRecognitionSkill(inputs=[InputFieldMappingEntry(name="text", source="/document/content")], outputs=[OutputFieldMappingEntry(name="organizations", target_name="organizations")]) - result = client.create_skillset(name='test-ss', skills=[s], description="desc") + skillset = SearchIndexerSkillset(name='test-ss', skills=list([s]), description="desc") + + result = client.create_skillset(skillset) etag = result.e_tag - updated = client.create_or_update_skillset(name='test-ss', skills=[s], description="updated") + skillset = SearchIndexerSkillset(name='test-ss', skills=list([s]), description="updated") + updated = client.create_or_update_skillset(skillset) updated.e_tag = etag with pytest.raises(HttpResponseError): @@ -419,7 +448,8 @@ def test_get_skillset(self, api_key, endpoint, index_name, **kwargs): s = EntityRecognitionSkill(inputs=[InputFieldMappingEntry(name="text", source="/document/content")], outputs=[OutputFieldMappingEntry(name="organizations", target_name="organizations")]) - client.create_skillset(name='test-ss', skills=[s], description="desc") + skillset = SearchIndexerSkillset(name='test-ss', skills=list([s]), description="desc") + client.create_skillset(skillset) assert len(client.get_skillsets()) == 1 result = client.get_skillset("test-ss") @@ -437,8 +467,10 @@ def test_get_skillsets(self, api_key, endpoint, index_name, **kwargs): s = EntityRecognitionSkill(inputs=[InputFieldMappingEntry(name="text", source="/document/content")], outputs=[OutputFieldMappingEntry(name="organizations", target_name="organizations")]) - client.create_skillset(name='test-ss-1', skills=[s], description="desc1") - client.create_skillset(name='test-ss-2', skills=[s], description="desc2") + skillset1 = SearchIndexerSkillset(name='test-ss-1', skills=list([s]), description="desc1") + client.create_skillset(skillset1) + skillset2 = SearchIndexerSkillset(name='test-ss-2', skills=list([s]), description="desc2") + client.create_skillset(skillset2) result = client.get_skillsets() assert isinstance(result, list) assert all(isinstance(x, SearchIndexerSkillset) for x in result) @@ -451,8 +483,10 @@ def test_create_or_update_skillset(self, api_key, endpoint, index_name, **kwargs s = EntityRecognitionSkill(inputs=[InputFieldMappingEntry(name="text", source="/document/content")], outputs=[OutputFieldMappingEntry(name="organizations", target_name="organizations")]) - client.create_or_update_skillset(name='test-ss', skills=[s], description="desc1") - client.create_or_update_skillset(name='test-ss', skills=[s], description="desc2") + skillset1 = SearchIndexerSkillset(name='test-ss', skills=list([s]), description="desc1") + client.create_or_update_skillset(skillset1) + skillset2 = SearchIndexerSkillset(name='test-ss', skills=list([s]), description="desc2") + client.create_or_update_skillset(skillset2) assert len(client.get_skillsets()) == 1 result = client.get_skillset("test-ss") @@ -467,8 +501,10 @@ def test_create_or_update_skillset_inplace(self, api_key, endpoint, index_name, s = EntityRecognitionSkill(inputs=[InputFieldMappingEntry(name="text", source="/document/content")], outputs=[OutputFieldMappingEntry(name="organizations", target_name="organizations")]) - ss = client.create_or_update_skillset(name='test-ss', skills=[s], description="desc1") - client.create_or_update_skillset(name='test-ss', skills=[s], description="desc2", skillset=ss) + skillset1 = SearchIndexerSkillset(name='test-ss', skills=list([s]), description="desc1") + ss = client.create_or_update_skillset(skillset1) + skillset2 = SearchIndexerSkillset(name='test-ss', skills=[s], description="desc2", skillset=ss) + client.create_or_update_skillset(skillset2) assert len(client.get_skillsets()) == 1 result = client.get_skillset("test-ss") @@ -483,16 +519,13 @@ def test_create_or_update_skillset_if_unchanged(self, api_key, endpoint, index_n s = EntityRecognitionSkill(inputs=[InputFieldMappingEntry(name="text", source="/document/content")], outputs=[OutputFieldMappingEntry(name="organizations", target_name="organizations")]) - ss = client.create_or_update_skillset(name='test-ss', skills=[s], description="desc1") + skillset1 = SearchIndexerSkillset(name='test-ss', skills=list([s]), description="desc1") + ss = client.create_or_update_skillset(skillset1) etag = ss.e_tag - - client.create_or_update_skillset(name='test-ss', skills=[s], description="desc2", skillset=ss) + skillset2 = SearchIndexerSkillset(name='test-ss', skills=[s], description="desc2", skillset=ss) + client.create_or_update_skillset(skillset2) assert len(client.get_skillsets()) == 1 - ss.e_tag = etag - with pytest.raises(HttpResponseError): - client.create_or_update_skillset(name='test-ss', skills=[s], skillset=ss, match_condition=MatchConditions.IfNotModified) - class SearchDataSourcesClientTest(AzureMgmtTestCase): def _create_data_source_connection(self, name="sample-datasource"): From 2a730c7891d05f5b2dc9d6b4bc999582f34dab8f Mon Sep 17 00:00:00 2001 From: Scott Beddall <45376673+scbedd@users.noreply.github.com> Date: Thu, 4 Jun 2020 14:43:52 -0700 Subject: [PATCH 18/25] update targeted pat (#11826) --- eng/pipelines/templates/jobs/update_pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/templates/jobs/update_pr.yml b/eng/pipelines/templates/jobs/update_pr.yml index 36d19954a93b..0301ea403f30 100644 --- a/eng/pipelines/templates/jobs/update_pr.yml +++ b/eng/pipelines/templates/jobs/update_pr.yml @@ -26,4 +26,4 @@ steps: - script: python3 -m packaging_tools.update_pr -v --pr-number $(System.PullRequest.PullRequestNumber) --repo $(Build.Repository.Name) displayName: 'Update packaging of PR' env: - GH_TOKEN: $(python-mgmt-update-pr-token) + GH_TOKEN: $(azuresdk-github-pat) From 6345cb8539e34906d1df9c515456808da59a5c39 Mon Sep 17 00:00:00 2001 From: Laurent Mazuel Date: Thu, 4 Jun 2020 15:49:32 -0700 Subject: [PATCH 19/25] Update ChangeLog of customvision (#11827) --- .../azure-cognitiveservices-vision-customvision/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sdk/cognitiveservices/azure-cognitiveservices-vision-customvision/CHANGELOG.md b/sdk/cognitiveservices/azure-cognitiveservices-vision-customvision/CHANGELOG.md index a45793eec633..bb340557b7f5 100644 --- a/sdk/cognitiveservices/azure-cognitiveservices-vision-customvision/CHANGELOG.md +++ b/sdk/cognitiveservices/azure-cognitiveservices-vision-customvision/CHANGELOG.md @@ -19,6 +19,10 @@ - Added operation CustomVisionPredictionClientOperationsMixin.detect_image - Added operation group CustomVisionTrainingClientOperationsMixin +**Breaking changes** + +- Credentials are now longer a simple string, but a `msrest.authentication.ApiKeyCredentials` instance instead + **General Breaking changes** This version uses a next-generation code generator that *might* From d7c0972f7e2a82adf460f0861bea14d8ee7b0145 Mon Sep 17 00:00:00 2001 From: Pierre Grimaud Date: Fri, 5 Jun 2020 01:07:19 +0200 Subject: [PATCH 20/25] docs: fix typos (#11742) --- common/smoketest/README.md | 2 +- doc/dev/mgmt/generating-integration-test.md | 2 +- doc/dev/mgmt/generation.md | 2 +- doc/dev/mgmt/multiapi.md | 4 ++-- doc/dev/mgmt/swagger_conf.md | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/common/smoketest/README.md b/common/smoketest/README.md index ae3dd469ed2e..d0adcac4171e 100644 --- a/common/smoketest/README.md +++ b/common/smoketest/README.md @@ -74,7 +74,7 @@ pip install -r requiriments.txt pip install -r requiriments_async.txt ``` -If a python version below 3.5 is being used, it is still possible to run the samples. When it gets to the async tests a message `'Async not suported'` will be displayed. +If a python version below 3.5 is being used, it is still possible to run the samples. When it gets to the async tests a message `'Async not supported'` will be displayed. ## Key concepts diff --git a/doc/dev/mgmt/generating-integration-test.md b/doc/dev/mgmt/generating-integration-test.md index 8d4841fa9cfc..98de9892d535 100644 --- a/doc/dev/mgmt/generating-integration-test.md +++ b/doc/dev/mgmt/generating-integration-test.md @@ -127,7 +127,7 @@ now you can run live integration test: ## Fixing Test -It's obvious that when running test for the first time someting is not going to work. +It's obvious that when running test for the first time something is not going to work. The best approach is to: - fix the test manually diff --git a/doc/dev/mgmt/generation.md b/doc/dev/mgmt/generation.md index a94bba3639b1..f5fec80c2d02 100644 --- a/doc/dev/mgmt/generation.md +++ b/doc/dev/mgmt/generation.md @@ -8,7 +8,7 @@ IMPORTANT NOTE: All the commands prefixed by `python` in this page assumes you h ### Autorest versioning -A few notes on [Autorest for Python versionning](https://github.com/Azure/autorest.python/blob/master/ChangeLog.md): +A few notes on [Autorest for Python versioning](https://github.com/Azure/autorest.python/blob/master/ChangeLog.md): - Autorest for Python v2.x is deprecated, and should not be used anymore for any generation under any circumstances. - Autorest for Python v3.x is the most currently used one. Should not be used, but still ok if service team are still in v3.x and they want to avoid breaking changes for a given version (rare). - Autorest for Python v4.x is the current recommendation. This generator can generates async code, but this should be disabled with --no-async. No package should be shipped with async based on v4 diff --git a/doc/dev/mgmt/multiapi.md b/doc/dev/mgmt/multiapi.md index 4792c9a28baa..dfe608047703 100644 --- a/doc/dev/mgmt/multiapi.md +++ b/doc/dev/mgmt/multiapi.md @@ -14,7 +14,7 @@ Because there is different flavors of Azure that are not necessarly provided wit ### Why a multi-api package? -Indeed, a simple solution would be to write down explictly what version of SDK supports what API version. Example: 1.0 supports 2015-06-01, 2.0 supports 2017-07-01, etc. The story for customers then would be to pin the specific SDK version for the specific API version they need. However, this was considered unacceptable in an end-to-end scenario: +Indeed, a simple solution would be to write down explicitly what version of SDK supports what API version. Example: 1.0 supports 2015-06-01, 2.0 supports 2017-07-01, etc. The story for customers then would be to pin the specific SDK version for the specific API version they need. However, this was considered unacceptable in an end-to-end scenario: - It means you cannot install in the same Python environment packages that would target different cloud (Python doesn't allow installation of different versions of the same package together). Azure CLI or Ansible supports for different clouds would then be extremely complicated. - This forces customers to use old SDK, that might have been fixed on different axis than API version (security fixes, new SDK features like async, etc.) - Customers rarely needs only one package, but a set of them (storage, compute, network, etc.) and having to keep track of the correct list of packages is challenging. @@ -44,7 +44,7 @@ Network interfaces operations are defines in a [network interface file](https:// **Python multi-api packaging is based on the assumptions that it's true.** If it's not, it's usually ok but requires a little more subtle packaging (see final section here) -Being that a given Swagger defines only *one* fixed API version, doing multi-api version in one package implies shipping several Swagger files into one package. This is achived by the `batch` directive of Autorest. More details on how to write Readme for Swagger in the specific page for it [swagger_conf.md](./swagger_conf.md). +Being that a given Swagger defines only *one* fixed API version, doing multi-api version in one package implies shipping several Swagger files into one package. This is archived by the `batch` directive of Autorest. More details on how to write Readme for Swagger in the specific page for it [swagger_conf.md](./swagger_conf.md). Python SDK team is responsible to design the correct set of tags to set for the `batch` node. Each line of the batch directive should contains only *one* api version to match the folder name used. this might require adding new tags in the readme.md that are specific to only one API version. These tags are usually suffixed by "-only" ([example with compute](https://github.com/Azure/azure-rest-api-specs/tree/master/specification/compute/resource-manager#tag-package-2019-03-01-only)) diff --git a/doc/dev/mgmt/swagger_conf.md b/doc/dev/mgmt/swagger_conf.md index 820ce6c11adf..198e4e7c0965 100644 --- a/doc/dev/mgmt/swagger_conf.md +++ b/doc/dev/mgmt/swagger_conf.md @@ -14,7 +14,7 @@ In practical terms, we want to control the version of Autorest used, the output ## Writing the readme -Writing the readme is the responsability of the Python SDK team. There is currently two types of templates for Python readmes: +Writing the readme is the responsibility of the Python SDK team. There is currently two types of templates for Python readmes: - Readme that handles only one API version, and generates packages that handle one API version only - Readme that handles several API versions, and generates packages with multiples API and profile supports From da470e075b0753030bc261cf9572923f6293f0ff Mon Sep 17 00:00:00 2001 From: Adam Dobrawy Date: Fri, 5 Jun 2020 01:10:58 +0200 Subject: [PATCH 21/25] Add missing dependency for azure-common (#11407) * Add missing dependency for azure-common * Import on scope to reduce dependencies --- sdk/core/azure-common/azure/common/client_factory.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/core/azure-common/azure/common/client_factory.py b/sdk/core/azure-common/azure/common/client_factory.py index 432ef187e515..5819dbb15d65 100644 --- a/sdk/core/azure-common/azure/common/client_factory.py +++ b/sdk/core/azure-common/azure/common/client_factory.py @@ -14,9 +14,6 @@ except ImportError: from inspect import getargspec as get_arg_spec -import adal -from msrestazure.azure_active_directory import AdalAuthentication - from .credentials import get_azure_cli_credentials from .cloud import get_cli_active_cloud @@ -153,6 +150,9 @@ def get_client_from_json_dict(client_class, config_dict, **kwargs): :param dict config_dict: A config dict. :return: An instantiated client """ + import adal + from msrestazure.azure_active_directory import AdalAuthentication + is_graphrbac = client_class.__name__ == 'GraphRbacManagementClient' is_keyvault = client_class.__name__ == 'KeyVaultClient' parameters = { From bce84db7837879cd093abc36c9df1f2e3e3f60b1 Mon Sep 17 00:00:00 2001 From: iscai-msft <43154838+iscai-msft@users.noreply.github.com> Date: Thu, 4 Jun 2020 19:11:55 -0400 Subject: [PATCH 22/25] fix typing and docs for initial_response parameter of LROPoller (#11717) * fix typing and docs for initial_response parameter of LROPoller * removed unnecessary import --- sdk/core/azure-core/azure/core/polling/_async_poller.py | 5 ++--- sdk/core/azure-core/azure/core/polling/_poller.py | 6 ++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/sdk/core/azure-core/azure/core/polling/_async_poller.py b/sdk/core/azure-core/azure/core/polling/_async_poller.py index cb51a3b2289a..935dc455987e 100644 --- a/sdk/core/azure-core/azure/core/polling/_async_poller.py +++ b/sdk/core/azure-core/azure/core/polling/_async_poller.py @@ -84,7 +84,7 @@ async def async_poller(client, initial_response, deserialization_callback, polli :param client: A pipeline service client. :type client: ~azure.core.PipelineClient :param initial_response: The initial call response - :type initial_response: ~azure.core.pipeline.transport.AsyncHttpResponse + :type initial_response: ~azure.core.pipeline.PipelineResponse :param deserialization_callback: A callback that takes a Response and return a deserialized object. If a subclass of Model is given, this passes "deserialize" as callback. :type deserialization_callback: callable or msrest.serialization.Model @@ -101,8 +101,7 @@ class AsyncLROPoller(Generic[PollingReturnType], Awaitable): :param client: A pipeline service client :type client: ~azure.core.PipelineClient :param initial_response: The initial call response - :type initial_response: - ~azure.core.pipeline.transport.HttpResponse or ~azure.core.pipeline.transport.AsyncHttpResponse + :type initial_response: ~azure.core.pipeline.PipelineResponse :param deserialization_callback: A callback that takes a Response and return a deserialized object. If a subclass of Model is given, this passes "deserialize" as callback. :type deserialization_callback: callable or msrest.serialization.Model diff --git a/sdk/core/azure-core/azure/core/polling/_poller.py b/sdk/core/azure-core/azure/core/polling/_poller.py index 4dff2ab220f6..a9f670504859 100644 --- a/sdk/core/azure-core/azure/core/polling/_poller.py +++ b/sdk/core/azure-core/azure/core/polling/_poller.py @@ -32,7 +32,6 @@ from urllib.parse import urlparse from typing import Any, Callable, Union, List, Optional, Tuple, TypeVar, Generic -from azure.core.pipeline.transport._base import HttpResponse from azure.core.tracing.decorator import distributed_trace from azure.core.tracing.common import with_current_context @@ -140,8 +139,7 @@ class LROPoller(Generic[PollingReturnType]): :param client: A pipeline service client :type client: ~azure.core.PipelineClient :param initial_response: The initial call response - :type initial_response: - ~azure.core.pipeline.transport.HttpResponse or ~azure.core.pipeline.transport.AsyncHttpResponse + :type initial_response: ~azure.core.pipeline.PipelineResponse :param deserialization_callback: A callback that takes a Response and return a deserialized object. If a subclass of Model is given, this passes "deserialize" as callback. :type deserialization_callback: callable or msrest.serialization.Model @@ -150,7 +148,7 @@ class LROPoller(Generic[PollingReturnType]): """ def __init__(self, client, initial_response, deserialization_callback, polling_method): - # type: (Any, HttpResponse, Callable, PollingMethod[PollingReturnType]) -> None + # type: (Any, Any, Callable, PollingMethod[PollingReturnType]) -> None self._callbacks = [] # type: List[Callable] self._polling_method = polling_method From 717c419fb47efe94770bdd4fc14441aac52b2342 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Thu, 4 Jun 2020 17:16:01 -0700 Subject: [PATCH 23/25] AzureCliCredential is unavailable when no account is logged in (#11829) --- sdk/identity/azure-identity/CHANGELOG.md | 3 ++ .../azure/identity/_credentials/azure_cli.py | 3 ++ .../identity/aio/_credentials/azure_cli.py | 4 +++ .../tests/test_cli_credential.py | 13 +++++++-- .../tests/test_cli_credential_async.py | 28 +++++++++---------- 5 files changed, 35 insertions(+), 16 deletions(-) diff --git a/sdk/identity/azure-identity/CHANGELOG.md b/sdk/identity/azure-identity/CHANGELOG.md index 781fe4b105c3..d753337d91cd 100644 --- a/sdk/identity/azure-identity/CHANGELOG.md +++ b/sdk/identity/azure-identity/CHANGELOG.md @@ -1,6 +1,9 @@ # Release History ## 1.4.0b4 (Unreleased) +- `AzureCliCredential` raises `CredentialUnavailableError` when no user is + logged in to the Azure CLI. + ([#11819](https://github.com/Azure/azure-sdk-for-python/issues/11819)) - `AzureCliCredential` and `VSCodeCredential`, which enable authenticating as the identity signed in to the Azure CLI and Visual Studio Code, respectively, can be imported from `azure.identity` and `azure.identity.aio`. diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py b/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py index e18dd43ca3a6..550e36fc1754 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/azure_cli.py @@ -24,6 +24,7 @@ CLI_NOT_FOUND = "Azure CLI not found on path" COMMAND_LINE = "az account get-access-token --output json --resource {}" +NOT_LOGGED_IN = "Please run 'az login' to set up an account" # CLI's "expiresOn" is naive, so we use this naive datetime for the epoch to calculate expires_on in UTC EPOCH = datetime.fromtimestamp(0) @@ -116,6 +117,8 @@ def _run_command(command): # non-zero return from shell if ex.returncode == 127 or ex.output.startswith("'az' is not recognized"): error = CredentialUnavailableError(message=CLI_NOT_FOUND) + elif "az login" in ex.output or "az account set" in ex.output: + error = CredentialUnavailableError(message=NOT_LOGGED_IN) else: # return code is from the CLI -> propagate its output if ex.output: diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py index 99ca177450e5..c049b1421cde 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/azure_cli.py @@ -13,6 +13,7 @@ CLI_NOT_FOUND, COMMAND_LINE, get_safe_working_dir, + NOT_LOGGED_IN, parse_token, sanitize_output, ) @@ -83,5 +84,8 @@ async def _run_command(command): if proc.returncode == 127 or output.startswith("'az' is not recognized"): raise CredentialUnavailableError(CLI_NOT_FOUND) + if "az login" in output or "az account set" in output: + raise CredentialUnavailableError(message=NOT_LOGGED_IN) + message = sanitize_output(output) if output else "Failed to invoke Azure CLI" raise ClientAuthenticationError(message=message) diff --git a/sdk/identity/azure-identity/tests/test_cli_credential.py b/sdk/identity/azure-identity/tests/test_cli_credential.py index 7377d330455e..3467a451356a 100644 --- a/sdk/identity/azure-identity/tests/test_cli_credential.py +++ b/sdk/identity/azure-identity/tests/test_cli_credential.py @@ -6,7 +6,7 @@ import json from azure.identity import AzureCliCredential, CredentialUnavailableError -from azure.identity._credentials.azure_cli import CLI_NOT_FOUND +from azure.identity._credentials.azure_cli import CLI_NOT_FOUND, NOT_LOGGED_IN from azure.core.exceptions import ClientAuthenticationError import subprocess @@ -98,10 +98,19 @@ def test_cannot_execute_shell(): def test_not_logged_in(): - """When the CLI isn't logged in, the credential should raise an error containing the CLI's output""" + """When the CLI isn't logged in, the credential should raise CredentialUnavailableError""" output = "ERROR: Please run 'az login' to setup account." with mock.patch(CHECK_OUTPUT, raise_called_process_error(1, output)): + with pytest.raises(CredentialUnavailableError, match=NOT_LOGGED_IN): + AzureCliCredential().get_token("scope") + + +def test_unexpected_error(): + """When the CLI returns an unexpected error, the credential should raise an error containing the CLI's output""" + + output = "something went wrong" + with mock.patch(CHECK_OUTPUT, raise_called_process_error(42, output)): with pytest.raises(ClientAuthenticationError, match=output): AzureCliCredential().get_token("scope") diff --git a/sdk/identity/azure-identity/tests/test_cli_credential_async.py b/sdk/identity/azure-identity/tests/test_cli_credential_async.py index 9e8ad1f82217..ae9dec90a341 100644 --- a/sdk/identity/azure-identity/tests/test_cli_credential_async.py +++ b/sdk/identity/azure-identity/tests/test_cli_credential_async.py @@ -9,7 +9,7 @@ from azure.identity import CredentialUnavailableError from azure.identity.aio import AzureCliCredential -from azure.identity._credentials.azure_cli import CLI_NOT_FOUND +from azure.identity._credentials.azure_cli import CLI_NOT_FOUND, NOT_LOGGED_IN from azure.core.exceptions import ClientAuthenticationError import pytest @@ -18,6 +18,8 @@ SUBPROCESS_EXEC = AzureCliCredential.__module__ + ".asyncio.create_subprocess_exec" +pytestmark = pytest.mark.asyncio + def mock_exec(stdout, stderr="", return_code=0): async def communicate(): @@ -27,7 +29,6 @@ async def communicate(): return mock.Mock(return_value=get_completed_future(process)) -@pytest.mark.asyncio async def test_no_scopes(): """The credential should raise ValueError when get_token is called with no scopes""" @@ -35,7 +36,6 @@ async def test_no_scopes(): await AzureCliCredential().get_token() -@pytest.mark.asyncio async def test_multiple_scopes(): """The credential should raise ValueError when get_token is called with more than one scope""" @@ -43,14 +43,12 @@ async def test_multiple_scopes(): await AzureCliCredential().get_token("one scope", "and another") -@pytest.mark.asyncio async def test_close(): """The credential must define close, although it's a no-op because the credential has no transport""" await AzureCliCredential().close() -@pytest.mark.asyncio async def test_context_manager(): """The credential must be a context manager, although it does nothing as one because it has no transport""" @@ -59,7 +57,6 @@ async def test_context_manager(): @pytest.mark.skipif(not sys.platform.startswith("win"), reason="tests Windows-specific behavior") -@pytest.mark.asyncio async def test_windows_fallback(): """The credential should fall back to the sync implementation when not using ProactorEventLoop on Windows""" @@ -74,7 +71,6 @@ async def test_windows_fallback(): assert sync_get_token.call_count == 1 -@pytest.mark.asyncio async def test_get_token(): """The credential should parse the CLI's output to an AccessToken""" @@ -100,7 +96,6 @@ async def test_get_token(): assert token.expires_on == valid_seconds -@pytest.mark.asyncio async def test_cli_not_installed_linux(): """The credential should raise CredentialUnavailableError when the CLI isn't installed""" @@ -111,7 +106,6 @@ async def test_cli_not_installed_linux(): await credential.get_token("scope") -@pytest.mark.asyncio async def test_cli_not_installed_windows(): """The credential should raise CredentialUnavailableError when the CLI isn't installed""" @@ -122,7 +116,6 @@ async def test_cli_not_installed_windows(): await credential.get_token("scope") -@pytest.mark.asyncio async def test_cannot_execute_shell(): """The credential should raise CredentialUnavailableError when the subprocess doesn't start""" @@ -132,19 +125,27 @@ async def test_cannot_execute_shell(): await credential.get_token("scope") -@pytest.mark.asyncio async def test_not_logged_in(): - """When the CLI isn't logged in, the credential should raise an error containing the CLI's output""" + """When the CLI isn't logged in, the credential should raise CredentialUnavailableError""" output = "ERROR: Please run 'az login' to setup account." with mock.patch(SUBPROCESS_EXEC, mock_exec(output, return_code=1)): + with pytest.raises(CredentialUnavailableError, match=NOT_LOGGED_IN): + credential = AzureCliCredential() + await credential.get_token("scope") + + +async def test_unexpected_error(): + """When the CLI returns an unexpected error, the credential should raise an error containing the CLI's output""" + + output = "something went wrong" + with mock.patch(SUBPROCESS_EXEC, mock_exec(output, return_code=42)): with pytest.raises(ClientAuthenticationError, match=output): credential = AzureCliCredential() await credential.get_token("scope") @pytest.mark.parametrize("output", TEST_ERROR_OUTPUTS) -@pytest.mark.asyncio async def test_parsing_error_does_not_expose_token(output): """Errors during CLI output parsing shouldn't expose access tokens in that output""" @@ -158,7 +159,6 @@ async def test_parsing_error_does_not_expose_token(output): @pytest.mark.parametrize("output", TEST_ERROR_OUTPUTS) -@pytest.mark.asyncio async def test_subprocess_error_does_not_expose_token(output): """Errors from the subprocess shouldn't expose access tokens in CLI output""" From 4af2070919c3a1d387de229e02ea1074fed0828c Mon Sep 17 00:00:00 2001 From: Mitch Denny Date: Fri, 5 Jun 2020 18:51:04 +1000 Subject: [PATCH 24/25] Fix CI config for appservice directory. (#11842) --- sdk/appservice/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/appservice/ci.yml b/sdk/appservice/ci.yml index b1ad32578688..207b66d86b97 100644 --- a/sdk/appservice/ci.yml +++ b/sdk/appservice/ci.yml @@ -20,7 +20,7 @@ trigger: - restapi* paths: include: - - sdk/web/ + - sdk/appservice/ pr: branches: @@ -32,7 +32,7 @@ pr: - restapi* paths: include: - - sdk/web/ + - sdk/appservice/ stages: From bddb342e3a90f52cce391f3981887f2a6911ef6c Mon Sep 17 00:00:00 2001 From: Mitch Denny Date: Wed, 24 Jun 2020 22:11:58 +1000 Subject: [PATCH 25/25] Freeze virtualenv. --- eng/ci_tools.txt | 1 + eng/pipelines/templates/steps/build-test.yml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/eng/ci_tools.txt b/eng/ci_tools.txt index 92d6682453e1..3315fe8a548c 100644 --- a/eng/ci_tools.txt +++ b/eng/ci_tools.txt @@ -1,6 +1,7 @@ # requirements leveraged by ci tools setuptools==44.1.0; python_version == '2.7' setuptools==45.1.0; python_version >= '3.5' +virtualenv==20.0.23 wheel==0.34.2 Jinja2==2.11.1 packaging==20.4 diff --git a/eng/pipelines/templates/steps/build-test.yml b/eng/pipelines/templates/steps/build-test.yml index 3cb09cfb3c8e..3523d73d8ba1 100644 --- a/eng/pipelines/templates/steps/build-test.yml +++ b/eng/pipelines/templates/steps/build-test.yml @@ -28,7 +28,7 @@ steps: OSName: ${{ parameters.OSName }} - script: | - python -m pip install pip == 20.1 + python -m pip install pip==20.1 pip install -r eng/ci_tools.txt pip --version displayName: 'Prep Environment' @@ -50,6 +50,7 @@ steps: ${{ parameters.ToxEnvParallel }} env: ${{ parameters.EnvVars }} + - ${{ parameters.AfterTestSteps }} - task: PublishTestResults@2