mirror of
https://github.com/explosion/spaCy.git
synced 2025-01-26 17:24:41 +03:00
* Generalize tagger code, in preparation for NER and supersense tagging.
This commit is contained in:
parent
81da61f3cf
commit
3733444101
|
@ -6,7 +6,7 @@ from cymem.cymem cimport Pool
|
||||||
from .typedefs cimport hash_t
|
from .typedefs cimport hash_t
|
||||||
from .tokens cimport Tokens
|
from .tokens cimport Tokens
|
||||||
from .lexeme cimport Lexeme
|
from .lexeme cimport Lexeme
|
||||||
from .pos cimport Tagger as PosTagger
|
from .tagger cimport Tagger
|
||||||
from .utf8string cimport StringStore
|
from .utf8string cimport StringStore
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,14 +41,13 @@ cdef class Language:
|
||||||
cdef PreshMap _specials
|
cdef PreshMap _specials
|
||||||
cpdef readonly Lexicon lexicon
|
cpdef readonly Lexicon lexicon
|
||||||
|
|
||||||
cpdef readonly PosTagger pos_tagger
|
cpdef readonly Tagger pos_tagger
|
||||||
|
|
||||||
cdef object _prefix_re
|
cdef object _prefix_re
|
||||||
cdef object _suffix_re
|
cdef object _suffix_re
|
||||||
cdef object _infix_re
|
cdef object _infix_re
|
||||||
|
|
||||||
cpdef Tokens tokenize(self, unicode text)
|
cpdef Tokens tokenize(self, unicode text)
|
||||||
cpdef Tokens pos_tag(self, Tokens t)
|
|
||||||
|
|
||||||
cdef int _tokenize(self, Tokens tokens, String* span, int start, int end) except -1
|
cdef int _tokenize(self, Tokens tokens, String* span, int start, int end) except -1
|
||||||
cdef String* _split_affixes(self, String* string, vector[Lexeme*] *prefixes,
|
cdef String* _split_affixes(self, String* string, vector[Lexeme*] *prefixes,
|
||||||
|
|
|
@ -23,7 +23,7 @@ from . import util
|
||||||
from .util import read_lang_data
|
from .util import read_lang_data
|
||||||
from .tokens import Tokens
|
from .tokens import Tokens
|
||||||
|
|
||||||
from .pos cimport Tagger as PosTagger
|
from .tagger cimport Tagger
|
||||||
|
|
||||||
|
|
||||||
cdef class Language:
|
cdef class Language:
|
||||||
|
@ -42,7 +42,7 @@ cdef class Language:
|
||||||
self.lexicon.strings.load(path.join(util.DATA_DIR, name, 'strings'))
|
self.lexicon.strings.load(path.join(util.DATA_DIR, name, 'strings'))
|
||||||
self._load_special_tokenization(rules)
|
self._load_special_tokenization(rules)
|
||||||
if path.exists(path.join(util.DATA_DIR, name, 'pos')):
|
if path.exists(path.join(util.DATA_DIR, name, 'pos')):
|
||||||
self.pos_tagger = PosTagger(path.join(util.DATA_DIR, name, 'pos'))
|
self.pos_tagger = Tagger(path.join(util.DATA_DIR, name, 'pos'))
|
||||||
else:
|
else:
|
||||||
self.pos_tagger = None
|
self.pos_tagger = None
|
||||||
|
|
||||||
|
@ -93,16 +93,6 @@ cdef class Language:
|
||||||
self._tokenize(tokens, &span, start, i)
|
self._tokenize(tokens, &span, start, i)
|
||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
cpdef Tokens pos_tag(self, Tokens t):
|
|
||||||
if self.pos_tagger is None:
|
|
||||||
return t
|
|
||||||
cdef int i
|
|
||||||
t.pos[-1] = self.pos_tagger.encode_pos('EOL')
|
|
||||||
t.pos[-2] = self.pos_tagger.encode_pos('EOL')
|
|
||||||
for i in range(t.length):
|
|
||||||
t.pos[i] = self.pos_tagger.predict(i, t, t.pos[i-1], t.pos[i-2])
|
|
||||||
return t
|
|
||||||
|
|
||||||
cdef int _tokenize(self, Tokens tokens, String* span, int start, int end) except -1:
|
cdef int _tokenize(self, Tokens tokens, String* span, int start, int end) except -1:
|
||||||
cdef vector[Lexeme*] prefixes
|
cdef vector[Lexeme*] prefixes
|
||||||
cdef vector[Lexeme*] suffixes
|
cdef vector[Lexeme*] suffixes
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
from cymem.cymem cimport Pool
|
|
||||||
|
|
||||||
from thinc.learner cimport LinearModel
|
|
||||||
from thinc.features cimport Extractor
|
|
||||||
from thinc.typedefs cimport atom_t, feat_t, weight_t, class_t
|
|
||||||
|
|
||||||
from .tokens cimport Tokens
|
|
||||||
|
|
||||||
|
|
||||||
cdef class Tagger:
|
|
||||||
cpdef readonly Extractor extractor
|
|
||||||
cpdef readonly LinearModel model
|
|
||||||
|
|
||||||
cpdef class_t predict(self, int i, Tokens tokens, class_t prev, class_t prev_prev) except 0
|
|
||||||
cpdef bint tell_answer(self, class_t gold_tag) except *
|
|
||||||
|
|
||||||
cdef Pool mem
|
|
||||||
cdef class_t _guess
|
|
||||||
cdef atom_t* _atoms
|
|
||||||
cdef feat_t* _feats
|
|
||||||
cdef weight_t* _values
|
|
||||||
cdef weight_t* _scores
|
|
|
@ -30,7 +30,7 @@ cdef class Tagger:
|
||||||
if path.exists(tags_loc):
|
if path.exists(tags_loc):
|
||||||
with open(tags_loc) as file_:
|
with open(tags_loc) as file_:
|
||||||
Tagger.tags.update(ujson.load(file_))
|
Tagger.tags.update(ujson.load(file_))
|
||||||
self.model = LinearModel(len(self.tags), self.extractor.n)
|
self.model = LinearModel(len(self.tags))
|
||||||
if path.exists(path.join(model_dir, 'model')):
|
if path.exists(path.join(model_dir, 'model')):
|
||||||
self.model.load(path.join(model_dir, 'model'))
|
self.model.load(path.join(model_dir, 'model'))
|
||||||
self.extractor = Extractor(TEMPLATES, [ConjFeat for _ in TEMPLATES])
|
self.extractor = Extractor(TEMPLATES, [ConjFeat for _ in TEMPLATES])
|
||||||
|
|
83
spacy/pos_feats.pxd
Normal file
83
spacy/pos_feats.pxd
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
from .tokens cimport Tokens
|
||||||
|
from thinc.typedefs cimport atom_t
|
||||||
|
|
||||||
|
|
||||||
|
cpdef enum:
|
||||||
|
P2i
|
||||||
|
P2c
|
||||||
|
P2w
|
||||||
|
P2shape
|
||||||
|
P2pref
|
||||||
|
P2suff
|
||||||
|
P2title
|
||||||
|
P2upper
|
||||||
|
P2oft_title
|
||||||
|
P2oft_upper
|
||||||
|
P2pos
|
||||||
|
P2url
|
||||||
|
P2num
|
||||||
|
|
||||||
|
P1i
|
||||||
|
P1c
|
||||||
|
P1w
|
||||||
|
P1shape
|
||||||
|
P1pre
|
||||||
|
P1suff
|
||||||
|
P1title
|
||||||
|
P1upper
|
||||||
|
P1oft_title
|
||||||
|
P1oft_upper
|
||||||
|
P1pos
|
||||||
|
P1url
|
||||||
|
P1num
|
||||||
|
|
||||||
|
N0i
|
||||||
|
N0c
|
||||||
|
N0w
|
||||||
|
N0shape
|
||||||
|
N0pref
|
||||||
|
N0suff
|
||||||
|
N0title
|
||||||
|
N0upper
|
||||||
|
N0oft_title
|
||||||
|
N0oft_upper
|
||||||
|
N0pos
|
||||||
|
N0url
|
||||||
|
N0num
|
||||||
|
|
||||||
|
N1i
|
||||||
|
N1c
|
||||||
|
N1w
|
||||||
|
N1shape
|
||||||
|
N1pref
|
||||||
|
N1suff
|
||||||
|
N1title
|
||||||
|
N1upper
|
||||||
|
N1oft_title
|
||||||
|
N1oft_upper
|
||||||
|
N1pos
|
||||||
|
N1url
|
||||||
|
N1num
|
||||||
|
|
||||||
|
N2i
|
||||||
|
N2c
|
||||||
|
N2w
|
||||||
|
N2shape
|
||||||
|
N2pref
|
||||||
|
N2suff
|
||||||
|
N2title
|
||||||
|
N2upper
|
||||||
|
N2oft_title
|
||||||
|
N2oft_upper
|
||||||
|
N2pos
|
||||||
|
N2url
|
||||||
|
N2num
|
||||||
|
|
||||||
|
P2t
|
||||||
|
P1t
|
||||||
|
|
||||||
|
CONTEXT_SIZE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cdef int fill_context(atom_t* context, int i, Tokens tokens) except -1
|
77
spacy/pos_feats.pyx
Normal file
77
spacy/pos_feats.pyx
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
from .lexeme cimport *
|
||||||
|
|
||||||
|
from thinc.typedefs cimport atom_t
|
||||||
|
|
||||||
|
|
||||||
|
TEMPLATES = (
|
||||||
|
(N0i,),
|
||||||
|
(N0w,),
|
||||||
|
(N0suff,),
|
||||||
|
(N0pref,),
|
||||||
|
(P1t,),
|
||||||
|
(P2t,),
|
||||||
|
(P1t, P2t),
|
||||||
|
(P1t, N0w),
|
||||||
|
(P1w,),
|
||||||
|
(P1suff,),
|
||||||
|
(P2w,),
|
||||||
|
(N1w,),
|
||||||
|
(N1suff,),
|
||||||
|
(N2w,),
|
||||||
|
|
||||||
|
(N0shape,),
|
||||||
|
(N0c,),
|
||||||
|
(N1c,),
|
||||||
|
(N2c,),
|
||||||
|
(P1c,),
|
||||||
|
(P2c,),
|
||||||
|
(P1c, N0c),
|
||||||
|
(N0c, N1c),
|
||||||
|
(P1c, P1t),
|
||||||
|
(P1c, P1t, N0c),
|
||||||
|
(P1t, N0c),
|
||||||
|
(N0oft_upper,),
|
||||||
|
(N0oft_title,),
|
||||||
|
|
||||||
|
(P1w, N0w),
|
||||||
|
(N0w, N1w),
|
||||||
|
|
||||||
|
(N0pos,),
|
||||||
|
(P1t, N0pos, N1pos),
|
||||||
|
(P1t, N1pos),
|
||||||
|
|
||||||
|
(N0url,),
|
||||||
|
(N0num,),
|
||||||
|
(P1url,),
|
||||||
|
(P1url,),
|
||||||
|
(N1num,),
|
||||||
|
(N1url,),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
cdef int fill_context(atom_t* context, int i, Tokens tokens) except -1:
|
||||||
|
_fill_token(&context[P2i], tokens.lex[i-2])
|
||||||
|
_fill_token(&context[P1i], tokens.lex[i-1])
|
||||||
|
_fill_token(&context[N0i], tokens.lex[i])
|
||||||
|
_fill_token(&context[N1i], tokens.lex[i+1])
|
||||||
|
_fill_token(&context[N2i], tokens.lex[i+2])
|
||||||
|
context[P1t] = tokens.pos[i-1]
|
||||||
|
context[P2t] = tokens.pos[i-2]
|
||||||
|
|
||||||
|
|
||||||
|
cdef inline void _fill_token(atom_t* atoms, Lexeme* lex) nogil:
|
||||||
|
atoms[0] = lex.sic
|
||||||
|
atoms[1] = lex.cluster
|
||||||
|
atoms[2] = lex.norm if (lex.prob != 0 and lex.prob >= -10) else lex.shape
|
||||||
|
atoms[3] = lex.shape
|
||||||
|
atoms[4] = lex.prefix
|
||||||
|
atoms[5] = lex.suffix
|
||||||
|
|
||||||
|
atoms[6] = lex.flags & (1 << IS_TITLE)
|
||||||
|
atoms[7] = lex.flags & (1 << IS_UPPER)
|
||||||
|
atoms[8] = lex.flags & (1 << OFT_TITLE)
|
||||||
|
atoms[9] = lex.flags & (1 << OFT_UPPER)
|
||||||
|
atoms[10] = lex.postype
|
||||||
|
atoms[11] = lex.flags & (1 << LIKE_URL)
|
||||||
|
atoms[12] = lex.flags & (1 << LIKE_NUMBER)
|
||||||
|
|
|
@ -6,9 +6,10 @@ from .en import EN
|
||||||
from .pos import Tagger
|
from .pos import Tagger
|
||||||
|
|
||||||
|
|
||||||
def read_gold(file_):
|
def read_gold(file_, tag_list):
|
||||||
paras = file_.read().strip().split('\n\n')
|
paras = file_.read().strip().split('\n\n')
|
||||||
golds = []
|
golds = []
|
||||||
|
tag_ids = dict((tag, i) for i, tag in enumerate(tag_list))
|
||||||
for para in paras:
|
for para in paras:
|
||||||
if not para.strip():
|
if not para.strip():
|
||||||
continue
|
continue
|
||||||
|
@ -32,10 +33,16 @@ def read_gold(file_):
|
||||||
else:
|
else:
|
||||||
conll_toks.pop(0)
|
conll_toks.pop(0)
|
||||||
assert len(tags) == len(tokens)
|
assert len(tags) == len(tokens)
|
||||||
tags = [Tagger.encode_pos(t) for t in tags]
|
tags = [_encode_pos(t, tag_ids, tag_list) for t in tags]
|
||||||
golds.append((tokens, tags))
|
golds.append((tokens, tags))
|
||||||
return golds
|
return golds
|
||||||
|
|
||||||
|
def _encode_pos(tag, tag_ids, tag_list):
|
||||||
|
if tag not in tag_ids:
|
||||||
|
tag_ids[tag] = len(tag_list)
|
||||||
|
tag_list.append(tag)
|
||||||
|
return tag_ids[tag]
|
||||||
|
|
||||||
|
|
||||||
def ptb_to_univ(tag):
|
def ptb_to_univ(tag):
|
||||||
mapping = dict(tuple(line.split()) for line in """
|
mapping = dict(tuple(line.split()) for line in """
|
||||||
|
|
|
@ -7,7 +7,7 @@ from thinc.typedefs cimport atom_t, feat_t, weight_t, class_t
|
||||||
from .tokens cimport Tokens
|
from .tokens cimport Tokens
|
||||||
|
|
||||||
|
|
||||||
cdef enum TagType:
|
cpdef enum TagType:
|
||||||
POS
|
POS
|
||||||
ENTITY
|
ENTITY
|
||||||
SENSE
|
SENSE
|
||||||
|
|
|
@ -1,37 +1,93 @@
|
||||||
# cython: profile=True
|
# cython: profile=True
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
from __future__ import division
|
||||||
|
|
||||||
from os import path
|
from os import path
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import random
|
import random
|
||||||
import codecs
|
|
||||||
import gzip
|
|
||||||
import json
|
import json
|
||||||
import cython
|
import cython
|
||||||
|
|
||||||
|
from .pos_feats cimport fill_context as pos_fill_context
|
||||||
|
from .pos_feats cimport CONTEXT_SIZE as POS_CONTEXT_SIZE
|
||||||
|
|
||||||
from thinc.features cimport ConjFeat
|
from thinc.features cimport ConjFeat
|
||||||
|
|
||||||
|
|
||||||
NULL_TAG = 0
|
NULL_TAG = 0
|
||||||
|
|
||||||
|
|
||||||
|
def setup_model_dir(tag_type, tag_names, templates, model_dir):
|
||||||
|
if path.exists(model_dir):
|
||||||
|
shutil.rmtree(model_dir)
|
||||||
|
os.mkdir(model_dir)
|
||||||
|
config = {
|
||||||
|
'tag_type': tag_type,
|
||||||
|
'templates': templates,
|
||||||
|
'tag_names': tag_names,
|
||||||
|
}
|
||||||
|
with open(path.join(model_dir, 'config.json'), 'w') as file_:
|
||||||
|
json.dump(config, file_)
|
||||||
|
|
||||||
|
|
||||||
|
def train(train_sents, model_dir, nr_iter=5):
|
||||||
|
tagger = Tagger(model_dir)
|
||||||
|
for _ in range(nr_iter):
|
||||||
|
n_corr = 0
|
||||||
|
total = 0
|
||||||
|
for tokens, golds in train_sents:
|
||||||
|
assert len(tokens) == len(golds), [t.string for t in tokens]
|
||||||
|
for i, gold in enumerate(golds):
|
||||||
|
guess = tagger.predict(i, tokens)
|
||||||
|
tokens.set_tag(i, tagger.tag_type, guess)
|
||||||
|
tagger.tell_answer(gold)
|
||||||
|
if gold != NULL_TAG:
|
||||||
|
total += 1
|
||||||
|
n_corr += guess == gold
|
||||||
|
print('%.4f' % ((n_corr / total) * 100))
|
||||||
|
random.shuffle(train_sents)
|
||||||
|
tagger.model.end_training()
|
||||||
|
tagger.model.dump(path.join(model_dir, 'model'), freq_thresh=10)
|
||||||
|
|
||||||
|
|
||||||
|
def evaluate(tagger, sents):
|
||||||
|
n_corr = 0
|
||||||
|
total = 0
|
||||||
|
for tokens, golds in sents:
|
||||||
|
for i, gold in enumerate(golds):
|
||||||
|
guess = tagger.predict(i, tokens)
|
||||||
|
tokens.set_tag(i, tagger.tag_type, guess)
|
||||||
|
if gold != NULL_TAG:
|
||||||
|
total += 1
|
||||||
|
n_corr += guess == gold
|
||||||
|
return n_corr / total
|
||||||
|
|
||||||
|
|
||||||
cdef class Tagger:
|
cdef class Tagger:
|
||||||
"""Assign part-of-speech, named entity or supersense tags, using greedy
|
"""Assign part-of-speech, named entity or supersense tags, using greedy
|
||||||
decoding. The tagger reads its model and configuration from disk.
|
decoding. The tagger reads its model and configuration from disk.
|
||||||
"""
|
"""
|
||||||
def __init__(self, model_dir):
|
def __init__(self, model_dir):
|
||||||
self.mem = Pool()
|
self.mem = Pool()
|
||||||
cfg = json.load(path.join(model_dir, 'config.json'))
|
cfg = json.load(open(path.join(model_dir, 'config.json')))
|
||||||
templates = cfg['templates']
|
templates = cfg['templates']
|
||||||
self.tag_names = cfg['tag_names']
|
self.tag_names = cfg['tag_names']
|
||||||
self.tag_type = cfg['tag_type']
|
self.tag_type = cfg['tag_type']
|
||||||
self.model = LinearModel(len(self.tag_names))
|
self.extractor = Extractor(templates, [ConjFeat] * len(templates))
|
||||||
|
self.model = LinearModel(len(self.tag_names), self.extractor.n)
|
||||||
|
print("Load tagger model")
|
||||||
if path.exists(path.join(model_dir, 'model')):
|
if path.exists(path.join(model_dir, 'model')):
|
||||||
self.model.load(path.join(model_dir, 'model'))
|
self.model.load(path.join(model_dir, 'model'))
|
||||||
self.extractor = Extractor(templates, [ConjFeat] * len(templates))
|
print("Done")
|
||||||
|
|
||||||
|
if self.tag_type == POS:
|
||||||
|
n_context = POS_CONTEXT_SIZE
|
||||||
|
self._context = <atom_t*>self.mem.alloc(n_context, sizeof(atom_t))
|
||||||
self._feats = <feat_t*>self.mem.alloc(self.extractor.n+1, sizeof(feat_t))
|
self._feats = <feat_t*>self.mem.alloc(self.extractor.n+1, sizeof(feat_t))
|
||||||
self._values = <weight_t*>self.mem.alloc(self.extractor.n+1, sizeof(weight_t))
|
self._values = <weight_t*>self.mem.alloc(self.extractor.n+1, sizeof(weight_t))
|
||||||
self._scores = <weight_t*>self.mem.alloc(len(self.cfg.tags), sizeof(weight_t))
|
self._scores = <weight_t*>self.mem.alloc(self.model.nr_class, sizeof(weight_t))
|
||||||
self._guess = NULL_TAG
|
self._guess = NULL_TAG
|
||||||
|
|
||||||
cpdef int set_tags(self, Tokens tokens) except -1:
|
cpdef int set_tags(self, Tokens tokens) except -1:
|
||||||
|
@ -54,8 +110,10 @@ cdef class Tagger:
|
||||||
>>> tag = EN.pos_tagger.predict(0, tokens)
|
>>> tag = EN.pos_tagger.predict(0, tokens)
|
||||||
>>> assert tag == EN.pos_tagger.tag_id('DT') == 5
|
>>> assert tag == EN.pos_tagger.tag_id('DT') == 5
|
||||||
"""
|
"""
|
||||||
#if self.tag_type == POS:
|
if self.tag_type == POS:
|
||||||
# _pos_feats.fill_context(self._context, i, tokens)
|
pos_fill_context(self._context, i, tokens)
|
||||||
|
else:
|
||||||
|
raise StandardError
|
||||||
self.extractor.extract(self._feats, self._values, self._context, NULL)
|
self.extractor.extract(self._feats, self._values, self._context, NULL)
|
||||||
self._guess = self.model.score(self._scores, self._feats, self._values)
|
self._guess = self.model.score(self._scores, self._feats, self._values)
|
||||||
return self._guess
|
return self._guess
|
||||||
|
|
|
@ -3,6 +3,7 @@ from cymem.cymem cimport Pool
|
||||||
from .lexeme cimport Lexeme
|
from .lexeme cimport Lexeme
|
||||||
from .typedefs cimport flag_t
|
from .typedefs cimport flag_t
|
||||||
from .utf8string cimport StringStore
|
from .utf8string cimport StringStore
|
||||||
|
from .tagger cimport TagType
|
||||||
|
|
||||||
from thinc.typedefs cimport atom_t
|
from thinc.typedefs cimport atom_t
|
||||||
|
|
||||||
|
@ -23,6 +24,7 @@ cdef class Tokens:
|
||||||
|
|
||||||
cdef int extend(self, int i, Lexeme** lexemes, int n) except -1
|
cdef int extend(self, int i, Lexeme** lexemes, int n) except -1
|
||||||
cdef int push_back(self, int i, Lexeme* lexeme) except -1
|
cdef int push_back(self, int i, Lexeme* lexeme) except -1
|
||||||
|
cpdef int set_tag(self, int i, TagType tag_type, int tag) except -1
|
||||||
|
|
||||||
|
|
||||||
cdef class Token:
|
cdef class Token:
|
||||||
|
|
|
@ -4,6 +4,7 @@ cimport cython
|
||||||
|
|
||||||
DEF PADDING = 5
|
DEF PADDING = 5
|
||||||
|
|
||||||
|
|
||||||
cdef int bounds_check(int i, int length, int padding) except -1:
|
cdef int bounds_check(int i, int length, int padding) except -1:
|
||||||
if (i + padding) < 0:
|
if (i + padding) < 0:
|
||||||
raise IndexError
|
raise IndexError
|
||||||
|
@ -89,6 +90,9 @@ cdef class Tokens:
|
||||||
idx = self.push_back(idx, lexemes[i])
|
idx = self.push_back(idx, lexemes[i])
|
||||||
return idx
|
return idx
|
||||||
|
|
||||||
|
cpdef int set_tag(self, int i, TagType tag_type, int tag) except -1:
|
||||||
|
self.pos[i] = tag
|
||||||
|
|
||||||
def _realloc(self, new_size):
|
def _realloc(self, new_size):
|
||||||
self.max_length = new_size
|
self.max_length = new_size
|
||||||
n = new_size + (PADDING * 2)
|
n = new_size + (PADDING * 2)
|
||||||
|
@ -130,4 +134,3 @@ cdef class Token:
|
||||||
return ''
|
return ''
|
||||||
cdef bytes utf8string = self._string_store[self.sic]
|
cdef bytes utf8string = self._string_store[self.sic]
|
||||||
return utf8string.decode('utf8')
|
return utf8string.decode('utf8')
|
||||||
|
|
||||||
|
|
|
@ -6,5 +6,3 @@ ctypedef uint64_t flag_t
|
||||||
ctypedef uint32_t id_t
|
ctypedef uint32_t id_t
|
||||||
ctypedef uint16_t len_t
|
ctypedef uint16_t len_t
|
||||||
ctypedef uint16_t tag_t
|
ctypedef uint16_t tag_t
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user