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

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

from builtins import str 

# -*- coding: UTF-8 -*- 

# Copyright 2011 Luc Saffre 

# License: BSD (see file COPYING for details) 

 

import logging 

logger = logging.getLogger(__name__) 

 

import os 

import sys 

from optparse import make_option 

from os.path import join 

 

from django.db import models 

from django.conf import settings 

from django.utils.translation import ugettext as _ 

from django.utils.encoding import force_text 

from django.core.management import call_command 

from django.core.management.base import BaseCommand, CommandError 

from django.db.models import loading 

 

import lino 

#from lino.core.utils import app_labels 

from lino.utils import curry 

from lino.utils import rstgen 

from lino.utils.restify import doc2rst, abstract 

from lino.core import dbtables 

 

from lino.api.dd import full_model_name 

 

 

def fieldtype(f): 

    if isinstance(f, models.ForeignKey): 

        return f.__class__.__name__ + " to " + refto(f.rel.model) 

    return f.__class__.__name__ 

 

 

def report_ref(rpt): 

    return settings.SITE.source_name + '.' + str(rpt) 

    #~ return ":ref:`%s.%s`" % (settings.SITE.source_name,str(rpt)) 

 

 

def model_ref(model): 

    return settings.SITE.source_name + '.' + model._meta.app_label + '.' + model.__name__ 

 

 

def refto(x): 

    if x is None: 

        return '`None`' 

    if issubclass(x, models.Model): 

        return ':doc:`' + x.__name__ + ' <' + full_model_name(x) + '>`' 

    #~ if isinstance(x,Field): 

    return ':ref:`' + x.verbose_name + ' <' + settings.SITE.source_name \ 

        + '.' + full_model_name(x.model) + '.' + x.name + '>`' 

 

 

def model_overview(model): 

    headers = ["name", "type"] 

    #~ formatters = [ 

      #~ lambda f: f.name, 

      #~ lambda f: f.__class__.__name__, 

    #~ ] 

    headers.append("verbose name") 

    #~ for lng in babel.AVAILABLE_LANGUAGES: 

        #~ headers.append("verbose name (" + lng + ")") 

    #~ headers.append("help text") 

    #~ formatters.append(lambda f: f.help_text) 

 

    def verbose_name(f): 

        settings.SITE.set_language(None) 

        label_en = force_text(_(f.verbose_name)) 

        babel_labels = [] 

        for lng in settings.SITE.languages[1:]: 

            dbutils.set_language(lng.django_code) 

            label = force_text(_(f.verbose_name)) 

            if label != label_en: 

                babel_labels.append(label) 

        if babel_labels: 

            label_en += " (%s)" % ",".join(babel_labels) 

        return label_en 

 

    def rowfmt(f): 

        cells = [ 

            f.name, 

            fieldtype(f), 

            verbose_name(f) 

        ] 

        #~ for lng in babel.AVAILABLE_LANGUAGES: 

            #~ babel.set_language(lng) 

            #~ cells.append(force_text(_(f.verbose_name))) 

        #~ cells.append(f.help_text) 

        return cells 

    rows = [rowfmt(f) for f in model._meta.fields] 

    s = rstgen.table(headers, rows) 

 

    model_reports = [r for r in dbtables.master_reports if r.model is model] 

    if model_reports: 

        s += '\n\nMaster tables: %s\n\n' % rptlist(model_reports) 

    if getattr(model, '_lino_slaves', None): 

        s += '\n\nSlave tables: %s\n\n' % rptlist(list(model._lino_slaves.values())) 

        #~ s += '\n\nSlave reports: ' 

        #~ s += ', '.join([name for name,rpt in model._lino_slaves.items()]) 

        #~ s += '\n\n' 

    return s 

 

 

def rptlist(l): 

    return ', '.join([ 

        ":ref:`%s (%s) <%s>`" % (str(rpt), 

                                 force_text(rpt.label), report_ref(rpt)) 

        for rpt in l]) 

 

 

def model_referenced_from(model): 

    #~ headers = ["name","description"] 

    #~ rows = [] 

    def ddhfmt(ddh): 

        return ', '.join([':ref:`%s.%s`' % (model_ref(model), fk.name) 

                          for model, fk in ddh.fklist]) 

    return ddhfmt(model._lino_ddh) 

    #~ rows.append(['_lino_ddh',ddhfmt(model._lino_ddh)]) 

    #~ return rstgen.table(headers,rows) 

 

 

