Skip to content

Commit 089b568

Browse files
authored
Merge pull request #5 from nexB/4-update-pygments-files
Update prog_lexers.py and pygments_lexers.py #4
2 parents 18b66e0 + 951ad67 commit 089b568

163 files changed

Lines changed: 682 additions & 351 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

configure

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ function setup {
3535
setup
3636

3737
$CONFIGURE_ROOT_DIR/tmp/bin/pip install -e .[testing]
38+
$CONFIGURE_ROOT_DIR/tmp/bin/pip install typecode_libmagic
3839

3940
if [ -f "$CONFIGURE_ROOT_DIR/tmp/bin/activate" ]; then
4041
source "$CONFIGURE_ROOT_DIR/tmp/bin/activate"

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ install_requires =
3333
commoncode
3434
pdfminer.six
3535
plugincode
36-
pygments
36+
pygments >= 2.7.1
3737
six
3838
setup_requires = setuptools_scm[toml] >= 4
3939

src/typecode/contenttype.py

Lines changed: 102 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,30 @@ def as_bytes(items):
106106
ELF_UNKNOWN = 'unknown'
107107
elf_types = (ELF_EXE, ELF_SHARED, ELF_RELOC,)
108108

109+
110+
PLAIN_TEXT_EXTENSIONS = (
111+
# docs
112+
'.rst', '.rest', '.md',
113+
'.txt',
114+
# This one is actually not handled by Pygments. There are probably more.
115+
'.log',
116+
# various data
117+
'.json',
118+
'.xml',
119+
)
120+
121+
if on_linux and py2:
122+
PLAIN_TEXT_EXTENSIONS = as_bytes(PLAIN_TEXT_EXTENSIONS)
123+
124+
125+
MAKEFILE_EXTENSIONS = (
126+
'Makefile',
127+
'Makefile.inc',
128+
)
129+
130+
if on_linux and py2:
131+
MAKEFILE_EXTENSIONS = as_bytes(MAKEFILE_EXTENSIONS)
132+
109133
# TODO:
110134
# http://svn.zope.org/z3c.mimetype/trunk/?pathrev=103648
111135
# http://svn.zope.org/z3c.sharedmimeinfo/trunk/TODO.txt?revision=103668&view=markup
@@ -157,7 +181,7 @@ class Type(object):
157181
'_mimetype_python',
158182
'_filetype_file',
159183
'_mimetype_file',
160-
'_filetype_pygments',
184+
'_filetype_pygment',
161185
'_is_pdf_with_text',
162186
'_is_text',
163187
'_is_text_with_long_lines',
@@ -178,18 +202,19 @@ class Type(object):
178202
'filetype_pygment',
179203
'elf_type',
180204
'programming_language',
205+
'link_target',
181206
]
182207

