Passed
Push — master ( 449da2...71a941 )
by Fabio
01:18
created

benedict.utils.parse_util.parse_datetime()   B

Complexity

Conditions 6

Size

Total Lines 19
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 18
dl 0
loc 19
rs 8.5666
c 0
b 0
f 0
cc 6
nop 2
1
# -*- coding: utf-8 -*-
2
3
from datetime import datetime
4
from dateutil import parser as date_parser
5
from decimal import Decimal, DecimalException
6
from MailChecker import MailChecker
7
from phonenumbers import phonenumberutil, PhoneNumberFormat
8
from six import string_types
9
from slugify import slugify
10
11
import ftfy
12
import json
13
import phonenumbers
14
import re
15
16
17
def parse_bool(val):
18
    if isinstance(val, bool):
19
        return val
20
    str_val = str(val).lower()
21
    val = None
22
    if str_val in ['1', 'true', 'yes', 'ok', 'on']:
23
        val = True
24
    elif str_val in ['0', 'false', 'no', 'ko', 'off']:
25
        val = False
26
    return val
27
28
29
def parse_datetime(val, format=None):
30
    if isinstance(val, datetime):
31
        return val
32
    str_val = str(val)
33
    val = None
34
    if format:
35
        try:
36
            val = datetime.strptime(str_val, format)
37
        except Exception:
38
            val = None
39
    else:
40
        try:
41
            val = date_parser.parse(str_val)
42
        except Exception:
43
            try:
44
                val = datetime.fromtimestamp(float(str_val))
45
            except Exception:
46
                val = None
47
    return val
48
49
50
def parse_decimal(val):
51
    if isinstance(val, Decimal):
52
        return val
53
    str_val = str(val)
54
    val = None
55
    try:
56
        val = Decimal(str_val)
57
    except (ValueError, DecimalException):
58
        pass
59
    return val
60
61
62
def parse_dict(val):
63
    if isinstance(val, dict):
64
        return val
65
    str_val = str(val)
66
    if not len(str_val):
67
        return None
68
    val = None
69
    try:
70
        val = json.loads(str_val)
71
        if not isinstance(val, dict):
72
            val = None
73
    except ValueError:
74
        pass
75
        # try:
76
        #     val = yaml.safe_load(str_val)
77
        # except yaml.YAMLError:
78
        #     try:
79
        #         val = xmltodict.parse(str_val)
80
        #     except Exception:
81
        #         pass
82
    return val
83
84
85
def parse_float(val):
86
    if isinstance(val, float):
87
        return val
88
    str_val = str(val)
89
    val = None
90
    try:
91
        val = float(str_val)
92
    except ValueError:
93
        pass
94
    return val
95
96
97
def parse_email(val, check_blacklist=True):
98
    val = parse_str(val)
99
    if not val:
100
        return None
101
    val = val.lower()
102
    if check_blacklist:
103
        if not MailChecker.is_valid(val):
104
            return None
105
    else:
106
        if not MailChecker.is_valid_email_format(val):
107
            return None
108
    return val
109
110
111
def parse_int(val):
112
    if isinstance(val, int):
113
        return val
114
    str_val = str(val)
115
    val = None
116
    try:
117
        val = int(str_val)
118
    except ValueError:
119
        pass
120
    return val
121
122
123
def parse_list(val, separator=None):
124
    if isinstance(val, (list, tuple, )):
125
        return list(val)
126
    str_val = str(val)
127
    if not len(str_val):
128
        return None
129
    val = None
130
    try:
131
        val = json.loads(str_val)
132
        if not isinstance(val, list):
133
            val = None
134
    except Exception:
135
        if separator:
136
            val = list(str_val.split(separator))
137
    return val
138
139
140
def parse_phonenumber(val, country_code=None):
141
    val = parse_str(val)
142
    if not val:
143
        return None
144
    phone_raw = re.sub(r'[^0-9\+]', ' ', val)
145
    phone_raw = phone_raw.strip()
146
    if phone_raw.startswith('00'):
147
        phone_raw = '+{}'.format(phone_raw[2:])
148
    if country_code and len(country_code) >= 2:
149
        country_code = country_code[0:2].upper()
150
    else:
151
        country_code = None
152
    try:
153
        phone_obj = phonenumbers.parse(phone_raw, country_code)
154
        if phonenumbers.is_valid_number(phone_obj):
155
            return {
156
                'e164': phonenumbers.format_number(
157
                    phone_obj, PhoneNumberFormat.E164),
158
                'international': phonenumbers.format_number(
159
                    phone_obj, PhoneNumberFormat.INTERNATIONAL),
160
                'national': phonenumbers.format_number(
161
                    phone_obj, PhoneNumberFormat.NATIONAL),
162
            }
163
        else:
164
            return None
165
    except phonenumberutil.NumberParseException:
166
        return None
167
168
169
def parse_slug(val):
170
    return slugify(parse_str(val))
171
172
173
def parse_str(val):
174
    if (isinstance(val, string_types)):
175
        try:
176
            val = ftfy.fix_text(val)
177
        except UnicodeError:
178
            pass
179
    else:
180
        val = str(val)
181
    val = val.strip()
182
    val = ' '.join(val.split())
183
    return val
184