[modules/wakatime] - New module that connects to https://wakatime.com and displays coding duration stats

This commit is contained in:
Duarte Figueiredo 2023-04-16 11:24:51 +01:00
parent e58afff48a
commit 42e041ce03
4 changed files with 154 additions and 0 deletions

View file

@ -0,0 +1,95 @@
# pylint: disable=C0111,R0903
"""
Displays the WakaTime daily/weekly/monthly times:
* https://wakatime.com/developers#stats
Uses `xdg-open` or `x-www-browser` to open web-pages.
Requires the following library:
* requests
Errors:
if the Wakatime status query failed, the shown value is `n/a`
Parameters:
* wakatime.token: Wakatime secret api key, you can get it in https://wakatime.com/settings/account.
* wakatime.range: Range of the output, default is "Today". Can be one of Today, Yesterday, Last 7 Days, Last 7 Days from Yesterday, Last 14 Days, Last 30 Days, This Week, Last Week, This Month, or Last Month.
* wakatime.format: Format of the output, default is "digital"
Valid inputs are:
* "decimal" -> 1.37
* "digital" -> 1:22
* "seconds" -> 4931.29
* "text" -> 1 hr 22 mins
* "%H:%M:%S" -> 01:22:31 (or any other valid format)
"""
import base64
import shutil
import time
from typing import Final, List
import requests
import core.decorators
import core.input
import core.module
import core.widget
HOST_API: Final[str] = "https://wakatime.com"
SUMMARIES_URL: Final[str] = f"{HOST_API}/api/v1/users/current/summaries"
UTF8: Final[str] = "utf-8"
FORMAT_PARAMETERS: Final[List[str]] = ["decimal", "digital", "seconds", "text"]
class Module(core.module.Module):
@core.decorators.every(minutes=5)
def __init__(self, config, theme):
super().__init__(config, theme, core.widget.Widget(self.wakatime))
self.background = True
self.__label = ""
self.__output_format = self.parameter("format", "digital")
self.__range = self.parameter("range", "Today")
self.__requests = requests.Session()
token = self.__encode_to_base_64(self.parameter("token", ""))
self.__requests.headers.update({"Authorization": f"Basic {token}"})
cmd = "xdg-open"
if not shutil.which(cmd):
cmd = "x-www-browser"
core.input.register(
self,
button=core.input.LEFT_MOUSE,
cmd=f"{cmd} {HOST_API}/dashboard",
)
def wakatime(self, _):
return self.__label
def update(self):
try:
self.__label = self.__get_waka_time(self.__range)
except Exception:
self.__label = "n/a"
def __get_waka_time(self, since_date: str) -> str:
response = self.__requests.get(f"{SUMMARIES_URL}?range={since_date}")
data = response.json()
grand_total = data["cumulative_total"]
if self.__output_format in FORMAT_PARAMETERS:
return str(grand_total[self.__output_format])
else:
total_seconds = int(grand_total["seconds"])
return time.strftime(self.__output_format, time.gmtime(total_seconds))
@staticmethod
def __encode_to_base_64(s: str) -> str:
return base64.b64encode(s.encode(UTF8)).decode(UTF8)

BIN
screenshots/wakatime.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -0,0 +1,56 @@
from unittest import TestCase, mock
import pytest
from requests import Session
import core.config
import core.widget
import modules.contrib.wakatime
pytest.importorskip("requests")
def build_wakatime_module(waka_format=None, waka_range=None):
config = core.config.Config([
"-p",
f"wakatime.format={waka_format}" if waka_format else "",
f"wakatime.range={waka_range}" if waka_range else ""
])
return modules.contrib.wakatime.Module(config=config, theme=None)
def mock_todo_api_response():
res = mock.Mock()
res.json = lambda: {
"cumulative_total": {
"text": "3 hrs 2 mins",
"seconds": 10996,
"digital": "3:02",
"decimal": "3.03"
},
}
res.status_code = 200
return res
class TestWakatimeUnit(TestCase):
def test_load_module(self):
__import__("modules.contrib.wakatime")
@mock.patch.object(Session, "get", return_value=mock_todo_api_response())
def test_default_values(self, mock_get):
module = build_wakatime_module()
module.update()
assert module.widgets()[0].full_text() == "3:02"
mock_get.assert_called_with('https://wakatime.com/api/v1/users/current/summaries?range=today')
@mock.patch.object(Session, "get", return_value=mock_todo_api_response())
def test_custom_configs(self, mock_get):
module = build_wakatime_module(waka_format="text", waka_range="last 7 days")
module.update()
assert module.widgets()[0].full_text() == "3 hrs 2 mins"
mock_get.assert_called_with('https://wakatime.com/api/v1/users/current/summaries?range=last 7 days')

View file

@ -584,6 +584,9 @@
"gitlab": { "gitlab": {
"prefix": "" "prefix": ""
}, },
"wakatime": {
"prefix": "W"
},
"deezer": { "deezer": {
"prefix": "  " "prefix": "  "
}, },