Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MAINT: Datetime deprecations #1330

Merged
merged 14 commits into from
Sep 10, 2023
9 changes: 7 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
fail-fast: false
matrix:
os: ["ubuntu-latest"]
python-version: ["3.7", "3.10", "pypy-3.8", "pypy-3.9"]
python-version: ["3.7", "3.10", "3.12.0-rc.2", "pypy-3.8", "pypy-3.9"]
r-version: ['release']
timeout-minutes: 30
steps:
Expand Down Expand Up @@ -44,9 +44,14 @@ jobs:
with:
r-version: ${{ matrix.r-version }}

- name: Install dependencies
- name: Install dependencies (standard)
if: matrix.python-version != '3.12.0-rc.2'
run: python -m pip install ".[test,hg]"

- name: Install dependencies (with --pre)
if: matrix.python-version == '3.12.0-rc.2'
run: python -m pip install ".[test,hg]" --pre

- name: Install asv
run: pip install .

Expand Down
16 changes: 16 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
0.6.1 (TBD)
-----------

New Features
^^^^^^^^^^^^

API Changes
^^^^^^^^^^^

Bug Fixes
^^^^^^^^^

Other Changes and Additions
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- ``asv`` timestamps via ``datetime`` are now Python 3.12 compatible (#1331)

0.6.0 (2023-08-20)
------------------

Expand Down
2 changes: 1 addition & 1 deletion asv/benchmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ def iter_unique(iter):
try:
with open(result_file, 'r') as fp:
benchmarks = json.load(fp)
except (IOError, ValueError):
except (OSError, ValueError):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these should be split into two at some point. The errors are very different, one is that the expected file cannot be found, the other is something else (what?) that fails during discovery.

log.error("Invalid discovery output")
raise util.UserError()

Expand Down
4 changes: 3 additions & 1 deletion asv/commands/publish.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,5 +282,7 @@ def copy_ignore(src, names):

util.write_json(os.path.join(conf.html_dir, "info.json"), {
'asv-version': __version__,
'timestamp': util.datetime_to_js_timestamp(datetime.datetime.utcnow())
'timestamp': util.datetime_to_js_timestamp(
datetime.datetime.now(datetime.timezone.utc)
)
})
2 changes: 1 addition & 1 deletion asv/commands/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ def run(cls, conf, range_spec=None, steps=None, date_period=None,
skipped_benchmarks[(commit_hash, result.env_name)].add(key)
if skip_successful and not failed:
skipped_benchmarks[(commit_hash, result.env_name)].add(key)
except IOError:
except OSError:
pass

if interleave_rounds:
Expand Down
10 changes: 5 additions & 5 deletions asv/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@ def check_presence(self):

try:
info = self.load_info_file(self._path)
except (util.UserError, IOError):
except (util.UserError, OSError):
return False

expected_info = {
Expand All @@ -701,7 +701,7 @@ def check_presence(self):
for executable in ['pip', 'python']:
try:
self.find_executable(executable)
except IOError:
except OSError:
return False

try:
Expand Down Expand Up @@ -945,7 +945,7 @@ def find_executable(self, executable):
"""
Find an executable (eg. python, pip) in the environment.

If not found, raises IOError
If not found, raises OSError
"""

# Assume standard virtualenv/Conda layout
Expand Down Expand Up @@ -1036,7 +1036,7 @@ def __init__(self, conf, executable, requirements, tagged_env_vars):
'import sys; '
'print(str(sys.version_info[0]) + "." + str(sys.version_info[1]))'
]).strip()
except (util.ProcessError, OSError, IOError):
except (util.ProcessError, OSError):
raise EnvironmentUnavailable()

self._executable = executable
Expand All @@ -1059,7 +1059,7 @@ def matches(cls, python):

try:
util.which(python)
except IOError:
except OSError:
return False
else:
return True
Expand Down
7 changes: 5 additions & 2 deletions asv/feed.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def write_atom(dest, entries, author, title, address, updated=None, link=None,
if entries:
updated = max(entry.updated for entry in entries)
else:
updated = datetime.datetime.utcnow()
updated = datetime.datetime.now(datetime.timezone.utc)

root = etree.Element(ATOM_NS + 'feed')

Expand Down Expand Up @@ -185,5 +185,8 @@ def _get_id(owner, date, content):
h.update(",".encode('utf-8'))

if date is None:
date = datetime.datetime(1970, 1, 1)
date = datetime.datetime(
1970, 1, 1,
tzinfo = datetime.timezone.utc
)
return f"tag:{owner},{date.strftime('%Y-%m-%d')}:/{h.hexdigest()}"
4 changes: 2 additions & 2 deletions asv/plugins/conda.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def _find_conda():

Raises
------
IOError
OSError
If the executable cannot be found in either the CONDA_EXE environment
variable or in the PATH.

Expand Down Expand Up @@ -203,7 +203,7 @@ def _run_conda(self, args, env=None):
"""
try:
conda = _find_conda()
except IOError as e:
except OSError as e:
raise util.UserError(str(e))

with _conda_lock():
Expand Down
2 changes: 1 addition & 1 deletion asv/plugins/virtualenv.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def _find_python(python):
# Find Python executable on path
try:
return util.which(executable)
except IOError:
except OSError:
pass

# Maybe the current one is correct?
Expand Down
2 changes: 1 addition & 1 deletion asv/repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ def checkout(self, path, commit_hash):

def get_date(self, hash):
if hash is None:
return datetime.datetime.now()
return datetime.datetime.now(datetime.timezone.utc)
self._raise_error()

def get_hashes_from_range(self, range):
Expand Down
4 changes: 2 additions & 2 deletions asv/results.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def iter_results_paths(results):
raise util.UserError(f"malformed {machine_json}")
except util.UserError as err:
machine_json_err = f"Skipping results: {err}"
except IOError:
except OSError:
machine_json_err = f"Skipping results: could not load {machine_json}"
else:
machine_json_err = None
Expand Down Expand Up @@ -468,7 +468,7 @@ def add_result(self, benchmark, result,
benchmark_version = benchmark['version']

if started_at is None:
started_at = datetime.datetime.utcnow()
started_at = datetime.datetime.now(datetime.timezone.utc)

new_stats = [None] * len(new_result)

Expand Down
14 changes: 8 additions & 6 deletions asv/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def skip_benchmarks(benchmarks, env, results=None):
log.step()
log.warning(f'{name} skipped')

started_at = datetime.datetime.utcnow()
started_at = datetime.datetime.now(datetime.timezone.utc)
r = fail_benchmark(benchmark)
results.add_result(benchmark, r,
selected_idx=benchmarks.benchmark_selection.get(name),
Expand Down Expand Up @@ -260,7 +260,7 @@ def iter_run_items():
continue

selected_idx = benchmarks.benchmark_selection.get(name)
started_at = datetime.datetime.utcnow()
started_at = datetime.datetime.now(datetime.timezone.utc)
res = fail_benchmark(benchmark, stderr=stderr)
results.add_result(benchmark, res,
selected_idx=selected_idx,
Expand All @@ -273,7 +273,7 @@ def iter_run_items():
for name, benchmark, setup_cache_key, is_final in iter_run_items():
selected_idx = benchmarks.benchmark_selection.get(name)

started_at = datetime.datetime.utcnow()
started_at = datetime.datetime.now(datetime.timezone.utc)

# Don't try to rerun failed benchmarks
if name in failed_benchmarks:
Expand Down Expand Up @@ -305,9 +305,11 @@ def iter_run_items():
log.error(stderr)
failed_setup_cache[setup_cache_key] = stderr

duration = (datetime.datetime.utcnow() - started_at).total_seconds()
duration = (datetime.datetime.now(
datetime.timezone.utc
) - started_at).total_seconds()
results.set_setup_cache_duration(setup_cache_key, duration)
started_at = datetime.datetime.utcnow()
started_at = datetime.datetime.now(datetime.timezone.utc)

if setup_cache_key in failed_setup_cache:
# Mark benchmark as failed
Expand Down Expand Up @@ -351,7 +353,7 @@ def iter_run_items():
cwd=cache_dir)

# Retain runtime durations
ended_at = datetime.datetime.utcnow()
ended_at = datetime.datetime.now(datetime.timezone.utc)
if name in benchmark_durations:
benchmark_durations[name] += (ended_at - started_at).total_seconds()
else:
Expand Down
13 changes: 8 additions & 5 deletions asv/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,10 @@ def which(filename, paths=None):
"""
Emulates the UNIX `which` command in Python.

Raises an IOError if no result is found.
Raises an OSError if no result is found.
"""
# Hide traceback from expected exceptions in pytest reports
__tracebackhide__ = operator.methodcaller('errisinstance', IOError)
__tracebackhide__ = operator.methodcaller('errisinstance', OSError)

if os.path.sep in filename:
locations = ['']
Expand Down Expand Up @@ -228,7 +228,7 @@ def which(filename, paths=None):
loc_info = 'PATH'
else:
loc_info = os.pathsep.join(locations)
raise IOError(f"Could not find '{filename}' in {loc_info}")
raise OSError(f"Could not find '{filename}' in {loc_info}")

return candidates[0]

Expand All @@ -239,7 +239,7 @@ def has_command(filename):
"""
try:
which(filename)
except IOError:
except OSError:
return False
else:
return True
Expand Down Expand Up @@ -944,7 +944,10 @@ def format_text_table(rows, num_headers=0,


def _datetime_to_timestamp(dt, divisor):
delta = dt - datetime.datetime(1970, 1, 1)
delta = dt - datetime.datetime(
1970, 1, 1,
tzinfo = datetime.timezone.utc
)
microseconds = (delta.days * 86400 + delta.seconds) * 10**6 + delta.microseconds
value, remainder = divmod(microseconds, divisor)
if remainder >= divisor // 2:
Expand Down
12 changes: 8 additions & 4 deletions docs/source/writing_benchmarks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -298,13 +298,15 @@ decorator ``@skip_for_params`` as::
for i in f(n):
pass

Benchmarks may aslo be condtionally skipped based on a boolean with ``@skip_benchmark_if``::
Benchmarks may also be conditionally skipped based on a boolean with ``@skip_benchmark_if``::

from asv_runner.benchmarks.mark import skip_benchmark_if
import datetime

# Skip if not before midday
@skip_benchmark_if(datetime.datetime.now().hour >= 12)
@skip_benchmark_if(
datetime.datetime.now(datetime.timezone.utc).hour >= 12
)
def time_ranges(n, func_name):
f = {'range': range, 'arange': np.arange}[func_name]
for i in f(n):
Expand All @@ -327,8 +329,10 @@ Similarly, for parameters we have ``@skip_params_if``::

# Skip benchmarking when size is either 100 or 200
# and the current hour is 12 or later.
@skip_params_if([(100,), (200,)],
datetime.datetime.now().hour >= 12)
@skip_params_if(
[(100,), (200,)],
datetime.datetime.now(datetime.timezone.utc).hour >= 12
)
def time_dict_update(self, size):
d = self.d
for i in range(size):
Expand Down
18 changes: 17 additions & 1 deletion test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ def pytest_addoption(parser):
"FirefoxHeadless. Alternatively, it can be arbitrary Python code "
"with a return statement with selenium.webdriver object, for "
"example 'return Chrome()'"))

parser.addoption(
"--runflaky", action="store_true", default=False, help="run flaky tests"
)
parser.addoption("--environment-type", action="store", default=None,
choices=("conda", "virtualenv", "mamba"),
help="environment_type to use in tests by default")
Expand Down Expand Up @@ -419,3 +421,17 @@ def restore():

assert isinstance(step_detect.get_mu_dist([0], [1]), L1Dist)
return False

def pytest_configure(config):
config.addinivalue_line("markers",
"flaky_pypy: Tests that are flaky on pypy.")


def pytest_collection_modifyitems(config, items):
if config.getoption("--runflaky"):
# --runflaky given in cli: do not skip flaky tests
return
skip_flaky = pytest.mark.skip(reason="need --runflaky option to run")
for item in items:
if "flaky" in item.keywords:
item.add_marker(skip_flaky)
Loading