示例#1
0
    def setup_context(self, context):
        if not sc.config.discourse["forum_url"]:
            return

        query = "%22{}%22|{}".format(uid_to_acro(self.uid).replace(" ", " "), self.uid)
        context.discourse_link = "{}?search={}".format(sc.config.discourse["forum_url"], query)
        context.discourse_url = sc.config.discourse["forum_url"]
        context.embed = self.embed
        try:
            context.discourse_results = sc.search.discourse.search(self.uid)
        except:
            logger.exception("Failed to retrieve discourse_results")
示例#2
0
    def setup_context(self, context):
        if not sc.config.discourse['forum_url']:
            return

        query = '%22{}%20%22'.format(
            uid_to_acro(self.uid).replace(' ', ' '), self.uid)
        context.discourse_link = '{}search?q={}'.format(
            sc.config.discourse['forum_url'], query)
        context.discourse_url = sc.config.discourse['forum_url']
        context.embed = self.embed
        try:
            context.discourse_results = sc.search.discourse.search(self.uid)
        except:
            logger.exception('Failed to retrieve discourse_results')
示例#3
0
def build_jinja2_environment():
    env = jinja2.Environment(loader=jinja2.FileSystemLoader(
        str(sc.templates_dir)),
                             extensions=[AssetsExtension],
                             trim_blocks=True,
                             lstrip_blocks=True,
                             auto_reload=not config.compile_assets)
    env.assets_environment = assets.get_env()

    env.filters['date'] = util.format_date
    env.filters['time'] = util.format_time
    env.filters['max'] = max
    env.filters['min'] = min
    env.filters['datetime'] = util.format_datetime
    env.filters['timedelta'] = util.format_timedelta
    env.filters['uid_to_name'] = lambda uid: uid_to_name(uid)
    env.filters['uid_to_acro'] = lambda uid: uid_to_acro(uid)
    env.filters['json'] = json.dumps

    def sub_filter(string, pattern, repl):
        return regex.sub(pattern, repl, string)

    env.filters['sub'] = sub_filter

    def sht_expansion(string):
        """Add links from SHT vol/page references to the sht-lookup page."""
        if 'SHT' in string:
            # Replace   with spaces
            string = string.replace(' ', ' ')
            baseurl = '/sht-lookup/'

            def replacement(m):
                # Ignore 'also cf. ix p. 393ff' and ' A'
                first, second = m[1], m[2]
                if regex.match(r'.+p\.\s*', first) or \
                   regex.match(r'.+A', first):
                    return '{}{}'.format(first, second)
                else:
                    # replace n-dash with dash
                    path = second.replace('−', '-')
                    return '{}<a href="{}{}" target="_blank">{}</a>'.format(
                        first, baseurl, path, second)

            string = regex.sub(
                r'([^0-9]+)([0-9]{1,4}(?:\.?[\−\+0-9a-zA-Z]+)?)', replacement,
                string)
        return string

    env.filters['sht_expansion'] = sht_expansion
    return env
示例#4
0
def build_jinja2_environment():
    env = jinja2.Environment(
        loader=jinja2.FileSystemLoader(str(sc.templates_dir)),
        extensions=[AssetsExtension],
        trim_blocks=True,
        lstrip_blocks=True,
        auto_reload=not config.compile_assets,
    )
    env.assets_environment = assets.get_env()

    env.filters["date"] = util.format_date
    env.filters["time"] = util.format_time
    env.filters["max"] = max
    env.filters["min"] = min
    env.filters["datetime"] = util.format_datetime
    env.filters["timedelta"] = util.format_timedelta
    env.filters["uid_to_name"] = lambda uid: uid_to_name(uid)
    env.filters["uid_to_acro"] = lambda uid: uid_to_acro(uid)
    env.filters["json"] = json.dumps

    def sub_filter(string, pattern, repl):
        return regex.sub(pattern, repl, string)

    env.filters["sub"] = sub_filter

    def sht_expansion(string):
        """Add links from SHT vol/page references to the sht-lookup page."""
        if "SHT" in string:
            # Replace &nbsp; with spaces
            string = string.replace("&nbsp;", " ")
            baseurl = "/sht-lookup/"

            def replacement(m):
                # Ignore 'also cf. ix p. 393ff' and ' A'
                first, second = m[1], m[2]
                if regex.match(r".+p\.\s*", first) or regex.match(r".+A", first):
                    return "{}{}".format(first, second)
                else:
                    # replace n-dash with dash
                    path = second.replace("−", "-")
                    return '{}<a href="{}{}" target="_blank">{}</a>'.format(first, baseurl, path, second)

            string = regex.sub(r"([^0-9]+)([0-9]{1,4}(?:\.?[\−\+0-9a-zA-Z]+)?)", replacement, string)
        return string

    env.filters["sht_expansion"] = sht_expansion
    return env
