Skip to content

Add runtime environment detection utilities#4

Merged
AndrewSazonov merged 21 commits intodevelopfrom
templates
Feb 25, 2026
Merged

Add runtime environment detection utilities#4
AndrewSazonov merged 21 commits intodevelopfrom
templates

Conversation

@AndrewSazonov
Copy link
Member

No description provided.

@AndrewSazonov AndrewSazonov added the [scope] enhancement Adds/improves features (major.MINOR.patch) label Feb 25, 2026
@codecov
Copy link

codecov bot commented Feb 25, 2026

Codecov Report

❌ Patch coverage is 78.12500% with 14 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (develop@bffa953). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/easyutilities/environment.py 78.12% 12 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             develop       #4   +/-   ##
==========================================
  Coverage           ?   78.12%           
==========================================
  Files              ?        1           
  Lines              ?       64           
  Branches           ?        7           
==========================================
  Hits               ?       50           
  Misses             ?       12           
  Partials           ?        2           
Flag Coverage Δ
integration 0.00% <0.00%> (?)
unittests 78.12% <78.12%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a new easyutilities.environment module that provides runtime environment detection utilities. The module enables detection of testing frameworks, terminals, IDEs, notebook environments, and CI systems, along with helpers for IPython/Jupyter display handling. The PR also includes workflow improvements, label updates, and configuration changes.

Changes:

  • Added new environment.py module with comprehensive environment detection functions
  • Added extensive test coverage with 291 lines of unit tests
  • Updated GitHub labels (renamed [bot] pull request to [bot] release, added [bot] backmerge)
  • Enhanced backmerge workflow with conflict detection and issue creation
  • Enabled additional Ruff linting rules in pyproject.toml

Reviewed changes

Copilot reviewed 26 out of 27 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/easyutilities/environment.py New module providing environment detection utilities with functions for pytest, Warp, PyCharm, Colab, Jupyter, GitHub CI, and IPython display helpers
tests/unit/easyutilities/test_environment.py Comprehensive test suite covering all environment detection functions with edge cases
tests/unit/easyutilities/test_dummy.py Removed dummy test file (no longer needed)
tools/update_github_labels.py Updated label definitions: renamed [bot] pull request to [bot] release, added [bot] backmerge label
pyproject.toml Uncommented and enabled Ruff linting rules (E, F, I, S, W)
pixi.toml Removed GSL dependency, reorganized and added GitHub configuration tasks
docs/mkdocs.yml Added environment module to API reference navigation, removed application docs link
docs/docs/introduction/index.md Updated project description to be more concise
docs/docs/installation-and-setup/index.md Added OneDrive warning for Windows users
docs/docs/index.md Removed "library" from title
docs/docs/api-reference/index.md Added reference to environment module
docs/docs/api-reference/environment.md New API documentation page for environment module
README.md Updated project description
.github/workflows/release-pr.yml Updated workflow name to show specific branches
.github/workflows/pypi-test.yml Updated comment to be more generic
.github/workflows/pypi-publish.yml Removed commented line
.github/workflows/pr-labels.yml Renamed workflow and job, improved step names
.github/workflows/issues-labels.yml New workflow to check and enforce issue labels
.github/workflows/backmerge.yml Enhanced workflow with conflict detection and issue creation on failure
.github/scripts/backmerge-conflict-issue.js New script to create/update issues for backmerge conflicts
.github/configs/rulesets-master.json New branch protection ruleset configuration for master
.github/configs/rulesets-develop.json New branch protection ruleset configuration for develop
.github/configs/rulesets-gh-pages.json New branch protection ruleset configuration for gh-pages
.github/configs/pages-deployment.json New GitHub Pages deployment configuration
.github/actions/publish-to-pypi/action.yml Removed attestations parameter
.copier-answers.yml Updated template version and project description

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 25 out of 26 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

# - The PR body makes clear that this is automation only (no review needed).

name: 'Release PR (<source><default>)'
name: 'Release PR (developmaster)'
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

The workflow name is hard-coded to "develop → master", but the workflow_dispatch input allows source_branch to be set to something else. Consider making the name: generic (or reflecting ${{ inputs.source_branch }}) to avoid misleading run names in the Actions UI.

Suggested change
name: 'Release PR (developmaster)'
name: 'Release PR (sourcedefault)'

Copilot uses AI. Check for mistakes.
@@ -42,7 +42,6 @@ channels = ['conda-forge']

[dependencies]
nodejs = '*' # Required for Prettier (non-Python formatting)
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