183-
exportable_attributes = text_attributes + [
208+
numeric_attributes = ['size', ]
209+
date_attributes = ['date', ]
210+
211+
boolean_attributes = [
184212
'is_file',
185213
'is_dir',
186214
'is_regular',
187215
'is_special',
188-
'date',
189216
'is_link',
190217
'is_broken_link',
191-
'link_target',
192-
'size',
193218
'is_pdf_with_text',
194219
'is_text',
195220
'is_text_with_long_lines',
@@ -216,7 +241,10 @@ class Type(object):
216241
'is_source',
217242
'is_stripped_elf',
218243
'is_winexe',
244+
'is_makefile',
219245
]
246+
exportable_attributes = (
247+
text_attributes + numeric_attributes + date_attributes + boolean_attributes)
220248

221249
def __init__(self, location):
222250
if (not location
@@ -234,7 +262,7 @@ def __init__(self, location):
234262
self.date = filetype.get_last_modified_date(location)
235263

236264
self.is_link = filetype.is_link(location)
237-
self.is_broken_link = filetype.is_broken_link(location)
265+
self.is_broken_link = bool(filetype.is_broken_link(location))
238266

239267
# FIXME: the way the True and False values are checked in properties is verbose and contrived at best
240268
# and is due to use None/True/False as different values
@@ -245,7 +273,7 @@ def __init__(self, location):
245273
self._mimetype_python = None
246274
self._filetype_file = None
247275
self._mimetype_file = None
248-
self._filetype_pygments = None
276+
self._filetype_pygment = None
249277
self._is_pdf_with_text = None
250278
self._is_text = None
251279
self._is_text_with_long_lines = None
@@ -267,7 +295,8 @@ def to_dict(self, include_date=True):
267295
"""
268296
nv = ((n, getattr(self, n)) for n in self.exportable_attributes)
269297
if not include_date:
270-
nv = ((n,v) for n,v in nv if n != 'date')
298+
nv = ((n, v) for n, v in nv if n not in self.date_attributes)
299+
271300
return OrderedDict(nv)
272301

273302
@property
@@ -303,8 +332,8 @@ def mimetype_python(self):
303332
if self.is_file is True:
304333
if not mimetype_python.inited:
305334
mimetype_python.init([APACHE_MIME_TYPES])
306-
val = mimetype_python.guess_type(self.location)[0]
307-
self._mimetype_python = val
335+
val = mimetype_python.guess_type(self.location)[0]
336+
self._mimetype_python = val or ''
308337
return self._mimetype_python
309338

310339
@property
@@ -334,15 +363,15 @@ def filetype_pygment(self):
334363
"""
335364
Return the filetype guessed using Pygments lexer, mostly for source code.
336365
"""
337-
if self._filetype_pygments is None:
338-
self._filetype_pygments = ''
366+
if self._filetype_pygment is None:
367+
self._filetype_pygment = ''
339368
if self.is_text and not self.is_media:
340369
lexer = get_pygments_lexer(self.location)
341370
if lexer and not lexer.name.startswith('JSON'):
342-
self._filetype_pygments = lexer.name or ''
371+
self._filetype_pygment = lexer.name or ''
343372
else:
344-
self._filetype_pygments = ''
345-
return self._filetype_pygments
373+
self._filetype_pygment = ''
374+
return self._filetype_pygment
346375

347376
# FIXME: we way we use tri booleans is a tad ugly
348377

@@ -585,8 +614,11 @@ def is_media_with_meta(self):
585614
# but we exclude some.
586615

587616
# FIXME: only include types that are known to have metadata
588-
if (self.is_media and self.filetype_file.lower().startswith(
589-
('gif image', 'png image', 'jpeg image', 'netpbm', 'mpeg'))):
617+
if not self.is_media:
618+
return False
619+
if self.filetype_file.lower().startswith(
620+
('gif image', 'png image', 'jpeg image', 'netpbm', 'mpeg')
621+
):
590622
return False
591623
else:
592624
return True
@@ -596,8 +628,7 @@ def is_pdf(self):
596628
"""
597629
Return True if the file is highly likely to be a pdf file.
598630
"""
599-
ft = self.mimetype_file
600-
if 'pdf' in ft:
631+
if 'pdf' in self.mimetype_file:
601632
return True
602633
else:
603634
return False
@@ -699,25 +730,33 @@ def is_script(self):
699730
else:
700731
return False
701732

733+
def _is_plain_text(self, _pte=PLAIN_TEXT_EXTENSIONS):
734+
return self.location.endswith(_pte)
735+
736+
@property
737+
def is_makefile(self):
738+
return self.location.endswith(MAKEFILE_EXTENSIONS)
739+
702740
@property
703741
def is_source(self):
704742
"""
705743
Return True if the file is source code.
706744
"""
707745
if self.is_text is False:
708746
return False
709-
PLAIN_TEXT_EXTENSIONS = (
710-
'.rst', '.rest', '.txt', '.md',
711-
# This one is actually not handled by Pygments. There are probably more.
712-
'.log')
713-
if on_linux and py2:
714-
PLAIN_TEXT_EXTENSIONS = as_bytes(PLAIN_TEXT_EXTENSIONS)
715747

716-
if self.location.endswith(PLAIN_TEXT_EXTENSIONS):
748+
elif self._is_plain_text():
749+
return False
750+
751+
elif self.is_makefile or self.is_js_map:
717752
return False
718753

719-
if self.filetype_pygment or self.is_script is True:
754+
elif self.is_java_source is True or self.is_c_source is True:
755+
return True
756+
757+
elif self.filetype_pygment or self.is_script is True:
720758
return True
759+
721760
else:
722761
return False
723762

@@ -727,7 +766,9 @@ def programming_language(self):
727766
Return the programming language if the file is source code or an empty
728767
string.
729768
"""
730-
return self.filetype_pygment or ''
769+
if self.is_source:
770+
return self.filetype_pygment or ''
771+
return ''
731772

732773
@property
733774
def is_c_source(self):
@@ -797,6 +838,7 @@ def is_java_source(self):
797838

798839
if (fnmatch.fnmatch(name, b'*.java' if on_linux and py2 else u'*.java')
799840
or fnmatch.fnmatch(name, b'*.aj' if on_linux and py2 else u'*.aj')
841+
or fnmatch.fnmatch(name, b'*.jad' if on_linux and py2 else u'*.jad')
800842
or fnmatch.fnmatch(name, b'*.ajt' if on_linux and py2 else u'*.ajt')):
801843
return True
802844
else:
@@ -889,31 +931,43 @@ def get_pygments_lexer(location):
889931
except KeyError:
890932
if is_binary(location):
891933
return
892-
try:
893-
# FIXME: Latest Pygments versions should work fine
894-
# win32_bug_on_s_files = dejacode.on_windows and location.endswith('.s')
895934

896-
# NOTE: we use only the location for its file name here, we could use
897-
# lowercase location may be
898-
lexer = get_lexer_for_filename(location, stripnl=False, stripall=False)
899-
return lexer
935+
# We first try to get a lexer using
936+
# - the filename
937+
# - then the lowercased filename
938+
# - and finally the begining of the file content.
939+
# We try with lowercase as detection is skewed otherwise (e.g. .java vs .JAVA)
900940

941+
try:
942+
return get_lexer_for_filename(location)
901943
except LexerClassNotFound:
902944
try:
903-
# if Pygments does not guess we should not carry forward
904-
# read the first 4K of the file
905-
try:
906-
with io.open(location, 'r') as f:
907-
content = f.read(4096)
908-
except:
909-
# try again as bytes and force unicode
910-
with open(location, 'rb') as f:
911-
content = text.as_unicode(f.read(4096))
912-
913-
guessed = guess_lexer(content)
914-
return guessed
945+
return get_lexer_for_filename(location.lower())
915946
except LexerClassNotFound:
916-
return
947+
try:
948+
# if Pygments does not guess we should not carry forward
949+
content = get_text_file_start(location)
950+
return guess_lexer(content)
951+
except LexerClassNotFound:
952+
return
953+
954+
955+
def get_text_file_start(location, length=4096):
956+
"""
957+
Return a unicode string with up the first "length" characters from the text
958+
file at location.
959+
"""
960+
content = None
961+
# read the first 4K of the file
962+
try:
963+
with io.open(location, 'r') as f:
964+
content = f.read(length)
965+
except:
966+
# try again as bytes and force unicode
967+
with open(location, 'rb') as f:
968+
content = text.as_unicode(f.read(length))
969+
finally:
970+
return content
917971

918972

919973
def get_filetype(location):

0 commit comments

Comments
 (0)