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

Chore: Improve linting and formatting #35

Merged
merged 5 commits into from
Dec 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
version: 2

updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "daily"

- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
14 changes: 12 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,18 @@ jobs:
with:
python-version: ${{ matrix.python-version }}

- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"

- name: Set timezone
uses: szenius/set-timezone@v2.0

- name: Run tests
run: make test
- name: Set up project
run: |
# Install package in editable mode.
uv pip install --system --editable='.[develop,test]'

- name: Run linters and software tests
run: poe check
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@

.DS_Store
gecko.log
*.orig
*.orig
28 changes: 28 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
repos:
- repo: https://github.com/fsfe/reuse-tool
rev: v4.0.3
hooks:
- id: reuse
args: ["annotate", "--license", "AGPL-3.0-or-later", "--recursive", "--copyright", "ASSUME Developers", "--exclude-year", "--skip-unrecognised", "--skip-existing", "."]

- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.7.2
hooks:
# Run the linter.
- id: ruff
args: [ --fix ]
# Run the formatter.
- id: ruff-format
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
- id: check-illegal-windows-names
- repo: https://github.com/codespell-project/codespell
rev: v2.3.0
hooks:
- id: codespell
types_or: [python, rst, markdown]
files: ^(assume|docs|tests)/
8 changes: 4 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -305,14 +305,14 @@ Development
cd grafanimate

# Create and activate virtualenv.
python3 -m venv .venv
uv venv
source .venv/bin/activate

# Install package in "editable" mode.
pip install --editable=.
uv pip install --editable='.[develop,test]'

# Run tests.
make test
# Run linters and software tests.
poe check


*******************
Expand Down
1 change: 1 addition & 0 deletions grafanimate/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"""grafanimate: Animate all the data"""

__appname__ = "grafanimate"
__version__ = "0.7.0"
17 changes: 8 additions & 9 deletions grafanimate/animations.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# (c) 2018-2021 Andreas Motl <andreas.motl@panodata.org>
# License: GNU Affero General Public License, Version 3
import logging
Expand All @@ -13,8 +12,9 @@


class SequentialAnimation:
def __init__(self, grafana: GrafanaWrapper, dashboard_uid: str = None, options: Munch = None):

def __init__(
self, grafana: GrafanaWrapper, dashboard_uid: str = None, options: Munch = None
):
self.grafana = grafana
self.dashboard_uid = dashboard_uid
self.options = options or None
Expand All @@ -30,15 +30,13 @@ def log(self, message):
self.grafana.console_info(message)

def run(self, sequence: AnimationSequence):

if not isinstance(sequence, AnimationSequence):
return

self.log("Starting animation: {}".format(sequence))
self.log(f"Starting animation: {sequence}")

frame: AnimationFrame = None
for frame in sequence.get_frames():

# logger.info("=" * 42)

# Render image.
Expand Down Expand Up @@ -67,15 +65,16 @@ def run(self, sequence: AnimationSequence):
self.log("Animation finished")

def render(self, frame: AnimationFrame):

logger.debug("Adjusting time range control")
self.grafana.timewarp(frame, self.dry_run)

logger.debug("Rendering image")
if self.options["exposure-time"] > 0:
logger.info("Waiting for {} seconds (exposure time)".format(self.options["exposure-time"]))
logger.info(
"Waiting for %s seconds (exposure time)", self.options["exposure-time"]
)
time.sleep(self.options["exposure-time"])

if self.options["panel-id"]:
logger.debug("Updating Panel Label")
self.grafana.update_tags()
Expand Down
30 changes: 22 additions & 8 deletions grafanimate/commands.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# (c) 2018-2021 Andreas Motl <andreas.motl@panodata.org>
# License: GNU Affero General Public License, Version 3
import json
Expand Down Expand Up @@ -128,7 +127,7 @@ def run():

# Debug command line options.
if debug:
log.info("Options: {}".format(json.dumps(options, indent=4)))
log.info(f"Options: {json.dumps(options, indent=4)}")

# Sanity checks.
if not options["scenario"]:
Expand All @@ -138,10 +137,14 @@ def run():
if not output_path:
output_path = os.environ.get("GRAFANIMATE_OUTPUT")
if not output_path:
raise DocoptExit("Error: Parameter --output or environment variable GRAFANIMATE_OUTPUT is mandatory")
raise DocoptExit(
"Error: Parameter --output or environment variable GRAFANIMATE_OUTPUT is mandatory"
)

