From baa136fd4fa94cfb6638c3074f10033dcc4f9da1 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Tue, 8 Aug 2023 19:16:40 -0400 Subject: [PATCH] fix: preserve new lines (#1721) --- gapic/utils/lines.py | 10 ++- .../services/asset_service/async_client.py | 3 + .../asset_v1/services/asset_service/client.py | 3 + .../google/cloud/eventarc_v1/types/trigger.py | 2 + .../config_service_v2/async_client.py | 2 + .../services/config_service_v2/client.py | 2 + .../logging_service_v2/async_client.py | 1 + .../services/logging_service_v2/client.py | 1 + .../metrics_service_v2/async_client.py | 4 ++ .../services/metrics_service_v2/client.py | 4 ++ .../metrics_service_v2/transports/rest.py | 3 + .../cloud/logging_v2/types/log_entry.py | 1 + .../cloud/logging_v2/types/logging_metrics.py | 1 + .../services/cloud_redis/async_client.py | 1 + .../redis_v1/services/cloud_redis/client.py | 1 + .../services/cloud_redis/transports/grpc.py | 1 + .../cloud_redis/transports/grpc_asyncio.py | 1 + tests/unit/utils/test_lines.py | 69 +++++++++++++++++++ 18 files changed, 108 insertions(+), 2 deletions(-) diff --git a/gapic/utils/lines.py b/gapic/utils/lines.py index 2c5cd4021c..358759b558 100644 --- a/gapic/utils/lines.py +++ b/gapic/utils/lines.py @@ -107,17 +107,23 @@ def wrap(text: str, width: int, *, offset: Optional[int] = None, indent: int = 0 # the sphinx docs build will fail. text = re.sub(r':\n([^\n])', r':\n\n\1', text) - text = text[len(first):].strip() + text = text[len(first):] if not text: return first.strip() + # Strip leading and ending whitespace. + # Preserve new line at the beginning. + new_line = '\n' if text[0] == '\n' else '' + text = new_line + text.strip() + # Tokenize the rest of the text to try to preserve line breaks # that semantically matter. tokens = [] token = '' for line in text.split('\n'): # Ensure that lines that start with a hyphen are always on a new line - if line.strip().startswith('-') and token: + # Ensure that blank lines are preserved + if (line.strip().startswith('-') or not len(line)) and token: tokens.append(token) token = '' token += line + '\n' diff --git a/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/async_client.py b/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/async_client.py index c5106ca73b..9d0193c98c 100755 --- a/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/async_client.py +++ b/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/async_client.py @@ -363,6 +363,7 @@ async def sample_list_assets(): Returns: google.cloud.asset_v1.services.asset_service.pagers.ListAssetsAsyncPager: ListAssets response. + Iterating over this object will yield results and resolve additional pages automatically. @@ -1211,6 +1212,7 @@ async def sample_search_all_resources(): Returns: google.cloud.asset_v1.services.asset_service.pagers.SearchAllResourcesAsyncPager: Search all resources response. + Iterating over this object will yield results and resolve additional pages automatically. @@ -1406,6 +1408,7 @@ async def sample_search_all_iam_policies(): Returns: google.cloud.asset_v1.services.asset_service.pagers.SearchAllIamPoliciesAsyncPager: Search all IAM policies response. + Iterating over this object will yield results and resolve additional pages automatically. diff --git a/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/client.py b/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/client.py index aeccfe63ae..42b9b727b2 100755 --- a/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/client.py +++ b/tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/client.py @@ -567,6 +567,7 @@ def sample_list_assets(): Returns: google.cloud.asset_v1.services.asset_service.pagers.ListAssetsPager: ListAssets response. + Iterating over this object will yield results and resolve additional pages automatically. @@ -1388,6 +1389,7 @@ def sample_search_all_resources(): Returns: google.cloud.asset_v1.services.asset_service.pagers.SearchAllResourcesPager: Search all resources response. + Iterating over this object will yield results and resolve additional pages automatically. @@ -1576,6 +1578,7 @@ def sample_search_all_iam_policies(): Returns: google.cloud.asset_v1.services.asset_service.pagers.SearchAllIamPoliciesPager: Search all IAM policies response. + Iterating over this object will yield results and resolve additional pages automatically. diff --git a/tests/integration/goldens/eventarc/google/cloud/eventarc_v1/types/trigger.py b/tests/integration/goldens/eventarc/google/cloud/eventarc_v1/types/trigger.py index e7f7acdd0b..504afb5fe6 100755 --- a/tests/integration/goldens/eventarc/google/cloud/eventarc_v1/types/trigger.py +++ b/tests/integration/goldens/eventarc/google/cloud/eventarc_v1/types/trigger.py @@ -153,6 +153,7 @@ class EventFilter(proto.Message): Required. The name of a CloudEvents attribute. Currently, only a subset of attributes are supported for filtering. + All triggers MUST provide a filter for the 'type' attribute. value (str): @@ -222,6 +223,7 @@ class CloudRun(proto.Message): Required. The name of the Cloud Run service being addressed. See https://cloud.google.com/run/docs/reference/rest/v1/namespaces.services. + Only services located in the same project of the trigger object can be addressed. path (str): diff --git a/tests/integration/goldens/logging/google/cloud/logging_v2/services/config_service_v2/async_client.py b/tests/integration/goldens/logging/google/cloud/logging_v2/services/config_service_v2/async_client.py index 746d2e4878..e42f507694 100755 --- a/tests/integration/goldens/logging/google/cloud/logging_v2/services/config_service_v2/async_client.py +++ b/tests/integration/goldens/logging/google/cloud/logging_v2/services/config_service_v2/async_client.py @@ -261,6 +261,7 @@ async def sample_list_buckets(): Returns: google.cloud.logging_v2.services.config_service_v2.pagers.ListBucketsAsyncPager: The response from ListBuckets. + Iterating over this object will yield results and resolve additional pages automatically. @@ -762,6 +763,7 @@ async def sample_list_views(): Returns: google.cloud.logging_v2.services.config_service_v2.pagers.ListViewsAsyncPager: The response from ListViews. + Iterating over this object will yield results and resolve additional pages automatically. diff --git a/tests/integration/goldens/logging/google/cloud/logging_v2/services/config_service_v2/client.py b/tests/integration/goldens/logging/google/cloud/logging_v2/services/config_service_v2/client.py index 4a515374cd..419f709448 100755 --- a/tests/integration/goldens/logging/google/cloud/logging_v2/services/config_service_v2/client.py +++ b/tests/integration/goldens/logging/google/cloud/logging_v2/services/config_service_v2/client.py @@ -491,6 +491,7 @@ def sample_list_buckets(): Returns: google.cloud.logging_v2.services.config_service_v2.pagers.ListBucketsPager: The response from ListBuckets. + Iterating over this object will yield results and resolve additional pages automatically. @@ -997,6 +998,7 @@ def sample_list_views(): Returns: google.cloud.logging_v2.services.config_service_v2.pagers.ListViewsPager: The response from ListViews. + Iterating over this object will yield results and resolve additional pages automatically. diff --git a/tests/integration/goldens/logging/google/cloud/logging_v2/services/logging_service_v2/async_client.py b/tests/integration/goldens/logging/google/cloud/logging_v2/services/logging_service_v2/async_client.py index 698b72276c..efc2a54185 100755 --- a/tests/integration/goldens/logging/google/cloud/logging_v2/services/logging_service_v2/async_client.py +++ b/tests/integration/goldens/logging/google/cloud/logging_v2/services/logging_service_v2/async_client.py @@ -818,6 +818,7 @@ async def sample_list_logs(): Returns: google.cloud.logging_v2.services.logging_service_v2.pagers.ListLogsAsyncPager: Result returned from ListLogs. + Iterating over this object will yield results and resolve additional pages automatically. diff --git a/tests/integration/goldens/logging/google/cloud/logging_v2/services/logging_service_v2/client.py b/tests/integration/goldens/logging/google/cloud/logging_v2/services/logging_service_v2/client.py index a77eb555ce..c9ad88c97e 100755 --- a/tests/integration/goldens/logging/google/cloud/logging_v2/services/logging_service_v2/client.py +++ b/tests/integration/goldens/logging/google/cloud/logging_v2/services/logging_service_v2/client.py @@ -980,6 +980,7 @@ def sample_list_logs(): Returns: google.cloud.logging_v2.services.logging_service_v2.pagers.ListLogsPager: Result returned from ListLogs. + Iterating over this object will yield results and resolve additional pages automatically. diff --git a/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/async_client.py b/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/async_client.py index ffcebb38ae..f6f7e55ff8 100755 --- a/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/async_client.py +++ b/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/async_client.py @@ -247,6 +247,7 @@ async def sample_list_log_metrics(): Returns: google.cloud.logging_v2.services.metrics_service_v2.pagers.ListLogMetricsAsyncPager: Result returned from ListLogMetrics. + Iterating over this object will yield results and resolve additional pages automatically. @@ -372,6 +373,7 @@ async def sample_get_log_metric(): value of the metric is the number of log entries that match a logs filter in a given time interval. + Logs-based metrics can also be used to extract values from logs and create a distribution of the values. The @@ -509,6 +511,7 @@ async def sample_create_log_metric(): value of the metric is the number of log entries that match a logs filter in a given time interval. + Logs-based metrics can also be used to extract values from logs and create a distribution of the values. The @@ -639,6 +642,7 @@ async def sample_update_log_metric(): value of the metric is the number of log entries that match a logs filter in a given time interval. + Logs-based metrics can also be used to extract values from logs and create a distribution of the values. The diff --git a/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/client.py b/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/client.py index 09e173e72d..7d74c4f613 100755 --- a/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/client.py +++ b/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/client.py @@ -441,6 +441,7 @@ def sample_list_log_metrics(): Returns: google.cloud.logging_v2.services.metrics_service_v2.pagers.ListLogMetricsPager: Result returned from ListLogMetrics. + Iterating over this object will yield results and resolve additional pages automatically. @@ -558,6 +559,7 @@ def sample_get_log_metric(): value of the metric is the number of log entries that match a logs filter in a given time interval. + Logs-based metrics can also be used to extract values from logs and create a distribution of the values. The @@ -687,6 +689,7 @@ def sample_create_log_metric(): value of the metric is the number of log entries that match a logs filter in a given time interval. + Logs-based metrics can also be used to extract values from logs and create a distribution of the values. The @@ -817,6 +820,7 @@ def sample_update_log_metric(): value of the metric is the number of log entries that match a logs filter in a given time interval. + Logs-based metrics can also be used to extract values from logs and create a distribution of the values. The diff --git a/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/transports/rest.py b/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/transports/rest.py index c68edad36d..9a834ebfad 100755 --- a/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/transports/rest.py +++ b/tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/transports/rest.py @@ -315,6 +315,7 @@ def __call__(self, value of the metric is the number of log entries that match a logs filter in a given time interval. + Logs-based metrics can also be used to extract values from logs and create a distribution of the values. The @@ -475,6 +476,7 @@ def __call__(self, value of the metric is the number of log entries that match a logs filter in a given time interval. + Logs-based metrics can also be used to extract values from logs and create a distribution of the values. The @@ -638,6 +640,7 @@ def __call__(self, value of the metric is the number of log entries that match a logs filter in a given time interval. + Logs-based metrics can also be used to extract values from logs and create a distribution of the values. The diff --git a/tests/integration/goldens/logging/google/cloud/logging_v2/types/log_entry.py b/tests/integration/goldens/logging/google/cloud/logging_v2/types/log_entry.py index 040a12549b..21f6b0cd67 100755 --- a/tests/integration/goldens/logging/google/cloud/logging_v2/types/log_entry.py +++ b/tests/integration/goldens/logging/google/cloud/logging_v2/types/log_entry.py @@ -90,6 +90,7 @@ class LogEntry(proto.Message): protocol buffer. Some Google Cloud Platform services use this field for their log entry payloads. + The following protocol buffer types are supported; user-defined types are not supported: diff --git a/tests/integration/goldens/logging/google/cloud/logging_v2/types/logging_metrics.py b/tests/integration/goldens/logging/google/cloud/logging_v2/types/logging_metrics.py index 8d39eb807f..1259e001a8 100755 --- a/tests/integration/goldens/logging/google/cloud/logging_v2/types/logging_metrics.py +++ b/tests/integration/goldens/logging/google/cloud/logging_v2/types/logging_metrics.py @@ -42,6 +42,7 @@ class LogMetric(proto.Message): r"""Describes a logs-based metric. The value of the metric is the number of log entries that match a logs filter in a given time interval. + Logs-based metrics can also be used to extract values from logs and create a distribution of the values. The distribution records the statistics of the extracted values along with an diff --git a/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/async_client.py b/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/async_client.py index 976bb3bd71..5babf20b10 100755 --- a/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/async_client.py +++ b/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/async_client.py @@ -1021,6 +1021,7 @@ async def export_instance(self, r"""Export Redis instance data into a Redis RDB format file in Cloud Storage. Redis will continue serving during this operation. + The returned operation is automatically deleted after a few hours, so there is no need to call DeleteOperation. diff --git a/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/client.py b/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/client.py index 414d578bfe..5f804c725a 100755 --- a/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/client.py +++ b/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/client.py @@ -1215,6 +1215,7 @@ def export_instance(self, r"""Export Redis instance data into a Redis RDB format file in Cloud Storage. Redis will continue serving during this operation. + The returned operation is automatically deleted after a few hours, so there is no need to call DeleteOperation. diff --git a/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/transports/grpc.py b/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/transports/grpc.py index 3c22cd0683..0c162e8bb1 100755 --- a/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/transports/grpc.py +++ b/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/transports/grpc.py @@ -465,6 +465,7 @@ def export_instance(self) -> Callable[ Export Redis instance data into a Redis RDB format file in Cloud Storage. Redis will continue serving during this operation. + The returned operation is automatically deleted after a few hours, so there is no need to call DeleteOperation. diff --git a/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/transports/grpc_asyncio.py b/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/transports/grpc_asyncio.py index 806b87287f..082123d465 100755 --- a/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/transports/grpc_asyncio.py +++ b/tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/transports/grpc_asyncio.py @@ -468,6 +468,7 @@ def export_instance(self) -> Callable[ Export Redis instance data into a Redis RDB format file in Cloud Storage. Redis will continue serving during this operation. + The returned operation is automatically deleted after a few hours, so there is no need to call DeleteOperation. diff --git a/tests/unit/utils/test_lines.py b/tests/unit/utils/test_lines.py index 934f2ad666..7a0638b71a 100644 --- a/tests/unit/utils/test_lines.py +++ b/tests/unit/utils/test_lines.py @@ -101,6 +101,15 @@ def test_wrap_with_short_lines(): assert lines.wrap(input, width=60) == expected +def test_lines_which_have_2_spaces_following_period(): + input = """Information related to the a standard versioned package. This includes +package info for APT, Yum, Zypper, and Googet package managers.""" + expected = """Information related to the a standard versioned package. +This includes package info for APT, Yum, Zypper, and Googet +package managers.""" + assert lines.wrap(input, width=60) == expected + + def test_list_each_item_in_list_has_new_line(): input = """Type of weather: - Hail @@ -177,3 +186,63 @@ def test_new_line_added_short_text_before_list(): - Rain - Snow""" assert lines.wrap(input, width=60) == expected + + +def test_new_line_preserved_short_text_before_list_without_colon(): + input = """Today's forecast will have different weather. + +- A mix of hail and snow, followed by rain clouds, then finally clear sky +- Rain +- Snow""" + expected = """Today's forecast will have different weather. + +- A mix of hail and snow, followed by rain clouds, then + finally clear sky +- Rain +- Snow""" + assert lines.wrap(input, width=60) == expected + + +def test_list_with_multiple_paragraphs(): + input = """Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec porta euismod est a viverra. Integer vulputate ipsum id lacus tincidunt, id tincidunt tortor ullamcorper. Vestibulum facilisis at nulla nec lobortis. Nunc consectetur suscipit lacus id aliquam. + +Donec et urna aliquam, efficitur mauris et, consectetur enim. Aliquam aliquet turpis eget erat gravida condimentum. Sed vel feugiat risus. + +Sed interdum. + +Convallis turpis nec congue. Integer vulputate sed urna eu mollis. Mauris in congue nisi, sed pellentesque ex. + +- Ut vestibulum +- consequat imperdiet +- Integer rhoncus varius. Ante, ac tempus augue +finibus sit amet. Integer ac fermentum neque, a sodales nibh. Mauris et dictum ipsum. Integer sit amet posuere urna. Nullam cursus molestie posuere. Praesent imperdiet cursus purus, in posuere odio. +- Orci varius natoque penatibus et + +Aagnis dis parturient montes, nascetur ridiculus mus. Mauris mattis turpis quis hendrerit gravida. Curabitur nec diam erat. In nec est nisl. Quisque ut orci efficitur, vestibulum ante non, vestibulum erat. Donec mollis ultricies nisl.""" + expected = """Lorem ipsum dolor sit amet, consectetur adipiscing elit. +Donec porta euismod est a viverra. Integer vulputate ipsum +id lacus tincidunt, id tincidunt tortor ullamcorper. +Vestibulum facilisis at nulla nec lobortis. Nunc consectetur +suscipit lacus id aliquam. Donec et urna aliquam, efficitur +mauris et, consectetur enim. Aliquam aliquet turpis eget +erat gravida condimentum. Sed vel feugiat risus. + +Sed interdum. + +Convallis turpis nec congue. Integer vulputate sed urna eu +mollis. Mauris in congue nisi, sed pellentesque ex. + +- Ut vestibulum +- consequat imperdiet +- Integer rhoncus varius. Ante, ac tempus augue finibus sit + amet. Integer ac fermentum neque, a sodales nibh. Mauris + et dictum ipsum. Integer sit amet posuere urna. Nullam + cursus molestie posuere. Praesent imperdiet cursus purus, + in posuere odio. +- Orci varius natoque penatibus et + +Aagnis dis parturient montes, nascetur ridiculus mus. Mauris +mattis turpis quis hendrerit gravida. Curabitur nec diam +erat. In nec est nisl. Quisque ut orci efficitur, vestibulum +ante non, vestibulum erat. Donec mollis ultricies nisl.""" + assert lines.wrap(input, width=60) == expected