示例#5
0
    def setup_context(self, context):
        from sc.tools import html

        m = self.content_regex.search(self.get_html())
        m.detach_string()  # Free up memory now.
        imm = scimm.imm()

        context.uid = self.uid
        context.sutta = imm.suttas.get(self.uid)
        context.subdivision = imm.subdivisions.get(self.uid)
        context.division = imm.divisions.get(self.uid)
        context.canonical = self.canonical

        context.textdata = textdata = imm.get_text_data(self.uid, self.lang_code)
        context.title = textdata.name if textdata else "?"
        context.text = m["content"]

        if self.lang_code in imm.font_data["css_font_class"]:
            context.font_class = imm.font_data["css_font_class"][self.lang_code]

        context.discourse_link = None
        context.discourse_results = None
        if (
            self.uid in imm.suttas
            and sc.config.discourse["forum_url"]
            and self.lang_code == "en"
            or imm.languages[self.lang_code].isroot
        ):
            sutta = imm.suttas
            query = "%22{}%22|{}".format(uid_to_acro(self.uid).replace(" ", " "), self.uid)
            context.discourse_link = "{}?search={}".format(sc.config.discourse["forum_url"], query)
            context.discourse_url = sc.config.discourse["forum_url"]
            try:
                context.discourse_results = sc.search.discourse.search(self.uid)
            except:
                logger.exception("Failed to retrieve discourse_results")

        if context.embed:
            context.text = self.shorter_text(context.text)
        context.has_quotes = "‘" in context.text or "“" in context.text
        try:
            context.snippet = self.get_snippet(context.text)
        except Exception as e:
            logger.error("Failed to generated snippet for {} ({})".format(self.uid, str(e)))
            context.snippet = ""
        # Eliminate newlines from Full-width-glyph languages like Chinese
        # because they convert into spaces when rendered.
        # TODO: This check should use 'language' table
        if self.lang_code in {"zh", "lzh", "ko", "jp"}:
            context.text = self.massage_cjk(context.text)
        context.lang_code = self.lang_code

        context.root_lang = None
        if context.sutta:
            context.root_lang = context.sutta.lang
        elif context.division:
            context.root_lang = context.division.collection.lang
        elif context.subdivision:
            context.root_lang = context.subdivision.division.collection.lang

        context.text_refs = imm.get_text_refs(context.uid)

        nextprev = imm.get_next_prev(uid=self.uid, lang_uid=self.lang_code)
        context.next_data = nextprev["next"]
        context.prev_data = nextprev["prev"]
        context.exports["uid"] = self.uid
        context.exports["lang"] = self.lang_code