if options["dashboard-view"] == "d-solo" and not options["panel-id"]:
raise DocoptExit("Error: Parameter --panel-id is mandatory for --dashboard-view=d-solo")
raise DocoptExit(
"Error: Parameter --panel-id is mandatory for --dashboard-view=d-solo"
)

options["exposure-time"] = float(options["exposure-time"])
options["use-panel-events"] = asbool(options["use-panel-events"])
Expand Down Expand Up @@ -171,19 +174,30 @@ def run():
if options["dashboard-uid"]:
scenario.dashboard_uid = options["dashboard-uid"]
if not scenario.dashboard_uid:
raise KeyError("Dashboard UID is mandatory, either supply it on the command line or via scenario file")
raise KeyError(
"Dashboard UID is mandatory, either supply it on the command line or via scenario file"
)

# Open a Grafana site in Firefox, using Marionette.
grafana = make_grafana(scenario.grafana_url, scenario.dashboard_uid, options, options["headless"])
grafana = make_grafana(
scenario.grafana_url, scenario.dashboard_uid, options, options["headless"]
)

# Invoke pipeline: Run stop motion animation, producing single frames.
storage: TemporaryStorage = run_animation_scenario(scenario=scenario, grafana=grafana, options=options)
storage: TemporaryStorage = run_animation_scenario(
scenario=scenario, grafana=grafana, options=options
)

# Define output filename pattern.
output = Path(output_path) / "{scenario}--{title}--{uid}.mp4"

# Run rendering sequences, produce composite media artifacts.
scenario.dashboard_title = grafana.get_dashboard_title()
if not options.dry_run:
results = produce_artifacts(input=storage.workdir, output=output, scenario=scenario, options=render_options)
results = produce_artifacts(
input=storage.workdir,
output=output,
scenario=scenario,
options=render_options,
)
log.info("Produced %s results\n%s", len(results), json.dumps(results, indent=2))
36 changes: 24 additions & 12 deletions grafanimate/core.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# (c) 2018-2021 Andreas Motl <andreas.motl@panodata.org>
# License: GNU Affero General Public License, Version 3
import importlib
Expand All @@ -17,8 +16,9 @@
log = logging.getLogger(__name__)


def make_grafana(url: str, dashboard_uid: str, options: dict, headless=False) -> GrafanaWrapper:

def make_grafana(
url: str, dashboard_uid: str, options: dict, headless=False
) -> GrafanaWrapper:
do_login = False
url = furl(url)
if url.username:
Expand All @@ -35,16 +35,22 @@ def make_grafana(url: str, dashboard_uid: str, options: dict, headless=False) ->
view = options["dashboard-view"]
if options["panel-id"]:
if options["dashboard-view"] == "d-solo":
query = "?panelId=" + options["panel-id"] + "&__feature.dashboardSceneSolo&fullscreen"
query = (
"?panelId="
+ options["panel-id"]
+ "&__feature.dashboardSceneSolo&fullscreen"
)
else:
query = "?viewPanel=" + options["panel-id"]

if str(url)[-1] != "/":
url = str(url) + "/"
url = str(url) + view + "/" + dashboard_uid + "/" + slug + query;
url = str(url) + view + "/" + dashboard_uid + "/" + slug + query
print(url)

grafana = GrafanaWrapper(baseurl=str(url), use_panel_events=options["use-panel-events"])
grafana = GrafanaWrapper(
baseurl=str(url), use_panel_events=options["use-panel-events"]
)
grafana.boot_firefox(headless=headless)
grafana.boot_grafana()

Expand All @@ -70,7 +76,9 @@ def get_scenario(source: str) -> AnimationScenario:
scenario: AnimationScenario = resolve_reference(module, symbol)

if scenario is None:
raise NotImplementedError('Animation scenario "{}" not found or implemented'.format(source))
raise NotImplementedError(
f'Animation scenario "{source}" not found or implemented'
)

scenario.source = source

Expand All @@ -96,9 +104,12 @@ def resolve_reference(module, symbol):
return reference


def run_animation_scenario(scenario: AnimationScenario, grafana: GrafanaWrapper, options: Munch) -> TemporaryStorage:

