heatmap_cli 0.22.33__tar.gz → 0.22.35__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. {heatmap_cli-0.22.33/src/heatmap_cli.egg-info → heatmap_cli-0.22.35}/PKG-INFO +1 -1
  2. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/pyproject.toml +1 -1
  3. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/src/heatmap_cli/__init__.py +3 -1
  4. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/src/heatmap_cli/__main__.py +2 -0
  5. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/src/heatmap_cli/cli.py +8 -7
  6. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/src/heatmap_cli/heatmap.py +32 -33
  7. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35/src/heatmap_cli.egg-info}/PKG-INFO +1 -1
  8. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/LICENSE.md +0 -0
  9. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/README.md +0 -0
  10. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/setup.cfg +0 -0
  11. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/src/heatmap_cli.egg-info/SOURCES.txt +0 -0
  12. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/src/heatmap_cli.egg-info/dependency_links.txt +0 -0
  13. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/src/heatmap_cli.egg-info/entry_points.txt +0 -0
  14. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/src/heatmap_cli.egg-info/requires.txt +0 -0
  15. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/src/heatmap_cli.egg-info/top_level.txt +0 -0
  16. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_animate_by_week.py +0 -0
  17. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_annotate_flag.py +0 -0
  18. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_cbar_flag.py +0 -0
  19. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_cmap_option.py +0 -0
  20. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_cmax_option.py +0 -0
  21. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_cmin_option.py +0 -0
  22. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_debug_flag.py +0 -0
  23. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_demo_option.py +0 -0
  24. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_end_date_option.py +0 -0
  25. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_env_flag.py +0 -0
  26. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_heatmap_direct.py +0 -0
  27. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_heatmap_errors.py +0 -0
  28. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_heatmap_utils.py +0 -0
  29. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_help_flag.py +0 -0
  30. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_output_dir_option.py +0 -0
  31. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_purge_flag.py +0 -0
  32. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_quiet_flag.py +0 -0
  33. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_start_date_option.py +0 -0
  34. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_title_option.py +0 -0
  35. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_verbose_flag.py +0 -0
  36. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_version_flag.py +0 -0
  37. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_week_option.py +0 -0
  38. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_year_option.py +0 -0
  39. {heatmap_cli-0.22.33 → heatmap_cli-0.22.35}/tests/test_yes_flag.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: heatmap_cli
3
- Version: 0.22.33
3
+ Version: 0.22.35
4
4
  Summary: A console program that generates a yearly calendar heatmap.
5
5
  Author-email: Kian-Meng Ang <kianmeng@cpan.org>
6
6
  License-Expression: AGPL-3.0-or-later
@@ -25,7 +25,7 @@ classifiers = [
25
25
  "Programming Language :: Python",
26
26
  "Topic :: Scientific/Engineering :: Visualization",
27
27
  ]
28
- version = "0.22.33"
28
+ version = "0.22.35"
29
29
  keywords = ["heatmap", "cli", "visualization", "calendar", "data-viz"]
30
30
  dependencies = [
31
31
  "matplotlib",
@@ -15,6 +15,8 @@
15
15
 
16
16
  """A console program that generates a yearly calendar heatmap."""
17
17
 
18
+ from __future__ import annotations
19
+
18
20
  import argparse
19
21
  import datetime
20
22
  import logging
@@ -56,7 +58,7 @@ def setup_logging(config: argparse.Namespace) -> None:
56
58
 
57
59
  match config:
58
60
  case argparse.Namespace(quiet=True):
59
- logging.disable(logging.NOTSET)
61
+ logging.disable()
60
62
  return
61
63
  case argparse.Namespace(debug=True):
62
64
  level = logging.DEBUG
@@ -15,6 +15,8 @@
15
15
 
16
16
  """Main entry point when running as a module."""
17
17
 
18
+ from __future__ import annotations
19
+
18
20
  from heatmap_cli.cli import main
19
21
 
20
22
  if __name__ == "__main__":
@@ -20,12 +20,17 @@ changelog: https://github.com/kianmeng/heatmap_cli/blob/master/CHANGELOG.md
20
20
  issues: https://github.com/kianmeng/heatmap_cli/issues
21
21
  """
22
22
 
23
+ from __future__ import annotations
24
+
23
25
  import argparse
24
26
  import datetime
25
27
  import multiprocessing
26
28
  import sys
27
- from collections.abc import Sequence
28
29
  from itertools import zip_longest
30
+ from typing import TYPE_CHECKING
31
+
32
+ if TYPE_CHECKING:
33
+ from collections.abc import Sequence
29
34
 
30
35
  from heatmap_cli import (
31
36
  CMAPS,
@@ -57,6 +62,7 @@ IMAGE_FORMATS = [
57
62
  logger = multiprocessing.get_logger()
58
63
 
59
64
  DEFAULT_CMAP = "RdYlGn_r"
65
+ CMAP_ITEMS_PER_ROW = 6
60
66
 
61
67
 
62
68
  def _valid_date(s: str) -> str:
@@ -361,9 +367,8 @@ def _generate_cmap_help() -> str:
361
367
  cmap_default = f" (default: '{DEFAULT_CMAP}')"
362
368
 
363
369
  # Always show all colormaps in help text
364
- items_per_row = 6
365
370
  cmap_choices = "\nAvailable colormaps:\n"
366
- cmap_bygroups = zip_longest(*(iter(CMAPS),) * items_per_row)
371
+ cmap_bygroups = zip_longest(*(iter(CMAPS),) * CMAP_ITEMS_PER_ROW)
367
372
  for cmap_bygroup in cmap_bygroups:
368
373
  cmap_choices += " " + ", ".join(filter(None, cmap_bygroup)) + "\n"
369
374
 
@@ -438,10 +443,6 @@ def main(args: Sequence[str] | None = None) -> None:
438
443
  """
439
444
  argv = args if args is not None else sys.argv[1:]
440
445
  parser = build_parser()
441
- # Use parse_known_args to potentially capture debug flag even if other args
442
- # fail. However, we'll rely on the full parse_args within the try block for
443
- # simplicity here.
444
- parsed_args = None
445
446
  debug_active = False # Initialize to False, will be set after parsing
446
447
 
447
448
  try:
@@ -15,7 +15,8 @@
15
15
 
16
16
  """Main logic to generate heatmap."""
17
17
 
18
- import argparse
18
+ from __future__ import annotations
19
+
19
20
  import copy
20
21
  import io
21
22
  import multiprocessing
@@ -24,7 +25,10 @@ import shutil
24
25
  import webbrowser
25
26
  from datetime import datetime, timedelta, timezone
26
27
  from pathlib import Path
27
- from typing import Any
28
+ from typing import TYPE_CHECKING, Any
29
+
30
+ if TYPE_CHECKING:
31
+ import argparse
28
32
 
29
33
  import matplotlib as mpl
30
34
  import matplotlib.pyplot as plt
@@ -73,7 +77,6 @@ COLORBAR_ANNOTATION_SUFFIX = ", count: nearest hundred"
73
77
 
74
78
  # Define constants for count truncation
75
79
  TRUNCATE_DIVISOR = 100
76
- TRUNCATE_ROUND_DECIMALS = -2
77
80
 
78
81
  # Define constants for week ranges
79
82
  ALL_WEEKS_RANGE = range(1, 54)
@@ -375,7 +378,7 @@ def _filter_and_pivot_data(
375
378
  def _truncate_rounded_count(count: float) -> int:
376
379
  """Truncate and round count values to fit them in heatmap box.
377
380
 
378
- Rounds the count to the nearest hundred and then divides by 100.
381
+ Divides the count by 100 and rounds to the nearest integer.
379
382
  This transformation is applied when annotations are enabled to simplify
380
383
  large numbers and make them fit visually within the heatmap cells.
381
384
  For example, 12345 becomes 123, 5678 becomes 57.
@@ -386,7 +389,7 @@ def _truncate_rounded_count(count: float) -> int:
386
389
  Returns:
387
390
  int: Truncated count value (divided by 100).
388
391
  """
389
- return int(round(count, TRUNCATE_ROUND_DECIMALS) / TRUNCATE_DIVISOR)
392
+ return round(count / TRUNCATE_DIVISOR)
390
393
 
391
394
 
392
395
  def _setup_plot_artists(
@@ -401,7 +404,7 @@ def _setup_plot_artists(
401
404
  Args:
402
405
  cmap (str): Colormap name used for the heatmap.
403
406
  config (argparse.Namespace): Config from command line arguments.
404
- dataframe (pd.core.frame.DataFrame): DataFrame with data.
407
+ dataframe (pd.DataFrame): DataFrame with data.
405
408
 
406
409
  Returns:
407
410
  plt.Axes: The Axes object with the heatmap plotted.
@@ -444,7 +447,7 @@ def _generate_heatmap(
444
447
  seq (int): Sequence number for generated heatmap image file.
445
448
  cmap (str): Colormap name used for the heatmap.
446
449
  config (argparse.Namespace): Config from command line arguments.
447
- dataframe (pd.core.frame.DataFrame): DataFrame with data loaded from
450
+ dataframe (pd.DataFrame): DataFrame with data loaded from
448
451
  CSV file.
449
452
  return_image (bool): If True, returns a PIL Image object instead of
450
453
  saving to disk.
@@ -506,9 +509,9 @@ def _configure_heatmap_options(
506
509
  "cbar_kws": cbar_options,
507
510
  }
508
511
 
509
- if config.cmap_min:
512
+ if config.cmap_min is not None:
510
513
  options["vmin"] = config.cmap_min
511
- if config.cmap_max:
514
+ if config.cmap_max is not None:
512
515
  options["vmax"] = config.cmap_max
513
516
 
514
517
  if config.annotate:
@@ -545,7 +548,11 @@ def _configure_cbar(res: plt.Axes) -> None:
545
548
  Args:
546
549
  res (plt.Axes): The matplotlib axes object returned by seaborn.
547
550
  """
551
+ if not res.collections:
552
+ return
548
553
  cbar = res.collections[0].colorbar
554
+ if cbar is None:
555
+ return
549
556
  cbar.set_label(cbar.ax.get_xlabel(), rotation=0, labelpad=8, loc="left")
550
557
 
551
558
 
@@ -626,7 +633,7 @@ def _open_heatmap(filename: Path) -> None:
626
633
  Returns:
627
634
  None
628
635
  """
629
- file_uri = f"file://{filename.resolve()}"
636
+ file_uri = filename.resolve().as_uri()
630
637
  webbrowser.open(file_uri)
631
638
  logger.info("Open heatmap: %s using default program.", filename.resolve())
632
639
 
@@ -720,29 +727,21 @@ def _refresh_output_dir(config: argparse.Namespace) -> None:
720
727
  """
721
728
  output_dir = _get_output_dir(config)
722
729
 
723
- # Determine if purging is required based on --purge and --yes flags.
724
- should_purge = False
725
730
  if config.purge:
726
- if config.yes:
727
- should_purge = True
728
- else:
729
- prompt = (
730
- f"Are you sure to purge output folder: {output_dir}? [y/N] "
731
- )
732
- match input(prompt).lower():
733
- case "y" | "yes":
734
- should_purge = True
735
-
736
- # If purging is required and the directory exists, remove it.
737
- if should_purge and output_dir.exists():
738
- logger.info("Purging output folder: %s", output_dir.absolute())
739
- try:
740
- shutil.rmtree(output_dir)
741
- except OSError as e:
742
- logger.error("Error removing directory: %s - %s.", output_dir, e)
743
- # Depending on desired error handling, you might want to raise an
744
- # exception here.
745
- return
731
+ should_purge = config.yes or input(
732
+ f"Are you sure to purge output folder: {output_dir}? [y/N] "
733
+ ).lower() in {"y", "yes"}
734
+ if should_purge and output_dir.exists():
735
+ logger.info("Purging output folder: %s", output_dir.absolute())
736
+ try:
737
+ shutil.rmtree(output_dir)
738
+ except OSError as e:
739
+ logger.error(
740
+ "Error removing directory: %s - %s.",
741
+ output_dir,
742
+ e,
743
+ )
744
+ return
746
745
 
747
746
  # Ensure the output directory exists for writing files.
748
747
  # This will create it if it doesn't exist or was just purged.
@@ -751,7 +750,7 @@ def _refresh_output_dir(config: argparse.Namespace) -> None:
751
750
 
752
751
 
753
752
  def _get_output_dir(config: argparse.Namespace) -> Path:
754
- """Get the current working directory.
753
+ """Get the output directory path, resolved relative to CWD.
755
754
 
756
755
  Args:
757
756
  config (argparse.Namespace): Config from command line arguments.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: heatmap_cli
3
- Version: 0.22.33
3
+ Version: 0.22.35
4
4
  Summary: A console program that generates a yearly calendar heatmap.
5
5
  Author-email: Kian-Meng Ang <kianmeng@cpan.org>
6
6
  License-Expression: AGPL-3.0-or-later
File without changes
File without changes
File without changes