diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b9a425e..2764007 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,10 +11,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Base Setup uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 diff --git a/.github/workflows/check-release.yml b/.github/workflows/check-release.yml index 21998f6..c5b5bf6 100644 --- a/.github/workflows/check-release.yml +++ b/.github/workflows/check-release.yml @@ -14,7 +14,7 @@ jobs: check_release: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - name: Check Release uses: jupyter-server/jupyter_releaser/.github/actions/check-release@v2 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ed33d47..24dcebb 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Base Setup uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 81daaac..2e181de 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,11 +13,11 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["3.8", "3.11"] + python-version: ["3.9", "3.13"] steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Base Setup uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 @@ -37,6 +37,6 @@ jobs: check_links: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - uses: jupyterlab/maintainer-tools/.github/actions/check-links@v1 diff --git a/jupyter_resource_usage/api.py b/jupyter_resource_usage/api.py index 22e3ae6..410a268 100644 --- a/jupyter_resource_usage/api.py +++ b/jupyter_resource_usage/api.py @@ -95,7 +95,7 @@ async def get(self): def _get_cpu_percent(self, all_processes): def get_cpu_percent(p): try: - return p.cpu_percent(interval=0.05) + return p.cpu_percent() # Avoid littering logs with stack traces complaining # about dead processes having no CPU usage except: diff --git a/jupyter_resource_usage/tests/test_basic.py b/jupyter_resource_usage/tests/test_basic.py index e9f4e99..3c7628f 100644 --- a/jupyter_resource_usage/tests/test_basic.py +++ b/jupyter_resource_usage/tests/test_basic.py @@ -30,13 +30,18 @@ def test_import_serverextension(self): nbapp_mock.web_app.settings = {"base_url": ""} # mock these out for unit test - with patch("tornado.ioloop.PeriodicCallback") as periodic_callback_mock, patch( - "jupyter_resource_usage.server_extension.ResourceUseDisplay" - ) as resource_use_display_mock, patch( - "jupyter_resource_usage.server_extension.PrometheusHandler" - ) as prometheus_handler_mock, patch( - "jupyter_resource_usage.server_extension.PSUtilMetricsLoader" - ) as psutil_metrics_loader: + with ( + patch("tornado.ioloop.PeriodicCallback") as periodic_callback_mock, + patch( + "jupyter_resource_usage.server_extension.ResourceUseDisplay" + ) as resource_use_display_mock, + patch( + "jupyter_resource_usage.server_extension.PrometheusHandler" + ) as prometheus_handler_mock, + patch( + "jupyter_resource_usage.server_extension.PSUtilMetricsLoader" + ) as psutil_metrics_loader, + ): # load up with mock load_jupyter_server_extension(nbapp_mock) diff --git a/packages/labextension/src/index.ts b/packages/labextension/src/index.ts index 7e4791a..48fc408 100644 --- a/packages/labextension/src/index.ts +++ b/packages/labextension/src/index.ts @@ -2,6 +2,7 @@ import { ILabShell, JupyterFrontEnd, JupyterFrontEndPlugin, + JupyterLab, } from '@jupyterlab/application'; import { IToolbarWidgetRegistry } from '@jupyterlab/apputils'; @@ -70,14 +71,25 @@ const resourceStatusPlugin: JupyterFrontEndPlugin = { id: '@jupyter-server/resource-usage:status-item', autoStart: true, requires: [ITranslator], - optional: [IStatusBar], + optional: [IStatusBar, JupyterLab.IInfo], activate: ( app: JupyterFrontEnd, translator: ITranslator, - statusBar: IStatusBar | null + statusBar: IStatusBar | null, + info: JupyterLab.IInfo ) => { + const refreshRate = DEFAULT_REFRESH_RATE; + const trans = translator.load('jupyter-resource-usage'); - const item = new ResourceUsageStatus(trans); + const item = new ResourceUsageStatus(trans, { + refreshRate, + refreshStandby: () => { + if (info) { + return !info.isConnected || 'when-hidden'; + } + return 'when-hidden'; + }, + }); if (statusBar) { statusBar.registerStatusItem(resourceStatusPlugin.id, { @@ -98,11 +110,12 @@ const systemMonitorPlugin: JupyterFrontEndPlugin = { id: '@jupyter-server/resource-usage:topbar-item', autoStart: true, requires: [IToolbarWidgetRegistry], - optional: [ISettingRegistry], + optional: [ISettingRegistry, JupyterLab.IInfo], activate: async ( app: JupyterFrontEnd, toolbarRegistry: IToolbarWidgetRegistry, - settingRegistry: ISettingRegistry | null + settingRegistry: ISettingRegistry | null, + info: JupyterLab.IInfo | null ) => { let enablePlugin = DEFAULT_ENABLE_SYSTEM_MONITOR; let refreshRate = DEFAULT_REFRESH_RATE; @@ -126,7 +139,15 @@ const systemMonitorPlugin: JupyterFrontEndPlugin = { diskLabel = diskSettings.label; } - const model = new ResourceUsage.Model({ refreshRate }); + const model = new ResourceUsage.Model({ + refreshRate, + refreshStandby: () => { + if (info) { + return !info.isConnected || 'when-hidden'; + } + return 'when-hidden'; + }, + }); await model.refresh(); if (enablePlugin && model.cpuAvailable) { diff --git a/packages/labextension/src/model.ts b/packages/labextension/src/model.ts index 042d758..2b85f49 100644 --- a/packages/labextension/src/model.ts +++ b/packages/labextension/src/model.ts @@ -64,8 +64,10 @@ export namespace ResourceUsage { frequency: { interval: options.refreshRate, backoff: true, + max: 300 * 1000, }, name: '@jupyterlab/statusbar:ResourceUsage#metrics', + standby: options.refreshStandby || 'when-hidden', }); this._poll.ticked.connect((poll) => { const { payload, phase } = poll.state; @@ -326,6 +328,11 @@ export namespace ResourceUsage { * The refresh rate (in ms) for querying the server. */ refreshRate: number; + + /** + * When the model stops polling the API. Defaults to `when-hidden`. + */ + refreshStandby?: Poll.Standby | (() => boolean | Poll.Standby); } /** diff --git a/packages/labextension/src/resourceUsage.tsx b/packages/labextension/src/resourceUsage.tsx index 9f6b11e..57d77a1 100644 --- a/packages/labextension/src/resourceUsage.tsx +++ b/packages/labextension/src/resourceUsage.tsx @@ -20,8 +20,8 @@ export class ResourceUsageStatus extends VDomRenderer { /** * Construct a new resource usage status item. */ - constructor(trans: TranslationBundle) { - super(new ResourceUsage.Model({ refreshRate: 5000 })); + constructor(trans: TranslationBundle, options: ResourceUsage.Model.IOptions) { + super(new ResourceUsage.Model(options)); this._trans = trans; } diff --git a/pyproject.toml b/pyproject.toml index 0d4cb95..7639399 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ build-backend = "hatchling.build" name = "jupyter-resource-usage" description = "Jupyter Extension to show resource usage" readme = "README.md" -requires-python = ">=3.8" +requires-python = ">=3.9" authors = [ { name = "Jupyter Development Team" }, ] @@ -30,15 +30,16 @@ classifiers = [ "License :: OSI Approved :: BSD License", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ] dependencies = [ "jupyter_server>=2.0", "prometheus_client", - "psutil~=5.6", + "psutil>=5.6", "pyzmq>=19", ] dynamic = ["version"] @@ -126,7 +127,7 @@ default = "" [tool.jupyter-releaser.hooks] before-build-npm = [ - "python -m pip install jupyterlab~=4.0", + "python -m pip install 'jupyterlab>=4.0,<5'", "jlpm", "jlpm clean", "jlpm build:prod",