log.info(f"Running animation scenario at {scenario.grafana_url}, with dashboard UID {scenario.dashboard_uid}")
def run_animation_scenario(
scenario: AnimationScenario, grafana: GrafanaWrapper, options: Munch
) -> TemporaryStorage:
log.info(
f"Running animation scenario at {scenario.grafana_url}, with dashboard UID {scenario.dashboard_uid}"
)

storage = TemporaryStorage()

Expand All @@ -117,7 +128,9 @@ def run_animation_scenario(scenario: AnimationScenario, grafana: GrafanaWrapper,
)

# Start the engines.
animation = SequentialAnimation(grafana=grafana, dashboard_uid=scenario.dashboard_uid, options=animation_options)
animation = SequentialAnimation(
grafana=grafana, dashboard_uid=scenario.dashboard_uid, options=animation_options
)
animation.start()

# Run animation scenario.
Expand All @@ -141,4 +154,3 @@ def run_animation_adhoc():
)
animator.run()
"""
pass
4 changes: 2 additions & 2 deletions grafanimate/grafana-studio.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class GrafanaStudioSrv {
// https://github.com/grafana/grafana/blob/v8.2.4/public/app/core/components/Login/LoginCtrl.tsx#L85-L106
$.post({
url: '/login', // The URL where the POST request is sent
contentType: 'application/json',
contentType: 'application/json',
data: JSON.stringify({ user: username, password: password }),
success: function(response) {
console.log('Success:', response); // Handle success
Expand Down Expand Up @@ -250,7 +250,7 @@ class GrafanaStudioSrv {

getDashboardTitle() {
// Build title from original one plus start time.

var dashboard = __grafanaSceneContext._state;
var title = dashboard.title;
if (!this.hasHeaderLayout("no-folder")) {
Expand Down
19 changes: 10 additions & 9 deletions grafanimate/grafana.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
# -*- coding: utf-8 -*-
# (c) 2018-2021 Andreas Motl <andreas.motl@panodata.org>
# License: GNU Affero General Public License, Version 3
import json
import logging
import time
from importlib.resources import read_text

from marionette_driver import Wait
from marionette_driver.errors import TimeoutException

from importlib.resources import read_text

from grafanimate.marionette import FirefoxMarionetteBase
from grafanimate.model import AnimationFrame
from grafanimate.timeutil import format_date_grafana
Expand All @@ -22,7 +20,9 @@ class GrafanaWrapper(FirefoxMarionetteBase):
https://marionette-client.readthedocs.io/en/master/interactive.html
"""

def __init__(self, baseurl: str = None, use_panel_events: bool = True, dry_run: bool = False):
def __init__(
self, baseurl: str = None, use_panel_events: bool = True, dry_run: bool = False
):
self.baseurl = baseurl
self.use_panel_events = use_panel_events
self.dry_run = dry_run
Expand All @@ -33,16 +33,15 @@ def boot_grafana(self):
"""
Navigate to Grafana application and inject Grafana Sidecar service.
"""
log.info("Starting Grafana at {}".format(self.baseurl))
self.set_window_size(1920,1080)
log.info("Starting Grafana at %s", self.baseurl)
self.set_window_size(1920, 1080)

self.navigate(self.baseurl)

rect = self.get_window_rect()
self.marionette.set_window_rect(height=rect["height"], width=rect["width"])

def navigate(self, url):

# Navigate to resource URL.
self.marionette.navigate(url)

Expand Down Expand Up @@ -112,7 +111,7 @@ def timewarp(self, frame: AnimationFrame, dry_run: bool = False):
"""

# Notify user.
message = "Timewarp to {} -> {}".format(frame.timerange.start, frame.timerange.stop)
message = f"Timewarp to {frame.timerange.start} -> {frame.timerange.stop}"
log.info(message)
self.console_log(message)

Expand Down Expand Up @@ -153,7 +152,9 @@ def run_javascript(self, sourcecode, silent=False):
# https://github.com/devtools-html/har-export-trigger/issues/27#issuecomment-424777524
if not silent:
log.debug("Running Javascript: %s", sourcecode)
return self.marionette.execute_script(sourcecode, sandbox=None, new_sandbox=False)
return self.marionette.execute_script(
sourcecode, sandbox=None, new_sandbox=False
)

def calljs(self, name, *args, silent=False):
return self.run_javascript(mkjscall(name, *args), silent=silent)
Expand Down
Loading