From 440f6f652bdedadcd59388cd062ee90434d60a28 Mon Sep 17 00:00:00 2001
From: NostraDavid <55331731+NostraDavid@users.noreply.github.com>
Date: Wed, 14 Oct 2026 19:43:22 +0200
Subject: [PATCH 01/13] packaging: require Python 3.11 and use timezone-aware
UTC datetimes
---
.../templates/automation_test.yml | 2 +-
.../messaging-cmdlet-gen.md | 4 +--
azure-pipelines.yml | 8 +++--
doc/command_guidelines.md | 2 +-
doc/debug/debug_in_vs_code.md | 2 +-
doc/extensions/authoring.md | 2 +-
doc/install_linux_prerequisites.md | 2 +-
scripts/ci/build.sh | 2 +-
scripts/ci/codegen_report.py | 2 +-
scripts/release/debian/Dockerfile | 2 +-
.../azure/cli/core/commands/__init__.py | 2 +-
.../azure/cli/core/intercept_survey.py | 12 ++++----
.../azure/cli/core/telemetry.py | 10 +++----
.../cli/core/tests/test_intercept_survey.py | 24 +++++++++++++++
src/azure-cli-core/pyproject.toml | 3 +-
src/azure-cli-telemetry/pyproject.toml | 2 +-
.../azure/cli/testsdk/preparers.py | 6 ++--
src/azure-cli-testsdk/pyproject.toml | 2 +-
.../azure/cli/command_modules/acr/_format.py | 4 +--
.../azure/cli/command_modules/acr/_utils.py | 6 ++--
.../acs/managed_cluster_decorator.py | 2 +-
.../acs/tests/latest/custom_preparers.py | 4 +--
.../acs/tests/latest/test_custom.py | 8 ++---
.../latest/test_managed_cluster_decorator.py | 4 +--
.../command_modules/apim/tests/__init__.py | 6 ++--
.../appservice/_github_oauth.py | 6 ++--
.../appservice/appservice_domains.py | 4 +--
.../cli/command_modules/appservice/custom.py | 6 ++--
.../appservice/static_sites.py | 4 +--
.../cli/command_modules/backup/custom.py | 8 ++---
.../backup/tests/latest/preparers.py | 6 ++--
.../backup/tests/latest/test_afs_commands.py | 6 ++--
.../tests/latest/test_backup_commands.py | 8 ++---
.../cli/command_modules/batchai/custom.py | 4 +--
.../command_modules/billing/tests/__init__.py | 6 ++--
.../containerapp/_github_oauth.py | 6 ++--
.../command_modules/containerapp/_utils.py | 16 +++++-----
.../cli/command_modules/cosmosdb/custom.py | 10 ++-----
.../test_cosmosdb_backuprestore_scenario.py | 23 +++++++++++++-
.../tests/latest/test_cosmosdb_commands.py | 20 ++++++-------
.../databoxedge/tests/__init__.py | 6 ++--
.../tests/latest/test_eventgrid_commands.py | 10 +++----
.../cli/command_modules/feedback/custom.py | 4 +--
.../feedback/tests/latest/test_feedback.py | 16 ++++++++++
.../azure/cli/command_modules/iot/_utils.py | 4 +--
.../iot/tests/latest/_test_utils.py | 8 ++---
.../tests/latest/test_keyvault_commands.py | 14 ++++-----
.../lab/tests/latest/test_lab_validators.py | 13 +++++++-
.../cli/command_modules/lab/validators.py | 4 ++-
.../marketplaceordering/tests/__init__.py | 6 ++--
.../command_modules/monitor/_legacy/custom.py | 8 ++---
.../cli/command_modules/monitor/custom.py | 8 ++---
.../azure/cli/command_modules/mysql/_util.py | 7 ++---
.../azure/cli/command_modules/mysql/custom.py | 5 ++--
.../mysql/tests/latest/test_mysql_scenario.py | 15 +++++-----
.../tests/latest/test_bucket_commands.py | 4 +--
.../tests/latest/test_network_commands.py | 21 ++++---------
.../postgresql/commands/backup_commands.py | 4 +--
.../commands/server_logs_commands.py | 7 ++---
.../postgresql/utils/_flexible_server_util.py | 5 ++--
.../rdbms/_flexible_server_util.py | 5 ++--
.../azure/cli/command_modules/rdbms/custom.py | 5 ++--
.../rdbms/flexible_server_custom_common.py | 5 ++--
.../rdbms/tests/latest/test_rdbms_commands.py | 5 ++--
.../redis/tests/latest/test_redis_scenario.py | 4 +--
.../resource/tests/latest/test_resource.py | 8 ++---
.../azure/cli/command_modules/role/custom.py | 10 +++----
.../role/tests/latest/test_role.py | 2 +-
.../role/tests/latest/test_role_custom.py | 9 ++++++
.../sql/tests/latest/test_sql_commands.py | 22 +++++++-------
.../command_modules/storage/_validators.py | 10 +++----
.../storage/operations/blob.py | 16 +++++-----
.../storage/operations/file.py | 16 +++++-----
.../storage/operations/fileshare.py | 4 +--
.../storage/operations/filesystem.py | 4 +--
.../storage/operations/fs_directory.py | 4 +--
.../storage/operations/fs_file.py | 4 +--
.../storage/operations/queue.py | 4 +--
.../latest/test_storage_account_scenarios.py | 6 ++--
.../test_storage_adls_gen2_scenarios.py | 30 +++++++++----------
.../latest/test_storage_azcopy_scenarios.py | 14 ++++-----
.../latest/test_storage_batch_operations.py | 14 ++++-----
.../test_storage_blob_copy_scenarios.py | 12 ++++----
.../test_storage_blob_live_scenarios.py | 6 ++--
.../test_storage_blob_rewrite_scenarios.py | 4 +--
.../latest/test_storage_blob_scenarios.py | 26 ++++++++--------
.../test_storage_container_access_policy.py | 8 ++---
.../latest/test_storage_file_scenarios.py | 12 ++++----
.../test_storage_file_share_scenarios.py | 14 ++++-----
.../latest/test_storage_queue_scenarios.py | 14 ++++-----
.../latest/test_storage_sas_scenarios.py | 28 ++++++++---------
.../test_storage_sas_tokan_url_scenarios.py | 6 ++--
.../latest/test_storage_table_scenarios.py | 4 +--
.../tests/latest/test_storage_validators.py | 5 ++++
.../azure/cli/command_modules/storage/util.py | 14 ++++-----
src/azure-cli/pyproject.toml | 3 +-
96 files changed, 425 insertions(+), 357 deletions(-)
create mode 100644 src/azure-cli-core/azure/cli/core/tests/test_intercept_survey.py
diff --git a/.azure-pipelines/templates/automation_test.yml b/.azure-pipelines/templates/automation_test.yml
index 742745a5ca6..0d6f5a02be4 100644
--- a/.azure-pipelines/templates/automation_test.yml
+++ b/.azure-pipelines/templates/automation_test.yml
@@ -3,7 +3,7 @@
parameters:
- name: pythonVersion
type: string
- default: 3.10
+ default: '3.11'
- name: profile
type: string
default: latest
diff --git a/.github/agents/Messaging-cmdlets-Generation/messaging-cmdlet-gen.md b/.github/agents/Messaging-cmdlets-Generation/messaging-cmdlet-gen.md
index 7503cb292e6..70ad53134e4 100644
--- a/.github/agents/Messaging-cmdlets-Generation/messaging-cmdlet-gen.md
+++ b/.github/agents/Messaging-cmdlets-Generation/messaging-cmdlet-gen.md
@@ -83,7 +83,7 @@ $VENV = "$SPEC_ROOT\.venv-aaz"
## 2. Environment
-**Python 3.10-3.14 required.** Verify with the explicit path, not `PATH`; do not install it yourself.
+**Python 3.11-3.14 required.** Verify with the explicit path, not `PATH`; do not install it yourself.
* Windows: `& "$env:LOCALAPPDATA\Programs\Python\Python312\python.exe" --version`
(installer from ; path form
`C:\Users\{xxxx}\AppData\Local\Programs\Python\Python3{xxxx}`)
@@ -734,7 +734,7 @@ Further reading: azure-cli `doc/` (extensions, command guidelines, authoring tes
- [ ] Plan echoed back and confirmed (service, `` -> ``, swagger path, branch, scope).
- [ ] **Section 4.1 pre-flight**: `az provider show` confirms whether ARM serves `` yet.
- [ ] **Section 4.2**: pre-existing aaz<->azure-cli drift isolated and listed before generating.
-- [ ] Python 3.10-3.14 venv active; `aaz-dev` + `azdev` installed.
+- [ ] Python 3.11-3.14 venv active; `aaz-dev` + `azdev` installed.
- [ ] Repos synced from upstream; `aaz` and `azure-cli` on identically named `feature-*` branches.
- [ ] `azdev setup --cli $CLI --repo $EXT` clean.
- [ ] `aaz-dev run` generation complete for the agreed scope.
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 280c045d7eb..550a02fd604 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -491,6 +491,8 @@ jobs:
displayName: Test Python Wheels
strategy:
matrix:
+ Python311:
+ python.version: '3.11'
Python312:
python.version: '3.12'
Python314:
@@ -531,6 +533,8 @@ jobs:
name: ${{ variables.ubuntu_pool }}
strategy:
matrix:
+ Python311:
+ python.version: '3.11'
Python312:
python.version: '3.12'
Python314:
@@ -548,8 +552,8 @@ jobs:
name: ${{ variables.ubuntu_pool }}
strategy:
matrix:
- Python310:
- python.version: '3.10'
+ Python311:
+ python.version: '3.11'
Python314:
python.version: '3.14'
steps:
diff --git a/doc/command_guidelines.md b/doc/command_guidelines.md
index 75059f0ff48..3aa07544da6 100644
--- a/doc/command_guidelines.md
+++ b/doc/command_guidelines.md
@@ -426,7 +426,7 @@ Follow the [Error Handling Guidelines](https://github.com/Azure/azure-cli/blob/d
## Coding Practices
-- All code must support Python 3.10 ~ 3.14
+- All code must support Python 3.11 ~ 3.14
- PRs to Azure/azure-cli and Azure/azure-cli-extensions must pass CI
- Code must pass style checks with pylint and pep8
- (*) All commands should have tests
diff --git a/doc/debug/debug_in_vs_code.md b/doc/debug/debug_in_vs_code.md
index 6a23e8383f7..1c49fb2cf77 100644
--- a/doc/debug/debug_in_vs_code.md
+++ b/doc/debug/debug_in_vs_code.md
@@ -4,7 +4,7 @@
* Visual Studio Code [Link](http://code.visualstudio.com/)
* Visual Studio Code Python Extension [Link](https://marketplace.visualstudio.com/items?itemName=ms-python.python)
-* Python 3.10+
+* Python 3.11+
* Set up development environment [Link](https://github.com/Azure/azure-cli/blob/master/doc/configuring_your_machine.md)
## Quick start
diff --git a/doc/extensions/authoring.md b/doc/extensions/authoring.md
index 2258e70bda1..ec2805e7afd 100644
--- a/doc/extensions/authoring.md
+++ b/doc/extensions/authoring.md
@@ -130,7 +130,7 @@ See [Extension Metadata](metadata.md) for more information.
### Test your extension on Python 3
-- The Azure CLI supports Python 3.10 ~ 3.14 so verify that your extension does the same.
+- The Azure CLI supports Python 3.11 ~ 3.14 so verify that your extension does the same.
- You can create virtual environments for different versions and run your extension in them.
- e.g. `python3.14 -m venv env314`.
diff --git a/doc/install_linux_prerequisites.md b/doc/install_linux_prerequisites.md
index 5b006179282..5503c9b8377 100644
--- a/doc/install_linux_prerequisites.md
+++ b/doc/install_linux_prerequisites.md
@@ -6,7 +6,7 @@ Some native Linux packages are required when installing the CLI with:
- Interactive installation script
- `pip`
-Current supported Python versions are Python 3.10 ~ 3.14.
+Current supported Python versions are Python 3.11 ~ 3.14.
The commands to run to install the dependencies for some common distributions are listed below.
diff --git a/scripts/ci/build.sh b/scripts/ci/build.sh
index 845a5d8b67b..6699b2dbce3 100755
--- a/scripts/ci/build.sh
+++ b/scripts/ci/build.sh
@@ -110,7 +110,6 @@ CLASSIFIERS = [
'Intended Audience :: Developers',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'License :: OSI Approved :: MIT License',
@@ -125,6 +124,7 @@ setup(
name='azure-cli-fulltest',
version=VERSION,
description='Microsoft Azure Command-Line Tools Full Tests',
+ python_requires='>=3.11.0',
license='MIT',
author='Microsoft Corporation',
author_email='azpycli@microsoft.com',
diff --git a/scripts/ci/codegen_report.py b/scripts/ci/codegen_report.py
index b6e3810fb7d..f0b1a552549 100644
--- a/scripts/ci/codegen_report.py
+++ b/scripts/ci/codegen_report.py
@@ -111,7 +111,7 @@ def generate_csv():
total = ref['total']
manual = total - codegenv1 - codegenv2
is_release = True if BUILD_BRANCH == 'release' else False
- date = (datetime.datetime.utcnow() + datetime.timedelta(hours=8)).strftime("%Y-%m-%d")
+ date = (datetime.datetime.now(datetime.UTC) + datetime.timedelta(hours=8)).strftime("%Y-%m-%d")
data.append([BUILD_ID, manual, codegenv1, codegenv2, total, is_release, date])
logger.info('Finish generate data for codegen report:')
logger.info("BUILD_ID, manual, codegenv1, codegenv2, total, is_release, date")
diff --git a/scripts/release/debian/Dockerfile b/scripts/release/debian/Dockerfile
index 11f4eaafdc1..73d81b42e1a 100644
--- a/scripts/release/debian/Dockerfile
+++ b/scripts/release/debian/Dockerfile
@@ -6,7 +6,7 @@ RUN apt-get update
RUN apt-get install -y libssl-dev libffi-dev python3-dev debhelper zlib1g-dev wget
# Download Python source code
-ARG python_version="3.10.10"
+ARG python_version="3.11.17"
ENV PYTHON_SRC_DIR=/usr/src/python
RUN mkdir -p ${PYTHON_SRC_DIR} && \
wget -qO- https://www.python.org/ftp/python/${python_version}/Python-${python_version}.tgz \
diff --git a/src/azure-cli-core/azure/cli/core/commands/__init__.py b/src/azure-cli-core/azure/cli/core/commands/__init__.py
index 2700595662a..11dd3cb98d8 100644
--- a/src/azure-cli-core/azure/cli/core/commands/__init__.py
+++ b/src/azure-cli-core/azure/cli/core/commands/__init__.py
@@ -1060,7 +1060,7 @@ def _generate_template_progress(self, correlation_id): # pylint: disable=no-sel
if correlation_id is not None: # pylint: disable=too-many-nested-blocks
formatter = "eventTimestamp ge {}"
- end_time = datetime.datetime.utcnow()
+ end_time = datetime.datetime.now(datetime.UTC)
start_time = end_time - datetime.timedelta(seconds=DEFAULT_QUERY_TIME_RANGE)
odata_filters = formatter.format(start_time.strftime('%Y-%m-%dT%H:%M:%SZ'))
diff --git a/src/azure-cli-core/azure/cli/core/intercept_survey.py b/src/azure-cli-core/azure/cli/core/intercept_survey.py
index 20d9c82fe11..1f4b4db363f 100644
--- a/src/azure-cli-core/azure/cli/core/intercept_survey.py
+++ b/src/azure-cli-core/azure/cli/core/intercept_survey.py
@@ -6,7 +6,7 @@
import os
import sys
import json
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
from azure.cli.core._config import GLOBAL_CONFIG_DIR
from azure.cli.core._profile import Profile
from azure.cli.core.style import print_styled_text
@@ -56,7 +56,7 @@ def should_prompt(cli):
# using their installationId
installation_id = Profile(cli_ctx=cli).get_installation_id()
prompt_period = EXPERIENCE_PERIOD_IN_DAYS + (uuid.UUID(installation_id).int & 127)
- next_prompt_time = datetime.utcnow() + timedelta(days=prompt_period)
+ next_prompt_time = datetime.now(UTC) + timedelta(days=prompt_period)
survey_note = {
'last_prompt_time': '',
'next_prompt_time': next_prompt_time.strftime('%Y-%m-%dT%H:%M:%S')
@@ -67,8 +67,8 @@ def should_prompt(cli):
with open(GLOBAL_SURVEY_NOTE_PATH, 'r', encoding='utf-8-sig') as f:
survey_note = json.load(f)
- next_prompt_time = datetime.strptime(survey_note['next_prompt_time'], '%Y-%m-%dT%H:%M:%S')
- if datetime.utcnow() < next_prompt_time:
+ next_prompt_time = datetime.strptime(survey_note['next_prompt_time'], '%Y-%m-%dT%H:%M:%S').replace(tzinfo=UTC)
+ if datetime.now(UTC) < next_prompt_time:
return False
return True
@@ -92,9 +92,9 @@ def prompt_survey_message(cli):
telemetry.set_survey_info(show_survey_message=True)
# log prompt time
- next_prompt_time = datetime.utcnow() + timedelta(days=PROMPT_INTERVAL_IN_DAYS)
+ next_prompt_time = datetime.now(UTC) + timedelta(days=PROMPT_INTERVAL_IN_DAYS)
survey_note = {
- 'last_prompt_time': datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S'),
+ 'last_prompt_time': datetime.now(UTC).strftime('%Y-%m-%dT%H:%M:%S'),
'next_prompt_time': next_prompt_time.strftime('%Y-%m-%dT%H:%M:%S')
}
with open(GLOBAL_SURVEY_NOTE_PATH, 'w') as f:
diff --git a/src/azure-cli-core/azure/cli/core/telemetry.py b/src/azure-cli-core/azure/cli/core/telemetry.py
index 1bb248f7bdf..c65611bffd4 100644
--- a/src/azure-cli-core/azure/cli/core/telemetry.py
+++ b/src/azure-cli-core/azure/cli/core/telemetry.py
@@ -292,7 +292,7 @@ def _wrapper(*args, **kwargs):
def start(mode=None):
if mode:
_session.mode = mode
- _session.start_time = datetime.datetime.utcnow()
+ _session.start_time = datetime.datetime.now(datetime.UTC)
@decorators.suppress_all_exceptions()
@@ -307,12 +307,12 @@ def set_invoke_time_elapsed(invoke_time_elapsed):
@decorators.suppress_all_exceptions()
def poll_start():
- _session.poll_start_time = datetime.datetime.utcnow()
+ _session.poll_start_time = datetime.datetime.now(datetime.UTC)
@decorators.suppress_all_exceptions()
def poll_end():
- _session.poll_end_time = datetime.datetime.utcnow()
+ _session.poll_end_time = datetime.datetime.now(datetime.UTC)
@_user_agrees_to_telemetry
@@ -322,7 +322,7 @@ def flush():
from azure.cli.telemetry import save
# flush out current information
- _session.end_time = datetime.datetime.utcnow()
+ _session.end_time = datetime.datetime.now(datetime.UTC)
save(get_config_dir(), _session.generate_payload())
# reset session fields, retaining correlation id and application
@@ -335,7 +335,7 @@ def conclude():
from azure.cli.core._environment import get_config_dir
from azure.cli.telemetry import save
- _session.end_time = datetime.datetime.utcnow()
+ _session.end_time = datetime.datetime.now(datetime.UTC)
save(get_config_dir(), _session.generate_payload())
diff --git a/src/azure-cli-core/azure/cli/core/tests/test_intercept_survey.py b/src/azure-cli-core/azure/cli/core/tests/test_intercept_survey.py
new file mode 100644
index 00000000000..a684f32b205
--- /dev/null
+++ b/src/azure-cli-core/azure/cli/core/tests/test_intercept_survey.py
@@ -0,0 +1,24 @@
+# --------------------------------------------------------------------------------------------
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License. See License.txt in the project root for license information.
+# --------------------------------------------------------------------------------------------
+
+import json
+import unittest
+from unittest import mock
+
+from azure.cli.core import intercept_survey
+
+
+class TestInterceptSurvey(unittest.TestCase):
+ def test_should_prompt_with_existing_utc_note(self):
+ cli = mock.Mock()
+ cli.config.getboolean.return_value = True
+ for timestamp, expected in [('2000-01-01T00:00:00', True), ('2999-01-01T00:00:00', False)]:
+ with self.subTest(timestamp=timestamp):
+ note = json.dumps({'next_prompt_time': timestamp})
+ with mock.patch.object(intercept_survey.sys.stderr, 'isatty', return_value=True), \
+ mock.patch.object(intercept_survey.sys, 'argv', ['az', 'group', 'list']), \
+ mock.patch.object(intercept_survey.os.path, 'isfile', return_value=True), \
+ mock.patch('azure.cli.core.intercept_survey.open', mock.mock_open(read_data=note)):
+ self.assertEqual(intercept_survey.should_prompt(cli), expected)
diff --git a/src/azure-cli-core/pyproject.toml b/src/azure-cli-core/pyproject.toml
index e63644e9ed2..b166313eb41 100644
--- a/src/azure-cli-core/pyproject.toml
+++ b/src/azure-cli-core/pyproject.toml
@@ -7,7 +7,7 @@ name = "azure-cli-core"
version = "2.91.0"
description = "Microsoft Azure Command-Line Tools Core Module"
readme = { file = "README.rst", content-type = "text/x-rst" }
-requires-python = ">=3.10.0"
+requires-python = ">=3.11.0"
license = "MIT"
license-files = ["LICENSE.txt"]
authors = [{ name = "Microsoft Corporation", email = "azpycli@microsoft.com" }]
@@ -17,7 +17,6 @@ classifiers = [
"Intended Audience :: System Administrators",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
diff --git a/src/azure-cli-telemetry/pyproject.toml b/src/azure-cli-telemetry/pyproject.toml
index 9998646086e..00f99b256ad 100644
--- a/src/azure-cli-telemetry/pyproject.toml
+++ b/src/azure-cli-telemetry/pyproject.toml
@@ -7,6 +7,7 @@ name = "azure-cli-telemetry"
version = "1.1.0"
description = "Microsoft Azure CLI Telemetry Package"
dynamic = ["readme"]
+requires-python = ">=3.11.0"
license = "MIT"
license-files = ["LICENSE.txt"]
authors = [{ name = "Microsoft Corporation", email = "azpycli@microsoft.com" }]
@@ -16,7 +17,6 @@ classifiers = [
"Intended Audience :: System Administrators",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
diff --git a/src/azure-cli-testsdk/azure/cli/testsdk/preparers.py b/src/azure-cli-testsdk/azure/cli/testsdk/preparers.py
index 8e7f079f118..92d8588c2be 100644
--- a/src/azure-cli-testsdk/azure/cli/testsdk/preparers.py
+++ b/src/azure-cli-testsdk/azure/cli/testsdk/preparers.py
@@ -5,7 +5,7 @@
import os
import sys
-from datetime import datetime
+from datetime import UTC, datetime
from .scenario_tests import AbstractPreparer, SingleValueReplacer
from .base import LiveScenarioTest
@@ -85,7 +85,7 @@ def create_resource(self, name, **kwargs):
module = test_class_path[index_of_module] if index_of_module >= 0 else 'unknown'
tags = {'product': 'azurecli',
'cause': 'automation test',
- 'date': datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ'),
+ 'date': datetime.now(UTC).strftime('%Y-%m-%dT%H:%M:%SZ'),
'test': self.test_class_instance._testMethodName,
'module': module}
if 'ENV_JOB_NAME' in os.environ:
@@ -419,7 +419,7 @@ def create_resource(self, name, **kwargs):
return {self.parameter_name: self.dev_setting_name, }
tags = {'product': 'azurecli', 'cause': 'automation',
- 'date': datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')}
+ 'date': datetime.now(UTC).strftime('%Y-%m-%dT%H:%M:%SZ')}
if 'ENV_JOB_NAME' in os.environ:
tags['job'] = os.environ['ENV_JOB_NAME']
tags = ' '.join(['{}={}'.format(key, value)
diff --git a/src/azure-cli-testsdk/pyproject.toml b/src/azure-cli-testsdk/pyproject.toml
index efb4889660f..d51b9cd4c57 100644
--- a/src/azure-cli-testsdk/pyproject.toml
+++ b/src/azure-cli-testsdk/pyproject.toml
@@ -7,6 +7,7 @@ name = "azure-cli-testsdk"
version = "0.3.0"
description = "Microsoft Azure Command-Line Tools Test SDK Module"
dynamic = ["readme"]
+requires-python = ">=3.11.0"
license = "MIT"
license-files = ["LICENSE.txt"]
authors = [{ name = "Microsoft Corporation", email = "azpycli@microsoft.com" }]
@@ -15,7 +16,6 @@ classifiers = [
"Intended Audience :: Developers",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
diff --git a/src/azure-cli/azure/cli/command_modules/acr/_format.py b/src/azure-cli/azure/cli/command_modules/acr/_format.py
index d8f0f8307f4..7df8ad10c69 100644
--- a/src/azure-cli/azure/cli/command_modules/acr/_format.py
+++ b/src/azure-cli/azure/cli/command_modules/acr/_format.py
@@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------
from collections import OrderedDict
-from datetime import datetime
+from datetime import UTC, datetime
from knack.log import get_logger
from ._constants import (
REF_KEY
@@ -530,4 +530,4 @@ def _get_duration(start_time, finish_time):
def add_timestamp(message):
- return "{} {}".format(datetime.utcnow(), message)
+ return "{} {}".format(datetime.now(UTC), message)
diff --git a/src/azure-cli/azure/cli/command_modules/acr/_utils.py b/src/azure-cli/azure/cli/command_modules/acr/_utils.py
index 3873b4a4124..7a2d175445a 100644
--- a/src/azure-cli/azure/cli/command_modules/acr/_utils.py
+++ b/src/azure-cli/azure/cli/command_modules/acr/_utils.py
@@ -415,11 +415,11 @@ def remove_timer_trigger(task_name,
def add_days_to_now(days):
if days <= 0:
raise CLIError('Days must be positive.')
- from datetime import datetime, timedelta
+ from datetime import UTC, datetime, timedelta
try:
- return datetime.utcnow() + timedelta(days=days)
+ return datetime.now(UTC) + timedelta(days=days)
except OverflowError:
- return datetime.max
+ return datetime.max.replace(tzinfo=UTC)
def is_vault_secret(cmd, credential):
diff --git a/src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py b/src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py
index 0fa7a008657..fb007b9763d 100644
--- a/src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py
+++ b/src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py
@@ -9601,7 +9601,7 @@ def update_upgrade_settings(self, mc: ManagedCluster) -> ManagedCluster:
f"{override_until} is not a valid datatime format."
)
elif force_upgrade:
- default_extended_until = datetime.datetime.utcnow() + datetime.timedelta(days=3)
+ default_extended_until = datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=3)
if existing_until is None or existing_until.timestamp() < default_extended_until.timestamp():
mc.upgrade_settings.override_settings.until = default_extended_until
diff --git a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/custom_preparers.py b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/custom_preparers.py
index 3d4c47b98fe..fe8db67be60 100644
--- a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/custom_preparers.py
+++ b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/custom_preparers.py
@@ -3,7 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
-from datetime import datetime
+from datetime import UTC, datetime
import os
import unittest
@@ -126,7 +126,7 @@ def create_resource(self, name, **kwargs):
tags = {
"product": "azurecli",
"cause": "automation",
- "date": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
+ "date": datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ"),
}
if "ENV_JOB_NAME" in os.environ:
tags["job"] = os.environ["ENV_JOB_NAME"]
diff --git a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_custom.py b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_custom.py
index 71ddc158a97..efaa08a39aa 100644
--- a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_custom.py
+++ b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_custom.py
@@ -2140,8 +2140,8 @@ def test_update_upgrade_settings(self, rg_def, get_resource_groups_client, get_r
instance.upgrade_settings = None
instance = _update_upgrade_settings(MockCmd(self.cli), instance, enable_force_upgrade=True, disable_force_upgrade=False, upgrade_override_until=None)
self.assertTrue(instance.upgrade_settings.override_settings.force_upgrade)
- self.assertGreater(instance.upgrade_settings.override_settings.until.timestamp(), (datetime.datetime.utcnow() + datetime.timedelta(days=2)).timestamp())
- self.assertLess(instance.upgrade_settings.override_settings.until.timestamp(), (datetime.datetime.utcnow() + datetime.timedelta(days=4)).timestamp())
+ self.assertGreater(instance.upgrade_settings.override_settings.until.timestamp(), (datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=2)).timestamp())
+ self.assertLess(instance.upgrade_settings.override_settings.until.timestamp(), (datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=4)).timestamp())
instance.upgrade_settings = self.models.ClusterUpgradeSettings(
override_settings = self.models.UpgradeOverrideSettings(
@@ -2150,8 +2150,8 @@ def test_update_upgrade_settings(self, rg_def, get_resource_groups_client, get_r
)
instance = _update_upgrade_settings(MockCmd(self.cli), instance, enable_force_upgrade=True, disable_force_upgrade=False, upgrade_override_until=None)
self.assertTrue(instance.upgrade_settings.override_settings.force_upgrade)
- self.assertGreater(instance.upgrade_settings.override_settings.until.timestamp(), (datetime.datetime.utcnow() + datetime.timedelta(days=2)).timestamp())
- self.assertLess(instance.upgrade_settings.override_settings.until.timestamp(), (datetime.datetime.utcnow() + datetime.timedelta(days=4)).timestamp())
+ self.assertGreater(instance.upgrade_settings.override_settings.until.timestamp(), (datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=2)).timestamp())
+ self.assertLess(instance.upgrade_settings.override_settings.until.timestamp(), (datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=4)).timestamp())
# force_upgrade False
instance.upgrade_settings = None
diff --git a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_managed_cluster_decorator.py b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_managed_cluster_decorator.py
index 02a3af58251..68c0e808603 100644
--- a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_managed_cluster_decorator.py
+++ b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_managed_cluster_decorator.py
@@ -10556,8 +10556,8 @@ def test_update_upgrade_settings(self):
dec_3.context.attach_mc(mc_3)
dec_mc_3 = dec_3.update_upgrade_settings(mc_3)
self.assertEqual(dec_mc_3.upgrade_settings.override_settings.force_upgrade, True)
- self.assertGreater(dec_mc_3.upgrade_settings.override_settings.until.timestamp(), (datetime.datetime.utcnow() + datetime.timedelta(days=2)).timestamp())
- self.assertLess(dec_mc_3.upgrade_settings.override_settings.until.timestamp(), (datetime.datetime.utcnow() + datetime.timedelta(days=4)).timestamp())
+ self.assertGreater(dec_mc_3.upgrade_settings.override_settings.until.timestamp(), (datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=2)).timestamp())
+ self.assertLess(dec_mc_3.upgrade_settings.override_settings.until.timestamp(), (datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=4)).timestamp())
# Set Until
dec_4 = AKSManagedClusterUpdateDecorator(
diff --git a/src/azure-cli/azure/cli/command_modules/apim/tests/__init__.py b/src/azure-cli/azure/cli/command_modules/apim/tests/__init__.py
index ba281d0650b..73e0338f818 100644
--- a/src/azure-cli/azure/cli/command_modules/apim/tests/__init__.py
+++ b/src/azure-cli/azure/cli/command_modules/apim/tests/__init__.py
@@ -61,14 +61,14 @@ def wrapper(*args, **kwargs):
test_map[func.__name__]["error_message"] = ""
test_map[func.__name__]["error_stack"] = ""
test_map[func.__name__]["error_normalized"] = ""
- test_map[func.__name__]["start_dt"] = dt.datetime.utcnow()
+ test_map[func.__name__]["start_dt"] = dt.datetime.now(dt.UTC)
ret = func_to_call(*args, **kwargs)
except (AssertionError, AzureError, CliTestError, CliExecutionError, SystemExit,
JMESPathCheckAssertionError) as e:
use_exception_cache = os.getenv("TEST_EXCEPTION_CACHE")
if use_exception_cache is None or use_exception_cache.lower() != "true":
raise
- test_map[func.__name__]["end_dt"] = dt.datetime.utcnow()
+ test_map[func.__name__]["end_dt"] = dt.datetime.now(dt.UTC)
test_map[func.__name__]["result"] = FAILED
test_map[func.__name__]["error_message"] = str(e).replace("\r\n", " ").replace("\n", " ")[:500]
test_map[func.__name__]["error_stack"] = traceback.format_exc().replace(
@@ -80,7 +80,7 @@ def wrapper(*args, **kwargs):
logger.info(traceback.format_exc())
exceptions.append((func.__name__, sys.exc_info()))
else:
- test_map[func.__name__]["end_dt"] = dt.datetime.utcnow()
+ test_map[func.__name__]["end_dt"] = dt.datetime.now(dt.UTC)
return ret
if inspect.isclass(func):
diff --git a/src/azure-cli/azure/cli/command_modules/appservice/_github_oauth.py b/src/azure-cli/azure/cli/command_modules/appservice/_github_oauth.py
index c43f257f3fa..fca076c29b1 100644
--- a/src/azure-cli/azure/cli/command_modules/appservice/_github_oauth.py
+++ b/src/azure-cli/azure/cli/command_modules/appservice/_github_oauth.py
@@ -6,7 +6,7 @@
import os
import sys
-from datetime import datetime
+from datetime import UTC, datetime
from knack.log import get_logger
from azure.cli.core.util import open_page_in_browser
@@ -49,10 +49,10 @@ def cache_github_token(cmd, token, repo):
if isinstance(entry, dict) and entry.get("value") == token:
if repo not in entry.get("repos", []):
entry["repos"] = [*entry.get("repos", []), repo]
- entry["last_modified_timestamp"] = datetime.utcnow().timestamp()
+ entry["last_modified_timestamp"] = datetime.now(UTC).timestamp()
break
else:
- cache_entry = {"last_modified_timestamp": datetime.utcnow().timestamp(), "value": token, "repos": [repo]}
+ cache_entry = {"last_modified_timestamp": datetime.now(UTC).timestamp(), "value": token, "repos": [repo]}
cache = [cache_entry, *cache]
secret_store.save(cache)
diff --git a/src/azure-cli/azure/cli/command_modules/appservice/appservice_domains.py b/src/azure-cli/azure/cli/command_modules/appservice/appservice_domains.py
index 6ee75725a80..b81cc880396 100644
--- a/src/azure-cli/azure/cli/command_modules/appservice/appservice_domains.py
+++ b/src/azure-cli/azure/cli/command_modules/appservice/appservice_domains.py
@@ -21,7 +21,7 @@ def create_domain(cmd, resource_group_name, hostname, contact_info, privacy=True
accept_terms=False, tags=None, dryrun=False, no_wait=False):
from azure.cli.core.commands.arm import ArmTemplateBuilder
from azure.cli.command_modules.appservice._template_builder import (build_dns_zone, build_domain)
- from datetime import datetime
+ from datetime import UTC, datetime
import socket
import json
@@ -41,7 +41,7 @@ def create_domain(cmd, resource_group_name, hostname, contact_info, privacy=True
'/blob/master/contact_info.json')
contact_info = verify_contact_info_and_format(contact_info)
- current_time = str(datetime.utcnow()).replace('+00:00', 'Z')
+ current_time = str(datetime.now(UTC)).replace('+00:00', 'Z')
local_ip_address = ''
try:
local_ip_address = socket.gethostbyname(socket.gethostname())
diff --git a/src/azure-cli/azure/cli/command_modules/appservice/custom.py b/src/azure-cli/azure/cli/command_modules/appservice/custom.py
index 218ed67f79f..1e91400bd5b 100644
--- a/src/azure-cli/azure/cli/command_modules/appservice/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/appservice/custom.py
@@ -2217,7 +2217,7 @@ def progress_callback(current, total):
blob_client = container_client.upload_blob(blob_name, zip_content, validate_content=True,
progress_hook=progress_callback)
- now = datetime.datetime.utcnow()
+ now = datetime.datetime.now(datetime.UTC)
blob_start = now - datetime.timedelta(minutes=10)
blob_end = now + datetime.timedelta(weeks=520)
BlobSharedAccessSignature = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_BLOB,
@@ -6482,7 +6482,7 @@ def update_backup_schedule(cmd, resource_group_name, webapp_name, storage_accoun
if backup_name and backup_name.lower().endswith('.zip'):
backup_name = backup_name[:-4]
if not backup_name:
- backup_name = '{0}_{1}'.format(webapp_name, datetime.datetime.utcnow().strftime('%Y%m%d%H%M'))
+ backup_name = '{0}_{1}'.format(webapp_name, datetime.datetime.now(datetime.UTC).strftime('%Y%m%d%H%M'))
try:
configuration = _generic_site_operation(cmd.cli_ctx, resource_group_name, webapp_name,
@@ -9106,7 +9106,7 @@ def _is_valid_runtime_setting(cls, runtime_setting, include_eol=False):
end_of_life_dt = end_of_life.replace(tzinfo=datetime.timezone.utc)
else:
end_of_life_dt = end_of_life
- now_utc = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc)
+ now_utc = datetime.datetime.now(datetime.UTC)
if now_utc >= end_of_life_dt:
return False
except (ValueError, AttributeError):
diff --git a/src/azure-cli/azure/cli/command_modules/appservice/static_sites.py b/src/azure-cli/azure/cli/command_modules/appservice/static_sites.py
index de9cc8829d5..d4aa68ff669 100644
--- a/src/azure-cli/azure/cli/command_modules/appservice/static_sites.py
+++ b/src/azure-cli/azure/cli/command_modules/appservice/static_sites.py
@@ -14,7 +14,7 @@
from knack.log import get_logger
from urllib.parse import urlparse
import uuid
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
from .utils import normalize_sku_for_staticapp, raise_missing_token_suggestion, raise_missing_ado_token_suggestion
from .custom import show_app, _build_identities_info
@@ -406,7 +406,7 @@ def _get_ado_token(cmd, source):
body = {
"displayName": f"SWA Deployment Token (created via the Azure CLI) - {uuid.uuid4().hex}",
"scope": "vso.build_execute vso.code_full vso.variablegroups_manage",
- "validTo": (datetime.utcnow() + timedelta(days=6 * 30)).isoformat(),
+ "validTo": (datetime.now(UTC) + timedelta(days=6 * 30)).isoformat(),
"allOrgs": False,
"targetAccounts": [org_id],
}
diff --git a/src/azure-cli/azure/cli/command_modules/backup/custom.py b/src/azure-cli/azure/cli/command_modules/backup/custom.py
index e4b18cbc6f3..9e41769ab73 100644
--- a/src/azure-cli/azure/cli/command_modules/backup/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/backup/custom.py
@@ -5,7 +5,7 @@
import time
import os
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
# pylint: disable=too-many-lines
from knack.log import get_logger
from knack.prompting import prompt_y_n
@@ -1860,7 +1860,7 @@ def stop_job(client, resource_group_name, vault_name, name, use_secondary_region
def wait_for_job(cmd, client, resource_group_name, vault_name, name, timeout=None, use_secondary_region=None):
logger.warning("Waiting for job '%s' ...", name)
- start_timestamp = datetime.utcnow()
+ start_timestamp = datetime.now(UTC)
if use_secondary_region:
vault = vaults_cf(cmd.cli_ctx).get(resource_group_name, vault_name)
vault_location = vault.location
@@ -1869,7 +1869,7 @@ def wait_for_job(cmd, client, resource_group_name, vault_name, name, timeout=Non
job_details = client.get(azure_region, CrrJobRequest(resource_id=vault.id, job_name=name))
while cust_help.job_in_progress(job_details.properties.status):
if timeout:
- elapsed_time = datetime.utcnow() - start_timestamp
+ elapsed_time = datetime.now(UTC) - start_timestamp
if elapsed_time.seconds > timeout:
logger.warning("Command timed out while waiting for job '%s'", name)
break
@@ -1879,7 +1879,7 @@ def wait_for_job(cmd, client, resource_group_name, vault_name, name, timeout=Non
job_details = client.get(vault_name, resource_group_name, name)
while cust_help.job_in_progress(job_details.properties.status):
if timeout:
- elapsed_time = datetime.utcnow() - start_timestamp
+ elapsed_time = datetime.now(UTC) - start_timestamp
if elapsed_time.seconds > timeout:
logger.warning("Command timed out while waiting for job '%s'", name)
break
diff --git a/src/azure-cli/azure/cli/command_modules/backup/tests/latest/preparers.py b/src/azure-cli/azure/cli/command_modules/backup/tests/latest/preparers.py
index 48b8f09df07..a06a09fcdec 100644
--- a/src/azure-cli/azure/cli/command_modules/backup/tests/latest/preparers.py
+++ b/src/azure-cli/azure/cli/command_modules/backup/tests/latest/preparers.py
@@ -5,7 +5,7 @@
import json
import os
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
from azure.cli.testsdk import CliTestError
from azure.cli.testsdk.preparers import AbstractPreparer, SingleValueReplacer, KeyVaultPreparer
@@ -395,7 +395,7 @@ def create_resource(self, name, **kwargs):
vault = self._get_vault(**kwargs)
vm = self._get_vm(**kwargs)
- retain_date = datetime.utcnow() + timedelta(days=30)
+ retain_date = datetime.now(UTC) + timedelta(days=30)
command_string = 'az backup protection backup-now --backup-management-type AzureIaasVM --workload-type VM -g {} -v {} -c {} -i {} --retain-until {} --query name'
command_string = command_string.format(self.resource_group, vault, vm, vm,
retain_date.strftime('%d-%m-%Y'))
@@ -817,7 +817,7 @@ def create_resource(self, name, **kwargs):
vault = self._get_vault(**kwargs)
afs = self._get_file_share(**kwargs)
- retain_date = datetime.utcnow() + timedelta(days=30)
+ retain_date = datetime.now(UTC) + timedelta(days=30)
retain_date = retain_date.strftime('%d-%m-%Y')
command_string = 'az backup protection backup-now'
command_string += ' -g {} -v {} -i {} -c {} --backup-management-type AzureStorage --retain-until {} --query name'
diff --git a/src/azure-cli/azure/cli/command_modules/backup/tests/latest/test_afs_commands.py b/src/azure-cli/azure/cli/command_modules/backup/tests/latest/test_afs_commands.py
index 54039dabdd3..ed24a3cda3f 100644
--- a/src/azure-cli/azure/cli/command_modules/backup/tests/latest/test_afs_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/backup/tests/latest/test_afs_commands.py
@@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------
import json
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
import unittest
import time
from azure.cli.testsdk import ScenarioTest, JMESPathCheckExists, \
@@ -42,7 +42,7 @@ def test_afs_backup_scenario(self, resource_group, vault_name, storage_account,
})
self.cmd('backup protection enable-for-azurefileshare -g {rg} -v {vault} --storage-account {container} --azure-file-share {item} -p {policy}')
- self.kwargs['retain_date'] = (datetime.utcnow() + timedelta(days=30)).strftime('%d-%m-%Y')
+ self.kwargs['retain_date'] = (datetime.now(UTC) + timedelta(days=30)).strftime('%d-%m-%Y')
self.kwargs['job'] = self.cmd('backup protection backup-now -g {rg} -v {vault} -c {container} -i {item} --retain-until {retain_date} --backup-management-type AzureStorage --query name').get_output_in_json()
self.cmd('backup job wait -g {rg} -v {vault} -n {job}')
@@ -384,7 +384,7 @@ def test_afs_backup_rp(self, resource_group, vault_name, storage_account, afs_na
rp_list = self.cmd('backup recoverypoint list -g {rg} -v {vault} -c {container} -i {item1} --backup-management-type {type}').get_output_in_json()
rp_count1 = len(rp_list)
- self.kwargs['retain_date'] = (datetime.utcnow() + timedelta(days=30)).strftime('%d-%m-%Y')
+ self.kwargs['retain_date'] = (datetime.now(UTC) + timedelta(days=30)).strftime('%d-%m-%Y')
self.kwargs['job'] = self.cmd('backup protection backup-now -g {rg} -v {vault} -c {container} -i {item1} --retain-until {retain_date} --backup-management-type AzureStorage --query name').get_output_in_json()
self.cmd('backup job wait -g {rg} -v {vault} -n {job}')
diff --git a/src/azure-cli/azure/cli/command_modules/backup/tests/latest/test_backup_commands.py b/src/azure-cli/azure/cli/command_modules/backup/tests/latest/test_backup_commands.py
index cb8404fe7d6..06bf14528df 100644
--- a/src/azure-cli/azure/cli/command_modules/backup/tests/latest/test_backup_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/backup/tests/latest/test_backup_commands.py
@@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------
import json
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
from types import SimpleNamespace
import unittest
import time
@@ -107,7 +107,7 @@ def test_backup_scenario(self, resource_group, vault_name, vm_name, storage_acco
self.kwargs['item'] = self.cmd('backup item list -g {rg} -v {vault} -c {container} --backup-management-type AzureIaasVM --workload-type VM --query [0].properties.friendlyName').get_output_in_json()
# Trigger Backup
- self.kwargs['retain_date'] = (datetime.utcnow() + timedelta(days=30)).strftime('%d-%m-%Y')
+ self.kwargs['retain_date'] = (datetime.now(UTC) + timedelta(days=30)).strftime('%d-%m-%Y')
self.kwargs['job'] = self.cmd('backup protection backup-now -g {rg} -v {vault} -c {container} -i {item} --backup-management-type AzureIaasVM --workload-type VM --retain-until {retain_date} --query name').get_output_in_json()
self.cmd('backup job wait -g {rg} -v {vault} -n {job}')
@@ -1028,7 +1028,7 @@ def _free_csb_vm():
self.assertEqual(item['properties']['containerSubscriptionId'], self.kwargs['vm_sub'])
# Take an on-demand backup so there is a recovery point to restore from.
- self.kwargs['retain_date'] = (datetime.utcnow() + timedelta(days=30)).strftime('%d-%m-%Y')
+ self.kwargs['retain_date'] = (datetime.now(UTC) + timedelta(days=30)).strftime('%d-%m-%Y')
self.kwargs['backup_job'] = self.cmd('backup protection backup-now --backup-management-type AzureIaasVM '
'--workload-type VM -g {rg} -v {vault} -c {vm_name} -i {vm_name} '
'--retain-until {retain_date} --query name').get_output_in_json()
@@ -1510,7 +1510,7 @@ def test_backup_disk_exclusion(self, resource_group, vault_name, vm_name, storag
self.check('properties.extendedProperties.diskExclusionProperties.isInclusionList', False),
])
- self.kwargs['retain_date'] = (datetime.utcnow() + timedelta(days=30)).strftime('%d-%m-%Y')
+ self.kwargs['retain_date'] = (datetime.now(UTC) + timedelta(days=30)).strftime('%d-%m-%Y')
self.kwargs['job'] = self.cmd('backup protection backup-now -g {rg} -v {vault} -c {vm} -i {vm} --backup-management-type AzureIaasVM --workload-type VM --retain-until {retain_date} --query name').get_output_in_json()
self.cmd('backup job wait -g {rg} -v {vault} -n {job}')
diff --git a/src/azure-cli/azure/cli/command_modules/batchai/custom.py b/src/azure-cli/azure/cli/command_modules/batchai/custom.py
index b5c256d1618..56ffea22c4c 100644
--- a/src/azure-cli/azure/cli/command_modules/batchai/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/batchai/custom.py
@@ -794,7 +794,7 @@ def _get_files_from_bfs(cli_ctx, bfs, path, expiry):
if b.properties.content_settings.contentMd5 is not None:
name = os.path.basename(b.name)
sas = sas_client.generate_blob(bfs.container_name, b.name, permission=BlobSasPermissions(read=True),
- expiry=datetime.datetime.utcnow() + datetime.timedelta(minutes=expiry))
+ expiry=datetime.datetime.now(datetime.UTC) + datetime.timedelta(minutes=expiry))
blob_url = b.url
if '?' not in blob_url:
blob_url += '?' + sas
@@ -843,7 +843,7 @@ def _get_files_from_afs(cli_ctx, afs, path, expiry):
if not f.is_directory:
sas = sas_client.generate_file(share_name, directory_name=effective_path, file_name=f.name,
permission=FileSasPermissions(read=True),
- expiry=datetime.datetime.utcnow() + datetime.timedelta(minutes=expiry))
+ expiry=datetime.datetime.now(datetime.UTC) + datetime.timedelta(minutes=expiry))
file_url = share_client.url + '/' + effective_path + '/' + f.name
if '?' not in file_url:
file_url += '?' + sas
diff --git a/src/azure-cli/azure/cli/command_modules/billing/tests/__init__.py b/src/azure-cli/azure/cli/command_modules/billing/tests/__init__.py
index 79f05307443..eb720283df1 100644
--- a/src/azure-cli/azure/cli/command_modules/billing/tests/__init__.py
+++ b/src/azure-cli/azure/cli/command_modules/billing/tests/__init__.py
@@ -62,11 +62,11 @@ def wrapper(*args, **kwargs):
test_map[func.__name__]["error_message"] = ""
test_map[func.__name__]["error_stack"] = ""
test_map[func.__name__]["error_normalized"] = ""
- test_map[func.__name__]["start_dt"] = dt.datetime.utcnow()
+ test_map[func.__name__]["start_dt"] = dt.datetime.now(dt.UTC)
ret = func_to_call(*args, **kwargs)
except (AssertionError, AzureError, CliTestError, CliExecutionError, SystemExit,
JMESPathCheckAssertionError) as e:
- test_map[func.__name__]["end_dt"] = dt.datetime.utcnow()
+ test_map[func.__name__]["end_dt"] = dt.datetime.now(dt.UTC)
test_map[func.__name__]["result"] = FAILED
test_map[func.__name__]["error_message"] = str(e).replace("\r\n", " ").replace("\n", " ")[:500]
test_map[func.__name__]["error_stack"] = traceback.format_exc().replace(
@@ -78,7 +78,7 @@ def wrapper(*args, **kwargs):
logger.info(traceback.format_exc())
exceptions.append((func.__name__, sys.exc_info()))
else:
- test_map[func.__name__]["end_dt"] = dt.datetime.utcnow()
+ test_map[func.__name__]["end_dt"] = dt.datetime.now(dt.UTC)
return ret
if inspect.isclass(func):
diff --git a/src/azure-cli/azure/cli/command_modules/containerapp/_github_oauth.py b/src/azure-cli/azure/cli/command_modules/containerapp/_github_oauth.py
index ce1ac41d337..0e2583c4cd7 100644
--- a/src/azure-cli/azure/cli/command_modules/containerapp/_github_oauth.py
+++ b/src/azure-cli/azure/cli/command_modules/containerapp/_github_oauth.py
@@ -6,7 +6,7 @@
import os
import sys
-from datetime import datetime
+from datetime import UTC, datetime
from knack.log import get_logger
from azure.cli.core.util import open_page_in_browser
@@ -49,10 +49,10 @@ def cache_github_token(cmd, token, repo):
if isinstance(entry, dict) and entry.get("value") == token:
if repo not in entry.get("repos", []):
entry["repos"] = [*entry.get("repos", []), repo]
- entry["last_modified_timestamp"] = datetime.utcnow().timestamp()
+ entry["last_modified_timestamp"] = datetime.now(UTC).timestamp()
break
else:
- cache_entry = {"last_modified_timestamp": datetime.utcnow().timestamp(), "value": token, "repos": [repo]}
+ cache_entry = {"last_modified_timestamp": datetime.now(UTC).timestamp(), "value": token, "repos": [repo]}
cache = [cache_entry, *cache]
secret_store.save(cache)
diff --git a/src/azure-cli/azure/cli/command_modules/containerapp/_utils.py b/src/azure-cli/azure/cli/command_modules/containerapp/_utils.py
index 35e98f1ab82..7a5af84a314 100644
--- a/src/azure-cli/azure/cli/command_modules/containerapp/_utils.py
+++ b/src/azure-cli/azure/cli/command_modules/containerapp/_utils.py
@@ -21,7 +21,7 @@
from urllib.parse import urlparse
from urllib.request import urlopen
-from datetime import datetime
+from datetime import UTC, datetime
from dateutil.relativedelta import relativedelta
from azure.cli.core.azclierror import (ValidationError, RequiredArgumentMissingError, CLIInternalError,
ResourceNotFoundError, FileOperationError, CLIError, UnauthorizedError,
@@ -161,7 +161,7 @@ def create_service_principal_for_github_action(cmd, scopes=None, role="contribut
RETRY_LIMIT = 36
client = graph_client_factory(cmd.cli_ctx)
- now = datetime.utcnow()
+ now = datetime.now(UTC)
app_display_name = 'azure-cli-' + now.strftime('%Y-%m-%d-%H-%M-%S')
app = retry_until_success(_create_application, SP_CREATION_ERR_TXT, RETRY_LIMIT, client, display_name=app_display_name)
sp = retry_until_success(_create_service_principal, SP_CREATION_ERR_TXT, RETRY_LIMIT, client, app_id=app["appId"])
@@ -221,7 +221,7 @@ def trigger_workflow(token, repo, workflow_name, branch):
def await_github_action(token, repo, workflow_name, timeout_secs=1200):
from ._clients import PollingAnimation
- start = datetime.utcnow()
+ start = datetime.now(UTC)
animation = PollingAnimation()
animation.tick()
@@ -237,14 +237,14 @@ def await_github_action(token, repo, workflow_name, timeout_secs=1200):
pass
animation.flush()
- if (datetime.utcnow() - start).seconds >= timeout_secs:
+ if (datetime.now(UTC) - start).seconds >= timeout_secs:
raise CLIInternalError("Timed out while waiting for the Github action to start.")
runs = workflow.get_runs()
while runs is None or not [r for r in runs if r.status in ('queued', 'in_progress')]:
time.sleep(SHORT_POLLING_INTERVAL_SECS)
runs = workflow.get_runs()
- if (datetime.utcnow() - start).seconds >= timeout_secs:
+ if (datetime.now(UTC) - start).seconds >= timeout_secs:
raise CLIInternalError("Timed out while waiting for the Github action to be started.")
runs = [r for r in runs if r.status in ('queued', 'in_progress')]
runs.sort(key=lambda r: r.created_at, reverse=True)
@@ -258,7 +258,7 @@ def await_github_action(token, repo, workflow_name, timeout_secs=1200):
animation.tick()
status = github_repo.get_workflow_run(run_id).status
animation.flush()
- if (datetime.utcnow() - start).seconds >= timeout_secs:
+ if (datetime.now(UTC) - start).seconds >= timeout_secs:
raise CLIInternalError("Timed out while waiting for the Github action to complete.")
animation.flush() # needed to clear the animation from the terminal
@@ -294,11 +294,11 @@ def _register_resource_provider(cmd, resource_provider):
# wait for registration to finish
timeout_secs = 120
registration = _is_resource_provider_registered(cmd, resource_provider)
- start = datetime.utcnow()
+ start = datetime.now(UTC)
while not registration:
registration = _is_resource_provider_registered(cmd, resource_provider)
time.sleep(SHORT_POLLING_INTERVAL_SECS)
- if (datetime.utcnow() - start).seconds >= timeout_secs:
+ if (datetime.now(UTC) - start).seconds >= timeout_secs:
raise CLIInternalError(f"Timed out while waiting for the {resource_provider} resource provider to be registered.")
except Exception as e:
diff --git a/src/azure-cli/azure/cli/command_modules/cosmosdb/custom.py b/src/azure-cli/azure/cli/command_modules/cosmosdb/custom.py
index 466842c2698..2274aff75b4 100644
--- a/src/azure-cli/azure/cli/command_modules/cosmosdb/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/cosmosdb/custom.py
@@ -1900,11 +1900,7 @@ def cli_cosmosdb_restore(cmd,
target_restorable_account = None
restore_timestamp_datetime_utc = _convert_to_utc_timestamp(restore_timestamp)
- # If restore timestamp is timezone aware, get the utcnow as timezone aware as well
- from datetime import timezone
- current_dateTime = datetime.datetime.utcnow()
- if restore_timestamp_datetime_utc.tzinfo is not None and restore_timestamp_datetime_utc.tzinfo.utcoffset(restore_timestamp_datetime_utc) is not None:
- current_dateTime = datetime.datetime.now(timezone.utc)
+ current_dateTime = datetime.datetime.now(datetime.UTC)
# Fail if provided restoretimesamp is greater than current timestamp
if restore_timestamp_datetime_utc > current_dateTime:
@@ -1952,11 +1948,11 @@ def _convert_to_utc_timestamp(timestamp_string):
import dateutil.parser
timestamp_datetime = dateutil.parser.parse(timestamp_string)
timestamp_datetime_utc = None
- # Convert to utc only if timezone aware
+ # Treat timestamps without an offset as UTC.
if timestamp_datetime.tzinfo is not None and timestamp_datetime.tzinfo.utcoffset(timestamp_datetime) is not None:
timestamp_datetime_utc = timestamp_datetime.astimezone(datetime.timezone.utc)
else:
- timestamp_datetime_utc = timestamp_datetime
+ timestamp_datetime_utc = timestamp_datetime.replace(tzinfo=datetime.UTC)
return timestamp_datetime_utc
diff --git a/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py b/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py
index eee0536c6ff..a86521137e0 100644
--- a/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py
+++ b/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py
@@ -10,7 +10,7 @@
from azure.cli.testsdk import (ScenarioTest, ResourceGroupPreparer, live_only)
from azure.cli.testsdk.scenario_tests import AllowLargeResponse
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
from dateutil import parser
@@ -530,6 +530,27 @@ def test_cosmosdb_xrr_single_region_account(self, resource_group):
class CosmosDBRestoreUnitTests(unittest.TestCase):
+ def test_restore_timestamp_is_utc(self):
+ from azure.cli.command_modules.cosmosdb.custom import _convert_to_utc_timestamp
+
+ expected = datetime(2020, 1, 1, tzinfo=UTC)
+ for timestamp in ['2020-01-01T00:00:00', '2020-01-01T00:00:00Z',
+ '2020-01-01T02:00:00+02:00', '2019-12-31T19:00:00-05:00']:
+ with self.subTest(timestamp=timestamp):
+ self.assertEqual(_convert_to_utc_timestamp(timestamp), expected)
+
+ @mock.patch('azure.cli.command_modules.cosmosdb.custom._create_database_account')
+ @mock.patch('azure.cli.command_modules.cosmosdb._client_factory.cf_restorable_database_accounts')
+ def test_restore_accepts_timestamp_without_offset(self, get_accounts, create_account):
+ from azure.cli.command_modules.cosmosdb.custom import cli_cosmosdb_restore
+
+ account = mock.Mock(account_name='source', deletion_time=None,
+ creation_time=datetime(2000, 1, 1, tzinfo=UTC))
+ get_accounts.return_value.list.return_value = [account]
+ cli_cosmosdb_restore(mock.Mock(), mock.Mock(), 'rg', 'source', 'target',
+ '2020-01-01T00:00:00', 'westus')
+ self.assertEqual(create_account.call_args.kwargs['restore_timestamp'], '2020-01-01T00:00:00+00:00')
+
def setUp(self):
# Only mock dependencies that cannot actually be imported. Never replace a
# real, importable package in sys.modules: these unit tests share a
diff --git a/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_commands.py b/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_commands.py
index 5762e48bf99..ed6be07b4dc 100644
--- a/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_commands.py
@@ -10,7 +10,7 @@
from azure.cli.testsdk import JMESPathCheck, ScenarioTest, ResourceGroupPreparer, KeyVaultPreparer, record_only
from knack.util import CLIError
from azure.cli.testsdk.scenario_tests import AllowLargeResponse
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta, timezone
from dateutil import parser
class CosmosDBTests(ScenarioTest):
@@ -2934,7 +2934,7 @@ def test_cosmosdb_sql_normal_database_restore(self, resource_group):
database_list = self.cmd('az cosmosdb sql database list -g {rg} -a {acc}').get_output_in_json()
assert len(database_list) == 1
- restore_ts_string = datetime.utcnow().isoformat()
+ restore_ts_string = datetime.now(UTC).isoformat()
self.kwargs.update({
'rts': restore_ts_string
@@ -3019,7 +3019,7 @@ def test_cosmosdb_sql_shared_database_restore(self, resource_group):
container_list = self.cmd('az cosmosdb sql container list -g {rg} -a {acc} -d {db_name}').get_output_in_json()
assert len(container_list) == 1
- restore_ts_string = datetime.utcnow().isoformat()
+ restore_ts_string = datetime.now(UTC).isoformat()
self.kwargs.update({
'rts': restore_ts_string,
@@ -3125,7 +3125,7 @@ def test_cosmosdb_sql_normal_database_prov_container_restore(self, resource_grou
container_list = self.cmd('az cosmosdb sql container list -g {rg} -a {acc} -d {db_name}').get_output_in_json()
assert len(container_list) == 1
- restore_ts_string = datetime.utcnow().isoformat()
+ restore_ts_string = datetime.now(UTC).isoformat()
self.kwargs.update({
'rts': restore_ts_string
@@ -3209,7 +3209,7 @@ def test_cosmosdb_sql_normal_database_prov_container_restore_nt(self, resource_g
container_list = self.cmd('az cosmosdb sql container list -g {rg} -a {acc} -d {db_name}').get_output_in_json()
assert len(container_list) == 1
- restore_ts_string = datetime.utcnow().isoformat()
+ restore_ts_string = datetime.now(UTC).isoformat()
self.kwargs.update({
'rts': restore_ts_string
@@ -3301,7 +3301,7 @@ def test_cosmosdb_sql_shared_database_prov_container_restore(self, resource_grou
container_list = self.cmd('az cosmosdb sql container list -g {rg} -a {acc} -d {db_name}').get_output_in_json()
assert len(container_list) == 1
- restore_ts_string = datetime.utcnow().isoformat()
+ restore_ts_string = datetime.now(UTC).isoformat()
self.kwargs.update({
'rts': restore_ts_string
@@ -3381,7 +3381,7 @@ def test_cosmosdb_mongodb_normal_database_prov_collection_restore(self, resource
assert self.cmd('az cosmosdb mongodb collection exists -g {rg} -a {acc} -d {db_name} -n {col_name}').get_output_in_json()
- restore_ts_string = datetime.utcnow().isoformat()
+ restore_ts_string = datetime.now(UTC).isoformat()
self.kwargs.update({
'rts': restore_ts_string
@@ -3508,7 +3508,7 @@ def test_cosmosdb_mongodb_shared_database_prov_collection_restore(self, resource
assert self.cmd('az cosmosdb mongodb collection exists -g {rg} -a {acc} -d {db_name} -n {col_name}').get_output_in_json()
- restore_ts_string = datetime.utcnow().isoformat()
+ restore_ts_string = datetime.now(UTC).isoformat()
self.kwargs.update({
'rts': restore_ts_string
@@ -3595,7 +3595,7 @@ def test_cosmosdb_gremlin_database_graph_restore(self, resource_group):
]).get_output_in_json()
#restore time
- restore_ts_string = datetime.utcnow().isoformat()
+ restore_ts_string = datetime.now(UTC).isoformat()
self.kwargs.update({
'rts': restore_ts_string
})
@@ -3729,7 +3729,7 @@ def test_cosmosdb_table(self, resource_group):
assert self.cmd('az cosmosdb table exists -g {rg} -a {acc} -n {table_name}').get_output_in_json()
- restore_ts_string = datetime.utcnow().isoformat()
+ restore_ts_string = datetime.now(UTC).isoformat()
self.kwargs.update({
'rts': restore_ts_string
diff --git a/src/azure-cli/azure/cli/command_modules/databoxedge/tests/__init__.py b/src/azure-cli/azure/cli/command_modules/databoxedge/tests/__init__.py
index ba281d0650b..73e0338f818 100644
--- a/src/azure-cli/azure/cli/command_modules/databoxedge/tests/__init__.py
+++ b/src/azure-cli/azure/cli/command_modules/databoxedge/tests/__init__.py
@@ -61,14 +61,14 @@ def wrapper(*args, **kwargs):
test_map[func.__name__]["error_message"] = ""
test_map[func.__name__]["error_stack"] = ""
test_map[func.__name__]["error_normalized"] = ""
- test_map[func.__name__]["start_dt"] = dt.datetime.utcnow()
+ test_map[func.__name__]["start_dt"] = dt.datetime.now(dt.UTC)
ret = func_to_call(*args, **kwargs)
except (AssertionError, AzureError, CliTestError, CliExecutionError, SystemExit,
JMESPathCheckAssertionError) as e:
use_exception_cache = os.getenv("TEST_EXCEPTION_CACHE")
if use_exception_cache is None or use_exception_cache.lower() != "true":
raise
- test_map[func.__name__]["end_dt"] = dt.datetime.utcnow()
+ test_map[func.__name__]["end_dt"] = dt.datetime.now(dt.UTC)
test_map[func.__name__]["result"] = FAILED
test_map[func.__name__]["error_message"] = str(e).replace("\r\n", " ").replace("\n", " ")[:500]
test_map[func.__name__]["error_stack"] = traceback.format_exc().replace(
@@ -80,7 +80,7 @@ def wrapper(*args, **kwargs):
logger.info(traceback.format_exc())
exceptions.append((func.__name__, sys.exc_info()))
else:
- test_map[func.__name__]["end_dt"] = dt.datetime.utcnow()
+ test_map[func.__name__]["end_dt"] = dt.datetime.now(dt.UTC)
return ret
if inspect.isclass(func):
diff --git a/src/azure-cli/azure/cli/command_modules/eventgrid/tests/latest/test_eventgrid_commands.py b/src/azure-cli/azure/cli/command_modules/eventgrid/tests/latest/test_eventgrid_commands.py
index bd1fb3930df..ba2a2009000 100644
--- a/src/azure-cli/azure/cli/command_modules/eventgrid/tests/latest/test_eventgrid_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/eventgrid/tests/latest/test_eventgrid_commands.py
@@ -10,7 +10,7 @@
from azure.cli.testsdk import ScenarioTest, ResourceGroupPreparer, StorageAccountPreparer
from knack.util import CLIError
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
EVENTGRID_TRIGGER_ENDPOINT_URL = "https://devexpfuncappdestination.azurewebsites.net/runtime/webhooks/EventGrid?functionName=EventGridTrigger1&code="
EVENTGRID_TRIGGER_ENDPOINT_BASE_URL = "https://devexpfuncappdestination.azurewebsites.net/runtime/webhooks/EventGrid"
@@ -1480,9 +1480,9 @@ def test_Partner_scenarios(self, resource_group):
guid3 = uuid.uuid1()
destination_subscription_id = '5b4b650e-28b9-4790-b3ab-ddbd88d727c4'
source = self.create_random_name(prefix='cli', length=40)
- exp_time = datetime.utcnow() + timedelta(hours=24)
+ exp_time = datetime.now(UTC) + timedelta(hours=24)
exp_time = exp_time.isoformat()
- creation_time = datetime.utcnow().isoformat()
+ creation_time = datetime.now(UTC).isoformat()
long_description = 'This is long description sample'
customer_service_number1 = '+1 800 123 4567'
@@ -1865,9 +1865,9 @@ def test_Partner_scenarios_v2(self, resource_group):
destination_endpoint_url = SECURED_WEBBOOK_DESTINATION_ENDPOINT_URL
source = self.create_random_name(prefix='cli', length=40)
- exp_time = datetime.utcnow() + timedelta(hours=24)
+ exp_time = datetime.now(UTC) + timedelta(hours=24)
exp_time = exp_time.isoformat()
- creation_time = datetime.utcnow().isoformat()
+ creation_time = datetime.now(UTC).isoformat()
default_maximum_expiration_time_in_days = 5
updated_default_max_expiration_time_in_days = 15
diff --git a/src/azure-cli/azure/cli/command_modules/feedback/custom.py b/src/azure-cli/azure/cli/command_modules/feedback/custom.py
index a86a19ffa3f..21fc5227bae 100644
--- a/src/azure-cli/azure/cli/command_modules/feedback/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/feedback/custom.py
@@ -605,8 +605,8 @@ def handle_survey(cmd):
with open(GLOBAL_SURVEY_NOTE_PATH, 'r') as f:
survey_note = json.load(f)
if survey_note['last_prompt_time']:
- last_prompt_time = datetime.datetime.strptime(survey_note['last_prompt_time'], '%Y-%m-%dT%H:%M:%S')
- use_duration = datetime.datetime.utcnow() - last_prompt_time
+ last_prompt_time = datetime.datetime.strptime(survey_note['last_prompt_time'], '%Y-%m-%dT%H:%M:%S').replace(tzinfo=datetime.UTC)
+ use_duration = datetime.datetime.now(datetime.UTC) - last_prompt_time
url = _SURVEY_URL.format(installation_id=Profile(cli_ctx=cmd.cli_ctx).get_installation_id(),
version=core_version,
diff --git a/src/azure-cli/azure/cli/command_modules/feedback/tests/latest/test_feedback.py b/src/azure-cli/azure/cli/command_modules/feedback/tests/latest/test_feedback.py
index 89ecd734a9f..986c3e5a889 100644
--- a/src/azure-cli/azure/cli/command_modules/feedback/tests/latest/test_feedback.py
+++ b/src/azure-cli/azure/cli/command_modules/feedback/tests/latest/test_feedback.py
@@ -207,5 +207,21 @@ def _handle_exception_with_log(ex, *args, **kwargs):
return result
+class TestSurvey(unittest.TestCase):
+ def test_existing_utc_note(self):
+ from azure.cli.command_modules.feedback import custom
+
+ note = '{"last_prompt_time": "2000-01-01T00:00:00"}'
+ with mock.patch.object(custom.os.path, 'isfile', return_value=True), \
+ mock.patch('azure.cli.command_modules.feedback.custom.open', mock.mock_open(read_data=note)), \
+ mock.patch('azure.cli.core._profile.Profile') as profile, \
+ mock.patch.object(custom, 'can_launch_browser', return_value=False), \
+ mock.patch('builtins.print') as output:
+ profile.return_value.get_installation_id.return_value = 'test-installation'
+ custom.handle_survey(mock.Mock())
+ self.assertIn('test-installation', output.call_args.args[0])
+ self.assertNotIn('d=-1', output.call_args.args[0])
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/src/azure-cli/azure/cli/command_modules/iot/_utils.py b/src/azure-cli/azure/cli/command_modules/iot/_utils.py
index 59c767c7396..9799c91f697 100644
--- a/src/azure-cli/azure/cli/command_modules/iot/_utils.py
+++ b/src/azure-cli/azure/cli/command_modules/iot/_utils.py
@@ -31,9 +31,9 @@ def create_self_signed_certificate(device_id, valid_days, cert_output_dir):
.issuer_name(subject_name)
.public_key(key.public_key())
.serial_number(x509.random_serial_number())
- .not_valid_before(datetime.datetime.utcnow())
+ .not_valid_before(datetime.datetime.now(datetime.UTC))
.not_valid_after(
- datetime.datetime.utcnow() + datetime.timedelta(days=valid_days)
+ datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=valid_days)
)
.sign(key, hashes.SHA256())
)
diff --git a/src/azure-cli/azure/cli/command_modules/iot/tests/latest/_test_utils.py b/src/azure-cli/azure/cli/command_modules/iot/tests/latest/_test_utils.py
index e3c74c77af6..917401f1943 100644
--- a/src/azure-cli/azure/cli/command_modules/iot/tests/latest/_test_utils.py
+++ b/src/azure-cli/azure/cli/command_modules/iot/tests/latest/_test_utils.py
@@ -29,9 +29,9 @@ def _create_test_cert(cert_file, key_file, subject, valid_days, serial_number):
.issuer_name(subject_name)
.public_key(key.public_key())
.serial_number(serial_number)
- .not_valid_before(datetime.datetime.utcnow())
+ .not_valid_before(datetime.datetime.now(datetime.UTC))
.not_valid_after(
- datetime.datetime.utcnow() + datetime.timedelta(days=valid_days)
+ datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=valid_days)
)
.sign(key, hashes.SHA256())
)
@@ -92,9 +92,9 @@ def _create_verification_cert(cert_file, key_file, verification_file, nonce, val
.issuer_name(signing_cert.subject)
.public_key(key.public_key())
.serial_number(serial_number)
- .not_valid_before(datetime.datetime.utcnow())
+ .not_valid_before(datetime.datetime.now(datetime.UTC))
.not_valid_after(
- datetime.datetime.utcnow() + datetime.timedelta(days=valid_days)
+ datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=valid_days)
)
.sign(k, hashes.SHA256())
)
diff --git a/src/azure-cli/azure/cli/command_modules/keyvault/tests/latest/test_keyvault_commands.py b/src/azure-cli/azure/cli/command_modules/keyvault/tests/latest/test_keyvault_commands.py
index c96ebf92ef5..8406e98afd6 100644
--- a/src/azure-cli/azure/cli/command_modules/keyvault/tests/latest/test_keyvault_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/keyvault/tests/latest/test_keyvault_commands.py
@@ -11,7 +11,7 @@
import time
from unittest import mock
import unittest
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
from dateutil import tz
from ipaddress import ip_network
@@ -975,8 +975,8 @@ def test_keyvault_hsm_selective_key_restore(self):
'key_name': self.create_random_name('selective-restore-', 24),
'storage_account': self.create_random_name('clitesthsmsa', 24),
'blob': self.create_random_name('clitesthsmblob', 24),
- 'sas_start': (datetime.utcnow() - timedelta(minutes=30)).strftime('%Y-%m-%dT%H:%M:%SZ'),
- 'sas_expiry': (datetime.utcnow() + timedelta(minutes=30)).strftime('%Y-%m-%dT%H:%M:%SZ')
+ 'sas_start': (datetime.now(UTC) - timedelta(minutes=30)).strftime('%Y-%m-%dT%H:%M:%SZ'),
+ 'sas_expiry': (datetime.now(UTC) + timedelta(minutes=30)).strftime('%Y-%m-%dT%H:%M:%SZ')
})
_clear_hsm(self, hsm_url=self.kwargs['hsm_url'])
@@ -1031,8 +1031,8 @@ def test_keyvault_hsm_full_backup_restore(self, resource_group, managed_hsm, sto
'hsm_name': managed_hsm,
'storage_account': storage_account,
'blob': self.create_random_name('clitesthsmblob', 24),
- 'sas_start': (datetime.utcnow() - timedelta(minutes=30)).strftime('%Y-%m-%dT%H:%M:%SZ'),
- 'sas_expiry': (datetime.utcnow() + timedelta(minutes=30)).strftime('%Y-%m-%dT%H:%M:%SZ')
+ 'sas_start': (datetime.now(UTC) - timedelta(minutes=30)).strftime('%Y-%m-%dT%H:%M:%SZ'),
+ 'sas_expiry': (datetime.now(UTC) + timedelta(minutes=30)).strftime('%Y-%m-%dT%H:%M:%SZ')
})
self.cmd('az storage container create -n {blob} --account-name {storage_account} -g {rg}')
@@ -2662,8 +2662,8 @@ def _generate_certificate(path, keyfile=None, password=None):
.issuer_name(issuer) \
.public_key(key.public_key()) \
.serial_number(x509.random_serial_number()) \
- .not_valid_before(datetime.utcnow()) \
- .not_valid_after(datetime.utcnow() + timedelta(days=10)) \
+ .not_valid_before(datetime.now(UTC)) \
+ .not_valid_after(datetime.now(UTC) + timedelta(days=10)) \
.sign(key, hashes.SHA256(), default_backend())
# Write the cert out to disk
diff --git a/src/azure-cli/azure/cli/command_modules/lab/tests/latest/test_lab_validators.py b/src/azure-cli/azure/cli/command_modules/lab/tests/latest/test_lab_validators.py
index b624a177420..343c1524787 100644
--- a/src/azure-cli/azure/cli/command_modules/lab/tests/latest/test_lab_validators.py
+++ b/src/azure-cli/azure/cli/command_modules/lab/tests/latest/test_lab_validators.py
@@ -4,9 +4,10 @@
# --------------------------------------------------------------------------------------------
import unittest
+from unittest import mock
from azure.mgmt.core.tools import is_valid_resource_id
from azure.cli.core.azclierror import ArgumentUsageError
-from azure.cli.command_modules.lab.validators import _update_artifacts
+from azure.cli.command_modules.lab.validators import _update_artifacts, _validate_expiration_date
class ValidatorsCommandTest(unittest.TestCase):
@@ -65,3 +66,13 @@ def test_update_artifacts(self):
del invalid_artifact['artifact_id']
with self.assertRaises(ArgumentUsageError):
_update_artifacts([invalid_artifact], self.lab_resource_id)
+
+ def test_expiration_date_with_and_without_timezone(self):
+ for suffix in ['', 'Z', '+02:00', '-05:00']:
+ with self.subTest(suffix=suffix):
+ args = mock.Mock()
+ args.expiration_date.to_serialized_data.return_value = '2999-01-01T00:00:00' + suffix
+ _validate_expiration_date(args)
+ args.expiration_date.to_serialized_data.return_value = '2000-01-01T00:00:00' + suffix
+ with self.assertRaises(ArgumentUsageError):
+ _validate_expiration_date(args)
diff --git a/src/azure-cli/azure/cli/command_modules/lab/validators.py b/src/azure-cli/azure/cli/command_modules/lab/validators.py
index 6cf9bcbc450..77ef72a7536 100644
--- a/src/azure-cli/azure/cli/command_modules/lab/validators.py
+++ b/src/azure-cli/azure/cli/command_modules/lab/validators.py
@@ -115,7 +115,9 @@ def _validate_expiration_date(args):
if has_value(args.expiration_date):
import datetime
import dateutil.parser
- if datetime.datetime.utcnow() >= dateutil.parser.parse(args.expiration_date.to_serialized_data()):
+ expiration_date = dateutil.parser.parse(args.expiration_date.to_serialized_data())
+ expiration_date = expiration_date.replace(tzinfo=expiration_date.tzinfo or datetime.UTC)
+ if datetime.datetime.now(datetime.UTC) >= expiration_date:
raise ArgumentUsageError(
"Expiration date '{}' must be in future.".format(args.expiration_date.to_serialized_data()))
diff --git a/src/azure-cli/azure/cli/command_modules/marketplaceordering/tests/__init__.py b/src/azure-cli/azure/cli/command_modules/marketplaceordering/tests/__init__.py
index ba281d0650b..73e0338f818 100644
--- a/src/azure-cli/azure/cli/command_modules/marketplaceordering/tests/__init__.py
+++ b/src/azure-cli/azure/cli/command_modules/marketplaceordering/tests/__init__.py
@@ -61,14 +61,14 @@ def wrapper(*args, **kwargs):
test_map[func.__name__]["error_message"] = ""
test_map[func.__name__]["error_stack"] = ""
test_map[func.__name__]["error_normalized"] = ""
- test_map[func.__name__]["start_dt"] = dt.datetime.utcnow()
+ test_map[func.__name__]["start_dt"] = dt.datetime.now(dt.UTC)
ret = func_to_call(*args, **kwargs)
except (AssertionError, AzureError, CliTestError, CliExecutionError, SystemExit,
JMESPathCheckAssertionError) as e:
use_exception_cache = os.getenv("TEST_EXCEPTION_CACHE")
if use_exception_cache is None or use_exception_cache.lower() != "true":
raise
- test_map[func.__name__]["end_dt"] = dt.datetime.utcnow()
+ test_map[func.__name__]["end_dt"] = dt.datetime.now(dt.UTC)
test_map[func.__name__]["result"] = FAILED
test_map[func.__name__]["error_message"] = str(e).replace("\r\n", " ").replace("\n", " ")[:500]
test_map[func.__name__]["error_stack"] = traceback.format_exc().replace(
@@ -80,7 +80,7 @@ def wrapper(*args, **kwargs):
logger.info(traceback.format_exc())
exceptions.append((func.__name__, sys.exc_info()))
else:
- test_map[func.__name__]["end_dt"] = dt.datetime.utcnow()
+ test_map[func.__name__]["end_dt"] = dt.datetime.now(dt.UTC)
return ret
if inspect.isclass(func):
diff --git a/src/azure-cli/azure/cli/command_modules/monitor/_legacy/custom.py b/src/azure-cli/azure/cli/command_modules/monitor/_legacy/custom.py
index 7c37796989c..8bbff592c6f 100644
--- a/src/azure-cli/azure/cli/command_modules/monitor/_legacy/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/monitor/_legacy/custom.py
@@ -33,12 +33,12 @@ def list_activity_log(cmd, correlation_id=None, resource_group=None, resource_id
def _build_activity_log_odata_filter(correlation_id=None, resource_group=None, resource_id=None, resource_provider=None,
start_time=None, end_time=None, caller=None, status=None, offset=None):
- from datetime import datetime
+ from datetime import UTC, datetime
import dateutil.parser
if not start_time and not end_time:
# if neither value provided, end_time is now
- end_time = datetime.utcnow().isoformat()
+ end_time = datetime.now(UTC).isoformat()
if not start_time:
# if no start_time, apply offset backwards from end_time
start_time = (dateutil.parser.parse(end_time) - offset).isoformat()
@@ -108,13 +108,13 @@ def list_metrics(cmd, resource,
metadata=None, dimension=None, aggregation=None, metrics=None,
filters=None, metric_namespace=None, orderby=None, top=10):
- from datetime import datetime
+ from datetime import UTC, datetime
import dateutil.parser
from urllib.parse import quote_plus
if not start_time and not end_time:
# if neither value provided, end_time is now
- end_time = datetime.utcnow().isoformat()
+ end_time = datetime.now(UTC).isoformat()
if not start_time:
# if no start_time, apply offset backwards from end_time
start_time = (dateutil.parser.parse(end_time) - offset).isoformat()
diff --git a/src/azure-cli/azure/cli/command_modules/monitor/custom.py b/src/azure-cli/azure/cli/command_modules/monitor/custom.py
index e94e814d847..1d6bf1680e9 100644
--- a/src/azure-cli/azure/cli/command_modules/monitor/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/monitor/custom.py
@@ -33,12 +33,12 @@ def list_activity_log(cmd, correlation_id=None, resource_group=None, resource_id
def _build_activity_log_odata_filter(correlation_id=None, resource_group=None, resource_id=None, resource_provider=None,
start_time=None, end_time=None, caller=None, status=None, offset=None):
- from datetime import datetime
+ from datetime import UTC, datetime
import dateutil.parser
if not start_time and not end_time:
# if neither value provided, end_time is now
- end_time = datetime.utcnow().isoformat()
+ end_time = datetime.now(UTC).isoformat()
if not start_time:
# if no start_time, apply offset backwards from end_time
start_time = (dateutil.parser.parse(end_time) - offset).isoformat()
@@ -108,13 +108,13 @@ def list_metrics(cmd, resource,
metadata=None, dimension=None, aggregation=None, metrics=None,
filters=None, metric_namespace=None, orderby=None, top=10):
- from datetime import datetime
+ from datetime import UTC, datetime
import dateutil.parser
from urllib.parse import quote_plus
if not start_time and not end_time:
# if neither value provided, end_time is now
- end_time = datetime.utcnow().isoformat()
+ end_time = datetime.now(UTC).isoformat()
if not start_time:
# if no start_time, apply offset backwards from end_time
start_time = (dateutil.parser.parse(end_time) - offset).isoformat()
diff --git a/src/azure-cli/azure/cli/command_modules/mysql/_util.py b/src/azure-cli/azure/cli/command_modules/mysql/_util.py
index 7e20ebf304b..064ef9df6a5 100644
--- a/src/azure-cli/azure/cli/command_modules/mysql/_util.py
+++ b/src/azure-cli/azure/cli/command_modules/mysql/_util.py
@@ -15,8 +15,7 @@
import sys
import yaml
from time import sleep
-import datetime as dt
-from datetime import datetime
+from datetime import UTC, datetime
from knack.log import get_logger
from knack.arguments import ignore_type
from knack.prompting import prompt_pass, prompt_y_n, NoTTYException
@@ -326,7 +325,7 @@ def _map_maintenance_window(day_of_week):
def get_current_time():
- return datetime.utcnow().replace(tzinfo=dt.timezone.utc, microsecond=0).isoformat()
+ return datetime.now(UTC).replace(microsecond=0).isoformat()
def get_id_components(rid):
@@ -616,7 +615,7 @@ def get_firewall_rules_from_paged_response(firewall_rules):
def get_current_utc_time():
- return datetime.utcnow().replace(tzinfo=dt.timezone.utc)
+ return datetime.now(UTC)
class ImportFromStorageState(Enum):
diff --git a/src/azure-cli/azure/cli/command_modules/mysql/custom.py b/src/azure-cli/azure/cli/command_modules/mysql/custom.py
index 901a00ead35..7ac6286c76c 100644
--- a/src/azure-cli/azure/cli/command_modules/mysql/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/mysql/custom.py
@@ -8,8 +8,7 @@
import re
import math
-from datetime import datetime, timedelta
-from dateutil.tz import tzutc
+from datetime import UTC, datetime, timedelta
from knack.log import get_logger
from urllib.request import urlretrieve
from importlib import import_module
@@ -273,7 +272,7 @@ def flexible_server_log_list(client, resource_group_name, server_name, filename_
if file_last_written is None:
file_last_written = 72
- time_line = datetime.utcnow().replace(tzinfo=tzutc()) - timedelta(hours=file_last_written)
+ time_line = datetime.now(UTC) - timedelta(hours=file_last_written)
for f in all_files:
if f.last_modified_time < time_line:
diff --git a/src/azure-cli/azure/cli/command_modules/mysql/tests/latest/test_mysql_scenario.py b/src/azure-cli/azure/cli/command_modules/mysql/tests/latest/test_mysql_scenario.py
index e4338270c43..369936f086d 100644
--- a/src/azure-cli/azure/cli/command_modules/mysql/tests/latest/test_mysql_scenario.py
+++ b/src/azure-cli/azure/cli/command_modules/mysql/tests/latest/test_mysql_scenario.py
@@ -7,10 +7,9 @@
import uuid
import unittest
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
from time import sleep
from dateutil import parser
-from dateutil.tz import tzutc
from azure.cli.testsdk.scenario_tests import AllowLargeResponse
from azure.cli.testsdk.base import execute
from azure.cli.testsdk.scenario_tests.const import ENV_LIVE_TEST
@@ -458,7 +457,7 @@ def _test_flexible_server_restore_mgmt(self, database_engine, resource_group):
result = self.cmd('{} flexible-server show -g {} -n {}'.format(database_engine, resource_group, source_server)).get_output_in_json()
# Wait until snapshot is created
- current_time = datetime.utcnow().replace(tzinfo=tzutc()).isoformat()
+ current_time = datetime.now(UTC).isoformat()
earliest_restore_time = result['backup']['earliestRestoreDate']
seconds_to_wait = (parser.isoparse(earliest_restore_time) - parser.isoparse(current_time)).total_seconds()
os.environ.get(ENV_LIVE_TEST, False) and sleep(max(0, seconds_to_wait) + 180)
@@ -690,7 +689,7 @@ def _test_flexible_server_georestore_update_mgmt(self, database_engine, resource
.format(database_engine, resource_group, source_server),
checks=[JMESPathCheck('backup.geoRedundantBackup', 'Enabled')]).get_output_in_json()
- current_time = datetime.utcnow().replace(tzinfo=tzutc()).isoformat()
+ current_time = datetime.now(UTC).isoformat()
earliest_restore_time = result['backup']['earliestRestoreDate']
seconds_to_wait = (parser.isoparse(earliest_restore_time) - parser.isoparse(current_time)).total_seconds()
os.environ.get(ENV_LIVE_TEST, False) and sleep(max(0, seconds_to_wait) + 1200)
@@ -936,7 +935,7 @@ def main_tests(geo_redundant_backup):
expect_failure=True)
# restore backup
- current_time = datetime.utcnow().replace(tzinfo=tzutc()).isoformat()
+ current_time = datetime.now(UTC).isoformat()
earliest_restore_time = result['backup']['earliestRestoreDate']
seconds_to_wait = (parser.isoparse(earliest_restore_time) - parser.isoparse(current_time)).total_seconds()
sleep(max(0, seconds_to_wait))
@@ -1519,7 +1518,7 @@ def _test_mysql_flexible_server_public_access_georestore(self, database_engine,
restore_server = self.cmd('resource show --id {} --api-version {}'.format(result['id'], api_version)).get_output_in_json()
- current_time = datetime.utcnow().replace(tzinfo=tzutc()).isoformat()
+ current_time = datetime.now(UTC).isoformat()
earliest_restore_time = restore_server['properties']['backup']['earliestRestoreDate']
seconds_to_wait = (parser.isoparse(earliest_restore_time) - parser.isoparse(current_time)).total_seconds()
time.sleep(max(0, seconds_to_wait) + 180)
@@ -1542,7 +1541,7 @@ def _test_mysql_flexible_server_public_access_restore(self, database_engine, res
restore_server = self.cmd('resource show --id {} --api-version {}'.format(result['id'], api_version)).get_output_in_json()
- current_time = datetime.utcnow().replace(tzinfo=tzutc()).isoformat()
+ current_time = datetime.now(UTC).isoformat()
earliest_restore_time = restore_server['properties']['backup']['earliestRestoreDate']
seconds_to_wait = (parser.isoparse(earliest_restore_time) - parser.isoparse(current_time)).total_seconds()
print(current_time)
@@ -2408,7 +2407,7 @@ def _test_flexible_server_export_create_mgmt(self, database_engine, resource_gro
# Create the blob container
container = self.create_container(target_account_info)
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
self.kwargs.update({
'expiry': expiry,
diff --git a/src/azure-cli/azure/cli/command_modules/netappfiles/tests/latest/test_bucket_commands.py b/src/azure-cli/azure/cli/command_modules/netappfiles/tests/latest/test_bucket_commands.py
index 6489a740e7d..c9816fa2737 100644
--- a/src/azure-cli/azure/cli/command_modules/netappfiles/tests/latest/test_bucket_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/netappfiles/tests/latest/test_bucket_commands.py
@@ -39,8 +39,8 @@ def _generate_self_signed_cert(fqdn):
.issuer_name(issuer)
.public_key(key.public_key())
.serial_number(x509.random_serial_number())
- .not_valid_before(datetime.datetime.utcnow())
- .not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=365))
+ .not_valid_before(datetime.datetime.now(datetime.UTC))
+ .not_valid_after(datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=365))
.sign(key, hashes.SHA256())
)
pem_data = cert.public_bytes(serialization.Encoding.PEM) + key.private_bytes(
diff --git a/src/azure-cli/azure/cli/command_modules/network/tests/latest/test_network_commands.py b/src/azure-cli/azure/cli/command_modules/network/tests/latest/test_network_commands.py
index c12e4b8d5a9..fdd94694d76 100644
--- a/src/azure-cli/azure/cli/command_modules/network/tests/latest/test_network_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/network/tests/latest/test_network_commands.py
@@ -6596,11 +6596,7 @@ class VpnConnectionAuthenticationScenarioTest(ScenarioTest):
@staticmethod
def _get_now_utc():
import datetime
- try:
- from datetime import timezone
- return datetime.datetime.now(timezone.utc)
- except ImportError:
- return datetime.datetime.utcnow()
+ return datetime.datetime.now(datetime.UTC)
@staticmethod
def _format_subject_dn(common_name: str):
@@ -7715,7 +7711,7 @@ def __init__(self, method_name):
@ResourceGroupPreparer(name_prefix='cli_test_active_active_vnet_vnet_connection')
@StorageAccountPreparer(name_prefix='clitestvpncnn')
def test_network_active_active_vnet_connection(self, resource_group, storage_account):
- from datetime import datetime, timedelta
+ from datetime import UTC, datetime, timedelta
self.kwargs.update({
'subnet': 'GatewaySubnet',
'vnet1': 'vnet1',
@@ -7739,7 +7735,7 @@ def test_network_active_active_vnet_connection(self, resource_group, storage_acc
'bgp_peer2': '10.53.255.253',
'storage_account': storage_account,
'ctn': self.create_random_name(prefix='clitestvpngw', length=24),
- 'expiry': (datetime.utcnow() + timedelta(hours=3)).strftime('%Y-%m-%dT%H:%MZ')
+ 'expiry': (datetime.now(UTC) + timedelta(hours=3)).strftime('%Y-%m-%dT%H:%MZ')
})
self.cmd('storage container create --account-name {storage_account} --name {ctn}')
@@ -7993,7 +7989,7 @@ def test_network_vpn_gateway_disconnect_connects(self, resource_group):
@ResourceGroupPreparer(name_prefix='cli_test_vpn_gateway_package_capture', location='westus')
@StorageAccountPreparer(name_prefix='clitestvpngw')
def test_network_vpn_gateway_package_capture(self, resource_group, storage_account):
- from datetime import datetime, timedelta
+ from datetime import UTC, datetime, timedelta
self.kwargs.update({
'vnet1': 'myvnet1',
'gw1': 'gateway1',
@@ -8001,7 +7997,7 @@ def test_network_vpn_gateway_package_capture(self, resource_group, storage_accou
'ip1': 'pubip1',
'storage_account': storage_account,
'ctn': self.create_random_name(prefix='clitestvpngw', length=24),
- 'expiry': (datetime.utcnow() + timedelta(hours=3)).strftime('%Y-%m-%dT%H:%MZ')
+ 'expiry': (datetime.now(UTC) + timedelta(hours=3)).strftime('%Y-%m-%dT%H:%MZ')
})
self.cmd('storage container create --account-name {storage_account} --name {ctn}')
@@ -8037,12 +8033,7 @@ def _generate_p2s_root_cert_public_file(cert_path, common_name="VpnGatewayAuthCe
from cryptography.hazmat.backends import default_backend
import datetime
- # timezone-aware now
- try:
- from datetime import timezone
- now = datetime.datetime.now(timezone.utc)
- except ImportError:
- now = datetime.datetime.utcnow()
+ now = datetime.datetime.now(datetime.UTC)
# Root key (private key not exported; we only write public cert)
root_key = rsa.generate_private_key(
diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/backup_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/backup_commands.py
index a2416c33e39..4aef2082653 100644
--- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/backup_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/backup_commands.py
@@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------
# pylint: disable=unused-argument, line-too-long
-from datetime import datetime
+from datetime import UTC, datetime
from azure.cli.core.util import user_confirmation
from knack.log import get_logger
from ..utils.validators import validate_resource_group, validate_backup_name
@@ -20,7 +20,7 @@ def _generate_backup_name(client, resource_group_name, server_name):
on_demand_count = sum(1 for name in existing_names if name.startswith(_BACKUP_NAME_PREFIX))
- date_str = datetime.utcnow().strftime("%m%d%Y")
+ date_str = datetime.now(UTC).strftime("%m%d%Y")
suffix = on_demand_count + 1
backup_name = f"{_BACKUP_NAME_PREFIX}-{date_str}-{suffix}"
while backup_name in existing_names:
diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/server_logs_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/server_logs_commands.py
index c690751be77..d90b96817a5 100644
--- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/server_logs_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/server_logs_commands.py
@@ -7,8 +7,7 @@
import re
from azure.cli.core.util import CLIError, user_confirmation
-from datetime import datetime, timedelta
-from dateutil.tz import tzutc # pylint: disable=import-error
+from datetime import UTC, datetime, timedelta
from knack.log import get_logger
from urllib.request import urlretrieve
from .._client_factory import cf_postgres_flexible_replica
@@ -62,7 +61,7 @@ def flexible_server_list_log_files_with_filter(client, resource_group_name, serv
if file_last_written is None:
file_last_written = 72
- time_line = datetime.utcnow().replace(tzinfo=tzutc()) - timedelta(hours=file_last_written)
+ time_line = datetime.now(UTC) - timedelta(hours=file_last_written)
for f in all_files:
if f.last_modified_time < time_line:
@@ -86,7 +85,7 @@ def flexible_server_log_list(client, resource_group_name, server_name, filename_
if file_last_written is None:
file_last_written = 72
- time_line = datetime.utcnow().replace(tzinfo=tzutc()) - timedelta(hours=file_last_written)
+ time_line = datetime.now(UTC) - timedelta(hours=file_last_written)
for f in all_files:
if f.last_modified_time < time_line:
diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/utils/_flexible_server_util.py b/src/azure-cli/azure/cli/command_modules/postgresql/utils/_flexible_server_util.py
index 9957faeb0e2..198d655fbb3 100644
--- a/src/azure-cli/azure/cli/command_modules/postgresql/utils/_flexible_server_util.py
+++ b/src/azure-cli/azure/cli/command_modules/postgresql/utils/_flexible_server_util.py
@@ -4,8 +4,7 @@
# --------------------------------------------------------------------------------------------
# pylint: disable=unused-argument, line-too-long, import-outside-toplevel, raise-missing-from
-import datetime as dt
-from datetime import datetime
+from datetime import UTC, datetime
import os
import random
import subprocess
@@ -201,7 +200,7 @@ def _map_maintenance_window(day_of_week):
def get_current_time():
- return datetime.utcnow().replace(tzinfo=dt.timezone.utc, microsecond=0).isoformat()
+ return datetime.now(UTC).replace(microsecond=0).isoformat()
def get_id_components(rid):
diff --git a/src/azure-cli/azure/cli/command_modules/rdbms/_flexible_server_util.py b/src/azure-cli/azure/cli/command_modules/rdbms/_flexible_server_util.py
index c870582db9c..6bc966762b5 100644
--- a/src/azure-cli/azure/cli/command_modules/rdbms/_flexible_server_util.py
+++ b/src/azure-cli/azure/cli/command_modules/rdbms/_flexible_server_util.py
@@ -4,8 +4,7 @@
# --------------------------------------------------------------------------------------------
# pylint: disable=unused-argument, line-too-long, import-outside-toplevel, raise-missing-from
-import datetime as dt
-from datetime import datetime
+from datetime import UTC, datetime
import os
import random
import subprocess
@@ -246,7 +245,7 @@ def _map_maintenance_window(day_of_week):
def get_current_time():
- return datetime.utcnow().replace(tzinfo=dt.timezone.utc, microsecond=0).isoformat()
+ return datetime.now(UTC).replace(microsecond=0).isoformat()
def get_id_components(rid):
diff --git a/src/azure-cli/azure/cli/command_modules/rdbms/custom.py b/src/azure-cli/azure/cli/command_modules/rdbms/custom.py
index 13d644df06f..3c787b8b91b 100644
--- a/src/azure-cli/azure/cli/command_modules/rdbms/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/rdbms/custom.py
@@ -4,10 +4,9 @@
# --------------------------------------------------------------------------------------------
# pylint: disable=unused-argument, line-too-long
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
from importlib import import_module
import re
-from dateutil.tz import tzutc # pylint: disable=import-error
from knack.log import get_logger
from knack.util import todict
from urllib.request import urlretrieve
@@ -603,7 +602,7 @@ def _list_log_files_with_filter(client, resource_group_name, server_name, filena
if file_last_written is None:
file_last_written = 72
- time_line = datetime.utcnow().replace(tzinfo=tzutc()) - timedelta(hours=file_last_written)
+ time_line = datetime.now(UTC) - timedelta(hours=file_last_written)
for f in all_files:
if f.last_modified_time < time_line:
diff --git a/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_custom_common.py b/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_custom_common.py
index 6974f6951ba..6aa639b21f4 100644
--- a/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_custom_common.py
+++ b/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_custom_common.py
@@ -6,8 +6,7 @@
# pylint: disable=unused-argument, line-too-long
import re
-from datetime import datetime, timedelta
-from dateutil.tz import tzutc
+from datetime import UTC, datetime, timedelta
from knack.log import get_logger
from knack.util import CLIError
from urllib.request import urlretrieve
@@ -228,7 +227,7 @@ def flexible_server_log_list(client, resource_group_name, server_name, filename_
if file_last_written is None:
file_last_written = 72
- time_line = datetime.utcnow().replace(tzinfo=tzutc()) - timedelta(hours=file_last_written)
+ time_line = datetime.now(UTC) - timedelta(hours=file_last_written)
for f in all_files:
if f.last_modified_time < time_line:
diff --git a/src/azure-cli/azure/cli/command_modules/rdbms/tests/latest/test_rdbms_commands.py b/src/azure-cli/azure/cli/command_modules/rdbms/tests/latest/test_rdbms_commands.py
index 9150f66feec..a9883870a8d 100644
--- a/src/azure-cli/azure/cli/command_modules/rdbms/tests/latest/test_rdbms_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/rdbms/tests/latest/test_rdbms_commands.py
@@ -4,8 +4,7 @@
# --------------------------------------------------------------------------------------------
import time
-from datetime import datetime
-from dateutil.tz import tzutc # pylint: disable=import-error
+from datetime import UTC, datetime
from azure.cli.testsdk.scenario_tests import AllowLargeResponse
from azure.core.exceptions import HttpResponseError
from azure.cli.core.util import CLIError
@@ -223,7 +222,7 @@ def _test_server_mgmt(self, database_engine, resource_group_1, resource_group_2)
JMESPathCheck('administratorLogin', admin_login)])
# Before we do restore we will have to check whether the current time is less than earliest restore time
- current_time = datetime.utcnow().replace(tzinfo=tzutc()).isoformat()
+ current_time = datetime.now(UTC).isoformat()
earliest_restore_time = result['earliestRestoreDate']
date_format = '%Y-%m-%dT%H:%M:%S.%f+00:00'
diff --git a/src/azure-cli/azure/cli/command_modules/redis/tests/latest/test_redis_scenario.py b/src/azure-cli/azure/cli/command_modules/redis/tests/latest/test_redis_scenario.py
index 9b6ecf1a569..9e174d43195 100644
--- a/src/azure-cli/azure/cli/command_modules/redis/tests/latest/test_redis_scenario.py
+++ b/src/azure-cli/azure/cli/command_modules/redis/tests/latest/test_redis_scenario.py
@@ -309,8 +309,8 @@ def test_redis_cache_export_import(self, resource_group):
'containerName': "testcontainer",
'userIdentity': user_identity,
'storageSubscriptionId': "6364f508-1150-4431-b973-c3f133466e56", # replace it with your subscription id while running tests in live mode
- 'startTime': (datetime.datetime.utcnow() - datetime.timedelta(minutes=60)).strftime(f"%Y-%m-%dT%H:%MZ"),
- 'expiryTime': (datetime.datetime.utcnow() + datetime.timedelta(minutes=200)).strftime(f"%Y-%m-%dT%H:%MZ")
+ 'startTime': (datetime.datetime.now(datetime.UTC) - datetime.timedelta(minutes=60)).strftime("%Y-%m-%dT%H:%MZ"),
+ 'expiryTime': (datetime.datetime.now(datetime.UTC) + datetime.timedelta(minutes=200)).strftime("%Y-%m-%dT%H:%MZ")
}
if self.is_live :
diff --git a/src/azure-cli/azure/cli/command_modules/resource/tests/latest/test_resource.py b/src/azure-cli/azure/cli/command_modules/resource/tests/latest/test_resource.py
index 3875c8c1501..2c947da715b 100644
--- a/src/azure-cli/azure/cli/command_modules/resource/tests/latest/test_resource.py
+++ b/src/azure-cli/azure/cli/command_modules/resource/tests/latest/test_resource.py
@@ -1331,8 +1331,8 @@ def test_resource_group_level_deployment_with_query_string(self, resource_group,
self.cmd('storage blob upload -c {container_name} -f "{tf}" -n mainTemplate --account-name {storage_account} --account-key {storage_key}')
self.cmd('storage blob upload -c {container_name} -f "{linked_tf}" -n storage_account_linked_template.json --account-name {storage_account} --account-key {storage_key}')
- from datetime import datetime, timedelta
- self.kwargs['expiry'] = (datetime.utcnow() + timedelta(hours=12)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ self.kwargs['expiry'] = (datetime.now(UTC) + timedelta(hours=12)).strftime('%Y-%m-%dT%H:%MZ')
self.kwargs['sas_token'] = self.cmd(
'storage container generate-sas --account-name {storage_account} --account-key {storage_key} --name {container_name} --permissions rw --expiry {expiry} -otsv').output.strip()
@@ -1379,8 +1379,8 @@ def test_subscription_level_deployment_with_query_string(self, resource_group, r
self.cmd('storage blob upload -c {container_name} -f "{linked_tf1}" -n createKeyVault.json --account-name {storage_account} --account-key {storage_key}')
self.cmd('storage blob upload -c {container_name} -f "{linked_tf2}" -n createKeyVaultWithSecret.json --account-name {storage_account} --account-key {storage_key}')
- from datetime import datetime, timedelta
- self.kwargs['expiry'] = (datetime.utcnow() + timedelta(hours=12)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ self.kwargs['expiry'] = (datetime.now(UTC) + timedelta(hours=12)).strftime('%Y-%m-%dT%H:%MZ')
self.kwargs['sas_token'] = self.cmd(
'storage container generate-sas --account-name {storage_account} --name {container_name} --permissions dlrw --expiry {expiry} --https-only -otsv').output.strip()
diff --git a/src/azure-cli/azure/cli/command_modules/role/custom.py b/src/azure-cli/azure/cli/command_modules/role/custom.py
index 279ad0d219b..687bdd7c80d 100644
--- a/src/azure-cli/azure/cli/command_modules/role/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/role/custom.py
@@ -489,15 +489,15 @@ def _get_assignment_events(cli_ctx, start_time=None, end_time=None):
DATE_TIME_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
if end_time:
try:
- end_time = datetime.datetime.strptime(end_time, DATE_TIME_FORMAT)
+ end_time = datetime.datetime.strptime(end_time, DATE_TIME_FORMAT).replace(tzinfo=datetime.UTC)
except ValueError:
raise CLIError("Input '{}' is not valid datetime. Valid example: 2000-12-31T12:59:59Z".format(end_time))
else:
- end_time = datetime.datetime.utcnow()
+ end_time = datetime.datetime.now(datetime.UTC)
if start_time:
try:
- start_time = datetime.datetime.strptime(start_time, DATE_TIME_FORMAT)
+ start_time = datetime.datetime.strptime(start_time, DATE_TIME_FORMAT).replace(tzinfo=datetime.UTC)
if start_time >= end_time:
raise CLIError("Start time cannot be later than end time.")
except ValueError:
@@ -1493,7 +1493,7 @@ def create_service_principal_for_rbac(
if not display_name:
# No display name is provided, create a new one
- app_display_name = 'azure-cli-' + datetime.datetime.utcnow().strftime('%Y-%m-%d-%H-%M-%S')
+ app_display_name = 'azure-cli-' + datetime.datetime.now(datetime.UTC).strftime('%Y-%m-%d-%H-%M-%S')
else:
app_display_name = display_name
# patch existing app with the same displayName to make the command idempotent
@@ -1980,7 +1980,7 @@ def _build_key_credentials(key_value=None, key_type=None, key_usage=None,
return []
if not start_date:
- start_date = datetime.datetime.utcnow()
+ start_date = datetime.datetime.now(datetime.UTC)
elif isinstance(start_date, str):
start_date = dateutil.parser.parse(start_date)
diff --git a/src/azure-cli/azure/cli/command_modules/role/tests/latest/test_role.py b/src/azure-cli/azure/cli/command_modules/role/tests/latest/test_role.py
index 165fffd8998..79f576dbf43 100644
--- a/src/azure-cli/azure/cli/command_modules/role/tests/latest/test_role.py
+++ b/src/azure-cli/azure/cli/command_modules/role/tests/latest/test_role.py
@@ -698,7 +698,7 @@ def test_role_assignment_audits(self, resource_group):
self.cmd('role assignment create --assignee {upn} --role reader --scope {rg_id}')
if self.is_live or self.in_recording:
- now = datetime.datetime.utcnow()
+ now = datetime.datetime.now(datetime.UTC)
start = now - datetime.timedelta(minutes=1)
end = now + datetime.timedelta(minutes=1)
start_time = '{}-{}-{}T{}:{}:{}Z'.format(start.year, start.month, start.day, start.hour,
diff --git a/src/azure-cli/azure/cli/command_modules/role/tests/latest/test_role_custom.py b/src/azure-cli/azure/cli/command_modules/role/tests/latest/test_role_custom.py
index 8e62ee971df..f89ec64703a 100644
--- a/src/azure-cli/azure/cli/command_modules/role/tests/latest/test_role_custom.py
+++ b/src/azure-cli/azure/cli/command_modules/role/tests/latest/test_role_custom.py
@@ -26,3 +26,12 @@ def test_resolve_role_id(self, ):
# action (using a full id)
test_full_id = '/subscriptions/0b1f6471-1bf0-4dda-aec3-cb9272123456/providers/microsoft.authorization/roleDefinitions/5370bbf4-6b73-4417-969b-8f2e6e123456'
self.assertEqual(test_full_id, _resolve_role_id(test_full_id, 'foobar', mock_client))
+
+ @mock.patch('azure.cli.core.commands.client_factory.get_mgmt_service_client')
+ def test_assignment_events_with_start_time_and_default_end_time(self, get_client):
+ from azure.cli.command_modules.role.custom import _get_assignment_events
+
+ get_client.return_value.activity_logs.list.return_value = []
+ _get_assignment_events(mock.Mock(), start_time='2000-01-01T00:00:00Z')
+ event_filter = get_client.return_value.activity_logs.list.call_args.kwargs['filter']
+ self.assertIn('eventTimestamp ge 2000-01-01T00:00:00Z', event_filter)
diff --git a/src/azure-cli/azure/cli/command_modules/sql/tests/latest/test_sql_commands.py b/src/azure-cli/azure/cli/command_modules/sql/tests/latest/test_sql_commands.py
index c6e90b95630..8ea906b9467 100644
--- a/src/azure-cli/azure/cli/command_modules/sql/tests/latest/test_sql_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/sql/tests/latest/test_sql_commands.py
@@ -33,7 +33,7 @@
ClientType,
ComputeModelType,
ResourceIdType)
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
# Constants
@@ -2045,12 +2045,12 @@ def _create_db_wait_for_first_backup(test, resource_group, server, database_name
db = test.cmd('sql db show -g {} -s {} -n {}'
.format(resource_group, server, database_name)).get_output_in_json()
- earliest_restore_date = _get_earliest_restore_date(db)
+ earliest_restore_date = _get_earliest_restore_date(db).replace(tzinfo=UTC)
- if datetime.utcnow() <= earliest_restore_date:
+ if datetime.now(UTC) <= earliest_restore_date:
print('Waiting until earliest restore date', earliest_restore_date)
- while datetime.utcnow() <= earliest_restore_date:
+ while datetime.now(UTC) <= earliest_restore_date:
time.sleep(10)
return db
@@ -5378,7 +5378,7 @@ def test_sql_zone_resilient_restore_hyperscale_database(self, resource_group, se
# Verify restored vldb has correct values (specifically zone redundancy == true and backup storage redundancy == Zone)
self.cmd('sql db restore -g {} --server {} --name {} --dest-name {} --time {} '
'--edition {} --family {} --capacity {} --backup-storage-redundancy {} --z'
- .format(resource_group, server, source_non_zr_db_name, restore_source_non_zr_true_param_db_name, datetime.utcnow().isoformat(),
+ .format(resource_group, server, source_non_zr_db_name, restore_source_non_zr_true_param_db_name, datetime.now(UTC).isoformat(),
"Hyperscale", 'Gen5', 2, 'zone'),
checks=[
JMESPathCheck('resourceGroup', resource_group),
@@ -5389,7 +5389,7 @@ def test_sql_zone_resilient_restore_hyperscale_database(self, resource_group, se
# Restore zone redundant source vldb with zone redundancy == false
# Verify restored vldb has correct values (specifically zone redundancy == false and backup storage redundancy == Zone)
self.cmd('sql db restore -g {} --server {} --name {} --dest-name {} --time {} --z {}'
- .format(resource_group, server, source_zr_db_name, restore_source_zr_false_param_db_name, datetime.utcnow().isoformat(), False),
+ .format(resource_group, server, source_zr_db_name, restore_source_zr_false_param_db_name, datetime.now(UTC).isoformat(), False),
checks=[
JMESPathCheck('resourceGroup', resource_group),
JMESPathCheck('name', restore_source_zr_false_param_db_name),
@@ -5400,7 +5400,7 @@ def test_sql_zone_resilient_restore_hyperscale_database(self, resource_group, se
# Restore non zone redundant source vldb with no parameters passed in
# Verify restored vldb has correct values (specifically zone redundancy == false and backup storage redundancy == Geo)
self.cmd('sql db restore -g {} --server {} --name {} --dest-name {} --time {}'
- .format(resource_group, server, source_non_zr_db_name, restore_source_non_zr_no_param_db_name, datetime.utcnow().isoformat()),
+ .format(resource_group, server, source_non_zr_db_name, restore_source_non_zr_no_param_db_name, datetime.now(UTC).isoformat()),
checks=[
JMESPathCheck('resourceGroup', resource_group),
JMESPathCheck('name', restore_source_non_zr_no_param_db_name),
@@ -5410,7 +5410,7 @@ def test_sql_zone_resilient_restore_hyperscale_database(self, resource_group, se
# Restore zone redundant source vldb with no parameters passed in
# Verify restored vldb has correct values (specifically zone redundancy == true and backup storage redundancy == Zone)
self.cmd('sql db restore -g {} --server {} --name {} --dest-name {} --time {}'
- .format(resource_group, server, source_zr_db_name, restore_source_zr_no_param_db_name, datetime.utcnow().isoformat()),
+ .format(resource_group, server, source_zr_db_name, restore_source_zr_no_param_db_name, datetime.now(UTC).isoformat()),
checks=[
JMESPathCheck('resourceGroup', resource_group),
JMESPathCheck('name', restore_source_zr_no_param_db_name),
@@ -6582,7 +6582,7 @@ def test_sql_managed_db_mgmt(self, mi, rg):
# test sql db restore command
# db1 = self.cmd('sql midb restore -g {} --mi {} -n {} --dest-name {} --time {}'
# .format(resource_group_1, managed_instance_name_1, database_name, database_name_restored,
- # datetime.utcnow().isoformat()),
+ # datetime.now(UTC).isoformat()),
# checks=[
# JMESPathCheck('resourceGroup', resource_group_1),
# JMESPathCheck('name', database_name_restored),
@@ -7870,8 +7870,8 @@ def test_sql_midb_logreplay_mgmt(self, mi, rg):
'last_backup_name': 'full.bak'
})
- from datetime import datetime, timedelta
- self.kwargs['expiry'] = (datetime.utcnow() + timedelta(hours=12)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ self.kwargs['expiry'] = (datetime.now(UTC) + timedelta(hours=12)).strftime('%Y-%m-%dT%H:%MZ')
self.kwargs['storage_key'] = str(self.cmd(
'az storage account keys list -n {storage_account} -g {resource_group} --query "[0].value"').output)
diff --git a/src/azure-cli/azure/cli/command_modules/storage/_validators.py b/src/azure-cli/azure/cli/command_modules/storage/_validators.py
index 0caee9ed3d5..2ba271842b9 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/_validators.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/_validators.py
@@ -506,9 +506,9 @@ def validate_source_url(cmd, namespace): # pylint: disable=too-many-statements,
if valid_blob_source:
client = cf_blob_service(cmd.cli_ctx, client_kwargs)
- from datetime import datetime, timedelta
- start = datetime.utcnow()
- expiry = datetime.utcnow() + timedelta(days=1)
+ from datetime import UTC, datetime, timedelta
+ start = datetime.now(UTC)
+ expiry = datetime.now(UTC) + timedelta(days=1)
source_user_delegation_key = client.get_user_delegation_key(start, expiry)
# Both source account name and either key or sas (or both) are now available
@@ -1559,8 +1559,8 @@ def as_user_validator(namespace):
expiry = get_datetime_type(False)(namespace.expiry)
- from datetime import datetime, timedelta
- if expiry > datetime.utcnow() + timedelta(days=7):
+ from datetime import UTC, datetime, timedelta
+ if expiry.replace(tzinfo=UTC) > datetime.now(UTC) + timedelta(days=7):
raise argparse.ArgumentError(
None, 'incorrect usage: --expiry should be within 7 days from now')
diff --git a/src/azure-cli/azure/cli/command_modules/storage/operations/blob.py b/src/azure-cli/azure/cli/command_modules/storage/operations/blob.py
index fef4f163baf..7973adb1e4a 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/operations/blob.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/operations/blob.py
@@ -5,7 +5,7 @@
import os
import sys
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
from azure.cli.core.profiles import ResourceType, get_sdk
from azure.cli.core.util import sdk_no_wait
@@ -888,7 +888,7 @@ def generate_sas_blob_uri(cmd, client, permission=None, expiry=None, start=None,
account_key = None
if as_user:
user_delegation_key = client.get_user_delegation_key(
- get_datetime_from_string(start) if start else datetime.utcnow(), get_datetime_from_string(expiry),
+ get_datetime_from_string(start) if start else datetime.now(UTC), get_datetime_from_string(expiry),
delegated_user_tid=user_delegation_tid)
else:
account_key = client.credential.account_key
@@ -938,7 +938,7 @@ def generate_container_shared_access_signature(cmd, client, container_name, perm
account_key = None
if as_user:
user_delegation_key = client.get_user_delegation_key(
- get_datetime_from_string(start) if start else datetime.utcnow(), get_datetime_from_string(expiry),
+ get_datetime_from_string(start) if start else datetime.now(UTC), get_datetime_from_string(expiry),
delegated_user_tid=user_delegation_tid)
else:
account_key = client.credential.account_key
@@ -974,8 +974,8 @@ def _copy_blob_to_blob_container(cmd, blob_service, source_blob_service, destina
# generate sas for oauth copy source
if not source_sas:
from ..util import create_short_lived_blob_sas_v2
- start = datetime.utcnow()
- expiry = datetime.utcnow() + timedelta(days=1)
+ start = datetime.now(UTC)
+ expiry = datetime.now(UTC) + timedelta(days=1)
source_user_delegation_key = source_blob_service.get_user_delegation_key(start, expiry)
source_sas = create_short_lived_blob_sas_v2(cmd, source_blob_service.account_name, source_container,
source_blob_name,
@@ -1010,8 +1010,8 @@ def _copy_file_to_blob_container(cmd, blob_service, source_file_service, destina
'_shared_access_signature#generate_share_sas')
t_file_permissions = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_FILESHARE,
'_models#FileSasPermissions')
- start = datetime.utcnow()
- expiry = datetime.utcnow() + timedelta(days=1)
+ start = datetime.now(UTC)
+ expiry = datetime.now(UTC) + timedelta(days=1)
source_sas = t_generate_share_sas(account_name=t_file_client.account_name, share_name=source_share,
account_key=t_file_client.credential.account_key,
permission=t_file_permissions(read=True),
@@ -1164,7 +1164,7 @@ def copy_blob(cmd, client, source_url, metadata=None, **kwargs):
as_user = True
if hasattr(blob_service_client.credential, 'account_key'):
as_user = False
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
source_url = generate_sas_blob_uri(cmd, blob_service_client, full_uri=True, blob_url=source_url,
blob_name=None, container_name=None, as_user=as_user,
expiry=expiry, permission='r')
diff --git a/src/azure-cli/azure/cli/command_modules/storage/operations/file.py b/src/azure-cli/azure/cli/command_modules/storage/operations/file.py
index f664cfd0ec2..ec45b5624ab 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/operations/file.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/operations/file.py
@@ -419,9 +419,9 @@ def _create_file_and_directory_from_blob(cmd, file_service, blob_service, share,
'_shared_access_signature#generate_blob_sas')
t_blob_permissions = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_BLOB,
'_models#BlobSasPermissions')
- from datetime import datetime, timedelta
- start = datetime.utcnow()
- expiry = datetime.utcnow() + timedelta(days=1)
+ from datetime import UTC, datetime, timedelta
+ start = datetime.now(UTC)
+ expiry = datetime.now(UTC) + timedelta(days=1)
source_sas = t_generate_blob_sas(account_name=blob_service.account_name, container_name=container,
blob_name=blob_name,
account_key=blob_service.credential.account_key,
@@ -468,9 +468,9 @@ def _create_file_and_directory_from_file(cmd, file_service, source_file_service,
'_shared_access_signature#generate_share_sas')
t_file_permissions = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_FILESHARE,
'_models#FileSasPermissions')
- from datetime import datetime, timedelta
- start = datetime.utcnow()
- expiry = datetime.utcnow() + timedelta(days=1)
+ from datetime import UTC, datetime, timedelta
+ start = datetime.now(UTC)
+ expiry = datetime.now(UTC) + timedelta(days=1)
source_sas = t_generate_share_sas(account_name=source_file_service.account_name, share_name=source_share,
account_key=source_file_service.credential.account_key,
permission=t_file_permissions(read=True),
@@ -554,9 +554,9 @@ def generate_sas_file(cmd, client, share_name=None, directory_name=None, file_na
account_key = None
user_delegation_key = None
if as_user:
- from datetime import datetime
+ from datetime import UTC, datetime
user_delegation_key = client.get_user_delegation_key(
- start=get_datetime_from_string(start) if start else datetime.utcnow(),
+ start=get_datetime_from_string(start) if start else datetime.now(UTC),
expiry=get_datetime_from_string(expiry),
delegated_user_tid=user_delegation_tid)
else:
diff --git a/src/azure-cli/azure/cli/command_modules/storage/operations/fileshare.py b/src/azure-cli/azure/cli/command_modules/storage/operations/fileshare.py
index 7cce7e02f2f..75f535dbbd7 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/operations/fileshare.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/operations/fileshare.py
@@ -3,7 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
import math
-from datetime import datetime
+from datetime import UTC, datetime
from knack.log import get_logger
@@ -67,7 +67,7 @@ def generate_share_sas(cmd, client, share_name=None, permission=None, expiry=Non
user_delegation_key = None
if as_user:
user_delegation_key = client.get_user_delegation_key(
- start=get_datetime_from_string(start) if start else datetime.utcnow(),
+ start=get_datetime_from_string(start) if start else datetime.now(UTC),
expiry=get_datetime_from_string(expiry),
delegated_user_tid=user_delegation_tid)
else:
diff --git a/src/azure-cli/azure/cli/command_modules/storage/operations/filesystem.py b/src/azure-cli/azure/cli/command_modules/storage/operations/filesystem.py
index b63b2a5294d..c2ac3ee5566 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/operations/filesystem.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/operations/filesystem.py
@@ -3,7 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
-from datetime import datetime
+from datetime import UTC, datetime
from azure.cli.core.profiles import ResourceType
from ..util import get_datetime_from_string
@@ -45,7 +45,7 @@ def generate_sas_fs_uri(client, cmd, file_system, permission=None,
sas_kwargs = {}
if as_user:
user_delegation_key = client.get_user_delegation_key(
- get_datetime_from_string(start) if start else datetime.utcnow(),
+ get_datetime_from_string(start) if start else datetime.now(UTC),
get_datetime_from_string(expiry),
delegated_user_tid=user_delegation_tid)
diff --git a/src/azure-cli/azure/cli/command_modules/storage/operations/fs_directory.py b/src/azure-cli/azure/cli/command_modules/storage/operations/fs_directory.py
index ac1f0d3dabd..8c3a39b6290 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/operations/fs_directory.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/operations/fs_directory.py
@@ -6,7 +6,7 @@
"""Custom operations for storage file datalake"""
# pylint: disable=too-many-locals
-from datetime import datetime
+from datetime import UTC, datetime
from azure.cli.core.profiles import ResourceType
from knack.util import todict
@@ -106,7 +106,7 @@ def generate_sas_directory_uri(client, cmd, file_system_name, directory_name, pe
sas_kwargs = {}
if as_user:
user_delegation_key = client.get_user_delegation_key(
- get_datetime_from_string(start) if start else datetime.utcnow(),
+ get_datetime_from_string(start) if start else datetime.now(UTC),
get_datetime_from_string(expiry),
delegated_user_tid=user_delegation_tid)
diff --git a/src/azure-cli/azure/cli/command_modules/storage/operations/fs_file.py b/src/azure-cli/azure/cli/command_modules/storage/operations/fs_file.py
index 110b9a1a5e1..8657e078745 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/operations/fs_file.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/operations/fs_file.py
@@ -7,7 +7,7 @@
# pylint: disable=too-many-locals
import os
-from datetime import datetime
+from datetime import UTC, datetime
from azure.core.exceptions import HttpResponseError
from azure.cli.core.profiles import ResourceType
@@ -160,7 +160,7 @@ def generate_sas_file_uri(client, cmd, file_system_name, path, permission=None,
sas_kwargs = {}
if as_user:
user_delegation_key = client.get_user_delegation_key(
- get_datetime_from_string(start) if start else datetime.utcnow(),
+ get_datetime_from_string(start) if start else datetime.now(UTC),
get_datetime_from_string(expiry),
delegated_user_tid=user_delegation_tid)
diff --git a/src/azure-cli/azure/cli/command_modules/storage/operations/queue.py b/src/azure-cli/azure/cli/command_modules/storage/operations/queue.py
index 23a43637bc3..4043b46cbae 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/operations/queue.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/operations/queue.py
@@ -52,9 +52,9 @@ def generate_queue_sas(cmd, client, queue_name=None, permission=None, expiry=Non
account_key = None
user_delegation_key = None
if as_user:
- from datetime import datetime
+ from datetime import UTC, datetime
user_delegation_key = client.get_user_delegation_key(
- start=get_datetime_from_string(start) if start else datetime.utcnow(),
+ start=get_datetime_from_string(start) if start else datetime.now(UTC),
expiry=get_datetime_from_string(expiry),
delegated_user_tid=user_delegation_tid)
else:
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_account_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_account_scenarios.py
index f0cacf85baf..1dec5ab13aa 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_account_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_account_scenarios.py
@@ -13,7 +13,7 @@
from azure.cli.core.profiles import ResourceType
from ..storage_test_util import StorageScenarioMixin
from knack.util import CLIError
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
from azure.cli.testsdk.scenario_tests import AllowLargeResponse
@@ -2004,10 +2004,10 @@ class RevokeStorageAccountTests(StorageScenarioMixin, RoleScenarioTest, LiveScen
def test_storage_account_revoke_delegation_keys(self, resource_group, storage_account):
if self.run_under_service_principal():
return # this test delete users which are beyond a SP's capacity, so quit...
- from datetime import datetime, timedelta
+ from datetime import UTC, datetime, timedelta
import time
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
account_info = self.get_account_info(resource_group, storage_account)
c = self.create_container(account_info)
b = self.create_random_name('blob', 24)
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_adls_gen2_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_adls_gen2_scenarios.py
index 7ede509158b..197b363f72c 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_adls_gen2_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_adls_gen2_scenarios.py
@@ -5,7 +5,7 @@
import unittest
import os
import time
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
from azure.cli.testsdk import (ScenarioTest, LiveScenarioTest, ResourceGroupPreparer, StorageAccountPreparer, JMESPathCheck, JMESPathCheckExists,
RoleBasedServicePrincipalPreparer)
@@ -503,14 +503,14 @@ def test_adls_file_scenarios(self, resource_group, storage_account):
@ResourceGroupPreparer()
@StorageAccountPreparer(kind="StorageV2", hns=True)
def test_adls_file_set_expiry_scenarios(self, resource_group, storage_account):
- from datetime import datetime, timedelta
+ from datetime import UTC, datetime, timedelta
account_info = self.get_account_info(resource_group, storage_account)
filesystem = self.create_file_system(account_info)
file = self.create_random_name(prefix="file", length=12)
self.storage_cmd('storage fs file create -p {} -f {} --content-type "application/json"',
account_info, file, filesystem)
- expiry = (datetime.utcnow() + timedelta(seconds=5)).strftime('%Y-%m-%dT%H:%M:%SZ')
+ expiry = (datetime.now(UTC) + timedelta(seconds=5)).strftime('%Y-%m-%dT%H:%M:%SZ')
self.storage_cmd("storage fs file set-expiry --expiry-options Absolute --expires-on {} -p {} -f {}",
account_info, expiry, file, filesystem)
self.storage_cmd("storage fs file exists -p {} -f {}", account_info, file, filesystem)\
@@ -565,7 +565,7 @@ def test_storage_fs_generate_sas_full_uri(self, resource_group, storage_account)
account_info = self.get_account_info(resource_group, storage_account)
f = self.create_file_system(account_info)
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
fs_uri = self.storage_cmd('storage fs generate-sas -n {} --expiry {} --permissions '
'r --https-only --full-uri', account_info, f, expiry).output
self.assertTrue(fs_uri)
@@ -578,7 +578,7 @@ def test_storage_fs_generate_sas_as_user(self, resource_group, storage_account):
account_info = self.get_account_info(resource_group, storage_account)
f = self.create_file_system(account_info)
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
with self.assertRaisesRegex(CLIError, "incorrect usage: specify --as-user when --auth-mode login"):
self.cmd('storage fs generate-sas --account-name {} -n {} --expiry {} --permissions r --https-only '
@@ -606,7 +606,7 @@ def test_storage_fs_generate_sas_with_user_delegation_oid(self, resource_group,
current_tenant = self.cmd('account show --query tenantId').get_output_in_json()
current_tenant = current_tenant if current_tenant is not None else '544a7a2e-697f-487c-b2b0-a13df7f346b6'
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
fs_sas = self.cmd('storage fs generate-sas --account-name {} -n {} --expiry {} --permissions '
'dlrwop --https-only --as-user --auth-mode login --user-delegation-oid '
@@ -636,7 +636,7 @@ def test_storage_fs_directory_generate_sas_full_uri(self, resource_group, storag
self.storage_cmd('storage fs directory create -n {} -f {}',
account_info, directory, filesystem)
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
fs_uri = self.storage_cmd('storage fs directory generate-sas -n {} -f {} --expiry {} --permissions '
'r --https-only --full-uri', account_info, directory, filesystem, expiry).output
self.assertTrue(fs_uri)
@@ -653,7 +653,7 @@ def test_storage_fs_directory_generate_sas_as_user(self, resource_group, storage
self.storage_cmd('storage fs directory create -n {} -f {}', account_info, directory, filesystem)
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
with self.assertRaisesRegex(CLIError, "incorrect usage: specify --as-user when --auth-mode login"):
self.cmd('storage fs directory generate-sas --account-name {} -n {} -f {} --expiry {} --permissions r '
@@ -685,7 +685,7 @@ def test_storage_fs_directory_generate_sas_with_user_delegation_oid(self, resour
self.storage_cmd('storage fs directory create -n {} -f {}', account_info, directory, filesystem)
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
fs_sas = self.cmd('storage fs directory generate-sas --account-name {} -n {} -f {} --expiry {} --permissions '
'dlrwop --https-only --as-user --auth-mode login --user-delegation-oid '
@@ -719,7 +719,7 @@ def test_storage_fs_file_generate_sas_as_user(self, resource_group, storage_acco
self.storage_cmd('storage fs directory create -n {} -f {}', account_info, directory, filesystem)
self.storage_cmd('storage fs file create -p {} -f {}', account_info, file_path, filesystem)
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
with self.assertRaisesRegex(CLIError, "incorrect usage: specify --as-user when --auth-mode login"):
self.cmd('storage fs file generate-sas --account-name {} -p {} -f {} --expiry {} --permissions r '
@@ -755,7 +755,7 @@ def test_storage_fs_file_generate_sas_with_user_delegation_oid(self, resource_gr
self.storage_cmd('storage fs file create -p {} -f {}', account_info, file_path, filesystem)
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
file_sas = self.cmd('storage fs file generate-sas --account-name {} -p {} -f {} --expiry {} --permissions '
'dlrwop --https-only --as-user --auth-mode login --user-delegation-oid '
@@ -790,8 +790,8 @@ def test_adls_directory_upload(self, resource_group, storage_account, test_dir):
self.storage_cmd('storage fs create -n {}', account_info, filesystem)
self.storage_cmd('storage fs directory create -n {} -f {}', account_info, directory, filesystem)
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
sas = self.storage_cmd('storage container generate-sas -n {} --https-only '
'--permissions acdlrw --expiry {} -otsv',
account_info, filesystem, expiry).output.strip()
@@ -855,8 +855,8 @@ def test_adls_directory_download(self, resource_group, storage_account, test_dir
self.storage_cmd('storage fs directory upload -f {} -d {} -s "{}" --recursive', account_info, filesystem,
directory, os.path.join(test_dir, 'apple'))
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
sas = self.storage_cmd('storage container generate-sas -n {} --https-only '
'--permissions lr --expiry {} -otsv',
account_info, filesystem, expiry).output.strip()
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_azcopy_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_azcopy_scenarios.py
index 95480cbbba3..f1efcec5129 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_azcopy_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_azcopy_scenarios.py
@@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------
import os
import shutil
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
from azure.cli.testsdk import (StorageAccountPreparer, LiveScenarioTest, JMESPathCheck, ResourceGroupPreparer)
from ..storage_test_util import StorageScenarioMixin, StorageTestFilesPreparer
from knack.util import CLIError
@@ -192,8 +192,8 @@ def test_storage_blob_azcopy_sync_oauth(self, storage_account, test_dir):
@StorageAccountPreparer()
@StorageTestFilesPreparer()
def test_storage_blob_azcopy_sync_sas(self, resource_group, storage_account, test_dir):
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
account_info = self.get_account_info(resource_group, storage_account)
container = self.create_random_name(prefix='container', length=20)
@@ -485,8 +485,8 @@ def test_storage_file_azcopy_remove_oauth(self, resource_group, storage_account)
@StorageAccountPreparer()
@StorageTestFilesPreparer()
def test_storage_azcopy_remove_sas(self, resource_group, storage_account, test_dir):
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
account_info = self.get_account_info(resource_group, storage_account)
container = self.create_container(account_info, prefix='container', length=20)
@@ -763,7 +763,7 @@ def test_storage_azcopy_blob_source_with_credential(self, resource_group, first_
self.assertEqual(11, sum(len(f) for r, d, f in os.walk(local_folder)))
# Download a set of files with source sas token
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
first_sas_token = self.cmd(
'storage container generate-sas --connection-string {} -n {} --expiry {} --permissions {} -o tsv'.format(
first_connection_string, first_container, expiry, 'rwalcd')).output.strip()
@@ -774,7 +774,7 @@ def test_storage_azcopy_blob_source_with_credential(self, resource_group, first_
self.assertEqual(21, sum(len(f) for r, d, f in os.walk(local_folder)))
# Copy a single blob to another single blob with sas token
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
second_sas_token = self.storage_cmd(
'storage container generate-sas -n {} --expiry {} --permissions {} -o tsv', second_account_info,
second_container, expiry, 'acdlrw').output.strip()
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_batch_operations.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_batch_operations.py
index 8e40c2be78b..acb2b8160d3 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_batch_operations.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_batch_operations.py
@@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------
import os
-from datetime import datetime
+from datetime import UTC, datetime
from azure.cli.testsdk import ScenarioTest, StorageAccountPreparer, ResourceGroupPreparer, JMESPathCheck, live_only
from ..storage_test_util import StorageScenarioMixin, StorageTestFilesPreparer
@@ -353,8 +353,8 @@ def test_storage_file_batch_upload_scenarios(self, test_dir, storage_account_inf
@StorageAccountPreparer(parameter_name='dst_account')
@StorageTestFilesPreparer()
def test_storage_blob_batch_copy(self, src_account_info, dst_account_info, test_dir):
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
src_container = 'container1'
self.storage_cmd('storage container create -n {}', src_account_info, src_container)
@@ -443,8 +443,8 @@ def test_storage_blob_batch_copy(self, src_account_info, dst_account_info, test_
@StorageAccountPreparer(parameter_name='dst_account')
@StorageTestFilesPreparer()
def test_storage_file_batch_copy(self, src_account_info, dst_account_info, test_dir):
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
src_container = 'container1'
self.storage_cmd('storage container create -n {}', src_account_info, src_container)
@@ -648,12 +648,12 @@ def create_and_populate_share(src_share):
@StorageTestFilesPreparer()
@live_only()
def test_storage_blob_batch_sas_scenarios(self, test_dir, resource_group, storage_account_info):
- from datetime import datetime, timedelta
+ from datetime import UTC, datetime, timedelta
container_name = 'container1'
self.storage_cmd('storage container create -n {}', storage_account_info, container_name)
temp_dir = self.create_temp_dir()
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
sas_token = self.storage_cmd('storage container generate-sas -n {} --permissions dwrl --expiry {}',
storage_account_info, container_name, expiry).get_output_in_json()
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_copy_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_copy_scenarios.py
index cbf65713799..1059b10fd21 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_copy_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_copy_scenarios.py
@@ -214,9 +214,9 @@ def test_storage_blob_copy_with_sas_and_snapshot(self, resource_group, source_ac
self.storage_cmd('storage blob upload -c {} -f "{}" -n src --overwrite', source_account_info,
source_container, source_file)
- from datetime import datetime, timedelta
- start = datetime.utcnow().strftime('%Y-%m-%dT%H:%MZ')
- expiry = (datetime.utcnow() + timedelta(minutes=5)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ start = datetime.now(UTC).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(minutes=5)).strftime('%Y-%m-%dT%H:%MZ')
sas = self.storage_cmd('storage blob generate-sas -c {} -n src --permissions r --start {}'
' --expiry {}', source_account_info, source_container, start,
expiry).output.strip()
@@ -260,9 +260,9 @@ def test_storage_blob_copy_same_account_sas(self, resource_group, storage_accoun
self.storage_cmd('storage blob upload -c {} -f "{}" -n src', account_info,
source_container, source_file)
- from datetime import datetime, timedelta
- start = datetime.utcnow().strftime('%Y-%m-%dT%H:%MZ')
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ start = datetime.now(UTC).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
sas = self.storage_cmd('storage blob generate-sas -c {} -n src --permissions r --start {}'
' --expiry {}', account_info, source_container, start,
expiry).output.strip()
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_live_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_live_scenarios.py
index 8e63766fb5a..c567a51d10c 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_live_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_live_scenarios.py
@@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------
import os
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
from azure.cli.testsdk import (LiveScenarioTest, ResourceGroupPreparer, StorageAccountPreparer,
JMESPathCheck, JMESPathCheckExists, NoneCheck)
from azure.cli.core.profiles import ResourceType
@@ -145,7 +145,7 @@ def test_storage_blob_query_scenario(self, resource_group, storage_account):
account_info, container, csv_blob, query_string).output
self.assertIsNotNone(result)
#test blob-url
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
blob_uri = self.storage_cmd('storage blob generate-sas -n {} -c {} --expiry {} --permissions '
'rwad --https-only --full-uri -o tsv',
account_info, csv_blob, container, expiry).output.strip()
@@ -193,7 +193,7 @@ def test_storage_blob_url_scenarios(self, resource_group, storage_account):
self.storage_cmd('storage blob upload -c {} -f "{}" -n {} ', account_info,
container, local_file1, blob_name1)
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
blob_uri = self.storage_cmd('storage blob generate-sas -n {} -c {} --expiry {} --permissions '
'rwad --https-only --full-uri -o tsv',
account_info, blob_name1, container, expiry).output.strip()
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_rewrite_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_rewrite_scenarios.py
index 4103c4cab49..7be520d6fc5 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_rewrite_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_rewrite_scenarios.py
@@ -3,7 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
from azure.cli.testsdk import LiveScenarioTest, ResourceGroupPreparer, StorageAccountPreparer,\
JMESPathCheck
from azure.cli.testsdk.decorators import serial_test
@@ -77,7 +77,7 @@ def test_storage_blob_rewrite_encryption_scope(self, group, account, file_size_k
])
# Update blob encryption
- expiry = (datetime.utcnow() + timedelta(days=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(days=1)).strftime('%Y-%m-%dT%H:%MZ')
source_url = self.storage_cmd(
'storage blob generate-sas -c {} -n {} --https-only --permissions r --expiry {} --full-uri -otsv',
account_info, container, blob, expiry).output.strip()
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_scenarios.py
index d9b6fa13def..255d2dc8f19 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_scenarios.py
@@ -6,7 +6,7 @@
import os
import re
import unittest
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
from azure.cli.testsdk import (ScenarioTest, ResourceGroupPreparer, StorageAccountPreparer,
JMESPathCheck, JMESPathCheckExists, NoneCheck)
from knack.util import CLIError
@@ -103,7 +103,7 @@ def verify_blob_upload_and_download(self, group, account, file_size_kb, blob_typ
else:
self.assertEqual(show_result.get('properties').get('pageRanges'), None)
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
sas = self.storage_cmd('storage blob generate-sas -n {} -c {} --expiry {} --permissions '
'r --https-only', account_info, blob_name, container, expiry).output
self.assertTrue(sas)
@@ -280,8 +280,8 @@ def test_storage_blob_container_operations(self, resource_group, storage_account
.assert_with_checks(JMESPathCheck('publicAccess', 'off'))
# test case with access policy set
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
policy = self.create_random_name('policy', 16)
self.storage_cmd('storage container policy create -c {} -n {} --expiry {} --permissions racwdxyltfmei',
account_info, c, policy, expiry)
@@ -336,8 +336,8 @@ def test_storage_blob_container_operations(self, resource_group, storage_account
JMESPathCheck('properties.lease.state', 'available'),
JMESPathCheck('properties.lease.status', 'unlocked'))
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
self.assertIn('sig=', self.storage_cmd('storage container generate-sas -n {} --permissions r --expiry {}',
account_info, c, expiry).output)
@@ -518,7 +518,7 @@ def test_storage_blob_generate_sas_full_uri(self, resource_group, storage_accoun
c = self.create_container(account_info)
b = self.create_random_name('blob', 24)
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
blob_uri = self.storage_cmd('storage blob generate-sas -n {} -c {} --expiry {} --permissions '
'r --https-only --full-uri', account_info, b, c, expiry).output
self.assertTrue(blob_uri)
@@ -532,7 +532,7 @@ def test_storage_blob_generate_sas_as_user(self, resource_group, storage_account
c = self.create_container(account_info)
b = self.create_random_name('blob', 24)
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
with self.assertRaisesRegex(CLIError, "incorrect usage: specify --as-user when --auth-mode login"):
self.cmd('storage blob generate-sas --account-name {} -n {} -c {} --expiry {} --permissions r --https-only '
@@ -572,7 +572,7 @@ def test_storage_blob_generate_sas_with_user_delegation_oid(self, resource_group
current_tenant = self.cmd('account show --query tenantId').get_output_in_json()
current_tenant = current_tenant if current_tenant is not None else '544a7a2e-697f-487c-b2b0-a13df7f346b6'
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
self.storage_cmd('storage blob upload -c {} -n {} -f "{}"', account_info, c, b, local_file)
@@ -892,8 +892,8 @@ def test_storage_blob_vlm(self, resource_group, storage_account_info):
self.storage_cmd('storage blob upload -c {} -f "{}" -n {} ', storage_account_info, container, file, blob)
# Test set immutability policy
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
result = self.storage_cmd('storage blob immutability-policy set -n {} -c {} '
'--expiry-time {} --policy-mode Unlocked',
storage_account_info, blob, container, expiry).get_output_in_json()
@@ -1042,7 +1042,7 @@ def test_storage_blob_restore(self, resource_group, storage_account):
JMESPathCheck('restorePolicy.days', 1),
JMESPathCheckExists('restorePolicy.minRestoreTime'))
- time_to_restore = (datetime.utcnow() + timedelta(seconds=-5)).strftime('%Y-%m-%dT%H:%MZ')
+ time_to_restore = (datetime.now(UTC) + timedelta(seconds=-5)).strftime('%Y-%m-%dT%H:%MZ')
# c1/b1 -> c1/b2
start_range = '/'.join([c1, b1])
@@ -1059,7 +1059,7 @@ def test_storage_blob_restore(self, resource_group, storage_account):
if self.is_live:
time.sleep(300)
- time_to_restore = (datetime.utcnow() + timedelta(seconds=-5)).strftime('%Y-%m-%dT%H:%MZ')
+ time_to_restore = (datetime.now(UTC) + timedelta(seconds=-5)).strftime('%Y-%m-%dT%H:%MZ')
# c1/b2 -> c2/b3
start_range = '/'.join([c1, b2])
end_range = '/'.join([c2, b3])
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_container_access_policy.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_container_access_policy.py
index 2641f94381d..d9860864899 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_container_access_policy.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_container_access_policy.py
@@ -8,13 +8,13 @@
JMESPathCheck, JMESPathCheckExists, NoneCheck, live_only)
from ..storage_test_util import StorageScenarioMixin
from knack.util import CLIError
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
class StorageSASScenario(StorageScenarioMixin, ScenarioTest):
@ResourceGroupPreparer()
@StorageAccountPreparer(allow_blob_public_access=True)
def test_storage_container_access_policy_scenario(self, resource_group, storage_account):
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
account_info = self.get_account_info(resource_group, storage_account)
container = self.create_random_name(prefix='cont', length=24)
@@ -40,8 +40,8 @@ def test_storage_container_access_policy_scenario(self, resource_group, storage_
container,
local_file, sas)
- new_start = (datetime.utcnow() - timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
- new_expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ new_start = (datetime.now(UTC) - timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ new_expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
self.storage_cmd('storage container policy update -c {} -n {} --permissions rwdxl --start {} --expiry {}',
account_info, container,
policy, new_start, new_expiry)
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_file_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_file_scenarios.py
index 8e3af8b0c30..b2e4023e7b2 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_file_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_file_scenarios.py
@@ -361,8 +361,8 @@ def validate_file_scenario(self, account_info, share):
file_list = self.storage_cmd('storage file list -s {}', account_info, share).get_output_in_json()
self.assertIsNotNone(file_list[0]['lastAccessTime'])
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
self.storage_cmd('storage file generate-sas -s {} -p {} --permissions r --expiry {}', account_info, share,
filename, expiry).assert_with_checks(StringContainCheck('sig='))
@@ -691,8 +691,8 @@ def test_storage_file_generate_sas_as_user(self, resource_group, storage_account
local_file = self.create_temp_file(1024)
file_name = os.path.basename(local_file)
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
with self.assertRaisesRegex(CLIError, "incorrect usage: specify --as-user when --auth-mode login"):
self.cmd('storage file generate-sas --account-name {} -p {} -s {} --expiry {} --permissions r --https-only '
@@ -725,8 +725,8 @@ def test_storage_file_generate_sas_with_user_delegation_oid(self, resource_group
current_tenant = self.cmd('account show --query tenantId').get_output_in_json()
current_tenant = current_tenant if current_tenant is not None else '544a7a2e-697f-487c-b2b0-a13df7f346b6'
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
file_sas = self.cmd('storage file generate-sas --account-name {} -p {} -s {} --expiry {} --permissions crwd '
'--https-only --as-user --auth-mode login --backup-intent --user-delegation-oid {} '
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_file_share_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_file_share_scenarios.py
index 147a09fc168..8672a3cee77 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_file_share_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_file_share_scenarios.py
@@ -13,7 +13,7 @@ class StorageShareScenarioTests(StorageScenarioMixin, ScenarioTest):
@ResourceGroupPreparer(name_prefix='clitest')
@StorageAccountPreparer(name_prefix='share', kind='StorageV2', location='eastus2', sku='Standard_RAGRS')
def test_storage_file_share_scenario(self, resource_group, storage_account):
- from datetime import datetime, timedelta
+ from datetime import UTC, datetime, timedelta
account_info = self.get_account_info(resource_group, storage_account)
connection_string = self.get_connection_string(resource_group, storage_account)
@@ -47,8 +47,8 @@ def test_storage_file_share_scenario(self, resource_group, storage_account):
self.assertIn(share_name, share_list, 'The newly created share is not listed.')
# Test generate-sas with start, expiry and permissions
- start = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
- expiry = (datetime.utcnow() + timedelta(hours=2)).strftime('%Y-%m-%dT%H:%MZ')
+ start = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=2)).strftime('%Y-%m-%dT%H:%MZ')
sas = self.storage_cmd('storage share generate-sas -n {} --permissions r --start {} --expiry {}',
account_info, share_name, start, expiry).output
self.assertIn('sig', sas, 'The sig segment is not in the sas {}'.format(sas))
@@ -164,8 +164,8 @@ def test_storage_share_generate_sas_as_user(self, resource_group, storage_accoun
share = self.create_share(account_info)
local_file = self.create_temp_file(1024)
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
with self.assertRaisesRegex(CLIError, "incorrect usage: specify --as-user when --auth-mode login"):
self.cmd('storage share generate-sas --account-name {} -n {} --expiry {} --permissions r --https-only '
@@ -197,8 +197,8 @@ def test_storage_share_generate_sas_with_user_delegation_oid(self, resource_grou
current_tenant = self.cmd('account show --query tenantId').get_output_in_json()
current_tenant = current_tenant if current_tenant is not None else '544a7a2e-697f-487c-b2b0-a13df7f346b6'
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
share_sas = self.cmd('storage share generate-sas --account-name {} -n {} --expiry {} --permissions crwld '
'--https-only --as-user --auth-mode login --backup-intent --user-delegation-oid '
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_queue_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_queue_scenarios.py
index 1e029b40733..600ec3075a3 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_queue_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_queue_scenarios.py
@@ -14,7 +14,7 @@ class StorageQueueScenarioTests(StorageScenarioMixin, ScenarioTest):
@ResourceGroupPreparer(name_prefix='clitest')
@StorageAccountPreparer(name_prefix='queue', kind='StorageV2', location='eastus2', sku='Standard_RAGRS')
def test_storage_queue_general_scenario(self, resource_group, storage_account):
- from datetime import datetime, timedelta
+ from datetime import UTC, datetime, timedelta
account_key = self.get_account_key(resource_group, storage_account)
connection_string = self.get_connection_string(resource_group, storage_account)
@@ -45,8 +45,8 @@ def test_storage_queue_general_scenario(self, resource_group, storage_account):
self.assertIn(queue, [x['name'] for x in res], 'The newly created queue is not listed.')
# Test generate-sas with start, expiry and permissions
- start = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
- expiry = (datetime.utcnow() + timedelta(hours=2)).strftime('%Y-%m-%dT%H:%MZ')
+ start = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=2)).strftime('%Y-%m-%dT%H:%MZ')
sas = self.cmd('storage queue generate-sas -n {} --permissions r --start {} --expiry {}'
.format(queue, start, expiry)).output
self.assertIn('sig', sas, 'The sig segment is not in the sas {}'.format(sas))
@@ -271,8 +271,8 @@ def test_storage_queue_generate_sas_as_user(self, resource_group, storage_accoun
self.cmd('storage queue create --account-name {} -n {}'.format(storage_account, queue))
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
with self.assertRaisesRegex(CLIError, "incorrect usage: specify --as-user when --auth-mode login"):
self.cmd('storage queue generate-sas --account-name {} -n {} --expiry {} --permissions r --https-only '
@@ -306,8 +306,8 @@ def test_storage_queue_generate_sas_with_user_delegation_oid(self, resource_grou
current_tenant = self.cmd('account show --query tenantId').get_output_in_json()
current_tenant = current_tenant if current_tenant is not None else '544a7a2e-697f-487c-b2b0-a13df7f346b6'
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
queue_sas = self.cmd('storage queue generate-sas --account-name {} -n {} --expiry {} --permissions raup '
'--https-only --as-user --user-delegation-oid {} '
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_scenarios.py
index fa168e7abc2..2f5991049ad 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_scenarios.py
@@ -13,8 +13,8 @@ class StorageSASScenario(StorageScenarioMixin, LiveScenarioTest):
@ResourceGroupPreparer()
@StorageAccountPreparer(location='EastUS2')
def test_storage_file_sas_scenario(self, resource_group, storage_account):
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
account_info = self.get_account_info(resource_group, storage_account)
share = self.create_share(account_info)
@@ -66,8 +66,8 @@ def test_storage_file_sas_scenario(self, resource_group, storage_account):
@ResourceGroupPreparer()
@StorageAccountPreparer()
def test_storage_blob_sas_scenario(self, resource_group, storage_account):
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
account_info = self.get_account_info(resource_group, storage_account)
container = self.create_container(account_info)
@@ -131,8 +131,8 @@ def test_storage_blob_sas_scenario(self, resource_group, storage_account):
@ResourceGroupPreparer(name_prefix='clitest')
@StorageAccountPreparer(name_prefix='queuesas', kind='StorageV2', location='eastus2', sku='Standard_RAGRS')
def test_storage_queue_sas_scenario(self, resource_group, storage_account):
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
account_info = self.get_account_info(resource_group, storage_account)
queue = self.create_random_name('queue', 24)
@@ -157,8 +157,8 @@ def test_storage_queue_sas_scenario(self, resource_group, storage_account):
@ResourceGroupPreparer()
@StorageAccountPreparer()
def test_storage_account_sas_scenario(self, resource_group, storage_account):
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
connection_str = self.cmd('storage account show-connection-string -n {} -otsv'.format(storage_account)).output
scope_name = self.create_random_name('scope', 16)
@@ -206,8 +206,8 @@ def test_storage_account_sas_scenario(self, resource_group, storage_account):
@ResourceGroupPreparer()
@StorageAccountPreparer(hns=True, kind='StorageV2')
def test_storage_fs_sas_scenario(self, resource_group, storage_account):
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
account_info = self.get_account_info(resource_group, storage_account)
file_system = self.create_file_system(account_info)
@@ -314,8 +314,8 @@ def test_storage_fs_sas_scenario(self, resource_group, storage_account):
@ResourceGroupPreparer()
@StorageAccountPreparer(hns=True, kind='StorageV2')
def test_storage_fs_sas_with_encryption_scope(self, resource_group, storage_account_info):
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
storage_account, account_key = storage_account_info
file_system = self.create_file_system(storage_account_info)
@@ -345,8 +345,8 @@ def test_storage_table_entity_sas(self, resource_group, storage_account):
self.storage_cmd('storage table create -n {} --fail-on-exist', account_info, table_name) \
.assert_with_checks(JMESPathCheck('created', True))
- from datetime import datetime, timedelta
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ from datetime import UTC, datetime, timedelta
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
sas_token_a = self.storage_cmd('storage table generate-sas -n {} --expiry {} --permissions a', account_info,
table_name, expiry).get_output_in_json()
account_name = account_info[0]
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_tokan_url_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_tokan_url_scenarios.py
index e36fedc7c8b..5add177a934 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_tokan_url_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_tokan_url_scenarios.py
@@ -5,7 +5,7 @@
import os
import requests
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
from azure.cli.testsdk import (LiveScenarioTest, ResourceGroupPreparer, StorageAccountPreparer,
JMESPathCheck, NoneCheck, StringCheck, StringContainCheck)
from ..storage_test_util import StorageScenarioMixin
@@ -19,7 +19,7 @@ def test_storage_file_url_sas_token_scenario(self, resource_group, storage_accou
share = self.create_share(account_info)
source_file = self.create_temp_file(128, full_random=False)
filename = "sample_file.bin"
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
self.storage_cmd('storage share exists -n {}', account_info, share) \
.assert_with_checks(JMESPathCheck('exists', True))
@@ -48,7 +48,7 @@ def test_storage_blob_url_sas_token_scenario(self, resource_group, storage_accou
container = self.create_container(account_info)
source_file = self.create_temp_file(128, full_random=False)
blob = "blob 1"
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
self.storage_cmd('storage container exists -n {}', account_info, container) \
.assert_with_checks(JMESPathCheck('exists', True))
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_table_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_table_scenarios.py
index f3e9d35ecc3..2394624f9b7 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_table_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_table_scenarios.py
@@ -12,7 +12,7 @@ class StorageTableScenarioTests(StorageScenarioMixin, ScenarioTest):
@ResourceGroupPreparer()
@StorageAccountPreparer(sku='Standard_RAGRS')
def test_storage_table_main_scenario(self, resource_group, storage_account):
- from datetime import datetime, timedelta
+ from datetime import UTC, datetime, timedelta
account_info = self.get_account_info(resource_group, storage_account)
table_name = self.create_random_name('table', 24)
@@ -24,7 +24,7 @@ def test_storage_table_main_scenario(self, resource_group, storage_account):
self.assertIn(table_name, self.storage_cmd('storage table list --query "[].name"',
account_info).get_output_in_json())
- expiry = (datetime.utcnow() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
sas = self.storage_cmd('storage table generate-sas -n {} --permissions r --expiry {}',
account_info, table_name, expiry).output
self.assertIn('sig=', sas)
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_validators.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_validators.py
index fba10572ff3..f293eb37700 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_validators.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_validators.py
@@ -442,6 +442,11 @@ def test_as_user_validator(self):
ns = self._create_namespace(as_user=True, expiry='2019-01-01', token_credential='token')
as_user_validator(ns)
+ def test_as_user_validator_rejects_expiry_beyond_seven_days(self):
+ ns = self._create_namespace(as_user=True, expiry='2999-01-01', token_credential='token')
+ with self.assertRaisesRegex(ArgumentError, 'within 7 days'):
+ as_user_validator(ns)
+
def _create_namespace(self, **kwargs):
ns = Namespace(account_key='my_storage_key', account_name='storage_name', connection_string=None, dryrun=False,
pattern='*', sas_token=None, source_account_key=None, source_account_name=None,
diff --git a/src/azure-cli/azure/cli/command_modules/storage/util.py b/src/azure-cli/azure/cli/command_modules/storage/util.py
index af8700b831c..49fa2ef1976 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/util.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/util.py
@@ -6,7 +6,7 @@
import os
from azure.cli.core.profiles import ResourceType
-from datetime import datetime
+from datetime import UTC, datetime
def collect_blobs(blob_service, container, pattern=None):
@@ -109,7 +109,7 @@ def create_short_lived_blob_sas_v2(cmd, account_name, container, blob, account_k
resource_type=ResourceType.DATA_STORAGE_BLOB)
t_blob_permissions = cmd.get_models('_models#BlobSasPermissions', resource_type=ResourceType.DATA_STORAGE_BLOB)
- expiry = (datetime.utcnow() + timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
+ expiry = (datetime.now(UTC) + timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
if account_key:
sas = t_sas(account_name, account_key=account_key)
elif user_delegation_key:
@@ -126,7 +126,7 @@ def create_short_lived_file_sas_v2(cmd, account_name, account_key, share, direct
resource_type=ResourceType.DATA_STORAGE_FILESHARE)
t_file_permissions = cmd.get_models('_models#FileSasPermissions', resource_type=ResourceType.DATA_STORAGE_FILESHARE)
- expiry = (datetime.utcnow() + timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
+ expiry = (datetime.now(UTC) + timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
sas = t_sas(account_name, account_key)
return sas.generate_file(share, directory_name=directory_name, file_name=file_name,
permission=t_file_permissions(read=True), expiry=expiry, protocol='https')
@@ -136,7 +136,7 @@ def create_short_lived_container_sas_track2(cmd, account_name, account_key, cont
from datetime import timedelta
t_generate_container_sas = cmd.get_models('_shared_access_signature#generate_container_sas',
resource_type=ResourceType.DATA_STORAGE_BLOB)
- expiry = (datetime.utcnow() + timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
+ expiry = (datetime.now(UTC) + timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
return t_generate_container_sas(account_name, container, account_key, permission='r', expiry=expiry,
protocol='https')
@@ -144,7 +144,7 @@ def create_short_lived_container_sas_track2(cmd, account_name, account_key, cont
def create_short_lived_share_sas_track2(cmd, account_name, account_key, share):
from datetime import timedelta
t_generate_share_sas = cmd.get_models('#generate_share_sas', resource_type=ResourceType.DATA_STORAGE_FILESHARE)
- expiry = (datetime.utcnow() + timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
+ expiry = (datetime.now(UTC) + timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
return t_generate_share_sas(account_name, share, account_key, permission='r', expiry=expiry,
protocol='https')
@@ -152,7 +152,7 @@ def create_short_lived_share_sas_track2(cmd, account_name, account_key, share):
def create_short_lived_blob_service_sas_track2(cmd, account_name, account_key, resource_types, permission='r'):
from datetime import timedelta
t_generate_blob_service_sas = cmd.get_models('#generate_account_sas', resource_type=ResourceType.DATA_STORAGE_BLOB)
- expiry = (datetime.utcnow() + timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
+ expiry = (datetime.now(UTC) + timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
return t_generate_blob_service_sas(account_name, account_key, resource_types, permission=permission, expiry=expiry)
@@ -160,7 +160,7 @@ def create_short_lived_file_service_sas_track2(cmd, account_name, account_key, r
from datetime import timedelta
t_generate_file_service_sas = cmd.get_models('#generate_account_sas',
resource_type=ResourceType.DATA_STORAGE_FILESHARE)
- expiry = (datetime.utcnow() + timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
+ expiry = (datetime.now(UTC) + timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
return t_generate_file_service_sas(account_name, account_key, resource_types, permission=permission, expiry=expiry)
diff --git a/src/azure-cli/pyproject.toml b/src/azure-cli/pyproject.toml
index fc3095d385c..70a56f71444 100644
--- a/src/azure-cli/pyproject.toml
+++ b/src/azure-cli/pyproject.toml
@@ -7,7 +7,7 @@ name = "azure-cli"
version = "2.91.0"
description = "Microsoft Azure Command-Line Tools"
readme = { file = "README.rst", content-type = "text/x-rst" }
-requires-python = ">=3.10.0"
+requires-python = ">=3.11.0"
license = "MIT"
license-files = ["LICENSE.txt"]
authors = [{ name = "Microsoft Corporation", email = "azpycli@microsoft.com" }]
@@ -17,7 +17,6 @@ classifiers = [
"Intended Audience :: System Administrators",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
From 5b35c11184dd5df103a51ef0c57910f2f0c3f5bd Mon Sep 17 00:00:00 2001
From: NostraDavid <55331731+NostraDavid@users.noreply.github.com>
Date: Wed, 14 Oct 2026 20:35:03 +0200
Subject: [PATCH 02/13] datetime: use the dt module alias consistently
---
scripts/ci/codegen_report.py | 4 +-
.../azure/cli/core/commands/__init__.py | 20 +++----
.../azure/cli/core/intercept_survey.py | 13 +++--
.../azure/cli/core/telemetry.py | 12 ++--
.../azure/cli/testsdk/preparers.py | 6 +-
.../azure/cli/command_modules/acr/_format.py | 4 +-
.../azure/cli/command_modules/acr/_utils.py | 6 +-
.../acs/managed_cluster_decorator.py | 4 +-
.../acs/tests/latest/custom_preparers.py | 4 +-
.../acs/tests/latest/test_custom.py | 20 +++----
.../latest/test_managed_cluster_decorator.py | 6 +-
.../appservice/_github_oauth.py | 6 +-
.../appservice/appservice_domains.py | 4 +-
.../cli/command_modules/appservice/custom.py | 52 ++++++++---------
.../appservice/static_sites.py | 4 +-
.../cli/command_modules/backup/custom.py | 10 ++--
.../backup/tests/latest/preparers.py | 6 +-
.../backup/tests/latest/test_afs_commands.py | 6 +-
.../tests/latest/test_backup_commands.py | 8 +--
.../cli/command_modules/batchai/custom.py | 6 +-
.../containerapp/_github_oauth.py | 6 +-
.../command_modules/containerapp/_utils.py | 18 +++---
.../cli/command_modules/cosmosdb/custom.py | 58 +++++++++----------
.../test_cosmosdb_backuprestore_scenario.py | 14 ++---
.../tests/latest/test_cosmosdb_commands.py | 51 ++++++++--------
.../tests/latest/test_eventgrid_commands.py | 10 ++--
.../cli/command_modules/feedback/custom.py | 20 +++----
.../feedback/tests/latest/test_feedback.py | 6 +-
.../azure/cli/command_modules/iot/_utils.py | 6 +-
.../iot/tests/latest/_test_utils.py | 10 ++--
.../tests/latest/test_keyvault_commands.py | 28 ++++-----
.../cli/command_modules/lab/validators.py | 6 +-
.../command_modules/monitor/_legacy/custom.py | 8 +--
.../cli/command_modules/monitor/custom.py | 8 +--
.../azure/cli/command_modules/mysql/_util.py | 8 +--
.../azure/cli/command_modules/mysql/custom.py | 6 +-
.../mysql/tests/latest/test_mysql_scenario.py | 14 ++---
.../tests/latest/test_bucket_commands.py | 6 +-
.../tests/latest/test_network_commands.py | 36 ++++++------
.../postgresql/commands/backup_commands.py | 4 +-
.../commands/server_logs_commands.py | 6 +-
.../postgresql/utils/_flexible_server_util.py | 4 +-
.../rdbms/_flexible_server_util.py | 4 +-
.../azure/cli/command_modules/rdbms/custom.py | 4 +-
.../rdbms/flexible_server_custom_common.py | 6 +-
.../rdbms/tests/latest/test_rdbms_commands.py | 6 +-
.../redis/tests/latest/test_redis_scenario.py | 6 +-
.../resource/tests/latest/test_resource.py | 8 +--
.../azure/cli/command_modules/role/custom.py | 35 ++++++-----
.../role/tests/latest/test_role.py | 8 +--
.../sql/tests/latest/test_sql_commands.py | 36 ++++++------
.../command_modules/storage/_validators.py | 20 +++----
.../storage/operations/blob.py | 21 ++++---
.../storage/operations/file.py | 24 ++++----
.../storage/operations/fileshare.py | 4 +-
.../storage/operations/filesystem.py | 4 +-
.../storage/operations/fs_directory.py | 4 +-
.../storage/operations/fs_file.py | 4 +-
.../storage/operations/queue.py | 4 +-
.../latest/test_storage_account_scenarios.py | 5 +-
.../test_storage_adls_gen2_scenarios.py | 27 ++++-----
.../latest/test_storage_azcopy_scenarios.py | 12 ++--
.../latest/test_storage_batch_operations.py | 18 +++---
.../test_storage_blob_copy_scenarios.py | 12 ++--
.../test_storage_blob_live_scenarios.py | 6 +-
.../test_storage_blob_rewrite_scenarios.py | 4 +-
.../latest/test_storage_blob_scenarios.py | 26 ++++-----
.../test_storage_container_access_policy.py | 8 +--
.../latest/test_storage_file_scenarios.py | 12 ++--
.../test_storage_file_share_scenarios.py | 14 ++---
.../latest/test_storage_queue_scenarios.py | 14 ++---
.../latest/test_storage_sas_scenarios.py | 28 ++++-----
.../test_storage_sas_tokan_url_scenarios.py | 6 +-
.../latest/test_storage_table_scenarios.py | 4 +-
.../tests/latest/test_storage_validators.py | 4 +-
.../azure/cli/command_modules/storage/util.py | 22 +++----
76 files changed, 463 insertions(+), 491 deletions(-)
diff --git a/scripts/ci/codegen_report.py b/scripts/ci/codegen_report.py
index f0b1a552549..2b2fe9d9092 100644
--- a/scripts/ci/codegen_report.py
+++ b/scripts/ci/codegen_report.py
@@ -5,7 +5,7 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
-import datetime
+import datetime as dt
import json
import logging
import os
@@ -111,7 +111,7 @@ def generate_csv():
total = ref['total']
manual = total - codegenv1 - codegenv2
is_release = True if BUILD_BRANCH == 'release' else False
- date = (datetime.datetime.now(datetime.UTC) + datetime.timedelta(hours=8)).strftime("%Y-%m-%d")
+ date = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=8)).strftime("%Y-%m-%d")
data.append([BUILD_ID, manual, codegenv1, codegenv2, total, is_release, date])
logger.info('Finish generate data for codegen report:')
logger.info("BUILD_ID, manual, codegenv1, codegenv2, total, is_release, date")
diff --git a/src/azure-cli-core/azure/cli/core/commands/__init__.py b/src/azure-cli-core/azure/cli/core/commands/__init__.py
index 11dd3cb98d8..bda0f37cc0d 100644
--- a/src/azure-cli-core/azure/cli/core/commands/__init__.py
+++ b/src/azure-cli-core/azure/cli/core/commands/__init__.py
@@ -6,7 +6,7 @@
# pylint: disable=too-many-lines
import argparse
-import datetime
+import datetime as dt
import json
import logging as logs
import os
@@ -218,7 +218,7 @@ def save(self, args, kwargs):
"Caching %s '%s' as: %s", self._model_name, self._resource_name,
os.path.join(directory, filename)
)
- self.last_saved = str(datetime.datetime.now())
+ self.last_saved = str(dt.datetime.now())
self._dump_to_file(f)
def result(self):
@@ -396,9 +396,9 @@ def _is_stale(cli_ctx, cache_obj):
cache_ttl = DEFAULT_CACHE_TTL
else:
raise ex
- time_now = datetime.datetime.now()
- time_cache = datetime.datetime.strptime(cache_obj.last_saved, '%Y-%m-%d %H:%M:%S.%f')
- return time_now - time_cache > datetime.timedelta(minutes=int(cache_ttl))
+ time_now = dt.datetime.now()
+ time_cache = dt.datetime.strptime(cache_obj.last_saved, '%Y-%m-%d %H:%M:%S.%f')
+ return time_now - time_cache > dt.timedelta(minutes=int(cache_ttl))
def cached_get(cmd_obj, operation, *args, **kwargs):
@@ -1032,7 +1032,7 @@ def __init__(self, cli_ctx, start_msg='', finish_msg='', poller_done_interval_ms
self.finish_msg = finish_msg
self.poller_done_interval_ms = poller_done_interval_ms
self.deploy_dict = {}
- self.last_progress_report = datetime.datetime.now()
+ self.last_progress_report = dt.datetime.now()
self._progress_bar = None
disable_progress_bar = self.cli_ctx.config.getboolean('core', 'disable_progress_bar', False)
@@ -1060,8 +1060,8 @@ def _generate_template_progress(self, correlation_id): # pylint: disable=no-sel
if correlation_id is not None: # pylint: disable=too-many-nested-blocks
formatter = "eventTimestamp ge {}"
- end_time = datetime.datetime.now(datetime.UTC)
- start_time = end_time - datetime.timedelta(seconds=DEFAULT_QUERY_TIME_RANGE)
+ end_time = dt.datetime.now(dt.UTC)
+ start_time = end_time - dt.timedelta(seconds=DEFAULT_QUERY_TIME_RANGE)
odata_filters = formatter.format(start_time.strftime('%Y-%m-%dT%H:%M:%SZ'))
odata_filters = "{} and {} eq '{}'".format(odata_filters, 'correlationId', correlation_id)
@@ -1141,8 +1141,8 @@ def __call__(self, poller): # pylint: disable=too-many-statements
except: # pylint: disable=bare-except
pass
- current_time = datetime.datetime.now()
- if is_verbose and current_time - self.last_progress_report >= datetime.timedelta(seconds=10):
+ current_time = dt.datetime.now()
+ if is_verbose and current_time - self.last_progress_report >= dt.timedelta(seconds=10):
self.last_progress_report = current_time
try:
self._generate_template_progress(correlation_id)
diff --git a/src/azure-cli-core/azure/cli/core/intercept_survey.py b/src/azure-cli-core/azure/cli/core/intercept_survey.py
index 1f4b4db363f..f7267494c21 100644
--- a/src/azure-cli-core/azure/cli/core/intercept_survey.py
+++ b/src/azure-cli-core/azure/cli/core/intercept_survey.py
@@ -6,7 +6,7 @@
import os
import sys
import json
-from datetime import UTC, datetime, timedelta
+import datetime as dt
from azure.cli.core._config import GLOBAL_CONFIG_DIR
from azure.cli.core._profile import Profile
from azure.cli.core.style import print_styled_text
@@ -56,7 +56,7 @@ def should_prompt(cli):
# using their installationId
installation_id = Profile(cli_ctx=cli).get_installation_id()
prompt_period = EXPERIENCE_PERIOD_IN_DAYS + (uuid.UUID(installation_id).int & 127)
- next_prompt_time = datetime.now(UTC) + timedelta(days=prompt_period)
+ next_prompt_time = dt.datetime.now(dt.UTC) + dt.timedelta(days=prompt_period)
survey_note = {
'last_prompt_time': '',
'next_prompt_time': next_prompt_time.strftime('%Y-%m-%dT%H:%M:%S')
@@ -67,8 +67,9 @@ def should_prompt(cli):
with open(GLOBAL_SURVEY_NOTE_PATH, 'r', encoding='utf-8-sig') as f:
survey_note = json.load(f)
- next_prompt_time = datetime.strptime(survey_note['next_prompt_time'], '%Y-%m-%dT%H:%M:%S').replace(tzinfo=UTC)
- if datetime.now(UTC) < next_prompt_time:
+ next_prompt_time = dt.datetime.strptime(
+ survey_note['next_prompt_time'], '%Y-%m-%dT%H:%M:%S').replace(tzinfo=dt.UTC)
+ if dt.datetime.now(dt.UTC) < next_prompt_time:
return False
return True
@@ -92,9 +93,9 @@ def prompt_survey_message(cli):
telemetry.set_survey_info(show_survey_message=True)
# log prompt time
- next_prompt_time = datetime.now(UTC) + timedelta(days=PROMPT_INTERVAL_IN_DAYS)
+ next_prompt_time = dt.datetime.now(dt.UTC) + dt.timedelta(days=PROMPT_INTERVAL_IN_DAYS)
survey_note = {
- 'last_prompt_time': datetime.now(UTC).strftime('%Y-%m-%dT%H:%M:%S'),
+ 'last_prompt_time': dt.datetime.now(dt.UTC).strftime('%Y-%m-%dT%H:%M:%S'),
'next_prompt_time': next_prompt_time.strftime('%Y-%m-%dT%H:%M:%S')
}
with open(GLOBAL_SURVEY_NOTE_PATH, 'w') as f:
diff --git a/src/azure-cli-core/azure/cli/core/telemetry.py b/src/azure-cli-core/azure/cli/core/telemetry.py
index c65611bffd4..5aa2de06de2 100644
--- a/src/azure-cli-core/azure/cli/core/telemetry.py
+++ b/src/azure-cli-core/azure/cli/core/telemetry.py
@@ -3,7 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
-import datetime
+import datetime as dt
import json
import locale
import os
@@ -292,7 +292,7 @@ def _wrapper(*args, **kwargs):
def start(mode=None):
if mode:
_session.mode = mode
- _session.start_time = datetime.datetime.now(datetime.UTC)
+ _session.start_time = dt.datetime.now(dt.UTC)
@decorators.suppress_all_exceptions()
@@ -307,12 +307,12 @@ def set_invoke_time_elapsed(invoke_time_elapsed):
@decorators.suppress_all_exceptions()
def poll_start():
- _session.poll_start_time = datetime.datetime.now(datetime.UTC)
+ _session.poll_start_time = dt.datetime.now(dt.UTC)
@decorators.suppress_all_exceptions()
def poll_end():
- _session.poll_end_time = datetime.datetime.now(datetime.UTC)
+ _session.poll_end_time = dt.datetime.now(dt.UTC)
@_user_agrees_to_telemetry
@@ -322,7 +322,7 @@ def flush():
from azure.cli.telemetry import save
# flush out current information
- _session.end_time = datetime.datetime.now(datetime.UTC)
+ _session.end_time = dt.datetime.now(dt.UTC)
save(get_config_dir(), _session.generate_payload())
# reset session fields, retaining correlation id and application
@@ -335,7 +335,7 @@ def conclude():
from azure.cli.core._environment import get_config_dir
from azure.cli.telemetry import save
- _session.end_time = datetime.datetime.now(datetime.UTC)
+ _session.end_time = dt.datetime.now(dt.UTC)
save(get_config_dir(), _session.generate_payload())
diff --git a/src/azure-cli-testsdk/azure/cli/testsdk/preparers.py b/src/azure-cli-testsdk/azure/cli/testsdk/preparers.py
index 92d8588c2be..8be44f3000b 100644
--- a/src/azure-cli-testsdk/azure/cli/testsdk/preparers.py
+++ b/src/azure-cli-testsdk/azure/cli/testsdk/preparers.py
@@ -5,7 +5,7 @@
import os
import sys
-from datetime import UTC, datetime
+import datetime as dt
from .scenario_tests import AbstractPreparer, SingleValueReplacer
from .base import LiveScenarioTest
@@ -85,7 +85,7 @@ def create_resource(self, name, **kwargs):
module = test_class_path[index_of_module] if index_of_module >= 0 else 'unknown'
tags = {'product': 'azurecli',
'cause': 'automation test',
- 'date': datetime.now(UTC).strftime('%Y-%m-%dT%H:%M:%SZ'),
+ 'date': dt.datetime.now(dt.UTC).strftime('%Y-%m-%dT%H:%M:%SZ'),
'test': self.test_class_instance._testMethodName,
'module': module}
if 'ENV_JOB_NAME' in os.environ:
@@ -419,7 +419,7 @@ def create_resource(self, name, **kwargs):
return {self.parameter_name: self.dev_setting_name, }
tags = {'product': 'azurecli', 'cause': 'automation',
- 'date': datetime.now(UTC).strftime('%Y-%m-%dT%H:%M:%SZ')}
+ 'date': dt.datetime.now(dt.UTC).strftime('%Y-%m-%dT%H:%M:%SZ')}
if 'ENV_JOB_NAME' in os.environ:
tags['job'] = os.environ['ENV_JOB_NAME']
tags = ' '.join(['{}={}'.format(key, value)
diff --git a/src/azure-cli/azure/cli/command_modules/acr/_format.py b/src/azure-cli/azure/cli/command_modules/acr/_format.py
index 7df8ad10c69..2d6d5ff2da8 100644
--- a/src/azure-cli/azure/cli/command_modules/acr/_format.py
+++ b/src/azure-cli/azure/cli/command_modules/acr/_format.py
@@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------
from collections import OrderedDict
-from datetime import UTC, datetime
+import datetime as dt
from knack.log import get_logger
from ._constants import (
REF_KEY
@@ -530,4 +530,4 @@ def _get_duration(start_time, finish_time):
def add_timestamp(message):
- return "{} {}".format(datetime.now(UTC), message)
+ return "{} {}".format(dt.datetime.now(dt.UTC), message)
diff --git a/src/azure-cli/azure/cli/command_modules/acr/_utils.py b/src/azure-cli/azure/cli/command_modules/acr/_utils.py
index 7a2d175445a..36a198d3e0a 100644
--- a/src/azure-cli/azure/cli/command_modules/acr/_utils.py
+++ b/src/azure-cli/azure/cli/command_modules/acr/_utils.py
@@ -415,11 +415,11 @@ def remove_timer_trigger(task_name,
def add_days_to_now(days):
if days <= 0:
raise CLIError('Days must be positive.')
- from datetime import UTC, datetime, timedelta
+ import datetime as dt
try:
- return datetime.now(UTC) + timedelta(days=days)
+ return dt.datetime.now(dt.UTC) + dt.timedelta(days=days)
except OverflowError:
- return datetime.max.replace(tzinfo=UTC)
+ return dt.datetime.max.replace(tzinfo=dt.UTC)
def is_vault_secret(cmd, credential):
diff --git a/src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py b/src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py
index fb007b9763d..a8c7bb07abc 100644
--- a/src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py
+++ b/src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py
@@ -11,7 +11,7 @@
import time
from types import SimpleNamespace
from typing import Dict, List, Optional, Tuple, TypeVar, Union
-import datetime
+import datetime as dt
from dateutil.parser import parse
from azure.mgmt.containerservice.models import KubernetesSupportPlan
@@ -9601,7 +9601,7 @@ def update_upgrade_settings(self, mc: ManagedCluster) -> ManagedCluster:
f"{override_until} is not a valid datatime format."
)
elif force_upgrade:
- default_extended_until = datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=3)
+ default_extended_until = dt.datetime.now(dt.UTC) + dt.timedelta(days=3)
if existing_until is None or existing_until.timestamp() < default_extended_until.timestamp():
mc.upgrade_settings.override_settings.until = default_extended_until
diff --git a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/custom_preparers.py b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/custom_preparers.py
index fe8db67be60..60c826174f7 100644
--- a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/custom_preparers.py
+++ b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/custom_preparers.py
@@ -3,7 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
-from datetime import UTC, datetime
+import datetime as dt
import os
import unittest
@@ -126,7 +126,7 @@ def create_resource(self, name, **kwargs):
tags = {
"product": "azurecli",
"cause": "automation",
- "date": datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ"),
+ "date": dt.datetime.now(dt.UTC).strftime("%Y-%m-%dT%H:%M:%SZ"),
}
if "ENV_JOB_NAME" in os.environ:
tags["job"] = os.environ["ENV_JOB_NAME"]
diff --git a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_custom.py b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_custom.py
index efaa08a39aa..ce9218b7070 100644
--- a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_custom.py
+++ b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_custom.py
@@ -14,7 +14,7 @@
import unittest
from unittest import mock
from urllib.error import HTTPError, URLError
-import datetime
+import datetime as dt
from contextlib import contextmanager
from dateutil.parser import parse
@@ -2140,8 +2140,8 @@ def test_update_upgrade_settings(self, rg_def, get_resource_groups_client, get_r
instance.upgrade_settings = None
instance = _update_upgrade_settings(MockCmd(self.cli), instance, enable_force_upgrade=True, disable_force_upgrade=False, upgrade_override_until=None)
self.assertTrue(instance.upgrade_settings.override_settings.force_upgrade)
- self.assertGreater(instance.upgrade_settings.override_settings.until.timestamp(), (datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=2)).timestamp())
- self.assertLess(instance.upgrade_settings.override_settings.until.timestamp(), (datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=4)).timestamp())
+ self.assertGreater(instance.upgrade_settings.override_settings.until.timestamp(), (dt.datetime.now(dt.UTC) + dt.timedelta(days=2)).timestamp())
+ self.assertLess(instance.upgrade_settings.override_settings.until.timestamp(), (dt.datetime.now(dt.UTC) + dt.timedelta(days=4)).timestamp())
instance.upgrade_settings = self.models.ClusterUpgradeSettings(
override_settings = self.models.UpgradeOverrideSettings(
@@ -2150,8 +2150,8 @@ def test_update_upgrade_settings(self, rg_def, get_resource_groups_client, get_r
)
instance = _update_upgrade_settings(MockCmd(self.cli), instance, enable_force_upgrade=True, disable_force_upgrade=False, upgrade_override_until=None)
self.assertTrue(instance.upgrade_settings.override_settings.force_upgrade)
- self.assertGreater(instance.upgrade_settings.override_settings.until.timestamp(), (datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=2)).timestamp())
- self.assertLess(instance.upgrade_settings.override_settings.until.timestamp(), (datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=4)).timestamp())
+ self.assertGreater(instance.upgrade_settings.override_settings.until.timestamp(), (dt.datetime.now(dt.UTC) + dt.timedelta(days=2)).timestamp())
+ self.assertLess(instance.upgrade_settings.override_settings.until.timestamp(), (dt.datetime.now(dt.UTC) + dt.timedelta(days=4)).timestamp())
# force_upgrade False
instance.upgrade_settings = None
@@ -2987,7 +2987,7 @@ def test_aks_agentpool_get_rollback_versions_returns_recently_used_versions(self
mock.Mock(
orchestrator_version="1.32.1",
node_image_version="AKSUbuntu-2204gen2containerd-202605.12.0",
- timestamp=datetime.datetime(2026, 5, 1),
+ timestamp=dt.datetime(2026, 5, 1),
)
]
upgrade_profile = mock.Mock(recently_used_versions=versions)
@@ -3005,12 +3005,12 @@ def test_aks_agentpool_rollback_uses_most_recent_version(self, mock_sdk_no_wait,
older_version = mock.Mock(
orchestrator_version="1.31.9",
node_image_version="AKSUbuntu-2204gen2containerd-202604.10.0",
- timestamp=datetime.datetime(2026, 4, 1),
+ timestamp=dt.datetime(2026, 4, 1),
)
most_recent_version = mock.Mock(
orchestrator_version="1.32.1",
node_image_version="AKSUbuntu-2204gen2containerd-202605.12.0",
- timestamp=datetime.datetime(2026, 5, 1),
+ timestamp=dt.datetime(2026, 5, 1),
)
upgrade_profile = mock.Mock(recently_used_versions=[older_version, most_recent_version])
agentpool = mock.Mock()
@@ -3064,7 +3064,7 @@ def test_aks_agentpool_rollback_warns_node_image_only_for_node_os_channel(
rollback_version = mock.Mock(
orchestrator_version="1.34.8",
node_image_version="AKSUbuntu-2204gen2containerd-202607.20.0",
- timestamp=datetime.datetime(2026, 8, 5),
+ timestamp=dt.datetime(2026, 8, 5),
)
client = mock.Mock()
client.get_upgrade_profile.return_value = mock.Mock(recently_used_versions=[rollback_version])
@@ -3094,7 +3094,7 @@ def test_aks_agentpool_rollback_prioritizes_upgrade_channel_warning(
rollback_version = mock.Mock(
orchestrator_version="1.34.8",
node_image_version="AKSUbuntu-2204gen2containerd-202607.20.0",
- timestamp=datetime.datetime(2026, 8, 5),
+ timestamp=dt.datetime(2026, 8, 5),
)
client = mock.Mock()
client.get_upgrade_profile.return_value = mock.Mock(recently_used_versions=[rollback_version])
diff --git a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_managed_cluster_decorator.py b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_managed_cluster_decorator.py
index 68c0e808603..9ecf2795dc4 100644
--- a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_managed_cluster_decorator.py
+++ b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_managed_cluster_decorator.py
@@ -103,7 +103,7 @@
from azure.cli.core.profiles import ResourceType
from azure.core.exceptions import HttpResponseError
from knack.prompting import NoTTYException
-import datetime
+import datetime as dt
from dateutil.parser import parse
@@ -10556,8 +10556,8 @@ def test_update_upgrade_settings(self):
dec_3.context.attach_mc(mc_3)
dec_mc_3 = dec_3.update_upgrade_settings(mc_3)
self.assertEqual(dec_mc_3.upgrade_settings.override_settings.force_upgrade, True)
- self.assertGreater(dec_mc_3.upgrade_settings.override_settings.until.timestamp(), (datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=2)).timestamp())
- self.assertLess(dec_mc_3.upgrade_settings.override_settings.until.timestamp(), (datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=4)).timestamp())
+ self.assertGreater(dec_mc_3.upgrade_settings.override_settings.until.timestamp(), (dt.datetime.now(dt.UTC) + dt.timedelta(days=2)).timestamp())
+ self.assertLess(dec_mc_3.upgrade_settings.override_settings.until.timestamp(), (dt.datetime.now(dt.UTC) + dt.timedelta(days=4)).timestamp())
# Set Until
dec_4 = AKSManagedClusterUpdateDecorator(
diff --git a/src/azure-cli/azure/cli/command_modules/appservice/_github_oauth.py b/src/azure-cli/azure/cli/command_modules/appservice/_github_oauth.py
index fca076c29b1..d3136b6048f 100644
--- a/src/azure-cli/azure/cli/command_modules/appservice/_github_oauth.py
+++ b/src/azure-cli/azure/cli/command_modules/appservice/_github_oauth.py
@@ -6,7 +6,7 @@
import os
import sys
-from datetime import UTC, datetime
+import datetime as dt
from knack.log import get_logger
from azure.cli.core.util import open_page_in_browser
@@ -49,10 +49,10 @@ def cache_github_token(cmd, token, repo):
if isinstance(entry, dict) and entry.get("value") == token:
if repo not in entry.get("repos", []):
entry["repos"] = [*entry.get("repos", []), repo]
- entry["last_modified_timestamp"] = datetime.now(UTC).timestamp()
+ entry["last_modified_timestamp"] = dt.datetime.now(dt.UTC).timestamp()
break
else:
- cache_entry = {"last_modified_timestamp": datetime.now(UTC).timestamp(), "value": token, "repos": [repo]}
+ cache_entry = {"last_modified_timestamp": dt.datetime.now(dt.UTC).timestamp(), "value": token, "repos": [repo]}
cache = [cache_entry, *cache]
secret_store.save(cache)
diff --git a/src/azure-cli/azure/cli/command_modules/appservice/appservice_domains.py b/src/azure-cli/azure/cli/command_modules/appservice/appservice_domains.py
index b81cc880396..95e2abae620 100644
--- a/src/azure-cli/azure/cli/command_modules/appservice/appservice_domains.py
+++ b/src/azure-cli/azure/cli/command_modules/appservice/appservice_domains.py
@@ -21,7 +21,7 @@ def create_domain(cmd, resource_group_name, hostname, contact_info, privacy=True
accept_terms=False, tags=None, dryrun=False, no_wait=False):
from azure.cli.core.commands.arm import ArmTemplateBuilder
from azure.cli.command_modules.appservice._template_builder import (build_dns_zone, build_domain)
- from datetime import UTC, datetime
+ import datetime as dt
import socket
import json
@@ -41,7 +41,7 @@ def create_domain(cmd, resource_group_name, hostname, contact_info, privacy=True
'/blob/master/contact_info.json')
contact_info = verify_contact_info_and_format(contact_info)
- current_time = str(datetime.now(UTC)).replace('+00:00', 'Z')
+ current_time = str(dt.datetime.now(dt.UTC)).replace('+00:00', 'Z')
local_ip_address = ''
try:
local_ip_address = socket.gethostbyname(socket.gethostname())
diff --git a/src/azure-cli/azure/cli/command_modules/appservice/custom.py b/src/azure-cli/azure/cli/command_modules/appservice/custom.py
index 1e91400bd5b..7791653eb9d 100644
--- a/src/azure-cli/azure/cli/command_modules/appservice/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/appservice/custom.py
@@ -16,7 +16,7 @@
from binascii import hexlify
from collections.abc import Mapping
from os import urandom
-import datetime
+import datetime as dt
import json
import ssl
import sys
@@ -2193,7 +2193,7 @@ def upload_zip_to_storage(cmd, resource_group_name, name, src, slot=None):
storage_connection = str(keyval['value'])
container_name = "function-releases"
- blob_name = "{}-{}.zip".format(datetime.datetime.today().strftime('%Y%m%d%H%M%S'), str(uuid.uuid4()))
+ blob_name = "{}-{}.zip".format(dt.datetime.today().strftime('%Y%m%d%H%M%S'), str(uuid.uuid4()))
BlobServiceClient = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_BLOB,
'_blob_service_client#BlobServiceClient')
blob_service_client = BlobServiceClient.from_connection_string(conn_str=storage_connection)
@@ -2217,9 +2217,9 @@ def progress_callback(current, total):
blob_client = container_client.upload_blob(blob_name, zip_content, validate_content=True,
progress_hook=progress_callback)
- now = datetime.datetime.now(datetime.UTC)
- blob_start = now - datetime.timedelta(minutes=10)
- blob_end = now + datetime.timedelta(weeks=520)
+ now = dt.datetime.now(dt.UTC)
+ blob_start = now - dt.timedelta(minutes=10)
+ blob_end = now + dt.timedelta(weeks=520)
BlobSharedAccessSignature = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_BLOB,
'_shared_access_signature#BlobSharedAccessSignature')
@@ -6482,7 +6482,7 @@ def update_backup_schedule(cmd, resource_group_name, webapp_name, storage_accoun
if backup_name and backup_name.lower().endswith('.zip'):
backup_name = backup_name[:-4]
if not backup_name:
- backup_name = '{0}_{1}'.format(webapp_name, datetime.datetime.now(datetime.UTC).strftime('%Y%m%d%H%M'))
+ backup_name = '{0}_{1}'.format(webapp_name, dt.datetime.now(dt.UTC).strftime('%Y%m%d%H%M'))
try:
configuration = _generic_site_operation(cmd.cli_ctx, resource_group_name, webapp_name,
@@ -7369,16 +7369,16 @@ def _runtime_error_is_recent(runtime_error, minutes=_RUNTIME_ERROR_FRESHNESS_MIN
ts = str(raw).strip()
if ts.endswith('Z'):
ts = ts[:-1] + '+00:00'
- parsed = datetime.datetime.fromisoformat(ts)
+ parsed = dt.datetime.fromisoformat(ts)
if parsed.tzinfo is None:
- parsed = parsed.replace(tzinfo=datetime.timezone.utc)
+ parsed = parsed.replace(tzinfo=dt.timezone.utc)
except (ValueError, TypeError):
return False
- delta = datetime.datetime.now(datetime.timezone.utc) - parsed
+ delta = dt.datetime.now(dt.timezone.utc) - parsed
# Reject future timestamps: a clock-skewed or malformed value would
# produce a negative delta, which still satisfies `<= 15min` and would
# incorrectly mark stale errors as recent.
- return datetime.timedelta(0) <= delta <= datetime.timedelta(minutes=minutes)
+ return dt.timedelta(0) <= delta <= dt.timedelta(minutes=minutes)
def _ensure_linux_webapp_for_troubleshoot(cmd, resource_group_name, name, slot=None):
@@ -8804,10 +8804,10 @@ def _compute_support_status(eol_date_str):
if not eol_date_str:
return 'n/a'
try:
- eol_date = datetime.datetime.strptime(eol_date_str, "%Y-%m-%d").replace(
- tzinfo=datetime.timezone.utc)
- now = datetime.datetime.now(datetime.timezone.utc)
- near_threshold = now + datetime.timedelta(days=365)
+ eol_date = dt.datetime.strptime(eol_date_str, "%Y-%m-%d").replace(
+ tzinfo=dt.timezone.utc)
+ now = dt.datetime.now(dt.timezone.utc)
+ near_threshold = now + dt.timedelta(days=365)
if eol_date <= now:
return 'EOL'
if eol_date <= near_threshold:
@@ -8824,11 +8824,11 @@ def _format_eol_date(eol_date):
if isinstance(eol_date, str):
for fmt in ("%Y-%m-%dT%H:%M:%S.%fZ", "%Y-%m-%dT%H:%M:%SZ"):
try:
- return datetime.datetime.strptime(eol_date, fmt).strftime("%Y-%m-%d")
+ return dt.datetime.strptime(eol_date, fmt).strftime("%Y-%m-%d")
except ValueError:
continue
return eol_date
- if isinstance(eol_date, datetime.datetime):
+ if isinstance(eol_date, dt.datetime):
return eol_date.strftime("%Y-%m-%d")
return None
@@ -9093,20 +9093,20 @@ def _is_valid_runtime_setting(cls, runtime_setting, include_eol=False):
try:
if isinstance(end_of_life, str):
try:
- end_of_life_dt = datetime.datetime.strptime(
+ end_of_life_dt = dt.datetime.strptime(
end_of_life, "%Y-%m-%dT%H:%M:%S.%fZ"
- ).replace(tzinfo=datetime.timezone.utc)
+ ).replace(tzinfo=dt.timezone.utc)
except ValueError:
- end_of_life_dt = datetime.datetime.strptime(
+ end_of_life_dt = dt.datetime.strptime(
end_of_life, "%Y-%m-%dT%H:%M:%SZ"
- ).replace(tzinfo=datetime.timezone.utc)
+ ).replace(tzinfo=dt.timezone.utc)
else:
# If already a datetime, ensure it's timezone-aware
if end_of_life.tzinfo is None:
- end_of_life_dt = end_of_life.replace(tzinfo=datetime.timezone.utc)
+ end_of_life_dt = end_of_life.replace(tzinfo=dt.timezone.utc)
else:
end_of_life_dt = end_of_life
- now_utc = datetime.datetime.now(datetime.UTC)
+ now_utc = dt.datetime.now(dt.UTC)
if now_utc >= end_of_life_dt:
return False
except (ValueError, AttributeError):
@@ -9633,11 +9633,11 @@ def validate_end_of_life_date(self, runtime, version, is_linux):
if runtime == 'custom':
return
- today = datetime.datetime.now(datetime.timezone.utc)
+ today = dt.datetime.now(dt.timezone.utc)
six_months = today + relativedelta(months=+6)
runtimes = [r for r in self.stacks if r.linux == is_linux and runtime == r.name]
runtimes.sort(key=lambda r: r.end_of_life_date or
- datetime.datetime.min.replace(tzinfo=datetime.timezone.utc), reverse=True)
+ dt.datetime.min.replace(tzinfo=dt.timezone.utc), reverse=True)
matched_runtime = next((r for r in runtimes if r.version == version), None)
if matched_runtime:
eol = matched_runtime.end_of_life_date
@@ -9716,7 +9716,7 @@ def get_default_version(self, runtime, functions_version, is_linux=False):
runtimes = [r for r in self.stacks if r.linux == is_linux and r.name == runtime]
# sort runtimes by end of life date
runtimes.sort(key=lambda r: r.end_of_life_date or
- datetime.datetime.min.replace(tzinfo=datetime.timezone.utc), reverse=True)
+ dt.datetime.min.replace(tzinfo=dt.timezone.utc), reverse=True)
for r in runtimes:
if functions_version in r.supported_func_versions:
return r
@@ -11203,7 +11203,7 @@ def _check_runtimestatus_with_deploymentstatusapi(cmd, resource_group_name, name
response_body = None
logger.warning('Polling the status of %s deployment. Start Time: %s UTC',
"async" if is_async else "sync",
- datetime.datetime.now(datetime.timezone.utc))
+ dt.datetime.now(dt.timezone.utc))
# verify if the app is a linux web app
if deploy_params is not None:
# Reuse the Site fetched (or cached) during the publish leg. Saves
diff --git a/src/azure-cli/azure/cli/command_modules/appservice/static_sites.py b/src/azure-cli/azure/cli/command_modules/appservice/static_sites.py
index d4aa68ff669..e0d4bff9e8e 100644
--- a/src/azure-cli/azure/cli/command_modules/appservice/static_sites.py
+++ b/src/azure-cli/azure/cli/command_modules/appservice/static_sites.py
@@ -14,7 +14,7 @@
from knack.log import get_logger
from urllib.parse import urlparse
import uuid
-from datetime import UTC, datetime, timedelta
+import datetime as dt
from .utils import normalize_sku_for_staticapp, raise_missing_token_suggestion, raise_missing_ado_token_suggestion
from .custom import show_app, _build_identities_info
@@ -406,7 +406,7 @@ def _get_ado_token(cmd, source):
body = {
"displayName": f"SWA Deployment Token (created via the Azure CLI) - {uuid.uuid4().hex}",
"scope": "vso.build_execute vso.code_full vso.variablegroups_manage",
- "validTo": (datetime.now(UTC) + timedelta(days=6 * 30)).isoformat(),
+ "validTo": (dt.datetime.now(dt.UTC) + dt.timedelta(days=6 * 30)).isoformat(),
"allOrgs": False,
"targetAccounts": [org_id],
}
diff --git a/src/azure-cli/azure/cli/command_modules/backup/custom.py b/src/azure-cli/azure/cli/command_modules/backup/custom.py
index 9e41769ab73..00ad234002a 100644
--- a/src/azure-cli/azure/cli/command_modules/backup/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/backup/custom.py
@@ -5,7 +5,7 @@
import time
import os
-from datetime import UTC, datetime, timedelta, timezone
+import datetime as dt
# pylint: disable=too-many-lines
from knack.log import get_logger
from knack.prompting import prompt_y_n
@@ -1215,7 +1215,7 @@ def update_policy_for_item(cmd, client, resource_group_name, vault_name, item, p
def backup_now(cmd, client, resource_group_name, vault_name, item, retain_until):
if retain_until is None:
- retain_until = datetime.now(timezone.utc) + timedelta(days=30)
+ retain_until = dt.datetime.now(dt.timezone.utc) + dt.timedelta(days=30)
# Get container and item URIs
container_uri = cust_help.get_protection_container_uri_from_id(item.id)
@@ -1860,7 +1860,7 @@ def stop_job(client, resource_group_name, vault_name, name, use_secondary_region
def wait_for_job(cmd, client, resource_group_name, vault_name, name, timeout=None, use_secondary_region=None):
logger.warning("Waiting for job '%s' ...", name)
- start_timestamp = datetime.now(UTC)
+ start_timestamp = dt.datetime.now(dt.UTC)
if use_secondary_region:
vault = vaults_cf(cmd.cli_ctx).get(resource_group_name, vault_name)
vault_location = vault.location
@@ -1869,7 +1869,7 @@ def wait_for_job(cmd, client, resource_group_name, vault_name, name, timeout=Non
job_details = client.get(azure_region, CrrJobRequest(resource_id=vault.id, job_name=name))
while cust_help.job_in_progress(job_details.properties.status):
if timeout:
- elapsed_time = datetime.now(UTC) - start_timestamp
+ elapsed_time = dt.datetime.now(dt.UTC) - start_timestamp
if elapsed_time.seconds > timeout:
logger.warning("Command timed out while waiting for job '%s'", name)
break
@@ -1879,7 +1879,7 @@ def wait_for_job(cmd, client, resource_group_name, vault_name, name, timeout=Non
job_details = client.get(vault_name, resource_group_name, name)
while cust_help.job_in_progress(job_details.properties.status):
if timeout:
- elapsed_time = datetime.now(UTC) - start_timestamp
+ elapsed_time = dt.datetime.now(dt.UTC) - start_timestamp
if elapsed_time.seconds > timeout:
logger.warning("Command timed out while waiting for job '%s'", name)
break
diff --git a/src/azure-cli/azure/cli/command_modules/backup/tests/latest/preparers.py b/src/azure-cli/azure/cli/command_modules/backup/tests/latest/preparers.py
index a06a09fcdec..99aae08be2b 100644
--- a/src/azure-cli/azure/cli/command_modules/backup/tests/latest/preparers.py
+++ b/src/azure-cli/azure/cli/command_modules/backup/tests/latest/preparers.py
@@ -5,7 +5,7 @@
import json
import os
-from datetime import UTC, datetime, timedelta
+import datetime as dt
from azure.cli.testsdk import CliTestError
from azure.cli.testsdk.preparers import AbstractPreparer, SingleValueReplacer, KeyVaultPreparer
@@ -395,7 +395,7 @@ def create_resource(self, name, **kwargs):
vault = self._get_vault(**kwargs)
vm = self._get_vm(**kwargs)
- retain_date = datetime.now(UTC) + timedelta(days=30)
+ retain_date = dt.datetime.now(dt.UTC) + dt.timedelta(days=30)
command_string = 'az backup protection backup-now --backup-management-type AzureIaasVM --workload-type VM -g {} -v {} -c {} -i {} --retain-until {} --query name'
command_string = command_string.format(self.resource_group, vault, vm, vm,
retain_date.strftime('%d-%m-%Y'))
@@ -817,7 +817,7 @@ def create_resource(self, name, **kwargs):
vault = self._get_vault(**kwargs)
afs = self._get_file_share(**kwargs)
- retain_date = datetime.now(UTC) + timedelta(days=30)
+ retain_date = dt.datetime.now(dt.UTC) + dt.timedelta(days=30)
retain_date = retain_date.strftime('%d-%m-%Y')
command_string = 'az backup protection backup-now'
command_string += ' -g {} -v {} -i {} -c {} --backup-management-type AzureStorage --retain-until {} --query name'
diff --git a/src/azure-cli/azure/cli/command_modules/backup/tests/latest/test_afs_commands.py b/src/azure-cli/azure/cli/command_modules/backup/tests/latest/test_afs_commands.py
index ed24a3cda3f..89906bbbbe6 100644
--- a/src/azure-cli/azure/cli/command_modules/backup/tests/latest/test_afs_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/backup/tests/latest/test_afs_commands.py
@@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------
import json
-from datetime import UTC, datetime, timedelta
+import datetime as dt
import unittest
import time
from azure.cli.testsdk import ScenarioTest, JMESPathCheckExists, \
@@ -42,7 +42,7 @@ def test_afs_backup_scenario(self, resource_group, vault_name, storage_account,
})
self.cmd('backup protection enable-for-azurefileshare -g {rg} -v {vault} --storage-account {container} --azure-file-share {item} -p {policy}')
- self.kwargs['retain_date'] = (datetime.now(UTC) + timedelta(days=30)).strftime('%d-%m-%Y')
+ self.kwargs['retain_date'] = (dt.datetime.now(dt.UTC) + dt.timedelta(days=30)).strftime('%d-%m-%Y')
self.kwargs['job'] = self.cmd('backup protection backup-now -g {rg} -v {vault} -c {container} -i {item} --retain-until {retain_date} --backup-management-type AzureStorage --query name').get_output_in_json()
self.cmd('backup job wait -g {rg} -v {vault} -n {job}')
@@ -384,7 +384,7 @@ def test_afs_backup_rp(self, resource_group, vault_name, storage_account, afs_na
rp_list = self.cmd('backup recoverypoint list -g {rg} -v {vault} -c {container} -i {item1} --backup-management-type {type}').get_output_in_json()
rp_count1 = len(rp_list)
- self.kwargs['retain_date'] = (datetime.now(UTC) + timedelta(days=30)).strftime('%d-%m-%Y')
+ self.kwargs['retain_date'] = (dt.datetime.now(dt.UTC) + dt.timedelta(days=30)).strftime('%d-%m-%Y')
self.kwargs['job'] = self.cmd('backup protection backup-now -g {rg} -v {vault} -c {container} -i {item1} --retain-until {retain_date} --backup-management-type AzureStorage --query name').get_output_in_json()
self.cmd('backup job wait -g {rg} -v {vault} -n {job}')
diff --git a/src/azure-cli/azure/cli/command_modules/backup/tests/latest/test_backup_commands.py b/src/azure-cli/azure/cli/command_modules/backup/tests/latest/test_backup_commands.py
index 06bf14528df..712137a8f3b 100644
--- a/src/azure-cli/azure/cli/command_modules/backup/tests/latest/test_backup_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/backup/tests/latest/test_backup_commands.py
@@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------
import json
-from datetime import UTC, datetime, timedelta
+import datetime as dt
from types import SimpleNamespace
import unittest
import time
@@ -107,7 +107,7 @@ def test_backup_scenario(self, resource_group, vault_name, vm_name, storage_acco
self.kwargs['item'] = self.cmd('backup item list -g {rg} -v {vault} -c {container} --backup-management-type AzureIaasVM --workload-type VM --query [0].properties.friendlyName').get_output_in_json()
# Trigger Backup
- self.kwargs['retain_date'] = (datetime.now(UTC) + timedelta(days=30)).strftime('%d-%m-%Y')
+ self.kwargs['retain_date'] = (dt.datetime.now(dt.UTC) + dt.timedelta(days=30)).strftime('%d-%m-%Y')
self.kwargs['job'] = self.cmd('backup protection backup-now -g {rg} -v {vault} -c {container} -i {item} --backup-management-type AzureIaasVM --workload-type VM --retain-until {retain_date} --query name').get_output_in_json()
self.cmd('backup job wait -g {rg} -v {vault} -n {job}')
@@ -1028,7 +1028,7 @@ def _free_csb_vm():
self.assertEqual(item['properties']['containerSubscriptionId'], self.kwargs['vm_sub'])
# Take an on-demand backup so there is a recovery point to restore from.
- self.kwargs['retain_date'] = (datetime.now(UTC) + timedelta(days=30)).strftime('%d-%m-%Y')
+ self.kwargs['retain_date'] = (dt.datetime.now(dt.UTC) + dt.timedelta(days=30)).strftime('%d-%m-%Y')
self.kwargs['backup_job'] = self.cmd('backup protection backup-now --backup-management-type AzureIaasVM '
'--workload-type VM -g {rg} -v {vault} -c {vm_name} -i {vm_name} '
'--retain-until {retain_date} --query name').get_output_in_json()
@@ -1510,7 +1510,7 @@ def test_backup_disk_exclusion(self, resource_group, vault_name, vm_name, storag
self.check('properties.extendedProperties.diskExclusionProperties.isInclusionList', False),
])
- self.kwargs['retain_date'] = (datetime.now(UTC) + timedelta(days=30)).strftime('%d-%m-%Y')
+ self.kwargs['retain_date'] = (dt.datetime.now(dt.UTC) + dt.timedelta(days=30)).strftime('%d-%m-%Y')
self.kwargs['job'] = self.cmd('backup protection backup-now -g {rg} -v {vault} -c {vm} -i {vm} --backup-management-type AzureIaasVM --workload-type VM --retain-until {retain_date} --query name').get_output_in_json()
self.cmd('backup job wait -g {rg} -v {vault} -n {job}')
diff --git a/src/azure-cli/azure/cli/command_modules/batchai/custom.py b/src/azure-cli/azure/cli/command_modules/batchai/custom.py
index 56ffea22c4c..663352ccd85 100644
--- a/src/azure-cli/azure/cli/command_modules/batchai/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/batchai/custom.py
@@ -6,7 +6,7 @@
# pylint: disable=too-many-lines
import collections
import copy
-import datetime
+import datetime as dt
import json
import os
import signal
@@ -794,7 +794,7 @@ def _get_files_from_bfs(cli_ctx, bfs, path, expiry):
if b.properties.content_settings.contentMd5 is not None:
name = os.path.basename(b.name)
sas = sas_client.generate_blob(bfs.container_name, b.name, permission=BlobSasPermissions(read=True),
- expiry=datetime.datetime.now(datetime.UTC) + datetime.timedelta(minutes=expiry))
+ expiry=dt.datetime.now(dt.UTC) + dt.timedelta(minutes=expiry))
blob_url = b.url
if '?' not in blob_url:
blob_url += '?' + sas
@@ -843,7 +843,7 @@ def _get_files_from_afs(cli_ctx, afs, path, expiry):
if not f.is_directory:
sas = sas_client.generate_file(share_name, directory_name=effective_path, file_name=f.name,
permission=FileSasPermissions(read=True),
- expiry=datetime.datetime.now(datetime.UTC) + datetime.timedelta(minutes=expiry))
+ expiry=dt.datetime.now(dt.UTC) + dt.timedelta(minutes=expiry))
file_url = share_client.url + '/' + effective_path + '/' + f.name
if '?' not in file_url:
file_url += '?' + sas
diff --git a/src/azure-cli/azure/cli/command_modules/containerapp/_github_oauth.py b/src/azure-cli/azure/cli/command_modules/containerapp/_github_oauth.py
index 0e2583c4cd7..4070ba89008 100644
--- a/src/azure-cli/azure/cli/command_modules/containerapp/_github_oauth.py
+++ b/src/azure-cli/azure/cli/command_modules/containerapp/_github_oauth.py
@@ -6,7 +6,7 @@
import os
import sys
-from datetime import UTC, datetime
+import datetime as dt
from knack.log import get_logger
from azure.cli.core.util import open_page_in_browser
@@ -49,10 +49,10 @@ def cache_github_token(cmd, token, repo):
if isinstance(entry, dict) and entry.get("value") == token:
if repo not in entry.get("repos", []):
entry["repos"] = [*entry.get("repos", []), repo]
- entry["last_modified_timestamp"] = datetime.now(UTC).timestamp()
+ entry["last_modified_timestamp"] = dt.datetime.now(dt.UTC).timestamp()
break
else:
- cache_entry = {"last_modified_timestamp": datetime.now(UTC).timestamp(), "value": token, "repos": [repo]}
+ cache_entry = {"last_modified_timestamp": dt.datetime.now(dt.UTC).timestamp(), "value": token, "repos": [repo]}
cache = [cache_entry, *cache]
secret_store.save(cache)
diff --git a/src/azure-cli/azure/cli/command_modules/containerapp/_utils.py b/src/azure-cli/azure/cli/command_modules/containerapp/_utils.py
index 7a5af84a314..d4b1652a710 100644
--- a/src/azure-cli/azure/cli/command_modules/containerapp/_utils.py
+++ b/src/azure-cli/azure/cli/command_modules/containerapp/_utils.py
@@ -21,7 +21,7 @@
from urllib.parse import urlparse
from urllib.request import urlopen
-from datetime import UTC, datetime
+import datetime as dt
from dateutil.relativedelta import relativedelta
from azure.cli.core.azclierror import (ValidationError, RequiredArgumentMissingError, CLIInternalError,
ResourceNotFoundError, FileOperationError, CLIError, UnauthorizedError,
@@ -161,7 +161,7 @@ def create_service_principal_for_github_action(cmd, scopes=None, role="contribut
RETRY_LIMIT = 36
client = graph_client_factory(cmd.cli_ctx)
- now = datetime.now(UTC)
+ now = dt.datetime.now(dt.UTC)
app_display_name = 'azure-cli-' + now.strftime('%Y-%m-%d-%H-%M-%S')
app = retry_until_success(_create_application, SP_CREATION_ERR_TXT, RETRY_LIMIT, client, display_name=app_display_name)
sp = retry_until_success(_create_service_principal, SP_CREATION_ERR_TXT, RETRY_LIMIT, client, app_id=app["appId"])
@@ -221,7 +221,7 @@ def trigger_workflow(token, repo, workflow_name, branch):
def await_github_action(token, repo, workflow_name, timeout_secs=1200):
from ._clients import PollingAnimation
- start = datetime.now(UTC)
+ start = dt.datetime.now(dt.UTC)
animation = PollingAnimation()
animation.tick()
@@ -237,14 +237,14 @@ def await_github_action(token, repo, workflow_name, timeout_secs=1200):
pass
animation.flush()
- if (datetime.now(UTC) - start).seconds >= timeout_secs:
+ if (dt.datetime.now(dt.UTC) - start).seconds >= timeout_secs:
raise CLIInternalError("Timed out while waiting for the Github action to start.")
runs = workflow.get_runs()
while runs is None or not [r for r in runs if r.status in ('queued', 'in_progress')]:
time.sleep(SHORT_POLLING_INTERVAL_SECS)
runs = workflow.get_runs()
- if (datetime.now(UTC) - start).seconds >= timeout_secs:
+ if (dt.datetime.now(dt.UTC) - start).seconds >= timeout_secs:
raise CLIInternalError("Timed out while waiting for the Github action to be started.")
runs = [r for r in runs if r.status in ('queued', 'in_progress')]
runs.sort(key=lambda r: r.created_at, reverse=True)
@@ -258,7 +258,7 @@ def await_github_action(token, repo, workflow_name, timeout_secs=1200):
animation.tick()
status = github_repo.get_workflow_run(run_id).status
animation.flush()
- if (datetime.now(UTC) - start).seconds >= timeout_secs:
+ if (dt.datetime.now(dt.UTC) - start).seconds >= timeout_secs:
raise CLIInternalError("Timed out while waiting for the Github action to complete.")
animation.flush() # needed to clear the animation from the terminal
@@ -294,11 +294,11 @@ def _register_resource_provider(cmd, resource_provider):
# wait for registration to finish
timeout_secs = 120
registration = _is_resource_provider_registered(cmd, resource_provider)
- start = datetime.now(UTC)
+ start = dt.datetime.now(dt.UTC)
while not registration:
registration = _is_resource_provider_registered(cmd, resource_provider)
time.sleep(SHORT_POLLING_INTERVAL_SECS)
- if (datetime.now(UTC) - start).seconds >= timeout_secs:
+ if (dt.datetime.now(dt.UTC) - start).seconds >= timeout_secs:
raise CLIInternalError(f"Timed out while waiting for the {resource_provider} resource provider to be registered.")
except Exception as e:
@@ -909,7 +909,7 @@ def _add_or_update_tags(containerapp_def, tags):
def _object_to_dict(obj):
def default_handler(x):
- if isinstance(x, datetime):
+ if isinstance(x, dt.datetime):
return x.isoformat()
return x.__dict__
diff --git a/src/azure-cli/azure/cli/command_modules/cosmosdb/custom.py b/src/azure-cli/azure/cli/command_modules/cosmosdb/custom.py
index 2274aff75b4..20e69a11fab 100644
--- a/src/azure-cli/azure/cli/command_modules/cosmosdb/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/cosmosdb/custom.py
@@ -5,7 +5,7 @@
# pylint: disable=too-many-lines
-import datetime
+import datetime as dt
from enum import Enum
from knack.log import get_logger
from knack.util import CLIError
@@ -1900,7 +1900,7 @@ def cli_cosmosdb_restore(cmd,
target_restorable_account = None
restore_timestamp_datetime_utc = _convert_to_utc_timestamp(restore_timestamp)
- current_dateTime = datetime.datetime.now(datetime.UTC)
+ current_dateTime = dt.datetime.now(dt.UTC)
# Fail if provided restoretimesamp is greater than current timestamp
if restore_timestamp_datetime_utc > current_dateTime:
@@ -1950,9 +1950,9 @@ def _convert_to_utc_timestamp(timestamp_string):
timestamp_datetime_utc = None
# Treat timestamps without an offset as UTC.
if timestamp_datetime.tzinfo is not None and timestamp_datetime.tzinfo.utcoffset(timestamp_datetime) is not None:
- timestamp_datetime_utc = timestamp_datetime.astimezone(datetime.timezone.utc)
+ timestamp_datetime_utc = timestamp_datetime.astimezone(dt.timezone.utc)
else:
- timestamp_datetime_utc = timestamp_datetime.replace(tzinfo=datetime.UTC)
+ timestamp_datetime_utc = timestamp_datetime.replace(tzinfo=dt.UTC)
return timestamp_datetime_utc
@@ -2808,15 +2808,15 @@ def cli_cosmosdb_managed_cassandra_datacenter_update(client,
def process_restorable_databases(restorable_databases, database_name):
- latest_database_delete_time = datetime.datetime.utcfromtimestamp(0)
- latest_database_create_or_recreate_time = datetime.datetime.utcfromtimestamp(0)
+ latest_database_delete_time = dt.datetime.utcfromtimestamp(0)
+ latest_database_create_or_recreate_time = dt.datetime.utcfromtimestamp(0)
database_rid = None
for restorable_database in restorable_databases:
resource = restorable_database.resource
if resource.owner_id == database_name:
database_rid = resource.owner_resource_id
- event_timestamp = datetime.datetime.strptime(resource.event_timestamp, "%Y-%m-%dT%H:%M:%SZ")
+ event_timestamp = dt.datetime.strptime(resource.event_timestamp, "%Y-%m-%dT%H:%M:%SZ")
if resource.operation_type == "Delete" and latest_database_delete_time < event_timestamp:
latest_database_delete_time = event_timestamp
@@ -2827,7 +2827,7 @@ def process_restorable_databases(restorable_databases, database_name):
raise CLIError("No restorable database found with name: {}".format(database_name))
# Database never deleted then reset it to max time
- latest_database_delete_time = datetime.datetime.max if latest_database_delete_time == datetime.datetime.utcfromtimestamp(0) else latest_database_delete_time
+ latest_database_delete_time = dt.datetime.max if latest_database_delete_time == dt.datetime.utcfromtimestamp(0) else latest_database_delete_time
logger.debug('process_restorable_databases: latest_database_delete_time {} latest_database_create_or_recreate_time {} database_name {}'.format(latest_database_delete_time, latest_database_create_or_recreate_time, database_name)) # pylint: disable=logging-format-interpolation
@@ -2835,15 +2835,15 @@ def process_restorable_databases(restorable_databases, database_name):
def process_restorable_collections(restorable_collections, collection_name, database_name):
- latest_collection_delete_time = datetime.datetime.utcfromtimestamp(0)
- latest_collection_create_or_recreate_time = datetime.datetime.utcfromtimestamp(0)
+ latest_collection_delete_time = dt.datetime.utcfromtimestamp(0)
+ latest_collection_create_or_recreate_time = dt.datetime.utcfromtimestamp(0)
collection_rid = None
for restorable_collection in restorable_collections:
resource = restorable_collection.resource
if resource.owner_id == collection_name:
collection_rid = resource.owner_resource_id
- event_timestamp = datetime.datetime.strptime(resource.event_timestamp, "%Y-%m-%dT%H:%M:%SZ")
+ event_timestamp = dt.datetime.strptime(resource.event_timestamp, "%Y-%m-%dT%H:%M:%SZ")
if resource.operation_type == "Delete" and latest_collection_delete_time < event_timestamp:
latest_collection_delete_time = event_timestamp
@@ -2854,7 +2854,7 @@ def process_restorable_collections(restorable_collections, collection_name, data
raise CLIError("No restorable collection with name: {} found in the database with name: {}".format(collection_name, database_name))
# Collection never deleted then reset it to max time
- latest_collection_delete_time = datetime.datetime.max if latest_collection_delete_time == datetime.datetime.utcfromtimestamp(0) else latest_collection_delete_time
+ latest_collection_delete_time = dt.datetime.max if latest_collection_delete_time == dt.datetime.utcfromtimestamp(0) else latest_collection_delete_time
logger.debug('process_restorable_databases: latest_collection_delete_time {} latest_collection_create_or_recreate_time {} database_name {} collection_name {}'.format(latest_collection_delete_time, latest_collection_create_or_recreate_time, database_name, collection_name)) # pylint: disable=logging-format-interpolation
@@ -2912,13 +2912,13 @@ def cli_cosmosdb_sql_database_restore(cmd,
latest_database_delete_time, latest_database_create_or_recreate_time, database_rid = process_restorable_databases(restorable_databases, database_name) # pylint: disable=unused-variable
# Database is alive if create or recreate timestamp is later than latest delete timestamp
- database_alive = latest_database_create_or_recreate_time > latest_database_delete_time or latest_database_delete_time == datetime.datetime.max
+ database_alive = latest_database_create_or_recreate_time > latest_database_delete_time or latest_database_delete_time == dt.datetime.max
if database_alive:
raise CLIError("Database with name {} already exists in this account with name {} in location {}".format(database_name, account_name, restorable_database_account.location))
# """Subtracting -1 second from the deleted timestamp to restore till end of logchain"""
- restore_time = latest_database_delete_time + datetime.timedelta(seconds=-1)
+ restore_time = latest_database_delete_time + dt.timedelta(seconds=-1)
restore_timestamp = restore_time.strftime("%Y-%m-%dT%H:%M:%S%Z")
except ResourceNotFoundError:
raise CLIError("Cannot find a database account with name {} that is online in location {}".format(account_name, restorable_database_account.location))
@@ -3000,7 +3000,7 @@ def cli_cosmosdb_sql_container_restore(cmd,
latest_database_delete_time, latest_database_create_or_recreate_time, database_rid = process_restorable_databases(restorable_databases, database_name)
# Database is alive if create or recreate timestamp is later than latest delete timestamp
- database_alive = latest_database_delete_time == datetime.datetime.max or latest_database_create_or_recreate_time > latest_database_delete_time
+ database_alive = latest_database_delete_time == dt.datetime.max or latest_database_create_or_recreate_time > latest_database_delete_time
if not database_alive:
raise CLIError("No active database with name {} found that contains the collection {}".format(database_name, container_name))
@@ -3015,13 +3015,13 @@ def cli_cosmosdb_sql_container_restore(cmd,
latest_container_delete_time, latest_container_create_or_recreate_time = process_restorable_collections(restorable_containers, container_name, database_name)
# Container is alive if create or recreate timestamp is later than latest delete timestamp
- container_alive = latest_container_create_or_recreate_time > latest_container_delete_time or latest_container_delete_time == datetime.datetime.max
+ container_alive = latest_container_create_or_recreate_time > latest_container_delete_time or latest_container_delete_time == dt.datetime.max
if container_alive:
raise CLIError("The collection {} is currently online. Please delete the collection and provide a restore timestamp for restoring different instance of the collection.".format(container_name))
# """Subtracting -1 second from the deleted timestamp to restore till end of logchain"""
- restore_time = latest_container_delete_time + datetime.timedelta(seconds=-1)
+ restore_time = latest_container_delete_time + dt.timedelta(seconds=-1)
restore_timestamp = restore_time.strftime("%Y-%m-%dT%H:%M:%S%Z")
except ResourceNotFoundError:
raise CLIError("Cannot find a database account with name {} that is online in location {}".format(account_name, restorable_database_account.location))
@@ -3104,13 +3104,13 @@ def cli_cosmosdb_mongodb_database_restore(cmd,
latest_database_delete_time, latest_database_create_or_recreate_time, database_rid = process_restorable_databases(restorable_databases, database_name) # pylint: disable=unused-variable
# Database is alive if create or recreate timestamp is later than latest delete timestamp
- database_alive = latest_database_create_or_recreate_time > latest_database_delete_time or latest_database_delete_time == datetime.datetime.max
+ database_alive = latest_database_create_or_recreate_time > latest_database_delete_time or latest_database_delete_time == dt.datetime.max
if database_alive:
raise CLIError("Database with name {} already exists in this account with name {} in location {}".format(database_name, account_name, restorable_database_account.location))
# """Subtracting -1 second from the deleted timestamp to restore till end of logchain"""
- restore_time = latest_database_delete_time + datetime.timedelta(seconds=-1)
+ restore_time = latest_database_delete_time + dt.timedelta(seconds=-1)
restore_timestamp = restore_time.strftime("%Y-%m-%dT%H:%M:%S%Z")
except ResourceNotFoundError:
raise CLIError("Cannot find a database account with name {} that is online in location {}".format(account_name, restorable_database_account.location))
@@ -3191,7 +3191,7 @@ def cli_cosmosdb_mongodb_collection_restore(cmd,
latest_database_delete_time, latest_database_create_or_recreate_time, database_rid = process_restorable_databases(restorable_databases, database_name)
# Database is alive if create or recreate timestamp is later than latest delete timestamp
- database_alive = latest_database_delete_time == datetime.datetime.max or latest_database_create_or_recreate_time > latest_database_delete_time
+ database_alive = latest_database_delete_time == dt.datetime.max or latest_database_create_or_recreate_time > latest_database_delete_time
if not database_alive:
raise CLIError("Cannot find a database account with name {} that is online when latest collection instance was deleted".format(account_name))
@@ -3206,13 +3206,13 @@ def cli_cosmosdb_mongodb_collection_restore(cmd,
latest_collection_delete_time, latest_collection_create_or_recreate_time = process_restorable_collections(restorable_collections, collection_name, database_name)
# Collection is alive if create or recreate timestamp is later than latest delete timestamp
- collection_alive = latest_collection_create_or_recreate_time > latest_collection_delete_time or latest_collection_delete_time == datetime.datetime.max
+ collection_alive = latest_collection_create_or_recreate_time > latest_collection_delete_time or latest_collection_delete_time == dt.datetime.max
if collection_alive:
raise CLIError("The collection {} is currently online. Please delete the collection and provide a restore timestamp for restoring different instance of the collection.".format(collection_name))
# """Subtracting -1 second from the deleted timestamp to restore till end of logchain"""
- restore_time = latest_collection_delete_time + datetime.timedelta(seconds=-1)
+ restore_time = latest_collection_delete_time + dt.timedelta(seconds=-1)
restore_timestamp = restore_time.strftime("%Y-%m-%dT%H:%M:%S%Z")
except ResourceNotFoundError:
raise CLIError("Cannot find a database account with name {} that is online in location {}".format(account_name, restorable_database_account.location))
@@ -3294,13 +3294,13 @@ def cli_cosmosdb_gremlin_database_restore(cmd,
latest_database_delete_time, latest_database_create_or_recreate_time, database_rid = process_restorable_databases(restorable_databases, database_name) # pylint: disable=unused-variable
# Database is alive if create or recreate timestamp is later than latest delete timestamp
- database_alive = latest_database_create_or_recreate_time > latest_database_delete_time or latest_database_delete_time == datetime.datetime.max
+ database_alive = latest_database_create_or_recreate_time > latest_database_delete_time or latest_database_delete_time == dt.datetime.max
if database_alive:
raise CLIError("Database with name {} already exists in this account with name {} in location {}".format(database_name, account_name, restorable_database_account.location))
# """Subtracting -1 second from the deleted timestamp to restore till end of logchain"""
- restore_time = latest_database_delete_time + datetime.timedelta(seconds=-1)
+ restore_time = latest_database_delete_time + dt.timedelta(seconds=-1)
restore_timestamp = restore_time.strftime("%Y-%m-%dT%H:%M:%S%Z")
except ResourceNotFoundError:
raise CLIError("Cannot find a Gremlin database account with name {} that is online in location {}".format(account_name, restorable_database_account.location))
@@ -3382,7 +3382,7 @@ def cli_cosmosdb_gremlin_graph_restore(cmd,
latest_database_delete_time, latest_database_create_or_recreate_time, database_rid = process_restorable_databases(restorable_databases, database_name)
# Database is alive if create or recreate timestamp is later than latest delete timestamp
- database_alive = latest_database_delete_time == datetime.datetime.max or latest_database_create_or_recreate_time > latest_database_delete_time
+ database_alive = latest_database_delete_time == dt.datetime.max or latest_database_create_or_recreate_time > latest_database_delete_time
if not database_alive:
raise CLIError("No active database with name {} found that contains the graph {}".format(database_name, graph_name))
@@ -3397,13 +3397,13 @@ def cli_cosmosdb_gremlin_graph_restore(cmd,
latest_graph_delete_time, latest_graph_create_or_recreate_time = process_restorable_collections(restorable_graphs, graph_name, database_name)
# Graph is alive if create or recreate timestamp is later than latest delete timestamp
- graph_alive = latest_graph_create_or_recreate_time > latest_graph_delete_time or latest_graph_delete_time == datetime.datetime.max
+ graph_alive = latest_graph_create_or_recreate_time > latest_graph_delete_time or latest_graph_delete_time == dt.datetime.max
if graph_alive:
raise CLIError("The graph {} is currently online. Please delete the graph and provide a restore timestamp for restoring different instance of the graph.".format(graph_name))
# """Subtracting -1 second from the deleted timestamp to restore till end of logchain"""
- restore_time = latest_graph_delete_time + datetime.timedelta(seconds=-1)
+ restore_time = latest_graph_delete_time + dt.timedelta(seconds=-1)
restore_timestamp = restore_time.strftime("%Y-%m-%dT%H:%M:%S%Z")
except ResourceNotFoundError:
raise CLIError("Cannot find a database account with name {} that is online in location {}".format(account_name, restorable_database_account.location))
@@ -3486,13 +3486,13 @@ def cli_cosmosdb_table_restore(cmd,
latest_table_delete_time, latest_table_create_or_recreate_time, table_rid = process_restorable_databases(restorable_tables, table_name) # pylint: disable=unused-variable
# Table is alive if create or recreate timestamp is later than latest delete timestamp
- table_alive = latest_table_create_or_recreate_time > latest_table_delete_time or latest_table_delete_time == datetime.datetime.max
+ table_alive = latest_table_create_or_recreate_time > latest_table_delete_time or latest_table_delete_time == dt.datetime.max
if table_alive:
raise CLIError("Table with name {} already exists in this account with name {} in location {}".format(table_name, account_name, restorable_database_account.location))
# """Subtracting -1 second from the deleted timestamp to restore till end of logchain"""
- restore_time = latest_table_delete_time + datetime.timedelta(seconds=-1)
+ restore_time = latest_table_delete_time + dt.timedelta(seconds=-1)
restore_timestamp = restore_time.strftime("%Y-%m-%dT%H:%M:%S%Z")
except ResourceNotFoundError:
raise CLIError("Cannot find a table account with name {} that is online in location {}".format(account_name, restorable_database_account.location))
diff --git a/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py b/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py
index a86521137e0..7045ff4aa66 100644
--- a/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py
+++ b/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py
@@ -10,7 +10,7 @@
from azure.cli.testsdk import (ScenarioTest, ResourceGroupPreparer, live_only)
from azure.cli.testsdk.scenario_tests import AllowLargeResponse
-from datetime import UTC, datetime, timedelta
+import datetime as dt
from dateutil import parser
@@ -288,7 +288,7 @@ def test_cosmosdb_system_identity_restore(self, resource_group):
account_creation_time = restorable_database_account['creationTime']
creation_timestamp_datetime = parser.parse(account_creation_time)
- restore_ts = creation_timestamp_datetime + timedelta(minutes=4)
+ restore_ts = creation_timestamp_datetime + dt.timedelta(minutes=4)
import time
time.sleep(240)
restore_ts_string = restore_ts.isoformat()
@@ -364,7 +364,7 @@ def test_cosmosdb_public_network_access_restore(self, resource_group):
account_creation_time = restorable_database_account['creationTime']
creation_timestamp_datetime = parser.parse(account_creation_time)
- restore_ts = creation_timestamp_datetime + timedelta(minutes=4)
+ restore_ts = creation_timestamp_datetime + dt.timedelta(minutes=4)
import time
time.sleep(240)
restore_ts_string = restore_ts.isoformat()
@@ -438,7 +438,7 @@ def test_cosmosdb_xrr(self, resource_group):
# So, we need to wait one hour in order to get the master backup for a restore to be performed.
account_creation_time = restorable_database_account['creationTime']
creation_timestamp_datetime = parser.parse(account_creation_time)
- restore_ts = creation_timestamp_datetime + timedelta(minutes=61)
+ restore_ts = creation_timestamp_datetime + dt.timedelta(minutes=61)
import time
# Cross region restore does not have a forced master backup during restore, so we need
# to wait one hour to get the master backup for a restore to be performed. This wait is
@@ -509,7 +509,7 @@ def test_cosmosdb_xrr_single_region_account(self, resource_group):
# So, we need to wait one hour in order to get the master backup for a restore to be performed.
account_creation_time = restorable_database_account['creationTime']
creation_timestamp_datetime = parser.parse(account_creation_time)
- restore_ts = creation_timestamp_datetime + timedelta(minutes=61)
+ restore_ts = creation_timestamp_datetime + dt.timedelta(minutes=61)
import time
time.sleep(3662)
restore_ts_string = restore_ts.isoformat()
@@ -533,7 +533,7 @@ class CosmosDBRestoreUnitTests(unittest.TestCase):
def test_restore_timestamp_is_utc(self):
from azure.cli.command_modules.cosmosdb.custom import _convert_to_utc_timestamp
- expected = datetime(2020, 1, 1, tzinfo=UTC)
+ expected = dt.datetime(2020, 1, 1, tzinfo=dt.UTC)
for timestamp in ['2020-01-01T00:00:00', '2020-01-01T00:00:00Z',
'2020-01-01T02:00:00+02:00', '2019-12-31T19:00:00-05:00']:
with self.subTest(timestamp=timestamp):
@@ -545,7 +545,7 @@ def test_restore_accepts_timestamp_without_offset(self, get_accounts, create_acc
from azure.cli.command_modules.cosmosdb.custom import cli_cosmosdb_restore
account = mock.Mock(account_name='source', deletion_time=None,
- creation_time=datetime(2000, 1, 1, tzinfo=UTC))
+ creation_time=dt.datetime(2000, 1, 1, tzinfo=dt.UTC))
get_accounts.return_value.list.return_value = [account]
cli_cosmosdb_restore(mock.Mock(), mock.Mock(), 'rg', 'source', 'target',
'2020-01-01T00:00:00', 'westus')
diff --git a/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_commands.py b/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_commands.py
index ed6be07b4dc..783e6e0fe3b 100644
--- a/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_commands.py
@@ -10,7 +10,7 @@
from azure.cli.testsdk import JMESPathCheck, ScenarioTest, ResourceGroupPreparer, KeyVaultPreparer, record_only
from knack.util import CLIError
from azure.cli.testsdk.scenario_tests import AllowLargeResponse
-from datetime import UTC, datetime, timedelta, timezone
+import datetime as dt
from dateutil import parser
class CosmosDBTests(ScenarioTest):
@@ -2083,9 +2083,8 @@ def test_cosmosdb_restore_using_create(self, resource_group, location):
account_creation_time = restorable_database_account['creationTime']
import dateutil.parser
- from datetime import timedelta
creation_timestamp_datetime = dateutil.parser.parse(account_creation_time)
- restore_ts = creation_timestamp_datetime + timedelta(minutes=4)
+ restore_ts = creation_timestamp_datetime + dt.timedelta(minutes=4)
restore_ts_string = restore_ts.isoformat()
import time
time.sleep(300)
@@ -2125,17 +2124,16 @@ def test_cosmosdb_restore_command(self, resource_group, location):
import dateutil.parser
import time
- from datetime import timedelta, datetime
# This should fail as restore time is before account creation time
- invalid_restore_time = dateutil.parser.parse(restorable_database_account['creationTime']) - timedelta(days=30)
+ invalid_restore_time = dateutil.parser.parse(restorable_database_account['creationTime']) - dt.timedelta(days=30)
self.kwargs.update({
'invalid_restore_time': invalid_restore_time.isoformat()
})
self.assertRaises(Exception, lambda: self.cmd('az cosmosdb restore --account-name {acc} -g {rg} --restore-timestamp {invalid_restore_time} --location {loc} --target-database-account-name {restored_acc}'))
# This should fail as restore time is in future
- invalid_restore_time = datetime.now() + timedelta(days=30)
+ invalid_restore_time = dt.datetime.now() + dt.timedelta(days=30)
self.kwargs.update({
'invalid_restore_time': invalid_restore_time.isoformat()
})
@@ -2144,7 +2142,7 @@ def test_cosmosdb_restore_command(self, resource_group, location):
# Get correct restore ts
account_creation_time = restorable_database_account['creationTime']
creation_timestamp_datetime = dateutil.parser.parse(account_creation_time)
- restore_ts = creation_timestamp_datetime + timedelta(minutes=4)
+ restore_ts = creation_timestamp_datetime + dt.timedelta(minutes=4)
restore_ts_string = restore_ts.isoformat()
self.kwargs.update({
@@ -2204,12 +2202,11 @@ def test_cosmosdb_deleted_account_restore(self, resource_group, location):
import dateutil.parser
import time
- from datetime import timedelta
# Get correct restore ts
account_creation_time = restorable_database_account['creationTime']
creation_timestamp_datetime = dateutil.parser.parse(account_creation_time)
- restore_ts = creation_timestamp_datetime + timedelta(minutes=4)
+ restore_ts = creation_timestamp_datetime + dt.timedelta(minutes=4)
restore_ts_string = restore_ts.isoformat()
self.kwargs.update({
@@ -2267,9 +2264,8 @@ def test_cosmosdb_sql_restorable_commands(self, resource_group, location):
account_creation_time = restorable_database_account['creationTime']
import dateutil.parser
- from datetime import timedelta
creation_timestamp_datetime = dateutil.parser.parse(account_creation_time)
- restore_ts = creation_timestamp_datetime + timedelta(minutes=2)
+ restore_ts = creation_timestamp_datetime + dt.timedelta(minutes=2)
import time
time.sleep(200)
restore_ts_string = restore_ts.isoformat()
@@ -2324,9 +2320,8 @@ def test_cosmosdb_mongodb_restorable_commands(self, resource_group, location):
account_creation_time = restorable_database_account['creationTime']
import dateutil.parser
- from datetime import timedelta
creation_timestamp_datetime = dateutil.parser.parse(account_creation_time)
- restore_ts = creation_timestamp_datetime + timedelta(minutes=2)
+ restore_ts = creation_timestamp_datetime + dt.timedelta(minutes=2)
import time
time.sleep(200)
restore_ts_string = restore_ts.isoformat()
@@ -2505,7 +2500,7 @@ def test_cosmosdb_gremlin_account_restore_using_create(self, resource_group):
account_creation_time = restorable_database_account['creationTime']
creation_timestamp_datetime = parser.parse(account_creation_time)
- restore_ts = creation_timestamp_datetime + timedelta(minutes=4)
+ restore_ts = creation_timestamp_datetime + dt.timedelta(minutes=4)
restore_ts_string = restore_ts.isoformat()
import time
time.sleep(240)
@@ -2547,7 +2542,7 @@ def test_cosmosdb_gremlin_account_restore_command(self, resource_group):
account_creation_time = restorable_database_account['creationTime']
creation_timestamp_datetime = parser.parse(account_creation_time)
- restore_ts = creation_timestamp_datetime + timedelta(minutes=4)
+ restore_ts = creation_timestamp_datetime + dt.timedelta(minutes=4)
import time
time.sleep(240)
restore_ts_string = restore_ts.isoformat()
@@ -2601,7 +2596,7 @@ def test_cosmosdb_gremlin_restorable_commands(self, resource_group):
account_creation_time = restorable_database_account['creationTime']
creation_timestamp_datetime = parser.parse(account_creation_time)
- restore_ts = creation_timestamp_datetime + timedelta(minutes=2)
+ restore_ts = creation_timestamp_datetime + dt.timedelta(minutes=2)
import time
time.sleep(120)
restore_ts_string = restore_ts.isoformat()
@@ -2636,7 +2631,7 @@ def test_cosmosdb_table_account_restore_using_create(self, resource_group):
account_creation_time = restorable_database_account['creationTime']
creation_timestamp_datetime = parser.parse(account_creation_time)
- restore_ts = creation_timestamp_datetime + timedelta(minutes=4)
+ restore_ts = creation_timestamp_datetime + dt.timedelta(minutes=4)
restore_ts_string = restore_ts.isoformat()
import time
time.sleep(240)
@@ -2676,7 +2671,7 @@ def test_cosmosdb_table_account_restore_command(self, resource_group):
account_creation_time = restorable_database_account['creationTime']
creation_timestamp_datetime = parser.parse(account_creation_time)
- restore_ts = creation_timestamp_datetime + timedelta(minutes=4)
+ restore_ts = creation_timestamp_datetime + dt.timedelta(minutes=4)
import time
time.sleep(240)
restore_ts_string = restore_ts.isoformat()
@@ -2723,7 +2718,7 @@ def test_cosmosdb_table_restorable_commands(self, resource_group):
account_creation_time = restorable_database_account['creationTime']
creation_timestamp_datetime = parser.parse(account_creation_time)
- restore_ts = creation_timestamp_datetime + timedelta(minutes=2)
+ restore_ts = creation_timestamp_datetime + dt.timedelta(minutes=2)
import time
time.sleep(120)
restore_ts_string = restore_ts.isoformat()
@@ -2934,7 +2929,7 @@ def test_cosmosdb_sql_normal_database_restore(self, resource_group):
database_list = self.cmd('az cosmosdb sql database list -g {rg} -a {acc}').get_output_in_json()
assert len(database_list) == 1
- restore_ts_string = datetime.now(UTC).isoformat()
+ restore_ts_string = dt.datetime.now(dt.UTC).isoformat()
self.kwargs.update({
'rts': restore_ts_string
@@ -3019,7 +3014,7 @@ def test_cosmosdb_sql_shared_database_restore(self, resource_group):
container_list = self.cmd('az cosmosdb sql container list -g {rg} -a {acc} -d {db_name}').get_output_in_json()
assert len(container_list) == 1
- restore_ts_string = datetime.now(UTC).isoformat()
+ restore_ts_string = dt.datetime.now(dt.UTC).isoformat()
self.kwargs.update({
'rts': restore_ts_string,
@@ -3125,7 +3120,7 @@ def test_cosmosdb_sql_normal_database_prov_container_restore(self, resource_grou
container_list = self.cmd('az cosmosdb sql container list -g {rg} -a {acc} -d {db_name}').get_output_in_json()
assert len(container_list) == 1
- restore_ts_string = datetime.now(UTC).isoformat()
+ restore_ts_string = dt.datetime.now(dt.UTC).isoformat()
self.kwargs.update({
'rts': restore_ts_string
@@ -3209,7 +3204,7 @@ def test_cosmosdb_sql_normal_database_prov_container_restore_nt(self, resource_g
container_list = self.cmd('az cosmosdb sql container list -g {rg} -a {acc} -d {db_name}').get_output_in_json()
assert len(container_list) == 1
- restore_ts_string = datetime.now(UTC).isoformat()
+ restore_ts_string = dt.datetime.now(dt.UTC).isoformat()
self.kwargs.update({
'rts': restore_ts_string
@@ -3301,7 +3296,7 @@ def test_cosmosdb_sql_shared_database_prov_container_restore(self, resource_grou
container_list = self.cmd('az cosmosdb sql container list -g {rg} -a {acc} -d {db_name}').get_output_in_json()
assert len(container_list) == 1
- restore_ts_string = datetime.now(UTC).isoformat()
+ restore_ts_string = dt.datetime.now(dt.UTC).isoformat()
self.kwargs.update({
'rts': restore_ts_string
@@ -3381,7 +3376,7 @@ def test_cosmosdb_mongodb_normal_database_prov_collection_restore(self, resource
assert self.cmd('az cosmosdb mongodb collection exists -g {rg} -a {acc} -d {db_name} -n {col_name}').get_output_in_json()
- restore_ts_string = datetime.now(UTC).isoformat()
+ restore_ts_string = dt.datetime.now(dt.UTC).isoformat()
self.kwargs.update({
'rts': restore_ts_string
@@ -3508,7 +3503,7 @@ def test_cosmosdb_mongodb_shared_database_prov_collection_restore(self, resource
assert self.cmd('az cosmosdb mongodb collection exists -g {rg} -a {acc} -d {db_name} -n {col_name}').get_output_in_json()
- restore_ts_string = datetime.now(UTC).isoformat()
+ restore_ts_string = dt.datetime.now(dt.UTC).isoformat()
self.kwargs.update({
'rts': restore_ts_string
@@ -3595,7 +3590,7 @@ def test_cosmosdb_gremlin_database_graph_restore(self, resource_group):
]).get_output_in_json()
#restore time
- restore_ts_string = datetime.now(UTC).isoformat()
+ restore_ts_string = dt.datetime.now(dt.UTC).isoformat()
self.kwargs.update({
'rts': restore_ts_string
})
@@ -3729,7 +3724,7 @@ def test_cosmosdb_table(self, resource_group):
assert self.cmd('az cosmosdb table exists -g {rg} -a {acc} -n {table_name}').get_output_in_json()
- restore_ts_string = datetime.now(UTC).isoformat()
+ restore_ts_string = dt.datetime.now(dt.UTC).isoformat()
self.kwargs.update({
'rts': restore_ts_string
diff --git a/src/azure-cli/azure/cli/command_modules/eventgrid/tests/latest/test_eventgrid_commands.py b/src/azure-cli/azure/cli/command_modules/eventgrid/tests/latest/test_eventgrid_commands.py
index ba2a2009000..07d77a692aa 100644
--- a/src/azure-cli/azure/cli/command_modules/eventgrid/tests/latest/test_eventgrid_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/eventgrid/tests/latest/test_eventgrid_commands.py
@@ -10,7 +10,7 @@
from azure.cli.testsdk import ScenarioTest, ResourceGroupPreparer, StorageAccountPreparer
from knack.util import CLIError
-from datetime import UTC, datetime, timedelta
+import datetime as dt
EVENTGRID_TRIGGER_ENDPOINT_URL = "https://devexpfuncappdestination.azurewebsites.net/runtime/webhooks/EventGrid?functionName=EventGridTrigger1&code="
EVENTGRID_TRIGGER_ENDPOINT_BASE_URL = "https://devexpfuncappdestination.azurewebsites.net/runtime/webhooks/EventGrid"
@@ -1480,9 +1480,9 @@ def test_Partner_scenarios(self, resource_group):
guid3 = uuid.uuid1()
destination_subscription_id = '5b4b650e-28b9-4790-b3ab-ddbd88d727c4'
source = self.create_random_name(prefix='cli', length=40)
- exp_time = datetime.now(UTC) + timedelta(hours=24)
+ exp_time = dt.datetime.now(dt.UTC) + dt.timedelta(hours=24)
exp_time = exp_time.isoformat()
- creation_time = datetime.now(UTC).isoformat()
+ creation_time = dt.datetime.now(dt.UTC).isoformat()
long_description = 'This is long description sample'
customer_service_number1 = '+1 800 123 4567'
@@ -1865,9 +1865,9 @@ def test_Partner_scenarios_v2(self, resource_group):
destination_endpoint_url = SECURED_WEBBOOK_DESTINATION_ENDPOINT_URL
source = self.create_random_name(prefix='cli', length=40)
- exp_time = datetime.now(UTC) + timedelta(hours=24)
+ exp_time = dt.datetime.now(dt.UTC) + dt.timedelta(hours=24)
exp_time = exp_time.isoformat()
- creation_time = datetime.now(UTC).isoformat()
+ creation_time = dt.datetime.now(dt.UTC).isoformat()
default_maximum_expiration_time_in_days = 5
updated_default_max_expiration_time_in_days = 15
diff --git a/src/azure-cli/azure/cli/command_modules/feedback/custom.py b/src/azure-cli/azure/cli/command_modules/feedback/custom.py
index 21fc5227bae..09496388db9 100644
--- a/src/azure-cli/azure/cli/command_modules/feedback/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/feedback/custom.py
@@ -3,7 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
-import datetime
+import datetime as dt
import math
import os
import platform
@@ -106,8 +106,8 @@ class CommandLogFile:
def __init__(self, log_file_path, time_now=None):
- if (time_now is not None) and (not isinstance(time_now, datetime.datetime)):
- raise TypeError("Expected type {} for time_now, instead received {}.".format(datetime.datetime, type(time_now))) # pylint: disable=line-too-long
+ if (time_now is not None) and (not isinstance(time_now, dt.datetime)):
+ raise TypeError("Expected type {} for time_now, instead received {}.".format(dt.datetime, type(time_now))) # pylint: disable=line-too-long
if not os.path.isfile(log_file_path):
raise ValueError("File {} is not an existing file.".format(log_file_path))
@@ -116,7 +116,7 @@ def __init__(self, log_file_path, time_now=None):
self._log_file_path = log_file_path
if time_now is None:
- self._time_now = datetime.datetime.now()
+ self._time_now = dt.datetime.now()
else:
self._time_now = time_now
@@ -179,7 +179,7 @@ def get_command_time_str(self):
total_seconds = self.metadata_tup.seconds_ago
- time_delta = datetime.timedelta(seconds=total_seconds)
+ time_delta = dt.timedelta(seconds=total_seconds)
logger.debug("%s time_delta", time_delta)
if time_delta.days > 0:
@@ -201,12 +201,12 @@ def _get_command_metadata_from_file(self):
if not self._log_file_path:
return None
- time_now = datetime.datetime.now() if not self._time_now else self._time_now
+ time_now = dt.datetime.now() if not self._time_now else self._time_now
try:
_, file_name = os.path.split(self._log_file_path)
poss_date, poss_time, poss_command, poss_pid, _ = file_name.split(".")
- date_time_stamp = datetime.datetime.strptime("{}-{}".format(poss_date, poss_time), "%Y-%m-%d-%H-%M-%S")
+ date_time_stamp = dt.datetime.strptime("{}-{}".format(poss_date, poss_time), "%Y-%m-%d-%H-%M-%S")
command = "az " + poss_command.replace("_", " ") if poss_command != _UNKNOWN_COMMAND else self.UNKNOWN_CMD # pylint: disable=line-too-long
except ValueError as e:
logger.debug("Could not load metadata from file name %s.", self._log_file_path)
@@ -490,7 +490,7 @@ def _pad_string(my_str, pad_len):
my_str += " "
return my_str
- time_now = datetime.datetime.now()
+ time_now = dt.datetime.now()
command_log_files = _get_command_log_files(cmd.cli_ctx, time_now)
@@ -605,8 +605,8 @@ def handle_survey(cmd):
with open(GLOBAL_SURVEY_NOTE_PATH, 'r') as f:
survey_note = json.load(f)
if survey_note['last_prompt_time']:
- last_prompt_time = datetime.datetime.strptime(survey_note['last_prompt_time'], '%Y-%m-%dT%H:%M:%S').replace(tzinfo=datetime.UTC)
- use_duration = datetime.datetime.now(datetime.UTC) - last_prompt_time
+ last_prompt_time = dt.datetime.strptime(survey_note['last_prompt_time'], '%Y-%m-%dT%H:%M:%S').replace(tzinfo=dt.UTC)
+ use_duration = dt.datetime.now(dt.UTC) - last_prompt_time
url = _SURVEY_URL.format(installation_id=Profile(cli_ctx=cmd.cli_ctx).get_installation_id(),
version=core_version,
diff --git a/src/azure-cli/azure/cli/command_modules/feedback/tests/latest/test_feedback.py b/src/azure-cli/azure/cli/command_modules/feedback/tests/latest/test_feedback.py
index 986c3e5a889..c4e7d66f365 100644
--- a/src/azure-cli/azure/cli/command_modules/feedback/tests/latest/test_feedback.py
+++ b/src/azure-cli/azure/cli/command_modules/feedback/tests/latest/test_feedback.py
@@ -3,7 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
-import datetime
+import datetime as dt
import logging
import os
import time
@@ -102,7 +102,7 @@ def _helper_test_get_repository_url_with_no_extension_match_raw(self):
self.assertEqual(_RAW_EXTENSIONS_ISSUES_URL, repo_url)
def _helper_test_log_metadata_correct(self):
- time_now = datetime.datetime.now()
+ time_now = dt.datetime.now()
command_log_files = _get_command_log_files(self.cli_ctx, time_now)
p_id = os.getpid()
self.assertEqual(len(command_log_files), 4)
@@ -123,7 +123,7 @@ def _helper_test_log_metadata_correct(self):
self.assertEqual("az alias list", command_log_files[3].metadata_tup.cmd)
def _helper_test_log_contents_correct(self):
- time_now = datetime.datetime.now()
+ time_now = dt.datetime.now()
command_log_files = _get_command_log_files(self.cli_ctx, time_now)
self.assertEqual(len(command_log_files), 4)
diff --git a/src/azure-cli/azure/cli/command_modules/iot/_utils.py b/src/azure-cli/azure/cli/command_modules/iot/_utils.py
index 9799c91f697..5b4ac2efd03 100644
--- a/src/azure-cli/azure/cli/command_modules/iot/_utils.py
+++ b/src/azure-cli/azure/cli/command_modules/iot/_utils.py
@@ -3,7 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
-import datetime
+import datetime as dt
from os.path import exists, join
import base64
from cryptography import x509
@@ -31,9 +31,9 @@ def create_self_signed_certificate(device_id, valid_days, cert_output_dir):
.issuer_name(subject_name)
.public_key(key.public_key())
.serial_number(x509.random_serial_number())
- .not_valid_before(datetime.datetime.now(datetime.UTC))
+ .not_valid_before(dt.datetime.now(dt.UTC))
.not_valid_after(
- datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=valid_days)
+ dt.datetime.now(dt.UTC) + dt.timedelta(days=valid_days)
)
.sign(key, hashes.SHA256())
)
diff --git a/src/azure-cli/azure/cli/command_modules/iot/tests/latest/_test_utils.py b/src/azure-cli/azure/cli/command_modules/iot/tests/latest/_test_utils.py
index 917401f1943..e6d065ef2f4 100644
--- a/src/azure-cli/azure/cli/command_modules/iot/tests/latest/_test_utils.py
+++ b/src/azure-cli/azure/cli/command_modules/iot/tests/latest/_test_utils.py
@@ -3,7 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
-import datetime
+import datetime as dt
from os.path import exists
import os
from cryptography import x509
@@ -29,9 +29,9 @@ def _create_test_cert(cert_file, key_file, subject, valid_days, serial_number):
.issuer_name(subject_name)
.public_key(key.public_key())
.serial_number(serial_number)
- .not_valid_before(datetime.datetime.now(datetime.UTC))
+ .not_valid_before(dt.datetime.now(dt.UTC))
.not_valid_after(
- datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=valid_days)
+ dt.datetime.now(dt.UTC) + dt.timedelta(days=valid_days)
)
.sign(key, hashes.SHA256())
)
@@ -92,9 +92,9 @@ def _create_verification_cert(cert_file, key_file, verification_file, nonce, val
.issuer_name(signing_cert.subject)
.public_key(key.public_key())
.serial_number(serial_number)
- .not_valid_before(datetime.datetime.now(datetime.UTC))
+ .not_valid_before(dt.datetime.now(dt.UTC))
.not_valid_after(
- datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=valid_days)
+ dt.datetime.now(dt.UTC) + dt.timedelta(days=valid_days)
)
.sign(k, hashes.SHA256())
)
diff --git a/src/azure-cli/azure/cli/command_modules/keyvault/tests/latest/test_keyvault_commands.py b/src/azure-cli/azure/cli/command_modules/keyvault/tests/latest/test_keyvault_commands.py
index 8406e98afd6..dcc9f56b8b9 100644
--- a/src/azure-cli/azure/cli/command_modules/keyvault/tests/latest/test_keyvault_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/keyvault/tests/latest/test_keyvault_commands.py
@@ -11,7 +11,7 @@
import time
from unittest import mock
import unittest
-from datetime import UTC, datetime, timedelta
+import datetime as dt
from dateutil import tz
from ipaddress import ip_network
@@ -97,13 +97,13 @@ def _clear_hsm(test, hsm_url):
class DateTimeParseTest(unittest.TestCase):
def test_parse_asn1_date(self):
- expected = datetime(year=2017,
- month=4,
- day=24,
- hour=16,
- minute=37,
- second=20,
- tzinfo=tz.tzutc())
+ expected = dt.datetime(year=2017,
+ month=4,
+ day=24,
+ hour=16,
+ minute=37,
+ second=20,
+ tzinfo=tz.tzutc())
self.assertEqual(_asn1_to_iso8601("20170424163720Z"), expected)
@@ -975,8 +975,8 @@ def test_keyvault_hsm_selective_key_restore(self):
'key_name': self.create_random_name('selective-restore-', 24),
'storage_account': self.create_random_name('clitesthsmsa', 24),
'blob': self.create_random_name('clitesthsmblob', 24),
- 'sas_start': (datetime.now(UTC) - timedelta(minutes=30)).strftime('%Y-%m-%dT%H:%M:%SZ'),
- 'sas_expiry': (datetime.now(UTC) + timedelta(minutes=30)).strftime('%Y-%m-%dT%H:%M:%SZ')
+ 'sas_start': (dt.datetime.now(dt.UTC) - dt.timedelta(minutes=30)).strftime('%Y-%m-%dT%H:%M:%SZ'),
+ 'sas_expiry': (dt.datetime.now(dt.UTC) + dt.timedelta(minutes=30)).strftime('%Y-%m-%dT%H:%M:%SZ')
})
_clear_hsm(self, hsm_url=self.kwargs['hsm_url'])
@@ -1031,8 +1031,8 @@ def test_keyvault_hsm_full_backup_restore(self, resource_group, managed_hsm, sto
'hsm_name': managed_hsm,
'storage_account': storage_account,
'blob': self.create_random_name('clitesthsmblob', 24),
- 'sas_start': (datetime.now(UTC) - timedelta(minutes=30)).strftime('%Y-%m-%dT%H:%M:%SZ'),
- 'sas_expiry': (datetime.now(UTC) + timedelta(minutes=30)).strftime('%Y-%m-%dT%H:%M:%SZ')
+ 'sas_start': (dt.datetime.now(dt.UTC) - dt.timedelta(minutes=30)).strftime('%Y-%m-%dT%H:%M:%SZ'),
+ 'sas_expiry': (dt.datetime.now(dt.UTC) + dt.timedelta(minutes=30)).strftime('%Y-%m-%dT%H:%M:%SZ')
})
self.cmd('az storage container create -n {blob} --account-name {storage_account} -g {rg}')
@@ -2662,8 +2662,8 @@ def _generate_certificate(path, keyfile=None, password=None):
.issuer_name(issuer) \
.public_key(key.public_key()) \
.serial_number(x509.random_serial_number()) \
- .not_valid_before(datetime.now(UTC)) \
- .not_valid_after(datetime.now(UTC) + timedelta(days=10)) \
+ .not_valid_before(dt.datetime.now(dt.UTC)) \
+ .not_valid_after(dt.datetime.now(dt.UTC) + dt.timedelta(days=10)) \
.sign(key, hashes.SHA256(), default_backend())
# Write the cert out to disk
diff --git a/src/azure-cli/azure/cli/command_modules/lab/validators.py b/src/azure-cli/azure/cli/command_modules/lab/validators.py
index 77ef72a7536..c376c7acb56 100644
--- a/src/azure-cli/azure/cli/command_modules/lab/validators.py
+++ b/src/azure-cli/azure/cli/command_modules/lab/validators.py
@@ -113,11 +113,11 @@ def _validate_expiration_date(args):
""" Validates expiration date if provided. """
if has_value(args.expiration_date):
- import datetime
+ import datetime as dt
import dateutil.parser
expiration_date = dateutil.parser.parse(args.expiration_date.to_serialized_data())
- expiration_date = expiration_date.replace(tzinfo=expiration_date.tzinfo or datetime.UTC)
- if datetime.datetime.now(datetime.UTC) >= expiration_date:
+ expiration_date = expiration_date.replace(tzinfo=expiration_date.tzinfo or dt.UTC)
+ if dt.datetime.now(dt.UTC) >= expiration_date:
raise ArgumentUsageError(
"Expiration date '{}' must be in future.".format(args.expiration_date.to_serialized_data()))
diff --git a/src/azure-cli/azure/cli/command_modules/monitor/_legacy/custom.py b/src/azure-cli/azure/cli/command_modules/monitor/_legacy/custom.py
index 8bbff592c6f..f49b5759c7d 100644
--- a/src/azure-cli/azure/cli/command_modules/monitor/_legacy/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/monitor/_legacy/custom.py
@@ -33,12 +33,12 @@ def list_activity_log(cmd, correlation_id=None, resource_group=None, resource_id
def _build_activity_log_odata_filter(correlation_id=None, resource_group=None, resource_id=None, resource_provider=None,
start_time=None, end_time=None, caller=None, status=None, offset=None):
- from datetime import UTC, datetime
+ import datetime as dt
import dateutil.parser
if not start_time and not end_time:
# if neither value provided, end_time is now
- end_time = datetime.now(UTC).isoformat()
+ end_time = dt.datetime.now(dt.UTC).isoformat()
if not start_time:
# if no start_time, apply offset backwards from end_time
start_time = (dateutil.parser.parse(end_time) - offset).isoformat()
@@ -108,13 +108,13 @@ def list_metrics(cmd, resource,
metadata=None, dimension=None, aggregation=None, metrics=None,
filters=None, metric_namespace=None, orderby=None, top=10):
- from datetime import UTC, datetime
+ import datetime as dt
import dateutil.parser
from urllib.parse import quote_plus
if not start_time and not end_time:
# if neither value provided, end_time is now
- end_time = datetime.now(UTC).isoformat()
+ end_time = dt.datetime.now(dt.UTC).isoformat()
if not start_time:
# if no start_time, apply offset backwards from end_time
start_time = (dateutil.parser.parse(end_time) - offset).isoformat()
diff --git a/src/azure-cli/azure/cli/command_modules/monitor/custom.py b/src/azure-cli/azure/cli/command_modules/monitor/custom.py
index 1d6bf1680e9..34ba567323f 100644
--- a/src/azure-cli/azure/cli/command_modules/monitor/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/monitor/custom.py
@@ -33,12 +33,12 @@ def list_activity_log(cmd, correlation_id=None, resource_group=None, resource_id
def _build_activity_log_odata_filter(correlation_id=None, resource_group=None, resource_id=None, resource_provider=None,
start_time=None, end_time=None, caller=None, status=None, offset=None):
- from datetime import UTC, datetime
+ import datetime as dt
import dateutil.parser
if not start_time and not end_time:
# if neither value provided, end_time is now
- end_time = datetime.now(UTC).isoformat()
+ end_time = dt.datetime.now(dt.UTC).isoformat()
if not start_time:
# if no start_time, apply offset backwards from end_time
start_time = (dateutil.parser.parse(end_time) - offset).isoformat()
@@ -108,13 +108,13 @@ def list_metrics(cmd, resource,
metadata=None, dimension=None, aggregation=None, metrics=None,
filters=None, metric_namespace=None, orderby=None, top=10):
- from datetime import UTC, datetime
+ import datetime as dt
import dateutil.parser
from urllib.parse import quote_plus
if not start_time and not end_time:
# if neither value provided, end_time is now
- end_time = datetime.now(UTC).isoformat()
+ end_time = dt.datetime.now(dt.UTC).isoformat()
if not start_time:
# if no start_time, apply offset backwards from end_time
start_time = (dateutil.parser.parse(end_time) - offset).isoformat()
diff --git a/src/azure-cli/azure/cli/command_modules/mysql/_util.py b/src/azure-cli/azure/cli/command_modules/mysql/_util.py
index 064ef9df6a5..a1c3cd2a20e 100644
--- a/src/azure-cli/azure/cli/command_modules/mysql/_util.py
+++ b/src/azure-cli/azure/cli/command_modules/mysql/_util.py
@@ -15,7 +15,7 @@
import sys
import yaml
from time import sleep
-from datetime import UTC, datetime
+import datetime as dt
from knack.log import get_logger
from knack.arguments import ignore_type
from knack.prompting import prompt_pass, prompt_y_n, NoTTYException
@@ -325,7 +325,7 @@ def _map_maintenance_window(day_of_week):
def get_current_time():
- return datetime.now(UTC).replace(microsecond=0).isoformat()
+ return dt.datetime.now(dt.UTC).replace(microsecond=0).isoformat()
def get_id_components(rid):
@@ -615,7 +615,7 @@ def get_firewall_rules_from_paged_response(firewall_rules):
def get_current_utc_time():
- return datetime.now(UTC)
+ return dt.datetime.now(dt.UTC)
class ImportFromStorageState(Enum):
@@ -648,7 +648,7 @@ def get_progress_message(self):
return msg
def _get_eta_time_duration_in_user_readable_string(self):
- time_remaining = datetime.fromisoformat(self._import_estimated_completion_time) - get_current_utc_time()
+ time_remaining = dt.datetime.fromisoformat(self._import_estimated_completion_time) - get_current_utc_time()
msg = " ETA : "
if time_remaining.total_seconds() < 60:
return msg + "Few seconds remaining"
diff --git a/src/azure-cli/azure/cli/command_modules/mysql/custom.py b/src/azure-cli/azure/cli/command_modules/mysql/custom.py
index 7ac6286c76c..60c9c38dc4c 100644
--- a/src/azure-cli/azure/cli/command_modules/mysql/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/mysql/custom.py
@@ -8,7 +8,7 @@
import re
import math
-from datetime import UTC, datetime, timedelta
+import datetime as dt
from knack.log import get_logger
from urllib.request import urlretrieve
from importlib import import_module
@@ -106,7 +106,7 @@ def firewall_rule_create_func(cmd, client, resource_group_name, server_name, fir
start_ip_address = end_ip_address
if firewall_rule_name is None:
- now = datetime.now()
+ now = dt.datetime.now()
firewall_rule_name = 'FirewallIPAddress_{}-{}-{}_{}-{}-{}'.format(now.year, now.month, now.day, now.hour, now.minute,
now.second)
if start_ip_address == '0.0.0.0' and end_ip_address == '0.0.0.0':
@@ -272,7 +272,7 @@ def flexible_server_log_list(client, resource_group_name, server_name, filename_
if file_last_written is None:
file_last_written = 72
- time_line = datetime.now(UTC) - timedelta(hours=file_last_written)
+ time_line = dt.datetime.now(dt.UTC) - dt.timedelta(hours=file_last_written)
for f in all_files:
if f.last_modified_time < time_line:
diff --git a/src/azure-cli/azure/cli/command_modules/mysql/tests/latest/test_mysql_scenario.py b/src/azure-cli/azure/cli/command_modules/mysql/tests/latest/test_mysql_scenario.py
index 369936f086d..414852a62a3 100644
--- a/src/azure-cli/azure/cli/command_modules/mysql/tests/latest/test_mysql_scenario.py
+++ b/src/azure-cli/azure/cli/command_modules/mysql/tests/latest/test_mysql_scenario.py
@@ -7,7 +7,7 @@
import uuid
import unittest
-from datetime import UTC, datetime, timedelta
+import datetime as dt
from time import sleep
from dateutil import parser
from azure.cli.testsdk.scenario_tests import AllowLargeResponse
@@ -457,7 +457,7 @@ def _test_flexible_server_restore_mgmt(self, database_engine, resource_group):
result = self.cmd('{} flexible-server show -g {} -n {}'.format(database_engine, resource_group, source_server)).get_output_in_json()
# Wait until snapshot is created
- current_time = datetime.now(UTC).isoformat()
+ current_time = dt.datetime.now(dt.UTC).isoformat()
earliest_restore_time = result['backup']['earliestRestoreDate']
seconds_to_wait = (parser.isoparse(earliest_restore_time) - parser.isoparse(current_time)).total_seconds()
os.environ.get(ENV_LIVE_TEST, False) and sleep(max(0, seconds_to_wait) + 180)
@@ -689,7 +689,7 @@ def _test_flexible_server_georestore_update_mgmt(self, database_engine, resource
.format(database_engine, resource_group, source_server),
checks=[JMESPathCheck('backup.geoRedundantBackup', 'Enabled')]).get_output_in_json()
- current_time = datetime.now(UTC).isoformat()
+ current_time = dt.datetime.now(dt.UTC).isoformat()
earliest_restore_time = result['backup']['earliestRestoreDate']
seconds_to_wait = (parser.isoparse(earliest_restore_time) - parser.isoparse(current_time)).total_seconds()
os.environ.get(ENV_LIVE_TEST, False) and sleep(max(0, seconds_to_wait) + 1200)
@@ -935,7 +935,7 @@ def main_tests(geo_redundant_backup):
expect_failure=True)
# restore backup
- current_time = datetime.now(UTC).isoformat()
+ current_time = dt.datetime.now(dt.UTC).isoformat()
earliest_restore_time = result['backup']['earliestRestoreDate']
seconds_to_wait = (parser.isoparse(earliest_restore_time) - parser.isoparse(current_time)).total_seconds()
sleep(max(0, seconds_to_wait))
@@ -1518,7 +1518,7 @@ def _test_mysql_flexible_server_public_access_georestore(self, database_engine,
restore_server = self.cmd('resource show --id {} --api-version {}'.format(result['id'], api_version)).get_output_in_json()
- current_time = datetime.now(UTC).isoformat()
+ current_time = dt.datetime.now(dt.UTC).isoformat()
earliest_restore_time = restore_server['properties']['backup']['earliestRestoreDate']
seconds_to_wait = (parser.isoparse(earliest_restore_time) - parser.isoparse(current_time)).total_seconds()
time.sleep(max(0, seconds_to_wait) + 180)
@@ -1541,7 +1541,7 @@ def _test_mysql_flexible_server_public_access_restore(self, database_engine, res
restore_server = self.cmd('resource show --id {} --api-version {}'.format(result['id'], api_version)).get_output_in_json()
- current_time = datetime.now(UTC).isoformat()
+ current_time = dt.datetime.now(dt.UTC).isoformat()
earliest_restore_time = restore_server['properties']['backup']['earliestRestoreDate']
seconds_to_wait = (parser.isoparse(earliest_restore_time) - parser.isoparse(current_time)).total_seconds()
print(current_time)
@@ -2407,7 +2407,7 @@ def _test_flexible_server_export_create_mgmt(self, database_engine, resource_gro
# Create the blob container
container = self.create_container(target_account_info)
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
self.kwargs.update({
'expiry': expiry,
diff --git a/src/azure-cli/azure/cli/command_modules/netappfiles/tests/latest/test_bucket_commands.py b/src/azure-cli/azure/cli/command_modules/netappfiles/tests/latest/test_bucket_commands.py
index c9816fa2737..0bfeb791352 100644
--- a/src/azure-cli/azure/cli/command_modules/netappfiles/tests/latest/test_bucket_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/netappfiles/tests/latest/test_bucket_commands.py
@@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------
import base64
-import datetime
+import datetime as dt
import time
import unittest
@@ -39,8 +39,8 @@ def _generate_self_signed_cert(fqdn):
.issuer_name(issuer)
.public_key(key.public_key())
.serial_number(x509.random_serial_number())
- .not_valid_before(datetime.datetime.now(datetime.UTC))
- .not_valid_after(datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=365))
+ .not_valid_before(dt.datetime.now(dt.UTC))
+ .not_valid_after(dt.datetime.now(dt.UTC) + dt.timedelta(days=365))
.sign(key, hashes.SHA256())
)
pem_data = cert.public_bytes(serialization.Encoding.PEM) + key.private_bytes(
diff --git a/src/azure-cli/azure/cli/command_modules/network/tests/latest/test_network_commands.py b/src/azure-cli/azure/cli/command_modules/network/tests/latest/test_network_commands.py
index fdd94694d76..b98c81c9184 100644
--- a/src/azure-cli/azure/cli/command_modules/network/tests/latest/test_network_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/network/tests/latest/test_network_commands.py
@@ -6595,8 +6595,8 @@ class VpnConnectionAuthenticationScenarioTest(ScenarioTest):
@staticmethod
def _get_now_utc():
- import datetime
- return datetime.datetime.now(datetime.UTC)
+ import datetime as dt
+ return dt.datetime.now(dt.UTC)
@staticmethod
def _format_subject_dn(common_name: str):
@@ -6615,7 +6615,7 @@ def generate_ca_chain(root_cert_path, intermediate_cert_path):
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend
- import datetime
+ import datetime as dt
now = VpnConnectionAuthenticationScenarioTest._get_now_utc()
@@ -6647,9 +6647,9 @@ def generate_ca_chain(root_cert_path, intermediate_cert_path):
).serial_number(
x509.random_serial_number()
).not_valid_before(
- now - datetime.timedelta(minutes=5)
+ now - dt.timedelta(minutes=5)
).not_valid_after(
- now + datetime.timedelta(days=3650)
+ now + dt.timedelta(days=3650)
).add_extension(
x509.BasicConstraints(ca=True, path_length=1),
critical=True,
@@ -6702,9 +6702,9 @@ def generate_ca_chain(root_cert_path, intermediate_cert_path):
).serial_number(
x509.random_serial_number()
).not_valid_before(
- now - datetime.timedelta(minutes=5)
+ now - dt.timedelta(minutes=5)
).not_valid_after(
- now + datetime.timedelta(days=1825)
+ now + dt.timedelta(days=1825)
).add_extension(
x509.BasicConstraints(ca=True, path_length=0),
critical=True,
@@ -6750,7 +6750,7 @@ def generate_leaf_certificate(common_name, signer_key, signer_cert, is_ca=False,
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend
- import datetime
+ import datetime as dt
now = VpnConnectionAuthenticationScenarioTest._get_now_utc()
@@ -6782,9 +6782,9 @@ def generate_leaf_certificate(common_name, signer_key, signer_cert, is_ca=False,
).serial_number(
x509.random_serial_number()
).not_valid_before(
- now - datetime.timedelta(minutes=5)
+ now - dt.timedelta(minutes=5)
).not_valid_after(
- now + datetime.timedelta(days=days)
+ now + dt.timedelta(days=days)
)
# Leaf cert constraints
@@ -7711,7 +7711,7 @@ def __init__(self, method_name):
@ResourceGroupPreparer(name_prefix='cli_test_active_active_vnet_vnet_connection')
@StorageAccountPreparer(name_prefix='clitestvpncnn')
def test_network_active_active_vnet_connection(self, resource_group, storage_account):
- from datetime import UTC, datetime, timedelta
+ import datetime as dt
self.kwargs.update({
'subnet': 'GatewaySubnet',
'vnet1': 'vnet1',
@@ -7735,7 +7735,7 @@ def test_network_active_active_vnet_connection(self, resource_group, storage_acc
'bgp_peer2': '10.53.255.253',
'storage_account': storage_account,
'ctn': self.create_random_name(prefix='clitestvpngw', length=24),
- 'expiry': (datetime.now(UTC) + timedelta(hours=3)).strftime('%Y-%m-%dT%H:%MZ')
+ 'expiry': (dt.datetime.now(dt.UTC) + dt.timedelta(hours=3)).strftime('%Y-%m-%dT%H:%MZ')
})
self.cmd('storage container create --account-name {storage_account} --name {ctn}')
@@ -7989,7 +7989,7 @@ def test_network_vpn_gateway_disconnect_connects(self, resource_group):
@ResourceGroupPreparer(name_prefix='cli_test_vpn_gateway_package_capture', location='westus')
@StorageAccountPreparer(name_prefix='clitestvpngw')
def test_network_vpn_gateway_package_capture(self, resource_group, storage_account):
- from datetime import UTC, datetime, timedelta
+ import datetime as dt
self.kwargs.update({
'vnet1': 'myvnet1',
'gw1': 'gateway1',
@@ -7997,7 +7997,7 @@ def test_network_vpn_gateway_package_capture(self, resource_group, storage_accou
'ip1': 'pubip1',
'storage_account': storage_account,
'ctn': self.create_random_name(prefix='clitestvpngw', length=24),
- 'expiry': (datetime.now(UTC) + timedelta(hours=3)).strftime('%Y-%m-%dT%H:%MZ')
+ 'expiry': (dt.datetime.now(dt.UTC) + dt.timedelta(hours=3)).strftime('%Y-%m-%dT%H:%MZ')
})
self.cmd('storage container create --account-name {storage_account} --name {ctn}')
@@ -8031,9 +8031,9 @@ def _generate_p2s_root_cert_public_file(cert_path, common_name="VpnGatewayAuthCe
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend
- import datetime
+ import datetime as dt
- now = datetime.datetime.now(datetime.UTC)
+ now = dt.datetime.now(dt.UTC)
# Root key (private key not exported; we only write public cert)
root_key = rsa.generate_private_key(
@@ -8060,9 +8060,9 @@ def _generate_p2s_root_cert_public_file(cert_path, common_name="VpnGatewayAuthCe
).serial_number(
x509.random_serial_number()
).not_valid_before(
- now - datetime.timedelta(minutes=5)
+ now - dt.timedelta(minutes=5)
).not_valid_after(
- now + datetime.timedelta(days=3650)
+ now + dt.timedelta(days=3650)
).add_extension(
x509.BasicConstraints(ca=True, path_length=1),
critical=True,
diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/backup_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/backup_commands.py
index 4aef2082653..d546d43095a 100644
--- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/backup_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/backup_commands.py
@@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------
# pylint: disable=unused-argument, line-too-long
-from datetime import UTC, datetime
+import datetime as dt
from azure.cli.core.util import user_confirmation
from knack.log import get_logger
from ..utils.validators import validate_resource_group, validate_backup_name
@@ -20,7 +20,7 @@ def _generate_backup_name(client, resource_group_name, server_name):
on_demand_count = sum(1 for name in existing_names if name.startswith(_BACKUP_NAME_PREFIX))
- date_str = datetime.now(UTC).strftime("%m%d%Y")
+ date_str = dt.datetime.now(dt.UTC).strftime("%m%d%Y")
suffix = on_demand_count + 1
backup_name = f"{_BACKUP_NAME_PREFIX}-{date_str}-{suffix}"
while backup_name in existing_names:
diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/commands/server_logs_commands.py b/src/azure-cli/azure/cli/command_modules/postgresql/commands/server_logs_commands.py
index d90b96817a5..c0a1150494e 100644
--- a/src/azure-cli/azure/cli/command_modules/postgresql/commands/server_logs_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/postgresql/commands/server_logs_commands.py
@@ -7,7 +7,7 @@
import re
from azure.cli.core.util import CLIError, user_confirmation
-from datetime import UTC, datetime, timedelta
+import datetime as dt
from knack.log import get_logger
from urllib.request import urlretrieve
from .._client_factory import cf_postgres_flexible_replica
@@ -61,7 +61,7 @@ def flexible_server_list_log_files_with_filter(client, resource_group_name, serv
if file_last_written is None:
file_last_written = 72
- time_line = datetime.now(UTC) - timedelta(hours=file_last_written)
+ time_line = dt.datetime.now(dt.UTC) - dt.timedelta(hours=file_last_written)
for f in all_files:
if f.last_modified_time < time_line:
@@ -85,7 +85,7 @@ def flexible_server_log_list(client, resource_group_name, server_name, filename_
if file_last_written is None:
file_last_written = 72
- time_line = datetime.now(UTC) - timedelta(hours=file_last_written)
+ time_line = dt.datetime.now(dt.UTC) - dt.timedelta(hours=file_last_written)
for f in all_files:
if f.last_modified_time < time_line:
diff --git a/src/azure-cli/azure/cli/command_modules/postgresql/utils/_flexible_server_util.py b/src/azure-cli/azure/cli/command_modules/postgresql/utils/_flexible_server_util.py
index 198d655fbb3..b689d848c9b 100644
--- a/src/azure-cli/azure/cli/command_modules/postgresql/utils/_flexible_server_util.py
+++ b/src/azure-cli/azure/cli/command_modules/postgresql/utils/_flexible_server_util.py
@@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------
# pylint: disable=unused-argument, line-too-long, import-outside-toplevel, raise-missing-from
-from datetime import UTC, datetime
+import datetime as dt
import os
import random
import subprocess
@@ -200,7 +200,7 @@ def _map_maintenance_window(day_of_week):
def get_current_time():
- return datetime.now(UTC).replace(microsecond=0).isoformat()
+ return dt.datetime.now(dt.UTC).replace(microsecond=0).isoformat()
def get_id_components(rid):
diff --git a/src/azure-cli/azure/cli/command_modules/rdbms/_flexible_server_util.py b/src/azure-cli/azure/cli/command_modules/rdbms/_flexible_server_util.py
index 6bc966762b5..737ae9e67d0 100644
--- a/src/azure-cli/azure/cli/command_modules/rdbms/_flexible_server_util.py
+++ b/src/azure-cli/azure/cli/command_modules/rdbms/_flexible_server_util.py
@@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------
# pylint: disable=unused-argument, line-too-long, import-outside-toplevel, raise-missing-from
-from datetime import UTC, datetime
+import datetime as dt
import os
import random
import subprocess
@@ -245,7 +245,7 @@ def _map_maintenance_window(day_of_week):
def get_current_time():
- return datetime.now(UTC).replace(microsecond=0).isoformat()
+ return dt.datetime.now(dt.UTC).replace(microsecond=0).isoformat()
def get_id_components(rid):
diff --git a/src/azure-cli/azure/cli/command_modules/rdbms/custom.py b/src/azure-cli/azure/cli/command_modules/rdbms/custom.py
index 3c787b8b91b..1b1e660e435 100644
--- a/src/azure-cli/azure/cli/command_modules/rdbms/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/rdbms/custom.py
@@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------
# pylint: disable=unused-argument, line-too-long
-from datetime import UTC, datetime, timedelta
+import datetime as dt
from importlib import import_module
import re
from knack.log import get_logger
@@ -602,7 +602,7 @@ def _list_log_files_with_filter(client, resource_group_name, server_name, filena
if file_last_written is None:
file_last_written = 72
- time_line = datetime.now(UTC) - timedelta(hours=file_last_written)
+ time_line = dt.datetime.now(dt.UTC) - dt.timedelta(hours=file_last_written)
for f in all_files:
if f.last_modified_time < time_line:
diff --git a/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_custom_common.py b/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_custom_common.py
index 6aa639b21f4..519146b4e70 100644
--- a/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_custom_common.py
+++ b/src/azure-cli/azure/cli/command_modules/rdbms/flexible_server_custom_common.py
@@ -6,7 +6,7 @@
# pylint: disable=unused-argument, line-too-long
import re
-from datetime import UTC, datetime, timedelta
+import datetime as dt
from knack.log import get_logger
from knack.util import CLIError
from urllib.request import urlretrieve
@@ -87,7 +87,7 @@ def firewall_rule_create_func(cmd, client, resource_group_name, server_name, fir
raise CLIError("Incorrect Usage : Need to pass in value for either \'--start-ip-address\' or \'--end-ip-address\'.")
if firewall_rule_name is None:
- now = datetime.now()
+ now = dt.datetime.now()
firewall_rule_name = 'FirewallIPAddress_{}-{}-{}_{}-{}-{}'.format(now.year, now.month, now.day, now.hour, now.minute,
now.second)
if start_ip_address == '0.0.0.0' and end_ip_address == '0.0.0.0':
@@ -227,7 +227,7 @@ def flexible_server_log_list(client, resource_group_name, server_name, filename_
if file_last_written is None:
file_last_written = 72
- time_line = datetime.now(UTC) - timedelta(hours=file_last_written)
+ time_line = dt.datetime.now(dt.UTC) - dt.timedelta(hours=file_last_written)
for f in all_files:
if f.last_modified_time < time_line:
diff --git a/src/azure-cli/azure/cli/command_modules/rdbms/tests/latest/test_rdbms_commands.py b/src/azure-cli/azure/cli/command_modules/rdbms/tests/latest/test_rdbms_commands.py
index a9883870a8d..91839ab2841 100644
--- a/src/azure-cli/azure/cli/command_modules/rdbms/tests/latest/test_rdbms_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/rdbms/tests/latest/test_rdbms_commands.py
@@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------
import time
-from datetime import UTC, datetime
+import datetime as dt
from azure.cli.testsdk.scenario_tests import AllowLargeResponse
from azure.core.exceptions import HttpResponseError
from azure.cli.core.util import CLIError
@@ -222,12 +222,12 @@ def _test_server_mgmt(self, database_engine, resource_group_1, resource_group_2)
JMESPathCheck('administratorLogin', admin_login)])
# Before we do restore we will have to check whether the current time is less than earliest restore time
- current_time = datetime.now(UTC).isoformat()
+ current_time = dt.datetime.now(dt.UTC).isoformat()
earliest_restore_time = result['earliestRestoreDate']
date_format = '%Y-%m-%dT%H:%M:%S.%f+00:00'
if current_time < earliest_restore_time:
- time.sleep((datetime.strptime(earliest_restore_time, date_format) - datetime.strptime(current_time,
+ time.sleep((dt.datetime.strptime(earliest_restore_time, date_format) - dt.datetime.strptime(current_time,
date_format)).total_seconds())
self.cmd('{} server restore -g {} --name {} '
diff --git a/src/azure-cli/azure/cli/command_modules/redis/tests/latest/test_redis_scenario.py b/src/azure-cli/azure/cli/command_modules/redis/tests/latest/test_redis_scenario.py
index 9e174d43195..48ee98a823f 100644
--- a/src/azure-cli/azure/cli/command_modules/redis/tests/latest/test_redis_scenario.py
+++ b/src/azure-cli/azure/cli/command_modules/redis/tests/latest/test_redis_scenario.py
@@ -6,7 +6,7 @@
import os
from azure.cli.testsdk import ScenarioTest, ResourceGroupPreparer
import time
-import datetime
+import datetime as dt
location = 'WestEurope'
seclocation = 'EastUS'
@@ -309,8 +309,8 @@ def test_redis_cache_export_import(self, resource_group):
'containerName': "testcontainer",
'userIdentity': user_identity,
'storageSubscriptionId': "6364f508-1150-4431-b973-c3f133466e56", # replace it with your subscription id while running tests in live mode
- 'startTime': (datetime.datetime.now(datetime.UTC) - datetime.timedelta(minutes=60)).strftime("%Y-%m-%dT%H:%MZ"),
- 'expiryTime': (datetime.datetime.now(datetime.UTC) + datetime.timedelta(minutes=200)).strftime("%Y-%m-%dT%H:%MZ")
+ 'startTime': (dt.datetime.now(dt.UTC) - dt.timedelta(minutes=60)).strftime("%Y-%m-%dT%H:%MZ"),
+ 'expiryTime': (dt.datetime.now(dt.UTC) + dt.timedelta(minutes=200)).strftime("%Y-%m-%dT%H:%MZ")
}
if self.is_live :
diff --git a/src/azure-cli/azure/cli/command_modules/resource/tests/latest/test_resource.py b/src/azure-cli/azure/cli/command_modules/resource/tests/latest/test_resource.py
index 2c947da715b..cac8ade0838 100644
--- a/src/azure-cli/azure/cli/command_modules/resource/tests/latest/test_resource.py
+++ b/src/azure-cli/azure/cli/command_modules/resource/tests/latest/test_resource.py
@@ -1331,8 +1331,8 @@ def test_resource_group_level_deployment_with_query_string(self, resource_group,
self.cmd('storage blob upload -c {container_name} -f "{tf}" -n mainTemplate --account-name {storage_account} --account-key {storage_key}')
self.cmd('storage blob upload -c {container_name} -f "{linked_tf}" -n storage_account_linked_template.json --account-name {storage_account} --account-key {storage_key}')
- from datetime import UTC, datetime, timedelta
- self.kwargs['expiry'] = (datetime.now(UTC) + timedelta(hours=12)).strftime('%Y-%m-%dT%H:%MZ')
+ import datetime as dt
+ self.kwargs['expiry'] = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=12)).strftime('%Y-%m-%dT%H:%MZ')
self.kwargs['sas_token'] = self.cmd(
'storage container generate-sas --account-name {storage_account} --account-key {storage_key} --name {container_name} --permissions rw --expiry {expiry} -otsv').output.strip()
@@ -1379,8 +1379,8 @@ def test_subscription_level_deployment_with_query_string(self, resource_group, r
self.cmd('storage blob upload -c {container_name} -f "{linked_tf1}" -n createKeyVault.json --account-name {storage_account} --account-key {storage_key}')
self.cmd('storage blob upload -c {container_name} -f "{linked_tf2}" -n createKeyVaultWithSecret.json --account-name {storage_account} --account-key {storage_key}')
- from datetime import UTC, datetime, timedelta
- self.kwargs['expiry'] = (datetime.now(UTC) + timedelta(hours=12)).strftime('%Y-%m-%dT%H:%MZ')
+ import datetime as dt
+ self.kwargs['expiry'] = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=12)).strftime('%Y-%m-%dT%H:%MZ')
self.kwargs['sas_token'] = self.cmd(
'storage container generate-sas --account-name {storage_account} --name {container_name} --permissions dlrw --expiry {expiry} --https-only -otsv').output.strip()
diff --git a/src/azure-cli/azure/cli/command_modules/role/custom.py b/src/azure-cli/azure/cli/command_modules/role/custom.py
index 687bdd7c80d..fb92d0cc7f8 100644
--- a/src/azure-cli/azure/cli/command_modules/role/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/role/custom.py
@@ -12,7 +12,7 @@
"""
import base64
-import datetime
+import datetime as dt
import itertools
import json
import os
@@ -52,7 +52,7 @@ def _coerce(value):
return value.value
if isinstance(value, list):
return [_coerce(v) for v in value]
- if isinstance(value, datetime.datetime):
+ if isinstance(value, dt.datetime):
return value.isoformat()
return value
@@ -489,21 +489,21 @@ def _get_assignment_events(cli_ctx, start_time=None, end_time=None):
DATE_TIME_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
if end_time:
try:
- end_time = datetime.datetime.strptime(end_time, DATE_TIME_FORMAT).replace(tzinfo=datetime.UTC)
+ end_time = dt.datetime.strptime(end_time, DATE_TIME_FORMAT).replace(tzinfo=dt.UTC)
except ValueError:
raise CLIError("Input '{}' is not valid datetime. Valid example: 2000-12-31T12:59:59Z".format(end_time))
else:
- end_time = datetime.datetime.now(datetime.UTC)
+ end_time = dt.datetime.now(dt.UTC)
if start_time:
try:
- start_time = datetime.datetime.strptime(start_time, DATE_TIME_FORMAT).replace(tzinfo=datetime.UTC)
+ start_time = dt.datetime.strptime(start_time, DATE_TIME_FORMAT).replace(tzinfo=dt.UTC)
if start_time >= end_time:
raise CLIError("Start time cannot be later than end time.")
except ValueError:
raise CLIError("Input '{}' is not valid datetime. Valid example: 2000-12-31T12:59:59Z".format(start_time))
else:
- start_time = end_time - datetime.timedelta(hours=1)
+ start_time = end_time - dt.timedelta(hours=1)
time_filter = 'eventTimestamp ge {} and eventTimestamp le {}'.format(_datetime_to_utc(start_time),
_datetime_to_utc(end_time))
@@ -1493,14 +1493,14 @@ def create_service_principal_for_rbac(
if not display_name:
# No display name is provided, create a new one
- app_display_name = 'azure-cli-' + datetime.datetime.now(datetime.UTC).strftime('%Y-%m-%d-%H-%M-%S')
+ app_display_name = 'azure-cli-' + dt.datetime.now(dt.UTC).strftime('%Y-%m-%d-%H-%M-%S')
else:
app_display_name = display_name
# patch existing app with the same displayName to make the command idempotent
query_exp = "displayName eq '{}'".format(display_name)
existing_sps = list(graph_client.service_principal_list(filter=query_exp))
- app_start_date = datetime.datetime.now(datetime.timezone.utc)
+ app_start_date = dt.datetime.now(dt.timezone.utc)
app_end_date = app_start_date + relativedelta(years=years or 1)
use_cert = False
@@ -1680,12 +1680,12 @@ def _validate_app_dates(app_start_date, app_end_date, cert_start_date, cert_end_
if cert_start_date > app_start_date:
logger.warning('Certificate is not valid until %s. Adjusting key credential start date to match.',
cert_start_date)
- app_start_date = cert_start_date + datetime.timedelta(seconds=1)
+ app_start_date = cert_start_date + dt.timedelta(seconds=1)
if cert_end_date < app_end_date:
logger.warning('Certificate expires %s. Adjusting key credential end date to match.',
cert_end_date)
- app_end_date = cert_end_date - datetime.timedelta(seconds=1)
+ app_end_date = cert_end_date - dt.timedelta(seconds=1)
return app_start_date, app_end_date, cert_start_date, cert_end_date
@@ -1700,7 +1700,6 @@ def _create_self_signed_cert(start_date, end_date): # pylint: disable=too-many-
from os import path
import tempfile
from OpenSSL import crypto
- from datetime import timedelta
# Create a PEM file ~/tmpxxxxxxxx.pem with both PRIVATE KEY & CERTIFICATE so users can use to log in.
# The PEM file looks like
@@ -1729,8 +1728,8 @@ def _create_self_signed_cert(start_date, end_date): # pylint: disable=too-many-
subject.CN = 'CLI-Login'
cert.set_serial_number(1000)
asn1_format = '%Y%m%d%H%M%SZ'
- cert_start_date = start_date - timedelta(seconds=1)
- cert_end_date = end_date + timedelta(seconds=1)
+ cert_start_date = start_date - dt.timedelta(seconds=1)
+ cert_end_date = end_date + dt.timedelta(seconds=1)
cert.set_notBefore(cert_start_date.strftime(asn1_format).encode('utf-8'))
cert.set_notAfter(cert_end_date.strftime(asn1_format).encode('utf-8'))
cert.set_issuer(cert.get_subject())
@@ -1928,8 +1927,8 @@ def _set_application_properties(body, **kwargs):
set_object_properties('application', body, **kwargs)
-def _datetime_to_utc(dt):
- return dt.strftime('%Y-%m-%dT%H:%M:%SZ')
+def _datetime_to_utc(value):
+ return value.strftime('%Y-%m-%dT%H:%M:%SZ')
def _build_required_resource_accesses(required_resource_accesses):
@@ -1980,7 +1979,7 @@ def _build_key_credentials(key_value=None, key_type=None, key_usage=None,
return []
if not start_date:
- start_date = datetime.datetime.now(datetime.UTC)
+ start_date = dt.datetime.now(dt.UTC)
elif isinstance(start_date, str):
start_date = dateutil.parser.parse(start_date)
@@ -2026,7 +2025,7 @@ def _reset_credential(cmd, graph_object, add_password_func, remove_password_func
# For keyCredential, customKeyIdentifier is automatically computed by Graph service as certificate thumbprint.
# https://github.com/Azure/azure-cli/issues/20561
- app_start_date = datetime.datetime.now(datetime.timezone.utc)
+ app_start_date = dt.datetime.now(dt.timezone.utc)
if years is not None and end_date is not None:
raise CLIError('usage error: --years | --end-date')
if end_date is None:
@@ -2035,7 +2034,7 @@ def _reset_credential(cmd, graph_object, add_password_func, remove_password_func
else:
app_end_date = dateutil.parser.parse(end_date)
if app_end_date.tzinfo is None:
- app_end_date = app_end_date.replace(tzinfo=datetime.timezone.utc)
+ app_end_date = app_end_date.replace(tzinfo=dt.timezone.utc)
years = (app_end_date - app_start_date).days / 365
# Created password
diff --git a/src/azure-cli/azure/cli/command_modules/role/tests/latest/test_role.py b/src/azure-cli/azure/cli/command_modules/role/tests/latest/test_role.py
index 79f576dbf43..075db671c57 100644
--- a/src/azure-cli/azure/cli/command_modules/role/tests/latest/test_role.py
+++ b/src/azure-cli/azure/cli/command_modules/role/tests/latest/test_role.py
@@ -9,7 +9,7 @@
import sys
import tempfile
import time
-import datetime
+import datetime as dt
from unittest import mock
import unittest
@@ -698,9 +698,9 @@ def test_role_assignment_audits(self, resource_group):
self.cmd('role assignment create --assignee {upn} --role reader --scope {rg_id}')
if self.is_live or self.in_recording:
- now = datetime.datetime.now(datetime.UTC)
- start = now - datetime.timedelta(minutes=1)
- end = now + datetime.timedelta(minutes=1)
+ now = dt.datetime.now(dt.UTC)
+ start = now - dt.timedelta(minutes=1)
+ end = now + dt.timedelta(minutes=1)
start_time = '{}-{}-{}T{}:{}:{}Z'.format(start.year, start.month, start.day, start.hour,
start.minute, start.second)
end_time = '{}-{}-{}T{}:{}:{}Z'.format(end.year, end.month, end.day, end.hour,
diff --git a/src/azure-cli/azure/cli/command_modules/sql/tests/latest/test_sql_commands.py b/src/azure-cli/azure/cli/command_modules/sql/tests/latest/test_sql_commands.py
index 8ea906b9467..40a7cb4137e 100644
--- a/src/azure-cli/azure/cli/command_modules/sql/tests/latest/test_sql_commands.py
+++ b/src/azure-cli/azure/cli/command_modules/sql/tests/latest/test_sql_commands.py
@@ -33,7 +33,7 @@
ClientType,
ComputeModelType,
ResourceIdType)
-from datetime import UTC, datetime, timedelta
+import datetime as dt
# Constants
@@ -2018,15 +2018,15 @@ def test_sql_db_copy_with_perdb_cmk(self, resource_group_1, resource_group_2,
def _get_earliest_restore_date(db):
- return datetime.strptime(db['earliestRestoreDate'], "%Y-%m-%dT%H:%M:%S+00:00")
+ return dt.datetime.strptime(db['earliestRestoreDate'], "%Y-%m-%dT%H:%M:%S+00:00")
def _get_earliest_restore_date_for_deleted_db(deleted_db):
- return datetime.strptime(deleted_db['earliestRestoreDate'], "%Y-%m-%dT%H:%M:%S+00:00")
+ return dt.datetime.strptime(deleted_db['earliestRestoreDate'], "%Y-%m-%dT%H:%M:%S+00:00")
def _get_deleted_date(deleted_db):
- return datetime.strptime(deleted_db['deletionDate'], "%Y-%m-%dT%H:%M:%S.%f+00:00")
+ return dt.datetime.strptime(deleted_db['deletionDate'], "%Y-%m-%dT%H:%M:%S.%f+00:00")
def _create_db_wait_for_first_backup(test, resource_group, server, database_name):
@@ -2045,12 +2045,12 @@ def _create_db_wait_for_first_backup(test, resource_group, server, database_name
db = test.cmd('sql db show -g {} -s {} -n {}'
.format(resource_group, server, database_name)).get_output_in_json()
- earliest_restore_date = _get_earliest_restore_date(db).replace(tzinfo=UTC)
+ earliest_restore_date = _get_earliest_restore_date(db).replace(tzinfo=dt.UTC)
- if datetime.now(UTC) <= earliest_restore_date:
+ if dt.datetime.now(dt.UTC) <= earliest_restore_date:
print('Waiting until earliest restore date', earliest_restore_date)
- while datetime.now(UTC) <= earliest_restore_date:
+ while dt.datetime.now(dt.UTC) <= earliest_restore_date:
time.sleep(10)
return db
@@ -2155,8 +2155,8 @@ def test_sql_db_restore_deleted(self, resource_group, resource_group_location, s
# Wait for deleted database to become visible. When run live, this will take around
# 5-10 minutes. Unforunately there's no way to speed this up. Use timeout to ensure
# test doesn't loop forever if there's a bug.
- start_time = datetime.now()
- timeout = timedelta(0, 15 * 60) # 15 minutes timeout
+ start_time = dt.datetime.now()
+ timeout = dt.timedelta(0, 15 * 60) # 15 minutes timeout
while True:
deleted_dbs = list(
@@ -2168,7 +2168,7 @@ def test_sql_db_restore_deleted(self, resource_group, resource_group_location, s
# Deleted db not found, sleep (if running live) and then poll again.
if self.is_live:
- self.assertTrue(datetime.now() < start_time + timeout, 'Deleted db not found before timeout expired.')
+ self.assertTrue(dt.datetime.now() < start_time + timeout, 'Deleted db not found before timeout expired.')
time.sleep(10) # seconds
deleted_db = deleted_dbs[0]
@@ -5378,7 +5378,7 @@ def test_sql_zone_resilient_restore_hyperscale_database(self, resource_group, se
# Verify restored vldb has correct values (specifically zone redundancy == true and backup storage redundancy == Zone)
self.cmd('sql db restore -g {} --server {} --name {} --dest-name {} --time {} '
'--edition {} --family {} --capacity {} --backup-storage-redundancy {} --z'
- .format(resource_group, server, source_non_zr_db_name, restore_source_non_zr_true_param_db_name, datetime.now(UTC).isoformat(),
+ .format(resource_group, server, source_non_zr_db_name, restore_source_non_zr_true_param_db_name, dt.datetime.now(dt.UTC).isoformat(),
"Hyperscale", 'Gen5', 2, 'zone'),
checks=[
JMESPathCheck('resourceGroup', resource_group),
@@ -5389,7 +5389,7 @@ def test_sql_zone_resilient_restore_hyperscale_database(self, resource_group, se
# Restore zone redundant source vldb with zone redundancy == false
# Verify restored vldb has correct values (specifically zone redundancy == false and backup storage redundancy == Zone)
self.cmd('sql db restore -g {} --server {} --name {} --dest-name {} --time {} --z {}'
- .format(resource_group, server, source_zr_db_name, restore_source_zr_false_param_db_name, datetime.now(UTC).isoformat(), False),
+ .format(resource_group, server, source_zr_db_name, restore_source_zr_false_param_db_name, dt.datetime.now(dt.UTC).isoformat(), False),
checks=[
JMESPathCheck('resourceGroup', resource_group),
JMESPathCheck('name', restore_source_zr_false_param_db_name),
@@ -5400,7 +5400,7 @@ def test_sql_zone_resilient_restore_hyperscale_database(self, resource_group, se
# Restore non zone redundant source vldb with no parameters passed in
# Verify restored vldb has correct values (specifically zone redundancy == false and backup storage redundancy == Geo)
self.cmd('sql db restore -g {} --server {} --name {} --dest-name {} --time {}'
- .format(resource_group, server, source_non_zr_db_name, restore_source_non_zr_no_param_db_name, datetime.now(UTC).isoformat()),
+ .format(resource_group, server, source_non_zr_db_name, restore_source_non_zr_no_param_db_name, dt.datetime.now(dt.UTC).isoformat()),
checks=[
JMESPathCheck('resourceGroup', resource_group),
JMESPathCheck('name', restore_source_non_zr_no_param_db_name),
@@ -5410,7 +5410,7 @@ def test_sql_zone_resilient_restore_hyperscale_database(self, resource_group, se
# Restore zone redundant source vldb with no parameters passed in
# Verify restored vldb has correct values (specifically zone redundancy == true and backup storage redundancy == Zone)
self.cmd('sql db restore -g {} --server {} --name {} --dest-name {} --time {}'
- .format(resource_group, server, source_zr_db_name, restore_source_zr_no_param_db_name, datetime.now(UTC).isoformat()),
+ .format(resource_group, server, source_zr_db_name, restore_source_zr_no_param_db_name, dt.datetime.now(dt.UTC).isoformat()),
checks=[
JMESPathCheck('resourceGroup', resource_group),
JMESPathCheck('name', restore_source_zr_no_param_db_name),
@@ -6582,7 +6582,7 @@ def test_sql_managed_db_mgmt(self, mi, rg):
# test sql db restore command
# db1 = self.cmd('sql midb restore -g {} --mi {} -n {} --dest-name {} --time {}'
# .format(resource_group_1, managed_instance_name_1, database_name, database_name_restored,
- # datetime.now(UTC).isoformat()),
+ # dt.datetime.now(dt.UTC).isoformat()),
# checks=[
# JMESPathCheck('resourceGroup', resource_group_1),
# JMESPathCheck('name', database_name_restored),
@@ -7870,8 +7870,7 @@ def test_sql_midb_logreplay_mgmt(self, mi, rg):
'last_backup_name': 'full.bak'
})
- from datetime import UTC, datetime, timedelta
- self.kwargs['expiry'] = (datetime.now(UTC) + timedelta(hours=12)).strftime('%Y-%m-%dT%H:%MZ')
+ self.kwargs['expiry'] = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=12)).strftime('%Y-%m-%dT%H:%MZ')
self.kwargs['storage_key'] = str(self.cmd(
'az storage account keys list -n {storage_account} -g {resource_group} --query "[0].value"').output)
@@ -8904,7 +8903,6 @@ class SqlManagedInstanceRestoreCrossSubscriptionScenarioTest(ScenarioTest):
@live_only()
@ManagedInstancePreparer()
def test_sql_managed_deleted_cross_subscription_restore(self, mi, rg):
- from datetime import datetime, timezone, timedelta
resource_prefix = 'MIRestoreCrossSubDB'
self.kwargs.update({
@@ -8915,7 +8913,7 @@ def test_sql_managed_deleted_cross_subscription_restore(self, mi, rg):
'source_rg': "gen4-testing-RG",
'source_mi': "filiptanic-gen4-on-gen7-different-subnet",
'source_db': "cross-sub-restored",
- 'pit': (datetime.now(timezone.utc) + timedelta(minutes=-15)).isoformat()
+ 'pit': (dt.datetime.now(dt.timezone.utc) + dt.timedelta(minutes=-15)).isoformat()
})
# test restore deleted database
diff --git a/src/azure-cli/azure/cli/command_modules/storage/_validators.py b/src/azure-cli/azure/cli/command_modules/storage/_validators.py
index 2ba271842b9..a0cb5b65ae9 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/_validators.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/_validators.py
@@ -506,9 +506,9 @@ def validate_source_url(cmd, namespace): # pylint: disable=too-many-statements,
if valid_blob_source:
client = cf_blob_service(cmd.cli_ctx, client_kwargs)
- from datetime import UTC, datetime, timedelta
- start = datetime.now(UTC)
- expiry = datetime.now(UTC) + timedelta(days=1)
+ import datetime as dt
+ start = dt.datetime.now(dt.UTC)
+ expiry = dt.datetime.now(dt.UTC) + dt.timedelta(days=1)
source_user_delegation_key = client.get_user_delegation_key(start, expiry)
# Both source account name and either key or sas (or both) are now available
@@ -1278,7 +1278,7 @@ def validate_subnet(cmd, namespace):
def get_datetime_type(to_string):
""" Validates UTC datetime. Examples of accepted forms:
2017-12-31T01:11:59Z,2017-12-31T01:11Z or 2017-12-31T01Z or 2017-12-31 """
- from datetime import datetime
+ import datetime as dt
def datetime_type(string):
""" Validates UTC datetime. Examples of accepted forms:
@@ -1288,9 +1288,9 @@ def datetime_type(string):
for form in accepted_date_formats:
try:
if to_string:
- return datetime.strptime(string, form).strftime(form)
+ return dt.datetime.strptime(string, form).strftime(form)
- return datetime.strptime(string, form)
+ return dt.datetime.strptime(string, form)
except ValueError:
continue
raise ValueError("Input '{}' not valid. Valid example: 2000-12-31T12:59:59Z".format(string))
@@ -1300,13 +1300,13 @@ def datetime_type(string):
def get_api_version_type():
""" Examples of accepted forms: 2017-12-31 """
- from datetime import datetime
+ import datetime as dt
def api_version_type(string):
""" Validates api version format. Examples of accepted form: 2017-12-31 """
accepted_format = '%Y-%m-%d'
try:
- return datetime.strptime(string, accepted_format).strftime(accepted_format)
+ return dt.datetime.strptime(string, accepted_format).strftime(accepted_format)
except ValueError:
from azure.cli.core.azclierror import InvalidArgumentValueError
raise InvalidArgumentValueError("Input '{}' not valid. Valid example: 2008-10-27.".format(string))
@@ -1559,8 +1559,8 @@ def as_user_validator(namespace):
expiry = get_datetime_type(False)(namespace.expiry)
- from datetime import UTC, datetime, timedelta
- if expiry.replace(tzinfo=UTC) > datetime.now(UTC) + timedelta(days=7):
+ import datetime as dt
+ if expiry.replace(tzinfo=dt.UTC) > dt.datetime.now(dt.UTC) + dt.timedelta(days=7):
raise argparse.ArgumentError(
None, 'incorrect usage: --expiry should be within 7 days from now')
diff --git a/src/azure-cli/azure/cli/command_modules/storage/operations/blob.py b/src/azure-cli/azure/cli/command_modules/storage/operations/blob.py
index 7973adb1e4a..ef7eacd711a 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/operations/blob.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/operations/blob.py
@@ -5,7 +5,7 @@
import os
import sys
-from datetime import UTC, datetime, timedelta
+import datetime as dt
from azure.cli.core.profiles import ResourceType, get_sdk
from azure.cli.core.util import sdk_no_wait
@@ -825,11 +825,10 @@ def storage_blob_delete_batch(client, source, source_container_name, pattern=Non
if_none_match=None, timeout=None, dryrun=False):
container_client = client.get_container_client(source_container_name)
- from datetime import timezone
if if_modified_since and not if_modified_since.tzinfo:
- if_modified_since = if_modified_since.replace(tzinfo=timezone.utc)
+ if_modified_since = if_modified_since.replace(tzinfo=dt.timezone.utc)
if if_unmodified_since and not if_unmodified_since.tzinfo:
- if_unmodified_since = if_unmodified_since.replace(tzinfo=timezone.utc)
+ if_unmodified_since = if_unmodified_since.replace(tzinfo=dt.timezone.utc)
@check_precondition_success
def _delete_blob(blob_name):
@@ -888,7 +887,7 @@ def generate_sas_blob_uri(cmd, client, permission=None, expiry=None, start=None,
account_key = None
if as_user:
user_delegation_key = client.get_user_delegation_key(
- get_datetime_from_string(start) if start else datetime.now(UTC), get_datetime_from_string(expiry),
+ get_datetime_from_string(start) if start else dt.datetime.now(dt.UTC), get_datetime_from_string(expiry),
delegated_user_tid=user_delegation_tid)
else:
account_key = client.credential.account_key
@@ -938,7 +937,7 @@ def generate_container_shared_access_signature(cmd, client, container_name, perm
account_key = None
if as_user:
user_delegation_key = client.get_user_delegation_key(
- get_datetime_from_string(start) if start else datetime.now(UTC), get_datetime_from_string(expiry),
+ get_datetime_from_string(start) if start else dt.datetime.now(dt.UTC), get_datetime_from_string(expiry),
delegated_user_tid=user_delegation_tid)
else:
account_key = client.credential.account_key
@@ -974,8 +973,8 @@ def _copy_blob_to_blob_container(cmd, blob_service, source_blob_service, destina
# generate sas for oauth copy source
if not source_sas:
from ..util import create_short_lived_blob_sas_v2
- start = datetime.now(UTC)
- expiry = datetime.now(UTC) + timedelta(days=1)
+ start = dt.datetime.now(dt.UTC)
+ expiry = dt.datetime.now(dt.UTC) + dt.timedelta(days=1)
source_user_delegation_key = source_blob_service.get_user_delegation_key(start, expiry)
source_sas = create_short_lived_blob_sas_v2(cmd, source_blob_service.account_name, source_container,
source_blob_name,
@@ -1010,8 +1009,8 @@ def _copy_file_to_blob_container(cmd, blob_service, source_file_service, destina
'_shared_access_signature#generate_share_sas')
t_file_permissions = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_FILESHARE,
'_models#FileSasPermissions')
- start = datetime.now(UTC)
- expiry = datetime.now(UTC) + timedelta(days=1)
+ start = dt.datetime.now(dt.UTC)
+ expiry = dt.datetime.now(dt.UTC) + dt.timedelta(days=1)
source_sas = t_generate_share_sas(account_name=t_file_client.account_name, share_name=source_share,
account_key=t_file_client.credential.account_key,
permission=t_file_permissions(read=True),
@@ -1164,7 +1163,7 @@ def copy_blob(cmd, client, source_url, metadata=None, **kwargs):
as_user = True
if hasattr(blob_service_client.credential, 'account_key'):
as_user = False
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
source_url = generate_sas_blob_uri(cmd, blob_service_client, full_uri=True, blob_url=source_url,
blob_name=None, container_name=None, as_user=as_user,
expiry=expiry, permission='r')
diff --git a/src/azure-cli/azure/cli/command_modules/storage/operations/file.py b/src/azure-cli/azure/cli/command_modules/storage/operations/file.py
index ec45b5624ab..cb92b402a69 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/operations/file.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/operations/file.py
@@ -419,9 +419,9 @@ def _create_file_and_directory_from_blob(cmd, file_service, blob_service, share,
'_shared_access_signature#generate_blob_sas')
t_blob_permissions = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_BLOB,
'_models#BlobSasPermissions')
- from datetime import UTC, datetime, timedelta
- start = datetime.now(UTC)
- expiry = datetime.now(UTC) + timedelta(days=1)
+ import datetime as dt
+ start = dt.datetime.now(dt.UTC)
+ expiry = dt.datetime.now(dt.UTC) + dt.timedelta(days=1)
source_sas = t_generate_blob_sas(account_name=blob_service.account_name, container_name=container,
blob_name=blob_name,
account_key=blob_service.credential.account_key,
@@ -468,9 +468,9 @@ def _create_file_and_directory_from_file(cmd, file_service, source_file_service,
'_shared_access_signature#generate_share_sas')
t_file_permissions = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_FILESHARE,
'_models#FileSasPermissions')
- from datetime import UTC, datetime, timedelta
- start = datetime.now(UTC)
- expiry = datetime.now(UTC) + timedelta(days=1)
+ import datetime as dt
+ start = dt.datetime.now(dt.UTC)
+ expiry = dt.datetime.now(dt.UTC) + dt.timedelta(days=1)
source_sas = t_generate_share_sas(account_name=source_file_service.account_name, share_name=source_share,
account_key=source_file_service.credential.account_key,
permission=t_file_permissions(read=True),
@@ -554,9 +554,9 @@ def generate_sas_file(cmd, client, share_name=None, directory_name=None, file_na
account_key = None
user_delegation_key = None
if as_user:
- from datetime import UTC, datetime
+ import datetime as dt
user_delegation_key = client.get_user_delegation_key(
- start=get_datetime_from_string(start) if start else datetime.now(UTC),
+ start=get_datetime_from_string(start) if start else dt.datetime.now(dt.UTC),
expiry=get_datetime_from_string(expiry),
delegated_user_tid=user_delegation_tid)
else:
@@ -650,25 +650,25 @@ def pre_operations(self):
def _transform_share_rm_output(result):
- from datetime import datetime
+ import datetime as dt
try:
if hasattr(result, 'properties'):
if hasattr(result.properties, 'next_allowed_quota_downgrade_time') \
and result.properties.next_allowed_quota_downgrade_time:
time_str = str(result.properties.next_allowed_quota_downgrade_time)
- time_obj = datetime.strptime(time_str, '%a, %d %b %Y %H:%M:%S %Z')
+ time_obj = dt.datetime.strptime(time_str, '%a, %d %b %Y %H:%M:%S %Z')
result.properties.next_allowed_quota_downgrade_time = \
time_obj.strftime("%Y-%m-%dT%H:%M:%S.%f0Z")
if hasattr(result.properties, 'next_allowed_provisioned_iops_downgrade_time') \
and result.properties.next_allowed_provisioned_iops_downgrade_time:
time_str = str(result.properties.next_allowed_provisioned_iops_downgrade_time)
- time_obj = datetime.strptime(time_str, '%a, %d %b %Y %H:%M:%S %Z')
+ time_obj = dt.datetime.strptime(time_str, '%a, %d %b %Y %H:%M:%S %Z')
result.properties.next_allowed_provisioned_iops_downgrade_time = \
time_obj.strftime("%Y-%m-%dT%H:%M:%S.%f0Z")
if hasattr(result.properties, 'next_allowed_provisioned_bandwidth_downgrade_time') \
and result.properties.next_allowed_provisioned_bandwidth_downgrade_time:
time_str = str(result.properties.next_allowed_provisioned_bandwidth_downgrade_time)
- time_obj = datetime.strptime(time_str, '%a, %d %b %Y %H:%M:%S %Z')
+ time_obj = dt.datetime.strptime(time_str, '%a, %d %b %Y %H:%M:%S %Z')
result.properties.next_allowed_provisioned_bandwidth_downgrade_time = \
time_obj.strftime("%Y-%m-%dT%H:%M:%S.%f0Z")
return result
diff --git a/src/azure-cli/azure/cli/command_modules/storage/operations/fileshare.py b/src/azure-cli/azure/cli/command_modules/storage/operations/fileshare.py
index 75f535dbbd7..38e31873bc0 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/operations/fileshare.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/operations/fileshare.py
@@ -3,7 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
import math
-from datetime import UTC, datetime
+import datetime as dt
from knack.log import get_logger
@@ -67,7 +67,7 @@ def generate_share_sas(cmd, client, share_name=None, permission=None, expiry=Non
user_delegation_key = None
if as_user:
user_delegation_key = client.get_user_delegation_key(
- start=get_datetime_from_string(start) if start else datetime.now(UTC),
+ start=get_datetime_from_string(start) if start else dt.datetime.now(dt.UTC),
expiry=get_datetime_from_string(expiry),
delegated_user_tid=user_delegation_tid)
else:
diff --git a/src/azure-cli/azure/cli/command_modules/storage/operations/filesystem.py b/src/azure-cli/azure/cli/command_modules/storage/operations/filesystem.py
index c2ac3ee5566..3e5646e6254 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/operations/filesystem.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/operations/filesystem.py
@@ -3,7 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
-from datetime import UTC, datetime
+import datetime as dt
from azure.cli.core.profiles import ResourceType
from ..util import get_datetime_from_string
@@ -45,7 +45,7 @@ def generate_sas_fs_uri(client, cmd, file_system, permission=None,
sas_kwargs = {}
if as_user:
user_delegation_key = client.get_user_delegation_key(
- get_datetime_from_string(start) if start else datetime.now(UTC),
+ get_datetime_from_string(start) if start else dt.datetime.now(dt.UTC),
get_datetime_from_string(expiry),
delegated_user_tid=user_delegation_tid)
diff --git a/src/azure-cli/azure/cli/command_modules/storage/operations/fs_directory.py b/src/azure-cli/azure/cli/command_modules/storage/operations/fs_directory.py
index 8c3a39b6290..ada9d4c794f 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/operations/fs_directory.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/operations/fs_directory.py
@@ -6,7 +6,7 @@
"""Custom operations for storage file datalake"""
# pylint: disable=too-many-locals
-from datetime import UTC, datetime
+import datetime as dt
from azure.cli.core.profiles import ResourceType
from knack.util import todict
@@ -106,7 +106,7 @@ def generate_sas_directory_uri(client, cmd, file_system_name, directory_name, pe
sas_kwargs = {}
if as_user:
user_delegation_key = client.get_user_delegation_key(
- get_datetime_from_string(start) if start else datetime.now(UTC),
+ get_datetime_from_string(start) if start else dt.datetime.now(dt.UTC),
get_datetime_from_string(expiry),
delegated_user_tid=user_delegation_tid)
diff --git a/src/azure-cli/azure/cli/command_modules/storage/operations/fs_file.py b/src/azure-cli/azure/cli/command_modules/storage/operations/fs_file.py
index 8657e078745..a56fbbaf0ac 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/operations/fs_file.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/operations/fs_file.py
@@ -7,7 +7,7 @@
# pylint: disable=too-many-locals
import os
-from datetime import UTC, datetime
+import datetime as dt
from azure.core.exceptions import HttpResponseError
from azure.cli.core.profiles import ResourceType
@@ -160,7 +160,7 @@ def generate_sas_file_uri(client, cmd, file_system_name, path, permission=None,
sas_kwargs = {}
if as_user:
user_delegation_key = client.get_user_delegation_key(
- get_datetime_from_string(start) if start else datetime.now(UTC),
+ get_datetime_from_string(start) if start else dt.datetime.now(dt.UTC),
get_datetime_from_string(expiry),
delegated_user_tid=user_delegation_tid)
diff --git a/src/azure-cli/azure/cli/command_modules/storage/operations/queue.py b/src/azure-cli/azure/cli/command_modules/storage/operations/queue.py
index 4043b46cbae..d6161872727 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/operations/queue.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/operations/queue.py
@@ -52,9 +52,9 @@ def generate_queue_sas(cmd, client, queue_name=None, permission=None, expiry=Non
account_key = None
user_delegation_key = None
if as_user:
- from datetime import UTC, datetime
+ import datetime as dt
user_delegation_key = client.get_user_delegation_key(
- start=get_datetime_from_string(start) if start else datetime.now(UTC),
+ start=get_datetime_from_string(start) if start else dt.datetime.now(dt.UTC),
expiry=get_datetime_from_string(expiry),
delegated_user_tid=user_delegation_tid)
else:
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_account_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_account_scenarios.py
index 1dec5ab13aa..ae0ddec0b21 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_account_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_account_scenarios.py
@@ -13,7 +13,7 @@
from azure.cli.core.profiles import ResourceType
from ..storage_test_util import StorageScenarioMixin
from knack.util import CLIError
-from datetime import UTC, datetime, timedelta
+import datetime as dt
from azure.cli.testsdk.scenario_tests import AllowLargeResponse
@@ -2004,10 +2004,9 @@ class RevokeStorageAccountTests(StorageScenarioMixin, RoleScenarioTest, LiveScen
def test_storage_account_revoke_delegation_keys(self, resource_group, storage_account):
if self.run_under_service_principal():
return # this test delete users which are beyond a SP's capacity, so quit...
- from datetime import UTC, datetime, timedelta
import time
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
account_info = self.get_account_info(resource_group, storage_account)
c = self.create_container(account_info)
b = self.create_random_name('blob', 24)
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_adls_gen2_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_adls_gen2_scenarios.py
index 197b363f72c..b1ab5cefb37 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_adls_gen2_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_adls_gen2_scenarios.py
@@ -5,7 +5,7 @@
import unittest
import os
import time
-from datetime import UTC, datetime, timedelta
+import datetime as dt
from azure.cli.testsdk import (ScenarioTest, LiveScenarioTest, ResourceGroupPreparer, StorageAccountPreparer, JMESPathCheck, JMESPathCheckExists,
RoleBasedServicePrincipalPreparer)
@@ -503,14 +503,13 @@ def test_adls_file_scenarios(self, resource_group, storage_account):
@ResourceGroupPreparer()
@StorageAccountPreparer(kind="StorageV2", hns=True)
def test_adls_file_set_expiry_scenarios(self, resource_group, storage_account):
- from datetime import UTC, datetime, timedelta
account_info = self.get_account_info(resource_group, storage_account)
filesystem = self.create_file_system(account_info)
file = self.create_random_name(prefix="file", length=12)
self.storage_cmd('storage fs file create -p {} -f {} --content-type "application/json"',
account_info, file, filesystem)
- expiry = (datetime.now(UTC) + timedelta(seconds=5)).strftime('%Y-%m-%dT%H:%M:%SZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(seconds=5)).strftime('%Y-%m-%dT%H:%M:%SZ')
self.storage_cmd("storage fs file set-expiry --expiry-options Absolute --expires-on {} -p {} -f {}",
account_info, expiry, file, filesystem)
self.storage_cmd("storage fs file exists -p {} -f {}", account_info, file, filesystem)\
@@ -565,7 +564,7 @@ def test_storage_fs_generate_sas_full_uri(self, resource_group, storage_account)
account_info = self.get_account_info(resource_group, storage_account)
f = self.create_file_system(account_info)
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
fs_uri = self.storage_cmd('storage fs generate-sas -n {} --expiry {} --permissions '
'r --https-only --full-uri', account_info, f, expiry).output
self.assertTrue(fs_uri)
@@ -578,7 +577,7 @@ def test_storage_fs_generate_sas_as_user(self, resource_group, storage_account):
account_info = self.get_account_info(resource_group, storage_account)
f = self.create_file_system(account_info)
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
with self.assertRaisesRegex(CLIError, "incorrect usage: specify --as-user when --auth-mode login"):
self.cmd('storage fs generate-sas --account-name {} -n {} --expiry {} --permissions r --https-only '
@@ -606,7 +605,7 @@ def test_storage_fs_generate_sas_with_user_delegation_oid(self, resource_group,
current_tenant = self.cmd('account show --query tenantId').get_output_in_json()
current_tenant = current_tenant if current_tenant is not None else '544a7a2e-697f-487c-b2b0-a13df7f346b6'
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
fs_sas = self.cmd('storage fs generate-sas --account-name {} -n {} --expiry {} --permissions '
'dlrwop --https-only --as-user --auth-mode login --user-delegation-oid '
@@ -636,7 +635,7 @@ def test_storage_fs_directory_generate_sas_full_uri(self, resource_group, storag
self.storage_cmd('storage fs directory create -n {} -f {}',
account_info, directory, filesystem)
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
fs_uri = self.storage_cmd('storage fs directory generate-sas -n {} -f {} --expiry {} --permissions '
'r --https-only --full-uri', account_info, directory, filesystem, expiry).output
self.assertTrue(fs_uri)
@@ -653,7 +652,7 @@ def test_storage_fs_directory_generate_sas_as_user(self, resource_group, storage
self.storage_cmd('storage fs directory create -n {} -f {}', account_info, directory, filesystem)
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
with self.assertRaisesRegex(CLIError, "incorrect usage: specify --as-user when --auth-mode login"):
self.cmd('storage fs directory generate-sas --account-name {} -n {} -f {} --expiry {} --permissions r '
@@ -685,7 +684,7 @@ def test_storage_fs_directory_generate_sas_with_user_delegation_oid(self, resour
self.storage_cmd('storage fs directory create -n {} -f {}', account_info, directory, filesystem)
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
fs_sas = self.cmd('storage fs directory generate-sas --account-name {} -n {} -f {} --expiry {} --permissions '
'dlrwop --https-only --as-user --auth-mode login --user-delegation-oid '
@@ -719,7 +718,7 @@ def test_storage_fs_file_generate_sas_as_user(self, resource_group, storage_acco
self.storage_cmd('storage fs directory create -n {} -f {}', account_info, directory, filesystem)
self.storage_cmd('storage fs file create -p {} -f {}', account_info, file_path, filesystem)
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
with self.assertRaisesRegex(CLIError, "incorrect usage: specify --as-user when --auth-mode login"):
self.cmd('storage fs file generate-sas --account-name {} -p {} -f {} --expiry {} --permissions r '
@@ -755,7 +754,7 @@ def test_storage_fs_file_generate_sas_with_user_delegation_oid(self, resource_gr
self.storage_cmd('storage fs file create -p {} -f {}', account_info, file_path, filesystem)
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
file_sas = self.cmd('storage fs file generate-sas --account-name {} -p {} -f {} --expiry {} --permissions '
'dlrwop --https-only --as-user --auth-mode login --user-delegation-oid '
@@ -790,8 +789,7 @@ def test_adls_directory_upload(self, resource_group, storage_account, test_dir):
self.storage_cmd('storage fs create -n {}', account_info, filesystem)
self.storage_cmd('storage fs directory create -n {} -f {}', account_info, directory, filesystem)
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
sas = self.storage_cmd('storage container generate-sas -n {} --https-only '
'--permissions acdlrw --expiry {} -otsv',
account_info, filesystem, expiry).output.strip()
@@ -855,8 +853,7 @@ def test_adls_directory_download(self, resource_group, storage_account, test_dir
self.storage_cmd('storage fs directory upload -f {} -d {} -s "{}" --recursive', account_info, filesystem,
directory, os.path.join(test_dir, 'apple'))
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
sas = self.storage_cmd('storage container generate-sas -n {} --https-only '
'--permissions lr --expiry {} -otsv',
account_info, filesystem, expiry).output.strip()
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_azcopy_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_azcopy_scenarios.py
index f1efcec5129..6cf95b0dc86 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_azcopy_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_azcopy_scenarios.py
@@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------
import os
import shutil
-from datetime import UTC, datetime, timedelta
+import datetime as dt
from azure.cli.testsdk import (StorageAccountPreparer, LiveScenarioTest, JMESPathCheck, ResourceGroupPreparer)
from ..storage_test_util import StorageScenarioMixin, StorageTestFilesPreparer
from knack.util import CLIError
@@ -192,8 +192,7 @@ def test_storage_blob_azcopy_sync_oauth(self, storage_account, test_dir):
@StorageAccountPreparer()
@StorageTestFilesPreparer()
def test_storage_blob_azcopy_sync_sas(self, resource_group, storage_account, test_dir):
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
account_info = self.get_account_info(resource_group, storage_account)
container = self.create_random_name(prefix='container', length=20)
@@ -485,8 +484,7 @@ def test_storage_file_azcopy_remove_oauth(self, resource_group, storage_account)
@StorageAccountPreparer()
@StorageTestFilesPreparer()
def test_storage_azcopy_remove_sas(self, resource_group, storage_account, test_dir):
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
account_info = self.get_account_info(resource_group, storage_account)
container = self.create_container(account_info, prefix='container', length=20)
@@ -763,7 +761,7 @@ def test_storage_azcopy_blob_source_with_credential(self, resource_group, first_
self.assertEqual(11, sum(len(f) for r, d, f in os.walk(local_folder)))
# Download a set of files with source sas token
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
first_sas_token = self.cmd(
'storage container generate-sas --connection-string {} -n {} --expiry {} --permissions {} -o tsv'.format(
first_connection_string, first_container, expiry, 'rwalcd')).output.strip()
@@ -774,7 +772,7 @@ def test_storage_azcopy_blob_source_with_credential(self, resource_group, first_
self.assertEqual(21, sum(len(f) for r, d, f in os.walk(local_folder)))
# Copy a single blob to another single blob with sas token
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
second_sas_token = self.storage_cmd(
'storage container generate-sas -n {} --expiry {} --permissions {} -o tsv', second_account_info,
second_container, expiry, 'acdlrw').output.strip()
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_batch_operations.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_batch_operations.py
index acb2b8160d3..670881ae43a 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_batch_operations.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_batch_operations.py
@@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------
import os
-from datetime import UTC, datetime
+import datetime as dt
from azure.cli.testsdk import ScenarioTest, StorageAccountPreparer, ResourceGroupPreparer, JMESPathCheck, live_only
from ..storage_test_util import StorageScenarioMixin, StorageTestFilesPreparer
@@ -154,9 +154,8 @@ def test_storage_blob_batch_upload_scenarios(self, test_dir, storage_account_inf
self.storage_cmd('storage blob upload-batch -d {} -s "{}"',
storage_account_info, container, test_dir)
import time
- from datetime import datetime
time.sleep(1)
- current = datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
+ current = dt.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
time.sleep(1)
result = self.storage_cmd('storage blob upload-batch -d {} -s "{}" --if-modified-since {}',
storage_account_info, container, test_dir, current).get_output_in_json()
@@ -353,8 +352,7 @@ def test_storage_file_batch_upload_scenarios(self, test_dir, storage_account_inf
@StorageAccountPreparer(parameter_name='dst_account')
@StorageTestFilesPreparer()
def test_storage_blob_batch_copy(self, src_account_info, dst_account_info, test_dir):
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
src_container = 'container1'
self.storage_cmd('storage container create -n {}', src_account_info, src_container)
@@ -443,8 +441,7 @@ def test_storage_blob_batch_copy(self, src_account_info, dst_account_info, test_
@StorageAccountPreparer(parameter_name='dst_account')
@StorageTestFilesPreparer()
def test_storage_file_batch_copy(self, src_account_info, dst_account_info, test_dir):
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
src_container = 'container1'
self.storage_cmd('storage container create -n {}', src_account_info, src_container)
@@ -580,9 +577,9 @@ def create_and_populate_container(src_container):
src_container = 'container7'
create_and_populate_container(src_container)
self.storage_cmd('storage blob delete-batch -s {} --if-unmodified-since {} --dryrun',
- storage_account_info, src_container, datetime.max.strftime('%Y-%m-%dT%H:%MZ'))
+ storage_account_info, src_container, dt.datetime.max.strftime('%Y-%m-%dT%H:%MZ'))
self.storage_cmd('storage blob delete-batch -s {} --if-unmodified-since {}',
- storage_account_info, src_container, datetime.max.strftime('%Y-%m-%dT%H:%MZ'))
+ storage_account_info, src_container, dt.datetime.max.strftime('%Y-%m-%dT%H:%MZ'))
self.storage_cmd('storage blob list -c {}', storage_account_info, src_container).assert_with_checks(
JMESPathCheck('length(@)', 0))
@@ -648,12 +645,11 @@ def create_and_populate_share(src_share):
@StorageTestFilesPreparer()
@live_only()
def test_storage_blob_batch_sas_scenarios(self, test_dir, resource_group, storage_account_info):
- from datetime import UTC, datetime, timedelta
container_name = 'container1'
self.storage_cmd('storage container create -n {}', storage_account_info, container_name)
temp_dir = self.create_temp_dir()
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
sas_token = self.storage_cmd('storage container generate-sas -n {} --permissions dwrl --expiry {}',
storage_account_info, container_name, expiry).get_output_in_json()
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_copy_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_copy_scenarios.py
index 1059b10fd21..4a1335396d4 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_copy_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_copy_scenarios.py
@@ -214,9 +214,9 @@ def test_storage_blob_copy_with_sas_and_snapshot(self, resource_group, source_ac
self.storage_cmd('storage blob upload -c {} -f "{}" -n src --overwrite', source_account_info,
source_container, source_file)
- from datetime import UTC, datetime, timedelta
- start = datetime.now(UTC).strftime('%Y-%m-%dT%H:%MZ')
- expiry = (datetime.now(UTC) + timedelta(minutes=5)).strftime('%Y-%m-%dT%H:%MZ')
+ import datetime as dt
+ start = dt.datetime.now(dt.UTC).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(minutes=5)).strftime('%Y-%m-%dT%H:%MZ')
sas = self.storage_cmd('storage blob generate-sas -c {} -n src --permissions r --start {}'
' --expiry {}', source_account_info, source_container, start,
expiry).output.strip()
@@ -260,9 +260,9 @@ def test_storage_blob_copy_same_account_sas(self, resource_group, storage_accoun
self.storage_cmd('storage blob upload -c {} -f "{}" -n src', account_info,
source_container, source_file)
- from datetime import UTC, datetime, timedelta
- start = datetime.now(UTC).strftime('%Y-%m-%dT%H:%MZ')
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ import datetime as dt
+ start = dt.datetime.now(dt.UTC).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
sas = self.storage_cmd('storage blob generate-sas -c {} -n src --permissions r --start {}'
' --expiry {}', account_info, source_container, start,
expiry).output.strip()
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_live_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_live_scenarios.py
index c567a51d10c..f01166258e1 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_live_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_live_scenarios.py
@@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------
import os
-from datetime import UTC, datetime, timedelta
+import datetime as dt
from azure.cli.testsdk import (LiveScenarioTest, ResourceGroupPreparer, StorageAccountPreparer,
JMESPathCheck, JMESPathCheckExists, NoneCheck)
from azure.cli.core.profiles import ResourceType
@@ -145,7 +145,7 @@ def test_storage_blob_query_scenario(self, resource_group, storage_account):
account_info, container, csv_blob, query_string).output
self.assertIsNotNone(result)
#test blob-url
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
blob_uri = self.storage_cmd('storage blob generate-sas -n {} -c {} --expiry {} --permissions '
'rwad --https-only --full-uri -o tsv',
account_info, csv_blob, container, expiry).output.strip()
@@ -193,7 +193,7 @@ def test_storage_blob_url_scenarios(self, resource_group, storage_account):
self.storage_cmd('storage blob upload -c {} -f "{}" -n {} ', account_info,
container, local_file1, blob_name1)
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
blob_uri = self.storage_cmd('storage blob generate-sas -n {} -c {} --expiry {} --permissions '
'rwad --https-only --full-uri -o tsv',
account_info, blob_name1, container, expiry).output.strip()
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_rewrite_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_rewrite_scenarios.py
index 7be520d6fc5..188639aa143 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_rewrite_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_rewrite_scenarios.py
@@ -3,7 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
-from datetime import UTC, datetime, timedelta
+import datetime as dt
from azure.cli.testsdk import LiveScenarioTest, ResourceGroupPreparer, StorageAccountPreparer,\
JMESPathCheck
from azure.cli.testsdk.decorators import serial_test
@@ -77,7 +77,7 @@ def test_storage_blob_rewrite_encryption_scope(self, group, account, file_size_k
])
# Update blob encryption
- expiry = (datetime.now(UTC) + timedelta(days=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(days=1)).strftime('%Y-%m-%dT%H:%MZ')
source_url = self.storage_cmd(
'storage blob generate-sas -c {} -n {} --https-only --permissions r --expiry {} --full-uri -otsv',
account_info, container, blob, expiry).output.strip()
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_scenarios.py
index 255d2dc8f19..eafa55ae5b4 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_scenarios.py
@@ -6,7 +6,7 @@
import os
import re
import unittest
-from datetime import UTC, datetime, timedelta
+import datetime as dt
from azure.cli.testsdk import (ScenarioTest, ResourceGroupPreparer, StorageAccountPreparer,
JMESPathCheck, JMESPathCheckExists, NoneCheck)
from knack.util import CLIError
@@ -103,7 +103,7 @@ def verify_blob_upload_and_download(self, group, account, file_size_kb, blob_typ
else:
self.assertEqual(show_result.get('properties').get('pageRanges'), None)
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
sas = self.storage_cmd('storage blob generate-sas -n {} -c {} --expiry {} --permissions '
'r --https-only', account_info, blob_name, container, expiry).output
self.assertTrue(sas)
@@ -280,8 +280,7 @@ def test_storage_blob_container_operations(self, resource_group, storage_account
.assert_with_checks(JMESPathCheck('publicAccess', 'off'))
# test case with access policy set
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
policy = self.create_random_name('policy', 16)
self.storage_cmd('storage container policy create -c {} -n {} --expiry {} --permissions racwdxyltfmei',
account_info, c, policy, expiry)
@@ -336,8 +335,7 @@ def test_storage_blob_container_operations(self, resource_group, storage_account
JMESPathCheck('properties.lease.state', 'available'),
JMESPathCheck('properties.lease.status', 'unlocked'))
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
self.assertIn('sig=', self.storage_cmd('storage container generate-sas -n {} --permissions r --expiry {}',
account_info, c, expiry).output)
@@ -518,7 +516,7 @@ def test_storage_blob_generate_sas_full_uri(self, resource_group, storage_accoun
c = self.create_container(account_info)
b = self.create_random_name('blob', 24)
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
blob_uri = self.storage_cmd('storage blob generate-sas -n {} -c {} --expiry {} --permissions '
'r --https-only --full-uri', account_info, b, c, expiry).output
self.assertTrue(blob_uri)
@@ -532,7 +530,7 @@ def test_storage_blob_generate_sas_as_user(self, resource_group, storage_account
c = self.create_container(account_info)
b = self.create_random_name('blob', 24)
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
with self.assertRaisesRegex(CLIError, "incorrect usage: specify --as-user when --auth-mode login"):
self.cmd('storage blob generate-sas --account-name {} -n {} -c {} --expiry {} --permissions r --https-only '
@@ -572,7 +570,7 @@ def test_storage_blob_generate_sas_with_user_delegation_oid(self, resource_group
current_tenant = self.cmd('account show --query tenantId').get_output_in_json()
current_tenant = current_tenant if current_tenant is not None else '544a7a2e-697f-487c-b2b0-a13df7f346b6'
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
self.storage_cmd('storage blob upload -c {} -n {} -f "{}"', account_info, c, b, local_file)
@@ -697,7 +695,6 @@ def md5(fname):
@ResourceGroupPreparer()
@StorageAccountPreparer()
def test_storage_blob_upload_precondition_scenarios(self, resource_group, storage_account_info):
- from datetime import datetime
import time
account_info = storage_account_info
container = self.create_container(account_info)
@@ -709,7 +706,7 @@ def test_storage_blob_upload_precondition_scenarios(self, resource_group, storag
self.storage_cmd('storage blob upload -c {} -f "{}" -n {}', account_info,
container, local_file, blob_name)
time.sleep(1)
- current = datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
+ current = dt.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
time.sleep(1)
with self.assertRaises(Exception):
self.storage_cmd('storage blob upload -c {} -f "{}" -n {}', account_info,
@@ -892,8 +889,7 @@ def test_storage_blob_vlm(self, resource_group, storage_account_info):
self.storage_cmd('storage blob upload -c {} -f "{}" -n {} ', storage_account_info, container, file, blob)
# Test set immutability policy
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
result = self.storage_cmd('storage blob immutability-policy set -n {} -c {} '
'--expiry-time {} --policy-mode Unlocked',
storage_account_info, blob, container, expiry).get_output_in_json()
@@ -1042,7 +1038,7 @@ def test_storage_blob_restore(self, resource_group, storage_account):
JMESPathCheck('restorePolicy.days', 1),
JMESPathCheckExists('restorePolicy.minRestoreTime'))
- time_to_restore = (datetime.now(UTC) + timedelta(seconds=-5)).strftime('%Y-%m-%dT%H:%MZ')
+ time_to_restore = (dt.datetime.now(dt.UTC) + dt.timedelta(seconds=-5)).strftime('%Y-%m-%dT%H:%MZ')
# c1/b1 -> c1/b2
start_range = '/'.join([c1, b1])
@@ -1059,7 +1055,7 @@ def test_storage_blob_restore(self, resource_group, storage_account):
if self.is_live:
time.sleep(300)
- time_to_restore = (datetime.now(UTC) + timedelta(seconds=-5)).strftime('%Y-%m-%dT%H:%MZ')
+ time_to_restore = (dt.datetime.now(dt.UTC) + dt.timedelta(seconds=-5)).strftime('%Y-%m-%dT%H:%MZ')
# c1/b2 -> c2/b3
start_range = '/'.join([c1, b2])
end_range = '/'.join([c2, b3])
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_container_access_policy.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_container_access_policy.py
index d9860864899..7de526ec655 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_container_access_policy.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_container_access_policy.py
@@ -8,13 +8,13 @@
JMESPathCheck, JMESPathCheckExists, NoneCheck, live_only)
from ..storage_test_util import StorageScenarioMixin
from knack.util import CLIError
-from datetime import UTC, datetime, timedelta
+import datetime as dt
class StorageSASScenario(StorageScenarioMixin, ScenarioTest):
@ResourceGroupPreparer()
@StorageAccountPreparer(allow_blob_public_access=True)
def test_storage_container_access_policy_scenario(self, resource_group, storage_account):
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
account_info = self.get_account_info(resource_group, storage_account)
container = self.create_random_name(prefix='cont', length=24)
@@ -40,8 +40,8 @@ def test_storage_container_access_policy_scenario(self, resource_group, storage_
container,
local_file, sas)
- new_start = (datetime.now(UTC) - timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
- new_expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ new_start = (dt.datetime.now(dt.UTC) - dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ new_expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
self.storage_cmd('storage container policy update -c {} -n {} --permissions rwdxl --start {} --expiry {}',
account_info, container,
policy, new_start, new_expiry)
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_file_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_file_scenarios.py
index b2e4023e7b2..137fdffd13e 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_file_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_file_scenarios.py
@@ -361,8 +361,8 @@ def validate_file_scenario(self, account_info, share):
file_list = self.storage_cmd('storage file list -s {}', account_info, share).get_output_in_json()
self.assertIsNotNone(file_list[0]['lastAccessTime'])
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ import datetime as dt
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
self.storage_cmd('storage file generate-sas -s {} -p {} --permissions r --expiry {}', account_info, share,
filename, expiry).assert_with_checks(StringContainCheck('sig='))
@@ -691,8 +691,8 @@ def test_storage_file_generate_sas_as_user(self, resource_group, storage_account
local_file = self.create_temp_file(1024)
file_name = os.path.basename(local_file)
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ import datetime as dt
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
with self.assertRaisesRegex(CLIError, "incorrect usage: specify --as-user when --auth-mode login"):
self.cmd('storage file generate-sas --account-name {} -p {} -s {} --expiry {} --permissions r --https-only '
@@ -725,8 +725,8 @@ def test_storage_file_generate_sas_with_user_delegation_oid(self, resource_group
current_tenant = self.cmd('account show --query tenantId').get_output_in_json()
current_tenant = current_tenant if current_tenant is not None else '544a7a2e-697f-487c-b2b0-a13df7f346b6'
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ import datetime as dt
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
file_sas = self.cmd('storage file generate-sas --account-name {} -p {} -s {} --expiry {} --permissions crwd '
'--https-only --as-user --auth-mode login --backup-intent --user-delegation-oid {} '
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_file_share_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_file_share_scenarios.py
index 8672a3cee77..d9c780ebe34 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_file_share_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_file_share_scenarios.py
@@ -13,7 +13,7 @@ class StorageShareScenarioTests(StorageScenarioMixin, ScenarioTest):
@ResourceGroupPreparer(name_prefix='clitest')
@StorageAccountPreparer(name_prefix='share', kind='StorageV2', location='eastus2', sku='Standard_RAGRS')
def test_storage_file_share_scenario(self, resource_group, storage_account):
- from datetime import UTC, datetime, timedelta
+ import datetime as dt
account_info = self.get_account_info(resource_group, storage_account)
connection_string = self.get_connection_string(resource_group, storage_account)
@@ -47,8 +47,8 @@ def test_storage_file_share_scenario(self, resource_group, storage_account):
self.assertIn(share_name, share_list, 'The newly created share is not listed.')
# Test generate-sas with start, expiry and permissions
- start = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
- expiry = (datetime.now(UTC) + timedelta(hours=2)).strftime('%Y-%m-%dT%H:%MZ')
+ start = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=2)).strftime('%Y-%m-%dT%H:%MZ')
sas = self.storage_cmd('storage share generate-sas -n {} --permissions r --start {} --expiry {}',
account_info, share_name, start, expiry).output
self.assertIn('sig', sas, 'The sig segment is not in the sas {}'.format(sas))
@@ -164,8 +164,8 @@ def test_storage_share_generate_sas_as_user(self, resource_group, storage_accoun
share = self.create_share(account_info)
local_file = self.create_temp_file(1024)
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ import datetime as dt
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
with self.assertRaisesRegex(CLIError, "incorrect usage: specify --as-user when --auth-mode login"):
self.cmd('storage share generate-sas --account-name {} -n {} --expiry {} --permissions r --https-only '
@@ -197,8 +197,8 @@ def test_storage_share_generate_sas_with_user_delegation_oid(self, resource_grou
current_tenant = self.cmd('account show --query tenantId').get_output_in_json()
current_tenant = current_tenant if current_tenant is not None else '544a7a2e-697f-487c-b2b0-a13df7f346b6'
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ import datetime as dt
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
share_sas = self.cmd('storage share generate-sas --account-name {} -n {} --expiry {} --permissions crwld '
'--https-only --as-user --auth-mode login --backup-intent --user-delegation-oid '
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_queue_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_queue_scenarios.py
index 600ec3075a3..a5338c52794 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_queue_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_queue_scenarios.py
@@ -14,7 +14,7 @@ class StorageQueueScenarioTests(StorageScenarioMixin, ScenarioTest):
@ResourceGroupPreparer(name_prefix='clitest')
@StorageAccountPreparer(name_prefix='queue', kind='StorageV2', location='eastus2', sku='Standard_RAGRS')
def test_storage_queue_general_scenario(self, resource_group, storage_account):
- from datetime import UTC, datetime, timedelta
+ import datetime as dt
account_key = self.get_account_key(resource_group, storage_account)
connection_string = self.get_connection_string(resource_group, storage_account)
@@ -45,8 +45,8 @@ def test_storage_queue_general_scenario(self, resource_group, storage_account):
self.assertIn(queue, [x['name'] for x in res], 'The newly created queue is not listed.')
# Test generate-sas with start, expiry and permissions
- start = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
- expiry = (datetime.now(UTC) + timedelta(hours=2)).strftime('%Y-%m-%dT%H:%MZ')
+ start = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=2)).strftime('%Y-%m-%dT%H:%MZ')
sas = self.cmd('storage queue generate-sas -n {} --permissions r --start {} --expiry {}'
.format(queue, start, expiry)).output
self.assertIn('sig', sas, 'The sig segment is not in the sas {}'.format(sas))
@@ -271,8 +271,8 @@ def test_storage_queue_generate_sas_as_user(self, resource_group, storage_accoun
self.cmd('storage queue create --account-name {} -n {}'.format(storage_account, queue))
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ import datetime as dt
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
with self.assertRaisesRegex(CLIError, "incorrect usage: specify --as-user when --auth-mode login"):
self.cmd('storage queue generate-sas --account-name {} -n {} --expiry {} --permissions r --https-only '
@@ -306,8 +306,8 @@ def test_storage_queue_generate_sas_with_user_delegation_oid(self, resource_grou
current_tenant = self.cmd('account show --query tenantId').get_output_in_json()
current_tenant = current_tenant if current_tenant is not None else '544a7a2e-697f-487c-b2b0-a13df7f346b6'
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ import datetime as dt
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
queue_sas = self.cmd('storage queue generate-sas --account-name {} -n {} --expiry {} --permissions raup '
'--https-only --as-user --user-delegation-oid {} '
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_scenarios.py
index 2f5991049ad..6a8126e7159 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_scenarios.py
@@ -13,8 +13,8 @@ class StorageSASScenario(StorageScenarioMixin, LiveScenarioTest):
@ResourceGroupPreparer()
@StorageAccountPreparer(location='EastUS2')
def test_storage_file_sas_scenario(self, resource_group, storage_account):
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ import datetime as dt
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
account_info = self.get_account_info(resource_group, storage_account)
share = self.create_share(account_info)
@@ -66,8 +66,8 @@ def test_storage_file_sas_scenario(self, resource_group, storage_account):
@ResourceGroupPreparer()
@StorageAccountPreparer()
def test_storage_blob_sas_scenario(self, resource_group, storage_account):
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ import datetime as dt
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
account_info = self.get_account_info(resource_group, storage_account)
container = self.create_container(account_info)
@@ -131,8 +131,8 @@ def test_storage_blob_sas_scenario(self, resource_group, storage_account):
@ResourceGroupPreparer(name_prefix='clitest')
@StorageAccountPreparer(name_prefix='queuesas', kind='StorageV2', location='eastus2', sku='Standard_RAGRS')
def test_storage_queue_sas_scenario(self, resource_group, storage_account):
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ import datetime as dt
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
account_info = self.get_account_info(resource_group, storage_account)
queue = self.create_random_name('queue', 24)
@@ -157,8 +157,8 @@ def test_storage_queue_sas_scenario(self, resource_group, storage_account):
@ResourceGroupPreparer()
@StorageAccountPreparer()
def test_storage_account_sas_scenario(self, resource_group, storage_account):
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ import datetime as dt
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
connection_str = self.cmd('storage account show-connection-string -n {} -otsv'.format(storage_account)).output
scope_name = self.create_random_name('scope', 16)
@@ -206,8 +206,8 @@ def test_storage_account_sas_scenario(self, resource_group, storage_account):
@ResourceGroupPreparer()
@StorageAccountPreparer(hns=True, kind='StorageV2')
def test_storage_fs_sas_scenario(self, resource_group, storage_account):
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ import datetime as dt
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
account_info = self.get_account_info(resource_group, storage_account)
file_system = self.create_file_system(account_info)
@@ -314,8 +314,8 @@ def test_storage_fs_sas_scenario(self, resource_group, storage_account):
@ResourceGroupPreparer()
@StorageAccountPreparer(hns=True, kind='StorageV2')
def test_storage_fs_sas_with_encryption_scope(self, resource_group, storage_account_info):
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ import datetime as dt
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
storage_account, account_key = storage_account_info
file_system = self.create_file_system(storage_account_info)
@@ -345,8 +345,8 @@ def test_storage_table_entity_sas(self, resource_group, storage_account):
self.storage_cmd('storage table create -n {} --fail-on-exist', account_info, table_name) \
.assert_with_checks(JMESPathCheck('created', True))
- from datetime import UTC, datetime, timedelta
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ import datetime as dt
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
sas_token_a = self.storage_cmd('storage table generate-sas -n {} --expiry {} --permissions a', account_info,
table_name, expiry).get_output_in_json()
account_name = account_info[0]
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_tokan_url_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_tokan_url_scenarios.py
index 5add177a934..25af58cf3a1 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_tokan_url_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_tokan_url_scenarios.py
@@ -5,7 +5,7 @@
import os
import requests
-from datetime import UTC, datetime, timedelta
+import datetime as dt
from azure.cli.testsdk import (LiveScenarioTest, ResourceGroupPreparer, StorageAccountPreparer,
JMESPathCheck, NoneCheck, StringCheck, StringContainCheck)
from ..storage_test_util import StorageScenarioMixin
@@ -19,7 +19,7 @@ def test_storage_file_url_sas_token_scenario(self, resource_group, storage_accou
share = self.create_share(account_info)
source_file = self.create_temp_file(128, full_random=False)
filename = "sample_file.bin"
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
self.storage_cmd('storage share exists -n {}', account_info, share) \
.assert_with_checks(JMESPathCheck('exists', True))
@@ -48,7 +48,7 @@ def test_storage_blob_url_sas_token_scenario(self, resource_group, storage_accou
container = self.create_container(account_info)
source_file = self.create_temp_file(128, full_random=False)
blob = "blob 1"
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
self.storage_cmd('storage container exists -n {}', account_info, container) \
.assert_with_checks(JMESPathCheck('exists', True))
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_table_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_table_scenarios.py
index 2394624f9b7..26cc4426904 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_table_scenarios.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_table_scenarios.py
@@ -12,7 +12,7 @@ class StorageTableScenarioTests(StorageScenarioMixin, ScenarioTest):
@ResourceGroupPreparer()
@StorageAccountPreparer(sku='Standard_RAGRS')
def test_storage_table_main_scenario(self, resource_group, storage_account):
- from datetime import UTC, datetime, timedelta
+ import datetime as dt
account_info = self.get_account_info(resource_group, storage_account)
table_name = self.create_random_name('table', 24)
@@ -24,7 +24,7 @@ def test_storage_table_main_scenario(self, resource_group, storage_account):
self.assertIn(table_name, self.storage_cmd('storage table list --query "[].name"',
account_info).get_output_in_json())
- expiry = (datetime.now(UTC) + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%MZ')
sas = self.storage_cmd('storage table generate-sas -n {} --permissions r --expiry {}',
account_info, table_name, expiry).output
self.assertIn('sig=', sas)
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_validators.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_validators.py
index f293eb37700..94bf14ad8d3 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_validators.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_validators.py
@@ -83,10 +83,10 @@ def test_datetime_string_type(self):
get_datetime_type(True)(input)
def test_datetime_type(self):
- import datetime
+ import datetime as dt
input = "2017-01-01T12:30Z"
actual = get_datetime_type(False)(input)
- expected = datetime.datetime(2017, 1, 1, 12, 30, 0)
+ expected = dt.datetime(2017, 1, 1, 12, 30, 0)
self.assertEqual(actual, expected)
input = "2017-01-01 12:30"
diff --git a/src/azure-cli/azure/cli/command_modules/storage/util.py b/src/azure-cli/azure/cli/command_modules/storage/util.py
index 49fa2ef1976..a365bc68fa2 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/util.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/util.py
@@ -6,7 +6,7 @@
import os
from azure.cli.core.profiles import ResourceType
-from datetime import UTC, datetime
+import datetime as dt
def collect_blobs(blob_service, container, pattern=None):
@@ -103,13 +103,12 @@ def glob_files_remotely_track2(client, share_name, pattern, snapshot=None, is_sh
def create_short_lived_blob_sas_v2(cmd, account_name, container, blob, account_key=None, user_delegation_key=None):
- from datetime import timedelta
t_sas = cmd.get_models('_shared_access_signature#BlobSharedAccessSignature',
resource_type=ResourceType.DATA_STORAGE_BLOB)
t_blob_permissions = cmd.get_models('_models#BlobSasPermissions', resource_type=ResourceType.DATA_STORAGE_BLOB)
- expiry = (datetime.now(UTC) + timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
if account_key:
sas = t_sas(account_name, account_key=account_key)
elif user_delegation_key:
@@ -120,47 +119,42 @@ def create_short_lived_blob_sas_v2(cmd, account_name, container, blob, account_k
def create_short_lived_file_sas_v2(cmd, account_name, account_key, share, directory_name, file_name):
- from datetime import timedelta
t_sas = cmd.get_models('_shared_access_signature#FileSharedAccessSignature',
resource_type=ResourceType.DATA_STORAGE_FILESHARE)
t_file_permissions = cmd.get_models('_models#FileSasPermissions', resource_type=ResourceType.DATA_STORAGE_FILESHARE)
- expiry = (datetime.now(UTC) + timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
sas = t_sas(account_name, account_key)
return sas.generate_file(share, directory_name=directory_name, file_name=file_name,
permission=t_file_permissions(read=True), expiry=expiry, protocol='https')
def create_short_lived_container_sas_track2(cmd, account_name, account_key, container):
- from datetime import timedelta
t_generate_container_sas = cmd.get_models('_shared_access_signature#generate_container_sas',
resource_type=ResourceType.DATA_STORAGE_BLOB)
- expiry = (datetime.now(UTC) + timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
return t_generate_container_sas(account_name, container, account_key, permission='r', expiry=expiry,
protocol='https')
def create_short_lived_share_sas_track2(cmd, account_name, account_key, share):
- from datetime import timedelta
t_generate_share_sas = cmd.get_models('#generate_share_sas', resource_type=ResourceType.DATA_STORAGE_FILESHARE)
- expiry = (datetime.now(UTC) + timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
return t_generate_share_sas(account_name, share, account_key, permission='r', expiry=expiry,
protocol='https')
def create_short_lived_blob_service_sas_track2(cmd, account_name, account_key, resource_types, permission='r'):
- from datetime import timedelta
t_generate_blob_service_sas = cmd.get_models('#generate_account_sas', resource_type=ResourceType.DATA_STORAGE_BLOB)
- expiry = (datetime.now(UTC) + timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
return t_generate_blob_service_sas(account_name, account_key, resource_types, permission=permission, expiry=expiry)
def create_short_lived_file_service_sas_track2(cmd, account_name, account_key, resource_types, permission='r'):
- from datetime import timedelta
t_generate_file_service_sas = cmd.get_models('#generate_account_sas',
resource_type=ResourceType.DATA_STORAGE_FILESHARE)
- expiry = (datetime.now(UTC) + timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
+ expiry = (dt.datetime.now(dt.UTC) + dt.timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ')
return t_generate_file_service_sas(account_name, account_key, resource_types, permission=permission, expiry=expiry)
@@ -258,7 +252,7 @@ def get_datetime_from_string(dt_str):
'%Y-%m-%dT%HZ', '%Y-%m-%d']
for form in accepted_date_formats:
try:
- return datetime.strptime(dt_str, form)
+ return dt.datetime.strptime(dt_str, form)
except ValueError:
continue
raise ValueError("datetime string '{}' not valid. Valid example: 2000-12-31T12:59:59Z".format(dt_str))
From 41195c3770a285b6516fc7bc4fc8c8b51a1392d0 Mon Sep 17 00:00:00 2001
From: NostraDavid <55331731+NostraDavid@users.noreply.github.com>
Date: Wed, 14 Oct 2026 20:42:16 +0200
Subject: [PATCH 03/13] packaging: add Python 3.15 to supported versions and CI
---
.../messaging-cmdlet-gen.md | 4 +--
azure-pipelines-full-tests.yml | 34 +++++++++++++++++++
azure-pipelines.yml | 14 ++++++++
doc/command_guidelines.md | 2 +-
doc/extensions/authoring.md | 2 +-
doc/install_linux_prerequisites.md | 2 +-
scripts/ci/build.sh | 3 ++
src/azure-cli-core/pyproject.toml | 1 +
src/azure-cli-core/tox.ini | 2 +-
src/azure-cli-telemetry/pyproject.toml | 1 +
src/azure-cli-telemetry/tox.ini | 2 +-
src/azure-cli-testsdk/pyproject.toml | 1 +
src/azure-cli/pyproject.toml | 1 +
13 files changed, 62 insertions(+), 7 deletions(-)
diff --git a/.github/agents/Messaging-cmdlets-Generation/messaging-cmdlet-gen.md b/.github/agents/Messaging-cmdlets-Generation/messaging-cmdlet-gen.md
index 70ad53134e4..1eaeb218026 100644
--- a/.github/agents/Messaging-cmdlets-Generation/messaging-cmdlet-gen.md
+++ b/.github/agents/Messaging-cmdlets-Generation/messaging-cmdlet-gen.md
@@ -83,7 +83,7 @@ $VENV = "$SPEC_ROOT\.venv-aaz"
## 2. Environment
-**Python 3.11-3.14 required.** Verify with the explicit path, not `PATH`; do not install it yourself.
+**Python 3.11-3.15 required.** Verify with the explicit path, not `PATH`; do not install it yourself.
* Windows: `& "$env:LOCALAPPDATA\Programs\Python\Python312\python.exe" --version`
(installer from ; path form
`C:\Users\{xxxx}\AppData\Local\Programs\Python\Python3{xxxx}`)
@@ -734,7 +734,7 @@ Further reading: azure-cli `doc/` (extensions, command guidelines, authoring tes
- [ ] Plan echoed back and confirmed (service, `` -> ``, swagger path, branch, scope).
- [ ] **Section 4.1 pre-flight**: `az provider show` confirms whether ARM serves `` yet.
- [ ] **Section 4.2**: pre-existing aaz<->azure-cli drift isolated and listed before generating.
-- [ ] Python 3.11-3.14 venv active; `aaz-dev` + `azdev` installed.
+- [ ] Python 3.11-3.15 venv active; `aaz-dev` + `azdev` installed.
- [ ] Repos synced from upstream; `aaz` and `azure-cli` on identically named `feature-*` branches.
- [ ] `azdev setup --cli $CLI --repo $EXT` clean.
- [ ] `aaz-dev run` generation complete for the agreed scope.
diff --git a/azure-pipelines-full-tests.yml b/azure-pipelines-full-tests.yml
index 8015a713518..09d01703286 100644
--- a/azure-pipelines-full-tests.yml
+++ b/azure-pipelines-full-tests.yml
@@ -83,3 +83,37 @@ jobs:
instance_idx: '$(Instance_idx)'
fullTest: true
jobName: 'FullTest'
+
+- job: AutomationFullTestPython315ProfileLatest
+ displayName: Automation Full Test Python315 Profile Latest
+ timeoutInMinutes: 9999
+ strategy:
+ maxParallel: 8
+ matrix:
+ instance1:
+ Instance_idx: 1
+ instance2:
+ Instance_idx: 2
+ instance3:
+ Instance_idx: 3
+ instance4:
+ Instance_idx: 4
+ instance5:
+ Instance_idx: 5
+ instance6:
+ Instance_idx: 6
+ instance7:
+ Instance_idx: 7
+ instance8:
+ Instance_idx: 8
+ pool:
+ name: ${{ variables.ubuntu_pool }}
+ steps:
+ - template: .azure-pipelines/templates/automation_test.yml
+ parameters:
+ pythonVersion: '3.15'
+ profile: 'latest'
+ instance_cnt: '8'
+ instance_idx: '$(Instance_idx)'
+ fullTest: true
+ jobName: 'FullTest'
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 550a02fd604..a274b63b3cf 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -497,6 +497,8 @@ jobs:
python.version: '3.12'
Python314:
python.version: '3.14'
+ Python315:
+ python.version: '3.15'
dependsOn: BuildPythonWheel
condition: succeeded()
pool:
@@ -539,6 +541,8 @@ jobs:
python.version: '3.12'
Python314:
python.version: '3.14'
+ Python315:
+ python.version: '3.15'
steps:
- template: .azure-pipelines/templates/automation_test.yml
parameters:
@@ -556,6 +560,8 @@ jobs:
python.version: '3.11'
Python314:
python.version: '3.14'
+ Python315:
+ python.version: '3.15'
steps:
- task: UsePythonVersion@0
inputs:
@@ -578,6 +584,8 @@ jobs:
python.version: '3.12'
Python314:
python.version: '3.14'
+ Python315:
+ python.version: '3.15'
steps:
- template: .azure-pipelines/templates/automation_test.yml
parameters:
@@ -598,6 +606,8 @@ jobs:
python.version: '3.12'
Python314:
python.version: '3.14'
+ Python315:
+ python.version: '3.15'
steps:
- task: UsePythonVersion@0
displayName: 'Use Python $(python.version)'
@@ -619,6 +629,8 @@ jobs:
matrix:
Python314:
python.version: '3.14'
+ Python315:
+ python.version: '3.15'
steps:
- task: UsePythonVersion@0
displayName: 'Use Python $(python.version)'
@@ -1066,6 +1078,8 @@ jobs:
python.version: '3.12'
Python314:
python.version: '3.14'
+ Python315:
+ python.version: '3.15'
pool:
name: ${{ variables.ubuntu_pool }}
steps:
diff --git a/doc/command_guidelines.md b/doc/command_guidelines.md
index 3aa07544da6..fd85c90a856 100644
--- a/doc/command_guidelines.md
+++ b/doc/command_guidelines.md
@@ -426,7 +426,7 @@ Follow the [Error Handling Guidelines](https://github.com/Azure/azure-cli/blob/d
## Coding Practices
-- All code must support Python 3.11 ~ 3.14
+- All code must support Python 3.11 ~ 3.15
- PRs to Azure/azure-cli and Azure/azure-cli-extensions must pass CI
- Code must pass style checks with pylint and pep8
- (*) All commands should have tests
diff --git a/doc/extensions/authoring.md b/doc/extensions/authoring.md
index ec2805e7afd..7b1db6ae554 100644
--- a/doc/extensions/authoring.md
+++ b/doc/extensions/authoring.md
@@ -130,7 +130,7 @@ See [Extension Metadata](metadata.md) for more information.
### Test your extension on Python 3
-- The Azure CLI supports Python 3.11 ~ 3.14 so verify that your extension does the same.
+- The Azure CLI supports Python 3.11 ~ 3.15 so verify that your extension does the same.
- You can create virtual environments for different versions and run your extension in them.
- e.g. `python3.14 -m venv env314`.
diff --git a/doc/install_linux_prerequisites.md b/doc/install_linux_prerequisites.md
index 5503c9b8377..29b2b11fc79 100644
--- a/doc/install_linux_prerequisites.md
+++ b/doc/install_linux_prerequisites.md
@@ -6,7 +6,7 @@ Some native Linux packages are required when installing the CLI with:
- Interactive installation script
- `pip`
-Current supported Python versions are Python 3.11 ~ 3.14.
+Current supported Python versions are Python 3.11 ~ 3.15.
The commands to run to install the dependencies for some common distributions are listed below.
diff --git a/scripts/ci/build.sh b/scripts/ci/build.sh
index 6699b2dbce3..fed0de996bb 100755
--- a/scripts/ci/build.sh
+++ b/scripts/ci/build.sh
@@ -112,6 +112,9 @@ CLASSIFIERS = [
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
+ 'Programming Language :: Python :: 3.13',
+ 'Programming Language :: Python :: 3.14',
+ 'Programming Language :: Python :: 3.15',
'License :: OSI Approved :: MIT License',
]
diff --git a/src/azure-cli-core/pyproject.toml b/src/azure-cli-core/pyproject.toml
index b166313eb41..d96ba507beb 100644
--- a/src/azure-cli-core/pyproject.toml
+++ b/src/azure-cli-core/pyproject.toml
@@ -21,6 +21,7 @@ classifiers = [
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
+ "Programming Language :: Python :: 3.15",
]
dependencies = [
'argcomplete~=3.5.2',
diff --git a/src/azure-cli-core/tox.ini b/src/azure-cli-core/tox.ini
index 8c6aec2e1ce..2d693e48373 100644
--- a/src/azure-cli-core/tox.ini
+++ b/src/azure-cli-core/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py36,py37,py38
+envlist = py311,py312,py313,py314,py315
skip_missing_interpreters = True
[testenv]
diff --git a/src/azure-cli-telemetry/pyproject.toml b/src/azure-cli-telemetry/pyproject.toml
index 00f99b256ad..5903aca9814 100644
--- a/src/azure-cli-telemetry/pyproject.toml
+++ b/src/azure-cli-telemetry/pyproject.toml
@@ -21,6 +21,7 @@ classifiers = [
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
+ "Programming Language :: Python :: 3.15",
]
dependencies = [
'applicationinsights>=0.11.1,<0.12',
diff --git a/src/azure-cli-telemetry/tox.ini b/src/azure-cli-telemetry/tox.ini
index 29a621711ee..10bc42465d1 100644
--- a/src/azure-cli-telemetry/tox.ini
+++ b/src/azure-cli-telemetry/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py36,py37,py38
+envlist = py311,py312,py313,py314,py315
skip_missing_interpreters = True
[testenv]
diff --git a/src/azure-cli-testsdk/pyproject.toml b/src/azure-cli-testsdk/pyproject.toml
index d51b9cd4c57..09561b7ee23 100644
--- a/src/azure-cli-testsdk/pyproject.toml
+++ b/src/azure-cli-testsdk/pyproject.toml
@@ -20,6 +20,7 @@ classifiers = [
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
+ "Programming Language :: Python :: 3.15",
]
dependencies = [
'ConfigArgParse>=0.12.0',
diff --git a/src/azure-cli/pyproject.toml b/src/azure-cli/pyproject.toml
index 70a56f71444..7bef17d34e0 100644
--- a/src/azure-cli/pyproject.toml
+++ b/src/azure-cli/pyproject.toml
@@ -21,6 +21,7 @@ classifiers = [
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
+ "Programming Language :: Python :: 3.15",
]
dependencies = [
"antlr4-python3-runtime~=4.13.1",
From a6f53b6426dd75261af61e07ba7f5e830ba0b735 Mon Sep 17 00:00:00 2001
From: NostraDavid <55331731+NostraDavid@users.noreply.github.com>
Date: Wed, 14 Oct 2026 20:47:54 +0200
Subject: [PATCH 04/13] core: explain the existing survey note regression test
---
.../azure/cli/core/tests/test_intercept_survey.py | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/azure-cli-core/azure/cli/core/tests/test_intercept_survey.py b/src/azure-cli-core/azure/cli/core/tests/test_intercept_survey.py
index a684f32b205..b42b67d61ef 100644
--- a/src/azure-cli-core/azure/cli/core/tests/test_intercept_survey.py
+++ b/src/azure-cli-core/azure/cli/core/tests/test_intercept_survey.py
@@ -12,6 +12,14 @@
class TestInterceptSurvey(unittest.TestCase):
def test_should_prompt_with_existing_utc_note(self):
+ """Preserve scheduling for existing UTC notes stored without an offset.
+
+ Past dates allow a prompt; future dates suppress it. This regression
+ test also passes before the migration. Replacing utcnow() alone would
+ compare a naive saved date with aware now(UTC) and raise TypeError,
+ so the reader must attach UTC to the parsed date.
+ Only the decision is checked, not prompt rendering or note creation.
+ """
cli = mock.Mock()
cli.config.getboolean.return_value = True
for timestamp, expected in [('2000-01-01T00:00:00', True), ('2999-01-01T00:00:00', False)]:
From 0c8c43800ff8485fa8a94ed5cd17d3efd0560693 Mon Sep 17 00:00:00 2001
From: NostraDavid <55331731+NostraDavid@users.noreply.github.com>
Date: Wed, 14 Oct 2026 20:55:49 +0200
Subject: [PATCH 05/13] cosmosdb: keep restore test fixtures before test
methods
---
.../test_cosmosdb_backuprestore_scenario.py | 43 +++++++++----------
1 file changed, 21 insertions(+), 22 deletions(-)
diff --git a/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py b/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py
index 7045ff4aa66..f97a497e91e 100644
--- a/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py
+++ b/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py
@@ -530,27 +530,6 @@ def test_cosmosdb_xrr_single_region_account(self, resource_group):
class CosmosDBRestoreUnitTests(unittest.TestCase):
- def test_restore_timestamp_is_utc(self):
- from azure.cli.command_modules.cosmosdb.custom import _convert_to_utc_timestamp
-
- expected = dt.datetime(2020, 1, 1, tzinfo=dt.UTC)
- for timestamp in ['2020-01-01T00:00:00', '2020-01-01T00:00:00Z',
- '2020-01-01T02:00:00+02:00', '2019-12-31T19:00:00-05:00']:
- with self.subTest(timestamp=timestamp):
- self.assertEqual(_convert_to_utc_timestamp(timestamp), expected)
-
- @mock.patch('azure.cli.command_modules.cosmosdb.custom._create_database_account')
- @mock.patch('azure.cli.command_modules.cosmosdb._client_factory.cf_restorable_database_accounts')
- def test_restore_accepts_timestamp_without_offset(self, get_accounts, create_account):
- from azure.cli.command_modules.cosmosdb.custom import cli_cosmosdb_restore
-
- account = mock.Mock(account_name='source', deletion_time=None,
- creation_time=dt.datetime(2000, 1, 1, tzinfo=dt.UTC))
- get_accounts.return_value.list.return_value = [account]
- cli_cosmosdb_restore(mock.Mock(), mock.Mock(), 'rg', 'source', 'target',
- '2020-01-01T00:00:00', 'westus')
- self.assertEqual(create_account.call_args.kwargs['restore_timestamp'], '2020-01-01T00:00:00+00:00')
-
def setUp(self):
# Only mock dependencies that cannot actually be imported. Never replace a
# real, importable package in sys.modules: these unit tests share a
@@ -812,4 +791,24 @@ def test_normal_create_aligns_arm_location_with_priority_zero(self):
mock_params.assert_called_once()
kwargs = mock_params.call_args.kwargs
# Non-restore path: priority-0 location overrides arm_location.
- self.assertEqual(kwargs.get('location'), "westus2")
\ No newline at end of file
+ self.assertEqual(kwargs.get('location'), "westus2")
+ def test_restore_timestamp_is_utc(self):
+ from azure.cli.command_modules.cosmosdb.custom import _convert_to_utc_timestamp
+
+ expected = dt.datetime(2020, 1, 1, tzinfo=dt.UTC)
+ for timestamp in ['2020-01-01T00:00:00', '2020-01-01T00:00:00Z',
+ '2020-01-01T02:00:00+02:00', '2019-12-31T19:00:00-05:00']:
+ with self.subTest(timestamp=timestamp):
+ self.assertEqual(_convert_to_utc_timestamp(timestamp), expected)
+
+ @mock.patch('azure.cli.command_modules.cosmosdb.custom._create_database_account')
+ @mock.patch('azure.cli.command_modules.cosmosdb._client_factory.cf_restorable_database_accounts')
+ def test_restore_accepts_timestamp_without_offset(self, get_accounts, create_account):
+ from azure.cli.command_modules.cosmosdb.custom import cli_cosmosdb_restore
+
+ account = mock.Mock(account_name='source', deletion_time=None,
+ creation_time=dt.datetime(2000, 1, 1, tzinfo=dt.UTC))
+ get_accounts.return_value.list.return_value = [account]
+ cli_cosmosdb_restore(mock.Mock(), mock.Mock(), 'rg', 'source', 'target',
+ '2020-01-01T00:00:00', 'westus')
+ self.assertEqual(create_account.call_args.kwargs['restore_timestamp'], '2020-01-01T00:00:00+00:00')
From d55192f680883acde3bfef06be5b46e634edd0ac Mon Sep 17 00:00:00 2001
From: NostraDavid <55331731+NostraDavid@users.noreply.github.com>
Date: Wed, 14 Oct 2026 21:02:37 +0200
Subject: [PATCH 06/13] cosmosdb: separate restore test methods with a blank
line
---
.../tests/latest/test_cosmosdb_backuprestore_scenario.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py b/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py
index f97a497e91e..221acee8013 100644
--- a/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py
+++ b/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py
@@ -792,6 +792,7 @@ def test_normal_create_aligns_arm_location_with_priority_zero(self):
kwargs = mock_params.call_args.kwargs
# Non-restore path: priority-0 location overrides arm_location.
self.assertEqual(kwargs.get('location'), "westus2")
+
def test_restore_timestamp_is_utc(self):
from azure.cli.command_modules.cosmosdb.custom import _convert_to_utc_timestamp
From 2aef274b0e00f1925818d268d78462534ac4392f Mon Sep 17 00:00:00 2001
From: NostraDavid <55331731+NostraDavid@users.noreply.github.com>
Date: Wed, 14 Oct 2026 21:06:43 +0200
Subject: [PATCH 07/13] feedback: clarify the saved survey timestamp test name
---
.../cli/command_modules/feedback/tests/latest/test_feedback.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/azure-cli/azure/cli/command_modules/feedback/tests/latest/test_feedback.py b/src/azure-cli/azure/cli/command_modules/feedback/tests/latest/test_feedback.py
index c4e7d66f365..71a19fd5e6a 100644
--- a/src/azure-cli/azure/cli/command_modules/feedback/tests/latest/test_feedback.py
+++ b/src/azure-cli/azure/cli/command_modules/feedback/tests/latest/test_feedback.py
@@ -208,7 +208,7 @@ def _handle_exception_with_log(ex, *args, **kwargs):
class TestSurvey(unittest.TestCase):
- def test_existing_utc_note(self):
+ def test_handle_survey_accepts_saved_timestamp_without_offset(self):
from azure.cli.command_modules.feedback import custom
note = '{"last_prompt_time": "2000-01-01T00:00:00"}'
From 55cccb49c68ce7b75296f58d8c31d0678295fe57 Mon Sep 17 00:00:00 2001
From: NostraDavid <55331731+NostraDavid@users.noreply.github.com>
Date: Wed, 14 Oct 2026 21:10:59 +0200
Subject: [PATCH 08/13] lab: keep the parsed expiration date separate
---
src/azure-cli/azure/cli/command_modules/lab/validators.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/azure-cli/azure/cli/command_modules/lab/validators.py b/src/azure-cli/azure/cli/command_modules/lab/validators.py
index c376c7acb56..733667f9f78 100644
--- a/src/azure-cli/azure/cli/command_modules/lab/validators.py
+++ b/src/azure-cli/azure/cli/command_modules/lab/validators.py
@@ -115,8 +115,8 @@ def _validate_expiration_date(args):
if has_value(args.expiration_date):
import datetime as dt
import dateutil.parser
- expiration_date = dateutil.parser.parse(args.expiration_date.to_serialized_data())
- expiration_date = expiration_date.replace(tzinfo=expiration_date.tzinfo or dt.UTC)
+ parsed_expiration_date = dateutil.parser.parse(args.expiration_date.to_serialized_data())
+ expiration_date = parsed_expiration_date.replace(tzinfo=parsed_expiration_date.tzinfo or dt.UTC)
if dt.datetime.now(dt.UTC) >= expiration_date:
raise ArgumentUsageError(
"Expiration date '{}' must be in future.".format(args.expiration_date.to_serialized_data()))
From 7d320ccf07158c6f76cf9d9314ca36e9f5f57922 Mon Sep 17 00:00:00 2001
From: NostraDavid <55331731+NostraDavid@users.noreply.github.com>
Date: Wed, 14 Oct 2026 21:26:42 +0200
Subject: [PATCH 09/13] pipeline: run the full suite on Python 3.11
---
azure-pipelines-full-tests.yml | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/azure-pipelines-full-tests.yml b/azure-pipelines-full-tests.yml
index 09d01703286..51383644be2 100644
--- a/azure-pipelines-full-tests.yml
+++ b/azure-pipelines-full-tests.yml
@@ -16,6 +16,40 @@ variables:
- template: ${{ variables.Pipeline.Workspace }}/.azure-pipelines/templates/variables.yml
jobs:
+- job: AutomationFullTestPython311ProfileLatest
+ displayName: Automation Full Test Python311 Profile Latest
+ timeoutInMinutes: 9999
+ strategy:
+ maxParallel: 8
+ matrix:
+ instance1:
+ Instance_idx: 1
+ instance2:
+ Instance_idx: 2
+ instance3:
+ Instance_idx: 3
+ instance4:
+ Instance_idx: 4
+ instance5:
+ Instance_idx: 5
+ instance6:
+ Instance_idx: 6
+ instance7:
+ Instance_idx: 7
+ instance8:
+ Instance_idx: 8
+ pool:
+ name: ${{ variables.ubuntu_pool }}
+ steps:
+ - template: .azure-pipelines/templates/automation_test.yml
+ parameters:
+ pythonVersion: '3.11'
+ profile: 'latest'
+ instance_cnt: '8'
+ instance_idx: '$(Instance_idx)'
+ fullTest: true
+ jobName: 'FullTest'
+
- job: AutomationFullTestPython312ProfileLatest
displayName: Automation Full Test Python312 Profile Latest
timeoutInMinutes: 9999
From b6f52e993ca9f79903e8aea7ebb4f2e32496618b Mon Sep 17 00:00:00 2001
From: NostraDavid <55331731+NostraDavid@users.noreply.github.com>
Date: Wed, 14 Oct 2026 21:35:48 +0200
Subject: [PATCH 10/13] pipeline: balance Python version coverage by test cost
---
azure-pipelines.yml | 26 ++++++++++++++++----------
1 file changed, 16 insertions(+), 10 deletions(-)
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index a274b63b3cf..c620cc53be6 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -495,6 +495,8 @@ jobs:
python.version: '3.11'
Python312:
python.version: '3.12'
+ Python313:
+ python.version: '3.13'
Python314:
python.version: '3.14'
Python315:
@@ -539,6 +541,8 @@ jobs:
python.version: '3.11'
Python312:
python.version: '3.12'
+ Python313:
+ python.version: '3.13'
Python314:
python.version: '3.14'
Python315:
@@ -558,6 +562,10 @@ jobs:
matrix:
Python311:
python.version: '3.11'
+ Python312:
+ python.version: '3.12'
+ Python313:
+ python.version: '3.13'
Python314:
python.version: '3.14'
Python315:
@@ -580,8 +588,12 @@ jobs:
name: ${{ variables.ubuntu_pool }}
strategy:
matrix:
+ Python311:
+ python.version: '3.11'
Python312:
python.version: '3.12'
+ Python313:
+ python.version: '3.13'
Python314:
python.version: '3.14'
Python315:
@@ -602,10 +614,8 @@ jobs:
name: ${{ variables.ubuntu_pool }}
strategy:
matrix:
- Python312:
- python.version: '3.12'
- Python314:
- python.version: '3.14'
+ Python311:
+ python.version: '3.11'
Python315:
python.version: '3.15'
steps:
@@ -627,8 +637,8 @@ jobs:
name: ${{ variables.ubuntu_pool }}
strategy:
matrix:
- Python314:
- python.version: '3.14'
+ Python311:
+ python.version: '3.11'
Python315:
python.version: '3.15'
steps:
@@ -1074,12 +1084,8 @@ jobs:
displayName: "PerformanceCheck"
strategy:
matrix:
- Python312:
- python.version: '3.12'
Python314:
python.version: '3.14'
- Python315:
- python.version: '3.15'
pool:
name: ${{ variables.ubuntu_pool }}
steps:
From 978013b81bcae5477f905d7eac2df29a35a09788 Mon Sep 17 00:00:00 2001
From: NostraDavid <55331731+NostraDavid@users.noreply.github.com>
Date: Wed, 14 Oct 2026 21:39:13 +0200
Subject: [PATCH 11/13] pipeline: shift compatibility checks to Python 3.11 and
3.15
---
azure-pipelines-full-tests.yml | 68 ----------------------------------
azure-pipelines.yml | 26 -------------
2 files changed, 94 deletions(-)
diff --git a/azure-pipelines-full-tests.yml b/azure-pipelines-full-tests.yml
index 51383644be2..9c1a841edef 100644
--- a/azure-pipelines-full-tests.yml
+++ b/azure-pipelines-full-tests.yml
@@ -50,74 +50,6 @@ jobs:
fullTest: true
jobName: 'FullTest'
-- job: AutomationFullTestPython312ProfileLatest
- displayName: Automation Full Test Python312 Profile Latest
- timeoutInMinutes: 9999
- strategy:
- maxParallel: 8
- matrix:
- instance1:
- Instance_idx: 1
- instance2:
- Instance_idx: 2
- instance3:
- Instance_idx: 3
- instance4:
- Instance_idx: 4
- instance5:
- Instance_idx: 5
- instance6:
- Instance_idx: 6
- instance7:
- Instance_idx: 7
- instance8:
- Instance_idx: 8
- pool:
- name: ${{ variables.ubuntu_pool }}
- steps:
- - template: .azure-pipelines/templates/automation_test.yml
- parameters:
- pythonVersion: '3.12'
- profile: 'latest'
- instance_cnt: '8'
- instance_idx: '$(Instance_idx)'
- fullTest: true
- jobName: 'FullTest'
-
-- job: AutomationFullTestPython314ProfileLatest
- displayName: Automation Full Test Python314 Profile Latest
- timeoutInMinutes: 9999
- strategy:
- maxParallel: 8
- matrix:
- instance1:
- Instance_idx: 1
- instance2:
- Instance_idx: 2
- instance3:
- Instance_idx: 3
- instance4:
- Instance_idx: 4
- instance5:
- Instance_idx: 5
- instance6:
- Instance_idx: 6
- instance7:
- Instance_idx: 7
- instance8:
- Instance_idx: 8
- pool:
- name: ${{ variables.ubuntu_pool }}
- steps:
- - template: .azure-pipelines/templates/automation_test.yml
- parameters:
- pythonVersion: '3.14'
- profile: 'latest'
- instance_cnt: '8'
- instance_idx: '$(Instance_idx)'
- fullTest: true
- jobName: 'FullTest'
-
- job: AutomationFullTestPython315ProfileLatest
displayName: Automation Full Test Python315 Profile Latest
timeoutInMinutes: 9999
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index c620cc53be6..a59d845be0c 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -493,12 +493,6 @@ jobs:
matrix:
Python311:
python.version: '3.11'
- Python312:
- python.version: '3.12'
- Python313:
- python.version: '3.13'
- Python314:
- python.version: '3.14'
Python315:
python.version: '3.15'
dependsOn: BuildPythonWheel
@@ -539,12 +533,6 @@ jobs:
matrix:
Python311:
python.version: '3.11'
- Python312:
- python.version: '3.12'
- Python313:
- python.version: '3.13'
- Python314:
- python.version: '3.14'
Python315:
python.version: '3.15'
steps:
@@ -562,12 +550,6 @@ jobs:
matrix:
Python311:
python.version: '3.11'
- Python312:
- python.version: '3.12'
- Python313:
- python.version: '3.13'
- Python314:
- python.version: '3.14'
Python315:
python.version: '3.15'
steps:
@@ -590,12 +572,6 @@ jobs:
matrix:
Python311:
python.version: '3.11'
- Python312:
- python.version: '3.12'
- Python313:
- python.version: '3.13'
- Python314:
- python.version: '3.14'
Python315:
python.version: '3.15'
steps:
@@ -637,8 +613,6 @@ jobs:
name: ${{ variables.ubuntu_pool }}
strategy:
matrix:
- Python311:
- python.version: '3.11'
Python315:
python.version: '3.15'
steps:
From e0dd5746812a19e779d4812e9ac4a92082b18754 Mon Sep 17 00:00:00 2001
From: NostraDavid <55331731+NostraDavid@users.noreply.github.com>
Date: Wed, 14 Oct 2026 22:15:35 +0200
Subject: [PATCH 12/13] datetime: cover UTC boundaries and test performance on
Python 3.11 and 3.15
---
azure-pipelines.yml | 6 ++++--
.../tests/latest/test_acr_commands_mock.py | 8 ++++++++
.../test_cosmosdb_backuprestore_scenario.py | 4 +++-
.../lab/tests/latest/test_lab_validators.py | 19 +++++++++++++++++++
.../role/tests/latest/test_role_custom.py | 12 ++++++++++++
.../tests/latest/test_storage_validators.py | 15 +++++++++++++++
6 files changed, 61 insertions(+), 3 deletions(-)
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index a59d845be0c..31edd1e0e7c 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -1058,8 +1058,10 @@ jobs:
displayName: "PerformanceCheck"
strategy:
matrix:
- Python314:
- python.version: '3.14'
+ Python311:
+ python.version: '3.11'
+ Python315:
+ python.version: '3.15'
pool:
name: ${{ variables.ubuntu_pool }}
steps:
diff --git a/src/azure-cli/azure/cli/command_modules/acr/tests/latest/test_acr_commands_mock.py b/src/azure-cli/azure/cli/command_modules/acr/tests/latest/test_acr_commands_mock.py
index 95c8e3c34db..54cd7bfcd97 100644
--- a/src/azure-cli/azure/cli/command_modules/acr/tests/latest/test_acr_commands_mock.py
+++ b/src/azure-cli/azure/cli/command_modules/acr/tests/latest/test_acr_commands_mock.py
@@ -4,6 +4,7 @@
# --------------------------------------------------------------------------------------------
from urllib.parse import urlencode
+import datetime as dt
import json
import unittest
from unittest import mock
@@ -64,6 +65,13 @@
class AcrMockCommandsTests(unittest.TestCase):
+ def test_add_days_to_now_returns_utc_max_on_overflow(self):
+ from azure.cli.command_modules.acr._utils import add_days_to_now
+
+ result = add_days_to_now(999999999)
+ self.assertEqual(result, dt.datetime.max.replace(tzinfo=dt.UTC))
+ self.assertIs(result.tzinfo, dt.UTC)
+
@mock.patch('azure.cli.command_modules.acr.repository.get_access_credentials', autospec=True)
@mock.patch('requests.request', autospec=True)
def test_repository_list(self, mock_requests_get, mock_get_access_credentials):
diff --git a/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py b/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py
index 221acee8013..81dad3b27d6 100644
--- a/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py
+++ b/src/azure-cli/azure/cli/command_modules/cosmosdb/tests/latest/test_cosmosdb_backuprestore_scenario.py
@@ -800,7 +800,9 @@ def test_restore_timestamp_is_utc(self):
for timestamp in ['2020-01-01T00:00:00', '2020-01-01T00:00:00Z',
'2020-01-01T02:00:00+02:00', '2019-12-31T19:00:00-05:00']:
with self.subTest(timestamp=timestamp):
- self.assertEqual(_convert_to_utc_timestamp(timestamp), expected)
+ result = _convert_to_utc_timestamp(timestamp)
+ self.assertEqual(result, expected)
+ self.assertEqual(result.utcoffset(), dt.timedelta(0))
@mock.patch('azure.cli.command_modules.cosmosdb.custom._create_database_account')
@mock.patch('azure.cli.command_modules.cosmosdb._client_factory.cf_restorable_database_accounts')
diff --git a/src/azure-cli/azure/cli/command_modules/lab/tests/latest/test_lab_validators.py b/src/azure-cli/azure/cli/command_modules/lab/tests/latest/test_lab_validators.py
index 343c1524787..4cf3fdf464a 100644
--- a/src/azure-cli/azure/cli/command_modules/lab/tests/latest/test_lab_validators.py
+++ b/src/azure-cli/azure/cli/command_modules/lab/tests/latest/test_lab_validators.py
@@ -3,6 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
+import datetime as dt
import unittest
from unittest import mock
from azure.mgmt.core.tools import is_valid_resource_id
@@ -76,3 +77,21 @@ def test_expiration_date_with_and_without_timezone(self):
args.expiration_date.to_serialized_data.return_value = '2000-01-01T00:00:00' + suffix
with self.assertRaises(ArgumentUsageError):
_validate_expiration_date(args)
+
+ def test_expiration_date_respects_offsets_near_current_time(self):
+ now = dt.datetime(2026, 10, 14, 12, tzinfo=dt.UTC)
+ cases = [('2026-10-14T11:30:00-01:00', False),
+ ('2026-10-14T13:30:00+02:00', True),
+ ('2026-10-14T12:30:00', False),
+ ('2026-10-14T12:00:00', True)]
+ with mock.patch('datetime.datetime', wraps=dt.datetime) as mock_datetime:
+ mock_datetime.now.return_value = now
+ for timestamp, expired in cases:
+ with self.subTest(timestamp=timestamp):
+ args = mock.Mock()
+ args.expiration_date.to_serialized_data.return_value = timestamp
+ if expired:
+ with self.assertRaises(ArgumentUsageError):
+ _validate_expiration_date(args)
+ else:
+ _validate_expiration_date(args)
diff --git a/src/azure-cli/azure/cli/command_modules/role/tests/latest/test_role_custom.py b/src/azure-cli/azure/cli/command_modules/role/tests/latest/test_role_custom.py
index f89ec64703a..550abc919cc 100644
--- a/src/azure-cli/azure/cli/command_modules/role/tests/latest/test_role_custom.py
+++ b/src/azure-cli/azure/cli/command_modules/role/tests/latest/test_role_custom.py
@@ -35,3 +35,15 @@ def test_assignment_events_with_start_time_and_default_end_time(self, get_client
_get_assignment_events(mock.Mock(), start_time='2000-01-01T00:00:00Z')
event_filter = get_client.return_value.activity_logs.list.call_args.kwargs['filter']
self.assertIn('eventTimestamp ge 2000-01-01T00:00:00Z', event_filter)
+
+ @mock.patch('azure.cli.core.commands.client_factory.get_mgmt_service_client')
+ def test_assignment_events_with_explicit_end_time(self, get_client):
+ from azure.cli.command_modules.role.custom import _get_assignment_events
+
+ get_client.return_value.activity_logs.list.return_value = []
+ for start_time in [None, '2000-01-01T00:00:00Z']:
+ with self.subTest(start_time=start_time):
+ _get_assignment_events(mock.Mock(), start_time=start_time, end_time='2000-01-01T01:00:00Z')
+ event_filter = get_client.return_value.activity_logs.list.call_args.kwargs['filter']
+ self.assertIn('eventTimestamp ge 2000-01-01T00:00:00Z and '
+ 'eventTimestamp le 2000-01-01T01:00:00Z', event_filter)
diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_validators.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_validators.py
index 94bf14ad8d3..955b605353b 100644
--- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_validators.py
+++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_validators.py
@@ -3,6 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
+import datetime as dt
import unittest
from unittest import mock
from argparse import (Namespace, ArgumentError)
@@ -447,6 +448,20 @@ def test_as_user_validator_rejects_expiry_beyond_seven_days(self):
with self.assertRaisesRegex(ArgumentError, 'within 7 days'):
as_user_validator(ns)
+ def test_as_user_validator_enforces_exact_seven_day_limit(self):
+ now = dt.datetime(2026, 10, 14, 12, tzinfo=dt.UTC)
+ with mock.patch('datetime.datetime', wraps=dt.datetime) as mock_datetime:
+ mock_datetime.now.return_value = now
+ for seconds in [-1, 0, 1]:
+ with self.subTest(seconds=seconds):
+ expiry = (now + dt.timedelta(days=7, seconds=seconds)).strftime('%Y-%m-%dT%H:%M:%SZ')
+ ns = self._create_namespace(as_user=True, expiry=expiry, token_credential='token')
+ if seconds > 0:
+ with self.assertRaisesRegex(ArgumentError, 'within 7 days'):
+ as_user_validator(ns)
+ else:
+ as_user_validator(ns)
+
def _create_namespace(self, **kwargs):
ns = Namespace(account_key='my_storage_key', account_name='storage_name', connection_string=None, dryrun=False,
pattern='*', sas_token=None, source_account_key=None, source_account_name=None,
From 4a666e51b60f87c3c80c3c1b9c8b2f3ea272dc69 Mon Sep 17 00:00:00 2001
From: NostraDavid <55331731+NostraDavid@users.noreply.github.com>
Date: Wed, 14 Oct 2026 22:53:32 +0200
Subject: [PATCH 13/13] feedback: wrap UTC survey timestamp parsing for pylint
---
src/azure-cli/azure/cli/command_modules/feedback/custom.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/azure-cli/azure/cli/command_modules/feedback/custom.py b/src/azure-cli/azure/cli/command_modules/feedback/custom.py
index 09496388db9..32f1910cd02 100644
--- a/src/azure-cli/azure/cli/command_modules/feedback/custom.py
+++ b/src/azure-cli/azure/cli/command_modules/feedback/custom.py
@@ -605,7 +605,8 @@ def handle_survey(cmd):
with open(GLOBAL_SURVEY_NOTE_PATH, 'r') as f:
survey_note = json.load(f)
if survey_note['last_prompt_time']:
- last_prompt_time = dt.datetime.strptime(survey_note['last_prompt_time'], '%Y-%m-%dT%H:%M:%S').replace(tzinfo=dt.UTC)
+ last_prompt_time = dt.datetime.strptime(
+ survey_note['last_prompt_time'], '%Y-%m-%dT%H:%M:%S').replace(tzinfo=dt.UTC)
use_duration = dt.datetime.now(dt.UTC) - last_prompt_time
url = _SURVEY_URL.format(installation_id=Profile(cli_ctx=cmd.cli_ctx).get_installation_id(),