clox 0.8__py3-none-any.whl → 0.9__py3-none-any.whl
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.
Potentially problematic release.
This version of clox might be problematic. Click here for more details.
- clox/functions.py +60 -64
- clox/jcalendar.py +41 -40
- clox/params.py +2 -1
- {clox-0.8.dist-info → clox-0.9.dist-info}/METADATA +16 -8
- clox-0.9.dist-info/RECORD +12 -0
- {clox-0.8.dist-info → clox-0.9.dist-info}/WHEEL +1 -1
- clox-0.8.dist-info/RECORD +0 -12
- {clox-0.8.dist-info → clox-0.9.dist-info}/entry_points.txt +0 -0
- {clox-0.8.dist-info → clox-0.9.dist-info/licenses}/AUTHORS.md +0 -0
- {clox-0.8.dist-info → clox-0.9.dist-info/licenses}/LICENSE +0 -0
- {clox-0.8.dist-info → clox-0.9.dist-info}/top_level.txt +0 -0
clox/functions.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
"""clox functions."""
|
|
3
|
+
from typing import Optional
|
|
3
4
|
import os
|
|
4
5
|
import sys
|
|
5
6
|
import time
|
|
@@ -13,6 +14,7 @@ from art import tprint
|
|
|
13
14
|
from .jcalendar import TextCalendar as JalaliCalendar
|
|
14
15
|
from .params import HORIZONTAL_TIME_24H_FORMATS, VERTICAL_TIME_24H_FORMATS
|
|
15
16
|
from .params import HORIZONTAL_TIME_12H_FORMATS, VERTICAL_TIME_12H_FORMATS
|
|
17
|
+
from .params import TIMEZONE_DIFFERENCE_FORMAT
|
|
16
18
|
from .params import CLOX_VERSION, DATE_FORMAT
|
|
17
19
|
from .params import TIMEZONES_LIST, COUNTRIES_LIST
|
|
18
20
|
from .params import ADDITIONAL_INFO, EXIT_MESSAGE
|
|
@@ -21,50 +23,63 @@ from .params import HORIZONTAL_FACES_LIST_EXAMPLE, VERTICAL_FACES_LIST_EXAMPLE
|
|
|
21
23
|
from .params import CLOX_OVERVIEW, CLOX_REPO
|
|
22
24
|
|
|
23
25
|
|
|
24
|
-
def clox_info():
|
|
25
|
-
"""
|
|
26
|
-
Print clox details.
|
|
27
|
-
|
|
28
|
-
:return: None
|
|
29
|
-
"""
|
|
26
|
+
def clox_info() -> None:
|
|
27
|
+
"""Print clox details."""
|
|
30
28
|
tprint("Clox")
|
|
31
29
|
tprint("V:" + CLOX_VERSION)
|
|
32
30
|
print(CLOX_OVERVIEW)
|
|
33
31
|
print(CLOX_REPO)
|
|
34
32
|
|
|
35
33
|
|
|
36
|
-
def clear_screen():
|
|
37
|
-
"""
|
|
38
|
-
Clear screen function.
|
|
39
|
-
|
|
40
|
-
:return: None
|
|
41
|
-
"""
|
|
34
|
+
def clear_screen() -> None:
|
|
35
|
+
"""Clear screen function."""
|
|
42
36
|
if sys.platform == "win32":
|
|
43
37
|
os.system('cls')
|
|
44
38
|
else:
|
|
45
39
|
os.system('clear')
|
|
46
40
|
|
|
47
41
|
|
|
48
|
-
def get_face(index):
|
|
42
|
+
def get_face(index: int) -> str:
|
|
49
43
|
"""
|
|
50
44
|
Return face name.
|
|
51
45
|
|
|
52
46
|
:param index: face index
|
|
53
|
-
:type index: int
|
|
54
|
-
:return: face name as str
|
|
55
47
|
"""
|
|
56
48
|
if index == -1:
|
|
57
49
|
index = random.choice(sorted(FACES_MAP))
|
|
58
50
|
return FACES_MAP[index]
|
|
59
51
|
|
|
60
52
|
|
|
61
|
-
def
|
|
53
|
+
def get_timezone_difference(timezone: str) -> str:
|
|
54
|
+
"""
|
|
55
|
+
Return timezone difference.
|
|
56
|
+
|
|
57
|
+
:param timezone: timezone
|
|
58
|
+
"""
|
|
59
|
+
direction = "ahead"
|
|
60
|
+
tz = pytz.timezone(timezone)
|
|
61
|
+
datetime_now_timezone = datetime.datetime.now(tz=tz)
|
|
62
|
+
datetime_now_local = datetime.datetime.now()
|
|
63
|
+
difference = datetime_now_timezone - tz.localize(datetime_now_local)
|
|
64
|
+
total_minutes = difference.total_seconds() // 60
|
|
65
|
+
if total_minutes < 0:
|
|
66
|
+
direction = "behind"
|
|
67
|
+
total_minutes = abs(total_minutes)
|
|
68
|
+
if total_minutes == 0:
|
|
69
|
+
direction = "same"
|
|
70
|
+
hours = total_minutes // 60
|
|
71
|
+
minutes = total_minutes % 60
|
|
72
|
+
minutes = round(minutes / 15) * 15
|
|
73
|
+
formatted_difference = TIMEZONE_DIFFERENCE_FORMAT.format(
|
|
74
|
+
hours=int(hours), minutes=int(minutes), direction=direction)
|
|
75
|
+
return formatted_difference
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def show_faces_list(vertical: bool = False) -> None:
|
|
62
79
|
"""
|
|
63
80
|
Show faces list.
|
|
64
81
|
|
|
65
82
|
:param vertical: vertical mode flag
|
|
66
|
-
:type vertical: bool
|
|
67
|
-
:return: None
|
|
68
83
|
"""
|
|
69
84
|
mode = "Horizontal"
|
|
70
85
|
example = HORIZONTAL_FACES_LIST_EXAMPLE
|
|
@@ -78,13 +93,11 @@ def show_faces_list(vertical=False):
|
|
|
78
93
|
print('=' * 80)
|
|
79
94
|
|
|
80
95
|
|
|
81
|
-
def show_timezones_list(country=None):
|
|
96
|
+
def show_timezones_list(country: Optional[str] = None) -> None:
|
|
82
97
|
"""
|
|
83
98
|
Show timezones list.
|
|
84
99
|
|
|
85
100
|
:param country: country iso3166 code
|
|
86
|
-
:type country: str
|
|
87
|
-
:return: None
|
|
88
101
|
"""
|
|
89
102
|
timezones_list = TIMEZONES_LIST
|
|
90
103
|
country_name = "All"
|
|
@@ -99,12 +112,8 @@ def show_timezones_list(country=None):
|
|
|
99
112
|
print("{index}. {timezone}".format(index=index, timezone=timezone))
|
|
100
113
|
|
|
101
114
|
|
|
102
|
-
def show_countries_list():
|
|
103
|
-
"""
|
|
104
|
-
Show countries list.
|
|
105
|
-
|
|
106
|
-
:return: None
|
|
107
|
-
"""
|
|
115
|
+
def show_countries_list() -> None:
|
|
116
|
+
"""Show countries list."""
|
|
108
117
|
print("Countries list:\n")
|
|
109
118
|
for index, country_code in enumerate(sorted(COUNTRIES_LIST), 1):
|
|
110
119
|
country_name = pytz.country_names[country_code]
|
|
@@ -116,23 +125,22 @@ def show_countries_list():
|
|
|
116
125
|
country_code=country_code, country_name=country_code))
|
|
117
126
|
|
|
118
127
|
|
|
119
|
-
def print_calendar(
|
|
128
|
+
def print_calendar(
|
|
129
|
+
mode: str = "month",
|
|
130
|
+
timezone: Optional[str] = None,
|
|
131
|
+
country: Optional[str] = None,
|
|
132
|
+
v_shift: int = 0,
|
|
133
|
+
h_shift: int = 0,
|
|
134
|
+
date_system: str = "gregorian") -> None:
|
|
120
135
|
"""
|
|
121
136
|
Print calendar.
|
|
122
137
|
|
|
123
138
|
:param mode: calendar mode
|
|
124
|
-
:type mode: str
|
|
125
139
|
:param timezone: timezone
|
|
126
|
-
:type timezone: str
|
|
127
140
|
:param country: country iso3166 code
|
|
128
|
-
:type country: str
|
|
129
141
|
:param v_shift: vertical shift
|
|
130
|
-
:type v_shift: int
|
|
131
142
|
:param h_shift: horizontal shift
|
|
132
|
-
:type h_shift: int
|
|
133
143
|
:param date_system: date system
|
|
134
|
-
:type date_system: str
|
|
135
|
-
:return: None
|
|
136
144
|
"""
|
|
137
145
|
datetime_lib = datetime
|
|
138
146
|
calendar_obj = GregorianCalendar()
|
|
@@ -145,6 +153,8 @@ def print_calendar(mode="month", timezone=None, country=None, v_shift=0, h_shift
|
|
|
145
153
|
timezone = pytz.country_timezones(country)[0].upper()
|
|
146
154
|
if timezone is not None:
|
|
147
155
|
timezone_str = timezone
|
|
156
|
+
timezone_diff = get_timezone_difference(timezone=timezone)
|
|
157
|
+
timezone_str += " ({timezone_diff})".format(timezone_diff=timezone_diff)
|
|
148
158
|
tz = pytz.timezone(timezone)
|
|
149
159
|
v_shift = max(0, v_shift)
|
|
150
160
|
h_shift = max(0, h_shift)
|
|
@@ -162,43 +172,31 @@ def print_calendar(mode="month", timezone=None, country=None, v_shift=0, h_shift
|
|
|
162
172
|
|
|
163
173
|
|
|
164
174
|
def run_clock(
|
|
165
|
-
timezone=None,
|
|
166
|
-
country=None,
|
|
167
|
-
v_shift=0,
|
|
168
|
-
h_shift=0,
|
|
169
|
-
face=1,
|
|
170
|
-
no_blink=False,
|
|
171
|
-
vertical=False,
|
|
172
|
-
hide_date=False,
|
|
173
|
-
hide_timezone=False,
|
|
174
|
-
am_pm=False,
|
|
175
|
-
date_system="gregorian"):
|
|
175
|
+
timezone: Optional[str] = None,
|
|
176
|
+
country: Optional[str] = None,
|
|
177
|
+
v_shift: int = 0,
|
|
178
|
+
h_shift: int = 0,
|
|
179
|
+
face: int = 1,
|
|
180
|
+
no_blink: bool = False,
|
|
181
|
+
vertical: bool = False,
|
|
182
|
+
hide_date: bool = False,
|
|
183
|
+
hide_timezone: bool = False,
|
|
184
|
+
am_pm: bool = False,
|
|
185
|
+
date_system: str = "gregorian") -> None:
|
|
176
186
|
"""
|
|
177
187
|
Run clock.
|
|
178
188
|
|
|
179
189
|
:param timezone: timezone
|
|
180
|
-
:type timezone: str
|
|
181
190
|
:param country: country iso3166 code
|
|
182
|
-
:type country: str
|
|
183
191
|
:param v_shift: vertical shift
|
|
184
|
-
:type v_shift: int
|
|
185
192
|
:param h_shift: horizontal shift
|
|
186
|
-
:type h_shift: int
|
|
187
193
|
:param face: face index
|
|
188
|
-
:type face: int
|
|
189
194
|
:param no_blink: no-blink flag
|
|
190
|
-
:type no_blink: bool
|
|
191
195
|
:param vertical: vertical mode flag
|
|
192
|
-
:type vertical: bool
|
|
193
196
|
:param hide_date: hide date flag
|
|
194
|
-
:type hide_date: bool
|
|
195
197
|
:param hide_timezone: hide timezone flag
|
|
196
|
-
:type hide_timezone: bool
|
|
197
198
|
:param am_pm: AM/PM mode flag
|
|
198
|
-
:type am_pm: bool
|
|
199
199
|
:param date_system: date system
|
|
200
|
-
:type date_system: str
|
|
201
|
-
:return: None
|
|
202
200
|
"""
|
|
203
201
|
datetime_lib = datetime
|
|
204
202
|
if date_system == "jalali":
|
|
@@ -213,6 +211,8 @@ def run_clock(
|
|
|
213
211
|
timezone = pytz.country_timezones(country)[0].upper()
|
|
214
212
|
if timezone is not None:
|
|
215
213
|
timezone_str = timezone
|
|
214
|
+
timezone_diff = get_timezone_difference(timezone=timezone)
|
|
215
|
+
timezone_str += " ({timezone_diff})".format(timezone_diff=timezone_diff)
|
|
216
216
|
tz = pytz.timezone(timezone)
|
|
217
217
|
v_shift = max(0, v_shift)
|
|
218
218
|
h_shift = max(0, h_shift)
|
|
@@ -236,12 +236,8 @@ def run_clock(
|
|
|
236
236
|
format_index = int(not format_index)
|
|
237
237
|
|
|
238
238
|
|
|
239
|
-
def main():
|
|
240
|
-
"""
|
|
241
|
-
CLI main function.
|
|
242
|
-
|
|
243
|
-
:return: None
|
|
244
|
-
"""
|
|
239
|
+
def main() -> None:
|
|
240
|
+
"""CLI main function."""
|
|
245
241
|
parser = argparse.ArgumentParser()
|
|
246
242
|
parser.epilog = ADDITIONAL_INFO
|
|
247
243
|
parser.add_argument('--timezone', help='timezone', type=str.upper, choices=TIMEZONES_LIST)
|
clox/jcalendar.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
"""clox jalali calendar."""
|
|
3
3
|
# Reference: https://github.com/IKermani/jcalendar
|
|
4
|
+
from typing import List, Tuple, Generator
|
|
4
5
|
import datetime
|
|
5
6
|
from itertools import repeat
|
|
6
7
|
import jdatetime
|
|
@@ -13,7 +14,7 @@ error = ValueError
|
|
|
13
14
|
class IllegalMonthError(ValueError):
|
|
14
15
|
"""Illegal month error."""
|
|
15
16
|
|
|
16
|
-
def __init__(self, month):
|
|
17
|
+
def __init__(self, month: int) -> None:
|
|
17
18
|
"""Initiate."""
|
|
18
19
|
self.month = month
|
|
19
20
|
|
|
@@ -25,7 +26,7 @@ class IllegalMonthError(ValueError):
|
|
|
25
26
|
class IllegalWeekdayError(ValueError):
|
|
26
27
|
"""Illegal weekday error."""
|
|
27
28
|
|
|
28
|
-
def __init__(self, weekday):
|
|
29
|
+
def __init__(self, weekday: int) -> None:
|
|
29
30
|
"""Initiate."""
|
|
30
31
|
self.weekday = weekday
|
|
31
32
|
|
|
@@ -58,12 +59,12 @@ month_abbr = [0] + jdatetime.date.j_months_short_en
|
|
|
58
59
|
(DOSHANBE, SESHANBE, CHAHARSHANBE, PANJSHANBE, JOME, SHANBE, YEKSHANBE) = range(7)
|
|
59
60
|
|
|
60
61
|
|
|
61
|
-
def isleap(year):
|
|
62
|
+
def isleap(year: int) -> bool:
|
|
62
63
|
"""Return True for leap years, False for non-leap years."""
|
|
63
64
|
return jdatetime.date(year, 1, 1).isleap()
|
|
64
65
|
|
|
65
66
|
|
|
66
|
-
def leapdays(y1, y2):
|
|
67
|
+
def leapdays(y1: int, y2: int) -> int:
|
|
67
68
|
"""Return number of leap years in range [y1, y2)."""
|
|
68
69
|
leapdays = 0
|
|
69
70
|
|
|
@@ -74,14 +75,14 @@ def leapdays(y1, y2):
|
|
|
74
75
|
return leapdays
|
|
75
76
|
|
|
76
77
|
|
|
77
|
-
def weekday(year, month, day):
|
|
78
|
+
def weekday(year: int, month: int, day: int) -> int:
|
|
78
79
|
"""Return week-day (0-6 ~ Mon-Sun)."""
|
|
79
80
|
if not datetime.MINYEAR <= year <= datetime.MAXYEAR:
|
|
80
81
|
year = 2000 + year % 400
|
|
81
82
|
return jdatetime.date(year, month, day).weekday()
|
|
82
83
|
|
|
83
84
|
|
|
84
|
-
def monthrange(year, month):
|
|
85
|
+
def monthrange(year: int, month: int) -> Tuple[int, int]:
|
|
85
86
|
"""Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for year, month."""
|
|
86
87
|
if not 1 <= month <= 12:
|
|
87
88
|
raise IllegalMonthError(month)
|
|
@@ -90,12 +91,12 @@ def monthrange(year, month):
|
|
|
90
91
|
return day1, ndays
|
|
91
92
|
|
|
92
93
|
|
|
93
|
-
def _monthlen(year, month):
|
|
94
|
+
def _monthlen(year: int, month: int) -> int:
|
|
94
95
|
"""Return length of month."""
|
|
95
96
|
return mdays[month] + (month == Esfand and isleap(year))
|
|
96
97
|
|
|
97
98
|
|
|
98
|
-
def _prevmonth(year, month):
|
|
99
|
+
def _prevmonth(year: int, month: int) -> Tuple[int, int]:
|
|
99
100
|
"""Return previous month."""
|
|
100
101
|
if month == 1:
|
|
101
102
|
return year - 1, 12
|
|
@@ -103,7 +104,7 @@ def _prevmonth(year, month):
|
|
|
103
104
|
return year, month - 1
|
|
104
105
|
|
|
105
106
|
|
|
106
|
-
def _nextmonth(year, month):
|
|
107
|
+
def _nextmonth(year: int, month: int) -> Tuple[int, int]:
|
|
107
108
|
"""Return next month."""
|
|
108
109
|
if month == 12:
|
|
109
110
|
return year + 1, 1
|
|
@@ -111,34 +112,34 @@ def _nextmonth(year, month):
|
|
|
111
112
|
return year, month + 1
|
|
112
113
|
|
|
113
114
|
|
|
114
|
-
class Calendar
|
|
115
|
+
class Calendar:
|
|
115
116
|
"""Base calendar class. This class doesn't do any formatting. It simply provides data to subclasses."""
|
|
116
117
|
|
|
117
|
-
def __init__(self, firstweekday=0):
|
|
118
|
+
def __init__(self, firstweekday: int = 0) -> None:
|
|
118
119
|
"""Initiate."""
|
|
119
120
|
self.firstweekday = firstweekday # 0 = Doshanbe, 6 = Yekshanbe
|
|
120
121
|
|
|
121
|
-
def getfirstweekday(self):
|
|
122
|
+
def getfirstweekday(self) -> int:
|
|
122
123
|
"""Get first weekday."""
|
|
123
124
|
return self._firstweekday % 7
|
|
124
125
|
|
|
125
|
-
def setfirstweekday(self, firstweekday):
|
|
126
|
+
def setfirstweekday(self, firstweekday: int) -> None:
|
|
126
127
|
"""Set first weekday."""
|
|
127
128
|
self._firstweekday = firstweekday
|
|
128
129
|
|
|
129
130
|
firstweekday = property(getfirstweekday, setfirstweekday)
|
|
130
131
|
|
|
131
|
-
def iterweekdays(self):
|
|
132
|
+
def iterweekdays(self) -> Generator[int, None, None]:
|
|
132
133
|
"""Return an iterator for one week of weekday numbers starting with the configured first one."""
|
|
133
134
|
for i in range(self.firstweekday, self.firstweekday + 7):
|
|
134
135
|
yield i % 7
|
|
135
136
|
|
|
136
|
-
def itermonthdates(self, year, month):
|
|
137
|
+
def itermonthdates(self, year: int, month: int) -> Generator[jdatetime.date, None, None]:
|
|
137
138
|
"""Return an iterator for one month."""
|
|
138
139
|
for y, m, d in self.itermonthdays3(year, month):
|
|
139
140
|
yield jdatetime.date(y, m, d)
|
|
140
141
|
|
|
141
|
-
def itermonthdays(self, year, month):
|
|
142
|
+
def itermonthdays(self, year: int, month: int) -> Generator[int, None, None]:
|
|
142
143
|
"""Like itermonthdates(), but will yield day numbers. For days outside the specified month the day number is 0."""
|
|
143
144
|
day1, ndays = monthrange(year, month)
|
|
144
145
|
days_before = (day1 - self.firstweekday) % 7
|
|
@@ -147,12 +148,12 @@ class Calendar(object):
|
|
|
147
148
|
days_after = (self.firstweekday - day1 - ndays) % 7
|
|
148
149
|
yield from repeat(0, days_after)
|
|
149
150
|
|
|
150
|
-
def itermonthdays2(self, year, month):
|
|
151
|
+
def itermonthdays2(self, year: int, month: int) -> Generator[Tuple[int, int], None, None]:
|
|
151
152
|
"""Like itermonthdates(), but will yield (day number, weekday number) tuples. For days outside the specified month the day number is 0."""
|
|
152
153
|
for i, d in enumerate(self.itermonthdays(year, month), self.firstweekday):
|
|
153
154
|
yield d, i % 7
|
|
154
155
|
|
|
155
|
-
def itermonthdays3(self, year, month):
|
|
156
|
+
def itermonthdays3(self, year: int, month: int) -> Generator[Tuple[int, int, int], None, None]:
|
|
156
157
|
"""Like itermonthdates(), but will yield (year, month, day) tuples. Can be used for dates outside of datetime.date range."""
|
|
157
158
|
day1, ndays = monthrange(year, month)
|
|
158
159
|
days_before = (day1 - self.firstweekday) % 7
|
|
@@ -167,27 +168,27 @@ class Calendar(object):
|
|
|
167
168
|
for d in range(1, days_after + 1):
|
|
168
169
|
yield y, m, d
|
|
169
170
|
|
|
170
|
-
def itermonthdays4(self, year, month):
|
|
171
|
+
def itermonthdays4(self, year: int, month: int) -> Generator[Tuple[int, int, int, int], None, None]:
|
|
171
172
|
"""Like itermonthdates(), but will yield (year, month, day, day_of_week) tuples. Can be used for dates outside of datetime.date range."""
|
|
172
173
|
for i, (y, m, d) in enumerate(self.itermonthdays3(year, month)):
|
|
173
174
|
yield y, m, d, (self.firstweekday + i) % 7
|
|
174
175
|
|
|
175
|
-
def monthdatescalendar(self, year, month):
|
|
176
|
+
def monthdatescalendar(self, year: int, month: int) -> List[List[jdatetime.date]]:
|
|
176
177
|
"""Return a matrix (list of lists) representing a month's calendar.Each row represents a week; week entries are datetime.date values."""
|
|
177
178
|
dates = list(self.itermonthdates(year, month))
|
|
178
179
|
return [dates[i:i + 7] for i in range(0, len(dates), 7)]
|
|
179
180
|
|
|
180
|
-
def monthdays2calendar(self, year, month):
|
|
181
|
+
def monthdays2calendar(self, year: int, month: int) -> List[List[Tuple[int, int]]]:
|
|
181
182
|
"""Return a matrix representing a month's calendar."""
|
|
182
183
|
days = list(self.itermonthdays2(year, month))
|
|
183
184
|
return [days[i:i + 7] for i in range(0, len(days), 7)]
|
|
184
185
|
|
|
185
|
-
def monthdayscalendar(self, year, month):
|
|
186
|
+
def monthdayscalendar(self, year: int, month: int) -> List[List[int]]:
|
|
186
187
|
"""Return a matrix representing a month's calendar."""
|
|
187
188
|
days = list(self.itermonthdays(year, month))
|
|
188
189
|
return [days[i:i + 7] for i in range(0, len(days), 7)]
|
|
189
190
|
|
|
190
|
-
def yeardatescalendar(self, year, width=3):
|
|
191
|
+
def yeardatescalendar(self, year: int, width: int = 3) -> List[List[List[List[jdatetime.date]]]]:
|
|
191
192
|
"""Return the data for the specified year ready for formatting."""
|
|
192
193
|
months = [
|
|
193
194
|
self.monthdatescalendar(year, i)
|
|
@@ -195,7 +196,7 @@ class Calendar(object):
|
|
|
195
196
|
]
|
|
196
197
|
return [months[i:i + width] for i in range(0, len(months), width)]
|
|
197
198
|
|
|
198
|
-
def yeardays2calendar(self, year, width=3):
|
|
199
|
+
def yeardays2calendar(self, year: int, width: int = 3) -> List[List[List[List[Tuple[int, int]]]]]:
|
|
199
200
|
"""Return the data for the specified year ready for formatting."""
|
|
200
201
|
months = [
|
|
201
202
|
self.monthdays2calendar(year, i)
|
|
@@ -203,7 +204,7 @@ class Calendar(object):
|
|
|
203
204
|
]
|
|
204
205
|
return [months[i:i + width] for i in range(0, len(months), width)]
|
|
205
206
|
|
|
206
|
-
def yeardayscalendar(self, year, width=3):
|
|
207
|
+
def yeardayscalendar(self, year: int, width: int = 3) -> List[List[List[int]]]:
|
|
207
208
|
"""Return the data for the specified year ready for formatting."""
|
|
208
209
|
months = [
|
|
209
210
|
self.monthdayscalendar(year, i)
|
|
@@ -215,11 +216,11 @@ class Calendar(object):
|
|
|
215
216
|
class TextCalendar(Calendar):
|
|
216
217
|
"""Subclass of Calendar that outputs a calendar as a simple plain text similar to the UNIX program cal."""
|
|
217
218
|
|
|
218
|
-
def prweek(self, theweek, width):
|
|
219
|
+
def prweek(self, theweek: List[Tuple[int, int]], width: int) -> None:
|
|
219
220
|
"""Print a single week (no newline)."""
|
|
220
221
|
print(self.formatweek(theweek, width), end='')
|
|
221
222
|
|
|
222
|
-
def formatday(self, day
|
|
223
|
+
def formatday(self, day: int, width: int) -> str:
|
|
223
224
|
"""Return a formatted day."""
|
|
224
225
|
if day == 0:
|
|
225
226
|
s = ''
|
|
@@ -227,11 +228,11 @@ class TextCalendar(Calendar):
|
|
|
227
228
|
s = '%2i' % day # right-align single-digit days
|
|
228
229
|
return s.center(width)
|
|
229
230
|
|
|
230
|
-
def formatweek(self, theweek, width):
|
|
231
|
+
def formatweek(self, theweek: List[Tuple[int, int]], width: int) -> str:
|
|
231
232
|
"""Return a single week in a string (no newline)."""
|
|
232
|
-
return ' '.join(self.formatday(d,
|
|
233
|
+
return ' '.join(self.formatday(d, width) for d, _ in theweek)
|
|
233
234
|
|
|
234
|
-
def formatweekday(self, day, width):
|
|
235
|
+
def formatweekday(self, day: int, width: int) -> str:
|
|
235
236
|
"""Return a formatted week day name."""
|
|
236
237
|
if width >= 9:
|
|
237
238
|
names = day_name
|
|
@@ -239,22 +240,22 @@ class TextCalendar(Calendar):
|
|
|
239
240
|
names = day_abbr
|
|
240
241
|
return names[day][:width].center(width)
|
|
241
242
|
|
|
242
|
-
def formatweekheader(self, width):
|
|
243
|
+
def formatweekheader(self, width: int) -> str:
|
|
243
244
|
"""Return a header for a week."""
|
|
244
245
|
return ' '.join(self.formatweekday(i, width) for i in self.iterweekdays())
|
|
245
246
|
|
|
246
|
-
def formatmonthname(self, theyear, themonth, width, withyear=True):
|
|
247
|
+
def formatmonthname(self, theyear: int, themonth: int, width: int, withyear: bool = True) -> str:
|
|
247
248
|
"""Return a formatted month name."""
|
|
248
249
|
s = month_name[themonth]
|
|
249
250
|
if withyear:
|
|
250
251
|
s = "%s %r" % (s, theyear)
|
|
251
252
|
return s.center(width)
|
|
252
253
|
|
|
253
|
-
def prmonth(self, theyear, themonth, w=0, l=0):
|
|
254
|
+
def prmonth(self, theyear: int, themonth: int, w: int = 0, l: int = 0) -> None:
|
|
254
255
|
"""Print a month's calendar."""
|
|
255
256
|
print(self.formatmonth(theyear, themonth, w, l), end='')
|
|
256
257
|
|
|
257
|
-
def formatmonth(self, theyear, themonth, w=0, l=0):
|
|
258
|
+
def formatmonth(self, theyear: int, themonth: int, w: int = 0, l: int = 0) -> str:
|
|
258
259
|
"""Return a month's calendar string (multi-line)."""
|
|
259
260
|
w = max(2, w)
|
|
260
261
|
l = max(1, l)
|
|
@@ -268,7 +269,7 @@ class TextCalendar(Calendar):
|
|
|
268
269
|
s += '\n' * l
|
|
269
270
|
return s
|
|
270
271
|
|
|
271
|
-
def formatyear(self, theyear, w=2, l=1, c=6, m=3):
|
|
272
|
+
def formatyear(self, theyear: int, w: int = 2, l: int = 1, c: int = 6, m: int = 3) -> str:
|
|
272
273
|
"""Return a year's calendar as a multi-line string."""
|
|
273
274
|
w = max(2, w)
|
|
274
275
|
l = max(1, l)
|
|
@@ -303,7 +304,7 @@ class TextCalendar(Calendar):
|
|
|
303
304
|
a('\n' * l)
|
|
304
305
|
return ''.join(v)
|
|
305
306
|
|
|
306
|
-
def pryear(self, theyear, w=0, l=0, c=6, m=3):
|
|
307
|
+
def pryear(self, theyear: int, w: int = 0, l: int = 0, c: int = 6, m: int = 3) -> None:
|
|
307
308
|
"""Print a year's calendar."""
|
|
308
309
|
print(self.formatyear(theyear, w, l, c, m), end='')
|
|
309
310
|
|
|
@@ -313,7 +314,7 @@ c = TextCalendar()
|
|
|
313
314
|
firstweekday = c.getfirstweekday
|
|
314
315
|
|
|
315
316
|
|
|
316
|
-
def setfirstweekday(firstweekday):
|
|
317
|
+
def setfirstweekday(firstweekday: int) -> None:
|
|
317
318
|
"""Set first weekday."""
|
|
318
319
|
if not DOSHANBE <= firstweekday <= YEKSHANBE:
|
|
319
320
|
raise IllegalWeekdayError(firstweekday)
|
|
@@ -334,12 +335,12 @@ _colwidth = 7 * 3 - 1 # Amount printed by prweek()
|
|
|
334
335
|
_spacing = 6 # Number of spaces between columns
|
|
335
336
|
|
|
336
337
|
|
|
337
|
-
def format(cols, colwidth=_colwidth, spacing=_spacing):
|
|
338
|
+
def format(cols: List[str], colwidth: int = _colwidth, spacing: int = _spacing) -> None:
|
|
338
339
|
"""Print multi-column formatting for year calendars."""
|
|
339
340
|
print(formatstring(cols, colwidth, spacing))
|
|
340
341
|
|
|
341
342
|
|
|
342
|
-
def formatstring(cols, colwidth=_colwidth, spacing=_spacing):
|
|
343
|
+
def formatstring(cols: List[str], colwidth: int = _colwidth, spacing: int = _spacing) -> str:
|
|
343
344
|
"""Return a string formatted from n strings, centered within n columns."""
|
|
344
345
|
spacing *= ' '
|
|
345
346
|
return spacing.join(c.center(colwidth) for c in cols)
|
|
@@ -349,7 +350,7 @@ EPOCH = 1970
|
|
|
349
350
|
_EPOCH_ORD = jdatetime.date(EPOCH, 1, 1).toordinal()
|
|
350
351
|
|
|
351
352
|
|
|
352
|
-
def timegm(tuple):
|
|
353
|
+
def timegm(tuple: Tuple) -> int:
|
|
353
354
|
"""Unrelated but handy function to calculate Unix timestamp from GMT."""
|
|
354
355
|
year, month, day, hour, minute, second = tuple[:6]
|
|
355
356
|
days = jdatetime.date(year, month, 1).toordinal() - _EPOCH_ORD + day - 1
|
clox/params.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"""clox params."""
|
|
3
3
|
import pytz
|
|
4
4
|
|
|
5
|
-
CLOX_VERSION = "0.
|
|
5
|
+
CLOX_VERSION = "0.9"
|
|
6
6
|
|
|
7
7
|
CLOX_OVERVIEW = '''
|
|
8
8
|
Clox is a terminal-based clock application designed for terminal enthusiasts who appreciate simplicity,
|
|
@@ -23,6 +23,7 @@ VERTICAL_TIME_24H_FORMATS = ['%H\n%M', '%H\n%M.']
|
|
|
23
23
|
HORIZONTAL_TIME_12H_FORMATS = ['%I:%M %p', '%I:%M %p.']
|
|
24
24
|
VERTICAL_TIME_12H_FORMATS = ['%I\n%M\n%p', '%I\n%M\n%p.']
|
|
25
25
|
DATE_FORMAT = "%A, %B %d, %Y"
|
|
26
|
+
TIMEZONE_DIFFERENCE_FORMAT = "{hours:02}h{minutes:02}m {direction}"
|
|
26
27
|
|
|
27
28
|
TIMEZONES_LIST = list(map(lambda x: x.upper(), pytz.all_timezones))
|
|
28
29
|
COUNTRIES_LIST = list(map(lambda x: x.upper(), pytz.country_timezones.keys()))
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: clox
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9
|
|
4
4
|
Summary: A Geeky Clock for Terminal Enthusiasts
|
|
5
5
|
Home-page: https://github.com/sepandhaghighi/clox
|
|
6
|
-
Download-URL: https://github.com/sepandhaghighi/clox/tarball/v0.
|
|
6
|
+
Download-URL: https://github.com/sepandhaghighi/clox/tarball/v0.9
|
|
7
7
|
Author: Sepand Haghighi
|
|
8
8
|
Author-email: me@sepand.tech
|
|
9
9
|
License: MIT
|
|
@@ -13,7 +13,6 @@ Classifier: Development Status :: 4 - Beta
|
|
|
13
13
|
Classifier: Natural Language :: English
|
|
14
14
|
Classifier: License :: OSI Approved :: MIT License
|
|
15
15
|
Classifier: Operating System :: OS Independent
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.7
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.8
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.9
|
|
@@ -27,7 +26,7 @@ Classifier: Intended Audience :: End Users/Desktop
|
|
|
27
26
|
Classifier: Intended Audience :: Other Audience
|
|
28
27
|
Classifier: Topic :: Games/Entertainment
|
|
29
28
|
Classifier: Topic :: Utilities
|
|
30
|
-
Requires-Python: >=3.
|
|
29
|
+
Requires-Python: >=3.7
|
|
31
30
|
Description-Content-Type: text/markdown
|
|
32
31
|
License-File: LICENSE
|
|
33
32
|
License-File: AUTHORS.md
|
|
@@ -43,6 +42,7 @@ Dynamic: download-url
|
|
|
43
42
|
Dynamic: home-page
|
|
44
43
|
Dynamic: keywords
|
|
45
44
|
Dynamic: license
|
|
45
|
+
Dynamic: license-file
|
|
46
46
|
Dynamic: project-url
|
|
47
47
|
Dynamic: requires-dist
|
|
48
48
|
Dynamic: requires-python
|
|
@@ -104,13 +104,13 @@ Clox is a terminal-based clock application designed for terminal enthusiasts who
|
|
|
104
104
|
## Installation
|
|
105
105
|
|
|
106
106
|
### Source Code
|
|
107
|
-
- Download [Version 0.
|
|
107
|
+
- Download [Version 0.9](https://github.com/sepandhaghighi/clox/archive/v0.9.zip) or [Latest Source](https://github.com/sepandhaghighi/clox/archive/dev.zip)
|
|
108
108
|
- `pip install .`
|
|
109
109
|
|
|
110
110
|
### PyPI
|
|
111
111
|
|
|
112
112
|
- Check [Python Packaging User Guide](https://packaging.python.org/installing/)
|
|
113
|
-
- `pip install clox==0.
|
|
113
|
+
- `pip install clox==0.9`
|
|
114
114
|
|
|
115
115
|
|
|
116
116
|
## Usage
|
|
@@ -292,6 +292,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
|
292
292
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
293
293
|
|
|
294
294
|
## [Unreleased]
|
|
295
|
+
## [0.9] - 2025-04-14
|
|
296
|
+
### Added
|
|
297
|
+
- Timezone difference
|
|
298
|
+
### Changed
|
|
299
|
+
- Python typing features added to all modules
|
|
300
|
+
- Test system modified
|
|
301
|
+
- `Python 3.6` support dropped
|
|
295
302
|
## [0.8] - 2025-03-16
|
|
296
303
|
### Added
|
|
297
304
|
- `--country` argument
|
|
@@ -345,7 +352,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
345
352
|
- `TIMEZONES.md`
|
|
346
353
|
- `FACES.md`
|
|
347
354
|
|
|
348
|
-
[Unreleased]: https://github.com/sepandhaghighi/clox/compare/v0.
|
|
355
|
+
[Unreleased]: https://github.com/sepandhaghighi/clox/compare/v0.9...dev
|
|
356
|
+
[0.9]: https://github.com/sepandhaghighi/clox/compare/v0.8...v0.9
|
|
349
357
|
[0.8]: https://github.com/sepandhaghighi/clox/compare/v0.7...v0.8
|
|
350
358
|
[0.7]: https://github.com/sepandhaghighi/clox/compare/v0.6...v0.7
|
|
351
359
|
[0.6]: https://github.com/sepandhaghighi/clox/compare/v0.5...v0.6
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
clox/__init__.py,sha256=gErclFSjUDschQpngWqOBGkBKt1jwd-Ww8B9iJmlU5s,108
|
|
2
|
+
clox/__main__.py,sha256=9oJYc1WXu4ZMrjKny_2-4Cgu46-VWHuE9xOqD1iJY0E,109
|
|
3
|
+
clox/functions.py,sha256=E5-nMw4OlASGsuSUO3TvoD3J2E1y7QFsz5cVAwYOF5M,10838
|
|
4
|
+
clox/jcalendar.py,sha256=RvtTikECGI4LjDSi5qbJF9grz7to2__fgR98xnnvme8,13462
|
|
5
|
+
clox/params.py,sha256=fUTq-i9Lr2oHj7mwXvuW9NaBjWmou0MTiEqcdNR0wg4,1722
|
|
6
|
+
clox-0.9.dist-info/licenses/AUTHORS.md,sha256=lmtnd18MnfgB57jdvfJbC0JHN3iARf2Ov4pY5kPGJC8,242
|
|
7
|
+
clox-0.9.dist-info/licenses/LICENSE,sha256=WoAsqqZ_lNVBGdyxjwh7YnVNXKfOB-qYVrRhrn-e-_4,1072
|
|
8
|
+
clox-0.9.dist-info/METADATA,sha256=pGZb1PCNl_wmayj6H6FzfdFjU1DoJNdBukRAG3Yx1RM,9713
|
|
9
|
+
clox-0.9.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
10
|
+
clox-0.9.dist-info/entry_points.txt,sha256=sP4Rmoe-DxYGjlF_Tld6nghbt_u-fK8h9ZUQFmO8TJs,45
|
|
11
|
+
clox-0.9.dist-info/top_level.txt,sha256=5DxGH-4VNfYkM8vbfngObh6-jpFEoSW4M90EvDGfhSw,5
|
|
12
|
+
clox-0.9.dist-info/RECORD,,
|
clox-0.8.dist-info/RECORD
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
clox/__init__.py,sha256=gErclFSjUDschQpngWqOBGkBKt1jwd-Ww8B9iJmlU5s,108
|
|
2
|
-
clox/__main__.py,sha256=9oJYc1WXu4ZMrjKny_2-4Cgu46-VWHuE9xOqD1iJY0E,109
|
|
3
|
-
clox/functions.py,sha256=rHrWxzW0NxARlaKaUlO-TXEPyhEG1MQ0jctDxBe192I,10008
|
|
4
|
-
clox/jcalendar.py,sha256=yAzuyXq6h8D5aJG_He_WuPR8Xy411W_l7pl8mtPJa5U,12296
|
|
5
|
-
clox/params.py,sha256=8rlLAfUv3nHNVh5cSsH_1O1aNQoDAgmyKxiTkqV8f54,1654
|
|
6
|
-
clox-0.8.dist-info/AUTHORS.md,sha256=lmtnd18MnfgB57jdvfJbC0JHN3iARf2Ov4pY5kPGJC8,242
|
|
7
|
-
clox-0.8.dist-info/LICENSE,sha256=WoAsqqZ_lNVBGdyxjwh7YnVNXKfOB-qYVrRhrn-e-_4,1072
|
|
8
|
-
clox-0.8.dist-info/METADATA,sha256=-c6IkxbwAxVIm0VY_MU9GICTe9v6xrtErvXEMHOr0iw,9509
|
|
9
|
-
clox-0.8.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
|
|
10
|
-
clox-0.8.dist-info/entry_points.txt,sha256=sP4Rmoe-DxYGjlF_Tld6nghbt_u-fK8h9ZUQFmO8TJs,45
|
|
11
|
-
clox-0.8.dist-info/top_level.txt,sha256=5DxGH-4VNfYkM8vbfngObh6-jpFEoSW4M90EvDGfhSw,5
|
|
12
|
-
clox-0.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|