nltk 3.2.1__zip → 3.3__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nltk-3.2.1 → nltk-3.3}/LICENSE.txt +1 -1
- {nltk-3.2.1/nltk.egg-info → nltk-3.3}/PKG-INFO +13 -5
- nltk-3.3/README.md +49 -0
- nltk-3.3/nltk/VERSION +1 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/__init__.py +3 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/app/__init__.py +2 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/app/chartparser_app.py +92 -92
- {nltk-3.2.1 → nltk-3.3}/nltk/app/chunkparser_app.py +11 -13
- {nltk-3.2.1 → nltk-3.3}/nltk/app/collocations_app.py +8 -11
- {nltk-3.2.1 → nltk-3.3}/nltk/app/concordance_app.py +9 -11
- {nltk-3.2.1 → nltk-3.3}/nltk/app/nemo_app.py +18 -17
- {nltk-3.2.1 → nltk-3.3}/nltk/app/rdparser_app.py +10 -12
- {nltk-3.2.1 → nltk-3.3}/nltk/app/srparser_app.py +16 -16
- {nltk-3.2.1 → nltk-3.3}/nltk/app/wordfreq_app.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/app/wordnet_app.py +11 -11
- {nltk-3.2.1 → nltk-3.3}/nltk/book.py +2 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/ccg/__init__.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/ccg/api.py +67 -47
- {nltk-3.2.1 → nltk-3.3}/nltk/ccg/chart.py +7 -5
- {nltk-3.2.1 → nltk-3.3}/nltk/ccg/combinator.py +42 -11
- {nltk-3.2.1 → nltk-3.3}/nltk/ccg/lexicon.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/ccg/logic.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/chat/__init__.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/chat/eliza.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/chat/iesha.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/chat/rude.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/chat/suntsu.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/chat/util.py +12 -10
- {nltk-3.2.1 → nltk-3.3}/nltk/chat/zen.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/chunk/__init__.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/chunk/api.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/chunk/named_entity.py +13 -13
- {nltk-3.2.1 → nltk-3.3}/nltk/chunk/regexp.py +9 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/chunk/util.py +12 -12
- {nltk-3.2.1 → nltk-3.3}/nltk/classify/__init__.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/classify/api.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/classify/decisiontree.py +18 -18
- {nltk-3.2.1 → nltk-3.3}/nltk/classify/maxent.py +26 -8
- {nltk-3.2.1 → nltk-3.3}/nltk/classify/megam.py +5 -4
- {nltk-3.2.1 → nltk-3.3}/nltk/classify/naivebayes.py +29 -26
- {nltk-3.2.1 → nltk-3.3}/nltk/classify/rte_classify.py +58 -89
- {nltk-3.2.1 → nltk-3.3}/nltk/classify/scikitlearn.py +4 -2
- {nltk-3.2.1 → nltk-3.3}/nltk/classify/senna.py +24 -22
- {nltk-3.2.1 → nltk-3.3}/nltk/classify/svm.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/classify/tadm.py +4 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/classify/textcat.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/classify/util.py +13 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/classify/weka.py +7 -6
- {nltk-3.2.1 → nltk-3.3}/nltk/cluster/__init__.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/cluster/api.py +9 -5
- {nltk-3.2.1 → nltk-3.3}/nltk/cluster/em.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/cluster/gaac.py +3 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/cluster/kmeans.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/cluster/util.py +35 -20
- nltk-3.3/nltk/collections.py +640 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/collocations.py +2 -2
- nltk-3.3/nltk/compat.py +365 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/__init__.py +37 -16
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/europarl_raw.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/__init__.py +4 -2
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/aligned.py +4 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/api.py +12 -10
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/bnc.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/bracket_parse.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/categorized_sents.py +4 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/chasen.py +5 -4
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/childes.py +8 -9
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/chunked.py +4 -4
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/cmudict.py +4 -2
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/comparative_sents.py +4 -2
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/conll.py +19 -12
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/crubadan.py +2 -2
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/dependency.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/framenet.py +1085 -119
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/ieer.py +4 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/indian.py +4 -5
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/ipipan.py +6 -5
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/knbc.py +2 -2
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/lin.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/mte.py +5 -4
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/nkjp.py +4 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/nombank.py +8 -8
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/nps_chat.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/opinion_lexicon.py +3 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/panlex_lite.py +1 -1
- nltk-3.3/nltk/corpus/reader/pl196x.py +292 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/plaintext.py +3 -4
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/ppattach.py +4 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/propbank.py +8 -10
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/pros_cons.py +5 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/reviews.py +3 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/rte.py +5 -7
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/semcor.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/senseval.py +4 -2
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/sentiwordnet.py +3 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/sinica_treebank.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/string_category.py +4 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/switchboard.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/tagged.py +4 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/timit.py +10 -8
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/toolbox.py +4 -4
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/twitter.py +4 -6
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/util.py +7 -3
- nltk-3.3/nltk/corpus/reader/verbnet.py +595 -0
- nltk-3.3/nltk/corpus/reader/wordlist.py +134 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/wordnet.py +357 -285
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/xmldocs.py +10 -5
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/ycoe.py +25 -24
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/util.py +22 -5
- {nltk-3.2.1 → nltk-3.3}/nltk/data.py +65 -29
- {nltk-3.2.1 → nltk-3.3}/nltk/decorators.py +5 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/downloader.py +59 -55
- {nltk-3.2.1 → nltk-3.3}/nltk/draw/__init__.py +4 -4
- {nltk-3.2.1 → nltk-3.3}/nltk/draw/cfg.py +5 -8
- {nltk-3.2.1 → nltk-3.3}/nltk/draw/dispersion.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/draw/table.py +4 -4
- {nltk-3.2.1 → nltk-3.3}/nltk/draw/tree.py +2 -5
- {nltk-3.2.1 → nltk-3.3}/nltk/draw/util.py +17 -17
- {nltk-3.2.1 → nltk-3.3}/nltk/featstruct.py +290 -173
- {nltk-3.2.1 → nltk-3.3}/nltk/grammar.py +87 -44
- {nltk-3.2.1 → nltk-3.3}/nltk/help.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/inference/__init__.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/inference/api.py +27 -19
- {nltk-3.2.1 → nltk-3.3}/nltk/inference/discourse.py +20 -16
- {nltk-3.2.1 → nltk-3.3}/nltk/inference/nonmonotonic.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/inference/prover9.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/inference/resolution.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/inference/tableau.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/internals.py +44 -44
- {nltk-3.2.1 → nltk-3.3}/nltk/jsontags.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/metrics/__init__.py +2 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/metrics/agreement.py +29 -9
- nltk-3.3/nltk/metrics/aline.py +607 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/metrics/association.py +8 -4
- {nltk-3.2.1 → nltk-3.3}/nltk/metrics/confusionmatrix.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/metrics/distance.py +12 -7
- {nltk-3.2.1 → nltk-3.3}/nltk/metrics/paice.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/metrics/scores.py +7 -7
- {nltk-3.2.1 → nltk-3.3}/nltk/metrics/segmentation.py +4 -5
- {nltk-3.2.1 → nltk-3.3}/nltk/metrics/spearman.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/misc/__init__.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/misc/chomsky.py +4 -2
- {nltk-3.2.1 → nltk-3.3}/nltk/misc/minimalset.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/misc/sort.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/misc/wordfinder.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/parse/__init__.py +2 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/parse/api.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/parse/bllip.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/parse/chart.py +8 -7
- nltk-3.3/nltk/parse/corenlp.py +780 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/parse/dependencygraph.py +4 -2
- {nltk-3.2.1 → nltk-3.3}/nltk/parse/earleychart.py +4 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/parse/evaluate.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/parse/featurechart.py +6 -4
- {nltk-3.2.1 → nltk-3.3}/nltk/parse/generate.py +15 -4
- {nltk-3.2.1 → nltk-3.3}/nltk/parse/malt.py +2 -2
- {nltk-3.2.1 → nltk-3.3}/nltk/parse/nonprojectivedependencyparser.py +3 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/parse/pchart.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/parse/projectivedependencyparser.py +6 -5
- {nltk-3.2.1 → nltk-3.3}/nltk/parse/recursivedescent.py +2 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/parse/shiftreduce.py +2 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/parse/stanford.py +53 -28
- {nltk-3.2.1 → nltk-3.3}/nltk/parse/transitionparser.py +11 -9
- {nltk-3.2.1 → nltk-3.3}/nltk/parse/util.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/parse/viterbi.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/probability.py +75 -20
- {nltk-3.2.1 → nltk-3.3}/nltk/sem/__init__.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/sem/boxer.py +15 -15
- {nltk-3.2.1 → nltk-3.3}/nltk/sem/chat80.py +6 -6
- {nltk-3.2.1 → nltk-3.3}/nltk/sem/cooper_storage.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/sem/drt.py +9 -8
- {nltk-3.2.1 → nltk-3.3}/nltk/sem/drt_glue_demo.py +5 -9
- {nltk-3.2.1 → nltk-3.3}/nltk/sem/evaluate.py +9 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/sem/glue.py +8 -6
- {nltk-3.2.1 → nltk-3.3}/nltk/sem/hole.py +4 -2
- {nltk-3.2.1 → nltk-3.3}/nltk/sem/lfg.py +4 -2
- {nltk-3.2.1 → nltk-3.3}/nltk/sem/linearlogic.py +4 -2
- {nltk-3.2.1 → nltk-3.3}/nltk/sem/logic.py +14 -14
- {nltk-3.2.1 → nltk-3.3}/nltk/sem/relextract.py +11 -18
- {nltk-3.2.1 → nltk-3.3}/nltk/sem/skolemize.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/sem/util.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/sentiment/__init__.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/sentiment/sentiment_analyzer.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/sentiment/util.py +14 -4
- {nltk-3.2.1 → nltk-3.3}/nltk/sentiment/vader.py +41 -42
- {nltk-3.2.1 → nltk-3.3}/nltk/stem/__init__.py +1 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/stem/api.py +7 -4
- nltk-3.3/nltk/stem/arlstem.py +369 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/stem/isri.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/stem/lancaster.py +39 -12
- nltk-3.3/nltk/stem/porter.py +710 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/stem/regexp.py +2 -2
- {nltk-3.2.1 → nltk-3.3}/nltk/stem/rslp.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/stem/snowball.py +537 -13
- {nltk-3.2.1 → nltk-3.3}/nltk/stem/util.py +11 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/stem/wordnet.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/tag/__init__.py +32 -7
- {nltk-3.2.1 → nltk-3.3}/nltk/tag/api.py +13 -8
- {nltk-3.2.1 → nltk-3.3}/nltk/tag/brill.py +4 -6
- {nltk-3.2.1 → nltk-3.3}/nltk/tag/crf.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/tag/hmm.py +11 -11
- {nltk-3.2.1 → nltk-3.3}/nltk/tag/hunpos.py +4 -4
- {nltk-3.2.1 → nltk-3.3}/nltk/tag/mapping.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/tag/perceptron.py +25 -10
- {nltk-3.2.1 → nltk-3.3}/nltk/tag/senna.py +25 -23
- {nltk-3.2.1 → nltk-3.3}/nltk/tag/sequential.py +19 -15
- {nltk-3.2.1 → nltk-3.3}/nltk/tag/stanford.py +59 -36
- {nltk-3.2.1 → nltk-3.3}/nltk/tag/tnt.py +11 -20
- {nltk-3.2.1 → nltk-3.3}/nltk/tag/util.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/tbl/__init__.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/tbl/demo.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/tbl/erroranalysis.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/tbl/feature.py +5 -7
- {nltk-3.2.1 → nltk-3.3}/nltk/tbl/rule.py +6 -6
- {nltk-3.2.1 → nltk-3.3}/nltk/tbl/template.py +18 -23
- {nltk-3.2.1 → nltk-3.3}/nltk/test/__init__.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/all.py +7 -6
- {nltk-3.2.1 → nltk-3.3}/nltk/test/bnc.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/ccg.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/ccg_semantics.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/chat80.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/childes_fixt.py +1 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/chunk.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/classify.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/classify_fixt.py +2 -1
- nltk-3.3/nltk/test/collections.doctest +20 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/collocations.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/compat.doctest +0 -4
- {nltk-3.2.1 → nltk-3.3}/nltk/test/compat_fixt.py +1 -0
- nltk-3.3/nltk/test/concordance.doctest +55 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/corpus.doctest +38 -49
- {nltk-3.2.1 → nltk-3.3}/nltk/test/crubadan.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/data.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/dependency.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/discourse.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/discourse_fixt.py +1 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/doctest_nose_plugin.py +8 -5
- {nltk-3.2.1 → nltk-3.3}/nltk/test/drt.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/featgram.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/featstruct.doctest +2 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/test/framenet.doctest +82 -33
- {nltk-3.2.1 → nltk-3.3}/nltk/test/generate.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/gensim.doctest +6 -7
- {nltk-3.2.1 → nltk-3.3}/nltk/test/gensim_fixt.py +1 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/gluesemantics.doctest +13 -15
- {nltk-3.2.1 → nltk-3.3}/nltk/test/gluesemantics_malt.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/gluesemantics_malt_fixt.py +1 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/grammar.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/grammartestsuites.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/index.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/inference.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/inference_fixt.py +1 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/internals.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/japanese.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/logic.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/metrics.doctest +3 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/test/misc.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/nonmonotonic.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/nonmonotonic_fixt.py +1 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/parse.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/portuguese_en.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/probability.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/probability_fixt.py +2 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/propbank.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/relextract.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/resolution.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/runtests.py +35 -13
- {nltk-3.2.1 → nltk-3.3}/nltk/test/semantics.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/sentiment.doctest +3 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/test/sentiwordnet.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/simple.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/stem.doctest +2 -2
- {nltk-3.2.1 → nltk-3.3}/nltk/test/tag.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/tokenize.doctest +109 -2
- {nltk-3.2.1 → nltk-3.3}/nltk/test/toolbox.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/translate.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/tree.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/treeprettyprinter.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/treetransforms.doctest +1 -1
- nltk-3.3/nltk/test/unit/test_aline.py +52 -0
- nltk-3.3/nltk/test/unit/test_chunk.py +56 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/test_classify.py +20 -18
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/test_collocations.py +16 -7
- nltk-3.3/nltk/test/unit/test_concordance.py +98 -0
- nltk-3.3/nltk/test/unit/test_corenlp.py +1000 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/test_corpora.py +18 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/test_json2csv_corpus.py +4 -3
- nltk-3.3/nltk/test/unit/test_rte_classify.py +86 -0
- nltk-3.3/nltk/test/unit/test_senna.py +74 -0
- nltk-3.3/nltk/test/unit/test_stem.py +121 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/test_tgrep.py +4 -2
- nltk-3.3/nltk/test/unit/test_tokenize.py +168 -0
- nltk-3.3/nltk/test/unit/test_wordnet.py +134 -0
- nltk-3.3/nltk/test/unit/translate/test_bleu.py +244 -0
- nltk-3.3/nltk/test/unit/translate/test_gdfa.py +57 -0
- nltk-3.3/nltk/test/unit/translate/test_nist.py +37 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/translate/test_stack_decoder.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/util.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/wordnet.doctest +17 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/test/wordnet_fixt.py +1 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/wordnet_lch.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/test/wsd.doctest +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/text.py +92 -39
- {nltk-3.2.1 → nltk-3.3}/nltk/tgrep.py +8 -7
- {nltk-3.2.1 → nltk-3.3}/nltk/tokenize/__init__.py +37 -15
- {nltk-3.2.1 → nltk-3.3}/nltk/tokenize/api.py +3 -4
- {nltk-3.2.1 → nltk-3.3}/nltk/tokenize/casual.py +10 -9
- {nltk-3.2.1 → nltk-3.3}/nltk/tokenize/mwe.py +2 -2
- nltk-3.3/nltk/tokenize/nist.py +173 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/tokenize/punkt.py +186 -167
- {nltk-3.2.1 → nltk-3.3}/nltk/tokenize/regexp.py +13 -7
- nltk-3.3/nltk/tokenize/repp.py +151 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/tokenize/sexpr.py +4 -6
- {nltk-3.2.1 → nltk-3.3}/nltk/tokenize/simple.py +7 -5
- {nltk-3.2.1 → nltk-3.3}/nltk/tokenize/stanford.py +18 -14
- nltk-3.3/nltk/tokenize/stanford_segmenter.py +246 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/tokenize/texttiling.py +43 -45
- nltk-3.3/nltk/tokenize/toktok.py +155 -0
- nltk-3.3/nltk/tokenize/treebank.py +363 -0
- nltk-3.3/nltk/tokenize/util.py +261 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/toolbox.py +4 -2
- {nltk-3.2.1 → nltk-3.3}/nltk/translate/__init__.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/translate/api.py +50 -40
- {nltk-3.2.1 → nltk-3.3}/nltk/translate/bleu_score.py +221 -156
- nltk-3.3/nltk/translate/chrf_score.py +137 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/translate/gale_church.py +32 -19
- {nltk-3.2.1 → nltk-3.3}/nltk/translate/gdfa.py +14 -10
- nltk-3.3/nltk/translate/gleu_score.py +193 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/translate/ibm1.py +17 -8
- {nltk-3.2.1 → nltk-3.3}/nltk/translate/ibm2.py +4 -4
- {nltk-3.2.1 → nltk-3.3}/nltk/translate/ibm4.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/translate/ibm5.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/translate/ibm_model.py +4 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/translate/metrics.py +1 -1
- nltk-3.3/nltk/translate/nist_score.py +178 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/translate/phrase_based.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/translate/ribes_score.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/translate/stack_decoder.py +5 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/tree.py +10 -8
- {nltk-3.2.1 → nltk-3.3}/nltk/treeprettyprinter.py +6 -6
- {nltk-3.2.1 → nltk-3.3}/nltk/twitter/__init__.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/twitter/api.py +8 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/twitter/common.py +9 -3
- {nltk-3.2.1 → nltk-3.3}/nltk/twitter/twitter_demo.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/twitter/twitterclient.py +1 -1
- {nltk-3.2.1 → nltk-3.3}/nltk/twitter/util.py +5 -4
- {nltk-3.2.1 → nltk-3.3}/nltk/util.py +41 -654
- {nltk-3.2.1 → nltk-3.3}/nltk/wsd.py +2 -2
- {nltk-3.2.1 → nltk-3.3/nltk.egg-info}/PKG-INFO +13 -5
- {nltk-3.2.1 → nltk-3.3}/nltk.egg-info/SOURCES.txt +23 -1
- nltk-3.3/nltk.egg-info/requires.txt +31 -0
- {nltk-3.2.1 → nltk-3.3}/setup.cfg +0 -1
- {nltk-3.2.1 → nltk-3.3}/setup.py +32 -5
- nltk-3.2.1/nltk/VERSION +0 -1
- nltk-3.2.1/nltk/compat.py +0 -706
- nltk-3.2.1/nltk/corpus/reader/pl196x.py +0 -278
- nltk-3.2.1/nltk/corpus/reader/verbnet.py +0 -408
- nltk-3.2.1/nltk/corpus/reader/wordlist.py +0 -37
- nltk-3.2.1/nltk/six.py +0 -868
- nltk-3.2.1/nltk/stem/porter.py +0 -692
- nltk-3.2.1/nltk/test/unit/test_stem.py +0 -36
- nltk-3.2.1/nltk/test/unit/test_tokenize.py +0 -23
- nltk-3.2.1/nltk/test/unit/translate/test_bleu.py +0 -138
- nltk-3.2.1/nltk/tokenize/stanford_segmenter.py +0 -157
- nltk-3.2.1/nltk/tokenize/treebank.py +0 -124
- nltk-3.2.1/nltk/tokenize/util.py +0 -90
- {nltk-3.2.1 → nltk-3.3}/INSTALL.txt +0 -0
- {nltk-3.2.1 → nltk-3.3}/MANIFEST.in +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/classify/positivenaivebayes.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/corpus/reader/udhr.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/inference/mace.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/lazyimport.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/misc/babelfish.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/tag/brill_trainer.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/tbl/api.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/bleu.doctest +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/childes.doctest +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/corpus_fixt.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/paice.doctest +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/portuguese_en_fixt.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/segmentation_fixt.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/semantics_fixt.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/translate_fixt.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/__init__.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/test_2x_compat.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/test_corpus_views.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/test_hmm.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/test_naivebayes.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/test_seekable_unicode_stream_reader.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/test_tag.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/test_twitter_auth.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/translate/__init__.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/translate/test_ibm1.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/translate/test_ibm2.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/translate/test_ibm3.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/translate/test_ibm4.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/translate/test_ibm5.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/translate/test_ibm_model.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/test/unit/utils.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/translate/ibm3.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk/treetransforms.py +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk.egg-info/dependency_links.txt +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk.egg-info/not-zip-safe +0 -0
- {nltk-3.2.1 → nltk-3.3}/nltk.egg-info/top_level.txt +0 -0
|
@@ -1,28 +1,57 @@
|
|
|
1
1
|
# Natural Language Toolkit: Framenet Corpus Reader
|
|
2
2
|
#
|
|
3
|
-
# Copyright (C) 2001-
|
|
3
|
+
# Copyright (C) 2001-2018 NLTK Project
|
|
4
4
|
# Authors: Chuck Wooters <wooters@icsi.berkeley.edu>,
|
|
5
|
-
# Nathan Schneider <
|
|
5
|
+
# Nathan Schneider <nathan.schneider@georgetown.edu>
|
|
6
6
|
# URL: <http://nltk.org/>
|
|
7
7
|
# For license information, see LICENSE.TXT
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
|
|
10
10
|
"""
|
|
11
|
-
Corpus reader for the
|
|
11
|
+
Corpus reader for the FrameNet 1.7 lexicon and corpus.
|
|
12
12
|
"""
|
|
13
|
-
|
|
14
|
-
__docformat__ = 'epytext en'
|
|
13
|
+
from __future__ import print_function, unicode_literals
|
|
15
14
|
|
|
16
15
|
import os, sys
|
|
17
16
|
import re
|
|
18
17
|
import textwrap
|
|
19
|
-
|
|
18
|
+
import itertools
|
|
19
|
+
import types
|
|
20
|
+
|
|
21
|
+
from six import string_types, text_type
|
|
22
|
+
from six.moves import zip_longest
|
|
23
|
+
|
|
24
|
+
from collections import defaultdict, OrderedDict
|
|
25
|
+
from operator import itemgetter
|
|
20
26
|
from pprint import pprint, pformat
|
|
21
27
|
from nltk.internals import ElementWrapper
|
|
22
28
|
from nltk.corpus.reader import XMLCorpusReader, XMLCorpusView
|
|
23
|
-
from nltk.compat import
|
|
24
|
-
from nltk.util import AbstractLazySequence, LazyMap
|
|
29
|
+
from nltk.compat import python_2_unicode_compatible
|
|
30
|
+
from nltk.util import AbstractLazySequence, LazyConcatenation, LazyMap, LazyIteratorList
|
|
25
31
|
|
|
32
|
+
__docformat__ = 'epytext en'
|
|
33
|
+
|
|
34
|
+
def mimic_wrap(lines, wrap_at=65, **kwargs):
|
|
35
|
+
"""
|
|
36
|
+
Wrap the first of 'lines' with textwrap and the remaining lines at exactly the same
|
|
37
|
+
positions as the first.
|
|
38
|
+
"""
|
|
39
|
+
l0 = textwrap.fill(lines[0], wrap_at, drop_whitespace=False).split('\n')
|
|
40
|
+
yield l0
|
|
41
|
+
|
|
42
|
+
def _(line):
|
|
43
|
+
il0 = 0
|
|
44
|
+
while line and il0<len(l0)-1:
|
|
45
|
+
yield line[:len(l0[il0])]
|
|
46
|
+
line = line[len(l0[il0]):]
|
|
47
|
+
il0 += 1
|
|
48
|
+
if line: # Remaining stuff on this line past the end of the mimicked line.
|
|
49
|
+
# So just textwrap this line.
|
|
50
|
+
for ln in textwrap.fill(line, wrap_at, drop_whitespace=False).split('\n'):
|
|
51
|
+
yield ln
|
|
52
|
+
|
|
53
|
+
for l in lines[1:]:
|
|
54
|
+
yield list(_(l))
|
|
26
55
|
|
|
27
56
|
def _pretty_longstring(defstr, prefix='', wrap_at=65):
|
|
28
57
|
|
|
@@ -163,11 +192,373 @@ def _pretty_lu(lu):
|
|
|
163
192
|
if 'semTypes' in lukeys:
|
|
164
193
|
outstr += "\n[semTypes] {0} semantic types\n".format(len(lu.semTypes))
|
|
165
194
|
outstr += " "*(len(lu.semTypes)>0) + ", ".join('{0}({1})'.format(x.name, x.ID) for x in lu.semTypes) + '\n'*(len(lu.semTypes)>0)
|
|
195
|
+
if 'URL' in lukeys:
|
|
196
|
+
outstr += "\n[URL] {0}\n".format(lu.URL)
|
|
166
197
|
if 'subCorpus' in lukeys:
|
|
167
198
|
subc = [x.name for x in lu.subCorpus]
|
|
168
199
|
outstr += "\n[subCorpus] {0} subcorpora\n".format(len(lu.subCorpus))
|
|
169
200
|
for line in textwrap.fill(", ".join(sorted(subc)), 60).split('\n'):
|
|
170
201
|
outstr += " {0}\n".format(line)
|
|
202
|
+
if 'exemplars' in lukeys:
|
|
203
|
+
outstr += "\n[exemplars] {0} sentences across all subcorpora\n".format(len(lu.exemplars))
|
|
204
|
+
|
|
205
|
+
return outstr
|
|
206
|
+
|
|
207
|
+
def _pretty_exemplars(exemplars, lu):
|
|
208
|
+
"""
|
|
209
|
+
Helper function for pretty-printing a list of exemplar sentences for a lexical unit.
|
|
210
|
+
|
|
211
|
+
:param sent: The list of exemplar sentences to be printed.
|
|
212
|
+
:type sent: list(AttrDict)
|
|
213
|
+
:return: An index of the text of the exemplar sentences.
|
|
214
|
+
:rtype: str
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
outstr = ""
|
|
218
|
+
outstr += "exemplar sentences for {0.name} in {0.frame.name}:\n\n".format(lu)
|
|
219
|
+
for i,sent in enumerate(exemplars):
|
|
220
|
+
outstr += "[{0}] {1}\n".format(i, sent.text)
|
|
221
|
+
outstr += "\n"
|
|
222
|
+
return outstr
|
|
223
|
+
|
|
224
|
+
def _pretty_fulltext_sentences(sents):
|
|
225
|
+
"""
|
|
226
|
+
Helper function for pretty-printing a list of annotated sentences for a full-text document.
|
|
227
|
+
|
|
228
|
+
:param sent: The list of sentences to be printed.
|
|
229
|
+
:type sent: list(AttrDict)
|
|
230
|
+
:return: An index of the text of the sentences.
|
|
231
|
+
:rtype: str
|
|
232
|
+
"""
|
|
233
|
+
|
|
234
|
+
outstr = ""
|
|
235
|
+
outstr += "full-text document ({0.ID}) {0.name}:\n\n".format(sents)
|
|
236
|
+
outstr += "[corpid] {0.corpid}\n[corpname] {0.corpname}\n[description] {0.description}\n[URL] {0.URL}\n\n".format(sents)
|
|
237
|
+
outstr += "[sentence]\n".format(sents)
|
|
238
|
+
for i,sent in enumerate(sents.sentence):
|
|
239
|
+
outstr += "[{0}] {1}\n".format(i, sent.text)
|
|
240
|
+
outstr += "\n"
|
|
241
|
+
return outstr
|
|
242
|
+
|
|
243
|
+
def _pretty_fulltext_sentence(sent):
|
|
244
|
+
"""
|
|
245
|
+
Helper function for pretty-printing an annotated sentence from a full-text document.
|
|
246
|
+
|
|
247
|
+
:param sent: The sentence to be printed.
|
|
248
|
+
:type sent: list(AttrDict)
|
|
249
|
+
:return: The text of the sentence with annotation set indices on frame targets.
|
|
250
|
+
:rtype: str
|
|
251
|
+
"""
|
|
252
|
+
|
|
253
|
+
outstr = ""
|
|
254
|
+
outstr += "full-text sentence ({0.ID}) in {1}:\n\n".format(sent, sent.doc.get('name',sent.doc.description))
|
|
255
|
+
outstr += "\n[POS] {0} tags\n".format(len(sent.POS))
|
|
256
|
+
outstr += "\n[POS_tagset] {0}\n\n".format(sent.POS_tagset)
|
|
257
|
+
outstr += "[text] + [annotationSet]\n\n"
|
|
258
|
+
outstr += sent._ascii() # -> _annotation_ascii()
|
|
259
|
+
outstr += "\n"
|
|
260
|
+
return outstr
|
|
261
|
+
|
|
262
|
+
def _pretty_pos(aset):
|
|
263
|
+
"""
|
|
264
|
+
Helper function for pretty-printing a sentence with its POS tags.
|
|
265
|
+
|
|
266
|
+
:param aset: The POS annotation set of the sentence to be printed.
|
|
267
|
+
:type sent: list(AttrDict)
|
|
268
|
+
:return: The text of the sentence and its POS tags.
|
|
269
|
+
:rtype: str
|
|
270
|
+
"""
|
|
271
|
+
|
|
272
|
+
outstr = ""
|
|
273
|
+
outstr += "POS annotation set ({0.ID}) {0.POS_tagset} in sentence {0.sent.ID}:\n\n".format(aset)
|
|
274
|
+
|
|
275
|
+
# list the target spans and their associated aset index
|
|
276
|
+
overt = sorted(aset.POS)
|
|
277
|
+
|
|
278
|
+
sent = aset.sent
|
|
279
|
+
s0 = sent.text
|
|
280
|
+
s1 = ''
|
|
281
|
+
s2 = ''
|
|
282
|
+
i = 0
|
|
283
|
+
adjust = 0
|
|
284
|
+
for j,k,lbl in overt:
|
|
285
|
+
assert j>=i,('Overlapping targets?',(j,k,lbl))
|
|
286
|
+
s1 += ' '*(j-i) + '-'*(k-j)
|
|
287
|
+
if len(lbl)>(k-j):
|
|
288
|
+
# add space in the sentence to make room for the annotation index
|
|
289
|
+
amt = len(lbl)-(k-j)
|
|
290
|
+
s0 = s0[:k+adjust]+ '~'*amt + s0[k+adjust:] # '~' to prevent line wrapping
|
|
291
|
+
s1 = s1[:k+adjust]+ ' '*amt + s1[k+adjust:]
|
|
292
|
+
adjust += amt
|
|
293
|
+
s2 += ' '*(j-i) + lbl.ljust(k-j)
|
|
294
|
+
i = k
|
|
295
|
+
|
|
296
|
+
long_lines = [s0, s1, s2]
|
|
297
|
+
|
|
298
|
+
outstr += '\n\n'.join(map('\n'.join, zip_longest(*mimic_wrap(long_lines), fillvalue=' '))).replace('~',' ')
|
|
299
|
+
outstr += "\n"
|
|
300
|
+
return outstr
|
|
301
|
+
|
|
302
|
+
def _pretty_annotation(sent, aset_level=False):
|
|
303
|
+
"""
|
|
304
|
+
Helper function for pretty-printing an exemplar sentence for a lexical unit.
|
|
305
|
+
|
|
306
|
+
:param sent: An annotation set or exemplar sentence to be printed.
|
|
307
|
+
:param aset_level: If True, 'sent' is actually an annotation set within a sentence.
|
|
308
|
+
:type sent: AttrDict
|
|
309
|
+
:return: A nicely formated string representation of the exemplar sentence
|
|
310
|
+
with its target, frame, and FE annotations.
|
|
311
|
+
:rtype: str
|
|
312
|
+
"""
|
|
313
|
+
|
|
314
|
+
sentkeys = sent.keys()
|
|
315
|
+
outstr = "annotation set" if aset_level else "exemplar sentence"
|
|
316
|
+
outstr += " ({0.ID}):\n".format(sent)
|
|
317
|
+
if aset_level: # TODO: any UNANN exemplars?
|
|
318
|
+
outstr += "\n[status] {0}\n".format(sent.status)
|
|
319
|
+
for k in ('corpID', 'docID', 'paragNo', 'sentNo', 'aPos'):
|
|
320
|
+
if k in sentkeys:
|
|
321
|
+
outstr += "[{0}] {1}\n".format(k, sent[k])
|
|
322
|
+
outstr += "\n[LU] ({0.ID}) {0.name} in {0.frame.name}\n".format(sent.LU) if sent.LU else '\n[LU] Not found!'
|
|
323
|
+
outstr += "\n[frame] ({0.ID}) {0.name}\n".format(sent.frame) # redundant with above, but .frame is convenient
|
|
324
|
+
if not aset_level:
|
|
325
|
+
outstr += "\n[annotationSet] {0} annotation sets\n".format(len(sent.annotationSet))
|
|
326
|
+
outstr += "\n[POS] {0} tags\n".format(len(sent.POS))
|
|
327
|
+
outstr += "\n[POS_tagset] {0}\n".format(sent.POS_tagset)
|
|
328
|
+
outstr += "\n[GF] {0} relation{1}\n".format(len(sent.GF), "s" if len(sent.GF)!=1 else "")
|
|
329
|
+
outstr += "\n[PT] {0} phrase{1}\n".format(len(sent.PT), "s" if len(sent.PT)!=1 else "")
|
|
330
|
+
"""
|
|
331
|
+
Special Layers
|
|
332
|
+
--------------
|
|
333
|
+
|
|
334
|
+
The 'NER' layer contains, for some of the data, named entity labels.
|
|
335
|
+
|
|
336
|
+
The 'WSL' (word status layer) contains, for some of the data,
|
|
337
|
+
spans which should not in principle be considered targets (NT).
|
|
338
|
+
|
|
339
|
+
The 'Other' layer records relative clause constructions (Rel=relativizer, Ant=antecedent),
|
|
340
|
+
pleonastic 'it' (Null), and existential 'there' (Exist).
|
|
341
|
+
On occasion they are duplicated by accident (e.g., annotationSet 1467275 in lu6700.xml).
|
|
342
|
+
|
|
343
|
+
The 'Sent' layer appears to contain labels that the annotator has flagged the
|
|
344
|
+
sentence with for their convenience: values include
|
|
345
|
+
'sense1', 'sense2', 'sense3', etc.;
|
|
346
|
+
'Blend', 'Canonical', 'Idiom', 'Metaphor', 'Special-Sent',
|
|
347
|
+
'keepS', 'deleteS', 'reexamine'
|
|
348
|
+
(sometimes they are duplicated for no apparent reason).
|
|
349
|
+
|
|
350
|
+
The POS-specific layers may contain the following kinds of spans:
|
|
351
|
+
Asp (aspectual particle), Non-Asp (non-aspectual particle),
|
|
352
|
+
Cop (copula), Supp (support), Ctrlr (controller),
|
|
353
|
+
Gov (governor), X. Gov and X always cooccur.
|
|
354
|
+
|
|
355
|
+
>>> from nltk.corpus import framenet as fn
|
|
356
|
+
>>> def f(luRE, lyr, ignore=set()):
|
|
357
|
+
... for i,ex in enumerate(fn.exemplars(luRE)):
|
|
358
|
+
... if lyr in ex and ex[lyr] and set(zip(*ex[lyr])[2]) - ignore:
|
|
359
|
+
... print(i,ex[lyr])
|
|
360
|
+
|
|
361
|
+
- Verb: Asp, Non-Asp
|
|
362
|
+
- Noun: Cop, Supp, Ctrlr, Gov, X
|
|
363
|
+
- Adj: Cop, Supp, Ctrlr, Gov, X
|
|
364
|
+
- Prep: Cop, Supp, Ctrlr
|
|
365
|
+
- Adv: Ctrlr
|
|
366
|
+
- Scon: (none)
|
|
367
|
+
- Art: (none)
|
|
368
|
+
"""
|
|
369
|
+
for lyr in ('NER', 'WSL', 'Other', 'Sent'):
|
|
370
|
+
if lyr in sent and sent[lyr]:
|
|
371
|
+
outstr += "\n[{0}] {1} entr{2}\n".format(lyr, len(sent[lyr]), "ies" if len(sent[lyr])!=1 else "y")
|
|
372
|
+
outstr += "\n[text] + [Target] + [FE]"
|
|
373
|
+
# POS-specific layers: syntactically important words that are neither the target
|
|
374
|
+
# nor the FEs. Include these along with the first FE layer but with '^' underlining.
|
|
375
|
+
for lyr in ('Verb', 'Noun', 'Adj', 'Adv', 'Prep', 'Scon', 'Art'):
|
|
376
|
+
if lyr in sent and sent[lyr]:
|
|
377
|
+
outstr += " + [{0}]".format(lyr)
|
|
378
|
+
if 'FE2' in sentkeys:
|
|
379
|
+
outstr += " + [FE2]"
|
|
380
|
+
if 'FE3' in sentkeys:
|
|
381
|
+
outstr += " + [FE3]"
|
|
382
|
+
outstr += "\n\n"
|
|
383
|
+
outstr += sent._ascii() # -> _annotation_ascii()
|
|
384
|
+
outstr += "\n"
|
|
385
|
+
|
|
386
|
+
return outstr
|
|
387
|
+
|
|
388
|
+
def _annotation_ascii(sent):
|
|
389
|
+
'''
|
|
390
|
+
Given a sentence or FE annotation set, construct the width-limited string showing
|
|
391
|
+
an ASCII visualization of the sentence's annotations, calling either
|
|
392
|
+
_annotation_ascii_frames() or _annotation_ascii_FEs() as appropriate.
|
|
393
|
+
This will be attached as a method to appropriate AttrDict instances
|
|
394
|
+
and called in the full pretty-printing of the instance.
|
|
395
|
+
'''
|
|
396
|
+
if sent._type=='fulltext_sentence' or ('annotationSet' in sent and len(sent.annotationSet)>2):
|
|
397
|
+
# a full-text sentence OR sentence with multiple targets.
|
|
398
|
+
# (multiple targets = >2 annotation sets, because the first annotation set is POS.)
|
|
399
|
+
return _annotation_ascii_frames(sent)
|
|
400
|
+
else: # an FE annotation set, or an LU sentence with 1 target
|
|
401
|
+
return _annotation_ascii_FEs(sent)
|
|
402
|
+
|
|
403
|
+
def _annotation_ascii_frames(sent):
|
|
404
|
+
'''
|
|
405
|
+
ASCII string rendering of the sentence along with its targets and frame names.
|
|
406
|
+
Called for all full-text sentences, as well as the few LU sentences with multiple
|
|
407
|
+
targets (e.g., fn.lu(6412).exemplars[82] has two want.v targets).
|
|
408
|
+
Line-wrapped to limit the display width.
|
|
409
|
+
'''
|
|
410
|
+
# list the target spans and their associated aset index
|
|
411
|
+
overt = []
|
|
412
|
+
for a,aset in enumerate(sent.annotationSet[1:]):
|
|
413
|
+
for j,k in aset.Target:
|
|
414
|
+
indexS = "[{0}]".format(a+1)
|
|
415
|
+
if aset.status=='UNANN' or aset.LU.status=='Problem':
|
|
416
|
+
indexS += " "
|
|
417
|
+
if aset.status=='UNANN':
|
|
418
|
+
indexS += "!" # warning indicator that there is a frame annotation but no FE annotation
|
|
419
|
+
if aset.LU.status=='Problem':
|
|
420
|
+
indexS += "?" # warning indicator that there is a missing LU definition (because the LU has Problem status)
|
|
421
|
+
overt.append((j,k,aset.LU.frame.name,indexS))
|
|
422
|
+
overt = sorted(overt)
|
|
423
|
+
|
|
424
|
+
duplicates = set()
|
|
425
|
+
for o,(j,k,fname,asetIndex) in enumerate(overt):
|
|
426
|
+
if o>0 and j<=overt[o-1][1]:
|
|
427
|
+
# multiple annotation sets on the same target
|
|
428
|
+
# (e.g. due to a coordination construction or multiple annotators)
|
|
429
|
+
if overt[o-1][:2]==(j,k) and overt[o-1][2]==fname: # same target, same frame
|
|
430
|
+
# splice indices together
|
|
431
|
+
combinedIndex = overt[o-1][3] + asetIndex # e.g., '[1][2]', '[1]! [2]'
|
|
432
|
+
combinedIndex = combinedIndex.replace(' !', '! ').replace(' ?', '? ')
|
|
433
|
+
overt[o-1] = overt[o-1][:3]+(combinedIndex,)
|
|
434
|
+
duplicates.add(o)
|
|
435
|
+
else: # different frames, same or overlapping targets
|
|
436
|
+
s = sent.text
|
|
437
|
+
for j,k,fname,asetIndex in overt:
|
|
438
|
+
s += '\n' + asetIndex + ' ' + sent.text[j:k] + ' :: ' + fname
|
|
439
|
+
s += '\n(Unable to display sentence with targets marked inline due to overlap)'
|
|
440
|
+
return s
|
|
441
|
+
for o in reversed(sorted(duplicates)):
|
|
442
|
+
del overt[o]
|
|
443
|
+
|
|
444
|
+
s0 = sent.text
|
|
445
|
+
s1 = ''
|
|
446
|
+
s11 = ''
|
|
447
|
+
s2 = ''
|
|
448
|
+
i = 0
|
|
449
|
+
adjust = 0
|
|
450
|
+
fAbbrevs = OrderedDict()
|
|
451
|
+
for j,k,fname,asetIndex in overt:
|
|
452
|
+
if not j>=i:
|
|
453
|
+
assert j>=i,('Overlapping targets?'+(' UNANN' if any(aset.status=='UNANN' for aset in sent.annotationSet[1:]) else ''),(j,k,asetIndex))
|
|
454
|
+
s1 += ' '*(j-i) + '*'*(k-j)
|
|
455
|
+
short = fname[:k-j]
|
|
456
|
+
if (k-j)<len(fname):
|
|
457
|
+
r = 0
|
|
458
|
+
while short in fAbbrevs:
|
|
459
|
+
if fAbbrevs[short]==fname:
|
|
460
|
+
break
|
|
461
|
+
r += 1
|
|
462
|
+
short = fname[:k-j-1] + str(r)
|
|
463
|
+
else: # short not in fAbbrevs
|
|
464
|
+
fAbbrevs[short] = fname
|
|
465
|
+
s11 += ' '*(j-i) + short.ljust(k-j)
|
|
466
|
+
if len(asetIndex)>(k-j):
|
|
467
|
+
# add space in the sentence to make room for the annotation index
|
|
468
|
+
amt = len(asetIndex)-(k-j)
|
|
469
|
+
s0 = s0[:k+adjust]+ '~'*amt + s0[k+adjust:] # '~' to prevent line wrapping
|
|
470
|
+
s1 = s1[:k+adjust]+ ' '*amt + s1[k+adjust:]
|
|
471
|
+
s11 = s11[:k+adjust]+ ' '*amt + s11[k+adjust:]
|
|
472
|
+
adjust += amt
|
|
473
|
+
s2 += ' '*(j-i) + asetIndex.ljust(k-j)
|
|
474
|
+
i = k
|
|
475
|
+
|
|
476
|
+
long_lines = [s0, s1, s11, s2]
|
|
477
|
+
|
|
478
|
+
outstr = '\n\n'.join(map('\n'.join, zip_longest(*mimic_wrap(long_lines), fillvalue=' '))).replace('~',' ')
|
|
479
|
+
outstr += '\n'
|
|
480
|
+
if fAbbrevs:
|
|
481
|
+
outstr += ' ('+', '.join('='.join(pair) for pair in fAbbrevs.items())+')'
|
|
482
|
+
assert len(fAbbrevs)==len(dict(fAbbrevs)),'Abbreviation clash'
|
|
483
|
+
|
|
484
|
+
return outstr
|
|
485
|
+
|
|
486
|
+
def _annotation_ascii_FE_layer(overt, ni, feAbbrevs):
|
|
487
|
+
'''Helper for _annotation_ascii_FEs().'''
|
|
488
|
+
s1 = ''
|
|
489
|
+
s2 = ''
|
|
490
|
+
i = 0
|
|
491
|
+
for j,k,fename in overt:
|
|
492
|
+
s1 += ' '*(j-i) + ('^' if fename.islower() else '-')*(k-j)
|
|
493
|
+
short = fename[:k-j]
|
|
494
|
+
if len(fename)>len(short):
|
|
495
|
+
r = 0
|
|
496
|
+
while short in feAbbrevs:
|
|
497
|
+
if feAbbrevs[short]==fename:
|
|
498
|
+
break
|
|
499
|
+
r += 1
|
|
500
|
+
short = fename[:k-j-1] + str(r)
|
|
501
|
+
else: # short not in feAbbrevs
|
|
502
|
+
feAbbrevs[short] = fename
|
|
503
|
+
s2 += ' '*(j-i) + short.ljust(k-j)
|
|
504
|
+
i = k
|
|
505
|
+
|
|
506
|
+
sNI = ''
|
|
507
|
+
if ni:
|
|
508
|
+
sNI += ' ['+', '.join(':'.join(x) for x in sorted(ni.items()))+']'
|
|
509
|
+
return [s1,s2,sNI]
|
|
510
|
+
|
|
511
|
+
def _annotation_ascii_FEs(sent):
|
|
512
|
+
'''
|
|
513
|
+
ASCII string rendering of the sentence along with a single target and its FEs.
|
|
514
|
+
Secondary and tertiary FE layers are included if present.
|
|
515
|
+
'sent' can be an FE annotation set or an LU sentence with a single target.
|
|
516
|
+
Line-wrapped to limit the display width.
|
|
517
|
+
'''
|
|
518
|
+
feAbbrevs = OrderedDict()
|
|
519
|
+
posspec = [] # POS-specific layer spans (e.g., Supp[ort], Cop[ula])
|
|
520
|
+
posspec_separate = False
|
|
521
|
+
for lyr in ('Verb', 'Noun', 'Adj', 'Adv', 'Prep', 'Scon', 'Art'):
|
|
522
|
+
if lyr in sent and sent[lyr]:
|
|
523
|
+
for a,b,lbl in sent[lyr]:
|
|
524
|
+
if lbl=='X': # skip this, which covers an entire phrase typically containing the target and all its FEs
|
|
525
|
+
# (but do display the Gov)
|
|
526
|
+
continue
|
|
527
|
+
if any(1 for x,y,felbl in sent.FE[0] if x<=a<y or a<=x<b):
|
|
528
|
+
# overlap between one of the POS-specific layers and first FE layer
|
|
529
|
+
posspec_separate = True # show POS-specific layers on a separate line
|
|
530
|
+
posspec.append((a,b,lbl.lower().replace('-',''))) # lowercase Cop=>cop, Non-Asp=>nonasp, etc. to distinguish from FE names
|
|
531
|
+
if posspec_separate:
|
|
532
|
+
POSSPEC = _annotation_ascii_FE_layer(posspec, {}, feAbbrevs)
|
|
533
|
+
FE1 = _annotation_ascii_FE_layer(sorted(sent.FE[0] + (posspec if not posspec_separate else [])), sent.FE[1], feAbbrevs)
|
|
534
|
+
FE2 = FE3 = None
|
|
535
|
+
if 'FE2' in sent:
|
|
536
|
+
FE2 = _annotation_ascii_FE_layer(sent.FE2[0], sent.FE2[1], feAbbrevs)
|
|
537
|
+
if 'FE3' in sent:
|
|
538
|
+
FE3 = _annotation_ascii_FE_layer(sent.FE3[0], sent.FE3[1], feAbbrevs)
|
|
539
|
+
|
|
540
|
+
for i,j in sent.Target:
|
|
541
|
+
FE1span, FE1name, FE1exp = FE1
|
|
542
|
+
if len(FE1span)<j:
|
|
543
|
+
FE1span += ' '*(j-len(FE1span))
|
|
544
|
+
if len(FE1name)<j:
|
|
545
|
+
FE1name += ' '*(j-len(FE1name))
|
|
546
|
+
FE1[1] = FE1name
|
|
547
|
+
FE1[0] = FE1span[:i] + FE1span[i:j].replace(' ','*').replace('-','=') + FE1span[j:]
|
|
548
|
+
long_lines = [sent.text]
|
|
549
|
+
if posspec_separate:
|
|
550
|
+
long_lines.extend(POSSPEC[:2])
|
|
551
|
+
long_lines.extend([FE1[0], FE1[1]+FE1[2]]) # lines with no length limit
|
|
552
|
+
if FE2:
|
|
553
|
+
long_lines.extend([FE2[0], FE2[1]+FE2[2]])
|
|
554
|
+
if FE3:
|
|
555
|
+
long_lines.extend([FE3[0], FE3[1]+FE3[2]])
|
|
556
|
+
long_lines.append('')
|
|
557
|
+
outstr = '\n'.join(map('\n'.join, zip_longest(*mimic_wrap(long_lines), fillvalue=' ')))
|
|
558
|
+
if feAbbrevs:
|
|
559
|
+
outstr += '('+', '.join('='.join(pair) for pair in feAbbrevs.items())+')'
|
|
560
|
+
assert len(feAbbrevs)==len(dict(feAbbrevs)),'Abbreviation clash'
|
|
561
|
+
outstr += "\n"
|
|
171
562
|
|
|
172
563
|
return outstr
|
|
173
564
|
|
|
@@ -225,6 +616,7 @@ def _pretty_frame(frame):
|
|
|
225
616
|
|
|
226
617
|
outstr = ""
|
|
227
618
|
outstr += "frame ({0.ID}): {0.name}\n\n".format(frame)
|
|
619
|
+
outstr += "[URL] {0}\n\n".format(frame.URL)
|
|
228
620
|
outstr += "[definition]\n"
|
|
229
621
|
outstr += _pretty_longstring(frame.definition, ' ') + '\n'
|
|
230
622
|
|
|
@@ -301,8 +693,11 @@ class AttrDict(dict):
|
|
|
301
693
|
return self.__repr__()
|
|
302
694
|
try:
|
|
303
695
|
return "<{0} ID={1} name={2}>".format(self['_type'], self['ID'], self['name'])
|
|
304
|
-
except KeyError:
|
|
305
|
-
|
|
696
|
+
except KeyError:
|
|
697
|
+
try: # no ID--e.g., for _type=lusubcorpus
|
|
698
|
+
return "<{0} name={1}>".format(self['_type'], self['name'])
|
|
699
|
+
except KeyError: # no name--e.g., for _type=lusentence
|
|
700
|
+
return "<{0} ID={1}>".format(self['_type'], self['ID'])
|
|
306
701
|
else:
|
|
307
702
|
return self.__repr__()
|
|
308
703
|
|
|
@@ -317,6 +712,18 @@ class AttrDict(dict):
|
|
|
317
712
|
outstr = _pretty_fe(self)
|
|
318
713
|
elif self['_type'] == 'lu':
|
|
319
714
|
outstr = _pretty_lu(self)
|
|
715
|
+
elif self['_type'] == 'luexemplars': # list of ALL exemplars for LU
|
|
716
|
+
outstr = _pretty_exemplars(self, self[0].LU)
|
|
717
|
+
elif self['_type'] == 'fulltext_annotation': # list of all sentences for full-text doc
|
|
718
|
+
outstr = _pretty_fulltext_sentences(self)
|
|
719
|
+
elif self['_type'] == 'lusentence':
|
|
720
|
+
outstr = _pretty_annotation(self)
|
|
721
|
+
elif self['_type'] == 'fulltext_sentence':
|
|
722
|
+
outstr = _pretty_fulltext_sentence(self)
|
|
723
|
+
elif self['_type'] in ('luannotationset', 'fulltext_annotationset'):
|
|
724
|
+
outstr = _pretty_annotation(self, aset_level=True)
|
|
725
|
+
elif self['_type'] == 'posannotationset':
|
|
726
|
+
outstr = _pretty_pos(self)
|
|
320
727
|
elif self['_type'] == 'semtype':
|
|
321
728
|
outstr = _pretty_semtype(self)
|
|
322
729
|
elif self['_type'] == 'framerelationtype':
|
|
@@ -340,6 +747,33 @@ class AttrDict(dict):
|
|
|
340
747
|
def __repr__(self):
|
|
341
748
|
return self.__str__()
|
|
342
749
|
|
|
750
|
+
@python_2_unicode_compatible
|
|
751
|
+
class SpecialList(list):
|
|
752
|
+
"""
|
|
753
|
+
A list subclass which adds a '_type' attribute for special printing
|
|
754
|
+
(similar to an AttrDict, though this is NOT an AttrDict subclass).
|
|
755
|
+
"""
|
|
756
|
+
def __init__(self, typ, *args, **kwargs):
|
|
757
|
+
super(SpecialList,self).__init__(*args, **kwargs)
|
|
758
|
+
self._type = typ
|
|
759
|
+
|
|
760
|
+
def _str(self):
|
|
761
|
+
outstr = ""
|
|
762
|
+
|
|
763
|
+
assert self._type
|
|
764
|
+
if len(self)==0:
|
|
765
|
+
outstr = "[]"
|
|
766
|
+
elif self._type == 'luexemplars': # list of ALL exemplars for LU
|
|
767
|
+
outstr = _pretty_exemplars(self, self[0].LU)
|
|
768
|
+
else:
|
|
769
|
+
assert False,self._type
|
|
770
|
+
return outstr
|
|
771
|
+
|
|
772
|
+
def __str__(self):
|
|
773
|
+
return self._str()
|
|
774
|
+
def __repr__(self):
|
|
775
|
+
return self.__str__()
|
|
776
|
+
|
|
343
777
|
class Future(object):
|
|
344
778
|
"""
|
|
345
779
|
Wraps and acts as a proxy for a value to be loaded lazily (on demand).
|
|
@@ -376,7 +810,6 @@ class Future(object):
|
|
|
376
810
|
def __repr__(self):
|
|
377
811
|
return self._data().__repr__()
|
|
378
812
|
|
|
379
|
-
|
|
380
813
|
@python_2_unicode_compatible
|
|
381
814
|
class PrettyDict(AttrDict):
|
|
382
815
|
"""
|
|
@@ -445,8 +878,60 @@ class PrettyLazyMap(LazyMap):
|
|
|
445
878
|
length += len(pieces[-1]) + 2
|
|
446
879
|
if length > self._MAX_REPR_SIZE and len(pieces) > 2:
|
|
447
880
|
return "[%s, ...]" % text_type(', ').join(pieces[:-1])
|
|
448
|
-
|
|
449
|
-
|
|
881
|
+
return "[%s]" % text_type(', ').join(pieces)
|
|
882
|
+
|
|
883
|
+
@python_2_unicode_compatible
|
|
884
|
+
class PrettyLazyIteratorList(LazyIteratorList):
|
|
885
|
+
"""
|
|
886
|
+
Displays an abbreviated repr of only the first several elements, not the whole list.
|
|
887
|
+
"""
|
|
888
|
+
# from nltk.util
|
|
889
|
+
_MAX_REPR_SIZE = 60
|
|
890
|
+
def __repr__(self):
|
|
891
|
+
"""
|
|
892
|
+
Return a string representation for this corpus view that is
|
|
893
|
+
similar to a list's representation; but if it would be more
|
|
894
|
+
than 60 characters long, it is truncated.
|
|
895
|
+
"""
|
|
896
|
+
pieces = []
|
|
897
|
+
length = 5
|
|
898
|
+
for elt in self:
|
|
899
|
+
pieces.append(elt._short_repr()) # key difference from inherited version: call to _short_repr()
|
|
900
|
+
length += len(pieces[-1]) + 2
|
|
901
|
+
if length > self._MAX_REPR_SIZE and len(pieces) > 2:
|
|
902
|
+
return "[%s, ...]" % text_type(', ').join(pieces[:-1])
|
|
903
|
+
return "[%s]" % text_type(', ').join(pieces)
|
|
904
|
+
|
|
905
|
+
@python_2_unicode_compatible
|
|
906
|
+
class PrettyLazyConcatenation(LazyConcatenation):
|
|
907
|
+
"""
|
|
908
|
+
Displays an abbreviated repr of only the first several elements, not the whole list.
|
|
909
|
+
"""
|
|
910
|
+
# from nltk.util
|
|
911
|
+
_MAX_REPR_SIZE = 60
|
|
912
|
+
def __repr__(self):
|
|
913
|
+
"""
|
|
914
|
+
Return a string representation for this corpus view that is
|
|
915
|
+
similar to a list's representation; but if it would be more
|
|
916
|
+
than 60 characters long, it is truncated.
|
|
917
|
+
"""
|
|
918
|
+
pieces = []
|
|
919
|
+
length = 5
|
|
920
|
+
for elt in self:
|
|
921
|
+
pieces.append(elt._short_repr()) # key difference from inherited version: call to _short_repr()
|
|
922
|
+
length += len(pieces[-1]) + 2
|
|
923
|
+
if length > self._MAX_REPR_SIZE and len(pieces) > 2:
|
|
924
|
+
return "[%s, ...]" % text_type(', ').join(pieces[:-1])
|
|
925
|
+
return "[%s]" % text_type(', ').join(pieces)
|
|
926
|
+
|
|
927
|
+
def __add__(self, other):
|
|
928
|
+
"""Return a list concatenating self with other."""
|
|
929
|
+
return PrettyLazyIteratorList(itertools.chain(self, other))
|
|
930
|
+
|
|
931
|
+
def __radd__(self, other):
|
|
932
|
+
"""Return a list concatenating other with self."""
|
|
933
|
+
return PrettyLazyIteratorList(itertools.chain(other, self))
|
|
934
|
+
|
|
450
935
|
|
|
451
936
|
class FramenetCorpusReader(XMLCorpusReader):
|
|
452
937
|
"""A corpus reader for the Framenet Corpus.
|
|
@@ -468,6 +953,17 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
468
953
|
in the XML index.
|
|
469
954
|
"""
|
|
470
955
|
|
|
956
|
+
_warnings = False
|
|
957
|
+
|
|
958
|
+
def warnings(self, v):
|
|
959
|
+
"""Enable or disable warnings of data integrity issues as they are encountered.
|
|
960
|
+
If v is truthy, warnings will be enabled.
|
|
961
|
+
|
|
962
|
+
(This is a function rather than just an attribute/property to ensure that if
|
|
963
|
+
enabling warnings is the first action taken, the corpus reader is instantiated first.)
|
|
964
|
+
"""
|
|
965
|
+
self._warnings = v
|
|
966
|
+
|
|
471
967
|
def __init__(self, root, fileids):
|
|
472
968
|
XMLCorpusReader.__init__(self, root, fileids)
|
|
473
969
|
|
|
@@ -479,6 +975,9 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
479
975
|
# sub dir containing the xml files for fulltext annotation files
|
|
480
976
|
self._fulltext_dir = "fulltext"
|
|
481
977
|
|
|
978
|
+
# location of latest development version of FrameNet
|
|
979
|
+
self._fnweb_url = "https://framenet2.icsi.berkeley.edu/fnReports/data"
|
|
980
|
+
|
|
482
981
|
# Indexes used for faster look-ups
|
|
483
982
|
self._frame_idx = None
|
|
484
983
|
self._cached_frames = {} # name -> ID
|
|
@@ -490,6 +989,91 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
490
989
|
self._ferel_idx = None # FE-to-FE relation instances
|
|
491
990
|
self._frel_f_idx = None # frame-to-frame relations associated with each frame
|
|
492
991
|
|
|
992
|
+
def help(self, attrname=None):
|
|
993
|
+
"""Display help information summarizing the main methods."""
|
|
994
|
+
|
|
995
|
+
if attrname is not None:
|
|
996
|
+
return help(self.__getattribute__(attrname))
|
|
997
|
+
|
|
998
|
+
# No need to mention frame_by_name() or frame_by_id(),
|
|
999
|
+
# as it's easier to just call frame().
|
|
1000
|
+
# Also not mentioning lu_basic().
|
|
1001
|
+
|
|
1002
|
+
|
|
1003
|
+
msg = """
|
|
1004
|
+
Citation: Nathan Schneider and Chuck Wooters (2017),
|
|
1005
|
+
"The NLTK FrameNet API: Designing for Discoverability with a Rich Linguistic Resource".
|
|
1006
|
+
Proceedings of EMNLP: System Demonstrations. https://arxiv.org/abs/1703.07438
|
|
1007
|
+
|
|
1008
|
+
Use the following methods to access data in FrameNet.
|
|
1009
|
+
Provide a method name to `help()` for more information.
|
|
1010
|
+
|
|
1011
|
+
FRAMES
|
|
1012
|
+
======
|
|
1013
|
+
|
|
1014
|
+
frame() to look up a frame by its exact name or ID
|
|
1015
|
+
frames() to get frames matching a name pattern
|
|
1016
|
+
frames_by_lemma() to get frames containing an LU matching a name pattern
|
|
1017
|
+
frame_ids_and_names() to get a mapping from frame IDs to names
|
|
1018
|
+
|
|
1019
|
+
FRAME ELEMENTS
|
|
1020
|
+
==============
|
|
1021
|
+
|
|
1022
|
+
fes() to get frame elements (a.k.a. roles) matching a name pattern, optionally constrained
|
|
1023
|
+
by a frame name pattern
|
|
1024
|
+
|
|
1025
|
+
LEXICAL UNITS
|
|
1026
|
+
=============
|
|
1027
|
+
|
|
1028
|
+
lu() to look up an LU by its ID
|
|
1029
|
+
lus() to get lexical units matching a name pattern, optionally constrained by frame
|
|
1030
|
+
lu_ids_and_names() to get a mapping from LU IDs to names
|
|
1031
|
+
|
|
1032
|
+
RELATIONS
|
|
1033
|
+
=========
|
|
1034
|
+
|
|
1035
|
+
frame_relation_types() to get the different kinds of frame-to-frame relations
|
|
1036
|
+
(Inheritance, Subframe, Using, etc.).
|
|
1037
|
+
frame_relations() to get the relation instances, optionally constrained by
|
|
1038
|
+
frame(s) or relation type
|
|
1039
|
+
fe_relations() to get the frame element pairs belonging to a frame-to-frame relation
|
|
1040
|
+
|
|
1041
|
+
SEMANTIC TYPES
|
|
1042
|
+
==============
|
|
1043
|
+
|
|
1044
|
+
semtypes() to get the different kinds of semantic types that can be applied to
|
|
1045
|
+
FEs, LUs, and entire frames
|
|
1046
|
+
semtype() to look up a particular semtype by name, ID, or abbreviation
|
|
1047
|
+
semtype_inherits() to check whether two semantic types have a subtype-supertype
|
|
1048
|
+
relationship in the semtype hierarchy
|
|
1049
|
+
propagate_semtypes() to apply inference rules that distribute semtypes over relations
|
|
1050
|
+
between FEs
|
|
1051
|
+
|
|
1052
|
+
ANNOTATIONS
|
|
1053
|
+
===========
|
|
1054
|
+
|
|
1055
|
+
annotations() to get annotation sets, in which a token in a sentence is annotated
|
|
1056
|
+
with a lexical unit in a frame, along with its frame elements and their syntactic properties;
|
|
1057
|
+
can be constrained by LU name pattern and limited to lexicographic exemplars or full-text.
|
|
1058
|
+
Sentences of full-text annotation can have multiple annotation sets.
|
|
1059
|
+
sents() to get annotated sentences illustrating one or more lexical units
|
|
1060
|
+
exemplars() to get sentences of lexicographic annotation, most of which have
|
|
1061
|
+
just 1 annotation set; can be constrained by LU name pattern, frame, and overt FE(s)
|
|
1062
|
+
doc() to look up a document of full-text annotation by its ID
|
|
1063
|
+
docs() to get documents of full-text annotation that match a name pattern
|
|
1064
|
+
docs_metadata() to get metadata about all full-text documents without loading them
|
|
1065
|
+
ft_sents() to iterate over sentences of full-text annotation
|
|
1066
|
+
|
|
1067
|
+
UTILITIES
|
|
1068
|
+
=========
|
|
1069
|
+
|
|
1070
|
+
buildindexes() loads metadata about all frames, LUs, etc. into memory to avoid
|
|
1071
|
+
delay when one is accessed for the first time. It does not load annotations.
|
|
1072
|
+
readme() gives the text of the FrameNet README file
|
|
1073
|
+
warnings(True) to display corpus consistency warnings when loading data
|
|
1074
|
+
"""
|
|
1075
|
+
print(msg)
|
|
1076
|
+
|
|
493
1077
|
def _buildframeindex(self):
|
|
494
1078
|
# The total number of Frames in Framenet is fairly small (~1200) so
|
|
495
1079
|
# this index should not be very large
|
|
@@ -546,6 +1130,11 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
546
1130
|
self._ferel_idx[ferel.ID] = ferel
|
|
547
1131
|
#print('...done building relation index', file=sys.stderr)
|
|
548
1132
|
|
|
1133
|
+
def _warn(self, *message, **kwargs):
|
|
1134
|
+
if self._warnings:
|
|
1135
|
+
kwargs.setdefault('file', sys.stderr)
|
|
1136
|
+
print(*message, **kwargs)
|
|
1137
|
+
|
|
549
1138
|
def readme(self):
|
|
550
1139
|
"""
|
|
551
1140
|
Return the contents of the corpus README.txt (or README) file.
|
|
@@ -568,7 +1157,7 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
568
1157
|
# frame and FE relations
|
|
569
1158
|
self._buildrelationindex()
|
|
570
1159
|
|
|
571
|
-
def
|
|
1160
|
+
def doc(self, fn_docid):
|
|
572
1161
|
"""
|
|
573
1162
|
Returns the annotated document whose id number is
|
|
574
1163
|
``fn_docid``. This id number can be obtained by calling the
|
|
@@ -630,7 +1219,11 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
630
1219
|
|
|
631
1220
|
# Grab the top-level xml element containing the fulltext annotation
|
|
632
1221
|
elt = XMLCorpusView(locpath, 'fullTextAnnotation')[0]
|
|
633
|
-
|
|
1222
|
+
info = self._handle_fulltextannotation_elt(elt)
|
|
1223
|
+
# add metadata
|
|
1224
|
+
for k,v in self._fulltext_idx[fn_docid].items():
|
|
1225
|
+
info[k] = v
|
|
1226
|
+
return info
|
|
634
1227
|
|
|
635
1228
|
def frame_by_id(self, fn_fid, ignorekeys=[]):
|
|
636
1229
|
"""
|
|
@@ -719,11 +1312,13 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
719
1312
|
fentry = self._handle_frame_elt(elt, ignorekeys)
|
|
720
1313
|
assert fentry
|
|
721
1314
|
|
|
1315
|
+
fentry.URL = self._fnweb_url + '/' + self._frame_dir + '/' + fn_fname + '.xml'
|
|
1316
|
+
|
|
722
1317
|
# INFERENCE RULE: propagate lexical semtypes from the frame to all its LUs
|
|
723
1318
|
for st in fentry.semTypes:
|
|
724
1319
|
if st.rootType.name=='Lexical_type':
|
|
725
1320
|
for lu in fentry.lexUnit.values():
|
|
726
|
-
if st
|
|
1321
|
+
if not any(x is st for x in lu.semTypes): # identity containment check
|
|
727
1322
|
lu.semTypes.append(st)
|
|
728
1323
|
|
|
729
1324
|
|
|
@@ -827,8 +1422,9 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
827
1422
|
search through ALL of the frame XML files in the db.
|
|
828
1423
|
|
|
829
1424
|
>>> from nltk.corpus import framenet as fn
|
|
830
|
-
>>>
|
|
831
|
-
|
|
1425
|
+
>>> from nltk.corpus.reader.framenet import PrettyList
|
|
1426
|
+
>>> PrettyList(sorted(fn.frames_by_lemma(r'(?i)a little'), key=itemgetter('ID'))) # doctest: +ELLIPSIS
|
|
1427
|
+
[<frame ID=189 name=Quanti...>, <frame ID=2001 name=Degree>]
|
|
832
1428
|
|
|
833
1429
|
:return: A list of frame objects.
|
|
834
1430
|
:rtype: list(AttrDict)
|
|
@@ -842,17 +1438,23 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
842
1438
|
``lu()`` function with "subCorpus" info excluded.
|
|
843
1439
|
|
|
844
1440
|
>>> from nltk.corpus import framenet as fn
|
|
845
|
-
>>> PrettyDict(fn.lu_basic(256), breakLines=True)
|
|
1441
|
+
>>> lu = PrettyDict(fn.lu_basic(256), breakLines=True)
|
|
1442
|
+
>>> # ellipses account for differences between FN 1.5 and 1.7
|
|
1443
|
+
>>> lu # doctest: +ELLIPSIS
|
|
846
1444
|
{'ID': 256,
|
|
847
1445
|
'POS': 'V',
|
|
1446
|
+
'URL': u'https://framenet2.icsi.berkeley.edu/fnReports/data/lu/lu256.xml',
|
|
848
1447
|
'_type': 'lu',
|
|
1448
|
+
'cBy': ...,
|
|
1449
|
+
'cDate': '02/08/2001 01:27:50 PST Thu',
|
|
849
1450
|
'definition': 'COD: be aware of beforehand; predict.',
|
|
1451
|
+
'definitionMarkup': 'COD: be aware of beforehand; predict.',
|
|
850
1452
|
'frame': <frame ID=26 name=Expectation>,
|
|
851
1453
|
'lemmaID': 15082,
|
|
852
1454
|
'lexemes': [{'POS': 'V', 'breakBefore': 'false', 'headword': 'false', 'name': 'foresee', 'order': 1}],
|
|
853
1455
|
'name': 'foresee.v',
|
|
854
1456
|
'semTypes': [],
|
|
855
|
-
'sentenceCount': {'annotated':
|
|
1457
|
+
'sentenceCount': {'annotated': ..., 'total': ...},
|
|
856
1458
|
'status': 'FN1_Sent'}
|
|
857
1459
|
|
|
858
1460
|
:param fn_luid: The id number of the desired LU
|
|
@@ -860,15 +1462,15 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
860
1462
|
:return: Basic information about the lexical unit
|
|
861
1463
|
:rtype: dict
|
|
862
1464
|
"""
|
|
863
|
-
return self.lu(fn_luid, ignorekeys=['subCorpus'])
|
|
1465
|
+
return self.lu(fn_luid, ignorekeys=['subCorpus', 'exemplars'])
|
|
864
1466
|
|
|
865
|
-
def lu(self, fn_luid, ignorekeys=[]):
|
|
1467
|
+
def lu(self, fn_luid, ignorekeys=[], luName=None, frameID=None, frameName=None):
|
|
866
1468
|
"""
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
1469
|
+
Access a lexical unit by its ID. luName, frameID, and frameName are used
|
|
1470
|
+
only in the event that the LU does not have a file in the database
|
|
1471
|
+
(which is the case for LUs with "Problem" status); in this case,
|
|
1472
|
+
a placeholder LU is created which just contains its name, ID, and frame.
|
|
1473
|
+
|
|
872
1474
|
|
|
873
1475
|
Usage examples:
|
|
874
1476
|
|
|
@@ -882,6 +1484,40 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
882
1484
|
>>> pprint(list(map(PrettyDict, fn.lu(256).lexemes)))
|
|
883
1485
|
[{'POS': 'V', 'breakBefore': 'false', 'headword': 'false', 'name': 'foresee', 'order': 1}]
|
|
884
1486
|
|
|
1487
|
+
>>> fn.lu(227).exemplars[23]
|
|
1488
|
+
exemplar sentence (352962):
|
|
1489
|
+
[sentNo] 0
|
|
1490
|
+
[aPos] 59699508
|
|
1491
|
+
<BLANKLINE>
|
|
1492
|
+
[LU] (227) guess.v in Coming_to_believe
|
|
1493
|
+
<BLANKLINE>
|
|
1494
|
+
[frame] (23) Coming_to_believe
|
|
1495
|
+
<BLANKLINE>
|
|
1496
|
+
[annotationSet] 2 annotation sets
|
|
1497
|
+
<BLANKLINE>
|
|
1498
|
+
[POS] 18 tags
|
|
1499
|
+
<BLANKLINE>
|
|
1500
|
+
[POS_tagset] BNC
|
|
1501
|
+
<BLANKLINE>
|
|
1502
|
+
[GF] 3 relations
|
|
1503
|
+
<BLANKLINE>
|
|
1504
|
+
[PT] 3 phrases
|
|
1505
|
+
<BLANKLINE>
|
|
1506
|
+
[Other] 1 entry
|
|
1507
|
+
<BLANKLINE>
|
|
1508
|
+
[text] + [Target] + [FE]
|
|
1509
|
+
<BLANKLINE>
|
|
1510
|
+
When he was inside the house , Culley noticed the characteristic
|
|
1511
|
+
------------------
|
|
1512
|
+
Content
|
|
1513
|
+
<BLANKLINE>
|
|
1514
|
+
he would n't have guessed at .
|
|
1515
|
+
-- ******* --
|
|
1516
|
+
Co C1 [Evidence:INI]
|
|
1517
|
+
(Co=Cognizer, C1=Content)
|
|
1518
|
+
<BLANKLINE>
|
|
1519
|
+
<BLANKLINE>
|
|
1520
|
+
|
|
885
1521
|
The dict that is returned from this function will contain most of the
|
|
886
1522
|
following information about the LU. Note that some LUs do not contain
|
|
887
1523
|
all of these pieces of information - particularly 'totalAnnotated' and
|
|
@@ -959,8 +1595,20 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
959
1595
|
# look for this LU in cache
|
|
960
1596
|
if not self._lu_idx:
|
|
961
1597
|
self._buildluindex()
|
|
962
|
-
|
|
963
|
-
|
|
1598
|
+
OOV = object()
|
|
1599
|
+
luinfo = self._lu_idx.get(fn_luid, OOV)
|
|
1600
|
+
if luinfo is OOV:
|
|
1601
|
+
# LU not in the index. We create a placeholder by falling back to
|
|
1602
|
+
# luName, frameID, and frameName. However, this will not be listed
|
|
1603
|
+
# among the LUs for its frame.
|
|
1604
|
+
self._warn('LU ID not found: {0} ({1}) in {2} ({3})'.format(luName, fn_luid, frameName, frameID))
|
|
1605
|
+
luinfo = AttrDict({'_type': 'lu', 'ID': fn_luid, 'name': luName,
|
|
1606
|
+
'frameID': frameID, 'status': 'Problem'})
|
|
1607
|
+
f = self.frame_by_id(luinfo.frameID)
|
|
1608
|
+
assert f.name==frameName,(f.name,frameName)
|
|
1609
|
+
luinfo['frame'] = f
|
|
1610
|
+
self._lu_idx[fn_luid] = luinfo
|
|
1611
|
+
elif '_type' not in luinfo:
|
|
964
1612
|
# we only have an index entry for the LU. loading the frame will replace this.
|
|
965
1613
|
f = self.frame_by_id(luinfo.frameID)
|
|
966
1614
|
luinfo = self._lu_idx[fn_luid]
|
|
@@ -988,9 +1636,18 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
988
1636
|
raise FramenetError('Unknown LU id: {0}'.format(fn_luid))
|
|
989
1637
|
|
|
990
1638
|
lu2 = self._handle_lexunit_elt(elt, ignorekeys)
|
|
1639
|
+
lu.URL = self._fnweb_url + '/' + self._lu_dir + '/' + fname
|
|
991
1640
|
lu.subCorpus = lu2.subCorpus
|
|
1641
|
+
lu.exemplars = SpecialList('luexemplars',
|
|
1642
|
+
[sent for subc in lu.subCorpus for sent in subc.sentence])
|
|
1643
|
+
for sent in lu.exemplars:
|
|
1644
|
+
sent['LU'] = lu
|
|
1645
|
+
sent['frame'] = lu.frame
|
|
1646
|
+
for aset in sent.annotationSet:
|
|
1647
|
+
aset['LU'] = lu
|
|
1648
|
+
aset['frame'] = lu.frame
|
|
992
1649
|
|
|
993
|
-
return lu
|
|
1650
|
+
return lu
|
|
994
1651
|
|
|
995
1652
|
def _loadsemtypes(self):
|
|
996
1653
|
"""Create the semantic types index."""
|
|
@@ -1034,11 +1691,11 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1034
1691
|
to traverse the neighboring relations on demand for each FE semtype.)
|
|
1035
1692
|
|
|
1036
1693
|
>>> from nltk.corpus import framenet as fn
|
|
1037
|
-
>>> sum(1 for f in fn.frames() for fe in f.FE.values() if fe.semType)
|
|
1038
|
-
4241
|
|
1694
|
+
>>> x = sum(1 for f in fn.frames() for fe in f.FE.values() if fe.semType)
|
|
1039
1695
|
>>> fn.propagate_semtypes()
|
|
1040
|
-
>>> sum(1 for f in fn.frames() for fe in f.FE.values() if fe.semType)
|
|
1041
|
-
|
|
1696
|
+
>>> y = sum(1 for f in fn.frames() for fe in f.FE.values() if fe.semType)
|
|
1697
|
+
>>> y-x > 1000
|
|
1698
|
+
True
|
|
1042
1699
|
"""
|
|
1043
1700
|
if not self._semtypes:
|
|
1044
1701
|
self._loadsemtypes()
|
|
@@ -1124,13 +1781,15 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1124
1781
|
Obtain details for a specific frame.
|
|
1125
1782
|
|
|
1126
1783
|
>>> from nltk.corpus import framenet as fn
|
|
1127
|
-
>>> len(fn.frames())
|
|
1128
|
-
|
|
1129
|
-
>>> PrettyList(fn.frames(r'(?i)
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
<frame ID=
|
|
1784
|
+
>>> len(fn.frames()) in (1019, 1221) # FN 1.5 and 1.7, resp.
|
|
1785
|
+
True
|
|
1786
|
+
>>> x = PrettyList(fn.frames(r'(?i)crim'), maxReprSize=0, breakLines=True)
|
|
1787
|
+
>>> x.sort(key=itemgetter('ID'))
|
|
1788
|
+
>>> x
|
|
1789
|
+
[<frame ID=200 name=Criminal_process>,
|
|
1790
|
+
<frame ID=500 name=Criminal_investigation>,
|
|
1791
|
+
<frame ID=692 name=Crime_scenario>,
|
|
1792
|
+
<frame ID=700 name=Committing_crime>]
|
|
1134
1793
|
|
|
1135
1794
|
A brief intro to Frames (excerpted from "FrameNet II: Extended
|
|
1136
1795
|
Theory and Practice" by Ruppenhofer et. al., 2010):
|
|
@@ -1198,28 +1857,33 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1198
1857
|
self._buildframeindex()
|
|
1199
1858
|
return dict((fID, finfo.name) for fID,finfo in self._frame_idx.items() if name is None or re.search(name, finfo.name) is not None)
|
|
1200
1859
|
|
|
1201
|
-
def fes(self, name=None):
|
|
1860
|
+
def fes(self, name=None, frame=None):
|
|
1202
1861
|
'''
|
|
1203
|
-
Lists frame element objects. If 'name' is provided, this is treated as
|
|
1204
|
-
a case-insensitive regular expression to filter by frame name.
|
|
1205
|
-
(Case-insensitivity is because casing of frame element names is not always
|
|
1206
|
-
consistent across frames.)
|
|
1207
|
-
|
|
1862
|
+
Lists frame element objects. If 'name' is provided, this is treated as
|
|
1863
|
+
a case-insensitive regular expression to filter by frame name.
|
|
1864
|
+
(Case-insensitivity is because casing of frame element names is not always
|
|
1865
|
+
consistent across frames.) Specify 'frame' to filter by a frame name pattern,
|
|
1866
|
+
ID, or object.
|
|
1867
|
+
|
|
1208
1868
|
>>> from nltk.corpus import framenet as fn
|
|
1209
1869
|
>>> fn.fes('Noise_maker')
|
|
1210
1870
|
[<fe ID=6043 name=Noise_maker>]
|
|
1211
1871
|
>>> sorted([(fe.frame.name,fe.name) for fe in fn.fes('sound')])
|
|
1212
|
-
[('Cause_to_make_noise', 'Sound_maker'), ('Make_noise', 'Sound'),
|
|
1213
|
-
('Make_noise', 'Sound_source'), ('Sound_movement', 'Location_of_sound_source'),
|
|
1214
|
-
('Sound_movement', 'Sound'), ('Sound_movement', 'Sound_source'),
|
|
1215
|
-
('Sounds', 'Component_sound'), ('Sounds', 'Location_of_sound_source'),
|
|
1216
|
-
('Sounds', 'Sound_source'), ('Vocalizations', 'Location_of_sound_source'),
|
|
1872
|
+
[('Cause_to_make_noise', 'Sound_maker'), ('Make_noise', 'Sound'),
|
|
1873
|
+
('Make_noise', 'Sound_source'), ('Sound_movement', 'Location_of_sound_source'),
|
|
1874
|
+
('Sound_movement', 'Sound'), ('Sound_movement', 'Sound_source'),
|
|
1875
|
+
('Sounds', 'Component_sound'), ('Sounds', 'Location_of_sound_source'),
|
|
1876
|
+
('Sounds', 'Sound_source'), ('Vocalizations', 'Location_of_sound_source'),
|
|
1217
1877
|
('Vocalizations', 'Sound_source')]
|
|
1878
|
+
>>> sorted([(fe.frame.name,fe.name) for fe in fn.fes('sound',r'(?i)make_noise')])
|
|
1879
|
+
[('Cause_to_make_noise', 'Sound_maker'),
|
|
1880
|
+
('Make_noise', 'Sound'),
|
|
1881
|
+
('Make_noise', 'Sound_source')]
|
|
1218
1882
|
>>> sorted(set(fe.name for fe in fn.fes('^sound')))
|
|
1219
1883
|
['Sound', 'Sound_maker', 'Sound_source']
|
|
1220
1884
|
>>> len(fn.fes('^sound$'))
|
|
1221
1885
|
2
|
|
1222
|
-
|
|
1886
|
+
|
|
1223
1887
|
:param name: A regular expression pattern used to match against
|
|
1224
1888
|
frame element names. If 'name' is None, then a list of all
|
|
1225
1889
|
frame elements will be returned.
|
|
@@ -1227,19 +1891,34 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1227
1891
|
:return: A list of matching frame elements
|
|
1228
1892
|
:rtype: list(AttrDict)
|
|
1229
1893
|
'''
|
|
1230
|
-
|
|
1894
|
+
# what frames are we searching in?
|
|
1895
|
+
if frame is not None:
|
|
1896
|
+
if isinstance(frame, int):
|
|
1897
|
+
frames = [self.frame(frame)]
|
|
1898
|
+
elif isinstance(frame, string_types):
|
|
1899
|
+
frames = self.frames(frame)
|
|
1900
|
+
else:
|
|
1901
|
+
frames = [frame]
|
|
1902
|
+
else:
|
|
1903
|
+
frames = self.frames()
|
|
1231
1904
|
|
|
1232
|
-
|
|
1905
|
+
return PrettyList(fe for f in frames for fename,fe in f.FE.items() if name is None or re.search(name, fename, re.I))
|
|
1906
|
+
|
|
1907
|
+
def lus(self, name=None, frame=None):
|
|
1233
1908
|
"""
|
|
1234
|
-
Obtain details for
|
|
1909
|
+
Obtain details for lexical units.
|
|
1910
|
+
Optionally restrict by lexical unit name pattern, and/or to a certain frame
|
|
1911
|
+
or frames whose name matches a pattern.
|
|
1235
1912
|
|
|
1236
1913
|
>>> from nltk.corpus import framenet as fn
|
|
1237
|
-
>>> len(fn.lus())
|
|
1238
|
-
|
|
1239
|
-
>>> PrettyList(fn.lus(r'(?i)a little'), maxReprSize=0, breakLines=True)
|
|
1240
|
-
[<lu ID=
|
|
1241
|
-
<lu ID=
|
|
1242
|
-
<lu ID=
|
|
1914
|
+
>>> len(fn.lus()) in (11829, 13572) # FN 1.5 and 1.7, resp.
|
|
1915
|
+
True
|
|
1916
|
+
>>> PrettyList(sorted(fn.lus(r'(?i)a little'), key=itemgetter('ID')), maxReprSize=0, breakLines=True)
|
|
1917
|
+
[<lu ID=14733 name=a little.n>,
|
|
1918
|
+
<lu ID=14743 name=a little.adv>,
|
|
1919
|
+
<lu ID=14744 name=a little bit.adv>]
|
|
1920
|
+
>>> PrettyList(sorted(fn.lus(r'interest', r'(?i)stimulus'), key=itemgetter('ID')))
|
|
1921
|
+
[<lu ID=14894 name=interested.a>, <lu ID=14920 name=interesting.a>]
|
|
1243
1922
|
|
|
1244
1923
|
A brief intro to Lexical Units (excerpted from "FrameNet II:
|
|
1245
1924
|
Extended Theory and Practice" by Ruppenhofer et. al., 2010):
|
|
@@ -1324,21 +2003,39 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1324
2003
|
scon - subordinating conjunction
|
|
1325
2004
|
|
|
1326
2005
|
:type name: str
|
|
2006
|
+
:type frame: str or int or frame
|
|
1327
2007
|
:return: A list of selected (or all) lexical units
|
|
1328
2008
|
:rtype: list of LU objects (dicts). See the lu() function for info
|
|
1329
2009
|
about the specifics of LU objects.
|
|
1330
2010
|
|
|
1331
2011
|
"""
|
|
1332
|
-
|
|
1333
|
-
luIDs = list(self._lu_idx.keys())
|
|
1334
|
-
except AttributeError:
|
|
2012
|
+
if not self._lu_idx:
|
|
1335
2013
|
self._buildluindex()
|
|
1336
|
-
luIDs = list(self._lu_idx.keys())
|
|
1337
2014
|
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
2015
|
+
|
|
2016
|
+
|
|
2017
|
+
if name is not None: # match LUs, then restrict by frame
|
|
2018
|
+
result = PrettyList(self.lu(luID) for luID,luName in self.lu_ids_and_names(name).items())
|
|
2019
|
+
if frame is not None:
|
|
2020
|
+
if isinstance(frame, int):
|
|
2021
|
+
frameIDs = {frame}
|
|
2022
|
+
elif isinstance(frame, string_types):
|
|
2023
|
+
frameIDs = {f.ID for f in self.frames(frame)}
|
|
2024
|
+
else:
|
|
2025
|
+
frameIDs = {frame.ID}
|
|
2026
|
+
result = PrettyList(lu for lu in result if lu.frame.ID in frameIDs)
|
|
2027
|
+
elif frame is not None: # all LUs in matching frames
|
|
2028
|
+
if isinstance(frame, int):
|
|
2029
|
+
frames = [self.frame(frame)]
|
|
2030
|
+
elif isinstance(frame, string_types):
|
|
2031
|
+
frames = self.frames(frame)
|
|
2032
|
+
else:
|
|
2033
|
+
frames = [frame]
|
|
2034
|
+
result = PrettyLazyIteratorList(iter(LazyConcatenation(list(f.lexUnit.values()) for f in frames)))
|
|
2035
|
+
else: # all LUs
|
|
2036
|
+
luIDs = [luID for luID,lu in self._lu_idx.items() if lu.status not in self._bad_statuses]
|
|
2037
|
+
result = PrettyLazyMap(self.lu, luIDs)
|
|
2038
|
+
return result
|
|
1342
2039
|
|
|
1343
2040
|
def lu_ids_and_names(self, name=None):
|
|
1344
2041
|
"""
|
|
@@ -1347,20 +2044,22 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1347
2044
|
"""
|
|
1348
2045
|
if not self._lu_idx:
|
|
1349
2046
|
self._buildluindex()
|
|
1350
|
-
return
|
|
2047
|
+
return {luID: luinfo.name for luID,luinfo in self._lu_idx.items()
|
|
2048
|
+
if luinfo.status not in self._bad_statuses
|
|
2049
|
+
and (name is None or re.search(name, luinfo.name) is not None)}
|
|
1351
2050
|
|
|
1352
|
-
def
|
|
2051
|
+
def docs_metadata(self, name=None):
|
|
1353
2052
|
"""
|
|
1354
|
-
Return
|
|
2053
|
+
Return an index of the annotated documents in Framenet.
|
|
1355
2054
|
|
|
1356
2055
|
Details for a specific annotated document can be obtained using this
|
|
1357
|
-
class's
|
|
2056
|
+
class's doc() function and pass it the value of the 'ID' field.
|
|
1358
2057
|
|
|
1359
2058
|
>>> from nltk.corpus import framenet as fn
|
|
1360
|
-
>>> len(fn.
|
|
1361
|
-
|
|
1362
|
-
>>> set([x.corpname for x in fn.
|
|
1363
|
-
'LUCorpus-v0.3', 'Miscellaneous', 'NTI', 'PropBank'
|
|
2059
|
+
>>> len(fn.docs()) in (78, 107) # FN 1.5 and 1.7, resp.
|
|
2060
|
+
True
|
|
2061
|
+
>>> set([x.corpname for x in fn.docs_metadata()])>=set(['ANC', 'KBEval', \
|
|
2062
|
+
'LUCorpus-v0.3', 'Miscellaneous', 'NTI', 'PropBank'])
|
|
1364
2063
|
True
|
|
1365
2064
|
|
|
1366
2065
|
:param name: A regular expression pattern used to search the
|
|
@@ -1394,16 +2093,162 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1394
2093
|
else:
|
|
1395
2094
|
return PrettyList(x for x in ftlist if re.search(name, x['filename']) is not None)
|
|
1396
2095
|
|
|
2096
|
+
def docs(self, name=None):
|
|
2097
|
+
"""
|
|
2098
|
+
Return a list of the annotated full-text documents in FrameNet,
|
|
2099
|
+
optionally filtered by a regex to be matched against the document name.
|
|
2100
|
+
"""
|
|
2101
|
+
return PrettyLazyMap((lambda x: self.doc(x.ID)), self.docs_metadata(name))
|
|
2102
|
+
|
|
2103
|
+
def sents(self, exemplars=True, full_text=True):
|
|
2104
|
+
"""
|
|
2105
|
+
Annotated sentences matching the specified criteria.
|
|
2106
|
+
"""
|
|
2107
|
+
if exemplars:
|
|
2108
|
+
if full_text:
|
|
2109
|
+
return self.exemplars() + self.ft_sents()
|
|
2110
|
+
else:
|
|
2111
|
+
return self.exemplars()
|
|
2112
|
+
elif full_text:
|
|
2113
|
+
return self.ft_sents()
|
|
2114
|
+
|
|
2115
|
+
def annotations(self, luNamePattern=None, exemplars=True, full_text=True):
|
|
2116
|
+
"""
|
|
2117
|
+
Frame annotation sets matching the specified criteria.
|
|
2118
|
+
"""
|
|
2119
|
+
|
|
2120
|
+
if exemplars:
|
|
2121
|
+
epart = PrettyLazyIteratorList(sent.frameAnnotation for sent in self.exemplars(luNamePattern))
|
|
2122
|
+
else:
|
|
2123
|
+
epart = []
|
|
2124
|
+
|
|
2125
|
+
if full_text:
|
|
2126
|
+
if luNamePattern is not None:
|
|
2127
|
+
matchedLUIDs = set(self.lu_ids_and_names(luNamePattern).keys())
|
|
2128
|
+
ftpart = PrettyLazyIteratorList(aset for sent in self.ft_sents() for aset in sent.annotationSet[1:] if luNamePattern is None or aset.get('luID','CXN_ASET') in matchedLUIDs)
|
|
2129
|
+
else:
|
|
2130
|
+
ftpart = []
|
|
2131
|
+
|
|
2132
|
+
if exemplars:
|
|
2133
|
+
if full_text:
|
|
2134
|
+
return epart + ftpart
|
|
2135
|
+
else:
|
|
2136
|
+
return epart
|
|
2137
|
+
elif full_text:
|
|
2138
|
+
return ftpart
|
|
2139
|
+
|
|
2140
|
+
def exemplars(self, luNamePattern=None, frame=None, fe=None, fe2=None):
|
|
2141
|
+
"""
|
|
2142
|
+
Lexicographic exemplar sentences, optionally filtered by LU name and/or 1-2 FEs that
|
|
2143
|
+
are realized overtly. 'frame' may be a name pattern, frame ID, or frame instance.
|
|
2144
|
+
'fe' may be a name pattern or FE instance; if specified, 'fe2' may also
|
|
2145
|
+
be specified to retrieve sentences with both overt FEs (in either order).
|
|
2146
|
+
"""
|
|
2147
|
+
if fe is None and fe2 is not None:
|
|
2148
|
+
raise FramenetError('exemplars(..., fe=None, fe2=<value>) is not allowed')
|
|
2149
|
+
elif fe is not None and fe2 is not None:
|
|
2150
|
+
if not isinstance(fe2, string_types):
|
|
2151
|
+
if isinstance(fe, string_types):
|
|
2152
|
+
# fe2 is specific to a particular frame. swap fe and fe2 so fe is always used to determine the frame.
|
|
2153
|
+
fe, fe2 = fe2, fe
|
|
2154
|
+
elif fe.frame is not fe2.frame: # ensure frames match
|
|
2155
|
+
raise FramenetError('exemplars() call with inconsistent `fe` and `fe2` specification (frames must match)')
|
|
2156
|
+
if frame is None and fe is not None and not isinstance(fe, string_types):
|
|
2157
|
+
frame = fe.frame
|
|
2158
|
+
|
|
2159
|
+
# narrow down to frames matching criteria
|
|
2160
|
+
|
|
2161
|
+
lusByFrame = defaultdict(list) # frame name -> matching LUs, if luNamePattern is specified
|
|
2162
|
+
if frame is not None or luNamePattern is not None:
|
|
2163
|
+
if frame is None or isinstance(frame, string_types):
|
|
2164
|
+
if luNamePattern is not None:
|
|
2165
|
+
frames = set()
|
|
2166
|
+
for lu in self.lus(luNamePattern, frame=frame):
|
|
2167
|
+
frames.add(lu.frame.ID)
|
|
2168
|
+
lusByFrame[lu.frame.name].append(lu)
|
|
2169
|
+
frames = LazyMap(self.frame, list(frames))
|
|
2170
|
+
else:
|
|
2171
|
+
frames = self.frames(frame)
|
|
2172
|
+
else:
|
|
2173
|
+
if isinstance(frame,int):
|
|
2174
|
+
frames = [self.frame(frame)]
|
|
2175
|
+
else: # frame object
|
|
2176
|
+
frames = [frame]
|
|
2177
|
+
|
|
2178
|
+
if luNamePattern is not None:
|
|
2179
|
+
lusByFrame = {frame.name: self.lus(luNamePattern, frame=frame)}
|
|
2180
|
+
|
|
2181
|
+
if fe is not None: # narrow to frames that define this FE
|
|
2182
|
+
if isinstance(fe, string_types):
|
|
2183
|
+
frames = PrettyLazyIteratorList(f for f in frames if fe in f.FE or any(re.search(fe, ffe, re.I) for ffe in f.FE.keys()))
|
|
2184
|
+
else:
|
|
2185
|
+
if fe.frame not in frames:
|
|
2186
|
+
raise FramenetError('exemplars() call with inconsistent `frame` and `fe` specification')
|
|
2187
|
+
frames = [fe.frame]
|
|
2188
|
+
|
|
2189
|
+
if fe2 is not None: # narrow to frames that ALSO define this FE
|
|
2190
|
+
if isinstance(fe2, string_types):
|
|
2191
|
+
frames = PrettyLazyIteratorList(f for f in frames if fe2 in f.FE or any(re.search(fe2, ffe, re.I) for ffe in f.FE.keys()))
|
|
2192
|
+
# else we already narrowed it to a single frame
|
|
2193
|
+
else: # frame, luNamePattern are None. fe, fe2 are None or strings
|
|
2194
|
+
if fe is not None:
|
|
2195
|
+
frames = {ffe.frame.ID for ffe in self.fes(fe)}
|
|
2196
|
+
if fe2 is not None:
|
|
2197
|
+
frames2 = {ffe.frame.ID for ffe in self.fes(fe2)}
|
|
2198
|
+
frames = frames & frames2
|
|
2199
|
+
frames = LazyMap(self.frame, list(frames))
|
|
2200
|
+
else:
|
|
2201
|
+
frames = self.frames()
|
|
2202
|
+
|
|
2203
|
+
# we've narrowed down 'frames'
|
|
2204
|
+
# now get exemplars for relevant LUs in those frames
|
|
2205
|
+
|
|
2206
|
+
def _matching_exs():
|
|
2207
|
+
for f in frames:
|
|
2208
|
+
fes = fes2 = None # FEs of interest
|
|
2209
|
+
if fe is not None:
|
|
2210
|
+
fes = {ffe for ffe in f.FE.keys() if re.search(fe, ffe, re.I)} if isinstance(fe, string_types) else {fe.name}
|
|
2211
|
+
if fe2 is not None:
|
|
2212
|
+
fes2 = {ffe for ffe in f.FE.keys() if re.search(fe2, ffe, re.I)} if isinstance(fe2, string_types) else {fe2.name}
|
|
2213
|
+
|
|
2214
|
+
for lu in lusByFrame[f.name] if luNamePattern is not None else f.lexUnit.values():
|
|
2215
|
+
for ex in lu.exemplars:
|
|
2216
|
+
if (fes is None or self._exemplar_of_fes(ex, fes)) and (fes2 is None or self._exemplar_of_fes(ex, fes2)):
|
|
2217
|
+
yield ex
|
|
2218
|
+
|
|
2219
|
+
return PrettyLazyIteratorList(_matching_exs())
|
|
2220
|
+
|
|
2221
|
+
def _exemplar_of_fes(self, ex, fes=None):
|
|
2222
|
+
"""
|
|
2223
|
+
Given an exemplar sentence and a set of FE names, return the subset of FE names
|
|
2224
|
+
that are realized overtly in the sentence on the FE, FE2, or FE3 layer.
|
|
2225
|
+
|
|
2226
|
+
If 'fes' is None, returns all overt FE names.
|
|
2227
|
+
"""
|
|
2228
|
+
overtNames = set(list(zip(*ex.FE[0]))[2]) if ex.FE[0] else set()
|
|
2229
|
+
if 'FE2' in ex:
|
|
2230
|
+
overtNames |= set(list(zip(*ex.FE2[0]))[2]) if ex.FE2[0] else set()
|
|
2231
|
+
if 'FE3' in ex:
|
|
2232
|
+
overtNames |= set(list(zip(*ex.FE3[0]))[2]) if ex.FE3[0] else set()
|
|
2233
|
+
return overtNames & fes if fes is not None else overtNames
|
|
2234
|
+
|
|
2235
|
+
def ft_sents(self, docNamePattern=None):
|
|
2236
|
+
"""
|
|
2237
|
+
Full-text annotation sentences, optionally filtered by document name.
|
|
2238
|
+
"""
|
|
2239
|
+
return PrettyLazyIteratorList(sent for d in self.docs(docNamePattern) for sent in d.sentence)
|
|
2240
|
+
|
|
2241
|
+
|
|
1397
2242
|
def frame_relation_types(self):
|
|
1398
2243
|
"""
|
|
1399
2244
|
Obtain a list of frame relation types.
|
|
1400
2245
|
|
|
1401
2246
|
>>> from nltk.corpus import framenet as fn
|
|
1402
|
-
>>> frts =
|
|
2247
|
+
>>> frts = sorted(fn.frame_relation_types(), key=itemgetter('ID'))
|
|
1403
2248
|
>>> isinstance(frts, list)
|
|
1404
2249
|
True
|
|
1405
|
-
>>> len(frts)
|
|
1406
|
-
|
|
2250
|
+
>>> len(frts) in (9, 10) # FN 1.5 and 1.7, resp.
|
|
2251
|
+
True
|
|
1407
2252
|
>>> PrettyDict(frts[0], breakLines=True)
|
|
1408
2253
|
{'ID': 1,
|
|
1409
2254
|
'_type': 'framerelationtype',
|
|
@@ -1435,15 +2280,15 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1435
2280
|
>>> frels = fn.frame_relations()
|
|
1436
2281
|
>>> isinstance(frels, list)
|
|
1437
2282
|
True
|
|
1438
|
-
>>> len(frels)
|
|
1439
|
-
|
|
2283
|
+
>>> len(frels) in (1676, 2070) # FN 1.5 and 1.7, resp.
|
|
2284
|
+
True
|
|
1440
2285
|
>>> PrettyList(fn.frame_relations('Cooking_creation'), maxReprSize=0, breakLines=True)
|
|
1441
2286
|
[<Parent=Intentionally_create -- Inheritance -> Child=Cooking_creation>,
|
|
1442
2287
|
<Parent=Apply_heat -- Using -> Child=Cooking_creation>,
|
|
1443
2288
|
<MainEntry=Apply_heat -- See_also -> ReferringEntry=Cooking_creation>]
|
|
1444
|
-
>>> PrettyList(fn.frame_relations(
|
|
1445
|
-
[<Parent=
|
|
1446
|
-
<
|
|
2289
|
+
>>> PrettyList(fn.frame_relations(274), breakLines=True)
|
|
2290
|
+
[<Parent=Avoiding -- Inheritance -> Child=Dodging>,
|
|
2291
|
+
<Parent=Avoiding -- Inheritance -> Child=Evading>, ...]
|
|
1447
2292
|
>>> PrettyList(fn.frame_relations(fn.frame('Cooking_creation')), breakLines=True)
|
|
1448
2293
|
[<Parent=Intentionally_create -- Inheritance -> Child=Cooking_creation>,
|
|
1449
2294
|
<Parent=Apply_heat -- Using -> Child=Cooking_creation>, ...]
|
|
@@ -1510,8 +2355,8 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1510
2355
|
>>> ferels = fn.fe_relations()
|
|
1511
2356
|
>>> isinstance(ferels, list)
|
|
1512
2357
|
True
|
|
1513
|
-
>>> len(ferels)
|
|
1514
|
-
|
|
2358
|
+
>>> len(ferels) in (10020, 12393) # FN 1.5 and 1.7, resp.
|
|
2359
|
+
True
|
|
1515
2360
|
>>> PrettyDict(ferels[0], breakLines=True)
|
|
1516
2361
|
{'ID': 14642,
|
|
1517
2362
|
'_type': 'ferelation',
|
|
@@ -1541,10 +2386,10 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1541
2386
|
|
|
1542
2387
|
>>> from nltk.corpus import framenet as fn
|
|
1543
2388
|
>>> stypes = fn.semtypes()
|
|
1544
|
-
>>> len(stypes)
|
|
1545
|
-
|
|
2389
|
+
>>> len(stypes) in (73, 109) # FN 1.5 and 1.7, resp.
|
|
2390
|
+
True
|
|
1546
2391
|
>>> sorted(stypes[0].keys())
|
|
1547
|
-
['ID', '_type', 'abbrev', 'definition', 'name', 'rootType', 'subTypes', 'superType']
|
|
2392
|
+
['ID', '_type', 'abbrev', 'definition', 'definitionMarkup', 'name', 'rootType', 'subTypes', 'superType']
|
|
1548
2393
|
|
|
1549
2394
|
:return: A list of all of the semantic types in framenet
|
|
1550
2395
|
:rtype: list(dict)
|
|
@@ -1577,8 +2422,8 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1577
2422
|
return d
|
|
1578
2423
|
|
|
1579
2424
|
# Ignore these attributes when loading attributes from an xml node
|
|
1580
|
-
ignore_attrs = ['cBy', 'cDate', 'mDate',
|
|
1581
|
-
'schemaLocation', 'xmlns', 'bgColor', 'fgColor']
|
|
2425
|
+
ignore_attrs = [ #'cBy', 'cDate', 'mDate', # <-- annotation metadata that could be of interest
|
|
2426
|
+
'xsi', 'schemaLocation', 'xmlns', 'bgColor', 'fgColor']
|
|
1582
2427
|
|
|
1583
2428
|
for attr in attr_dict:
|
|
1584
2429
|
|
|
@@ -1602,6 +2447,13 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1602
2447
|
"""
|
|
1603
2448
|
|
|
1604
2449
|
try:
|
|
2450
|
+
'''
|
|
2451
|
+
# Look for boundary issues in markup. (Sometimes FEs are pluralized in definitions.)
|
|
2452
|
+
m = re.search(r'\w[<][^/]|[<][/][^>]+[>](s\w|[a-rt-z0-9])', data)
|
|
2453
|
+
if m:
|
|
2454
|
+
print('Markup boundary:', data[max(0,m.start(0)-10):m.end(0)+10].replace('\n',' '), file=sys.stderr)
|
|
2455
|
+
'''
|
|
2456
|
+
|
|
1605
2457
|
data = data.replace('<t>', '')
|
|
1606
2458
|
data = data.replace('</t>', '')
|
|
1607
2459
|
data = re.sub('<fex name="[^"]+">', '', data)
|
|
@@ -1657,6 +2509,7 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1657
2509
|
else:
|
|
1658
2510
|
docname = doc.description
|
|
1659
2511
|
doc.filename = "{0}__{1}.xml".format(corpname, docname)
|
|
2512
|
+
doc.URL = self._fnweb_url + '/' + self._fulltext_dir + '/' + doc.filename
|
|
1660
2513
|
doc.corpname = corpname
|
|
1661
2514
|
doc.corpid = corpid
|
|
1662
2515
|
retlist.append(doc)
|
|
@@ -1664,11 +2517,12 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1664
2517
|
return retlist
|
|
1665
2518
|
|
|
1666
2519
|
def _handle_frame_elt(self, elt, ignorekeys=[]):
|
|
1667
|
-
"""Load the info for a Frame from
|
|
2520
|
+
"""Load the info for a Frame from a frame xml file"""
|
|
1668
2521
|
frinfo = self._load_xml_attributes(AttrDict(), elt)
|
|
1669
2522
|
|
|
1670
2523
|
frinfo['_type'] = 'frame'
|
|
1671
2524
|
frinfo['definition'] = ""
|
|
2525
|
+
frinfo['definitionMarkup'] = ""
|
|
1672
2526
|
frinfo['FE'] = PrettyDict()
|
|
1673
2527
|
frinfo['FEcoreSets'] = []
|
|
1674
2528
|
frinfo['lexUnit'] = PrettyDict()
|
|
@@ -1679,6 +2533,7 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1679
2533
|
|
|
1680
2534
|
for sub in elt:
|
|
1681
2535
|
if sub.tag.endswith('definition') and 'definition' not in ignorekeys:
|
|
2536
|
+
frinfo['definitionMarkup'] = sub.text
|
|
1682
2537
|
frinfo['definition'] = self._strip_tags(sub.text)
|
|
1683
2538
|
elif sub.tag.endswith('FE') and 'FE' not in ignorekeys:
|
|
1684
2539
|
feinfo = self._handle_fe_elt(sub)
|
|
@@ -1694,7 +2549,9 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1694
2549
|
# problematic LU entry; ignore it
|
|
1695
2550
|
continue
|
|
1696
2551
|
luentry['frame'] = frinfo
|
|
1697
|
-
luentry['
|
|
2552
|
+
luentry['URL'] = self._fnweb_url + '/' + self._lu_dir + '/' + "lu{0}.xml".format(luentry['ID'])
|
|
2553
|
+
luentry['subCorpus'] = Future((lambda lu: lambda: self._lu_file(lu).subCorpus)(luentry))
|
|
2554
|
+
luentry['exemplars'] = Future((lambda lu: lambda: self._lu_file(lu).exemplars)(luentry))
|
|
1698
2555
|
frinfo['lexUnit'][luentry.name] = luentry
|
|
1699
2556
|
if not self._lu_idx:
|
|
1700
2557
|
self._buildluindex()
|
|
@@ -1765,7 +2622,7 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1765
2622
|
element (which we ignore here) and a bunch of 'sentence'
|
|
1766
2623
|
elements."""
|
|
1767
2624
|
info = AttrDict()
|
|
1768
|
-
info['_type'] = '
|
|
2625
|
+
info['_type'] = 'fulltext_annotation'
|
|
1769
2626
|
info['sentence'] = []
|
|
1770
2627
|
|
|
1771
2628
|
for sub in elt:
|
|
@@ -1773,40 +2630,59 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1773
2630
|
continue # not used
|
|
1774
2631
|
elif sub.tag.endswith('sentence'):
|
|
1775
2632
|
s = self._handle_fulltext_sentence_elt(sub)
|
|
2633
|
+
s.doc = info
|
|
1776
2634
|
info['sentence'].append(s)
|
|
1777
2635
|
|
|
1778
2636
|
return info
|
|
1779
2637
|
|
|
1780
2638
|
def _handle_fulltext_sentence_elt(self, elt):
|
|
1781
2639
|
"""Load information from the given 'sentence' element. Each
|
|
1782
|
-
'sentence' element contains a "text" and
|
|
1783
|
-
|
|
2640
|
+
'sentence' element contains a "text" and "annotationSet" sub
|
|
2641
|
+
elements."""
|
|
1784
2642
|
info = self._load_xml_attributes(AttrDict(), elt)
|
|
1785
|
-
info['_type'] = "
|
|
2643
|
+
info['_type'] = "fulltext_sentence"
|
|
1786
2644
|
info['annotationSet'] = []
|
|
2645
|
+
info['targets'] = []
|
|
2646
|
+
target_spans = set()
|
|
2647
|
+
info['_ascii'] = types.MethodType(_annotation_ascii, info) # attach a method for this instance
|
|
1787
2648
|
info['text'] = ""
|
|
1788
2649
|
|
|
1789
2650
|
for sub in elt:
|
|
1790
2651
|
if sub.tag.endswith('text'):
|
|
1791
2652
|
info['text'] = self._strip_tags(sub.text)
|
|
1792
2653
|
elif sub.tag.endswith('annotationSet'):
|
|
1793
|
-
a = self._handle_fulltextannotationset_elt(sub)
|
|
2654
|
+
a = self._handle_fulltextannotationset_elt(sub, is_pos=(len(info['annotationSet'])==0))
|
|
2655
|
+
if 'cxnID' in a: # ignoring construction annotations for now
|
|
2656
|
+
continue
|
|
2657
|
+
a.sent = info
|
|
2658
|
+
a.text = info.text
|
|
1794
2659
|
info['annotationSet'].append(a)
|
|
1795
|
-
|
|
2660
|
+
if 'Target' in a:
|
|
2661
|
+
for tspan in a.Target:
|
|
2662
|
+
if tspan in target_spans:
|
|
2663
|
+
self._warn('Duplicate target span "{0}"'.format(info.text[slice(*tspan)]),
|
|
2664
|
+
tspan, 'in sentence',info['ID'], info.text)
|
|
2665
|
+
# this can happen in cases like "chemical and biological weapons"
|
|
2666
|
+
# being annotated as "chemical weapons" and "biological weapons"
|
|
2667
|
+
else:
|
|
2668
|
+
target_spans.add(tspan)
|
|
2669
|
+
info['targets'].append((a.Target, a.luName, a.frameName))
|
|
2670
|
+
|
|
2671
|
+
assert info['annotationSet'][0].status=='UNANN'
|
|
2672
|
+
info['POS'] = info['annotationSet'][0].POS
|
|
2673
|
+
info['POS_tagset'] = info['annotationSet'][0].POS_tagset
|
|
1796
2674
|
return info
|
|
1797
2675
|
|
|
1798
|
-
def _handle_fulltextannotationset_elt(self, elt):
|
|
2676
|
+
def _handle_fulltextannotationset_elt(self, elt, is_pos=False):
|
|
1799
2677
|
"""Load information from the given 'annotationSet' element. Each
|
|
1800
2678
|
'annotationSet' contains several "layer" elements."""
|
|
1801
|
-
info = self._load_xml_attributes(AttrDict(), elt)
|
|
1802
|
-
info['_type'] = "annotationset"
|
|
1803
|
-
info['layer'] = []
|
|
1804
|
-
|
|
1805
|
-
for sub in elt:
|
|
1806
|
-
if sub.tag.endswith('layer'):
|
|
1807
|
-
l = self._handle_fulltextlayer_elt(sub)
|
|
1808
|
-
info['layer'].append(l)
|
|
1809
2679
|
|
|
2680
|
+
info = self._handle_luannotationset_elt(elt, is_pos=is_pos)
|
|
2681
|
+
if not is_pos:
|
|
2682
|
+
info['_type'] = 'fulltext_annotationset'
|
|
2683
|
+
if 'cxnID' not in info: # ignoring construction annotations for now
|
|
2684
|
+
info['LU'] = self.lu(info.luID, luName=info.luName, frameID=info.frameID, frameName=info.frameName)
|
|
2685
|
+
info['frame'] = info.LU.frame
|
|
1810
2686
|
return info
|
|
1811
2687
|
|
|
1812
2688
|
def _handle_fulltextlayer_elt(self, elt):
|
|
@@ -1829,22 +2705,33 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1829
2705
|
luinfo['_type'] = 'lu'
|
|
1830
2706
|
luinfo = self._load_xml_attributes(luinfo, elt)
|
|
1831
2707
|
luinfo["definition"] = ""
|
|
2708
|
+
luinfo["definitionMarkup"] = ""
|
|
1832
2709
|
luinfo["sentenceCount"] = PrettyDict()
|
|
1833
2710
|
luinfo['lexemes'] = PrettyList() # multiword LUs have multiple lexemes
|
|
1834
2711
|
luinfo['semTypes'] = PrettyList() # an LU can have multiple semtypes
|
|
1835
2712
|
|
|
1836
2713
|
for sub in elt:
|
|
1837
2714
|
if sub.tag.endswith('definition'):
|
|
2715
|
+
luinfo['definitionMarkup'] = sub.text
|
|
1838
2716
|
luinfo['definition'] = self._strip_tags(sub.text)
|
|
1839
2717
|
elif sub.tag.endswith('sentenceCount'):
|
|
1840
2718
|
luinfo['sentenceCount'] = self._load_xml_attributes(
|
|
1841
2719
|
PrettyDict(), sub)
|
|
1842
2720
|
elif sub.tag.endswith('lexeme'):
|
|
1843
|
-
|
|
2721
|
+
lexemeinfo = self._load_xml_attributes(PrettyDict(), sub)
|
|
2722
|
+
if not isinstance(lexemeinfo.name, string_types):
|
|
2723
|
+
# some lexeme names are ints by default: e.g.,
|
|
2724
|
+
# thousand.num has lexeme with name="1000"
|
|
2725
|
+
lexemeinfo.name = str(lexemeinfo.name)
|
|
2726
|
+
luinfo['lexemes'].append(lexemeinfo)
|
|
1844
2727
|
elif sub.tag.endswith('semType'):
|
|
1845
2728
|
semtypeinfo = self._load_xml_attributes(PrettyDict(), sub)
|
|
1846
2729
|
luinfo['semTypes'].append(self.semtype(semtypeinfo.ID))
|
|
1847
2730
|
|
|
2731
|
+
# sort lexemes by 'order' attribute
|
|
2732
|
+
# otherwise, e.g., 'write down.v' may have lexemes in wrong order
|
|
2733
|
+
luinfo['lexemes'].sort(key=lambda x: x.order)
|
|
2734
|
+
|
|
1848
2735
|
return luinfo
|
|
1849
2736
|
|
|
1850
2737
|
def _handle_lexunit_elt(self, elt, ignorekeys):
|
|
@@ -1856,6 +2743,7 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1856
2743
|
luinfo = self._load_xml_attributes(AttrDict(), elt)
|
|
1857
2744
|
luinfo['_type'] = 'lu'
|
|
1858
2745
|
luinfo['definition'] = ""
|
|
2746
|
+
luinfo['definitionMarkup'] = ""
|
|
1859
2747
|
luinfo['subCorpus'] = PrettyList()
|
|
1860
2748
|
luinfo['lexemes'] = PrettyList() # multiword LUs have multiple lexemes
|
|
1861
2749
|
luinfo['semTypes'] = PrettyList() # an LU can have multiple semtypes
|
|
@@ -1869,6 +2757,7 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1869
2757
|
elif sub.tag.endswith('valences'):
|
|
1870
2758
|
continue # not used
|
|
1871
2759
|
elif sub.tag.endswith('definition') and 'definition' not in ignorekeys:
|
|
2760
|
+
luinfo['definitionMarkup'] = sub.text
|
|
1872
2761
|
luinfo['definition'] = self._strip_tags(sub.text)
|
|
1873
2762
|
elif sub.tag.endswith('subCorpus') and 'subCorpus' not in ignorekeys:
|
|
1874
2763
|
sc = self._handle_lusubcorpus_elt(sub)
|
|
@@ -1886,7 +2775,7 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1886
2775
|
"""Load a subcorpus of a lexical unit from the given xml."""
|
|
1887
2776
|
sc = AttrDict()
|
|
1888
2777
|
try:
|
|
1889
|
-
sc['name'] =
|
|
2778
|
+
sc['name'] = elt.get('name')
|
|
1890
2779
|
except AttributeError:
|
|
1891
2780
|
return None
|
|
1892
2781
|
sc['_type'] = "lusubcorpus"
|
|
@@ -1905,25 +2794,99 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1905
2794
|
info = self._load_xml_attributes(AttrDict(), elt)
|
|
1906
2795
|
info['_type'] = 'lusentence'
|
|
1907
2796
|
info['annotationSet'] = []
|
|
2797
|
+
info['_ascii'] = types.MethodType(_annotation_ascii, info) # attach a method for this instance
|
|
1908
2798
|
for sub in elt:
|
|
1909
2799
|
if sub.tag.endswith('text'):
|
|
1910
2800
|
info['text'] = self._strip_tags(sub.text)
|
|
1911
2801
|
elif sub.tag.endswith('annotationSet'):
|
|
1912
|
-
annset = self._handle_luannotationset_elt(sub)
|
|
2802
|
+
annset = self._handle_luannotationset_elt(sub, is_pos=(len(info['annotationSet'])==0))
|
|
1913
2803
|
if annset is not None:
|
|
2804
|
+
assert annset.status=='UNANN' or 'FE' in annset,annset
|
|
2805
|
+
if annset.status!='UNANN':
|
|
2806
|
+
info['frameAnnotation'] = annset
|
|
2807
|
+
# copy layer info up to current level
|
|
2808
|
+
for k in ('Target', 'FE', 'FE2', 'FE3', 'GF', 'PT', 'POS', 'POS_tagset',
|
|
2809
|
+
'Other', 'Sent', 'Verb', 'Noun', 'Adj', 'Adv', 'Prep', 'Scon', 'Art'):
|
|
2810
|
+
if k in annset:
|
|
2811
|
+
info[k] = annset[k]
|
|
1914
2812
|
info['annotationSet'].append(annset)
|
|
2813
|
+
annset['sent'] = info
|
|
2814
|
+
annset['text'] = info.text
|
|
1915
2815
|
return info
|
|
1916
2816
|
|
|
1917
|
-
def _handle_luannotationset_elt(self, elt):
|
|
2817
|
+
def _handle_luannotationset_elt(self, elt, is_pos=False):
|
|
1918
2818
|
"""Load an annotation set from a sentence in an subcorpus of an LU"""
|
|
1919
2819
|
info = self._load_xml_attributes(AttrDict(), elt)
|
|
1920
|
-
info['_type'] = 'luannotationset'
|
|
2820
|
+
info['_type'] = 'posannotationset' if is_pos else 'luannotationset'
|
|
1921
2821
|
info['layer'] = []
|
|
2822
|
+
info['_ascii'] = types.MethodType(_annotation_ascii, info) # attach a method for this instance
|
|
2823
|
+
|
|
2824
|
+
if 'cxnID' in info: # ignoring construction annotations for now.
|
|
2825
|
+
return info
|
|
2826
|
+
|
|
1922
2827
|
for sub in elt:
|
|
1923
2828
|
if sub.tag.endswith('layer'):
|
|
1924
2829
|
l = self._handle_lulayer_elt(sub)
|
|
1925
2830
|
if l is not None:
|
|
2831
|
+
overt = []
|
|
2832
|
+
ni = {} # null instantiations
|
|
2833
|
+
|
|
1926
2834
|
info['layer'].append(l)
|
|
2835
|
+
for lbl in l.label:
|
|
2836
|
+
if 'start' in lbl:
|
|
2837
|
+
thespan = (lbl.start,lbl.end+1,lbl.name)
|
|
2838
|
+
if l.name not in ('Sent','Other'): # 'Sent' and 'Other' layers sometimes contain accidental duplicate spans
|
|
2839
|
+
assert thespan not in overt,(info.ID,l.name,thespan)
|
|
2840
|
+
overt.append(thespan)
|
|
2841
|
+
else: # null instantiation
|
|
2842
|
+
if lbl.name in ni:
|
|
2843
|
+
self._warn('FE with multiple NI entries:', lbl.name, ni[lbl.name], lbl.itype)
|
|
2844
|
+
else:
|
|
2845
|
+
ni[lbl.name] = lbl.itype
|
|
2846
|
+
overt = sorted(overt)
|
|
2847
|
+
|
|
2848
|
+
if l.name=='Target':
|
|
2849
|
+
if not overt:
|
|
2850
|
+
self._warn('Skipping empty Target layer in annotation set ID={0}'.format(info.ID))
|
|
2851
|
+
continue
|
|
2852
|
+
assert all(lblname=='Target' for i,j,lblname in overt)
|
|
2853
|
+
if 'Target' in info:
|
|
2854
|
+
self._warn('Annotation set {0} has multiple Target layers'.format(info.ID))
|
|
2855
|
+
else:
|
|
2856
|
+
info['Target'] = [(i,j) for (i,j,_) in overt]
|
|
2857
|
+
elif l.name=='FE':
|
|
2858
|
+
if l.rank==1:
|
|
2859
|
+
assert 'FE' not in info
|
|
2860
|
+
info['FE'] = (overt, ni)
|
|
2861
|
+
#assert False,info
|
|
2862
|
+
else:
|
|
2863
|
+
# sometimes there are 3 FE layers! e.g. Change_position_on_a_scale.fall.v
|
|
2864
|
+
assert 2<=l.rank<=3,l.rank
|
|
2865
|
+
k = 'FE'+str(l.rank)
|
|
2866
|
+
assert k not in info
|
|
2867
|
+
info[k] = (overt, ni)
|
|
2868
|
+
elif l.name in ('GF', 'PT'):
|
|
2869
|
+
assert l.rank==1
|
|
2870
|
+
info[l.name] = overt
|
|
2871
|
+
elif l.name in ('BNC', 'PENN'):
|
|
2872
|
+
assert l.rank==1
|
|
2873
|
+
info['POS'] = overt
|
|
2874
|
+
info['POS_tagset'] = l.name
|
|
2875
|
+
else:
|
|
2876
|
+
if is_pos:
|
|
2877
|
+
if l.name not in ('NER', 'WSL'):
|
|
2878
|
+
self._warn('Unexpected layer in sentence annotationset:', l.name)
|
|
2879
|
+
else:
|
|
2880
|
+
if l.name not in ('Sent', 'Verb', 'Noun', 'Adj', 'Adv', 'Prep', 'Scon', 'Art', 'Other'):
|
|
2881
|
+
self._warn('Unexpected layer in frame annotationset:', l.name)
|
|
2882
|
+
info[l.name] = overt
|
|
2883
|
+
if not is_pos and 'cxnID' not in info:
|
|
2884
|
+
if 'Target' not in info:
|
|
2885
|
+
self._warn('Missing target in annotation set ID={0}'.format(info.ID))
|
|
2886
|
+
assert 'FE' in info
|
|
2887
|
+
if 'FE3' in info:
|
|
2888
|
+
assert 'FE2' in info
|
|
2889
|
+
|
|
1927
2890
|
return info
|
|
1928
2891
|
|
|
1929
2892
|
def _handle_lulayer_elt(self, elt):
|
|
@@ -1943,11 +2906,13 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1943
2906
|
feinfo = self._load_xml_attributes(AttrDict(), elt)
|
|
1944
2907
|
feinfo['_type'] = 'fe'
|
|
1945
2908
|
feinfo['definition'] = ""
|
|
2909
|
+
feinfo['definitionMarkup'] = ""
|
|
1946
2910
|
feinfo['semType'] = None
|
|
1947
2911
|
feinfo['requiresFE'] = None
|
|
1948
2912
|
feinfo['excludesFE'] = None
|
|
1949
2913
|
for sub in elt:
|
|
1950
2914
|
if sub.tag.endswith('definition'):
|
|
2915
|
+
feinfo['definitionMarkup'] = sub.text
|
|
1951
2916
|
feinfo['definition'] = self._strip_tags(sub.text)
|
|
1952
2917
|
elif sub.tag.endswith('semType'):
|
|
1953
2918
|
stinfo = self._load_xml_attributes(AttrDict(), sub)
|
|
@@ -1966,6 +2931,7 @@ class FramenetCorpusReader(XMLCorpusReader):
|
|
|
1966
2931
|
semt['subTypes'] = PrettyList()
|
|
1967
2932
|
for sub in elt:
|
|
1968
2933
|
if sub.text is not None:
|
|
2934
|
+
semt['definitionMarkup'] = sub.text
|
|
1969
2935
|
semt['definition'] = self._strip_tags(sub.text)
|
|
1970
2936
|
else:
|
|
1971
2937
|
supertypeinfo = self._load_xml_attributes(AttrDict(), sub)
|
|
@@ -1994,7 +2960,7 @@ def demo():
|
|
|
1994
2960
|
#
|
|
1995
2961
|
print('Number of Frames:', len(fn.frames()))
|
|
1996
2962
|
print('Number of Lexical Units:', len(fn.lus()))
|
|
1997
|
-
print('Number of annotated documents:', len(fn.
|
|
2963
|
+
print('Number of annotated documents:', len(fn.docs()))
|
|
1998
2964
|
print()
|
|
1999
2965
|
|
|
2000
2966
|
#
|
|
@@ -2065,14 +3031,14 @@ def demo():
|
|
|
2065
3031
|
# Get a list of all of the corpora used for fulltext annotation
|
|
2066
3032
|
#
|
|
2067
3033
|
print('\nNames of all of the corpora used for fulltext annotation:')
|
|
2068
|
-
allcorpora = set([x.corpname for x in fn.
|
|
3034
|
+
allcorpora = set([x.corpname for x in fn.docs_metadata()])
|
|
2069
3035
|
pprint(list(allcorpora))
|
|
2070
3036
|
|
|
2071
3037
|
#
|
|
2072
3038
|
# Get the names of the annotated documents in the first corpus
|
|
2073
3039
|
#
|
|
2074
3040
|
firstcorp = list(allcorpora)[0]
|
|
2075
|
-
firstcorp_docs = fn.
|
|
3041
|
+
firstcorp_docs = fn.docs(firstcorp)
|
|
2076
3042
|
print(
|
|
2077
3043
|
'\nNames of the annotated documents in the "{0}" corpus:'.format(firstcorp))
|
|
2078
3044
|
pprint([x.filename for x in firstcorp_docs])
|