Song.source()   B
last analyzed

Complexity

Conditions 6

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
c 0
b 0
f 0
dl 0
loc 21
rs 7.8867
ccs 18
cts 18
cp 1
crap 6
1
"""Classes and functions to interact with songs."""
2
3 1
import os
4 1
import shutil
5 1
import uuid
6 1
import logging
7
8 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...
9
10
11 1
class Song(object):
12
    """Represents a song file or link."""
13
14 1
    def __init__(self, path, downloads=None, friendname=None):
15 1
        self.path = path
16 1
        self.downloads = downloads
17 1
        self.friendname = friendname
18
19 1
    def __str__(self):
20 1
        return str(self.path)
21
22 1
    def link(self, dirpath):
23
        """Create a link to the song in the specified directory."""
24 1
        if not os.path.isdir(dirpath):
25 1
            logging.warning("creating missing folder: {}".format(dirpath))
26 1
            os.makedirs(dirpath)
27 1
        relpath = os.path.relpath(self.path, dirpath)
28 1
        filename = "{}.yml".format(uuid.uuid4().hex)
29 1
        path = os.path.join(dirpath, filename)
30 1
        logging.info("creating link {}...".format(path))
31 1
        with open(path, 'w') as link:
32 1
            data = {'link': relpath.replace('\\', '/')}  # always *nix format
33 1
            link.write(yaml.dump(data, default_flow_style=False))
34
35 1
    @property
36
    def source(self):
37
        """If the song is a link, return its source. Otherwise its path."""
38 1
        src = self.path
39 1
        if self.path.endswith('.yml'):
40 1
            with open(self.path, 'r') as yml:
41 1
                text = yml.read()
42 1
                try:
43 1
                    data = yaml.load(text)
44 1
                except yaml.parser.ParserError:  # pylint: disable=E1101
45 1
                    logging.warning("invalid YAML: {}".format(self.path))
46 1
                    data = None
47 1
                if data:
48 1
                    relpath = data.get('link', None)
49 1
                    if relpath:
50 1
                        dirpath = os.path.dirname(self.path)
51 1
                        path = os.path.join(dirpath, relpath)
52 1
                        src = os.path.normpath(path)
53
                    else:
54 1
                        logging.debug("non-link YAML: {}".format(self.path))
55 1
        return src
56
57 1
    @property
58
    def in_string(self):
59
        """Get the string representation for an incoming song."""
60 1
        filename = os.path.basename(self.source)
61 1
        return "{} (from {})".format(filename, self.friendname)
62
63 1
    @property
64
    def out_string(self):
65
        """Get the string representation for an incoming song."""
66 1
        filename = os.path.basename(self.source)
67 1
        return "{} (to {})".format(filename, self.friendname)
68
69 1
    def download(self, catch=True):
70
        """Move the song to the user's download directory.
71
72
        @return: path to downloaded file or None on broken links
73
        """
74 1
        assert self.downloads  # only called in cases where downloads is set
75
        # Determine if the song file is actually a link
76 1
        src = self.source
77 1
        dst = None
78
        # Move the file or copy from the link
79 1
        try:
80 1
            if not os.path.isdir(self.downloads):
81 1
                msg = "invalid download location: {}".format(self.downloads)
82 1
                raise IOError(msg)
83 1
            if src == self.path:
84 1
                logging.info("moving {}...".format(src))
85
                # Copy then delete in case the operation is canceled
86 1
                shutil.copy(src, self.downloads)
87 1
                dst = os.path.join(self.downloads, os.path.basename(src))
88 1
                os.remove(src)
89
            else:
90 1
                if os.path.exists(src):
91 1
                    logging.info("copying {}...".format(src))
92 1
                    shutil.copy(src, self.downloads)
93 1
                    dst = os.path.join(self.downloads, os.path.basename(src))
94 1
                    os.remove(self.path)
95
                else:
96 1
                    logging.debug("unknown link target: {}".format(src))
97 1
                    logging.warning("broken link: {}".format(self.path))
98 1
                    os.remove(self.path)
99 1
        except IOError as error:
100 1
            logging.error(error)
101 1
            if not catch:
102 1
                raise
103 1
        return dst
104
105 1
    def ignore(self):
106
        """Delete the song."""
107 1
        logging.info("deleting {}...".format(self.path))
108
        os.remove(self.path)
109