Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

# Copyright (C) 2015 Chintalagiri Shashank 

# 

# This file is part of Tendril. 

# 

# This program is free software: you can redistribute it and/or modify 

# it under the terms of the GNU Affero General Public License as published by 

# the Free Software Foundation, either version 3 of the License, or 

# (at your option) any later version. 

# 

# This program is distributed in the hope that it will be useful, 

# but WITHOUT ANY WARRANTY; without even the implied warranty of 

# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 

# GNU Affero General Public License for more details. 

# 

# You should have received a copy of the GNU Affero General Public License 

# along with this program.  If not, see <http://www.gnu.org/licenses/>. 

""" 

The LibreOffice Utils Module (:mod:`tendril.utils.libreoffice`) 

=============================================================== 

 

This module provides utilities to deal with LibreOffice files. Functionality 

is implemented lazily, so this doesn't really do much. 

 

Presently, whatever it does do, it does by relying on external python code, 

executed in a shell by :mod:`subprocess`. This is required since the default 

LibreOffice install I have only supports a python 3 API. 

 

For details about how it actually works, look at the documentation of the 

:mod:`sofficehelpers` package. The scripts used from that package are : 

 

- :mod:`sofficehelpers.ssconverter` for converting spreadsheets to CSV files. 

 

.. todo:: Publish the :mod:`sofficehelpers` package somewhere, or find a 

          pre-existing alternative. If there is a functionally sufficient 

          alternative, it will probably be better. 

 

""" 

 

from tendril.utils.fsutils import TEMPDIR 

 

import shutil 

import os 

import subprocess 

import atexit 

 

 

#: A list of all files currently open which the module is responsible for. 

open_files = [] 

 

 

class XLFile(object): 

    """ 

    This class allows reading data from LibreOffice supported Spreadsheet 

    files, by converting each sheet into a CSV file, which can then be read by 

    application code. Note that this is a one way conversion only. The 

    original spreadsheet file is not written to. 

 

    When the object is instantiated, a copy of the file is made in the 

    temporary folder by :func:`_make_copy`, which is then converted into one 

    CSV file per sheet in the original spreadsheet file by 

    :func:`_make_csv_files`. It then adds itself to the modules 

    :data:`open_files` list. 

 

    :param filepath: The path of the spreadsheet to be opened. 

    :ivar fpath: The path to the original spreadsheet file. 

    :ivar fname: The file name of the original spreadsheet file. 

    :ivar _csv_list: The list of CSV files generated from the spreadsheet, 

                     one per sheet. 

 

    """ 

    def __init__(self, filepath): 

        self.fpath = filepath 

        self.fname = os.path.split(filepath)[1] 

        self._csv_list = [] 

        self._tfpath = self._make_copy() 

        self._make_csv_files() 

 

        open_files.append(self) 

 

    def get_csv_path(self, sheetname): 

        """ 

        Gets the path to the CSV file that was created at object 

        initialization corresponding to the sheetname provided. 

 

        :param sheetname: Name of the Spreadsheet Sheet. 

        """ 

        for (sname, spath) in self._csv_list: 

            if sname == sheetname: 

                return spath 

        return None 

 

    def _make_copy(self): 

        """ 

        Makes a copy of the original file in the temporary directory 

        """ 

        tfpath = os.path.join(TEMPDIR, self.fname) 

        shutil.copyfile(self.fpath, tfpath) 

        return tfpath 

 

    def _make_csv_files(self): 

        """ 

        Converts a SpreadSheet file supported by LibreOffice into a set of CSV 

        files, one per sheet, using the :mod:`sofficehelpers.ssconverter` 

        script. The output is parsed by :func:`_parse_sscout`. 

        """ 

        fname = os.path.splitext(self.fname)[0] 

        csvpath = os.path.join(TEMPDIR, fname + '-%s.csv') 

        cstrl = ["ssconverter", self._tfpath, csvpath] 

        self._csv_list = self._parse_sscout(subprocess.check_output(cstrl)) 

 

    def _parse_sscout(self, string): 

        """ 

        Parses the output of the :mod:`sofficehelpers.ssconverter` script, 

        extracting the Sheet names and corresponding CSV file names from the 

        output. 

        """ 

        fname = os.path.splitext(self.fname)[0] 

        rlist = [x.strip() for x in string.split('\n')[1:-1]] 

        rlist = [(os.path.split(x)[1][len(fname) + 1:-4], x) for x in rlist] 

        return rlist 

 

    def close(self): 

        """ 

        Closes the object and removes it from the :data:`open_files` list. 

        Also runs :func:`_clean` to remove all the files it created. 

        """ 

        self._clean() 

        open_files.remove(self) 

 

    def _clean(self): 

        """ 

        Removes all temporary files created during the object instantiation. 

        """ 

        os.remove(self._tfpath) 

        for (s, csvpath) in self._csv_list: 

            os.remove(csvpath) 

 

 

def get_xlf(fpath): 

    """ 

    Gets the :class:`XLFile` object for the spreadsheet at ``fpath``, 

    `opening` the file and creating the object if it does not already 

    exist. 

 

    :param fpath: Path of the spreadsheet file to open. 

    :return: The opened :class:`XLFile` instance. 

    """ 

    """ 

    :param fpath: 

    :return: 

    """ 

    for f in open_files: 

        if f.fpath == fpath: 

            return f 

    f = XLFile(fpath) 

    return f 

 

 

def ooutils_cleanup(): 

    """ 

    Called when the python interpreter is shutting down. Cleans up all 

    `tendril.utils.libreoffice` related objects and other artifacts created 

    by the module. 

 

    Performs the following tasks: 

        - Closes all :data:`open_files` 

 

    """ 

    for f in open_files: 

        f.close() 

 

atexit.register(ooutils_cleanup)