class GeneratingCommand(BaseCommand): 

    tmpl_dir = '' 

    args = "output_dir" 

 

    option_list = BaseCommand.option_list + ( 

        make_option('--noinput', action='store_false', 

                    dest='interactive', default=True, 

                    help='Do not prompt for input of any kind.'), 

        #~ make_option('--overwrite', action='store_true', 

        #~ dest='overwrite', default=False, 

        #~ help='Overwrite existing files.'), 

    ) 

 

    def create_parser(self, prog_name, subcommand): 

        self.subcommand = subcommand 

        return super(GeneratingCommand, self).create_parser(prog_name, subcommand) 

 

    def handle(self, *args, **options): 

        if len(args) != 1: 

            raise CommandError("No output_dir specified.") 

 

        self.output_dir = os.path.abspath(args[0]) 

        if not os.path.exists(self.output_dir): 

            raise CommandError("Specified output_dir %s does not exist." % 

                               self.output_dir) 

        #~ self.overwrite 

        #~ self.output_dir = os.path.abspath(output_dir) 

        self.generated_count = 0 

        self.options = options 

 

        logger.info("Running %s to %s.", self, self.output_dir) 

        self.generate_files() 

        logger.info("Generated %s files", self.generated_count) 

 

    def generate(self, tplname, fn, **context): 

        from lino.api import rt 

        from Cheetah.Template import Template as CheetahTemplate 

 

        #~ if self.tmpl_dir: 

            #~ tplname = join(self.tmpl_dir,tplname) 

        #~ tplname = self.subcommand + '/' + tplname 

        tpl_filename = rt.find_config_file(tplname, self.tmpl_dir) 

        if tpl_filename is None: 

            raise Exception("No file %s found" % tplname) 

        if isinstance(tpl_filename, str): 

            tpl_filename = tpl_filename.encode(sys.getfilesystemencoding()) 

        tpl_filename = os.path.abspath(tpl_filename) 

        fn = join(self.output_dir, fn) 

 

        #~ if os.path.exists(fn): 

            #~ if not self.options.get('overwrite'): 

                #~ if not confirm("Overwrite existing file %s (y/n) ?" % fn): 

                    #~ logger.info("Skipping %s because file exists.",fn) 

                    #~ return 

        #~ else: 

            #~ mkdir_if(os.path.dirname(fn)) 

 

        settings.SITE.makedirs_if_missing(os.path.dirname(fn)) 

 

        logger.info("Generating %s", fn) 

        #~ logger.info("Generating %s from %s",fn,tpl_filename) 

 

        def app_labels(): 

            return [p.app_label for p in settings.SITE.installed_plugins] 

        context.update( 

            lino=lino, 

            #~ models=models, 

            settings=settings, 

            app_labels=app_labels) 

        #~ d = dict(site=site) 

        #~ print 20110223, [m for m in models.get_models()] 

        #~ print 20110315, context 

        tpl = CheetahTemplate(file=tpl_filename, namespaces=[context]) 

        #~ tpl = CheetahTemplate(file(tpl_filename).read(),namespaces=[context]) 

        s = str(tpl) 

        #~ print s 

        file(fn, 'w').write(s.encode('utf-8')) 

        self.generated_count += 1 

 

 

class Command(GeneratingCommand): 

    help = """Writes a Sphinx documentation tree about models on this Site. 

    """ 

    tmpl_dir = 'makedocs' 

 

    def generate_files(self): 

 

        from lino.ui.extjs3 import UI 

        #~ UI = settings.SITE.get_ui_class 

        ui = UI(make_messages=True) 

        # ~ # install Lino urls under root location (`/`) 

        #~ ui = urlpatterns = ui.get_patterns() 

        #~ settings.SITE.setup() 

        ui.make_linolib_messages() 

 

        context = dict( 

            header=rstgen.header, 

            h1=curry(rstgen.header, 1), 

            table=rstgen.table, 

            doc=doc2rst, 

            loading=loading, 

            models=models, 

            abstract=abstract, 

            refto=refto, 

            #~ py2rst=rstgen.py2rst, 

            full_model_name=full_model_name, 

            model_overview=model_overview, 

            model_referenced_from=model_referenced_from, 

            model_ref=model_ref, 

        ) 

        self.generate('index.rst.tmpl', 'index.rst', **context) 

        for a in loading.get_apps(): 

            app_label = a.__name__.split('.')[-2] 

            app_models = models.get_models(a, include_auto_created=True) 

            context.update( 

                app=a, 

                app_label=app_label, 

                app_models=app_models 

            ) 

            self.generate('app.rst.tmpl', '%s.rst' % app_label, **context) 

            for model in app_models: 

                context.update( 

                    model=model, 

                ) 

                self.generate('model.rst.tmpl', '%s.rst' % 

                              full_model_name(model), **context)