示例#6
0
    def setup_context(self, context):
        from sc.tools import html
        m = self.content_regex.search(self.get_html())
        m.detach_string()  # Free up memory now.
        imm = scimm.imm()

        context.uid = self.uid
        context.sutta = imm.suttas.get(self.uid)
        context.subdivision = imm.subdivisions.get(self.uid)
        context.division = imm.divisions.get(self.uid)
        context.canonical = self.canonical

        context.textdata = textdata = imm.get_text_data(
            self.uid, self.lang_code)
        context.title = textdata.name if textdata else '?'
        context.text = m['content']

        if self.lang_code in imm.font_data['css_font_class']:
            context.font_class = imm.font_data['css_font_class'][
                self.lang_code]

        context.discourse_link = None
        context.discourse_results = None
        if (self.uid in imm.suttas and sc.config.discourse['forum_url']
                and self.lang_code == 'en'
                or imm.languages[self.lang_code].isroot):
            sutta = imm.suttas
            query = '%22{}%20%22'.format(
                uid_to_acro(self.uid).replace(' ', ' '), self.uid)
            context.discourse_link = '{}search?q={}'.format(
                sc.config.discourse['forum_url'], query)
            context.discourse_url = sc.config.discourse['forum_url']
            try:
                context.discourse_results = sc.search.discourse.search(
                    self.uid)
            except:
                logger.exception('Failed to retrieve discourse_results')

        if context.embed:
            context.text = self.shorter_text(context.text)
        context.has_quotes = '‘' in context.text or '“' in context.text
        try:
            context.snippet = self.get_snippet(context.text)
        except Exception as e:
            logger.error('Failed to generated snippet for {} ({})'.format(
                self.uid, str(e)))
            context.snippet = ''
        # Eliminate newlines from Full-width-glyph languages like Chinese
        # because they convert into spaces when rendered.
        # TODO: This check should use 'language' table
        if self.lang_code in {'zh', 'lzh', 'ko', 'jp'}:
            context.text = self.massage_cjk(context.text)
        context.lang_code = self.lang_code

        context.root_lang = None
        if context.sutta:
            context.root_lang = context.sutta.lang
        elif context.division:
            context.root_lang = context.division.collection.lang
        elif context.subdivision:
            context.root_lang = context.subdivision.division.collection.lang

        context.text_refs = imm.get_text_refs(context.uid)

        nextprev = imm.get_next_prev(uid=self.uid, lang_uid=self.lang_code)
        context.next_data = nextprev['next']
        context.prev_data = nextprev['prev']
        context.exports['uid'] = self.uid
        context.exports['lang'] = self.lang_code