gsl was removed from Pixi dependencies, but the installation docs still state that the Pixi method "handles GSL installation automatically" (and that pdffit2 depends on it). Either restore the Pixi dependency or update the docs to match, otherwise users following the Pixi path may end up without the stated functionality.

Suggested change
nodejs = '*' # Required for Prettier (non-Python formatting)
nodejs = '*' # Required for Prettier (non-Python formatting)
gsl = '*' # Required by pdffit2; installed automatically via Pixi

Copilot uses AI. Check for mistakes.
Comment on lines 1 to 13
# This workflow automatically merges `master` into `develop` whenever a
# new version tag is pushed (v*).
#
# Key points:
# - Directly merges master into develop without creating a PR.
# - Skips CI on the merge commit using [skip ci] in the commit message.
# - The code being merged has already been tested as part of the release process.
# - This ensures develop stays up-to-date with release changes (version bumps, etc.).
#
# Required organization config:
# https://github.com/organizations/easyscience/settings/secrets/actions
# https://github.com/organizations/easyscience/settings/variables/actions
# - Actions secret: EASYSCIENCE_APP_KEY (GitHub App private key PEM)
# - Actions variable: EASYSCIENCE_APP_ID (GitHub App ID)
#
# IMPORTANT:
# The GitHub App must be added to the develop branch ruleset bypass list.

name: Backmerge (master -> develop)
# new version release with a tag is published. It can also be triggered
# manually via workflow_dispatch for cases where an automatic backmerge
# is needed outside of the standard release process.
# If a merge conflict occurs, the workflow creates an issue to notify
# maintainers for manual resolution.

name: Backmerge (master → develop)

on:
push:
tags: ['v*']
release:
types: [published, prereleased]
workflow_dispatch:
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

This PR is titled "Add runtime environment detection utilities", but it also introduces/changes multiple GitHub operational workflows and branch protection rulesets. Consider splitting the GitHub automation/ruleset changes into a separate PR so the environment-utility change can be reviewed and released independently.

Copilot uses AI. Check for mistakes.
Comment on lines +151 to +156
except ImportError:
# Fallback heuristic when IPython is unavailable
try:
mod = getattr(getattr(obj, '__class__', None), '__module__', '')
return isinstance(mod, str) and mod.startswith('IPython')
except (AttributeError, TypeError):
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

is_ipython_display_handle() claims to check for a DisplayHandle, but the fallback path returns True for any object whose __class__.__module__ starts with IPython, which can misclassify non-DisplayHandle objects. Consider making the heuristic stricter (e.g., also check the class name and/or exact module), or return False when IPython isn't importable so the function's contract remains accurate.

Copilot uses AI. Check for mistakes.
Comment on lines +285 to +289
def test_can_use_ipython_display_handles_exception_gracefully():
"""Test can_use_ipython_display() handles errors."""
# Object that may cause issues during type checking
bad_obj = MagicMock()
bad_obj.__class__ = None
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

Setting bad_obj.__class__ = None will raise TypeError in Python (since __class__ can only be assigned to a compatible class), so this test is likely to fail before it reaches the assertion. Use an object that triggers TypeError/AttributeError inside isinstance without assigning to __class__ (e.g., a custom object with a problematic __instancecheck__, or patch easyutilities.environment.DisplayHandle/isinstance behavior in the test).

Suggested change
def test_can_use_ipython_display_handles_exception_gracefully():
"""Test can_use_ipython_display() handles errors."""
# Object that may cause issues during type checking
bad_obj = MagicMock()
bad_obj.__class__ = None
def test_can_use_ipython_display_handles_exception_gracefully(monkeypatch):
"""Test can_use_ipython_display() handles errors."""
# Ensure IPython is available so env is configured as in normal use
pytest.importorskip('IPython.display')
class _BadDisplayHandleMeta(type):
def __instancecheck__(cls, instance):
# Simulate a failure inside isinstance
raise TypeError("Simulated isinstance failure")
class _BadDisplayHandle(metaclass=_BadDisplayHandleMeta):
"""Dummy DisplayHandle class whose isinstance checks fail."""
pass
# Patch env.DisplayHandle so that isinstance(obj, DisplayHandle) fails
monkeypatch.setattr(env, "DisplayHandle", _BadDisplayHandle, raising=False)
# Object passed to can_use_ipython_display; type itself is normal
bad_obj = MagicMock()

Copilot uses AI. Check for mistakes.
@AndrewSazonov AndrewSazonov merged commit 4dc600b into develop Feb 25, 2026
39 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[scope] enhancement Adds/improves features (major.MINOR.patch)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants