Showing 1 of 9 files from the diff.
Newly tracked file
tracklr/__init__.py changed.
Other files ignored by Codecov

@@ -1,19 +1,17 @@
Loading
1 1
# -*- coding: utf-8 -*-
2 +
import logging
2 3
import os
4 +
import pytz
3 5
import re
6 +
import requests
4 7
import warnings
8 +
import yaml
5 9
6 -
# Python2 Backward Compatibility
7 -
try:
8 -
    FileNotFoundError
9 -
except NameError:
10 -
    FileNotFoundError = IOError
10 +
from icalendar import Calendar
11 +
from requests.auth import HTTPBasicAuth
12 +
from requests.exceptions import MissingSchema
11 13
12 -
# Python2 Backward Compatibility
13 -
try:
14 -
    ModuleNotFoundError
15 -
except NameError:
16 -
    ModuleNotFoundError = ImportError
14 +
from tracklr.vdir import Vdir
17 15
18 16
try:
19 17
    import appdirs
@@ -22,37 +20,18 @@
Loading
22 20
        "appdirs missing - should the issue persists post install, "
23 21
        "run `pip install appdirs` manually"
24 22
    )
25 -
import logging
26 -
import pytz
27 -
import requests
28 -
import yaml
29 23
30 24
try:
31 25
    from pyfiglet import Figlet
32 26
except ModuleNotFoundError:
33 27
    Figlet = None
34 -
from icalendar import Calendar
35 -
from requests.auth import HTTPBasicAuth
36 -
from requests.exceptions import MissingSchema
37 -
38 -
from tracklr.vdir import Vdir
39 -
40 -
41 -
WARN_CONFIG_URL = ("Use `location` instead of `url` in your configuration. "
42 -
                   "`url` is deprecated since v1.0.0. "
43 -
                   "See https://www.tracklr.com/configuration.html")
44 -
WARN_CONFIG_TZ = ("Use `timezone` instead of `x_wr_timezone` "
45 -
                  "in your configuration. "
46 -
                  "`x_wr_timezone` is deprecated since v1.0.0. "
47 -
                  "See https://www.tracklr.com/configuration.html")
48 -
49 28
50 29
class Tracklr(object):
51 30
    """Tracklr loads events recorded in `iCalendar` feeds and
52 31
    uses them to create reports.
53 32
    """
54 33
55 -
    __version__ = "1.4.2"
34 +
    __version__ = "1.5.0"
56 35
57 36
    __config__ = """
58 37
---
@@ -146,7 +125,7 @@
Loading
146 125
        self.config = None
147 126
        self.configure()
148 127
149 -
    def banner(self, kalendar, title=None, subtitle=None):
128 +
    def banner(self, kalendar, title=None, subtitle=None, use_figlet=True):
150 129
        """Displays base information about the Tracklr instance.
151 130
        """
152 131
        cal = self.get_calendar_config(kalendar)
@@ -155,15 +134,19 @@
Loading
155 134
        subtitle = self.get_subtitle(cal["name"], subtitle)
156 135
157 136
        tracklr_banner = "Tracklr"
158 -
        if Figlet is not None:
159 -
            banner = Figlet(font="cybermedium")
137 +
138 +
        if Figlet is not None and use_figlet is True:
139 +
            banner = Figlet(font="fuzzy")
160 140
            tracklr_banner = banner.renderText(tracklr_banner).rstrip(" \n")
161 141
162 -
        self.log.info("{} v{}\n".format(tracklr_banner, self.__version__))
142 +
        banner = f"{tracklr_banner} v{self.__version__}\n"
163 143
164 -
        self.log.info("Title: {}".format(title))
165 -
        self.log.info("Subtitle: {}".format(subtitle))
166 -
        self.log.info("Configuration: {}".format(self.loaded_config_file))
144 +
        self.log.info(banner)
145 +
        self.log.info(f"Title: {title}")
146 +
        self.log.info(f"Subtitle: {subtitle}")
147 +
        self.log.info(f"Configuration: {self.loaded_config_file}")
148 +
149 +
        return banner
167 150
168 151
    def configure(self):
169 152
        """Tries to load Tracklr configuration from current working directory
@@ -205,17 +188,10 @@
Loading
205 188
                self.calendars[name] = cal
206 189
            except KeyError:
207 190
                name = "default"
208 -
                try:
209 -
                    self.calendars[name] = {
210 -
                        "name": name,
211 -
                        "location": cal["location"],
212 -
                    }
213 -
                except KeyError:
214 -
                    self.calendars[name] = {
215 -
                        "name": name,
216 -
                        "location": cal["url"],
217 -
                    }
218 -
                    warnings.warn(WARN_CONFIG_URL)
191 +
                self.calendars[name] = {
192 +
                    "name": name,
193 +
                    "location": cal["location"],
194 +
                }
219 195
            except TypeError:
220 196
                name = "default"
221 197
                self.calendars[name] = {"name": name, "location": cal}
@@ -229,9 +205,8 @@
Loading
229 205
        calendars = "\n".join([cal for cal in self.calendars])
230 206
        if calendar not in self.calendars:
231 207
            self.log.error(
232 -
                "calendar {} not found in configured calendars:\n{}".format(
233 -
                    calendar, calendars
234 -
                )
208 +
                f"calendar {calendar} not found "
209 +
                f"in the configured calendars:\n{calendars}"
235 210
            )
236 211
            raise
237 212
        return self.calendars[calendar]
@@ -246,9 +221,7 @@
Loading
246 221
        log_level = self.log_levels["INFO"]
247 222
        if "log_level" in self.config:
248 223
            log_level = self.log_levels[self.config["log_level"].upper()]
249 -
            self.log.debug(
250 -
                "Set logging to {}".format(self.config["log_level"].upper())
251 -
            )
224 +
            self.log.debug(f"Set logging to {self.config['log_level'].upper()}")
252 225
253 226
        self.log.setLevel(log_level)
254 227
@@ -286,10 +259,9 @@
Loading
286 259
        """Returns "title - subtitle" string.
287 260
        """
288 261
        cal = self.get_calendar_config(calendar)
289 -
        return "{} - {}".format(
290 -
            self.get_title(cal["name"], title),
291 -
            self.get_subtitle(cal["name"], subtitle),
292 -
        )
262 +
        title = self.get_title(cal["name"], title)
263 +
        subtitle = self.get_subtitle(cal["name"], subtitle)
264 +
        return f"{title} - {subtitle}"
293 265
294 266
    def parse_summary(self, key, summary):
295 267
        """Parses given event summary and returns all strings
@@ -304,9 +276,13 @@
Loading
304 276
            if isinstance(summary, list):
305 277
                return pattern.findall(" ".join(summary))
306 278
279 +
        self.log.info(key)
280 +
307 281
        # 23g, 1024hPa, 30C, ...
282 +
        pattern = re.compile(f"([0-9.]+){key}")
283 +
        matches = find_matches(summary, pattern)
308 284
        try:
309 -
            pattern = re.compile(r"([0-9\.\,]+){}".format(key))
285 +
            pattern = re.compile(f"([0-9.]+){key}")
310 286
            matches = find_matches(summary, pattern)
311 287
        except Exception:
312 288
            matches = None
@@ -316,7 +292,7 @@
Loading
316 292
317 293
        # #hastags, $monies, @something, ...
318 294
        try:
319 -
            pattern = re.compile(r"\{}([a-zA-Z0-9_\-\.]+)".format(key))
295 +
            pattern = re.compile(f"{key}([a-zA-Z0-9_-.]+)")
320 296
            return find_matches(summary, pattern)
321 297
        except Exception:
322 298
            return None
@@ -331,8 +307,6 @@
Loading
331 307
        For more info see:
332 308
        https://blog.jonudell.net/2011/10/17/x-wr-timezone-considered-harmful/
333 309
        """
334 -
        if self.calendars[name].get("x_wr_timezone", False) is not False:
335 -
            warnings.warn(WARN_CONFIG_TZ)
336 310
        timezone = self.calendars[name].get("timezone", False)
337 311
        if timezone is not False:
338 312
            if timezone is True:
@@ -401,38 +375,21 @@
Loading
401 375
                    for event in event_ical.walk("vevent"):
402 376
                        self.calendars[name]["events"].append(event)
403 377
            except IOError:
404 -
                self.log.warning("No calendar found at {}".format(location))
378 +
                self.log.warning(f"No calendar found at {location}")
405 379
406 380
    def get_calendar(self, calendar):
407 381
        """Loads multiple calendars which can use BasicHTTPAuth.
408 382
        """
409 383
        cal = self.get_calendar_config(calendar)
410 384
        if "username" in cal and "password" in cal:
411 -
            try:
412 -
                self.get_feed(
413 -
                    cal["name"],
414 -
                    cal["location"],
415 -
                    cal["username"],
416 -
                    cal["password"]
417 -
                )
418 -
            except KeyError:
419 -
                self.get_feed(
420 -
                    cal["name"],
421 -
                    cal["url"],
422 -
                    cal["username"],
423 -
                    cal["password"]
424 -
                )
425 -
                warnings.warn(WARN_CONFIG_URL)
385 +
            self.get_feed(
386 +
                cal["name"],
387 +
                cal["location"],
388 +
                cal["username"],
389 +
                cal["password"]
390 +
            )
426 391
        else:
427 -
            try:
428 -
                self.get_feed(cal["name"], cal["location"])
429 -
            except KeyError:
430 -
                self.get_feed(cal["name"], cal["url"])
431 -
                warnings.warn(WARN_CONFIG_URL)
432 -
433 -
        if cal.get("x_wr_timezone", False) is not False:
434 -
            warnings.warn(WARN_CONFIG_TZ)
435 -
            self.set_timezone(cal["name"])
392 +
            self.get_feed(cal["name"], cal["location"])
436 393
437 394
        if cal.get("timezone", False) is not False:
438 395
            self.set_timezone(cal["name"])
@@ -450,7 +407,7 @@
Loading
450 407
        if s.year == e.year and s.month == e.month and s.day == e.day:
451 408
            return s.strftime(format)
452 409
        else:
453 -
            return "{} - {}".format(s.strftime(format), e.strftime(format))
410 +
            return f"{s.strftime(format)} - {e.strftime(format)}"
454 411
455 412
    def filter_event(self, key, event, date_pattern, include, exclude):
456 413
        """Decides whether the event should be included or excluded.
@@ -473,7 +430,7 @@
Loading
473 430
            filter_out = False
474 431
            matches = self.parse_summary(key, include)
475 432
            for t in matches:
476 -
                if "{}{}".format(key, t) not in summary:
433 +
                if f"{key}{t}" not in summary:
477 434
                    filter_out = True
478 435
            if filter_out:
479 436
                return True
@@ -487,7 +444,7 @@
Loading
487 444
            filter_out = False
488 445
            matches = self.parse_summary(key, exclude)
489 446
            for t in matches:
490 -
                if "{}{}".format(key, t) in summary:
447 +
                if f"{key}{t}" in summary:
491 448
                    filter_out = True
492 449
            if filter_out:
493 450
                return True
@@ -515,11 +472,8 @@
Loading
515 472
                summary = event["SUMMARY"].strip()
516 473
                matches = self.parse_summary(key, summary)
517 474
518 -
                self.log.info(matches)
519 475
                for match in matches:
520 -
                    match_check = match.replace(".", "", 1)
521 -
                    match_check = match_check.replace(",", "", 1)
522 -
                    if match_check.isdigit():
476 +
                    if match.replace(".", "", 1).isdigit():
523 477
                        matches_processed.append(float(match))
524 478
                    else:
525 479
                        matches_processed.append(str(match))
@@ -546,7 +500,7 @@
Loading
546 500
                    date,
547 501
                    summary,
548 502
                    description,
549 -
                    lent.total_seconds() / 3600.0,
503 +
                    round(lent.total_seconds() / 3600.0, 2),
550 504
                    matches_result,
551 505
                )
552 506
            else:
@@ -554,7 +508,7 @@
Loading
554 508
                    date,
555 509
                    summary,
556 510
                    description,
557 -
                    lent.total_seconds() / 3600.0,
511 +
                    round(lent.total_seconds() / 3600.0, 2),
558 512
                )
559 513
            self.report.append(entry)
560 514
@@ -562,13 +516,13 @@
Loading
562 516
                date,
563 517
                str(summary).replace("\n", "<br />"),
564 518
                str(description).replace("\n", "<br />"),
565 -
                lent.total_seconds() / 3600.0,
519 +
                round(lent.total_seconds() / 3600.0, 2),
566 520
                matches_result,
567 521
            )
568 522
            self.report_html.append(entry_html)
569 523
570 524
            self.total_seconds = self.total_seconds + lent.total_seconds()
571 -
            self.total_hours = self.total_seconds / 3600.0
525 +
            self.total_hours = round(self.total_seconds / 3600.0, 2)
572 526
            for matched_item in matches_result:
573 527
                if isinstance(matched_item, float):
574 528
                    self.total_sum = self.total_sum + matched_item
@@ -601,17 +555,17 @@
Loading
601 555
                    lent = self.get_event_length(event)
602 556
                    for t in matches:
603 557
                        if t in self.matches:
604 -
                            self.matches[t] += (
558 +
                            self.matches[t] += round((
605 559
                                lent.total_seconds() / 3600.0
606 -
                            ) / float(match_no)
560 +
                            ) / float(match_no), 2)
607 561
                        else:
608 -
                            self.matches[t] = (
562 +
                            self.matches[t] = round((
609 563
                                lent.total_seconds() / 3600.0
610 -
                            ) / float(match_no)
564 +
                            ) / float(match_no), 2)
611 565
                    self.total_seconds = (
612 566
                        self.total_seconds + lent.total_seconds()
613 567
                    )
614 -
                    self.total_hours = self.total_seconds / 3600.0
568 +
                    self.total_hours = round(self.total_seconds / 3600.0, 2)
615 569
            except KeyError:
616 570
                self.log.debug("No summary found")
617 571
Files Coverage
tracklr 51.00%
Project Totals (8 files) 51.00%
Untitled

No yaml found.

Create your codecov.yml to customize your Codecov experience

Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading