PK!prevenger/__init__.pyPK!F.66prevenger/cache/__init__.py""" FILE Cache FIFO LFU LRU TIMED CACHE WeakCache """ PK!<ƅ prevenger/cli.pyimport sys import click import click_completion import crayons from click_didyoumean import DYMCommandCollection from prevenger.kit.captcha_kit import create_wheezy_captcha from prevenger.kit.rand_kit import rand_letters_digits click_completion.init() CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"]) class PrevengerGroup(click.Group): def get_help_option(self, ctx): help_options = self.get_help_option_names(ctx) def show_help(ctx, param, value): click.echo(ctx.get_help(), color=ctx.color) return click.Option( help_options, is_flag=True, is_eager=True, expose_value=False, callback=show_help, help="Show this message and exit.", ) def setup_verbose(ctx, param, value): if value: import logging logging.getLogger("requests").setLevel(logging.INFO) return value @click.group( cls=PrevengerGroup, invoke_without_command=True, context_settings=CONTEXT_SETTINGS ) @click.option("-v", "--verbose", is_flag=True, help="Enables verbose mode.") @click.version_option(prog_name=crayons.white("prevenger", bold=True)) @click.pass_context def cli(ctx, verbose): """ The Must-Have Utils For Every Pythonista 2018 - 2019. """ ctx.verbose = verbose @click.command( short_help="execute python and then enter ipython", context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), ) def run(): click.echo("is executing") pass @click.command( short_help="self testing", context_settings=dict(ignore_unknown_options=True, allow_extra_args=True), ) def self_test(): click.echo("is self test") """使用REQUESTS请求某个地址,跳转到IPython便于下一步解析.""" all_colors = "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white" for color in all_colors: click.echo(click.style("I am colored %s" % color, fg=color)) for color in all_colors: click.echo(click.style("I am colored %s and bold" % color, fg=color, bold=True)) for color in all_colors: click.echo( click.style("I am reverse colored %s" % color, fg=color, reverse=True) ) click.echo(click.style("I am blinking", blink=True)) click.echo(click.style("I am underlined", underline=True)) args_str = ["-s"] import pytest pytest.cmdline.main(args_str) @click.command( short_help="create wheezy captcha", ) @click.option("--f", default=".", help="make captcha.") def captcha(f="."): chars = rand_letters_digits(5) create_wheezy_captcha(chars).save(f"{f}/captcha.png") @click.command() def touch(f): click.echo(click.format_filename(f)) # Install click commands. cli.add_command(self_test) cli.add_command(captcha) if "-" not in "".join(sys.argv) and len(sys.argv) > 1: cli = DYMCommandCollection(sources=[cli]) def main(): cli() if __name__ == "__main__": main() PK!prevenger/crypto/__init__.pyPK!prevenger/gen/__init__.pyPK! z.SSprevenger/inspector/__init__.pyimport inspect def get_function_args(f): return inspect.getfullargspec(f)[0] PK!prevenger/kit/__init__.pyPK! prevenger/kit/bloomfilter_kit.pyPK!{"Vprevenger/kit/captcha_kit.py""" port from: https://bitbucket.org/akorn/wheezy.captcha Copyright (C) 2011 by Andriy Kornatskyy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ import os import random from PIL import Image from PIL import ImageFilter from PIL.ImageColor import getrgb from PIL.ImageDraw import Draw from PIL.ImageFont import truetype T_SEQUENCE = tuple([t / 20.0 for t in range(21)]) beziers = {} def pascal_row(n): """ Returns n-th row of Pascal's triangle """ result = [1] x, numerator = 1, n for denominator in range(1, n // 2 + 1): x *= numerator x /= denominator result.append(x) numerator -= 1 if n & 1 == 0: result.extend(reversed(result[:-1])) else: result.extend(reversed(result)) return result def make_bezier(n): """ Bezier curves: http://en.wikipedia.org/wiki/B%C3%A9zier_curve#Generalization """ try: return beziers[n] except KeyError: combinations = pascal_row(n - 1) result = [] for t in T_SEQUENCE: tpowers = (t ** i for i in range(n)) upowers = ((1 - t) ** i for i in range(n - 1, -1, -1)) coefs = [c * a * b for c, a, b in zip(combinations, tpowers, upowers)] result.append(coefs) beziers[n] = result return result def captcha(drawings, width=200, height=75): def render(text): image = Image.new("RGB", (width, height), (255, 255, 255)) for drawing in drawings: image = drawing(image, text) assert image return image return render # region: captcha drawers def background(color="#EEEECC"): color = getrgb(color) def drawer(image, text): Draw(image).rectangle([(0, 0), image.size], fill=color) return image return drawer def smooth_filter(): def drawer(image, text): return image.filter(ImageFilter.SMOOTH) return drawer def curve_filter(color="#5C87B2", width=4, number=6): if not callable(color): c = getrgb(color) def color(): return c def drawer(image, text): dx, height = image.size dx = dx / number path = [(dx * i, random.randint(0, height)) for i in range(1, number)] bcoefs = make_bezier(number - 1) points = [] for coefs in bcoefs: points.append( tuple( sum([coef * p for coef, p in zip(coefs, ps)]) for ps in zip(*path) ) ) draw = Draw(image) draw.line(points, fill=color(), width=width) return image return drawer def noise_filter(number=50, color="#EEEECC", level=2): if not callable(color): c = getrgb(color) def color(): return c def drawer(image, text): width, height = image.size dx = width / 10 width = width - dx dy = height / 10 height = height - dy draw = Draw(image) for i in range(number): x = int(random.uniform(dx, width)) y = int(random.uniform(dy, height)) draw.line(((x, y), (x + level, y)), fill=color(), width=level) return image return drawer def draw_chars(fonts, font_sizes=None, drawings=None, color="#5C87B2", squeeze_factor=0.8): fonts = tuple( [truetype(name, size) for name in fonts for size in font_sizes or (65, 70, 75)] ) if not callable(color): c = getrgb(color) def color(): return c def drawer(image, chars): draw = Draw(image) char_images = [] for c in chars: font = random.choice(fonts) c_width, c_height = draw.textsize(c, font=font) char_image = Image.new("RGB", (c_width, c_height), (0, 0, 0)) char_draw = Draw(char_image) char_draw.text((0, 0), c, font=font, fill=color()) char_image = char_image.crop(char_image.getbbox()) for drawing in drawings: char_image = drawing(char_image, c) char_images.append(char_image) width, height = image.size offset = int( ( width - sum(int(i.size[0] * squeeze_factor) for i in char_images[:-1]) - char_images[-1].size[0] ) / 2 ) for char_image in char_images: c_width, c_height = char_image.size mask = char_image.convert("L").point(lambda i: i * 1.97) image.paste(char_image, (offset, int((height - c_height) / 2)), mask) offset += int(c_width * squeeze_factor) return image return drawer # region: text drawers def warp_filter(dx_factor=0.27, dy_factor=0.21): def drawer(image, text): width, height = image.size dx = width * dx_factor dy = height * dy_factor x1 = int(random.uniform(-dx, dx)) y1 = int(random.uniform(-dy, dy)) x2 = int(random.uniform(-dx, dx)) y2 = int(random.uniform(-dy, dy)) image2 = Image.new( "RGB", (width + abs(x1) + abs(x2), height + abs(y1) + abs(y2)) ) image2.paste(image, (abs(x1), abs(y1))) width2, height2 = image2.size return image2.transform( (width, height), Image.QUAD, (x1, y1, -x1, height2 - y2, width2 + x2, height2 + y2, width2 - x2, -y1), ) return drawer def offset_filter(dx_factor=0.1, dy_factor=0.2): def drawer(image, text): width, height = image.size dx = int(random.random() * width * dx_factor) dy = int(random.random() * height * dy_factor) image2 = Image.new("RGB", (width + dx, height + dy)) image2.paste(image, (dx, dy)) return image2 return drawer def rotate_filter(angle=25): def drawer(image, text): return image.rotate(random.uniform(-angle, angle), Image.BILINEAR, expand=1) return drawer def create_wheezy_captcha(chars, width: int = 200, height: int = 75) -> Image: default_font_path = os.path.dirname(os.path.dirname(__file__)) + "/assets/helvetica.ttf" captcha_image = captcha( drawings=[ background(), draw_chars( fonts=[default_font_path], drawings=[warp_filter(), rotate_filter(), offset_filter()], ), curve_filter(), noise_filter(), smooth_filter(), ], width=width, height=height, ) image = captcha_image(chars) return image PK![T%prevenger/kit/dfa_kit.py""" @Author: twocucao @Email: twocucao@gmail.com @Date: 2016-09-19 @Desc: 常用正则表达式,用于抽取/验证/替换 是整数? 是小数? 是QQ? 是日期? 是链接? 是IP? 银行卡? 电子邮箱? 其他 参考实现: https://github.com/madisonmay/CommonRegex/blob/master/commonregex.py http://blog.jobbole.com/96052/ """ import re PT_CHINESE = "([\u4e00-\u9fa5]+)+?" PT_CHINESE_AND_NUMBER = "([\u4e00-\u9fa5\d\w]+)+?" PT_CLEAN_WORDS = "([\u4e00-\u9fa5\d\s\a\w]+)+?" PT_CHINESE_ID_CARD = r"([0-9]){7,18}(x|X)?" PT_CHINESE_MOB_NUM = ( r"(?:13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}" ) # noqa PT_CHINESE_TELEPHONE = r"\d{3}-\d{8}|\d{4}-\d{7}" PT_CHINESE_MONEY = r"¥\s*\d+" PT_CHINESE_PRICE = r"[$]\s?[+-]?[0-9]{1,3}(?:(?:,?[0-9]{3}))*(?:\.[0-9]{1,2})?" PT_CHINESE_SETENCE = r"[\u4e00-\u9fa5]{1,}" PT_DATE = r"" PT_DATETIME = r"" PT_DOMAIN = ( r"[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?" ) # noqa PT_EMAIL = r"([a-z0-9!#$%&'*+\/=?^_`{|.}~-]+@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)" # noqa PT_HEX_COLOR = r"(#(?:[0-9a-fA-F]{8})|#(?:[0-9a-fA-F]{3}){1,2})\\b" PT_HTTP_HTTPS_LINK = r"" PT_INT_NUM = r"[0-9]*" PT_IP_V4 = r"(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" # noqa PT_IP_V6 = r"\s*(?!.*::.*::)(?:(?!:)|:(?=:))(?:[0-9a-f]{0,4}(?:(?<=::)|(?", '"', '"'] def sub_chinese_punctuations(_str): """ :param _str: :return: """ for k, v in zip(ch_puncs, en_puncs): _str = _str.replace(k, v) return _str def shrink_repeated4bilibili(_str, word_len=20): """ :param _str: :param max_times: :param word_len: :return: """ _str = re.sub(r"\s+", " ", _str) for i in range(1, word_len + 1): if i <= 3: max_times = 3 elif i <= 5: max_times = 2 else: max_times = 1 _str = shrink_repeated_with_len(_str, max_times=max_times, word_len=i) return _str def shrink_repeated(_str, max_times=3, word_len=20): """ :param _str: :param max_times: :param word_len: :return: """ _str = re.sub(r"\s+", " ", _str) for i in range(1, word_len + 1): _str = shrink_repeated_with_len(_str, max_times=max_times, word_len=i) return _str def shrink_repeated_with_len(_str, max_times=3, word_len=3): """ :param _str: :param max_times: :param word_len: n 为支持的字符串长度 n 为 3 ,max_times 为3的时候 周杰伦周杰伦周杰伦周杰伦周杰伦 -> 周杰伦周杰伦周杰伦 :return: """ pat = r"(" + r"." * word_len + r")\1{%d,}" % max_times repl = r"".join([r"\1" for i in range(max_times)]) return re.sub(pat, repl, _str) def shrink_online_rent(_str): _str = sub_chinese_punctuations(_str) _str = shrink_repeated(_str, 4) return _str """ 这是对HTML文本处理的一些常见的方案,主要是通过BeautifulSoup实现,主要用户处理常见的一些HTML处理和提取. """ def html_escape_chars_to_string(_str): return ( _str if is_empty(_str) else _str.replace("<", "<") .replace(">", ">") .replace("&", "&") .replace(""", '"') ) def extract_links_from_html(_str): raise NotImplementedError() return "" def shrink_string(_str, strip_chars=None, nullable=True): """ :param _str: :param nullable: :param strip_chars: :return: """ if isinstance(_str, str): if strip_chars is None: return _str.strip() else: return _str.strip(strip_chars) if nullable: return None else: return "" def restrip_or_none(_str, strips=" ", replaces=""): if isinstance(_str, str): _str = _str.strip(strips + " ").replace(replaces, "") if len(_str) == 0: return None return _str else: return None def half_width_to_full_width(_str): raise NotImplementedError return _str def full_width_to_half_width(_str): raise NotImplementedError return _str chinese_digits_mapping = { "零": 0, "一": 1, "二": 2, "三": 3, "四": 4, "五": 5, "六": 6, "七": 7, "八": 8, "九": 9, "十": 10, "百": 100, "千": 1000, "万": 10000, "0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9, "壹": 1, "贰": 2, "叁": 3, "肆": 4, "伍": 5, "陆": 6, "柒": 7, "捌": 8, "玖": 9, "拾": 10, "佰": 100, "仟": 1000, "萬": 10000, "亿": 100000000, } def get_digits_from_chinese(a): """ :param a: :return: author: binux(17175297.hk@gmail.com) modified by: twocucao """ count = 0 result = 0 tmp = 0 Billion = 0 while count < len(a): tmpChr = a[count] # print(tmpChr) tmpNum = chinese_digits_mapping.get(tmpChr, None) # 如果等于1亿 if tmpNum == 100000000: result += tmp result = result * tmpNum # 获得亿以上的数量,将其保存在中间变量Billion中并清空result Billion = Billion * 100000000 + result result = 0 tmp = 0 # 如果等于1万 elif tmpNum == 10000: result += tmp result = result * tmpNum tmp = 0 # 如果等于十或者百,千 elif tmpNum >= 10: if tmp == 0: tmp = 1 result += tmpNum * tmp tmp = 0 # 如果是个位数 elif tmpNum is not None: tmp = tmp * 10 + tmpNum count += 1 result = result + tmp result = result + Billion return result PK!prevenger/kit/http_kit.pyPK!prevenger/kit/id_card_kit.pyPK!prevenger/kit/image_kit.pyimport base64 import os import sys from PIL import Image def data_uri_encode(): raise NotImplementedError def data_uri_decode(): raise NotImplementedError def b64_encode(s: str) -> str: return base64.b64encode(s) def b64_decode(s: str) -> str: return base64.b64decode(s) def save_as_jpg(infile, outfile): try: Image.open(infile).save(outfile) except IOError: print("cannot convert", infile) def save_thumbnail(infile, outfile): size = (128, 128) try: im = Image.open(infile) im.thumbnail(size) im.save(outfile, "JPEG") except IOError: print("cannot create thumbnail for", infile) def create_qrcode(content, width): pass PK!'$  prevenger/kit/path_kit.pydef get_path(): raise NotImplementedError def get_absolute_path(): raise NotImplementedError def get_canonical_path(): raise NotImplementedError def get_cwd_path(): raise NotImplementedError def is_absolute_path(): raise NotImplementedError PK!prevenger/kit/qrcode_kit.pyPK!Բ-Uprevenger/kit/rand_kit.pyimport random import string def rand_digits(length=8): return "".join(random.choice(string.digits) for _ in range(length)) def rand_letters_digits(length=8): return "".join( random.choice(string.ascii_letters + string.digits) for _ in range(length) ) def rand_upper_ascii(length=8): return "".join(random.choice(string.ascii_uppercase) for _ in range(length)) PK!prevenger/orm/__init__.pyPK!&prevenger/orm/smart_filter/__init__.pyPK!'--prevenger/records/__init__.pyimport sqlalchemy as sa class DB: pass PK!prevenger/str_kit/__init__.pyPK!'Pnnprevenger/str_kit/regex_kit.pydef is_blank(): "字符串为 null 或者内部字符全部为 ' ' '\t' '\n' '\r' 这四类字符时返回 true" raise NotImplementedError def not_blank(): raise NotImplementedError def snake_to_camel_case(): raise NotImplementedError def camel_to_snake_case(): raise NotImplementedError def capitalize(s: str): return s.capitalize() PK!11x x prevenger/str_kit/str_kit.pydef is_blank(s: [str, None]): """ 判断是否为空(除去空格换行) :param s: :return: """ return s is None or len(s.strip()) == 0 def is_empty(s: [str, None]): """ 判断是否为空(包含空格字符) :param s: :return: """ return s is None or len(s) == 0 def approximate_equal(actual, expected, min_length=5, accepted_rate=0.8): """ 利用字符串近似算法进行近似比较 :param actual: :param expected: :param min_length: :param accepted_rate: :return: """ raise NotImplementedError() HALF2FULL = dict((i, i + 0xFEE0) for i in range(0x21, 0x7F)) HALF2FULL[0x20] = 0x3000 FULL2HALF = dict((i + 0xFEE0, i) for i in range(0x21, 0x7F)) FULL2HALF[0x3000] = 0x20 def full_to_half_width(_str): """ Convert all ASCII characters to the full-width counterpart. """ return str(_str).translate(FULL2HALF) def half_to_full_width(_str): """ Convert full-width characters to ASCII counterpart """ return str(_str).translate(HALF2FULL) def LevenshteinDistance(s, t): """字符串相似度算法(Levenshtein Distance算法) 一个字符串可以通过增加一个字符,删除一个字符,替换一个字符得到另外一个 字符串,假设,我们把从字符串A转换成字符串B,前面3种操作所执行的最少 次数称为AB相似度 这算法是由俄国科学家Levenshtein提出的。 Step Description 1 Set n to be the length of s. Set m to be the length of t. If n = 0, return m and exit. If m = 0, return n and exit. Construct a matrix containing 0..m rows and 0..n columns. 2 Initialize the first row to 0..n. Initialize the first column to 0..m. 3 Examine each character of s (i from 1 to n). 4 Examine each character of t (j from 1 to m). 5 If s[i] equals t[j], the cost is 0. If s[i] doesn't equal t[j], the cost is 1. 6 Set cell d[i,j] of the matrix equal to the minimum of: a. The cell immediately above plus 1: d[i-1,j] + 1. b. The cell immediately to the left plus 1: d[i,j-1] + 1. c. The cell diagonally above and to the left plus the cost: d[i-1,j-1] + cost. 7 After the iteration steps (3, 4, 5, 6) are complete, the distance is found in cell d[n,m]. """ m, n = len(s), len(t) if not (m and n): return m or n # 构造矩阵 matrix = [[0 for i in range(n + 1)] for j in range(m + 1)] matrix[0] = list(range(n + 1)) for i in range(m + 1): matrix[i][0] = i for i in range(m): for j in range(n): cost = int(s[i] != t[j]) # 因为 Python 的字符索引从 0 开始 matrix[i + 1][j + 1] = min( matrix[i][j + 1] + 1, # a. matrix[i + 1][j] + 1, # b. matrix[i][j] + cost, # c. ) return matrix[m][n] valid_similarity = LevenshteinDistance PK!"prevenger/str_kit/validator_kit.pyPK!!!prevenger/timer.pyfrom __future__ import annotations import datetime from calendar import monthrange WEEK_PREFIX = "周" DATETIME_FMT = "%Y-%m-%d %H:%M:%S" DATETIME_FMT_LENGTH = 19 DATE_FMT = "%Y-%m-%d" TIME_FMT = "%H:%M:%S" class DateTime: """ TODO: 毫秒级 """ _datetime: datetime.datetime def __init__(self, dt: [str, datetime.datetime]): if isinstance(dt, str): if len(dt) == 19: self._datetime = datetime.datetime.strptime(dt, DATETIME_FMT) else: self._datetime = datetime.datetime.strptime(dt, DATE_FMT) elif isinstance(dt, datetime.datetime): self._datetime = dt else: raise NotImplementedError @staticmethod def now(): return DateTime(datetime.datetime.now()) def hour_justified(self, left=True) -> DateTime: if left: t = datetime.datetime( self._datetime.year, self._datetime.month, self._datetime.day, 0, 0, 0 ) else: t = datetime.datetime( self._datetime.year, self._datetime.month, self._datetime.day, 23, 59, 59, ) return DateTime(t) def day_justified(self, left=True) -> DateTime: if left: t = datetime.datetime(self._datetime.year, self._datetime.month, 1, 0, 0, 0) else: t = datetime.datetime( self._datetime.year, self._datetime.month, monthrange(self._datetime.year, self._datetime.month)[1], 23, 59, 59, ) return DateTime(t) def week_justified(self, left=True): start = self._datetime - datetime.timedelta(days=self._datetime.weekday()) if left: t = DateTime(start).hour_justified().raw else: t = ( DateTime(start + datetime.timedelta(days=6)) .hour_justified(left=False) .raw ) return DateTime(t) def month_justified(self, left=True) -> DateTime: if left: t = datetime.datetime(self._datetime.year, 1, 1, 0, 0, 0) else: t = datetime.datetime(self._datetime.year, 12, 31, 23, 59, 59) return DateTime(t) @property def date(self) -> Date: return Date(self._datetime) @property def time(self) -> Time: return Time(self._datetime) def weeks(self): pass @classmethod def gen_datetime_range( cls, from_datetime, to_datetime, year=0, month=0, day=0, hour=0, minute=0, seconds=0, ): pass def __eq__(self, o: [DateTime, Date, Time]) -> bool: if isinstance(o, DateTime): return self.raw == o.raw if isinstance(o, Date): return self.date == o if isinstance(o, Time): return self.time == o raise NotImplementedError def __ne__(self, o: [DateTime, Date, Time]) -> bool: return not self.__eq__(o) def __gt__(self, o: [DateTime, Date, Time]) -> bool: if isinstance(o, DateTime): return self.raw > o.raw if isinstance(o, Date): return self.date > o if isinstance(o, Time): return self.time > o raise NotImplementedError def __ge__(self, o: [DateTime, Date, Time]) -> bool: return self.__eq__(o) or self.__gt__(o) def __lt__(self, o: [DateTime, Date, Time]) -> bool: if isinstance(o, DateTime): return self.raw < o.raw if isinstance(o, Date): return self.date < o if isinstance(o, Time): return self.time < o raise NotImplementedError def __le__(self, o: [DateTime, Date, Time]) -> bool: return self.__eq__(o) or self.__lt__(o) def __str__(self) -> str: return super().__str__() def __repr__(self) -> str: return super().__repr__() @property def raw(self): return self._datetime @property def fmt(self): return self._datetime.strftime(DATETIME_FMT) class Date: _date: datetime.date def __init__(self, _date: [str, datetime.datetime, DateTime]): if isinstance(_date, str): self._date = datetime.datetime.strptime(_date, DATE_FMT).date() elif isinstance(_date, datetime.datetime): self._date = _date.date() elif isinstance(_date, DateTime): self._date = _date.date.raw else: raise NotImplementedError @staticmethod def today(): return Date(datetime.datetime.now()) def day_justified(self, left=True) -> Date: return Date(DateTime(self._date).day_justified(left=left)) def week_justified(self, left=True) -> Date: return Date(DateTime(self._date).week_justified(left=left)) def month_justified(self, left=True) -> Date: return Date(DateTime(self._date).month_justified(left=left)) def __eq__(self, o: [DateTime, Date]) -> bool: if isinstance(o, Date): return self.raw == o.raw if isinstance(o, DateTime): return self == o.date raise NotImplementedError def __ne__(self, o: [DateTime, Date]) -> bool: return not self.__eq__(o) def __lt__(self, o: [DateTime, Date]) -> bool: if isinstance(o, DateTime): return self < o.date if isinstance(o, Date): return self.raw < o.raw raise NotImplementedError def __le__(self, o: [DateTime, Date]) -> bool: return self.__lt__(o) or self.__eq__(o) def __gt__(self, o: [DateTime, Date]) -> bool: if isinstance(o, DateTime): return self > o.date if isinstance(o, Date): return self.raw > o.raw raise NotImplementedError def __ge__(self, o: [DateTime, Date]) -> bool: return self.__gt__(o) or self.__eq__(o) @property def raw(self): return self._date @property def fmt(self): return self._date.strftime(DATE_FMT) @classmethod def gen_date_range(cls, start: Date, end: Date, step=1): return [ cls(start.raw + datetime.timedelta(days=x)) for x in range(0, (end.raw - start.raw).days, step=step) ] @classmethod def gen_date_range_fmt(cls, start: Date, end: Date, step=1): return list(map(cls.gen_date_range(start=start, end=end, step=step))) class Time: _time: datetime.time def __init__(self, _time: [str, datetime.datetime, DateTime]): if isinstance(_time, str): self._time = datetime.datetime.strptime(_time, TIME_FMT).time() elif isinstance(_time, datetime.datetime): self._time = _time.time() elif isinstance(_time, DateTime): self._time = _time.raw.time() else: raise NotImplementedError @staticmethod def hour_justified(left=True) -> Time: if left: return Time("00:00:00") else: return Time("23:59:59") @staticmethod def now(): return datetime.datetime.now() @classmethod def tomorrow(cls): return @property def raw(self): return self._time @property def fmt(self): return self._time.strftime(TIME_FMT) def __eq__(self, o: [DateTime, Time]) -> bool: if isinstance(o, Time): return self.raw == o.raw if isinstance(o, DateTime): return self == o.time raise NotImplementedError def __ne__(self, o: [DateTime, Time]) -> bool: return not self.__eq__(o) def __gt__(self, o: [DateTime, Time]) -> bool: if isinstance(o, DateTime): return self > o.time if isinstance(o, Time): return self.raw > o.raw raise NotImplementedError def __lt__(self, o: [DateTime, Time]) -> bool: if isinstance(o, DateTime): return self < o.time if isinstance(o, Time): return self.raw < o.raw raise NotImplementedError def __le__(self, o: [DateTime, Time]) -> bool: return self.__lt__(o) or self.__eq__(o) def __ge__(self, o: [DateTime, Time]) -> bool: return self.__gt__(o) or self.__eq__(o) PK!prevenger/validator/__init__.pyPK!H\-4*prevenger-0.0.2.dist-info/entry_points.txtN+I/N.,()*(J-KKO-Mɴ<<..PK!HڽTUprevenger-0.0.2.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!Hg+!"prevenger-0.0.2.dist-info/METADATATMOAϯbH$afR 1t;̶'H8hh# % Ąt ζU;U$OAwL>%` hǦMC#"`ą6Ǖj}uv!y//n_|MU:Z76*; XQN )o`d-Z+/[ޝ7PK!HNp8 prevenger-0.0.2.dist-info/RECORDIH{Vv}@@AeQ AA(kzfp*2.O~KB0:gu𭝱>ElWN:j^ [Ezw~T9 Dr/nLe*C XV&[j=_"hQ,Emt) YX-e=8S2 FE+@JĨr!4AP\Dٻb2iI+džV8AE˦ҢD/REq=slXfຒ[̈́SbMrQK1Ѝ&: ְ:[`$g ߹rGcWs6]$abeKO͌]խ|h/[`?݉c~Vk$ʟbExp 냏^#sx8%@Wf1F0Ik?=è~nƅkesצ1ڵdvapHl`*('1!_5?NGkR_Pl攈(ߡ~eH2pړtj5FRtv|Sk&UԳ(~y5U1aP}>i—J)ө<]Oy,eo k:FeDRTT>82վ/tzlGUsηYE^2f70b#Y WVo[R/ jmoiAMqy-nX|dH;&2bӴ opY>ՀFfQ6Az\FRUU34oT]vIpp:# =kn}]K'ή0akrM~C[x$ PK!prevenger/__init__.pyPK!F.663prevenger/cache/__init__.pyPK!<ƅ prevenger/cli.pyPK!v prevenger/crypto/__init__.pyPK! prevenger/gen/__init__.pyPK! z.SS prevenger/inspector/__init__.pyPK!w prevenger/kit/__init__.pyPK! prevenger/kit/bloomfilter_kit.pyPK!{"V prevenger/kit/captcha_kit.pyPK![T%+prevenger/kit/dfa_kit.pyPK!Gprevenger/kit/http_kit.pyPK!Gprevenger/kit/id_card_kit.pyPK!5Hprevenger/kit/image_kit.pyPK!'$  ?Kprevenger/kit/path_kit.pyPK!Lprevenger/kit/qrcode_kit.pyPK!Բ-ULprevenger/kit/rand_kit.pyPK!yNprevenger/orm/__init__.pyPK!&Nprevenger/orm/smart_filter/__init__.pyPK!'--Nprevenger/records/__init__.pyPK!\Oprevenger/str_kit/__init__.pyPK!'PnnOprevenger/str_kit/regex_kit.pyPK!11x x AQprevenger/str_kit/str_kit.pyPK!"\prevenger/str_kit/validator_kit.pyPK!!!3]prevenger/timer.pyPK!q~prevenger/validator/__init__.pyPK!H\-4*~prevenger-0.0.2.dist-info/entry_points.txtPK!HڽTU#prevenger-0.0.2.dist-info/WHEELPK!Hg+!"prevenger-0.0.2.dist-info/METADATAPK!HNp8 ςprevenger-0.0.2.dist-info/RECORDPKd}