PageRenderTime 32ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/venv/Lib/site-packages/nltk/data.py

https://bitbucket.org/AlgirdasKartaviciusKT/ai
Python | 1487 lines | 1416 code | 19 blank | 52 comment | 11 complexity | 30988827a15109b916a9e7b0c83e2586 MD5 | raw file
Possible License(s): BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. # Natural Language Toolkit: Utility functions
  2. #
  3. # Copyright (C) 2001-2018 NLTK Project
  4. # Author: Edward Loper <edloper@gmail.com>
  5. # URL: <http://nltk.org/>
  6. # For license information, see LICENSE.TXT
  7. """
  8. Functions to find and load NLTK resource files, such as corpora,
  9. grammars, and saved processing objects. Resource files are identified
  10. using URLs, such as ``nltk:corpora/abc/rural.txt`` or
  11. ``http://nltk.org/sample/toy.cfg``. The following URL protocols are
  12. supported:
  13. - ``file:path``: Specifies the file whose path is *path*.
  14. Both relative and absolute paths may be used.
  15. - ``http://host/path``: Specifies the file stored on the web
  16. server *host* at path *path*.
  17. - ``nltk:path``: Specifies the file stored in the NLTK data
  18. package at *path*. NLTK will search for these files in the
  19. directories specified by ``nltk.data.path``.
  20. If no protocol is specified, then the default protocol ``nltk:`` will
  21. be used.
  22. This module provides to functions that can be used to access a
  23. resource file, given its URL: ``load()`` loads a given resource, and
  24. adds it to a resource cache; and ``retrieve()`` copies a given resource
  25. to a local file.
  26. """
  27. from __future__ import print_function, unicode_literals
  28. from __future__ import division
  29. from abc import ABCMeta, abstractmethod
  30. from six import add_metaclass
  31. import functools
  32. import textwrap
  33. import io
  34. import os
  35. import re
  36. import sys
  37. import zipfile
  38. import codecs
  39. from gzip import GzipFile, READ as GZ_READ, WRITE as GZ_WRITE
  40. try: # Python 3.
  41. textwrap_indent = functools.partial(textwrap.indent, prefix=' ')
  42. except AttributeError: # Python 2; indent() not available for Python2.
  43. textwrap_fill = functools.partial(textwrap.fill,
  44. initial_indent=' ',
  45. subsequent_indent=' ',
  46. replace_whitespace=False)
  47. def textwrap_indent(text):
  48. return '\n'.join(textwrap_fill(line) for line in text.splitlines())
  49. try:
  50. from zlib import Z_SYNC_FLUSH as FLUSH
  51. except ImportError:
  52. from zlib import Z_FINISH as FLUSH
  53. try:
  54. import cPickle as pickle
  55. except ImportError:
  56. import pickle
  57. from six import string_types, text_type
  58. from six.moves.urllib.request import urlopen, url2pathname
  59. # this import should be more specific:
  60. import nltk
  61. from nltk.compat import py3_data, add_py3_data, BytesIO
  62. ######################################################################
  63. # Search Path
  64. ######################################################################
  65. path = []
  66. """A list of directories where the NLTK data package might reside.
  67. These directories will be checked in order when looking for a
  68. resource in the data package. Note that this allows users to
  69. substitute in their own versions of resources, if they have them
  70. (e.g., in their home directory under ~/nltk_data)."""
  71. # User-specified locations:
  72. _paths_from_env = os.environ.get('NLTK_DATA', str('')).split(os.pathsep)
  73. path += [d for d in _paths_from_env if d]
  74. if 'APPENGINE_RUNTIME' not in os.environ and os.path.expanduser('~/') != '~/':
  75. path.append(os.path.expanduser(str('~/nltk_data')))
  76. if sys.platform.startswith('win'):
  77. # Common locations on Windows:
  78. path += [
  79. str(r'C:\nltk_data'), str(r'D:\nltk_data'), str(r'E:\nltk_data'),
  80. os.path.join(sys.prefix, str('nltk_data')),
  81. os.path.join(sys.prefix, str('share'), str('nltk_data')),
  82. os.path.join(sys.prefix, str('lib'), str('nltk_data')),
  83. os.path.join(
  84. os.environ.get(str('APPDATA'), str('C:\\')), str('nltk_data'))
  85. ]
  86. else:
  87. # Common locations on UNIX & OS X:
  88. path += [
  89. str('/usr/share/nltk_data'),
  90. str('/usr/local/share/nltk_data'),
  91. str('/usr/lib/nltk_data'),
  92. str('/usr/local/lib/nltk_data'),
  93. os.path.join(sys.prefix, str('nltk_data')),
  94. os.path.join(sys.prefix, str('share'), str('nltk_data')),
  95. os.path.join(sys.prefix, str('lib'), str('nltk_data'))
  96. ]
  97. ######################################################################
  98. # Util Functions
  99. ######################################################################
  100. def gzip_open_unicode(filename, mode="rb", compresslevel=9, encoding='utf-8',
  101. fileobj=None, errors=None, newline=None):
  102. if fileobj is None:
  103. fileobj = GzipFile(filename, mode, compresslevel, fileobj)
  104. return io.TextIOWrapper(fileobj, encoding, errors, newline)
  105. def split_resource_url(resource_url):
  106. """
  107. Splits a resource url into "<protocol>:<path>".
  108. >>> windows = sys.platform.startswith('win')
  109. >>> split_resource_url('nltk:home/nltk')
  110. ('nltk', 'home/nltk')
  111. >>> split_resource_url('nltk:/home/nltk')
  112. ('nltk', '/home/nltk')
  113. >>> split_resource_url('file:/home/nltk')
  114. ('file', '/home/nltk')
  115. >>> split_resource_url('file:///home/nltk')
  116. ('file', '/home/nltk')
  117. >>> split_resource_url('file:///C:/home/nltk')
  118. ('file', '/C:/home/nltk')
  119. """
  120. protocol, path_ = resource_url.split(':', 1)
  121. if protocol == 'nltk':
  122. pass
  123. elif protocol == 'file':
  124. if path_.startswith('/'):
  125. path_ = '/' + path_.lstrip('/')
  126. else:
  127. path_ = re.sub(r'^/{0,2}', '', path_)
  128. return protocol, path_
  129. def normalize_resource_url(resource_url):
  130. r"""
  131. Normalizes a resource url
  132. >>> windows = sys.platform.startswith('win')
  133. >>> os.path.normpath(split_resource_url(normalize_resource_url('file:grammar.fcfg'))[1]) == \
  134. ... ('\\' if windows else '') + os.path.abspath(os.path.join(os.curdir, 'grammar.fcfg'))
  135. True
  136. >>> not windows or normalize_resource_url('file:C:/dir/file') == 'file:///C:/dir/file'
  137. True
  138. >>> not windows or normalize_resource_url('file:C:\\dir\\file') == 'file:///C:/dir/file'
  139. True
  140. >>> not windows or normalize_resource_url('file:C:\\dir/file') == 'file:///C:/dir/file'
  141. True
  142. >>> not windows or normalize_resource_url('file://C:/dir/file') == 'file:///C:/dir/file'
  143. True
  144. >>> not windows or normalize_resource_url('file:////C:/dir/file') == 'file:///C:/dir/file'
  145. True
  146. >>> not windows or normalize_resource_url('nltk:C:/dir/file') == 'file:///C:/dir/file'
  147. True
  148. >>> not windows or normalize_resource_url('nltk:C:\\dir\\file') == 'file:///C:/dir/file'
  149. True
  150. >>> windows or normalize_resource_url('file:/dir/file/toy.cfg') == 'file:///dir/file/toy.cfg'
  151. True
  152. >>> normalize_resource_url('nltk:home/nltk')
  153. 'nltk:home/nltk'
  154. >>> windows or normalize_resource_url('nltk:/home/nltk') == 'file:///home/nltk'
  155. True
  156. >>> normalize_resource_url('http://example.com/dir/file')
  157. 'http://example.com/dir/file'
  158. >>> normalize_resource_url('dir/file')
  159. 'nltk:dir/file'
  160. """
  161. try:
  162. protocol, name = split_resource_url(resource_url)
  163. except ValueError:
  164. # the resource url has no protocol, use the nltk protocol by default
  165. protocol = 'nltk'
  166. name = resource_url
  167. # use file protocol if the path is an absolute path
  168. if protocol == 'nltk' and os.path.isabs(name):
  169. protocol = 'file://'
  170. name = normalize_resource_name(name, False, None)
  171. elif protocol == 'file':
  172. protocol = 'file://'
  173. # name is absolute
  174. name = normalize_resource_name(name, False, None)
  175. elif protocol == 'nltk':
  176. protocol = 'nltk:'
  177. name = normalize_resource_name(name, True)
  178. else:
  179. # handled by urllib
  180. protocol += '://'
  181. return ''.join([protocol, name])
  182. def normalize_resource_name(resource_name, allow_relative=True, relative_path=None):
  183. """
  184. :type resource_name: str or unicode
  185. :param resource_name: The name of the resource to search for.
  186. Resource names are posix-style relative path names, such as
  187. ``corpora/brown``. Directory names will automatically
  188. be converted to a platform-appropriate path separator.
  189. Directory trailing slashes are preserved
  190. >>> windows = sys.platform.startswith('win')
  191. >>> normalize_resource_name('.', True)
  192. './'
  193. >>> normalize_resource_name('./', True)
  194. './'
  195. >>> windows or normalize_resource_name('dir/file', False, '/') == '/dir/file'
  196. True
  197. >>> not windows or normalize_resource_name('C:/file', False, '/') == '/C:/file'
  198. True
  199. >>> windows or normalize_resource_name('/dir/file', False, '/') == '/dir/file'
  200. True
  201. >>> windows or normalize_resource_name('../dir/file', False, '/') == '/dir/file'
  202. True
  203. >>> not windows or normalize_resource_name('/dir/file', True, '/') == 'dir/file'
  204. True
  205. >>> windows or normalize_resource_name('/dir/file', True, '/') == '/dir/file'
  206. True
  207. """
  208. is_dir = bool(re.search(r'[\\/.]$', resource_name)) or resource_name.endswith(os.path.sep)
  209. if sys.platform.startswith('win'):
  210. resource_name = resource_name.lstrip('/')
  211. else:
  212. resource_name = re.sub(r'^/+', '/', resource_name)
  213. if allow_relative:
  214. resource_name = os.path.normpath(resource_name)
  215. else:
  216. if relative_path is None:
  217. relative_path = os.curdir
  218. resource_name = os.path.abspath(
  219. os.path.join(relative_path, resource_name))
  220. resource_name = resource_name.replace('\\', '/').replace(os.path.sep, '/')
  221. if sys.platform.startswith('win') and os.path.isabs(resource_name):
  222. resource_name = '/' + resource_name
  223. if is_dir and not resource_name.endswith('/'):
  224. resource_name += '/'
  225. return resource_name
  226. ######################################################################
  227. # Path Pointers
  228. ######################################################################
  229. @add_metaclass(ABCMeta)
  230. class PathPointer(object):
  231. """
  232. An abstract base class for 'path pointers,' used by NLTK's data
  233. package to identify specific paths. Two subclasses exist:
  234. ``FileSystemPathPointer`` identifies a file that can be accessed
  235. directly via a given absolute path. ``ZipFilePathPointer``
  236. identifies a file contained within a zipfile, that can be accessed
  237. by reading that zipfile.
  238. """
  239. @abstractmethod
  240. def open(self, encoding=None):
  241. """
  242. Return a seekable read-only stream that can be used to read
  243. the contents of the file identified by this path pointer.
  244. :raise IOError: If the path specified by this pointer does
  245. not contain a readable file.
  246. """
  247. @abstractmethod
  248. def file_size(self):
  249. """
  250. Return the size of the file pointed to by this path pointer,
  251. in bytes.
  252. :raise IOError: If the path specified by this pointer does
  253. not contain a readable file.
  254. """
  255. @abstractmethod
  256. def join(self, fileid):
  257. """
  258. Return a new path pointer formed by starting at the path
  259. identified by this pointer, and then following the relative
  260. path given by ``fileid``. The path components of ``fileid``
  261. should be separated by forward slashes, regardless of
  262. the underlying file system's path seperator character.
  263. """
  264. class FileSystemPathPointer(PathPointer, text_type):
  265. """
  266. A path pointer that identifies a file which can be accessed
  267. directly via a given absolute path.
  268. """
  269. @py3_data
  270. def __init__(self, _path):
  271. """
  272. Create a new path pointer for the given absolute path.
  273. :raise IOError: If the given path does not exist.
  274. """
  275. _path = os.path.abspath(_path)
  276. if not os.path.exists(_path):
  277. raise IOError('No such file or directory: %r' % _path)
  278. self._path = _path
  279. # There's no need to call str.__init__(), since it's a no-op;
  280. # str does all of its setup work in __new__.
  281. @property
  282. def path(self):
  283. """The absolute path identified by this path pointer."""
  284. return self._path
  285. def open(self, encoding=None):
  286. stream = open(self._path, 'rb')
  287. if encoding is not None:
  288. stream = SeekableUnicodeStreamReader(stream, encoding)
  289. return stream
  290. def file_size(self):
  291. return os.stat(self._path).st_size
  292. def join(self, fileid):
  293. _path = os.path.join(self._path, fileid)
  294. return FileSystemPathPointer(_path)
  295. def __repr__(self):
  296. # This should be a byte string under Python 2.x;
  297. # we don't want transliteration here so
  298. # @python_2_unicode_compatible is not used.
  299. return str('FileSystemPathPointer(%r)' % self._path)
  300. def __str__(self):
  301. return self._path
  302. class BufferedGzipFile(GzipFile):
  303. """
  304. A ``GzipFile`` subclass that buffers calls to ``read()`` and ``write()``.
  305. This allows faster reads and writes of data to and from gzip-compressed
  306. files at the cost of using more memory.
  307. The default buffer size is 2MB.
  308. ``BufferedGzipFile`` is useful for loading large gzipped pickle objects
  309. as well as writing large encoded feature files for classifier training.
  310. """
  311. MB = 2 ** 20
  312. SIZE = 2 * MB
  313. @py3_data
  314. def __init__(self, filename=None, mode=None, compresslevel=9,
  315. fileobj=None, **kwargs):
  316. """
  317. Return a buffered gzip file object.
  318. :param filename: a filesystem path
  319. :type filename: str
  320. :param mode: a file mode which can be any of 'r', 'rb', 'a', 'ab',
  321. 'w', or 'wb'
  322. :type mode: str
  323. :param compresslevel: The compresslevel argument is an integer from 1
  324. to 9 controlling the level of compression; 1 is fastest and
  325. produces the least compression, and 9 is slowest and produces the
  326. most compression. The default is 9.
  327. :type compresslevel: int
  328. :param fileobj: a BytesIO stream to read from instead of a file.
  329. :type fileobj: BytesIO
  330. :param size: number of bytes to buffer during calls to read() and write()
  331. :type size: int
  332. :rtype: BufferedGzipFile
  333. """
  334. GzipFile.__init__(self, filename, mode, compresslevel, fileobj)
  335. self._size = kwargs.get('size', self.SIZE)
  336. self._nltk_buffer = BytesIO()
  337. # cStringIO does not support len.
  338. self._len = 0
  339. def _reset_buffer(self):
  340. # For some reason calling BytesIO.truncate() here will lead to
  341. # inconsistent writes so just set _buffer to a new BytesIO object.
  342. self._nltk_buffer = BytesIO()
  343. self._len = 0
  344. def _write_buffer(self, data):
  345. # Simply write to the buffer and increment the buffer size.
  346. if data is not None:
  347. self._nltk_buffer.write(data)
  348. self._len += len(data)
  349. def _write_gzip(self, data):
  350. # Write the current buffer to the GzipFile.
  351. GzipFile.write(self, self._nltk_buffer.getvalue())
  352. # Then reset the buffer and write the new data to the buffer.
  353. self._reset_buffer()
  354. self._write_buffer(data)
  355. def close(self):
  356. # GzipFile.close() doesn't actuallly close anything.
  357. if self.mode == GZ_WRITE:
  358. self._write_gzip(None)
  359. self._reset_buffer()
  360. return GzipFile.close(self)
  361. def flush(self, lib_mode=FLUSH):
  362. self._nltk_buffer.flush()
  363. GzipFile.flush(self, lib_mode)
  364. def read(self, size=None):
  365. if not size:
  366. size = self._size
  367. contents = BytesIO()
  368. while True:
  369. blocks = GzipFile.read(self, size)
  370. if not blocks:
  371. contents.flush()
  372. break
  373. contents.write(blocks)
  374. return contents.getvalue()
  375. else:
  376. return GzipFile.read(self, size)
  377. def write(self, data, size=-1):
  378. """
  379. :param data: bytes to write to file or buffer
  380. :type data: bytes
  381. :param size: buffer at least size bytes before writing to file
  382. :type size: int
  383. """
  384. if not size:
  385. size = self._size
  386. if self._len + len(data) <= size:
  387. self._write_buffer(data)
  388. else:
  389. self._write_gzip(data)
  390. class GzipFileSystemPathPointer(FileSystemPathPointer):
  391. """
  392. A subclass of ``FileSystemPathPointer`` that identifies a gzip-compressed
  393. file located at a given absolute path. ``GzipFileSystemPathPointer`` is
  394. appropriate for loading large gzip-compressed pickle objects efficiently.
  395. """
  396. def open(self, encoding=None):
  397. # Note: In >= Python3.5, GzipFile is already using a
  398. # buffered reader in the backend which has a variable self._buffer
  399. # See https://github.com/nltk/nltk/issues/1308
  400. if sys.version.startswith('2.7') or sys.version.startswith('3.4'):
  401. stream = BufferedGzipFile(self._path, 'rb')
  402. else:
  403. stream = GzipFile(self._path, 'rb')
  404. if encoding:
  405. stream = SeekableUnicodeStreamReader(stream, encoding)
  406. return stream
  407. class ZipFilePathPointer(PathPointer):
  408. """
  409. A path pointer that identifies a file contained within a zipfile,
  410. which can be accessed by reading that zipfile.
  411. """
  412. @py3_data
  413. def __init__(self, zipfile, entry=''):
  414. """
  415. Create a new path pointer pointing at the specified entry
  416. in the given zipfile.
  417. :raise IOError: If the given zipfile does not exist, or if it
  418. does not contain the specified entry.
  419. """
  420. if isinstance(zipfile, string_types):
  421. zipfile = OpenOnDemandZipFile(os.path.abspath(zipfile))
  422. # Normalize the entry string, it should be relative:
  423. entry = normalize_resource_name(entry, True, '/').lstrip('/')
  424. # Check that the entry exists:
  425. if entry != '.':
  426. try:
  427. zipfile.getinfo(entry)
  428. except Exception:
  429. # Sometimes directories aren't explicitly listed in
  430. # the zip file. So if `entry` is a directory name,
  431. # then check if the zipfile contains any files that
  432. # are under the given directory.
  433. if (entry.endswith('/') and
  434. [n for n in zipfile.namelist() if n.startswith(entry)]):
  435. pass # zipfile contains a file in that directory.
  436. else:
  437. # Otherwise, complain.
  438. raise IOError('Zipfile %r does not contain %r' %
  439. (zipfile.filename, entry))
  440. self._zipfile = zipfile
  441. self._entry = entry
  442. @property
  443. def zipfile(self):
  444. """
  445. The zipfile.ZipFile object used to access the zip file
  446. containing the entry identified by this path pointer.
  447. """
  448. return self._zipfile
  449. @property
  450. def entry(self):
  451. """
  452. The name of the file within zipfile that this path
  453. pointer points to.
  454. """
  455. return self._entry
  456. def open(self, encoding=None):
  457. data = self._zipfile.read(self._entry)
  458. stream = BytesIO(data)
  459. if self._entry.endswith('.gz'):
  460. # Note: In >= Python3.5, GzipFile is already using a
  461. # buffered reader in the backend which has a variable self._buffer
  462. # See https://github.com/nltk/nltk/issues/1308
  463. if sys.version.startswith('2.7') or sys.version.startswith('3.4'):
  464. stream = BufferedGzipFile(self._entry, fileobj=stream)
  465. else:
  466. stream = GzipFile(self._entry, fileobj=stream)
  467. elif encoding is not None:
  468. stream = SeekableUnicodeStreamReader(stream, encoding)
  469. return stream
  470. def file_size(self):
  471. return self._zipfile.getinfo(self._entry).file_size
  472. def join(self, fileid):
  473. entry = '%s/%s' % (self._entry, fileid)
  474. return ZipFilePathPointer(self._zipfile, entry)
  475. def __repr__(self):
  476. return str('ZipFilePathPointer(%r, %r)') % (
  477. self._zipfile.filename, self._entry)
  478. def __str__(self):
  479. return os.path.normpath(os.path.join(self._zipfile.filename,
  480. self._entry))
  481. ######################################################################
  482. # Access Functions
  483. ######################################################################
  484. # Don't use a weak dictionary, because in the common case this
  485. # causes a lot more reloading that necessary.
  486. _resource_cache = {}
  487. """A dictionary used to cache resources so that they won't
  488. need to be loaded more than once."""
  489. def find(resource_name, paths=None):
  490. """
  491. Find the given resource by searching through the directories and
  492. zip files in paths, where a None or empty string specifies an absolute path.
  493. Returns a corresponding path name. If the given resource is not
  494. found, raise a ``LookupError``, whose message gives a pointer to
  495. the installation instructions for the NLTK downloader.
  496. Zip File Handling:
  497. - If ``resource_name`` contains a component with a ``.zip``
  498. extension, then it is assumed to be a zipfile; and the
  499. remaining path components are used to look inside the zipfile.
  500. - If any element of ``nltk.data.path`` has a ``.zip`` extension,
  501. then it is assumed to be a zipfile.
  502. - If a given resource name that does not contain any zipfile
  503. component is not found initially, then ``find()`` will make a
  504. second attempt to find that resource, by replacing each
  505. component *p* in the path with *p.zip/p*. For example, this
  506. allows ``find()`` to map the resource name
  507. ``corpora/chat80/cities.pl`` to a zip file path pointer to
  508. ``corpora/chat80.zip/chat80/cities.pl``.
  509. - When using ``find()`` to locate a directory contained in a
  510. zipfile, the resource name must end with the forward slash
  511. character. Otherwise, ``find()`` will not locate the
  512. directory.
  513. :type resource_name: str or unicode
  514. :param resource_name: The name of the resource to search for.
  515. Resource names are posix-style relative path names, such as
  516. ``corpora/brown``. Directory names will be
  517. automatically converted to a platform-appropriate path separator.
  518. :rtype: str
  519. """
  520. resource_name = normalize_resource_name(resource_name, True)
  521. # Resolve default paths at runtime in-case the user overrides
  522. # nltk.data.path
  523. if paths is None:
  524. paths = path
  525. # Check if the resource name includes a zipfile name
  526. m = re.match(r'(.*\.zip)/?(.*)$|', resource_name)
  527. zipfile, zipentry = m.groups()
  528. # Check each item in our path
  529. for path_ in paths:
  530. # Is the path item a zipfile?
  531. if path_ and (os.path.isfile(path_) and path_.endswith('.zip')):
  532. try:
  533. return ZipFilePathPointer(path_, resource_name)
  534. except IOError:
  535. # resource not in zipfile
  536. continue
  537. # Is the path item a directory or is resource_name an absolute path?
  538. elif not path_ or os.path.isdir(path_):
  539. if zipfile is None:
  540. p = os.path.join(path_, url2pathname(resource_name))
  541. if os.path.exists(p):
  542. if p.endswith('.gz'):
  543. return GzipFileSystemPathPointer(p)
  544. else:
  545. return FileSystemPathPointer(p)
  546. else:
  547. p = os.path.join(path_, url2pathname(zipfile))
  548. if os.path.exists(p):
  549. try:
  550. return ZipFilePathPointer(p, zipentry)
  551. except IOError:
  552. # resource not in zipfile
  553. continue
  554. # Fallback: if the path doesn't include a zip file, then try
  555. # again, assuming that one of the path components is inside a
  556. # zipfile of the same name.
  557. if zipfile is None:
  558. pieces = resource_name.split('/')
  559. for i in range(len(pieces)):
  560. modified_name = '/'.join(pieces[:i] +
  561. [pieces[i] + '.zip'] + pieces[i:])
  562. try:
  563. return find(modified_name, paths)
  564. except LookupError:
  565. pass
  566. # Identify the package (i.e. the .zip file) to download.
  567. resource_zipname = resource_name.split('/')[1]
  568. if resource_zipname.endswith('.zip'):
  569. resource_zipname = resource_zipname.rpartition('.')[0]
  570. # Display a friendly error message if the resource wasn't found:
  571. msg = str("Resource \33[93m{resource}\033[0m not found.\n"
  572. "Please use the NLTK Downloader to obtain the resource:\n\n"
  573. "\33[31m" # To display red text in terminal.
  574. ">>> import nltk\n"
  575. ">>> nltk.download(\'{resource}\')\n"
  576. "\033[0m").format(resource=resource_zipname)
  577. msg = textwrap_indent(msg)
  578. msg += '\n Searched in:' + ''.join('\n - %r' % d for d in paths)
  579. sep = '*' * 70
  580. resource_not_found = '\n%s\n%s\n%s\n' % (sep, msg, sep)
  581. raise LookupError(resource_not_found)
  582. def retrieve(resource_url, filename=None, verbose=True):
  583. """
  584. Copy the given resource to a local file. If no filename is
  585. specified, then use the URL's filename. If there is already a
  586. file named ``filename``, then raise a ``ValueError``.
  587. :type resource_url: str
  588. :param resource_url: A URL specifying where the resource should be
  589. loaded from. The default protocol is "nltk:", which searches
  590. for the file in the the NLTK data package.
  591. """
  592. resource_url = normalize_resource_url(resource_url)
  593. if filename is None:
  594. if resource_url.startswith('file:'):
  595. filename = os.path.split(resource_url)[-1]
  596. else:
  597. filename = re.sub(r'(^\w+:)?.*/', '', resource_url)
  598. if os.path.exists(filename):
  599. filename = os.path.abspath(filename)
  600. raise ValueError("File %r already exists!" % filename)
  601. if verbose:
  602. print('Retrieving %r, saving to %r' % (resource_url, filename))
  603. # Open the input & output streams.
  604. infile = _open(resource_url)
  605. # Copy infile -> outfile, using 64k blocks.
  606. with open(filename, "wb") as outfile:
  607. while True:
  608. s = infile.read(1024 * 64) # 64k blocks.
  609. outfile.write(s)
  610. if not s:
  611. break
  612. infile.close()
  613. #: A dictionary describing the formats that are supported by NLTK's
  614. #: load() method. Keys are format names, and values are format
  615. #: descriptions.
  616. FORMATS = {
  617. 'pickle': "A serialized python object, stored using the pickle module.",
  618. 'json': "A serialized python object, stored using the json module.",
  619. 'yaml': "A serialized python object, stored using the yaml module.",
  620. 'cfg': "A context free grammar.",
  621. 'pcfg': "A probabilistic CFG.",
  622. 'fcfg': "A feature CFG.",
  623. 'fol': "A list of first order logic expressions, parsed with "
  624. "nltk.sem.logic.Expression.fromstring.",
  625. 'logic': "A list of first order logic expressions, parsed with "
  626. "nltk.sem.logic.LogicParser. Requires an additional logic_parser "
  627. "parameter",
  628. 'val': "A semantic valuation, parsed by nltk.sem.Valuation.fromstring.",
  629. 'raw': "The raw (byte string) contents of a file.",
  630. 'text': "The raw (unicode string) contents of a file. "
  631. }
  632. #: A dictionary mapping from file extensions to format names, used
  633. #: by load() when format="auto" to decide the format for a
  634. #: given resource url.
  635. AUTO_FORMATS = {
  636. 'pickle': 'pickle',
  637. 'json': 'json',
  638. 'yaml': 'yaml',
  639. 'cfg': 'cfg',
  640. 'pcfg': 'pcfg',
  641. 'fcfg': 'fcfg',
  642. 'fol': 'fol',
  643. 'logic': 'logic',
  644. 'val': 'val',
  645. 'txt': 'text',
  646. 'text': 'text',
  647. }
  648. def load(resource_url, format='auto', cache=True, verbose=False,
  649. logic_parser=None, fstruct_reader=None, encoding=None):
  650. """
  651. Load a given resource from the NLTK data package. The following
  652. resource formats are currently supported:
  653. - ``pickle``
  654. - ``json``
  655. - ``yaml``
  656. - ``cfg`` (context free grammars)
  657. - ``pcfg`` (probabilistic CFGs)
  658. - ``fcfg`` (feature-based CFGs)
  659. - ``fol`` (formulas of First Order Logic)
  660. - ``logic`` (Logical formulas to be parsed by the given logic_parser)
  661. - ``val`` (valuation of First Order Logic model)
  662. - ``text`` (the file contents as a unicode string)
  663. - ``raw`` (the raw file contents as a byte string)
  664. If no format is specified, ``load()`` will attempt to determine a
  665. format based on the resource name's file extension. If that
  666. fails, ``load()`` will raise a ``ValueError`` exception.
  667. For all text formats (everything except ``pickle``, ``json``, ``yaml`` and ``raw``),
  668. it tries to decode the raw contents using UTF-8, and if that doesn't
  669. work, it tries with ISO-8859-1 (Latin-1), unless the ``encoding``
  670. is specified.
  671. :type resource_url: str
  672. :param resource_url: A URL specifying where the resource should be
  673. loaded from. The default protocol is "nltk:", which searches
  674. for the file in the the NLTK data package.
  675. :type cache: bool
  676. :param cache: If true, add this resource to a cache. If load()
  677. finds a resource in its cache, then it will return it from the
  678. cache rather than loading it. The cache uses weak references,
  679. so a resource wil automatically be expunged from the cache
  680. when no more objects are using it.
  681. :type verbose: bool
  682. :param verbose: If true, print a message when loading a resource.
  683. Messages are not displayed when a resource is retrieved from
  684. the cache.
  685. :type logic_parser: LogicParser
  686. :param logic_parser: The parser that will be used to parse logical
  687. expressions.
  688. :type fstruct_reader: FeatStructReader
  689. :param fstruct_reader: The parser that will be used to parse the
  690. feature structure of an fcfg.
  691. :type encoding: str
  692. :param encoding: the encoding of the input; only used for text formats.
  693. """
  694. resource_url = normalize_resource_url(resource_url)
  695. resource_url = add_py3_data(resource_url)
  696. # Determine the format of the resource.
  697. if format == 'auto':
  698. resource_url_parts = resource_url.split('.')
  699. ext = resource_url_parts[-1]
  700. if ext == 'gz':
  701. ext = resource_url_parts[-2]
  702. format = AUTO_FORMATS.get(ext)
  703. if format is None:
  704. raise ValueError('Could not determine format for %s based '
  705. 'on its file\nextension; use the "format" '
  706. 'argument to specify the format explicitly.'
  707. % resource_url)
  708. if format not in FORMATS:
  709. raise ValueError('Unknown format type: %s!' % (format,))
  710. # If we've cached the resource, then just return it.
  711. if cache:
  712. resource_val = _resource_cache.get((resource_url, format))
  713. if resource_val is not None:
  714. if verbose:
  715. print('<<Using cached copy of %s>>' % (resource_url,))
  716. return resource_val
  717. # Let the user know what's going on.
  718. if verbose:
  719. print('<<Loading %s>>' % (resource_url,))
  720. # Load the resource.
  721. opened_resource = _open(resource_url)
  722. if format == 'raw':
  723. resource_val = opened_resource.read()
  724. elif format == 'pickle':
  725. resource_val = pickle.load(opened_resource)
  726. elif format == 'json':
  727. import json
  728. from nltk.jsontags import json_tags
  729. resource_val = json.load(opened_resource)
  730. tag = None
  731. if len(resource_val) != 1:
  732. tag = next(resource_val.keys())
  733. if tag not in json_tags:
  734. raise ValueError('Unknown json tag.')
  735. elif format == 'yaml':
  736. import yaml
  737. resource_val = yaml.load(opened_resource)
  738. else:
  739. # The resource is a text format.
  740. binary_data = opened_resource.read()
  741. if encoding is not None:
  742. string_data = binary_data.decode(encoding)
  743. else:
  744. try:
  745. string_data = binary_data.decode('utf-8')
  746. except UnicodeDecodeError:
  747. string_data = binary_data.decode('latin-1')
  748. if format == 'text':
  749. resource_val = string_data
  750. elif format == 'cfg':
  751. resource_val = nltk.grammar.CFG.fromstring(
  752. string_data, encoding=encoding)
  753. elif format == 'pcfg':
  754. resource_val = nltk.grammar.PCFG.fromstring(
  755. string_data, encoding=encoding)
  756. elif format == 'fcfg':
  757. resource_val = nltk.grammar.FeatureGrammar.fromstring(
  758. string_data, logic_parser=logic_parser,
  759. fstruct_reader=fstruct_reader, encoding=encoding)
  760. elif format == 'fol':
  761. resource_val = nltk.sem.read_logic(
  762. string_data, logic_parser=nltk.sem.logic.LogicParser(),
  763. encoding=encoding)
  764. elif format == 'logic':
  765. resource_val = nltk.sem.read_logic(
  766. string_data, logic_parser=logic_parser, encoding=encoding)
  767. elif format == 'val':
  768. resource_val = nltk.sem.read_valuation(
  769. string_data, encoding=encoding)
  770. else:
  771. raise AssertionError("Internal NLTK error: Format %s isn't "
  772. "handled by nltk.data.load()" % (format,))
  773. opened_resource.close()
  774. # If requested, add it to the cache.
  775. if cache:
  776. try:
  777. _resource_cache[(resource_url, format)] = resource_val
  778. # TODO: add this line
  779. # print('<<Caching a copy of %s>>' % (resource_url,))
  780. except TypeError:
  781. # We can't create weak references to some object types, like
  782. # strings and tuples. For now, just don't cache them.
  783. pass
  784. return resource_val
  785. def show_cfg(resource_url, escape='##'):
  786. """
  787. Write out a grammar file, ignoring escaped and empty lines.
  788. :type resource_url: str
  789. :param resource_url: A URL specifying where the resource should be
  790. loaded from. The default protocol is "nltk:", which searches
  791. for the file in the the NLTK data package.
  792. :type escape: str
  793. :param escape: Prepended string that signals lines to be ignored
  794. """
  795. resource_url = normalize_resource_url(resource_url)
  796. resource_val = load(resource_url, format='text', cache=False)
  797. lines = resource_val.splitlines()
  798. for l in lines:
  799. if l.startswith(escape):
  800. continue
  801. if re.match('^$', l):
  802. continue
  803. print(l)
  804. def clear_cache():
  805. """
  806. Remove all objects from the resource cache.
  807. :see: load()
  808. """
  809. _resource_cache.clear()
  810. def _open(resource_url):
  811. """
  812. Helper function that returns an open file object for a resource,
  813. given its resource URL. If the given resource URL uses the "nltk:"
  814. protocol, or uses no protocol, then use ``nltk.data.find`` to find
  815. its path, and open it with the given mode; if the resource URL
  816. uses the 'file' protocol, then open the file with the given mode;
  817. otherwise, delegate to ``urllib2.urlopen``.
  818. :type resource_url: str
  819. :param resource_url: A URL specifying where the resource should be
  820. loaded from. The default protocol is "nltk:", which searches
  821. for the file in the the NLTK data package.
  822. """
  823. resource_url = normalize_resource_url(resource_url)
  824. protocol, path_ = split_resource_url(resource_url)
  825. if protocol is None or protocol.lower() == 'nltk':
  826. return find(path_, path + ['']).open()
  827. elif protocol.lower() == 'file':
  828. # urllib might not use mode='rb', so handle this one ourselves:
  829. return find(path_, ['']).open()
  830. else:
  831. return urlopen(resource_url)
  832. ######################################################################
  833. # Lazy Resource Loader
  834. ######################################################################
  835. # We shouldn't apply @python_2_unicode_compatible
  836. # decorator to LazyLoader, this is resource.__class__ responsibility.
  837. class LazyLoader(object):
  838. @py3_data
  839. def __init__(self, _path):
  840. self._path = _path
  841. def __load(self):
  842. resource = load(self._path)
  843. # This is where the magic happens! Transform ourselves into
  844. # the object by modifying our own __dict__ and __class__ to
  845. # match that of `resource`.
  846. self.__dict__ = resource.__dict__
  847. self.__class__ = resource.__class__
  848. def __getattr__(self, attr):
  849. self.__load()
  850. # This looks circular, but its not, since __load() changes our
  851. # __class__ to something new:
  852. return getattr(self, attr)
  853. def __repr__(self):
  854. self.__load()
  855. # This looks circular, but its not, since __load() changes our
  856. # __class__ to something new:
  857. return repr(self)
  858. ######################################################################
  859. # Open-On-Demand ZipFile
  860. ######################################################################
  861. class OpenOnDemandZipFile(zipfile.ZipFile):
  862. """
  863. A subclass of ``zipfile.ZipFile`` that closes its file pointer
  864. whenever it is not using it; and re-opens it when it needs to read
  865. data from the zipfile. This is useful for reducing the number of
  866. open file handles when many zip files are being accessed at once.
  867. ``OpenOnDemandZipFile`` must be constructed from a filename, not a
  868. file-like object (to allow re-opening). ``OpenOnDemandZipFile`` is
  869. read-only (i.e. ``write()`` and ``writestr()`` are disabled.
  870. """
  871. @py3_data
  872. def __init__(self, filename):
  873. if not isinstance(filename, string_types):
  874. raise TypeError('ReopenableZipFile filename must be a string')
  875. zipfile.ZipFile.__init__(self, filename)
  876. assert self.filename == filename
  877. self.close()
  878. # After closing a ZipFile object, the _fileRefCnt needs to be cleared
  879. # for Python2and3 compatible code.
  880. self._fileRefCnt = 0
  881. def read(self, name):
  882. assert self.fp is None
  883. self.fp = open(self.filename, 'rb')
  884. value = zipfile.ZipFile.read(self, name)
  885. # Ensure that _fileRefCnt needs to be set for Python2and3 compatible code.
  886. # Since we only opened one file here, we add 1.
  887. self._fileRefCnt += 1
  888. self.close()
  889. return value
  890. def write(self, *args, **kwargs):
  891. """:raise NotImplementedError: OpenOnDemandZipfile is read-only"""
  892. raise NotImplementedError('OpenOnDemandZipfile is read-only')
  893. def writestr(self, *args, **kwargs):
  894. """:raise NotImplementedError: OpenOnDemandZipfile is read-only"""
  895. raise NotImplementedError('OpenOnDemandZipfile is read-only')
  896. def __repr__(self):
  897. return repr(str('OpenOnDemandZipFile(%r)') % self.filename)
  898. ######################################################################
  899. #{ Seekable Unicode Stream Reader
  900. ######################################################################
  901. class SeekableUnicodeStreamReader(object):
  902. """
  903. A stream reader that automatically encodes the source byte stream
  904. into unicode (like ``codecs.StreamReader``); but still supports the
  905. ``seek()`` and ``tell()`` operations correctly. This is in contrast
  906. to ``codecs.StreamReader``, which provide *broken* ``seek()`` and
  907. ``tell()`` methods.
  908. This class was motivated by ``StreamBackedCorpusView``, which
  909. makes extensive use of ``seek()`` and ``tell()``, and needs to be
  910. able to handle unicode-encoded files.
  911. Note: this class requires stateless decoders. To my knowledge,
  912. this shouldn't cause a problem with any of python's builtin
  913. unicode encodings.
  914. """
  915. DEBUG = True # : If true, then perform extra sanity checks.
  916. @py3_data
  917. def __init__(self, stream, encoding, errors='strict'):
  918. # Rewind the stream to its beginning.
  919. stream.seek(0)
  920. self.stream = stream
  921. """The underlying stream."""
  922. self.encoding = encoding
  923. """The name of the encoding that should be used to encode the
  924. underlying stream."""
  925. self.errors = errors
  926. """The error mode that should be used when decoding data from
  927. the underlying stream. Can be 'strict', 'ignore', or
  928. 'replace'."""
  929. self.decode = codecs.getdecoder(encoding)
  930. """The function that is used to decode byte strings into
  931. unicode strings."""
  932. self.bytebuffer = b''
  933. """A buffer to use bytes that have been read but have not yet
  934. been decoded. This is only used when the final bytes from
  935. a read do not form a complete encoding for a character."""
  936. self.linebuffer = None
  937. """A buffer used by ``readline()`` to hold characters that have
  938. been read, but have not yet been returned by ``read()`` or
  939. ``readline()``. This buffer consists of a list of unicode
  940. strings, where each string corresponds to a single line.
  941. The final element of the list may or may not be a complete
  942. line. Note that the existence of a linebuffer makes the
  943. ``tell()`` operation more complex, because it must backtrack
  944. to the beginning of the buffer to determine the correct
  945. file position in the underlying byte stream."""
  946. self._rewind_checkpoint = 0
  947. """The file position at which the most recent read on the
  948. underlying stream began. This is used, together with
  949. ``_rewind_numchars``, to backtrack to the beginning of
  950. ``linebuffer`` (which is required by ``tell()``)."""
  951. self._rewind_numchars = None
  952. """The number of characters that have been returned since the
  953. read that started at ``_rewind_checkpoint``. This is used,
  954. together with ``_rewind_checkpoint``, to backtrack to the
  955. beginning of ``linebuffer`` (which is required by ``tell()``)."""
  956. self._bom = self._check_bom()
  957. """The length of the byte order marker at the beginning of
  958. the stream (or None for no byte order marker)."""
  959. #/////////////////////////////////////////////////////////////////
  960. # Read methods
  961. #/////////////////////////////////////////////////////////////////
  962. def read(self, size=None):
  963. """
  964. Read up to ``size`` bytes, decode them using this reader's
  965. encoding, and return the resulting unicode string.
  966. :param size: The maximum number of bytes to read. If not
  967. specified, then read as many bytes as possible.
  968. :type size: int
  969. :rtype: unicode
  970. """
  971. chars = self._read(size)
  972. # If linebuffer is not empty, then include it in the result
  973. if self.linebuffer:
  974. chars = ''.join(self.linebuffer) + chars
  975. self.linebuffer = None
  976. self._rewind_numchars = None
  977. return chars
  978. def readline(self, size=None):
  979. """
  980. Read a line of text, decode it using this reader's encoding,
  981. and return the resulting unicode string.
  982. :param size: The maximum number of bytes to read. If no
  983. newline is encountered before ``size`` bytes have been read,
  984. then the returned value may not be a complete line of text.
  985. :type size: int
  986. """
  987. # If we have a non-empty linebuffer, then return the first
  988. # line from it. (Note that the last element of linebuffer may
  989. # not be a complete line; so let _read() deal with it.)
  990. if self.linebuffer and len(self.linebuffer) > 1:
  991. line = self.linebuffer.pop(0)
  992. self._rewind_numchars += len(line)
  993. return line
  994. readsize = size or 72
  995. chars = ''
  996. # If there's a remaining incomplete line in the buffer, add it.
  997. if self.linebuffer:
  998. chars += self.linebuffer.pop()
  999. self.linebuffer = None
  1000. while True:
  1001. startpos = self.stream.tell() - len(self.bytebuffer)
  1002. new_chars = self._read(readsize)
  1003. # If we're at a '\r', then read one extra character, since
  1004. # it might be a '\n', to get the proper line ending.
  1005. if new_chars and new_chars.endswith('\r'):
  1006. new_chars += self._read(1)
  1007. chars += new_chars
  1008. lines = chars.splitlines(True)
  1009. if len(lines) > 1:
  1010. line = lines[0]
  1011. self.linebuffer = lines[1:]
  1012. self._rewind_numchars = (len(new_chars) -
  1013. (len(chars) - len(line)))
  1014. self._rewind_checkpoint = startpos
  1015. break
  1016. elif len(lines) == 1:
  1017. line0withend = lines[0]
  1018. line0withoutend = lines[0].splitlines(False)[0]
  1019. if line0withend != line0withoutend: # complete line
  1020. line = line0withend
  1021. break
  1022. if not new_chars or size is not None:
  1023. line = chars
  1024. break
  1025. # Read successively larger blocks of text.
  1026. if readsize < 8000:
  1027. readsize *= 2
  1028. return line
  1029. def readlines(self, sizehint=None, keepends=True):
  1030. """
  1031. Read this file's contents, decode them using this reader's
  1032. encoding, and return it as a list of unicode lines.
  1033. :rtype: list(unicode)
  1034. :param sizehint: Ignored.
  1035. :param keepends: If false, then strip newlines.
  1036. """
  1037. return self.read().splitlines(keepends)
  1038. def next(self):
  1039. """Return the next decoded line from the underlying stream."""
  1040. line = self.readline()
  1041. if line:
  1042. return line
  1043. else:
  1044. raise StopIteration
  1045. def __next__(self):
  1046. return self.next()
  1047. def __iter__(self):
  1048. """Return self"""
  1049. return self
  1050. def xreadlines(self):
  1051. """Return self"""
  1052. return self
  1053. #/////////////////////////////////////////////////////////////////
  1054. # Pass-through methods & properties
  1055. #/////////////////////////////////////////////////////////////////
  1056. @property
  1057. def closed(self):
  1058. """True if the underlying stream is closed."""
  1059. return self.stream.closed
  1060. @property
  1061. def name(self):
  1062. """The name of the underlying stream."""
  1063. return self.stream.name
  1064. @property
  1065. def mode(self):
  1066. """The mode of the underlying stream."""
  1067. return self.stream.mode
  1068. def close(self):
  1069. """
  1070. Close the underlying stream.
  1071. """
  1072. self.stream.close()
  1073. #/////////////////////////////////////////////////////////////////
  1074. # Seek and tell
  1075. #/////////////////////////////////////////////////////////////////
  1076. def seek(self, offset, whence=0):
  1077. """
  1078. Move the stream to a new file position. If the reader is
  1079. maintaining any buffers, then they will be cleared.
  1080. :param offset: A byte count offset.
  1081. :param whence: If 0, then the offset is from the start of the file
  1082. (offset should be positive), if 1, then the offset is from the
  1083. current position (offset may be positive or negative); and if 2,
  1084. then the offset is from the end of the file (offset should
  1085. typically be negative).
  1086. """
  1087. if whence == 1:
  1088. raise ValueError('Relative seek is not supported for '
  1089. 'SeekableUnicodeStreamReader -- consider '
  1090. 'using char_seek_forward() instead.')
  1091. self.stream.seek(offset, whence)
  1092. self.linebuffer = None
  1093. self.bytebuffer = b''
  1094. self._rewind_numchars = None
  1095. self._rewind_checkpoint = self.stream.tell()
  1096. def char_seek_forward(self, offset):
  1097. """
  1098. Move the read pointer forward by ``offset`` characters.
  1099. """
  1100. if offset < 0:
  1101. raise ValueError('Negative offsets are not supported')
  1102. # Clear all buffers.
  1103. self.seek(self.tell())
  1104. # Perform the seek operation.
  1105. self._char_seek_forward(offset)
  1106. def _char_seek_forward(self, offset, est_bytes=None):
  1107. """
  1108. Move the file position forward by ``offset`` characters,
  1109. ignoring all buffers.
  1110. :param est_bytes: A hint, giving an estimate of the number of
  1111. bytes that will be needed to move forward by ``offset`` chars.
  1112. Defaults to ``offset``.
  1113. """
  1114. if est_bytes is None:
  1115. est_bytes = offset
  1116. bytes = b''
  1117. while True:
  1118. # Read in a block of bytes.
  1119. newbytes = self.stream.read(est_bytes - len(bytes))
  1120. bytes += newbytes
  1121. # Decode the bytes to characters.
  1122. chars, bytes_decoded = self._incr_decode(bytes)
  1123. # If we got the right number of characters, then seek
  1124. # backwards over any truncated characters, and return.
  1125. if len(chars) == offset:
  1126. self.stream.seek(-len(bytes) + bytes_decoded, 1)
  1127. return
  1128. # If we went too far, then we can back-up until we get it
  1129. # right, using the bytes we've already read.
  1130. if len(chars) > offset:
  1131. while len(chars) > offset:
  1132. # Assume at least one byte/char.
  1133. est_bytes += offset - len(chars)
  1134. chars, bytes_decoded = self._incr_decode(bytes[:est_bytes])
  1135. self.stream.seek(-len(bytes) + bytes_decoded, 1)
  1136. return
  1137. # Otherwise, we haven't read enough bytes yet; loop again.
  1138. est_bytes += offset - len(chars)
  1139. def tell(self):
  1140. """
  1141. Return the current file position on the underlying byte
  1142. stream. If this reader is maintaining any buffers, then the
  1143. returned file position will be the position of the beginning
  1144. of those buffers.
  1145. """

Large files files are truncated, but you can click here to view the full file