示例#7
0
    def build(self):
        """ Build the sutta central In Memory Model

        This starts from the highest level (i.e. collection) and works to
        the lowest level (i.e. parallels - the relationship between suttas)
        Since it is fully navigitable both up and down this means some
        elements can't be populated initially. This means that suttas
        insert themselves into the subdivision where they belong.

        Some tables are indexed as dicts, with the key being the uid.
        These include:
        collection, division, subdivision, sutta, language
        
        When classes are contained within a class, for example, suttas in
        a subdivision, this is always represented by a list. That list will
        be sorted appropriately and can be directly outputted, generally
        without any need for filtering or sorting.

        When an attribute is a list or dict, the name always end in an 's'
        for example:
        imm.suttas['sn1.1'].subdivision.division.subdivisions[0].suttas[0]

        Some things, such as parallels, are not indexed at all, and are
        only accessable as attributes of the relevant suttas.
        
        The imm also examines the file system. The fully qualified path to a 
        text can be acquired using:
        imm.text_paths[lang][uid]

        """
        
        # Build Pitakas
        self.pitakas = OrderedDict()
        for row in table_reader('pitaka'):
            self.pitakas[row.uid] = Pitaka(uid=row.uid, name=row.name, always_full=row.always_full)

        # Build Sects
        self.sects = OrderedDict()
        for row in table_reader('sect'):
            self.sects[row.uid] = Sect(uid=row.uid, name=row.name)

        # Build Languages (indexed by id)
        self.languages = OrderedDict()
        for row in table_reader('language'):
            self.languages[row.uid] = Language(
                uid=row.uid,
                name=row.name,
                iso_code=row.iso_code,
                isroot=row.isroot,
                priority=int(row.priority),
                search_priority=float(row.search_priority),
                collections=[],
                )
        
        # Note that one isocode can map to multiple languages
        # for example zh modern/ancient
        self.isocode_to_language = {}
        for language in self.languages.values():
            if language.iso_code not in self.isocode_to_language:
                self.isocode_to_language[language.iso_code] = []
            self.isocode_to_language[language.iso_code].append(language)
        
        # From external_text table
        text_refs = defaultdict(list)
        for row in table_reader('external_text'):
            text_refs[row.sutta_uid].append( TextRef(lang=self.languages[row.language], name=None, abstract=row.abstract, url=row.url, priority=row.priority) )

        self._external_text_refs = text_refs.copy()
        
        collections = []
        for i, row in enumerate(table_reader('collection')):
            if row.sect_uid:
                sect = self.sects[row.sect_uid]
            else:
                sect = None
            collection = Collection(
                uid=row.uid,
                name=row.name,
                abbrev_name=row.abbrev_name,
                lang=self.languages[row.language],
                sect=sect,
                pitaka=self.pitakas[row.pitaka_uid],
                menu_seq=i,
                divisions=[] # Populate later
                )
            collections.append(collection)

        # Sort collections by menu_seq
        collections.sort(key=Collection.sort_key)

        self.collections = OrderedDict()
        for collection in collections:
            self.collections[collection.uid] = collection
            self.languages[collection.lang.uid].collections.append(collection)

        # Build divisions (indexed by uid)
        self.divisions = OrderedDict()
        for i, row in enumerate(table_reader('division')):
            collection = self.collections[row.collection_uid]
            
            text_ref = self.get_text_ref(uid=row.uid, lang_uid=collection.lang.uid);
            
            division = Division(
                uid=row.uid,
                name=row.name,
                alt_name=row.alt_name,
                text_ref=text_ref,
                acronym=row.acronym or uid_to_acro(row.uid),
                subdiv_ind=row.subdiv_ind,
                menu_seq=i,
                menu_gwn_ind=bool(row.menu_gwn_ind),
                collection=collection,
                subdivisions=[], # Populate later
            )
            self.divisions[row.uid] = division
            # Populate collections
            collection.divisions.append(division)

        # Sort divisions within collections by menu_seq
        for collection in self.collections.values():
            collection.divisions.sort(key=Division.sort_key)

        # Build subdivisions (indexed by uid)
        self.subdivisions = OrderedDict()
        self.nosubs = set()
        for i, row in enumerate(table_reader('subdivision')):
            subdivision = Subdivision(
                uid=row.uid,
                acronym=row.acronym,
                division=self.divisions[row.division_uid],
                name=row.name,
                vagga_numbering_ind=row.vagga_numbering_ind,
                order=i,
                vaggas=[], # Populate later
                suttas=[] # Populate later
            )
            self.subdivisions[row.uid] = subdivision
            if row.uid.endswith('-nosub'):
                self.nosubs.add(row.uid[:-6])
            # populate divisions.subdivisions
            self.divisions[row.division_uid].subdivisions.append(subdivision)
        
        for division in self.divisions.values():
            if not division.subdivisions:
                subdivision = Subdivision(
                                uid=division.uid,
                                acronym=None,
                                division=division,
                                name=None,
                                vagga_numbering_ind=False,
                                order=9000,
                                vaggas=[],
                                suttas=[])
                division.subdivisions.append(subdivision)
                self.subdivisions[division.uid] = subdivision
        
        # Build vaggas
        self.vaggas = OrderedDict()
        for row in table_reader('vagga'):
            vagga = Vagga(
                subdivision=self.subdivisions[row.subdivision_uid],
                number=row.number,
                name=row.name,
                suttas=[], # Populate later
            )
            self.vaggas[(row.subdivision_uid, row.number)] = vagga
            # Populate subdivision.vaggas
            vagga.subdivision.vaggas.append(vagga)
        
        for subdivision in self.subdivisions.values():
            if not subdivision.vaggas:
                subdivision.vaggas.append(Vagga(
                    subdivision=subdivision,
                    number=0,
                    name=None,
                    suttas=[]))
        
        # Load biblio entries (Not into an instance variable)
        biblios = {}
        for row in table_reader('biblio'):
            biblios[row.uid] = BiblioEntry(
                uid=row.uid,
                name=row.name,
                text=row.text)
        
        # Build suttas (indexed by uid)
        suttas = []
        for row in table_reader('sutta'):
            uid = row.uid
            volpage = row.volpage.split('//')
            acro = row.acronym.split('//')
            if not acro[0]:
                acro[0] = uid_to_acro(uid)
            
            lang = self.languages[row.language]
            
            subdivision = self.subdivisions[row.subdivision_uid]
            
            if row.vagga_number:
                vagga_number = int(row.vagga_number)
                vagga = subdivision.vaggas[vagga_number - 1]
            else:
                vagga_number = 0
                vagga = subdivision.vaggas[0]
            
            m = regex.search(r'(?r)\d+', row.uid)
            if m:
                number = int(m[0])
            else:
                number = 9999
            
            biblio_entry = None
            if row.biblio_uid:
                biblio_entry = biblios.get(row.biblio_uid)
            
            sutta = Sutta(
                uid=row.uid,
                acronym=acro[0],
                alt_acronym=acro[1] if len(acro) > 1 else None,
                name=row.name,
                vagga_number=vagga_number,
                lang=lang,
                subdivision=subdivision,
                vagga=vagga,
                number=number,
                number_in_vagga=row.number_in_vagga,
                volpage=volpage[0],
                alt_volpage_info=volpage[1] if len(volpage) > 1 else None,
                biblio_entry=biblio_entry,
                parallels=[],
                imm=self,
            )
            suttas.append( (uid, sutta) )
        
        suttas = sorted(suttas, key=numsortkey)
        
        self.suttas = OrderedDict(suttas)
        
        # Populate subdivisions.suttas
        for sutta in self.suttas.values():
            sutta.subdivision.suttas.append(sutta)
            sutta.vagga.suttas.append(sutta)
示例#8
0
 def acronym(self):
     return uid_to_acro(self.uid)
示例#9
0
    def build(self):
        """ Build the sutta central In Memory Model

        This starts from the highest level (i.e. collection) and works to
        the lowest level (i.e. parallels - the relationship between suttas)
        Since it is fully navigitable both up and down this means some
        elements can't be populated initially. This means that suttas
        insert themselves into the subdivision where they belong.

        Some tables are indexed as dicts, with the key being the uid.
        These include:
        collection, division, subdivision, sutta, language
        
        When classes are contained within a class, for example, suttas in
        a subdivision, this is always represented by a list. That list will
        be sorted appropriately and can be directly outputted, generally
        without any need for filtering or sorting.

        When an attribute is a list or dict, the name always end in an 's'
        for example:
        imm.suttas['sn1.1'].subdivision.division.subdivisions[0].suttas[0]

        Some things, such as parallels, are not indexed at all, and are
        only accessable as attributes of the relevant suttas.
        
        The imm also examines the file system. The fully qualified path to a 
        text can be acquired using:
        imm.text_paths[lang][uid]

        """
        
        # Build Pitakas
        self.pitakas = OrderedDict()
        for row in table_reader('pitaka'):
            self.pitakas[row.uid] = Pitaka(uid=row.uid, name=row.name, always_full=row.always_full)

        # Build Sects
        self.sects = OrderedDict()
        for row in table_reader('sect'):
            self.sects[row.uid] = Sect(uid=row.uid, name=row.name)

        # Build Languages (indexed by id)
        self.languages = OrderedDict()
        for row in table_reader('language'):
            self.languages[row.uid] = Language(
                uid=row.uid,
                name=row.name,
                iso_code=row.iso_code,
                isroot=row.isroot,
                priority=int(row.priority),
                search_priority=float(row.search_priority),
                collections=[],
                )
        
        # Note that one isocode can map to multiple languages
        # for example zh modern/ancient
        self.isocode_to_language = {}
        for language in self.languages.values():
            if language.iso_code not in self.isocode_to_language:
                self.isocode_to_language[language.iso_code] = []
            self.isocode_to_language[language.iso_code].append(language)
        
        # From external_text table
        text_refs = defaultdict(list)
        for row in table_reader('external_text'):
            text_refs[row.sutta_uid].append( TextRef(lang=self.languages[row.language], name=None, abstract=row.abstract, url=row.url, priority=row.priority) )

        self._external_text_refs = text_refs.copy()
        
        collections = []
        for i, row in enumerate(table_reader('collection')):
            if row.sect_uid:
                sect = self.sects[row.sect_uid]
            else:
                sect = None
            collection = Collection(
                uid=row.uid,
                name=row.name,
                abbrev_name=row.abbrev_name,
                lang=self.languages[row.language],
                sect=sect,
                pitaka=self.pitakas[row.pitaka_uid],
                menu_seq=i,
                divisions=[] # Populate later
                )
            collections.append(collection)

        # Sort collections by menu_seq
        collections.sort(key=Collection.sort_key)

        self.collections = OrderedDict()
        for collection in collections:
            self.collections[collection.uid] = collection
            self.languages[collection.lang.uid].collections.append(collection)

        # Build divisions (indexed by uid)
        self.divisions = OrderedDict()
        for i, row in enumerate(table_reader('division')):
            collection = self.collections[row.collection_uid]
            
            text_ref = self.get_text_ref(uid=row.uid, lang_uid=collection.lang.uid);
            
            division = Division(
                uid=row.uid,
                name=row.name,
                alt_name=row.alt_name,
                text_ref=text_ref,
                acronym=row.acronym or uid_to_acro(row.uid),
                subdiv_ind=row.subdiv_ind,
                menu_seq=i,
                menu_gwn_ind=bool(row.menu_gwn_ind),
                collection=collection,
                subdivisions=[], # Populate later
            )
            self.divisions[row.uid] = division
            # Populate collections
            collection.divisions.append(division)

        # Sort divisions within collections by menu_seq
        for collection in self.collections.values():
            collection.divisions.sort(key=Division.sort_key)

        # Build subdivisions (indexed by uid)
        self.subdivisions = OrderedDict()
        self.nosubs = set()
        for i, row in enumerate(table_reader('subdivision')):
            subdivision = Subdivision(
                uid=row.uid,
                acronym=row.acronym,
                division=self.divisions[row.division_uid],
                name=row.name,
                vagga_numbering_ind=row.vagga_numbering_ind,
                order=i,
                vaggas=[], # Populate later
                suttas=[] # Populate later
            )
            self.subdivisions[row.uid] = subdivision
            if row.uid.endswith('-nosub'):
                self.nosubs.add(row.uid[:-6])
            # populate divisions.subdivisions
            self.divisions[row.division_uid].subdivisions.append(subdivision)
        
        for division in self.divisions.values():
            if not division.subdivisions:
                subdivision = Subdivision(
                                uid=division.uid,
                                acronym=None,
                                division=division,
                                name=None,
                                vagga_numbering_ind=False,
                                order=9000,
                                vaggas=[],
                                suttas=[])
                division.subdivisions.append(subdivision)
                self.subdivisions[division.uid] = subdivision
        
        # Build vaggas
        self.vaggas = OrderedDict()
        for row in table_reader('vagga'):
            vagga = Vagga(
                subdivision=self.subdivisions[row.subdivision_uid],
                number=row.number,
                name=row.name,
                suttas=[], # Populate later
            )
            self.vaggas[(row.subdivision_uid, row.number)] = vagga
            # Populate subdivision.vaggas
            vagga.subdivision.vaggas.append(vagga)
        
        for subdivision in self.subdivisions.values():
            if not subdivision.vaggas:
                subdivision.vaggas.append(Vagga(
                    subdivision=subdivision,
                    number=0,
                    name=None,
                    suttas=[]))
        
        # Load biblio entries (Not into an instance variable)
        biblios = {}
        for row in table_reader('biblio'):
            biblios[row.uid] = BiblioEntry(
                uid=row.uid,
                name=row.name,
                text=row.text)
        
        # Build suttas (indexed by uid)
        suttas = []
        for row in table_reader('sutta'):
            uid = row.uid
            volpage = row.volpage.split('//')
            acro = row.acronym.split('//')
            if not acro[0]:
                acro[0] = uid_to_acro(uid)
            
            lang = self.languages[row.language]
            
            subdivision = self.subdivisions[row.subdivision_uid]
            
            if row.vagga_number:
                vagga_number = int(row.vagga_number)
                vagga = subdivision.vaggas[vagga_number - 1]
            else:
                vagga_number = 0
                vagga = subdivision.vaggas[0]
            
            m = regex.search(r'(?r)\d+', row.uid)
            if m:
                number = int(m[0])
            else:
                number = 9999
            
            biblio_entry = None
            if row.biblio_uid:
                biblio_entry = biblios.get(row.biblio_uid)
            
            sutta = Sutta(
                uid=row.uid,
                acronym=acro[0],
                alt_acronym=acro[1] if len(acro) > 1 else None,
                name=row.name,
                vagga_number=vagga_number,
                lang=lang,
                subdivision=subdivision,
                vagga=vagga,
                number=number,
                number_in_vagga=row.number_in_vagga,
                volpage=volpage[0],
                alt_volpage_info=volpage[1] if len(volpage) > 1 else None,
                biblio_entry=biblio_entry,
                parallels=[],
                imm=self,
            )
            suttas.append( (uid, sutta) )
        
        suttas = sorted(suttas, key=numsortkey)
        
        self.suttas = OrderedDict(suttas)
        
        # Populate subdivisions.suttas
        for sutta in self.suttas.values():
            sutta.subdivision.suttas.append(sutta)
            sutta.vagga.suttas.append(sutta)
示例#10
0
 def acronym(self):
     return uid_to_acro(self.uid)