Completed
Push — develop ( 10b422...8844b4 )
by Jace
9s
created

parse()   B

Complexity

Conditions 4

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 4.074
Metric Value
cc 4
dl 0
loc 23
rs 8.7972
ccs 10
cts 12
cp 0.8333
crap 4.074
1
"""Functions to work with files and data formats."""
2
3 1
import os
4 1
import shutil
5
6 1
import simplejson as json
0 ignored issues
show
Configuration introduced by
The import simplejson could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
7 1
import yaml
0 ignored issues
show
Configuration introduced by
The import yaml could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
8
9 1
from . import common, exceptions
10
11 1
log = common.logger(__name__)
12
13
14 1
def exists(path):
15
    """Determine if a path exists."""
16 1
    return os.path.exists(path)
17
18
19 1
def touch(path):
20
    """Ensure a file path exists."""
21 1
    if not os.path.exists(path):
22 1
        dirpath = os.path.dirname(path)
23 1
        if dirpath and not os.path.isdir(dirpath):
24 1
            log.trace("Creating directory '{}'...".format(dirpath))
25 1
            os.makedirs(dirpath)
26 1
        log.trace("Creating empty '{}'...".format(path))
27 1
        write("", path)
28
29
30 1
def read(path, encoding='utf-8'):
31
    """Read text from a file.
32
33
    :param path: file path to read from
34
    :param encoding: input file encoding
35
36
    :return: string contents of file
37
38
    """
39 1
    log.trace("Reading text from '{}'...".format(path))
40
41 1
    with open(path, 'r', encoding=encoding) as stream:
42 1
        text = stream.read()
43
44 1
    return text
45
46
47 1
def write(text, path, encoding='utf-8'):
48
    """Write text to a file.
49
50
    :param text: string
51
    :param path: file path to write text
52
    :param encoding: output file encoding
53
54
    :return: path of file
55
56
    """
57 1
    if text:
58 1
        log.trace("Writing text to '{}'...".format(path))
59
60 1
    with open(path, 'wb') as stream:
61 1
        data = text.encode(encoding)
62 1
        stream.write(data)
63
64 1
    return path
65
66
67 1
def stamp(path):
68
    """Get the modification timestamp from a file."""
69 1
    return os.path.getmtime(path)
70
71
72 1
def delete(path):
73
    """Delete a file or directory."""
74 1
    if os.path.isdir(path):
75 1
        try:
76 1
            log.trace("Deleting '{}'...".format(path))
77 1
            shutil.rmtree(path)
78
        except IOError:
79
            # bug: http://code.activestate.com/lists/python-list/159050
80
            msg = "Unable to delete: {}".format(path)
81
            log.warning(msg)
82 1
    elif os.path.isfile(path):
83 1
        log.trace("Deleting '{}'...".format(path))
84 1
        os.remove(path)
85
86
87 1
def parse(text, path):
88
    """Parse a dictionary of data from formatted text.
89
90
    :param text: string containing dumped data
91
    :param path: file path to specify formatting
92
93
    :return: dictionary of data
94
95
    """
96 1
    ext = _get_ext(path)
97 1
    if ext in ['json']:
98 1
        data = _parse_json(text, path)
99 1
    elif ext in ['yml', 'yaml']:
100 1
        data = _parse_yaml(text, path)
101
    else:
102
        log.warning("Unrecognized file extension: %s", ext)
103
        data = _parse_yaml(text, path)
104
105 1
    if not isinstance(data, dict):
106 1
        msg = "Invalid file contents: {}".format(path)
107 1
        raise exceptions.FileContentError(msg)
108
109 1
    return data
110
111
112 1
def _parse_json(text, path):
113 1
    try:
114 1
        return json.loads(text) or {}
115
    except json.JSONDecodeError as exc:
116
        msg = "Invalid JSON contents: {}:\n{}".format(path, exc)
117
        raise exceptions.FileContentError(msg) from None
118
119
120 1
def _parse_yaml(text, path):
121 1
    try:
122 1
        return yaml.load(text) or {}
123 1
    except yaml.error.YAMLError as exc:
124 1
        msg = "Invalid YAML contents: {}:\n{}".format(path, exc)
125 1
        raise exceptions.FileContentError(msg) from None
126
127
128 1
def dump(data, path):
129
    """Format a dictionary into a serialization format.
130
131
    :param text: dictionary of data to format
132
    :param path: file path to specify formatting
133
134
    :return: string of formatted data
135
136
    """
137 1
    ext = _get_ext(path)
138
139 1
    if ext in ['json']:
140 1
        return json.dumps(data, indent=4, sort_keys=True)
141
142 1
    if ext not in ['yml', 'yaml']:
143
        log.warning("Unrecognized file extension: %s", ext)
144
145 1
    return yaml.dump(data, default_flow_style=False, allow_unicode=True)
146
147
148 1
def _get_ext(path):
149 1
    if '.' in path:
150 1
        return path.split('.')[-1].lower()
151
    else:
152
        return 'yml'
153